Removed apparently unused piece of code, that prevents the use of ->trace() to slurp...
[p5sagit/App-FatPacker.git] / lib / App / FatPacker.pm
CommitLineData
48af1939 1package App::FatPacker;
2
3use strict;
4use warnings FATAL => 'all';
8572221e 5use 5.008001;
48af1939 6use Getopt::Long;
7use Cwd qw(cwd);
8use File::Find qw(find);
9use File::Spec::Functions qw(
10 catdir splitpath splitdir catpath rel2abs abs2rel
11);
cbd99f49 12use File::Spec::Unix;
48af1939 13use File::Copy qw(copy);
4d5603b7 14use File::Path qw(mkpath rmtree);
48af1939 15use B qw(perlstring);
16
9faebd20 17our $VERSION = '0.009014'; # 0.009.014
f5a54fa1 18
19$VERSION = eval $VERSION;
20
48af1939 21sub call_parser {
24d68aa2 22 my $self = shift;
69667cc8 23 my ($args, $options) = @_;
24d68aa2 24
25 local *ARGV = [ @{$args} ];
69667cc8 26 $self->{option_parser}->getoptions(@$options);
24d68aa2 27
28 return [ @ARGV ];
48af1939 29}
30
31sub lines_of {
32 map +(chomp,$_)[1], do { local @ARGV = ($_[0]); <> };
33}
34
35sub stripspace {
36 my ($text) = @_;
37 $text =~ /^(\s+)/ && $text =~ s/^$1//mg;
38 $text;
39}
40
48af1939 41sub import {
24d68aa2 42 $_[1] && $_[1] eq '-run_script'
48af1939 43 and return shift->new->run_script;
44}
45
24d68aa2 46sub new {
47 bless {
48 option_parser => Getopt::Long::Parser->new(
49 config => [ qw(require_order pass_through bundling no_auto_abbrev) ]
50 ),
51 }, $_[0];
52}
48af1939 53
54sub run_script {
55 my ($self, $args) = @_;
56 my @args = $args ? @$args : @ARGV;
3e4dadce 57 (my $cmd = shift @args || 'help') =~ s/-/_/g;
24d68aa2 58
48af1939 59 if (my $meth = $self->can("script_command_${cmd}")) {
60 $self->$meth(\@args);
61 } else {
62 die "No such command ${cmd}";
63 }
64}
65
3e4dadce 66sub script_command_help {
67 print "Try `perldoc fatpack` for how to use me\n";
68}
69
48af1939 70sub script_command_trace {
71 my ($self, $args) = @_;
24d68aa2 72
69667cc8 73 $args = $self->call_parser($args => [
48af1939 74 'to=s' => \my $file,
75 'to-stderr' => \my $to_stderr,
3fdf85ca 76 'use=s' => \my @additional_use
69667cc8 77 ]);
48af1939 78
79 die "Can't use to and to-stderr on same call" if $file && $to_stderr;
80
3fdf85ca 81 $file ||= 'fatpacker.trace';
69667cc8 82
3fdf85ca 83 if (!$to_stderr and -e $file) {
84 unlink $file or die "Couldn't remove old trace file: $!";
48af1939 85 }
86 my $arg = do {
3fdf85ca 87 if ($to_stderr) {
020d9b76 88 ">&STDERR"
3fdf85ca 89 } elsif ($file) {
276a30c9 90 ">>${file}"
48af1939 91 }
92 };
3fdf85ca 93
b4704b1a 94 $self->trace(
5e1de95d 95 use => \@additional_use,
96 args => $args,
7a3662c8 97 output => $arg,
b4704b1a 98 );
abd7cf01 99}
100
101sub trace {
b4704b1a 102 my ($self, %opts) = @_;
69667cc8 103
1ea23474 104 my $output = $opts{output};
69667cc8 105 my $trace_opts = join ',', $output||'>&STDOUT', @{$opts{use}||[]};
7a3662c8 106
69667cc8 107 local $ENV{PERL5OPT} = '-MApp::FatPacker::Trace='.$trace_opts;
abd7cf01 108
69667cc8 109 my @args = @{$opts{args}||[]};
e0cd89ab 110
69667cc8 111 if ($output) {
112 # user specified output target, JFDI
113 system $^X, @args;
114 return;
e0cd89ab 115 } else {
69667cc8 116 # no output target specified, slurp
117 open my $out_fh, '-|', $^X, @args;
118 return do { local $/; <$out_fh> };
119 }
48af1939 120}
121
122sub script_command_packlists_for {
123 my ($self, $args) = @_;
124 foreach my $pl ($self->packlists_containing($args)) {
125 print "${pl}\n";
126 }
127}
128
129sub packlists_containing {
130 my ($self, $targets) = @_;
131 my @targets = @$targets;
a976705b 132 foreach my $t (@targets) {
133 require $t;
134 }
48af1939 135 my @search = grep -d $_, map catdir($_, 'auto'), @INC;
136 my %pack_rev;
137 my $cwd = cwd;
138 find(sub {
139 return unless $_ eq '.packlist' && -f $_;
140 $pack_rev{$_} = $File::Find::name for lines_of $File::Find::name;
141 }, @search);
142 chdir($cwd) or die "Couldn't chdir back to ${cwd} after find: $!";
f5a54fa1 143 my %found; @found{map +($pack_rev{$INC{$_}}||()), @targets} = ();
48af1939 144 sort keys %found;
145}
146
147sub script_command_tree {
148 my ($self, $args) = @_;
149 my $base = catdir(cwd,'fatlib');
150 $self->packlists_to_tree($base, $args);
151}
152
153sub packlists_to_tree {
154 my ($self, $where, $packlists) = @_;
4d5603b7 155 rmtree $where;
156 mkpath $where;
48af1939 157 foreach my $pl (@$packlists) {
158 my ($vol, $dirs, $file) = splitpath $pl;
159 my @dir_parts = splitdir $dirs;
160 my $pack_base;
161 PART: foreach my $p (0 .. $#dir_parts) {
162 if ($dir_parts[$p] eq 'auto') {
163 # $p-2 since it's <wanted path>/$Config{archname}/auto
164 $pack_base = catpath $vol, catdir @dir_parts[0..$p-2];
165 last PART;
166 }
167 }
168 die "Couldn't figure out base path of packlist ${pl}" unless $pack_base;
169 foreach my $source (lines_of $pl) {
170 # there is presumably a better way to do "is this under this base?"
171 # but if so, it's not obvious to me in File::Spec
172 next unless substr($source,0,length $pack_base) eq $pack_base;
173 my $target = rel2abs( abs2rel($source, $pack_base), $where );
174 my $target_dir = catpath((splitpath $target)[0,1]);
4d5603b7 175 mkpath $target_dir;
48af1939 176 copy $source => $target;
177 }
178 }
179}
180
181sub script_command_file {
182 my ($self, $args) = @_;
183 my $file = shift @$args;
184 my $cwd = cwd;
0c46b17a 185 my @dirs = grep -d, map rel2abs($_, $cwd), ('lib','fatlib');
48af1939 186 my %files;
187 foreach my $dir (@dirs) {
188 find(sub {
189 return unless -f $_;
190 !/\.pm$/ and warn "File ${File::Find::name} isn't a .pm file - can't pack this and if you hoped we were going to things may not be what you expected later\n" and return;
cbd99f49 191 $files{File::Spec::Unix->abs2rel($File::Find::name,$dir)} = do {
48af1939 192 local (@ARGV, $/) = ($File::Find::name); <>
193 };
0de38c11 194 close ARGV;
48af1939 195 }, $dir);
196 }
197 my $start = stripspace <<' END_START';
198 # This chunk of stuff was generated by App::FatPacker. To find the original
199 # file's code, look for the end of this BEGIN block or the string 'FATPACK'
200 BEGIN {
201 my %fatpacked;
202 END_START
203 my $end = stripspace <<' END_END';
204 s/^ //mg for values %fatpacked;
205
206 unshift @INC, sub {
207 if (my $fat = $fatpacked{$_[1]}) {
7bf1d4f2 208 if ($] < 5.008) {
209 return sub {
210 return 0 unless length $fat;
87108237 211 $fat =~ s/^([^\n]*\n?)//;
7bf1d4f2 212 $_ = $1;
213 return 1;
214 };
215 }
002ecfea 216 open my $fh, '<', \$fat
217 or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
48af1939 218 return $fh;
219 }
220 return
221 };
222
223 } # END OF FATPACK CODE
224 END_END
225 my @segments = map {
226 (my $stub = $_) =~ s/\.pm$//;
227 my $name = uc join '_', split '/', $stub;
cc5db92a 228 my $data = $files{$_}; $data =~ s/^/ /mg; $data =~ s/(?<!\n)\z/\n/;
48af1939 229 '$fatpacked{'.perlstring($_).qq!} = <<'${name}';\n!
230 .qq!${data}${name}\n!;
231 } sort keys %files;
232 print join "\n", $start, @segments, $end;
233}
f5a54fa1 234
bb49414d 235=encoding UTF-8
236
f5a54fa1 237=head1 NAME
238
239App::FatPacker - pack your dependencies onto your script file
240
241=head1 SYNOPSIS
242
243 $ fatpack trace myscript.pl
62ceea28 244 $ fatpack packlists-for `cat fatpacker.trace` >packlists
245 $ fatpack tree `cat packlists`
24b4367e 246 $ (head -n1 myscript.pl |grep '^#!'; fatpack file; cat myscript.pl) >myscript.packed.pl
f5a54fa1 247
cb50b68f 248The C<head -n1 myscript.pl |grep '^#!'> code pulls out the Unix shebang
249line, if there is one, and injects it at the start of the packed script.
250
f5a54fa1 251See the documentation for the L<fatpack> script itself for more information.
252
3fdf85ca 253The programmatic API for this code is not yet fully decided, hence the 0.9
f5a54fa1 254release version. Expect that to be cleaned up for 1.0.
255
66a19d01 256=head1 SEE ALSO
257
258L<article for Perl Advent 2012|http://www.perladvent.org/2012/2012-12-14.html>
259
f5a54fa1 260=head1 SUPPORT
261
262Your current best avenue is to come annoy annoy mst on #toolchain on
263irc.perl.org. There should be a non-IRC means of support by 1.0.
264
265=head1 AUTHOR
266
267Matt S. Trout (mst) <mst@shadowcat.co.uk>
268
269=head2 CONTRIBUTORS
270
99b15200 271miyagawa - Tatsuhiko Miyagawa (cpan:MIYAGAWA) <miyagawa@bulknews.net>
272
273tokuhirom - MATSUNO★Tokuhiro (cpan:TOKUHIROM) <tokuhirom@gmail.com>
274
275dg - David Leadbeater (cpan:DGL) <dgl@dgl.cx>
276
277gugod - 劉康民 (cpan:GUGOD) <gugod@cpan.org>
278
279t0m - Tomas Doran (cpan:BOBTFISH) <bobtfish@bobtfish.net>
280
281sawyer - Sawyer X (cpan:XSAWYERX) <xsawyerx@cpan.org>
282
283ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
284
cbd99f49 285Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
286
99b15200 287Many more people are probably owed thanks for ideas. Yet
f5a54fa1 288another doc nit to fix.
289
290=head1 COPYRIGHT
291
292Copyright (c) 2010 the App::FatPacker L</AUTHOR> and L</CONTRIBUTORS>
293as listed above.
294
295=head1 LICENSE
296
297This library is free software and may be distributed under the same terms
298as perl itself.
299
300=cut
301
48af1939 3021;
24d68aa2 303