line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/env perl |
2
|
|
|
|
|
|
|
package App::implode::cli; |
3
|
2
|
|
|
2
|
|
766
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
73
|
|
4
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
44
|
|
5
|
2
|
|
|
2
|
|
1261
|
use Archive::Tar; |
|
2
|
|
|
|
|
169571
|
|
|
2
|
|
|
|
|
119
|
|
6
|
2
|
|
|
2
|
|
15
|
use Cwd 'abs_path'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
76
|
|
7
|
2
|
|
|
2
|
|
941
|
use Carton (); |
|
2
|
|
|
|
|
4148
|
|
|
2
|
|
|
|
|
34
|
|
8
|
2
|
|
|
2
|
|
808
|
use Carton::Builder; |
|
2
|
|
|
|
|
57513
|
|
|
2
|
|
|
|
|
72
|
|
9
|
2
|
|
|
2
|
|
912
|
use Carton::Environment; |
|
2
|
|
|
|
|
205742
|
|
|
2
|
|
|
|
|
66
|
|
10
|
2
|
|
|
2
|
|
865
|
use Carton::Mirror; |
|
2
|
|
|
|
|
1719
|
|
|
2
|
|
|
|
|
58
|
|
11
|
2
|
|
|
2
|
|
11
|
use File::Basename 'basename'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
129
|
|
12
|
2
|
|
|
2
|
|
12
|
use File::Find (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
30
|
|
13
|
2
|
|
|
2
|
|
11
|
use File::Path (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
39
|
|
14
|
2
|
|
|
2
|
|
1084
|
use File::Spec::Functions qw( catdir catfile ); |
|
2
|
|
|
|
|
1264
|
|
|
2
|
|
|
|
|
140
|
|
15
|
2
|
|
|
2
|
|
3306
|
use File::Temp 'tempdir'; |
|
2
|
|
|
|
|
16628
|
|
|
2
|
|
|
|
|
146
|
|
16
|
2
|
|
|
2
|
|
17
|
use IO::Compress::Bzip2; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
3079
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
our $PATH = abs_path(__FILE__); |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub DESTROY { |
21
|
4
|
|
|
4
|
|
2054
|
my $self = shift; |
22
|
4
|
100
|
|
|
|
59
|
return chdir $self->[0] if UNIVERSAL::isa($self, 'ARRAY'); |
23
|
2
|
50
|
33
|
|
|
60
|
File::Path::remove_tree($self->{tmpdir}) if $self->{cleanup} and $self->{tmpdir}; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
0
|
|
0
|
0
|
|
0
|
sub mirror { shift->{mirror} ||= Carton::Mirror->new($ENV{PERL_CARTON_MIRROR} || $Carton::Mirror::DefaultMirror) } |
|
|
|
0
|
|
|
|
|
27
|
1
|
0
|
33
|
1
|
|
4
|
sub tmpdir { shift->{tmpdir} //= tempdir(CLEANUP => $ENV{IMPLODE_NO_CLEANUP} ? 0 : 1) } |
28
|
3
|
50
|
66
|
3
|
|
16
|
sub verbose { shift->{verbose} //= $ENV{APP_IMPLODE_VERBOSE} ? 0 : -t STDOUT } |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub bundle { |
31
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
32
|
0
|
|
|
|
|
0
|
my $script = $self->slurp($self->{script}); |
33
|
0
|
|
|
|
|
0
|
my $exploder = $self->code('exploder'); |
34
|
0
|
|
|
|
|
0
|
my $id = basename $self->{out}; |
35
|
|
|
|
|
|
|
|
36
|
0
|
|
|
|
|
0
|
$exploder =~ s!^sub.*\@_;!BEGIN{my \$id='$id';!s; |
37
|
0
|
|
|
|
|
0
|
$exploder =~ s!^\s+!!mg; |
38
|
0
|
|
|
|
|
0
|
$exploder =~ s!\n!!g; |
39
|
|
|
|
|
|
|
|
40
|
0
|
0
|
|
|
|
0
|
open my $OUT, '>', $self->{out} or die "Could not write $self->{out}: $!\n"; |
41
|
0
|
0
|
|
|
|
0
|
warn sprintf "Generating $self->{out} with embedded bzip archive...\n" if $self->verbose; |
42
|
0
|
0
|
|
|
|
0
|
print $OUT $script =~ s/^(#!.+?[\r\n]+)//m ? $1 : "#!/usr/bin/perl\n"; |
43
|
0
|
|
|
|
|
0
|
print $OUT $exploder, "\n", $script, "\n__END__\n"; |
44
|
0
|
|
|
|
|
0
|
$self->tarball->write(IO::Compress::Bzip2->new($OUT), COMPRESS_GZIP); |
45
|
0
|
|
|
|
|
0
|
close $OUT; |
46
|
0
|
|
|
|
|
0
|
chmod 0755, $self->{out}; |
47
|
0
|
0
|
|
|
|
0
|
warn sprintf "$self->{out} is generated.\n" if $self->verbose; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub chdir { |
51
|
2
|
|
|
2
|
|
2
|
my $self = shift; |
52
|
2
|
|
|
|
|
12
|
my $guard = bless [abs_path], ref($self); |
53
|
2
|
50
|
|
|
|
24
|
chdir $_[0] or die "chdir $_[0]: $!"; |
54
|
2
|
|
|
|
|
4
|
$guard; |
55
|
|
|
|
|
|
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub code { |
58
|
1
|
|
|
1
|
|
2
|
my ($self, $name) = @_; |
59
|
1
|
50
|
|
|
|
31
|
open my $SELF, '<', $PATH or die "Read $PATH: $!"; |
60
|
1
|
|
|
|
|
86
|
return join '', grep { /^sub $name/ .. /^\}/ } <$SELF>; |
|
159
|
|
|
|
|
208
|
|
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub deps { |
64
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
65
|
0
|
|
|
|
|
0
|
my $env = Carton::Environment->build('cpanfile', $self->tmpdir); |
66
|
0
|
|
|
|
|
0
|
my $builder = Carton::Builder->new(mirror => $self->mirror, cpanfile => $env->cpanfile); |
67
|
|
|
|
|
|
|
|
68
|
0
|
0
|
|
|
|
0
|
$self->dir_is_empty($self->tmpdir) or die "Cannot build $self->{script}: @{[$env->install_path]} already exists.\n"; |
|
0
|
|
|
|
|
0
|
|
69
|
0
|
|
|
|
|
0
|
$self->{cleanup} = 1; |
70
|
0
|
|
|
|
|
0
|
$builder->install($env->install_path); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub dir_is_empty { |
74
|
3
|
|
|
3
|
|
300
|
my ($self, $dir) = @_; |
75
|
3
|
100
|
|
|
|
69
|
opendir(my $DH, $dir) or return 1; |
76
|
2
|
|
|
|
|
26
|
not scalar grep {/\w/} readdir $DH; |
|
9
|
|
|
|
|
34
|
|
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub exploder { |
80
|
1
|
|
|
1
|
|
464
|
my ($self, $id) = @_; |
81
|
1
|
|
|
|
|
6
|
require Archive::Tar; |
82
|
1
|
|
|
|
|
4
|
require File::Path; |
83
|
1
|
|
|
|
|
3
|
require File::Spec; |
84
|
1
|
|
|
|
|
4
|
require IO::Uncompress::Bunzip2; |
85
|
1
|
|
|
1
|
|
1418
|
sub App::implode::temp::DESTROY { File::Path::remove_tree(${$_[0]}) } |
|
1
|
|
|
|
|
625
|
|
86
|
1
|
|
33
|
|
|
101
|
$App::implode::explodedir |
87
|
|
|
|
|
|
|
= bless \($ENV{APP_EXPLODE_DIR} || File::Spec->catdir(File::Spec->tmpdir, "app-implode-$id")), 'App::implode::temp'; |
88
|
1
|
50
|
|
|
|
7
|
warn "[App::implode] cd $$App::implode::explodedir; tar -xfz $0\n" if $ENV{APP_EXPLODE_VERBOSE}; |
89
|
1
|
|
|
|
|
8
|
my $tar = Archive::Tar->new; |
90
|
|
|
|
|
|
|
$tar->read( |
91
|
|
|
|
|
|
|
IO::Uncompress::Bunzip2->new( |
92
|
1
|
|
|
|
|
14
|
do { |
93
|
1
|
|
|
|
|
27
|
open my $FH, '<', $0; |
94
|
1
|
|
|
|
|
2
|
my $m = 0; |
95
|
1
|
100
|
100
|
|
|
61
|
\join '', grep { $m++ if /^__END__\r?\n/ || $m; $m > 1; } <$FH>; |
|
44
|
|
|
|
|
124
|
|
|
44
|
|
|
|
|
62
|
|
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
) |
98
|
|
|
|
|
|
|
); |
99
|
1
|
|
|
|
|
3405
|
$tar->setcwd($$App::implode::explodedir); |
100
|
1
|
50
|
|
|
|
10
|
$tar->extract or die "[App::implode] tar -xfz $0 failed: @{[$tar->error]}"; |
|
0
|
|
|
|
|
0
|
|
101
|
1
|
|
|
|
|
1399
|
unshift @INC, File::Spec->catdir($$App::implode::explodedir, 'lib', 'perl5'); |
102
|
1
|
|
|
|
|
9
|
$ENV{PATH} = join ':', grep {defined} File::Spec->catdir($$App::implode::explodedir, 'bin'), $ENV{PATH}; |
|
2
|
|
|
|
|
8
|
|
103
|
1
|
|
|
|
|
37
|
$ENV{PERL5LIB} = join ':', @INC; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub slurp { |
107
|
1
|
|
|
1
|
|
2
|
my ($self, $file) = @_; |
108
|
1
|
50
|
|
|
|
22
|
open my $FH, '<', $file or die "Could not read $file: $!\n"; |
109
|
1
|
|
|
|
|
3
|
local $/; |
110
|
1
|
|
|
|
|
22
|
readline $FH; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub tarball { |
114
|
1
|
|
|
1
|
|
1
|
my $self = shift; |
115
|
1
|
|
|
|
|
2
|
my $chdir = $self->chdir($self->tmpdir); |
116
|
1
|
100
|
|
8
|
|
3
|
my $chmod = sub { -f and chmod 0600 | (0777 & (stat _)[2]), $_ }; |
|
8
|
|
|
|
|
346
|
|
117
|
1
|
50
|
|
2
|
|
2
|
my $files = sub { @_ > 1 and File::Find::find({no_chdir => 1, wanted => shift}, @_) }; |
|
2
|
|
|
|
|
109
|
|
118
|
1
|
|
|
|
|
6
|
my $tar = Archive::Tar->new; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
$files->( |
121
|
|
|
|
|
|
|
sub { |
122
|
5
|
100
|
|
5
|
|
453
|
return unless $chmod->(); |
123
|
2
|
50
|
|
|
|
8
|
warn sprintf "Add @{[catfile $self->{tmpdir}, $_]}\n" if $self->verbose; |
|
0
|
|
|
|
|
0
|
|
124
|
2
|
|
|
|
|
8
|
$tar->add_files($_); |
125
|
|
|
|
|
|
|
}, |
126
|
1
|
|
|
|
|
13
|
grep {-d} qw( bin lib ) |
|
2
|
|
|
|
|
16
|
|
127
|
|
|
|
|
|
|
); |
128
|
|
|
|
|
|
|
|
129
|
1
|
|
|
|
|
284
|
undef $chdir; |
130
|
|
|
|
|
|
|
$files->( |
131
|
|
|
|
|
|
|
sub { |
132
|
3
|
100
|
66
|
3
|
|
4
|
return unless $chmod->() and s!lib!lib/perl5!; |
133
|
1
|
50
|
|
|
|
4
|
warn sprintf "Add $_\n" if $self->verbose; |
134
|
1
|
|
|
|
|
3
|
$tar->add_data($_, $self->slurp($File::Find::name)); |
135
|
|
|
|
|
|
|
}, |
136
|
1
|
|
|
|
|
3
|
grep {-d} qw( lib ) |
|
1
|
|
|
|
|
9
|
|
137
|
|
|
|
|
|
|
); |
138
|
|
|
|
|
|
|
|
139
|
1
|
|
|
|
|
184
|
return $tar; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub run { |
143
|
2
|
|
|
2
|
|
717
|
my $self = shift; |
144
|
|
|
|
|
|
|
|
145
|
2
|
100
|
|
|
|
14
|
$self->{script} = shift or die "Usage: implode myapp.pl [path/to/outfile.pl]\n\n"; |
146
|
1
|
|
33
|
|
|
50
|
$self->{out} = shift || basename $self->{script}; |
147
|
1
|
50
|
|
|
|
31
|
-r $self->{script} or die "Cannot read '$self->{script}'.\n"; |
148
|
0
|
0
|
|
|
|
|
-e $self->{out} and die "Outfile '$self->{out}' already exists.\n"; |
149
|
|
|
|
|
|
|
|
150
|
0
|
0
|
|
|
|
|
warn sprintf "Building application in %s\n", $self->tmpdir if $self->verbose; |
151
|
0
|
|
|
|
|
|
$self->deps; |
152
|
0
|
|
|
|
|
|
$self->bundle; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
return 0; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
exit((bless {})->run(@ARGV)) unless defined wantarray; |
158
|
2
|
|
|
2
|
|
12
|
no warnings; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
122
|
|
159
|
|
|
|
|
|
|
'App::implode::cli'; |