1 package App::FatPacker;
4 use warnings FATAL => 'all';
8 use File::Find qw(find);
9 use File::Spec::Functions qw(
10 catdir splitpath splitdir catpath rel2abs abs2rel
13 use File::Copy qw(copy);
14 use File::Path qw(mkpath rmtree);
17 our $VERSION = '0.009014'; # 0.009.014
19 $VERSION = eval $VERSION;
23 my ($args, $options) = @_;
25 local *ARGV = [ @{$args} ];
26 $self->{option_parser}->getoptions(@$options);
32 map +(chomp,$_)[1], do { local @ARGV = ($_[0]); <> };
37 $text =~ /^(\s+)/ && $text =~ s/^$1//mg;
42 $_[1] && $_[1] eq '-run_script'
43 and return shift->new->run_script;
48 option_parser => Getopt::Long::Parser->new(
49 config => [ qw(require_order pass_through bundling no_auto_abbrev) ]
55 my ($self, $args) = @_;
56 my @args = $args ? @$args : @ARGV;
57 (my $cmd = shift @args || 'help') =~ s/-/_/g;
59 if (my $meth = $self->can("script_command_${cmd}")) {
62 die "No such command ${cmd}";
66 sub script_command_help {
67 print "Try `perldoc fatpack` for how to use me\n";
70 sub script_command_trace {
71 my ($self, $args) = @_;
73 $args = $self->call_parser($args => [
75 'to-stderr' => \my $to_stderr,
76 'use=s' => \my @additional_use
79 die "Can't use to and to-stderr on same call" if $file && $to_stderr;
81 $file ||= 'fatpacker.trace';
83 if (!$to_stderr and -e $file) {
84 unlink $file or die "Couldn't remove old trace file: $!";
95 use => \@additional_use,
102 my ($self, %opts) = @_;
104 my $output = $opts{output};
105 my $trace_opts = join ',', $output||'>&STDOUT', @{$opts{use}||[]};
107 local $ENV{PERL5OPT} = '-MApp::FatPacker::Trace='.$trace_opts;
109 my @args = @{$opts{args}||[]};
112 # user specified output target, JFDI
116 # no output target specified, slurp
117 open my $out_fh, '-|', $^X, @args;
118 return do { local $/; <$out_fh> };
122 sub script_command_packlists_for {
123 my ($self, $args) = @_;
124 foreach my $pl ($self->packlists_containing($args)) {
129 sub packlists_containing {
130 my ($self, $targets) = @_;
131 my @targets = @$targets;
132 foreach my $t (@targets) {
135 my @search = grep -d $_, map catdir($_, 'auto'), @INC;
139 return unless $_ eq '.packlist' && -f $_;
140 $pack_rev{$_} = $File::Find::name for lines_of $File::Find::name;
142 chdir($cwd) or die "Couldn't chdir back to ${cwd} after find: $!";
143 my %found; @found{map +($pack_rev{$INC{$_}}||()), @targets} = ();
147 sub script_command_tree {
148 my ($self, $args) = @_;
149 my $base = catdir(cwd,'fatlib');
150 $self->packlists_to_tree($base, $args);
153 sub packlists_to_tree {
154 my ($self, $where, $packlists) = @_;
157 foreach my $pl (@$packlists) {
158 my ($vol, $dirs, $file) = splitpath $pl;
159 my @dir_parts = splitdir $dirs;
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];
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]);
176 copy $source => $target;
181 sub script_command_file {
182 my ($self, $args) = @_;
183 my $file = shift @$args;
185 my @dirs = grep -d, map rel2abs($_, $cwd), ('lib','fatlib');
187 foreach my $dir (@dirs) {
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;
191 $files{File::Spec::Unix->abs2rel($File::Find::name,$dir)} = do {
192 local (@ARGV, $/) = ($File::Find::name); <>
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'
203 my $end = stripspace <<' END_END';
204 s/^ //mg for values %fatpacked;
207 if (my $fat = $fatpacked{$_[1]}) {
210 return 0 unless length $fat;
211 $fat =~ s/^([^\n]*\n?)//;
216 open my $fh, '<', \$fat
217 or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
223 } # END OF FATPACK CODE
226 (my $stub = $_) =~ s/\.pm$//;
227 my $name = uc join '_', split '/', $stub;
228 my $data = $files{$_}; $data =~ s/^/ /mg; $data =~ s/(?<!\n)\z/\n/;
229 '$fatpacked{'.perlstring($_).qq!} = <<'${name}';\n!
230 .qq!${data}${name}\n!;
232 print join "\n", $start, @segments, $end;
239 App::FatPacker - pack your dependencies onto your script file
243 $ fatpack trace myscript.pl
244 $ fatpack packlists-for `cat fatpacker.trace` >packlists
245 $ fatpack tree `cat packlists`
246 $ (head -n1 myscript.pl |grep '^#!'; fatpack file; cat myscript.pl) >myscript.packed.pl
248 The C<head -n1 myscript.pl |grep '^#!'> code pulls out the Unix shebang
249 line, if there is one, and injects it at the start of the packed script.
251 See the documentation for the L<fatpack> script itself for more information.
253 The programmatic API for this code is not yet fully decided, hence the 0.9
254 release version. Expect that to be cleaned up for 1.0.
258 L<article for Perl Advent 2012|http://www.perladvent.org/2012/2012-12-14.html>
262 Your current best avenue is to come annoy annoy mst on #toolchain on
263 irc.perl.org. There should be a non-IRC means of support by 1.0.
267 Matt S. Trout (mst) <mst@shadowcat.co.uk>
271 miyagawa - Tatsuhiko Miyagawa (cpan:MIYAGAWA) <miyagawa@bulknews.net>
273 tokuhirom - MATSUNO★Tokuhiro (cpan:TOKUHIROM) <tokuhirom@gmail.com>
275 dg - David Leadbeater (cpan:DGL) <dgl@dgl.cx>
277 gugod - 劉康民 (cpan:GUGOD) <gugod@cpan.org>
279 t0m - Tomas Doran (cpan:BOBTFISH) <bobtfish@bobtfish.net>
281 sawyer - Sawyer X (cpan:XSAWYERX) <xsawyerx@cpan.org>
283 ether - Karen Etheridge (cpan:ETHER) <ether@cpan.org>
285 Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@googlemail.com>
287 Many more people are probably owed thanks for ideas. Yet
288 another doc nit to fix.
292 Copyright (c) 2010 the App::FatPacker L</AUTHOR> and L</CONTRIBUTORS>
297 This library is free software and may be distributed under the same terms