Hello List,
I am maintaining a perl/Tk database app and use PAR::Packer to create binaries.
Works perfect on Linux/ MacOS /Windows - thanks for a great tool.
There are a lot of dependencies in my app therefore the packing takes some
minutes. Now I was making up my mind about the possibility to add a dependencies
cache - most of the time my dependencies do not change - and just tried it.
It's a quick hack: uses Storable to store/retrieve state inside the
pack_manifest_hash method. However it works and I'd like to share it here, maybe
as a feature suggestion rather than a patch...
It speeds packing up from minutes to seconds in my case.
Btw sorry: Diff is against $VERSION = '0.982' I didn't check before I started...
Cheers, Christoph
--- C:\Dokumente und Einstellungen\chris\Desktop\oper_wc\PAR\Packer-ori.pm
Di Jul 29 17:36:44 2008
+++ C:\Dokumente und Einstellungen\chris\Desktop\oper_wc\PAR\Packer.pm Fr Jun
26 01:22:32 2009
@@ -33,6 +33,7 @@
use File::Spec ();
use File::Temp ();
use Module::ScanDeps ();
+use Storable;
use PAR ();
use PAR::Filter ();
@@ -69,6 +70,8 @@
'vv|verbose2', => 'Verbosity level 2',
'vvv|verbose3', => 'Verbosity level 3',
'z|compress:i' => 'Compression level',
+ 'D|savedeps:s' => 'Save detected dependencies to a file',
+ 'U|usedeps:s' => 'Read dependencies from a file',
};
my $ValidOptions = {};
@@ -453,7 +456,7 @@
my $opt = $self->{options};
my $par_file = $self->get_par_file();
-
+
$self->_add_pack_manifest();
$self->_add_add_manifest();
$self->_make_manifest();
@@ -470,7 +473,6 @@
sub _write_zip {
my ($self) = @_;
-
my $old_member = $self->{pack_attrib}{old_member};
my $oldsize = $self->{pack_attrib}{old_size};
my $par_file = $self->{par_file};
@@ -538,7 +540,6 @@
sub _make_manifest {
my ($self) = @_;
-
my $full_manifest = $self->{full_manifest};
my $opt = $self->{options};
@@ -665,100 +666,127 @@
my $par_file = $self->{par_file};
my (@modules, @data, @exclude);
- foreach my $name (@{ $opt->{M} || [] }) {
- $self->_name2moddata($name, \...@modules, \...@data);
- }
+ my %map;
+ my %text;
+
+ if ($opt->{usedeps}) {
+ my $file = $opt->{usedeps};
+ my $stored = retrieve($file)
+ or die "Couldn't retrieve from file[$file]\n";
+ my ($stored_obj,$stored_data) = @$stored;
+ my $pack_attrib = delete $stored_obj->{pack_attrib};
+ # compare deeply here and croak if settings differ?
+ for my $slot (qw/text
+ map
+ shared_libs
+ /) {
+ $self->{pack_attrib}{$slot} = $pack_attrib->{$slot};
+ }
+ %map = %{$pack_attrib->{map}};
+ %text = %{$pack_attrib->{text}};
+ @SharedLibs = @{$pack_attrib->{shared_libs}};
+ @data = @$stored_data;
+ } else {
+
+ foreach my $name (@{ $opt->{M} || [] }) {
+ $self->_name2moddata($name, \...@modules, \...@data);
+ }
- # Skip either
- # a) all files from a .par file or
- # b) A module
- foreach my $name ('PAR', @{ $opt->{X} || [] }) {
- if (-f $name and my $dep_zip = Archive::Zip->new($name)) {
- for ($dep_zip->memberNames()) {
- next if ( /MANIFEST/ or /META.yml/ or /^script\// );
- $dep_zip_files{$_} ||= $name;
+ # Skip either
+ # a) all files from a .par file or
+ # b) A module
+ foreach my $name ('PAR', @{ $opt->{X} || [] }) {
+ if (-f $name and my $dep_zip = Archive::Zip->new($name)) {
+ for ($dep_zip->memberNames()) {
+ next if ( /MANIFEST/ or /META.yml/ or /^script\// );
+ $dep_zip_files{$_} ||= $name;
+ }
+ } else {
+ $self->_name2moddata($name, \...@exclude, \...@exclude);
}
}
- else {
- $self->_name2moddata($name, \...@exclude, \...@exclude);
- }
- }
- my %map;
+
+ unshift(@INC, @{ $opt->{I} || [] });
+ unshift(@SharedLibs,
+ map $self->_find_shlib($_, $sn), @{ $opt->{l} || [] });
- unshift(@INC, @{ $opt->{I} || [] });
- unshift(@SharedLibs, map $self->_find_shlib($_, $sn), @{ $opt->{l} || []
});
+ my $inc_find = $self->_obj_function($fe, '_find_in_inc');
- my $inc_find = $self->_obj_function($fe, '_find_in_inc');
+ my %skip = map { $_, 1 } map &$inc_find($_), @exclude;
+ if ($^O eq 'MSWin32') {
+ %skip = (%skip, map { s{\\}{/}g; lc($_), 1 } @SharedLibs);
+ } else {
+ %skip = (%skip, map { $_, 1 } @SharedLibs);
+ }
- my %skip = map { $_, 1 } map &$inc_find($_), @exclude;
- if ($^O eq 'MSWin32') {
- %skip = (%skip, map { s{\\}{/}g; lc($_), 1 } @SharedLibs);
- }
- else {
- %skip = (%skip, map { $_, 1 } @SharedLibs);
- }
+ my $add_deps = $self->_obj_function($fe, 'add_deps');
- my $add_deps = $self->_obj_function($fe, 'add_deps');
-
- my @files; # files to scan
- # Apply %Preload to the -M'd modules and add them to the list of
- # files to scan
- foreach my $module (@modules) {
- my $file = &$inc_find($module);
- push @files, $file;
+ my @files; # files to scan
+ # Apply %Preload to the -M'd modules and add them to the list of
+ # files to scan
+ foreach my $module (@modules) {
+ my $file = &$inc_find($module);
+ push @files, $file;
- my $preload = Module::ScanDeps::_get_preload($module) or next;
+ my $preload = Module::ScanDeps::_get_preload($module) or next;
- $add_deps->(
- used_by => $file,
- rv => \%map,
- modules => $preload,
- skip => \%skip,
-# warn_missing => $args->{warn_missing},
- );
- push @files, map {&$inc_find($_)} @$preload;
- }
- push @files, @$input;
+ $add_deps->(
+ used_by => $file,
+ rv => \%map,
+ modules => $preload,
+ skip => \%skip,
+ # warn_missing => $args->{warn_missing},
+ );
+ push @files, map {&$inc_find($_)} @$preload;
+ }
+ push @files, @$input;
- # Search for scannable code in all -I'd paths
- push @Module::ScanDeps::IncludeLibs, @{$opt->{I}} if $opt->{I};
+ # Search for scannable code in all -I'd paths
+ push @Module::ScanDeps::IncludeLibs, @{$opt->{I}} if $opt->{I};
- my $scan_dispatch =
- $opt->{n}
- ? $self->_obj_function($fe, 'scan_deps_runtime')
- : $self->_obj_function($fe, 'scan_deps');
+ my $scan_dispatch =
+ $opt->{n}
+ ? $self->_obj_function($fe, 'scan_deps_runtime')
+ : $self->_obj_function($fe, 'scan_deps');
- $scan_dispatch->(
- rv => \%map,
- files => \...@files,
- execute => $opt->{x},
- compile => $opt->{c},
- skip => \%skip,
- ($opt->{n}) ? () : (
- recurse => 1,
- first => 1,
- ),
- );
+ $scan_dispatch->(
+ rv => \%map,
+ files => \...@files,
+ execute => $opt->{x},
+ compile => $opt->{c},
+ skip => \%skip,
+ ($opt->{n}) ? () : (
+ recurse => 1,
+ first => 1,
+ ),
+ );
- %skip = map { $_, 1 } map &$inc_find($_), @exclude;
- %skip = (%skip, map { $_, 1 } @SharedLibs);
+ %skip = map { $_, 1 } map &$inc_find($_), @exclude;
+ %skip = (%skip, map { $_, 1 } @SharedLibs);
- &$add_deps(
- rv => \%map,
- modules => \...@modules,
- skip => \%skip,
- );
+ &$add_deps(
+ rv => \%map,
+ modules => \...@modules,
+ skip => \%skip,
+ );
- my %text;
- $text{$_} = ($map{$_}{type} =~ /^(?:module|autoload)$/) for keys %map;
- $map{$_} = $map{$_}{file} for keys %map;
+ $text{$_} = ($map{$_}{type} =~ /^(?:module|autoload)$/) for keys %map;
+ $map{$_} = $map{$_}{file} for keys %map;
- $self->{pack_attrib}{text} = \%text;
- $self->{pack_attrib}{map} = \%map;
- $self->{pack_attrib}{shared_libs} = \...@sharedlibs;
+ $self->{pack_attrib}{text} = \%text;
+ $self->{pack_attrib}{map} = \%map;
+ $self->{pack_attrib}{shared_libs} = \...@sharedlibs;
+ #print Dumper \%text, \%map, \...@sharedlibs, \%skip;
+ if ($opt->{savedeps}) {
+ my $file = $opt->{savedeps};
+ store([$self,\...@data], $file)
+ or die "Can't store $self in file [$file\\n";
+ }
+ }
+
my $size = 0;
my $old_member;