use Cwd qw(cwd);
use File::Find qw(find);
use File::Spec::Functions qw(
- catdir splitpath splitdir catpath rel2abs abs2rel
+ catdir catfile 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.009010'; # 0.9.10
+our $VERSION = '0.009018'; # 0.009.017
$VERSION = eval $VERSION;
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) = @_;
sub trace {
my ($self, %opts) = @_;
- my $capture;
-
- my $output = $opts{output} || do {
- $capture++; '>&STDOUT'
- };
-
+ my $output = $opts{output};
my $trace_opts = join ',', $output||'>&STDOUT', @{$opts{use}||[]};
local $ENV{PERL5OPT} = '-MApp::FatPacker::Trace='.$trace_opts;
return;
} else {
# no output target specified, slurp
- open my $out_fh, '-|', $^X, @args;
+ open my $out_fh, "$^X @args |";
return do { local $/; <$out_fh> };
}
}
}
my @search = grep -d $_, map catdir($_, 'auto'), @INC;
my %pack_rev;
- my $cwd = cwd;
- find(sub {
- return unless $_ eq '.packlist' && -f $_;
- $pack_rev{$_} = $File::Find::name for lines_of $File::Find::name;
+ find({
+ no_chdir => 1,
+ wanted => sub {
+ return unless /[\\\/]\.packlist$/ && -f $_;
+ $pack_rev{$_} = $File::Find::name for lines_of $File::Find::name;
+ },
}, @search);
- chdir($cwd) or die "Couldn't chdir back to ${cwd} after find: $!";
- my %found; @found{map +($pack_rev{$INC{$_}}||()), @targets} = ();
+ my %found; @found{map +($pack_rev{Cwd::abs_path($INC{$_})}||()), @targets} = ();
sort keys %found;
}
my ($self, $where, $packlists) = @_;
rmtree $where;
mkpath $where;
+ # Build a copy of @INC with dir separator added after each path
+ my @inc = map
+ { catfile($_, '') }
+ @INC;
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 <wanted path>/$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) {
+ my $base;
+ foreach my $inc_base (@inc) {
+ # XXX Not case-proof (for case ignorant filesystems)
+ if (substr($source,0,length $inc_base) eq $inc_base) {
+ $base = $inc_base;
+ last;
+ }
+ }
+ unless ($base) {
+ die "Couldn't figure out \@INC path of ${source}" if substr($source, -3) eq '.pm';
+ next;
+ }
+
# 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 = rel2abs( abs2rel($source, $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 $cwd = cwd;
- my @dirs = map rel2abs($_, $cwd), ('lib','fatlib');
+ my @dirs = grep -d, map rel2abs($_, $cwd), ('lib','fatlib');
my %files;
foreach my $dir (@dirs) {
find(sub {
return unless -f $_;
- !/\.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;
+ !/\.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)} = do {
local (@ARGV, $/) = ($File::Find::name); <>
};
unshift @INC, sub {
if (my $fat = $fatpacked{$_[1]}) {
+ if ($] < 5.008) {
+ return sub {
+ return 0 unless length $fat;
+ $fat =~ s/^([^\n]*\n?)//;
+ $_ = $1;
+ return 1;
+ };
+ }
open my $fh, '<', \$fat
or die "FatPacker error loading $_[1] (could be a perl installation issue?)";
return $fh;
'$fatpacked{'.perlstring($_).qq!} = <<'${name}';\n!
.qq!${data}${name}\n!;
} sort keys %files;
- print join "\n", $start, @segments, $end;
+ my $shebang = "";
+ my $script = "";
+ if ( defined $file and -r $file ) {
+ open my $fh, "<", $file or die("Can't read $file: $!");
+ $shebang = <$fh>;
+ $script = join "", <$fh>;
+ close $fh;
+ unless ( index($shebang, '#!') == 0 ) {
+ $script = $shebang . $script;
+ $shebang = "";
+ }
+ }
+ return join "\n", $shebang, $start, @segments, $end, $script;
}
=encoding UTF-8
=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; cat myscript.pl) >myscript.packed.pl
+ $ fatpack file myscript.pl >myscript.packed.pl
See the documentation for the L<fatpack> script itself for more information.
The programmatic API for this code is not yet fully decided, hence the 0.9
release version. Expect that to be cleaned up for 1.0.
+=head1 SEE ALSO
+
+L<article for Perl Advent 2012|http://www.perladvent.org/2012/2012-12-14.html>
+
=head1 SUPPORT
Your current best avenue is to come annoy annoy mst on #toolchain on