App-FatPacker-0.010005/000700 000766 000024 00000000000 12633422416 014561 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/Changes000644 000766 000024 00000005457 12633422375 016105 0ustar00etherstaff000000 000000 Revision history for App-FatPacker 0.010005 - 2015-12-14 - fix fatpacked code to work properly on perl 5.6 in all cases - removed x_static_install metadata (RT#110299) 0.010004 - 2015-06-28 - fix tests to work reliably on win32 0.010003 - 2015-04-17 - exclude virtual %INC entries from trace output 0.010002 - 2014-08-16 - correctly specify perl prerequisite of 5.8 in meta files 0.010001 - 2014-03-18 - include 'lib' in @INC for packlists_containing's require() calls 0.010000 - 2013-11-27 - use object for @INC hook instead of subref, including a 'files' method to return a list of files provided - generate #line relative to the whole fatpacked script so die() reports and caller() now point directly to the right line in the script (RT#87118, DOLMEN) 0.009018 - 2013-07-26 - deal with relative paths better by changing options passed to File::Find (RT#84414, miyagawa) 0.009017 - 2013-05-29 - fix fatal "List form of piped open not implemented" on MSWin32 (RT#85712, ether) 0.009016 - 2013-04-07 - 'file' command now takes care of keeping its original shebang line when given the original file as its argument. The 'pack' command makes use of that too. (Robin Smidsrod, miyagawa) 0.009015 - 2013-04-07 - new 'pack' command, to do everything in one command (thanks, miyagawa!) (RT#84415) 0.009014 - 2013-04-03 - avoid fatal error when lib/ doesn't exist (now it is simply skipped) (RT#84413, miyagawa) 0.009013 - 2013-01-22 - fix to support for < 5.8 perls (haarg) 0.009012 - 2013-01-18 - support for < 5.8 perls (RT#57811, haarg) 0.009011 - 2012-09-24 - RT #79835: install bin/fatpack (lost in 0.009009 in the Module::Install -> Distar conversion) 0.009010 - 2012-09-19 - enable temp file deletion in pack.t on Win32 - RT #79489: %fatpacked keys need to be unix paths 0.009009 - 2012-08-03 - RT #78724: fix trace --to-stderr (ether) 0.009008 - 2012-07-16 - RT #78391: Avoid using $_ when requiring modules 0.009007 - 2012-07-12 - Allow capturing of trace information into return value - Add repsoitory metadata to META.YML 0.009006 - 2011-01-18 - Use File::Path's "legacy" mkpath and rmtree functions. No longer needs File::Path >= 2.07. 0.009005 - 2011-01-12 - Avoid using done_testing so this works on older systems 0.009004 - 2011-01-12 - Die if open fails in @INC handler, reduces confusing errors (DGL) - RT #63466: Add ending newline if input lacks one (GUGOD) - RT #60622: Fix conditional loading, only fatpack loaded modules (DGL) 0.009003 - 2010-07-22 - fixed dependency for File::Path(remove_tree/make_path was first appeared at 2.07) 0.009002 - 2010-07-07 - fixed typo and doc bug on command usage.(miyagawa) - added `help' command for slightly better user experience(miyagawa) 0.009001 - 2010-03-25 - Initial release App-FatPacker-0.010005/MANIFEST000644 000766 000024 00000001013 12633422416 015717 0ustar00etherstaff000000 000000 bin/fatpack Changes lib/App/FatPacker.pm lib/App/FatPacker/Trace.pm maint/Makefile.PL.include Makefile.PL MANIFEST This list of files t/basic.t t/line.t t/line/lib/line/a.pm t/line/line-test.pl t/mod/a.pm t/mod/b.pm t/mod/c.pm t/mod/cond.pm t/mod/d.pl t/mod/d.pm t/pack.t t/trace.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) README README file (added by Distar) App-FatPacker-0.010005/META.json000600 000766 000024 00000003506 12633422416 016210 0ustar00etherstaff000000 000000 { "abstract" : "pack your dependencies onto your script file", "author" : [ "mst - Matt S. Trout (cpan:MSTROUT) " ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 7.1103, CPAN::Meta::Converter version 2.150005", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "App-FatPacker", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "B" : "1.01", "Cwd" : "0", "File::Copy" : "0", "File::Find" : "0", "File::Path" : "0", "File::Spec::Functions" : "0", "File::Spec::Unix" : "0", "Getopt::Long" : "0", "perl" : "5.008000" } }, "test" : { "requires" : { "File::Basename" : "0", "File::Spec" : "0", "File::Temp" : "0", "Test::More" : "0.82" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-App-FatPacker-Metadata@rt.cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=App-FatPacker" }, "repository" : { "type" : "git", "url" : "git://git.shadowcat.co.uk/p5sagit/App-FatPacker.git", "web" : "http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/App-FatPacker.git" } }, "version" : "0.010005", "x_serialization_backend" : "JSON::PP version 2.27300" } App-FatPacker-0.010005/META.yml000600 000766 000024 00000001734 12633422416 016041 0ustar00etherstaff000000 000000 --- abstract: 'pack your dependencies onto your script file' author: - 'mst - Matt S. Trout (cpan:MSTROUT) ' build_requires: ExtUtils::MakeMaker: '0' File::Basename: '0' File::Spec: '0' File::Temp: '0' Test::More: '0.82' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 7.1103, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: App-FatPacker no_index: directory: - t - inc requires: B: '1.01' Cwd: '0' File::Copy: '0' File::Find: '0' File::Path: '0' File::Spec::Functions: '0' File::Spec::Unix: '0' Getopt::Long: '0' perl: '5.008000' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=App-FatPacker repository: git://git.shadowcat.co.uk/p5sagit/App-FatPacker.git version: '0.010005' x_serialization_backend: 'CPAN::Meta::YAML version 0.017' App-FatPacker-0.010005/Makefile.PL000644 000766 000024 00000002664 12633421552 016555 0ustar00etherstaff000000 000000 use strict; use warnings FATAL => 'all'; use ExtUtils::MakeMaker; use 5.008000; (do 'maint/Makefile.PL.include' or die $@) unless -f 'META.yml'; WriteMakefile( NAME => 'App::FatPacker', VERSION_FROM => 'lib/App/FatPacker.pm', EXE_FILES => [ 'bin/fatpack', ], META_MERGE => { 'meta-spec' => { version => '2' }, dynamic_config => 0, resources => { # r/w: p5sagit@git.shadowcat.co.uk:App-FatPacker.git repository => { url => 'git://git.shadowcat.co.uk/p5sagit/App-FatPacker.git', web => 'http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/App-FatPacker.git', type => 'git', }, bugtracker => { mailto => 'bug-App-FatPacker-Metadata@rt.cpan.org', web => 'https://rt.cpan.org/Public/Dist/Display.html?Name=App-FatPacker', }, }, prereqs => { runtime => { requires => { # B::perlstring was added in B 1.01 (perl 5.8.0) perl => '5.008000', 'B' => '1.01', 'Cwd' => '0', 'File::Copy' => '0', 'File::Find' => '0', 'File::Path' => '0', 'File::Spec::Functions' => '0', 'File::Spec::Unix' => '0', 'Getopt::Long' => '0', }, }, test => { requires => { 'File::Basename' => '0', 'File::Spec' => '0', 'File::Temp' => '0', 'Test::More' => '0.82', }, }, }, }, ); App-FatPacker-0.010005/README000600 000766 000024 00000004000 12633422416 015435 0ustar00etherstaff000000 000000 NAME App::FatPacker - pack your dependencies onto your script file SYNOPSIS $ fatpack pack myscript.pl >myscript.packed.pl Or, with more step-by-step control: $ fatpack trace myscript.pl $ fatpack packlists-for `cat fatpacker.trace` >packlists $ fatpack tree `cat packlists` $ fatpack file myscript.pl >myscript.packed.pl See the documentation for the fatpack script itself for more information. The programmatic API for this code is not yet fully decided, hence the 0.x release version. Expect that to be cleaned up for 1.0. SEE ALSO article for Perl Advent 2012 SUPPORT Bugs may be submitted through the RT bug tracker (or bug-App-FatPacker@rt.cpan.org ). You can normally also obtain assistance on irc, in #toolchain on irc.perl.org. AUTHOR Matt S. Trout (mst) CONTRIBUTORS miyagawa - Tatsuhiko Miyagawa (cpan:MIYAGAWA) tokuhirom - MATSUNO★Tokuhiro (cpan:TOKUHIROM) dg - David Leadbeater (cpan:DGL) gugod - 劉康民 (cpan:GUGOD) t0m - Tomas Doran (cpan:BOBTFISH) sawyer - Sawyer X (cpan:XSAWYERX) ether - Karen Etheridge (cpan:ETHER) Mithaldu - Christian Walde (cpan:MITHALDU) dolmen - Olivier Mengué (cpan:DOLMEN) djerius - Diab Jerius (cpan:DJERIUS) haarg - Graham Knop (cpan:HAARG> Many more people are probably owed thanks for ideas. Yet another doc nit to fix. COPYRIGHT Copyright (c) 2010 the App::FatPacker "AUTHOR" and "CONTRIBUTORS" as listed above. LICENSE This library is free software and may be distributed under the same terms as perl itself. App-FatPacker-0.010005/bin/000700 000766 000024 00000000000 12633422416 015331 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/lib/000700 000766 000024 00000000000 12633422416 015327 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/maint/000700 000766 000024 00000000000 12633422416 015671 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/t/000700 000766 000024 00000000000 12633422416 015024 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/t/basic.t000644 000766 000024 00000000166 12633421267 016312 0ustar00etherstaff000000 000000 use strict; use warnings FATAL => 'all'; use Test::More qw(no_plan); require App::FatPacker; pass "Didn't blow up"; App-FatPacker-0.010005/t/line/000700 000766 000024 00000000000 12633422416 015753 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/t/line.t000644 000766 000024 00000000735 12633421267 016162 0ustar00etherstaff000000 000000 use strict; use warnings FATAL => 'all'; use Test::More tests => 2; use File::Temp qw/tempdir/; use File::Spec; use App::FatPacker; chdir 't/line'; my $fp = App::FatPacker->new; my $temp_fh = File::Temp->new; select $temp_fh; $fp->script_command_file([ 'line-test.pl' ]); select STDOUT; close $temp_fh; # make sure we don't pick up things from our created dir chdir File::Spec->tmpdir; # Packed, now try using it. This should run the tests inside t/line/a.pm do $temp_fh; App-FatPacker-0.010005/t/mod/000700 000766 000024 00000000000 12633422416 015603 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/t/pack.t000644 000766 000024 00000003372 12633421267 016151 0ustar00etherstaff000000 000000 use strict; use warnings FATAL => 'all'; use Test::More qw(no_plan); use File::Basename; use File::Copy; use File::Path; use File::Temp qw/tempdir/; use File::Spec; use Cwd; use App::FatPacker; my $keep = $ENV{'FATPACKER_KEEP_TESTDIR'}; my $cwd = getcwd; my $tempdir = tempdir('fatpacker-XXXXX', DIR => "$cwd/t", $keep ? (CLEANUP => 0) : (CLEANUP => 1)); mkpath([<$tempdir/{lib,fatlib}/t/mod>]); for() { copy $_, "$tempdir/lib/$_" or die "copy failed: $!"; } chdir $tempdir; my $fp = App::FatPacker->new; my $packed_file = "$tempdir/script"; open my $temp_fh, '>', $packed_file or die "can't write to $packed_file: $!"; select $temp_fh; $fp->script_command_file; print "1;\n"; select STDOUT; close $temp_fh; # make sure we don't pick up things from our created dir chdir File::Spec->tmpdir; # Packed, now try using it: require $packed_file; { require t::mod::a; no warnings 'once'; ok $t::mod::a::foo eq 'bar', "packed script works"; } { ok ref $INC[0], "\$INC[0] is a reference"; ok $INC[0]->can( "files" ), "\$INC[0] has a files method"; my @files = sort $INC[0]->files; is_deeply( \@files, [ 't/mod/a.pm', 't/mod/b.pm', 't/mod/c.pm', 't/mod/cond.pm', 't/mod/d.pm', ], "\$INC[0]->files returned the files" ); } if (my $testwith = $ENV{'FATPACKER_TESTWITH'}) { for my $perl (split ' ', $testwith) { my $out = system $perl, '-e', q{alarm 5; require $ARGV[0]; require t::mod::a; exit($t::mod::a::foo eq 'bar' ? 0 : 1)}, $temp_fh; ok !$out, "packed script works with $perl"; $out = system $perl, '-e', q{alarm 5; require $ARGV[0]; exit( (sort $INC[0]->files)[0] eq 't/mod/a.pm' ? 0 : 1 )}, $temp_fh; ok !$out, "\$INC[0]->files works with $perl"; } } App-FatPacker-0.010005/t/trace.t000644 000766 000024 00000002371 12633421267 016327 0ustar00etherstaff000000 000000 use strict; use warnings FATAL => 'all'; use Test::More qw(no_plan); test_trace("t/mod/a.pm" => ("t/mod/b.pm", "t/mod/c.pm")); test_trace("t/mod/b.pm" => ("t/mod/c.pm")); test_trace("t/mod/c.pm" => ()); test_trace("t/mod/d.pl" => ("t/mod/d.pm")); # Attempts to conditionally load a module that isn't present test_trace("t/mod/cond.pm" => ()); sub test_trace { my($file, @loaded) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; unlink "fatpacker.trace"; system($^X, "-Mblib", "-MApp::FatPacker::Trace", $file); open my $trace, "<", "fatpacker.trace"; my @traced = sort map { chomp; $_ } <$trace>; close $trace; is_deeply \@traced, \@loaded, "All expected modules loaded for $file"; unlink "fatpacker.trace"; } test_trace("t/mod/a.pm" => ("t/mod/b.pm", "t/mod/c.pm")); sub test_trace_stderr { my($file, @loaded) = @_; local $Test::Builder::Level = $Test::Builder::Level + 1; system(join(' ', $^X, "-Mblib", "-MApp::FatPacker::Trace", '--to-stderr', $file, '>', 'fatpacker.trace', '2>&1')); open my $trace, "<", "fatpacker.trace"; while(<$trace>) { chomp; my $load = $_; @loaded = grep { $load ne $_ } @loaded; } ok !@loaded, "All expected modules loaded for $file"; unlink "fatpacker.trace"; } App-FatPacker-0.010005/t/mod/a.pm000644 000766 000024 00000000065 12500156416 016371 0ustar00etherstaff000000 000000 package t::mod::a; use t::mod::b; $foo = "bar"; 1; App-FatPacker-0.010005/t/mod/b.pm000644 000766 000024 00000000045 12500156416 016370 0ustar00etherstaff000000 000000 package t::mod::b; use t::mod::c; 1; App-FatPacker-0.010005/t/mod/c.pm000644 000766 000024 00000000102 12633203644 016366 0ustar00etherstaff000000 000000 package t::mod::c; sub xyz { shift() ? 666 : 999 } 1; App-FatPacker-0.010005/t/mod/cond.pm000644 000766 000024 00000000073 12500156416 017073 0ustar00etherstaff000000 000000 package t::mod::cond; eval { require t::mod::nothere }; 1; App-FatPacker-0.010005/t/mod/d.pl000644 000766 000024 00000000017 12633203644 016373 0ustar00etherstaff000000 000000 use t::mod::d; App-FatPacker-0.010005/t/mod/d.pm000644 000766 000024 00000000074 12633203644 016377 0ustar00etherstaff000000 000000 package t::mod::d; $INC{"t/mod/foreign.pm"} = __FILE__; 1; App-FatPacker-0.010005/t/line/lib/000700 000766 000024 00000000000 12633422416 016521 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/t/line/line-test.pl000644 000766 000024 00000000351 12633421456 020230 0ustar00etherstaff000000 000000 # To run this test manually: # perl -I../../lib ../../bin/fatpack file line-test.pl | perl package OurTest; use Test::More; our $main_file = __FILE__; note "File: $main_file"; # Run the tests in the packed file do 'line/a.pm'; App-FatPacker-0.010005/t/line/lib/line/000700 000766 000024 00000000000 12633422416 017450 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/t/line/lib/line/a.pm000644 000766 000024 00000000423 12500156416 020234 0ustar00etherstaff000000 000000 # This file will be included in the packed file generated by t/line.t # Check that the name is the one of the packed file is __FILE__, $main_file, '__FILE__'; # Check that the line is the one where the module code starts in the packed file is __LINE__, 14, '__LINE__'; 1; App-FatPacker-0.010005/maint/Makefile.PL.include000644 000766 000024 00000000463 12633421456 021305 0ustar00etherstaff000000 000000 BEGIN { -e 'Distar' or system("git clone git://git.shadowcat.co.uk/p5sagit/Distar.git") } use lib 'Distar/lib'; use Distar; author 'mst - Matt S. Trout (cpan:MSTROUT) '; manifest_include 'bin' => qr/.*/; manifest_include 't/mod' => qr/.*/; manifest_include 't/line' => qr/.*\.p[ml]/; App-FatPacker-0.010005/lib/App/000700 000766 000024 00000000000 12633422416 016047 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/lib/App/FatPacker/000700 000766 000024 00000000000 12633422416 017707 5ustar00etherstaff000000 000000 App-FatPacker-0.010005/lib/App/FatPacker.pm000644 000766 000024 00000023034 12633421552 020261 0ustar00etherstaff000000 000000 package App::FatPacker; use strict; use warnings FATAL => 'all'; use 5.008001; use Getopt::Long; use Cwd qw(cwd); use File::Find qw(find); use File::Spec::Functions qw( catdir splitpath splitdir catpath rel2abs abs2rel ); use File::Spec::Unix; use File::Copy qw(copy); use File::Path qw(mkpath rmtree); use B qw(perlstring); our $VERSION = '0.010005'; # 0.10.5 $VERSION = eval $VERSION; sub call_parser { my $self = shift; my ($args, $options) = @_; local *ARGV = [ @{$args} ]; $self->{option_parser}->getoptions(@$options); return [ @ARGV ]; } sub lines_of { map +(chomp,$_)[1], do { local @ARGV = ($_[0]); <> }; } sub stripspace { my ($text) = @_; $text =~ /^(\s+)/ && $text =~ s/^$1//mg; $text; } sub import { $_[1] && $_[1] eq '-run_script' and return shift->new->run_script; } sub new { bless { option_parser => Getopt::Long::Parser->new( config => [ qw(require_order pass_through bundling no_auto_abbrev) ] ), }, $_[0]; } sub run_script { my ($self, $args) = @_; my @args = $args ? @$args : @ARGV; (my $cmd = shift @args || 'help') =~ s/-/_/g; if (my $meth = $self->can("script_command_${cmd}")) { $self->$meth(\@args); } else { die "No such command ${cmd}"; } } sub script_command_help { print "Try `perldoc fatpack` for how to use me\n"; } sub script_command_pack { my ($self, $args) = @_; my @modules = split /\r?\n/, $self->trace(args => $args); my @packlists = $self->packlists_containing(\@modules); my $base = catdir(cwd, 'fatlib'); $self->packlists_to_tree($base, \@packlists); my $file = shift @$args; print $self->fatpack_file($file); } sub script_command_trace { my ($self, $args) = @_; $args = $self->call_parser($args => [ 'to=s' => \my $file, 'to-stderr' => \my $to_stderr, 'use=s' => \my @additional_use ]); die "Can't use to and to-stderr on same call" if $file && $to_stderr; $file ||= 'fatpacker.trace'; if (!$to_stderr and -e $file) { unlink $file or die "Couldn't remove old trace file: $!"; } my $arg = do { if ($to_stderr) { ">&STDERR" } elsif ($file) { ">>${file}" } }; $self->trace( use => \@additional_use, args => $args, output => $arg, ); } sub trace { my ($self, %opts) = @_; my $output = $opts{output}; my $trace_opts = join ',', $output||'>&STDOUT', @{$opts{use}||[]}; local $ENV{PERL5OPT} = join ' ', ($ENV{PERL5OPT}||()), '-MApp::FatPacker::Trace='.$trace_opts; my @args = @{$opts{args}||[]}; if ($output) { # user specified output target, JFDI system $^X, @args; return; } else { # no output target specified, slurp open my $out_fh, "$^X @args |"; return do { local $/; <$out_fh> }; } } sub script_command_packlists_for { my ($self, $args) = @_; foreach my $pl ($self->packlists_containing($args)) { print "${pl}\n"; } } sub packlists_containing { my ($self, $targets) = @_; my @targets = @$targets; { local @INC = ('lib', @INC); foreach my $t (@targets) { require $t; } } my @search = grep -d $_, map catdir($_, 'auto'), @INC; my %pack_rev; find({ no_chdir => 1, wanted => sub { return unless /[\\\/]\.packlist$/ && -f $_; $pack_rev{$_} = $File::Find::name for lines_of $File::Find::name; }, }, @search); my %found; @found{map +($pack_rev{Cwd::abs_path($INC{$_})}||()), @targets} = (); sort keys %found; } sub script_command_tree { my ($self, $args) = @_; my $base = catdir(cwd,'fatlib'); $self->packlists_to_tree($base, $args); } sub packlists_to_tree { my ($self, $where, $packlists) = @_; rmtree $where; mkpath $where; foreach my $pl (@$packlists) { my ($vol, $dirs, $file) = splitpath $pl; my @dir_parts = splitdir $dirs; my $pack_base; PART: foreach my $p (0 .. $#dir_parts) { if ($dir_parts[$p] eq 'auto') { # $p-2 since it's /$Config{archname}/auto $pack_base = catpath $vol, catdir @dir_parts[0..$p-2]; last PART; } } die "Couldn't figure out base path of packlist ${pl}" unless $pack_base; foreach my $source (lines_of $pl) { # there is presumably a better way to do "is this under this base?" # but if so, it's not obvious to me in File::Spec next unless substr($source,0,length $pack_base) eq $pack_base; my $target = rel2abs( abs2rel($source, $pack_base), $where ); my $target_dir = catpath((splitpath $target)[0,1]); mkpath $target_dir; copy $source => $target; } } } sub script_command_file { my ($self, $args) = @_; my $file = shift @$args; print $self->fatpack_file($file); } sub fatpack_file { my ($self, $file) = @_; my $shebang = ""; my $script = ""; if ( defined $file and -r $file ) { ($shebang, $script) = $self->load_main_script($file); } my @dirs = $self->collect_dirs(); my %files; $self->collect_files($_, \%files) for @dirs; return join "\n", $shebang, $self->fatpack_code(\%files), $script; } # This method can be overload in sub classes # For example to skip POD sub load_file { my ($self, $file) = @_; my $content = do { local (@ARGV, $/) = ($file); <> }; close ARGV; return $content; } sub collect_dirs { my ($self) = @_; my $cwd = cwd; return grep -d, map rel2abs($_, $cwd), ('lib','fatlib'); } sub collect_files { my ($self, $dir, $files) = @_; find(sub { return unless -f $_; !/\.pm$/ and warn "File ${File::Find::name} isn't a .pm file - can't pack this -- if you hoped we were going to, things may not be what you expected later\n" and return; $files->{File::Spec::Unix->abs2rel($File::Find::name,$dir)} = $self->load_file($File::Find::name); }, $dir); } sub load_main_script { my ($self, $file) = @_; open my $fh, "<", $file or die("Can't read $file: $!"); my $shebang = <$fh>; my $script = join "", <$fh>; close $fh; unless ( index($shebang, '#!') == 0 ) { $script = $shebang . $script; $shebang = ""; } return ($shebang, $script); } sub fatpack_start { return stripspace <<' END_START'; # This chunk of stuff was generated by App::FatPacker. To find the original # file's code, look for the end of this BEGIN block or the string 'FATPACK' BEGIN { my %fatpacked; END_START } sub fatpack_end { return stripspace <<' END_END'; s/^ //mg for values %fatpacked; my $class = 'FatPacked::'.(0+\%fatpacked); no strict 'refs'; *{"${class}::files"} = sub { keys %{$_[0]} }; if ($] < 5.008) { *{"${class}::INC"} = sub { if (my $fat = $_[0]{$_[1]}) { my $pos = 0; my $last = length $fat; return (sub { return 0 if $pos == $last; my $next = (1 + index $fat, "\n", $pos) || $last; $_ .= substr $fat, $pos, $next - $pos; $pos = $next; return 1; }); } }; } else { *{"${class}::INC"} = sub { if (my $fat = $_[0]{$_[1]}) { open my $fh, '<', \$fat or die "FatPacker error loading $_[1] (could be a perl installation issue?)"; return $fh; } return; }; } unshift @INC, bless \%fatpacked, $class; } # END OF FATPACK CODE END_END } sub fatpack_code { my ($self, $files) = @_; my @segments = map { (my $stub = $_) =~ s/\.pm$//; my $name = uc join '_', split '/', $stub; my $data = $files->{$_}; $data =~ s/^/ /mg; $data =~ s/(?fatpack_start, @segments, $self->fatpack_end; } =encoding UTF-8 =head1 NAME App::FatPacker - pack your dependencies onto your script file =head1 SYNOPSIS $ fatpack pack myscript.pl >myscript.packed.pl Or, with more step-by-step control: $ fatpack trace myscript.pl $ fatpack packlists-for `cat fatpacker.trace` >packlists $ fatpack tree `cat packlists` $ fatpack file myscript.pl >myscript.packed.pl See the documentation for the L script itself for more information. The programmatic API for this code is not yet fully decided, hence the 0.x release version. Expect that to be cleaned up for 1.0. =head1 SEE ALSO L
=head1 SUPPORT Bugs may be submitted through L (or L). You can normally also obtain assistance on irc, in #toolchain on irc.perl.org. =head1 AUTHOR Matt S. Trout (mst) =head2 CONTRIBUTORS miyagawa - Tatsuhiko Miyagawa (cpan:MIYAGAWA) tokuhirom - MATSUNO★Tokuhiro (cpan:TOKUHIROM) dg - David Leadbeater (cpan:DGL) gugod - 劉康民 (cpan:GUGOD) t0m - Tomas Doran (cpan:BOBTFISH) sawyer - Sawyer X (cpan:XSAWYERX) ether - Karen Etheridge (cpan:ETHER) Mithaldu - Christian Walde (cpan:MITHALDU) dolmen - Olivier Mengué (cpan:DOLMEN) djerius - Diab Jerius (cpan:DJERIUS) haarg - Graham Knop (cpan:HAARG> Many more people are probably owed thanks for ideas. Yet another doc nit to fix. =head1 COPYRIGHT Copyright (c) 2010 the App::FatPacker L and L as listed above. =head1 LICENSE This library is free software and may be distributed under the same terms as perl itself. =cut 1; App-FatPacker-0.010005/lib/App/FatPacker/Trace.pm000644 000766 000024 00000006302 12633203644 021316 0ustar00etherstaff000000 000000 package App::FatPacker::Trace; use strict; use warnings FATAL => 'all'; use B (); my $trace_file; my %initial_inc; sub import { my (undef, $file, @extras) = @_; $trace_file = $file || '>>fatpacker.trace'; # For filtering out our own deps later. # (Not strictly required as these are core only and won't have packlists, but # looks neater.) %initial_inc = %INC; # Use any extra modules specified eval "use $_" for @extras; B::minus_c; } CHECK { return unless $trace_file; # not imported open my $trace, $trace_file or die "Couldn't open $trace_file to trace to: $!"; for my $inc (keys %INC) { next if exists $initial_inc{$inc}; next unless $INC{$inc} =~ /\Q${inc}\E\Z/; print $trace "$inc\n"; } } 1; __END__ =head1 NAME App::FatPacker::Trace - Tracing module usage using compilation checking =head1 SYNOPSIS # open STDERR for writing # will be like: open my $fh, '>', '&STDERR'... perl -MApp::FatPacker::Trace=>&STDERR myscript.pl # open a file for writing # will be like: open my $fh, '>>', 'fatpacker.trace' perl -MApp::FatPacker::Trace=>>fatpacker.trace myscript.pl =head1 DESCRIPTION This module allows tracing the modules being used by your code. It does that using clever trickery using the C method, the C block and L's C function. When App::FatPacker::Trace is being used, the import() method will call C in order to set up the global compilation-only flag perl (the interpreter) has. This will prevent any other code from being run. Then in the C block which is reached at the end of the compilation phase (see L), it will gather all modules that have been loaded, using C<%INC>, and will write it to a file or to STDERR, determined by parameters sent to the C method. =head1 METHODS =head2 import This method gets run when you just load L. It will note the current C<%INC> and will set up the output to be written to, and raise the compilation-only flag, which will prevent anything from being run past that point. This flag cannot be unset, so this is most easily run from the command line as such: perl -MApp::FatPacker::Trace [...] You can control the parameters to the import using an equal sign, as such: # send the parameter "hello" perl -MApp::FatPacker::Trace=hello [...] # send the parameter ">&STDERR" perl -MApp::FatPacker::Trace=>&STDERR [...] The import method accepts a first parameter telling it which output to open and how. These are both sent in a single parameter. # append to mytrace.txt perl -MApp::FatPacker::Trace=>>mytrace.txt myscript.pl # write to STDERR perl -MApp::FatPacker::Trace=>&STDERR myscript.pl The import method accepts additional parameters of extra modules to load. It will then add these modules to the trace. This is helpful if you want to explicitly indicate additional modules to trace, even if they aren't used in your script. Perhaps you're conditionally using them, perhaps they're for additional features, perhaps they're loaded lazily, whatever the reason. # Add Moo to the trace, even if you don't trace it in myscript.pl perl -MApp::FatPacker::Trace=>&STDERR,Moo myscript.pl App-FatPacker-0.010005/bin/fatpack000755 000766 000024 00000004622 12633421456 016711 0ustar00etherstaff000000 000000 #!/usr/bin/env perl use App::FatPacker -run_script; =head1 NAME fatpack - Command line frontend for App::FatPacker =head1 COMMANDS =head2 pack $ fatpack pack myscript.pl > myscript.packed.pl A shortcut to do all the work of tracing, collecting packlists, extracting modules in fatlib, then concatenating into a packed script - in one shot. If you need more detailed controls for additional modules, use the following commands separately (see L). =head2 trace $ fatpack trace [--to=trace-file|--to-stderr] [--use=MODULE] myscript.pl Compiles myscript.pl (as in "perl -c") and writes out a trace file containing every module require()d during the compilation. The trace file is called 'fatpacker.trace' by default; the --to option overrides this. If you pass --to-stderr fatpack writes the trace to STDERR instead. You cannot pass both --to and --to-stderr. If the --use option specifies a module (or modules, if used multiple times) those modules will be additionally included in the trace output. =head2 packlists-for $ fatpack packlists-for Module1 Module2 Module3 Searches your perl's @INC for .packlist files containing the .pm files for the modules requested and emits a list of unique packlist files to STDOUT. These packlists will, in a pure cpan-installation environment, be all non-core distributions required for those modules. Unfortunately most vendors strip the .packlist files so if you installed modules via e.g. apt-get you may be missing those modules; installing your dependencies into a L first is the preferred workaround. =head2 tree $ fatpack tree fatlib packlist1 packlist2 packlist3 Takes a list of packlist files and copies their contents into a tree at the requested location. This tree should be sufficient to 'use lib' to make available all modules provided by the distributions whose packlists were specified. =head2 file $ fatpack file Recurses into the 'lib' and 'fatlib' directories and bundles all .pm files found into a BEGIN block which adds a virtual @INC entry to load these files from the bundled code rather than disk. =head1 RECIPES Current basic recipe for packing: $ fatpack trace myscript.pl $ fatpack packlists-for `cat fatpacker.trace` >packlists $ fatpack tree `cat packlists` $ fatpack file myscript.pl >myscript.packed.pl =head1 COPYRIGHT, LICENSE, AUTHOR See the corresponding sections in L. =cut