add fatpacker script
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Tue, 3 Sep 2019 01:37:33 +0000 (19:37 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Tue, 3 Sep 2019 01:58:29 +0000 (19:58 -0600)
bin/homebank2ledger
dist.ini
maint/branch_solo.pl [new file with mode: 0755]
maint/fatpack.pl [new file with mode: 0755]

index 1139928ea98c30dd8b8bdc86ef4f5a94e3903f09..03d710f5a287e31ef359a1fca839f5849cac15e1 100644 (file)
 
 =head1 DESCRIPTION
 
-C<homebank2ledger> converts L<HomeBank|http://homebank.free.fr/> files to a format usable by
+F<homebank2ledger> converts L<HomeBank|http://homebank.free.fr/> files to a format usable by
 L<Ledger|https://www.ledger-cli.org/>. It can also convert directly to the similar
 L<Beancount|http://furius.ca/beancount/> format.
 
 This software is B<EXPERIMENTAL>, in early development. Its interface may change without notice.
 
-I wrote C<homebank2ledger> because I have been maintaining my own personal finances using HomeBank
+I wrote F<homebank2ledger> because I have been maintaining my own personal finances using HomeBank
 (which is awesome) and I wanted to investigate using plain text accounting programs. It works well
 enough for my data, but you may be using HomeBank features that I don't so there may be cases this
 doesn't handle well or at all. Feel free to file a bug report. This script does NOT try to modify
@@ -45,6 +45,43 @@ You can migrate the data you have in HomeBank so you can start maintaining your
 Or if you don't plan to switch completely off of HomeBank, you can continue to maintain your
 accounts in HomeBank and use this script to also take advantage of the reports Ledger offers.
 
+=head1 INSTALL
+
+There are several ways to install F<homebank2ledger> to your system.
+
+=head2 using cpanm
+
+You can install F<homebank2ledger> using L<cpanm>. If you have a local perl (plenv, perlbrew, etc.),
+you can just do:
+
+    cpanm App::Homebank2Ledger
+
+to install the F<homebank2ledger> executable and its dependencies. The executable will be installed
+to your perl's bin path, like F<~/perl5/perlbrew/bin/homebank2ledger>.
+
+If you're installing to your system perl, you can do:
+
+    cpanm --sudo App::Homebank2Ledger
+
+to install the F<homebank2ledger> executable to a system directory, like
+F</usr/local/bin/homebank2ledger> (depending on your perl).
+
+=head2 Downloading just the executable
+
+You may also choose to download F<homebank2ledger> as a single executable, like this:
+
+    curl -OL https://raw.githubusercontent.com/chazmcgarvey/homebank2ledger/solo/homebank2ledger
+    chmod +x homebank2ledger
+
+=head2 For developers
+
+If you're a developer and want to hack on the source, clone the repository and pull the
+dependencies:
+
+    git clone https://github.com/chazmcgarvey/homebank2ledger.git
+    cd homebank2ledger
+    make bootstrap      # installs dependencies; requires cpanm
+
 =head1 OPTIONS
 
 =head2 --version
@@ -135,7 +172,7 @@ Date must be in the form "YYYY-MM-DD". Defaults to the date of the first transac
 
 =head2 --rename-account STR
 
-Specifies a mapping for renaming accounts in the output. By default C<homebank2ledger> tries to come
+Specifies a mapping for renaming accounts in the output. By default F<homebank2ledger> tries to come
 up with sensible account names (based on your HomeBank accounts and categories) that fit into five
 root accounts:
 
@@ -213,6 +250,8 @@ it's just plain text.
 
 =cut
 
+# FATPACK - Do not remove this line.
+
 use warnings;
 use strict;
 
index 32568d3541253e4a08d29eb1f2fc876d322c5ed5..1e774fc8a24280bca781d3c8fd0b5d1989832506 100644 (file)
--- a/dist.ini
+++ b/dist.ini
@@ -7,9 +7,13 @@ copyright_year      = 2019
 license             = MIT
 
 [@Filter]
--bundle         = @Author::CCM
--remove         = Test::CleanNamespaces
-max_target_perl = 5.14
+-bundle             = @Author::CCM
+-remove             = Test::CleanNamespaces
+max_target_perl     = 5.14
+PruneFiles.filename = maint
+
+[Run::Release]
+run                 = %x maint%pbranch_solo.pl %v %d
 
 [ConsistentVersionTest]
 
diff --git a/maint/branch_solo.pl b/maint/branch_solo.pl
new file mode 100755 (executable)
index 0000000..c9eed65
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/env perl
+
+# This script prepares the homebank2ledger script for standalone use and puts it in a new branch.
+
+use strict;
+use warnings;
+use autodie;
+
+use File::Copy;
+use File::Path qw(make_path remove_tree);
+use String::ShellQuote;
+
+
+my $version = shift or die 'Need version';
+my $distdir = shift or die 'Need distdir';
+
+my $branch_name = 'solo';
+my $script_name = 'homebank2ledger';
+
+my $branch_oldref = '';
+my $branch_oldref_origin = '';
+
+open(my $fh, '-|', qw{git show-ref}, $branch_name);
+while (my $line = <$fh>) {
+    chomp $line;
+    my ($hash, $ref) = split(/\s+/, $line);
+    $branch_oldref = $hash          if $ref eq "refs/heads/$branch_name";
+    $branch_oldref_origin = $hash   if $ref eq "refs/remotes/origin/$branch_name";
+}
+if ($branch_oldref_origin && $branch_oldref ne $branch_oldref_origin) {
+    # reset local branch
+    system(qw{git branch -f}, $branch_name, "origin/$branch_name");
+    $branch_oldref = $branch_oldref_origin
+}
+
+my $commit_msg = shell_quote("Release $version");
+
+my $solodir = "solo_branch.$$";
+make_path($solodir);
+
+use Config;
+system($Config{'perlpath'}, qw{maint/fatpack.pl}, $distdir);
+move($script_name, "$solodir/$script_name");
+
+copy("$distdir/README", "$solodir/README");
+
+system(qw{git update-index --add}, glob("$solodir/*"));
+my $tree_ref = `git write-tree --prefix=$solodir/`;
+chomp $tree_ref;
+
+system(qw{git reset});
+remove_tree($solodir);
+
+my $branch_oldref_safe = shell_quote($branch_oldref);
+my $tree_ref_safe = shell_quote($tree_ref);
+my $parent = $branch_oldref ? "-p $branch_oldref_safe" : '';
+my $commit_ref = `git commit-tree -m $commit_msg $parent $tree_ref_safe`;
+chomp $commit_ref;
+
+system(qw(git branch -f), $branch_name, $commit_ref);
+system(qw(git tag -a -m), "Version $version", "$branch_name-$version", $commit_ref);
+
diff --git a/maint/fatpack.pl b/maint/fatpack.pl
new file mode 100755 (executable)
index 0000000..af14d1b
--- /dev/null
@@ -0,0 +1,180 @@
+#!/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;
+}
+
This page took 0.028256 seconds and 4 git commands to generate.