about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--leo.138
-rwxr-xr-xleo.pl184
-rw-r--r--share/leo.conf34
3 files changed, 99 insertions, 157 deletions
diff --git a/leo.1 b/leo.1
index 5df1e38..be04a50 100644
--- a/leo.1
+++ b/leo.1
@@ -1,11 +1,11 @@
-.TH LEO 1 "15 November 2020" "v0.4.1"
+.TH LEO 1 "21 November 2020" "v0.5.0"
 
 .SH NAME
 leo \- a simple backup program
 
 .SH SYNOPSIS
 .B leo
-[--help] [--version] [--verbose] profiles
+[-hpvV] profiles
 .P
 
 .SH DESRIPTION
@@ -23,35 +23,17 @@ up.
 .SH OPTIONS
 The options are as follows:
 .TP
-.B --verbose
-Verbose output. This flag will be passed to commands that leo
-executes.
+.B -h
+Print help.
 .TP
-.BI --version
-Print version.
+.B -p
+Print profiles.
 .TP
-.B --help
-Print help. This will also print list of profiles with their
-configuration.
-.SH ENVIRONMENT VARIABLES
-As shown in examples below, environment variables can be used to
-configure leo.
-
-Available options are:
-.B L_ENCRYPT
-.B L_SIGN
-.B L_SIGNIFY
-.B L_GZIP
-.SH EXAMPLES
+.B -v
+Increase verbosity.
 .TP
-.B leo journal emacs
-Backup `journal' & `emacs' profile.
+.B -V
+Print version.
 .TP
-.B L_ENCRYPT=1 leo journal
-Backup `journal' & encrypt it. This encrypt option can be over-ridden
-by the config file.
-.SH BUGS
-It'll set the tar & gpg output file's mode to 0600 & there is no way
-to configure that.
 .SH AUTHOR
 Andinus <andinus@nand.sh>
diff --git a/leo.pl b/leo.pl
index 6ff74c2..135b3d7 100755
--- a/leo.pl
+++ b/leo.pl
@@ -7,28 +7,28 @@ use IPC::Run3;
 use Path::Tiny;
 use Config::Tiny;
 use POSIX qw(strftime);
-use Getopt::Long qw/ GetOptions /;
 
-my $version = "leo v0.4.4";
+die "usage: leo [-hpvV] <profile>\n" unless scalar @ARGV;
 
-# Options.
-my %options = (
-    L_SIGN => $ENV{L_SIGN},
-    L_GZIP => $ENV{L_GZIP},
-    L_ENCRYPT => $ENV{L_ENCRYPT},
-    L_SIGNIFY => $ENV{L_SIGNIFY},
-);
+my ($VERBOSE, $PRINT_PROFILES);
+my $VERSION = "v0.5.0";
 
-GetOptions(
-    \%options,
-    qw{ verbose help version }
-) or die "leo: error in command line arguments\n";
+# Dispatch table to be parsed before url.
+my %dispatch = (
+    '-V'  => sub { print "Leo $VERSION\n"; exit; },
+    '-v'  => sub { $VERBOSE = 1; },
+    '-h'  => \&HelpMessage,
+    '-p'  => sub { $PRINT_PROFILES = 1; },
+);
+if (exists $dispatch{$ARGV[0]}) {
+    # shift @ARGV to get profile in next shift.
+    $dispatch{shift @ARGV}->();
+}
 
-# Print version.
-print $version, "\n" and exit 0 if $options{version};
+# Set umask.
+umask 077;
 
 # Configuration.
-
 my $config_file = $ENV{XDG_CONFIG_HOME} || "$ENV{HOME}/.config";
 $config_file .= "/leo.conf";
 
@@ -37,25 +37,16 @@ $config = Config::Tiny->read( $config_file )
     or die "Cannot read config file: `$config_file'\n";
 
 # Reading config file.
-
+my %options;
 foreach my $key (sort keys $config->{_}->%*) {
     $options{$key} = $config->{_}->{$key};
 }
 
-# Die if user is using older config format.
-die "leo: old config format detected\n"
-    if exists $options{encrypt} or exists $options{sign};
-
 my %profile;
-
+# Iterate through all sections in config file, we call this profile.
 foreach my $prof (sort keys $config->%*) {
     next if $prof eq "_";
 
-    # Set global values to local profiles.
-    foreach (qw(L_ENCRYPT L_SIGN L_SIGNIFY L_GZIP)) {
-        $profile{$prof}{$_} = $options{$_};
-    }
-
     foreach my $key (sort keys $config->{$prof}->%*) {
         # $profile{$prof} contains config values ($), {exclude}
         # (@), {backup} (@).
@@ -74,53 +65,41 @@ foreach my $prof (sort keys $config->%*) {
     }
 }
 
-my $date = date();
 my $backup_dir = $options{backup_dir} || "/tmp/backups";
-
-my @gpg_recipients;
-@gpg_recipients = split / /, $options{gpg_recipients}
-    if $options{gpg_recipients};
-
-my $gpg_bin = $options{gpg_bin} || "gpg";
-warn "[WARN] \$gpg_bin is set to `$gpg_bin'"
-    unless $gpg_bin =~ /^(gpg2?)$/;
-
-# Print help.
-HelpMessage() and exit 0 if scalar @ARGV == 0 or $options{help};
+PrintProfiles() if $PRINT_PROFILES;
 
 # Parsing the arguments.
 foreach my $prof ( @ARGV ) {
     if ( $profile{ $prof } ) {
         print "--------  $prof";
-        print " [Encrypt]" if $profile{$prof}{L_ENCRYPT};
-        print " [Sign]"    if $profile{$prof}{L_SIGN};
-        print " [Signify]" if $profile{$prof}{L_SIGNIFY};
-        print " [gzip]"    if $profile{$prof}{L_GZIP};
+        print " [GnuPG]" if $profile{$prof}{L_GnuPG};
+        print " [Signify]" if $profile{$prof}{L_signify};
         print "\n";
 
-        my $file = "$backup_dir/${prof}/${date}.tar";
-        $file .= ".gz" if $profile{$prof}{L_GZIP};
-
-        path("$backup_dir/${prof}")->mkpath; # Create backup directory.
-        backup($prof, $file);
+        # Create backup directory.
+        path("$backup_dir/${prof}")->mkpath;
 
-        my $is_gpg_req = 1 if $profile{$prof}{L_SIGN} or $profile{$prof}{L_ENCRYPT};
-        encrypt_sign($prof, $file) if $is_gpg_req;
+        my $date = date();
+        my $file = "$backup_dir/${prof}/${date}.tgz";
 
-        # gpg would've removed the `.tar' file.
-        $file = "${file}.gpg" if $is_gpg_req;
-        signify($prof, $file) if $profile{$prof}{L_SIGNIFY};
+        run_tar($prof, $file);
+        run_gnupg($prof, $file) and $file = "${file}.gpg"
+            if $profile{$prof}{L_GnuPG};
+        run_signify($prof, $file) if $profile{$prof}{L_signify};
     } else {
-        warn "[WARN] leo: no such profile :: `$prof' \n";
+        warn "leo: no such profile :: `$prof' \n";
     }
 }
 
-sub backup {
+sub run_tar {
     my $prof = shift @_;
-    my $tar_file = shift @_;
+    my $file = shift @_;
 
-    my @options = ("-C", "/");
-    push @options, "-z" if $profile{$prof}{L_GZIP};
+    my @options = ( "-c",
+                    "-f", $file,
+                    "-C", '/',
+                    "-z");
+    push @options, "-v" if $options{verbose};
 
     my @backup_paths;
     foreach my $path ($profile{$prof}{backup}->@*) {
@@ -140,53 +119,47 @@ sub backup {
         @backup_paths = grep !/$exclude/, @backup_paths;
     }
 
-    # All paths should be relative to '/'.
+    # All paths should be relative to '/.
     @backup_paths = map { $_->relative('/') } @backup_paths;
 
-    tar_create($tar_file, @options, @backup_paths);
+    run3 ["/bin/tar", @options, @backup_paths];
     $? # tar returns 1 on errors.
         ? die "Backup creation failed :: $?\n"
-        : print "Backup: $tar_file\n";
-
-    path($tar_file)->chmod(0600);
-    print "File was compressed with gzip(1).\n"
-        if $profile{$prof}{L_GZIP} and $options{verbose};
-
-    tar_list($tar_file) if $options{verbose};
+        : print "Backup: $file\n";
 }
 
-# Encrypt, Sign backups.
-sub encrypt_sign {
+sub run_gnupg {
     my $prof = shift @_;
     my $file = shift @_;
 
-    my @options = ();
-    push @options, "--default-key", $options{gpg_fingerprint}
+    my @options = ( "--sign", "--encrypt",
+                    "--yes",
+                    "-o", "${file}.gpg"
+                );
+
+    push @options,
+        "--default-key", $options{gpg_fingerprint},
+        "--recipient", $options{gpg_fingerprint}
         if $options{gpg_fingerprint};
 
-    if ( $profile{$prof}{L_ENCRYPT} ) {
-        push @options, "--encrypt";
-        push @options, "--recipient", $options{gpg_fingerprint}
-            if $options{gpg_fingerprint};
-        push @options, "--recipient", $_
-            foreach @gpg_recipients;
-    }
+    # Add recipients.
+    my @gpg_recipients;
+    @gpg_recipients = split / /, $options{gpg_recipients}
+        if $options{gpg_recipients};
+    push @options, "--recipient", $_ foreach @gpg_recipients;
 
-    push @options, "--sign" if $profile{$prof}{L_SIGN};
     push @options, "--verbose" if $options{verbose};
 
-    run3 [$gpg_bin, "--yes", "-o", "${file}.gpg", @options, $file];
+    run3 ["/usr/local/bin/gpg2", @options, $file];
 
     $? # We assume non-zero is an error.
-        ? die "GPG failed :: $?\n"
-        : print "GPG: $file.gpg\n";
-
-    unlink $file or warn "[WARN] Could not delete `$file': $!\n";
+        ? die "GnuPG failed :: $?\n"
+        : print "GnuPG: $file.gpg\n";
 
-    path("$file.gpg")->chmod(0600);
+    unlink $file or warn "leo: Could not delete `$file': $!\n";
 }
 
-sub signify {
+sub run_signify {
     my $prof = shift @_;
     my $file = shift @_;
 
@@ -202,32 +175,31 @@ sub signify {
         : print "Signify: ${file}.sig\n";
 }
 
-sub HelpMessage {
-    print qq{Backup files to $backup_dir.
-
-Profile:\n};
+sub PrintProfiles {
+    print "Profile:\n";
     foreach my $prof (sort keys %profile) {
         print "    $prof";
-        if ($options{verbose}) {
-            print " [Encrypt]" if $profile{$prof}{L_ENCRYPT};
-            print " [Sign]" if $profile{$prof}{L_SIGN};
-            print " [Signify]" if $profile{$prof}{L_SIGNIFY};
-            print " [gzip]" if $profile{$prof}{L_GZIP};
-            print "\n";
-
-            print "        + $_\n" foreach $profile{$prof}{backup}->@*;
-            print "        - $_\n" foreach $profile{$prof}{exclude}->@*;
-        }
+        print " [GnuPG]" if $profile{$prof}{L_GnuPG};
+        print " [Signify]" if $profile{$prof}{L_signify};
+        print "\n";
+
+        print "        + $_\n" foreach $profile{$prof}{backup}->@*;
+        print "        - $_\n" foreach $profile{$prof}{exclude}->@*;
         print "\n";
     }
+}
+sub HelpMessage {
     print qq{Options:
-    --version [$version]
-    --verbose
-    --help
+    -V [$VERSION]
+        Print version.
+    -v
+        Increase verbosity.
+    -p
+        Print profiles.
+    -h
+        Print help.
 };
+    exit;
 }
 
-sub tar_create { run3 ["/bin/tar", "cf", @_]; }
-sub tar_list { print "\n"; run3 ["/bin/tar", "tvf", @_]; print "\n";}
-
 sub date { return strftime '%FT%T%z', localtime() }
diff --git a/share/leo.conf b/share/leo.conf
index 083a5ff..4fe8903 100644
--- a/share/leo.conf
+++ b/share/leo.conf
@@ -1,31 +1,19 @@
 backup_dir = /home/andinus/backups
 
-gpg_fingerprint = D9AE4AEEE1F1B3598E81D9DFB67D55D482A799FD
-# You don't have to include your key in gpg_recipients, it's added by
-# default. Add multiple keys seperated by a space.
-gpg_recipients = D9AE4AEEE1F1B3598E81D9DFB67D55D482A799FD
-gpg_bin = gpg2
+gpg_fingerprint = andinus@redacted
+gpg_recipients = redacted
 
-signify_seckey = /home/andinus/.totally_not_my_key.sec
-
-# Options.
-L_ENCRYPT = 1
-L_SIGN = 1
+signify_seckey = /home/andinus/redacted.sec
 
 # Profile names in [].
-[journal]
-L_ENCRYPT = 0
-L_SIGNIFY = 1
-# Paths to backup. '=' after path is important.
-/home/andinus/documents/not_important.org.gpg =
-/home/andinus/documents/archive.org =
-
 [emacs]
-# compress this archive
-L_GZIP = 1
+L_GnuPG = 1
+
+# Paths to backup. '=' after path is important.
 /home/andinus/.emacs.d =
+# Exclude directories with `exclude' value.
+/home/andinus/.emacs.d/elpa = exclude
 
-[projects]
-/home/andinus/projects =
-# Exclude directories with `exclude' value. (regex supported)
-/home/andinus/projects/forks = exclude
+[emacs/elpa]
+L_GnuPG = 1
+/home/andinus/.emacs.d/elpa =