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
12 use File::Copy qw(copy);
13 use File::Path qw(mkpath rmtree);
16 our $VERSION = '0.009006'; # 0.9.6
18 $VERSION = eval $VERSION;
20 my $option_parser = Getopt::Long::Parser->new(
21 config => [ qw(require_order pass_through bundling no_auto_abbrev) ]
25 local *ARGV = [ @{$_[0]} ];
26 $option_parser->getoptions(@{$_[1]});
31 map +(chomp,$_)[1], do { local @ARGV = ($_[0]); <> };
36 $text =~ /^(\s+)/ && $text =~ s/^$1//mg;
41 $_[1] eq '-run_script'
42 and return shift->new->run_script;
45 sub new { bless({}, $_[0]) }
48 my ($self, $args) = @_;
49 my @args = $args ? @$args : @ARGV;
50 (my $cmd = shift @args || 'help') =~ s/-/_/g;
51 if (my $meth = $self->can("script_command_${cmd}")) {
54 die "No such command ${cmd}";
58 sub script_command_help {
59 print "Try `perldoc fatpack` for how to use me\n";
62 sub script_command_trace {
63 my ($self, $args) = @_;
65 $args = call_parser $args => [
67 'to-stderr' => \my $to_stderr,
68 'use=s' => \my @additional_use
71 die "Can't use to and to-stderr on same call" if $file && $to_stderr;
73 $file ||= 'fatpacker.trace';
74 if (!$to_stderr and -e $file) {
75 unlink $file or die "Couldn't remove old trace file: $!";
86 $arg .= "," . join ",", @additional_use;
90 local $ENV{PERL5OPT} = '-MApp::FatPacker::Trace'.$arg;
95 sub script_command_packlists_for {
96 my ($self, $args) = @_;
97 foreach my $pl ($self->packlists_containing($args)) {
102 sub packlists_containing {
103 my ($self, $targets) = @_;
104 my @targets = @$targets;
105 require $_ for @targets;
106 my @search = grep -d $_, map catdir($_, 'auto'), @INC;
110 return unless $_ eq '.packlist' && -f $_;
111 $pack_rev{$_} = $File::Find::name for lines_of $File::Find::name;
113 chdir($cwd) or die "Couldn't chdir back to ${cwd} after find: $!";
114 my %found; @found{map +($pack_rev{$INC{$_}}||()), @targets} = ();
118 sub script_command_tree {
119 my ($self, $args) = @_;
120 my $base = catdir(cwd,'fatlib');
121 $self->packlists_to_tree($base, $args);
124 sub packlists_to_tree {
125 my ($self, $where, $packlists) = @_;
128 foreach my $pl (@$packlists) {
129 my ($vol, $dirs, $file) = splitpath $pl;
130 my @dir_parts = splitdir $dirs;
132 PART: foreach my $p (0 .. $#dir_parts) {
133 if ($dir_parts[$p] eq 'auto') {
134 # $p-2 since it's <wanted path>/$Config{archname}/auto
135 $pack_base = catpath $vol, catdir @dir_parts[0..$p-2];
139 die "Couldn't figure out base path of packlist ${pl}" unless $pack_base;
140 foreach my $source (lines_of $pl) {
141 # there is presumably a better way to do "is this under this base?"
142 # but if so, it's not obvious to me in File::Spec
143 next unless substr($source,0,length $pack_base) eq $pack_base;
144 my $target = rel2abs( abs2rel($source, $pack_base), $where );
145 my $target_dir = catpath((splitpath $target)[0,1]);
147 copy $source => $target;
152 sub script_command_file {
153 my ($self, $args) = @_;
154 my $file = shift @$args;
156 my @dirs = map rel2abs($_, $cwd), ('lib','fatlib');
158 foreach my $dir (@dirs) {
161 !/\.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;
162 $files{abs2rel($File::Find::name,$dir)} = do {
163 local (@ARGV, $/) = ($File::Find::name); <>
167 my $start = stripspace <<' END_START';
168 # This chunk of stuff was generated by App::FatPacker. To find the original
169 # file's code, look for the end of this BEGIN block or the string 'FATPACK'
173 my $end = stripspace <<' END_END';
174 s/^ //mg for values %fatpacked;
177 if (my $fat = $fatpacked{$_[1]}) {
178 open my $fh, '<', \$fat
179 or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
185 } # END OF FATPACK CODE
188 (my $stub = $_) =~ s/\.pm$//;
189 my $name = uc join '_', split '/', $stub;
190 my $data = $files{$_}; $data =~ s/^/ /mg; $data =~ s/(?<!\n)\z/\n/;
191 '$fatpacked{'.perlstring($_).qq!} = <<'${name}';\n!
192 .qq!${data}${name}\n!;
194 print join "\n", $start, @segments, $end;
199 App::FatPacker - pack your dependencies onto your script file
203 $ fatpack trace myscript.pl
204 $ fatpack packlists-for `cat fatpacker.trace` >packlists
205 $ fatpack tree `cat packlists`
206 $ (fatpack file; cat myscript.pl) >myscript.packed.pl
208 See the documentation for the L<fatpack> script itself for more information.
210 The programmatic API for this code is not yet fully decided, hence the 0.9
211 release version. Expect that to be cleaned up for 1.0.
215 Your current best avenue is to come annoy annoy mst on #toolchain on
216 irc.perl.org. There should be a non-IRC means of support by 1.0.
220 Matt S. Trout (mst) <mst@shadowcat.co.uk>
224 None as yet, though I probably owe lots of people thanks for ideas. Yet
225 another doc nit to fix.
229 Copyright (c) 2010 the App::FatPacker L</AUTHOR> and L</CONTRIBUTORS>
234 This library is free software and may be distributed under the same terms