File Coverage

blib/lib/App/Web/VPKBuilder.pm
Criterion Covered Total %
statement 57 133 42.8
branch 0 22 0.0
condition 0 4 0.0
subroutine 19 30 63.3
pod 2 6 33.3
total 78 195 40.0


line stmt bran cond sub pod time code
1             package App::Web::VPKBuilder;
2              
3 1     1   24085 use 5.014000;
  1         4  
  1         36  
4 1     1   7 use strict;
  1         2  
  1         36  
5 1     1   5 use warnings;
  1         7  
  1         43  
6 1     1   872 use parent qw/Plack::Component/;
  1         364  
  1         5  
7             our $VERSION = '0.000_002';
8              
9 1     1   16737 use File::Find qw/find/;
  1         2  
  1         82  
10 1     1   5 use File::Path qw/remove_tree/;
  1         2  
  1         68  
11 1     1   1001 use File::Spec::Functions qw/abs2rel catfile rel2abs/;
  1         924  
  1         83  
12 1     1   1229 use File::Temp qw/tempdir/;
  1         14140  
  1         71  
13 1     1   1098 use IO::Compress::Zip qw/zip ZIP_CM_LZMA/;
  1         543531  
  1         118  
14 1     1   1172 use sigtrap qw/die normal-signals/;
  1         1360  
  1         8  
15              
16 1     1   1075 use Data::Diver qw/DiveRef/;
  1         1252  
  1         87  
17 1     1   999 use File::Slurp qw/write_file/;
  1         15657  
  1         79  
18 1     1   1677 use HTML::Element;
  1         38230  
  1         6  
19 1     1   1269 use HTML::TreeBuilder;
  1         7464  
  1         14  
20 1     1   855 use Hash::Merge qw/merge/;
  1         2522  
  1         63  
21 1     1   1380 use List::MoreUtils qw/uniq/;
  1         2237  
  1         87  
22 1     1   750 use Plack::Request;
  1         59636  
  1         40  
23 1     1   1126 use Sort::ByExample qw/sbe/;
  1         28137  
  1         10  
24 1     1   1286 use YAML qw/LoadFile/;
  1         14385  
  1         1663  
25              
26             sub new {
27 0     0 1   my $self = shift->SUPER::new(@_);
28 0           $self->{cfg} = {};
29 0           for (sort ) {
30 0           my $cfg = LoadFile $_;
31 0           $self->{cfg} = merge $self->{cfg}, $cfg
32             }
33 0   0       $self->{cfg}{vpk_extension} //= 'vpk';
34 0     0     $self->{cfg}{sort} = sbe $self->{cfg}{sort_order}, { fallback => sub { shift cmp shift } };
  0            
35 0           $self
36             }
37              
38             sub addpkg {
39 0     0 0   my ($pkg, $dir) = @_;
40 0 0         return unless $pkg =~ /^[a-zA-Z0-9_-]+$/aa;
41 0           my @dirs = ($dir);
42             find {
43 0     0     postprocess => sub { pop @dirs },
44             wanted => sub {
45 0     0     my $dest = catfile @dirs, $_;
46 0 0         mkdir $dest if -d;
47 0 0         push @dirs, $_ if -d;
48 0 0         link $_, $dest if -f;
49 0           }}, catfile 'pkg', $pkg;
50             }
51              
52             sub makepkg {
53 0     0 0   my ($self, @pkgs) = @_;
54 0           mkdir $self->{cfg}{dir};
55 0           my $dir = rel2abs tempdir 'workXXXX', DIR => $self->{cfg}{dir};
56 0           my $dest = catfile $dir, 'pkg';
57 0           mkdir $dest;
58 0           @pkgs = grep { exists $self->{cfg}{pkgs}{$_} } @pkgs;
  0            
59 0   0       push @pkgs, split ',', ($self->{cfg}{pkgs}{$_}{deps} // '') for @pkgs;
60 0           @pkgs = uniq @pkgs;
61 0           addpkg $_, $dest for @pkgs;
62 0           write_file catfile ($dir, 'readme.txt'), $self->{cfg}{readme};
63 0           my @zip_files = catfile $dir, 'readme.txt';
64 0 0         if ($self->{cfg}{vpk}) {
65 0           system $self->{cfg}{vpk} => $dest;
66 0           push @zip_files, catfile $dir, "pkg.$self->{cfg}{vpk_extension}"
67             } else {
68 0 0   0     find sub { push @zip_files, $File::Find::name if -f }, $dest;
  0            
69             }
70 0     0     zip \@zip_files, catfile($dir, 'pkg.zip'), FilterName => sub { $_ = abs2rel $_, $dir }, -Level => 1;
  0            
71 0           open my $fh, '<', catfile $dir, 'pkg.zip';
72 0           remove_tree $dir;
73 0           [200, ['Content-Type' => 'application/zip', 'Content-Disposition' => 'attachment; filename=pkg.zip'], $fh]
74             }
75              
76             sub makelist {
77 0     0 0   my ($self, $elem, $tree, $lvl, $key) = @_;
78 0           my $name = HTML::Element->new('span', class => 'name');
79 0           $name->push_content($key);
80 0 0         $elem->push_content($name) if defined $key;
81 0 0         if (ref $tree eq 'ARRAY') {
82 0           my $sel = HTML::Element->new('select', name => 'pkg');
83 0           my $opt = HTML::Element->new('option', value => '');
84 0           $opt->push_content('None');
85 0           $sel->push_content($opt);
86 0           for my $pkg (sort { $a->{name} cmp $b->{name} } values $tree) {
  0            
87 0 0         my $opt = HTML::Element->new('option', value => $pkg->{pkg}, $pkg->{default} ? (selected => 'selected') : ());
88 0           $opt->push_content($pkg->{name});
89 0           $sel->push_content($opt);
90             }
91 0           $elem->push_content($sel);
92             } else {
93 0           my $ul = HTML::Element->new('ul');
94 0           for my $key ($self->{cfg}{sort}->(keys $tree)) {
95 0           my $li = HTML::Element->new('li', class => "level$lvl");
96 0           $self->makelist($li, $tree->{$key}, $lvl + 1, $key);
97 0           $ul->push_content($li);
98             }
99 0           $elem->push_content($ul);
100             }
101             }
102              
103             sub makeindex {
104 0     0 0   my ($self) = @_;
105 0           my ($pkgs, $tree) = ($self->{cfg}{pkgs}, {});
106 0           for (keys $pkgs) {
107 0           my $ref = DiveRef ($tree, split ',', $pkgs->{$_}{path});
108 0 0         $$ref = [] unless ref $$ref eq 'ARRAY';
109 0           push $$ref, {pkg => $_, name => $pkgs->{$_}{name}, default => $pkgs->{$_}{default}};
110             }
111 0           my $html = HTML::TreeBuilder->new_from_file('index.html');
112 0           $self->makelist(scalar $html->look_down(id => 'list'), $tree, 1);
113 0           my $ret = $html->as_HTML('', ' ');
114 0           utf8::encode($ret);
115 0           [200, ['Content-Type' => 'text/html;charset=utf-8'], [$ret]]
116             }
117              
118             sub call{
119 0     0 1   my ($self, $env) = @_;
120 0           my $req = Plack::Request->new($env);
121 0 0         return $self->makepkg($req->param('pkg')) if $req->path eq '/makepkg';
122 0           $self->makeindex;
123             }
124              
125             1;
126             __END__