#!/usr/bin/perl use strict; use warnings; use feature 'say'; use IPC::Run3; use Path::Tiny; use Getopt::Long qw/ GetOptions /; my %options = (); GetOptions( \%options, qw{ verbose encrypt sign delete } ) or die "Error in command line arguments\n"; $options{encrypt} = $ENV{LEO_ENCRYPT}; $options{sign} = $ENV{LEO_SIGN}; $options{delete} = $ENV{LEO_DELETE}; my $gpg_fingerprint = "D9AE4AEEE1F1B3598E81D9DFB67D55D482A799FD"; my $archive_dir = "/tmp/archive"; my $ymd = ymd(); # YYYY-MM-DD. # Dispatch table. All paths should be relative to $ENV{HOME}. my %dispatch = ( journal => sub { my $tmp = $options{encrypt} and undef $options{encrypt} if $options{encrypt}; archive("$archive_dir/journal_$ymd.tar", "documents/andinus.org.gpg", "documents/archive.org.gpg"); $options{encrypt} = $tmp; }, emacs => sub { archive("$archive_dir/emacs_$ymd.tar", ".emacs.d", ".elfeed", ".org-timestamps"); }, config => sub { archive("$archive_dir/config_$ymd.tar", qw{ .config .kshrc .kshrc.d .tmux.conf .xsession .screenlayout .mg .mbsyncrc .fehbg .profile .remind .plan .authinfo.gpg .Xresources }); }, ); # This adds directories with different profile name and path. my %directories = ( ssh => "$ENV{HOME}/.ssh", pass => "$ENV{HOME}/.password-store", mozilla => "$ENV{HOME}/.mozilla", ); foreach my $dir (sort keys %directories) { $dispatch{$dir} = sub { archive("$archive_dir/${dir}_${ymd}.tar", "$directories{$dir}"); }; } # This adds the directories with same profile name as path. foreach my $profile (qw( emails music projects documents videos pictures downloads )) { $dispatch{$profile} = sub { archive("$archive_dir/${profile}_$ymd.tar", $profile); }; } # User must pass $tar_file first & `-C' optionally. sub archive { my $tar_file = shift @_; my @archive_paths = @_; say "Archive: $tar_file"; warn "[WARN] $tar_file exists, might overwrite.\n" if -e $tar_file; print "\n"; tar_create($tar_file, "-C", $ENV{HOME}, @_); $? # tar returns 1 on errors. ? die "Archive creation failed :: $?\n" # Print absolute paths for all archived files/directories. : say path($_)->absolute($ENV{HOME}), " archived." foreach @archive_paths; print "\n" and tar_list($tar_file) if $options{verbose}; encrypt_sign($tar_file) if $options{encrypt} or $options{sign}; } # Encrypt, Sign archives. sub encrypt_sign() { my $file = shift @_; my @options = (); push @options, "--recipient", $gpg_fingerprint, "--encrypt" if $options{encrypt}; push @options, "--sign" if $options{sign}; push @options, "--verbose" if $options{verbose}; say "\nEncrypt/Sign: $file"; warn "[WARN] $file.gpg exists, might overwrite.\n" if -e "$file.gpg"; run3 ["gpg2", "--yes", "-o", "$file.gpg", @options, $file]; $? # We assume non-zero is an error. ? die "Encrypt/Sign failed :: $?\n" : print "\nOutput: $file.gpg"; print " [Encrypted]" if $options{encrypt}; print " [Signed]" if $options{sign}; print "\n"; unlink $file and say "$file deleted." or warn "[WARN] Could not delete $file: $!\n" if $options{delete}; } sub HelpMessage { say qq{Archive files to $archive_dir. Usage: documents Archive $ENV{HOME}/documents journal Archive $ENV{HOME}/documents/andinus.org.gpg, $ENV{HOME}/documents/archive.org.gpg ssh Archive $ENV{HOME}/.ssh pass Archive $ENV{HOME}/.password-store Options: --encrypt Encrypt files with $gpg_fingerprint --sign Sign files with $gpg_fingerprint --delete Delete the archive after running gpg2 --verbose}; } HelpMessage() if scalar @ARGV == 0; path($archive_dir)->mkpath; # Create archive directory. foreach my $arg ( @ARGV ) { if ( $dispatch{ $arg } ) { say "--------------------------------"; $dispatch{ $arg }->(); } else { die "leo: no such option\n"; } } sub tar_create { run3 ["/bin/tar", "cf", @_]; } sub tar_list { run3 ["/bin/tar", "tvf", @_]; } sub ymd { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $year += 1900; # $year contains the number of years since 1900. # $mon the month in the range 0..11 , with 0 indicating January # and 11 indicating December. my @months = qw( 01 02 03 04 05 06 07 08 09 10 11 12 ); my $month = $months[$mon]; return "$year-$month-$mday"; }