diff options
-rw-r--r-- | leo.1 | 38 | ||||
-rwxr-xr-x | leo.pl | 184 | ||||
-rw-r--r-- | share/leo.conf | 34 |
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 = |