--- /dev/null
+#!/usr/bin/env perl
+
+# This script creates a fatpacked version of homebank2ledger. Much of this code was inspired by or
+# blatantly copied from cpanminus build scripts, written by Tatsuhiko Miyagawa.
+
+use warnings FATAL => 'all';
+use strict;
+use autodie ':all';
+
+use App::FatPacker ();
+use Cwd;
+use File::Find;
+use File::Path;
+use File::pushd;
+use Module::CoreList;
+
+
+my $distdir = shift;
+
+my $script_name = 'bin/homebank2ledger';
+my $libdir = 'lib';
+
+if ($distdir) {
+ if (-d "$distdir/blib") {
+ $script_name = "$distdir/blib/script/homebank2ledger";
+ $libdir = "$distdir/blib/lib";
+ }
+ else {
+ $script_name = "$distdir/$script_name";
+ $libdir = "$distdir/$libdir";
+ }
+}
+
+make_fatlib();
+make_script();
+exit;
+
+
+BEGIN {
+ # IO::Socket::IP requires newer Socket, which is C-based
+ $ENV{PERL_HTTP_TINY_IPV4_ONLY} = 1;
+}
+
+END {
+ no autodie;
+ unlink('homebank2ledger.tmp');
+ rmtree('.fatpack-build');
+ rmtree('fatlib');
+}
+
+
+sub find_requires {
+ my $file = shift;
+
+ my %requires;
+ open my $in, "<", $file;
+ while (<$in>) {
+ /^\s*(?:use|require) (\S+)[^;]*;\s*$/
+ and $requires{$1} = 1;
+ }
+
+ keys %requires;
+}
+
+sub mod_to_pm {
+ local $_ = shift;
+ s!::!/!g;
+ "$_.pm";
+}
+
+sub pm_to_mod {
+ local $_ = shift;
+ s!/!::!g;
+ s/\.pm$//;
+ $_;
+}
+
+sub in_lib {
+ my $file = shift;
+ -e "$libdir/$file";
+}
+
+sub is_core {
+ my $module = shift;
+ exists $Module::CoreList::version{5.008001}{$module};
+}
+
+sub exclude_modules {
+ my($modules, $except) = @_;
+ my %exclude = map { $_ => 1 } @$except;
+ [ grep !$exclude{$_}, @$modules ];
+}
+
+sub pack_modules {
+ my($path, $modules, $no_trace) = @_;
+
+ $modules = exclude_modules($modules, $no_trace);
+
+ my $packer = App::FatPacker->new;
+ my @requires = grep !is_core(pm_to_mod($_)), grep /\.pm$/, split /\n/,
+ $packer->trace(use => $modules, args => ['-e', 1]);
+ push @requires, map mod_to_pm($_), @$no_trace;
+
+ my @packlists = $packer->packlists_containing(\@requires);
+ for my $packlist (@packlists) {
+ print "Packing $packlist\n";
+ }
+ $packer->packlists_to_tree($path, \@packlists);
+}
+
+sub make_fatlib {
+ my @modules = grep !in_lib(mod_to_pm($_)), find_requires($script_name);
+
+ pack_modules(cwd . '/fatlib', \@modules, []);
+
+ use Config;
+ print "Remove fatlib/$Config{archname}\n";
+ rmtree("fatlib/$Config{archname}");
+ rmtree("fatlib/POD2");
+
+ my $want = sub {
+ if (/\.pod$/) {
+ print "Remove $_\n";
+ unlink $_;
+ }
+ };
+
+ find({ wanted => $want, no_chdir => 1 }, 'fatlib');
+}
+
+
+sub generate_file {
+ my($base, $target, $fatpack) = @_;
+
+ open my $in, "<", $base;
+ open my $out, ">", "$target.tmp";
+
+ print STDERR "Generating $target from $base\n";
+
+ while (<$in>) {
+ s|^#!\h*perl|#!/usr/bin/env perl|;
+ s|^# FATPACK.*|$fatpack|;
+ print $out $_;
+ }
+
+ close $out;
+
+ eval { unlink $target };
+ rename "$target.tmp", $target;
+}
+
+sub make_script {
+ mkdir '.fatpack-build';
+ system qw(cp -r fatlib), $libdir, qw(.fatpack-build/);
+
+ my $fatpack_compact = do {
+ my $dir = pushd '.fatpack-build';
+
+ my @files;
+ my $want = sub {
+ push @files, $_ if /\.pm$/;
+ if (/\.pod$/) {
+ print "Remove $_\n";
+ unlink $_;
+ }
+ };
+
+ find({ wanted => $want, no_chdir => 1 }, 'fatlib', 'lib');
+ system qw(perlstrip --cache -v), @files;
+
+ `fatpack file`;
+ };
+
+ my $filename = $script_name;
+ $filename =~ s!^.*/!!;
+
+ generate_file($script_name, $filename, $fatpack_compact);
+ chmod 0755, $filename;
+}
+