From 04da16dd682a073513e989276ed179a1a27f8c9a Mon Sep 17 00:00:00 2001 From: Andinus Date: Sat, 14 Nov 2020 18:58:06 +0530 Subject: Add Makefile, man page, change config format, bump version This commit pushes a lot of changes at once. Older config will no longer work with this. The file name will contain time in local timezone instead of UTC. Makefile & man page was copied from tomasino's pb(1). (tomasino.org) --- Makefile | 26 +++++++++++ README | 137 +++++++-------------------------------------------------- leo.1 | 57 ++++++++++++++++++++++++ leo.pl | 122 ++++++++++++++++++-------------------------------- share/leo.conf | 17 +++---- 5 files changed, 151 insertions(+), 208 deletions(-) create mode 100644 Makefile create mode 100644 leo.1 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e646a32 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +# Install to /usr/local unless otherwise specified, such as `make +# PREFIX=/app`. +PREFIX?=/usr/local + +INSTALL?=install +INSTALL_PROGRAM=$(INSTALL) -Dm 755 +INSTALL_DATA=$(INSTALL) -Dm 644 + +bindir=$(DESTDIR)$(PREFIX)/bin +sharedir=$(DESTDIR)$(PREFIX)/share + +help: + @echo "targets:" + @awk -F '#' '/^[a-zA-Z0-9_-]+:.*?#/ { print $0 }' $(MAKEFILE_LIST) \ + | sed -n 's/^\(.*\): \(.*\)#\(.*\)/ \1|-\3/p' \ + | column -t -s '|' + +install: leo.pl leo.1 # system install + $(INSTALL_PROGRAM) leo.pl $(bindir)/leo + $(INSTALL_DATA) leo.1 $(sharedir)/man/man1/leo.1 + +uninstall: # system uninstall + rm -f $(bindir)/leo + rm -f $(sharedir)/man/man1/leo.1 + +.PHONY: install uninstall help diff --git a/README b/README index 0c04e4c..4fa56de 100644 --- a/README +++ b/README @@ -9,16 +9,8 @@ Table of Contents ───────────────── 1. Installation -2. Documentation -.. 1. Profile -.. 2. Options -..... 1. encrypt/sign -..... 2. signify -..... 3. gzip -..... 4. help -3. Example -4. Demo -5. History +.. 1. OpenBSD +2. Demo Leo is a simple backup program. It creates tar(1) files from a @@ -34,12 +26,9 @@ with signify(1). ══════════════ ┌──── - │ # Install all the dependencies. (OpenBSD) - │ doas pkg_add p5-IPC-Run3 p5-Config-Tiny p5-Path-Tiny - │ │ # Clone the project. - │ git clone https://git.tilde.institute/andinus/leo && \ - │ cd leo + │ git clone https://git.tilde.institute/andinus/leo + │ cd leo │ │ # Install dependencies with cpanm. │ cpanm --installdeps . @@ -48,103 +37,32 @@ with signify(1). │ cp share/leo.conf $HOME/.config/leo.conf │ │ # Copy the script & make it executable. - │ cp leo.pl $HOME/bin/leo && \ - │ chmod +x $HOME/bin/leo + │ sudo make install └──── -2 Documentation -═══════════════ - - I use this to quickly backup some of my files. It works on profiles, - profiles are simple lists of files which get backed up. - - *Note*: Backup file's mode will be changed to `0600'. - - -2.1 Profile +1.1 OpenBSD ─────────── - Profile is a simple hash table (`%profile') which contains the list of - profiles. The profiles are mapped to a list of file paths which are to - be backed up. - - You can run `help' to see all the profiles along with the paths. - - -2.2 Options -─────────── - - Some options can also be passed through environment variables. That - allows for configuration in shell rc file & the user can run leo - directly without looking at options. - - ━━━━━━━━━━━━━━━━━━━━━━━━ - encrypt `LEO_ENCRYPT' - sign `LEO_SIGN' - signify `LEO_SIGNIFY' - gzip `LEO_GZIP' - ━━━━━━━━━━━━━━━━━━━━━━━━ - - -2.2.1 encrypt/sign -╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ - - `encrypt_sign' handles `gpg2' related functions. It passes `--yes' by - default. - - • `encrypt' / `sign' can also be set in configuration file, one can - also configure it for specific profile. - - *Note*: `gpg2' might compress the backups depending on your config. - Default is to enable compression, if you don't want this then add `-z - 0' to `@options'. `-z' specifies the compression level & 0 means no - compression. - - -2.2.2 signify -╌╌╌╌╌╌╌╌╌╌╌╌╌ - - `signify' will invoke `signify(1)' & the file will be signed. - - -2.2.3 gzip -╌╌╌╌╌╌╌╌╌╌ - - `gzip' will compress the tar archive with `gzip(1)'. - - -2.2.4 help -╌╌╌╌╌╌╌╌╌╌ - - Running just `leo' will print help. - - -3 Example -═════════ - + Clone & copy the config as shown above, then run these to install + dependencies & leo. ┌──── - │ # This will encrypt, sign the tar file for documents, journal, pass & - │ # ssh profile. - │ leo --encrypt --sign documents journal pass ssh - │ - │ # This will do the same. You can add these environment variables to - │ # your shell rc & then just run ``leo documents journal ssh pass'' to - │ # do the same. - │ LEO_ENCRYPT=1 LEO_SIGN=1 leo documents journal ssh pass + │ # Install all the dependencies. (OpenBSD) + │ doas pkg_add p5-IPC-Run3 p5-Config-Tiny p5-Path-Tiny │ - │ # Sign the file with signify(1). - │ leo --signify journal + │ # The man-path `/usr/local/share/man` is not indexed by default on + │ # openbsd. Using the `/usr` prefix works around this issue. + │ doas make PREFIX=/usr install └──── -4 Demo +2 Demo ══════ It's very easy to setup `leo', I made a demo video to show this. I already have Perl environment setup for this. - *Note*: Leo has changed since this was published. + *Note*: Leo has changed *a lot* since this was published. • Leo 2020-08-31: @@ -154,28 +72,3 @@ with signify(1). [cast file] - - -5 History -═════════ - - This was Leo's initial description: - - Leo is a program to run my personal scripts. You might not - find them useful, these were previously shell scripts that - I rewrote in Perl. - - I had created a sync function initially & was going to expand it. Then - I decided to remove those sync functions because it was too complex, I - replaced then with simple `sh' scripts. - - I added a simple `archive' function later & decided to turn Leo into - that function. So, it's not a meta-program anymore. I was thinking of - creating something that does all the things for me but that'll be too - complex. - - Later on the same day I removed dispatch table & switched to using - simple hash of lists to store backup paths mapped to profiles. And - also changed the word "archive" to "backup" everywhere. - - I added a simple INI based config file before 0.1.0 release. diff --git a/leo.1 b/leo.1 new file mode 100644 index 0000000..74637f9 --- /dev/null +++ b/leo.1 @@ -0,0 +1,57 @@ +.TH LEO 1 "14 November 2020" "v0.4.0" + +.SH NAME +leo \- a simple backup program + +.SH SYNOPSIS +.B leo +[--help] [--version] [--verbose] profiles +.P + +.SH DESRIPTION +.B leo +is a simple backup program. It creates tar(1) files from a pre-defined +list. It can encrypt/sign files with gpg2(1) & sign files with +signify(1). + +I use this to quickly backup some of my files. It works on profiles, +profiles are simple lists of files which get backed up. +.SH PROFILE +Profile is a simple hash table which contains the list of profiles. +The profiles are mapped to a list of file paths which are to be backed +up. +.SH OPTIONS +The options are as follows: +.TP +.B --verbose +Verbose output. This flag will be passed to commands that leo +executes. +.TP +.BI --version +Print version. +.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 +.TP +.B leo journal emacs +Backup `journal' & `emacs' profile. +.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 diff --git a/leo.pl b/leo.pl index 3aece04..17b6482 100755 --- a/leo.pl +++ b/leo.pl @@ -7,23 +7,17 @@ use feature 'say'; use IPC::Run3; use Path::Tiny; use Config::Tiny; +use POSIX qw(strftime); use Getopt::Long qw/ GetOptions /; -my $version = "leo v0.3.4"; +my $version = "leo v0.4.0"; # Options. - -my %options = ( - encrypt => $ENV{LEO_ENCRYPT}, - sign => $ENV{LEO_SIGN}, - signify => $ENV{LEO_SIGNIFY}, - gzip => $ENV{LEO_GZIP}, -); - +my %options; GetOptions( \%options, - qw{ verbose encrypt sign signify gzip help version } -) or die "Error in command line arguments\n"; + qw{ verbose help version } +) or die "leo: error in command line arguments\n"; # Print version. print $version, "\n" and exit 0 if $options{version}; @@ -43,38 +37,41 @@ 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; -foreach my $section (sort keys $config->%*) { - next if $section eq "_"; +foreach my $prof (sort keys $config->%*) { + next if $prof eq "_"; # Set global values to local profiles. - foreach (qw( encrypt sign signify gzip )) { - $profile{$section}{$_} = $options{$_}; + foreach (qw(L_ENCRYPT L_SIGN L_SIGNIFY L_GZIP)) { + $profile{$prof}{$_} = $options{$_}; } - foreach my $key (sort keys $config->{$section}->%*) { - # Override encrypt & sign options with local values. - if ($key eq "encrypt" - or $key eq "sign" - or $key eq "signify" - or $key eq "gzip") { - $profile{$section}{$key} = $config->{$section}->{$key}; + foreach my $key (sort keys $config->{$prof}->%*) { + # $profile{$prof} contains config values ($), {exclude} + # (@), {backup} (@). + + # Set config values. + if ( length($key) >= 2 + and substr($key, 0, 2) eq "L_") { + $profile{$prof}{$key} = $config->{$prof}->{$key}; next; } - push @{ $profile{$section}{exclude} }, $key and next - if $config->{$section}->{$key} eq "exclude"; + push @{ $profile{$prof}{exclude} }, $key and next + if $config->{$prof}->{$key} eq "exclude"; - push @{ $profile{$section}{backup} }, $key; + push @{ $profile{$prof}{backup} }, $key; } } my $date = date(); my $backup_dir = $options{backup_dir} || "/tmp/backups"; -path($backup_dir)->mkpath; # Create backup directory. - my $gpg_fingerprint = $options{gpg_fingerprint} || "`nil'"; my @gpg_recipients; @@ -92,18 +89,18 @@ foreach my $prof ( @ARGV ) { say "++++++++********++++++++"; my $file = "$backup_dir/${prof}/${date}.tar"; - $file .= ".gz" if $profile{$prof}{gzip}; + $file .= ".gz" if $profile{$prof}{L_GZIP}; path("$backup_dir/${prof}")->mkpath; # Create backup directory. backup($prof, $file); - encrypt_sign($prof, $file) if $profile{$prof}{sign} or $profile{$prof}{encrypt}; + encrypt_sign($prof, $file) if $profile{$prof}{L_SIGN} or $profile{$prof}{L_ENCRYPT}; # gpg would've removed the `.tar' file so we sign the # encrypted file instead. my $encrypted_file = "${file}.gpg"; - $file = $encrypted_file if $profile{$prof}{sign} or $profile{$prof}{encrypt}; - signify($prof, $file) if $profile{$prof}{signify}; + $file = $encrypted_file if $profile{$prof}{L_SIGN} or $profile{$prof}{L_ENCRYPT}; + signify($prof, $file) if $profile{$prof}{L_SIGNIFY}; } else { warn "[WARN] leo: no such profile :: `$prof' \n"; } @@ -114,7 +111,7 @@ sub backup { my $tar_file = shift @_; my @options; - push @options, "-z" if $profile{$prof}{gzip}; + push @options, "-z" if $profile{$prof}{L_GZIP}; # Make @backup_paths relative to '/'. my @backup_paths; @@ -153,7 +150,7 @@ sub backup { path($tar_file)->chmod(0600) and print "Changed `$tar_file' mode to 0600.\n"; - print "File was compressed with gzip(1)\n" if $profile{$prof}{gzip}; + print "File was compressed with gzip(1)\n" if $profile{$prof}{L_GZIP}; print "\n" and tar_list($tar_file) if $options{verbose}; } @@ -166,14 +163,14 @@ sub encrypt_sign { my @options = (); push @options, "--default-key", $gpg_fingerprint; - if ( $profile{$prof}{encrypt} ) { + if ( $profile{$prof}{L_ENCRYPT} ) { push @options, "--encrypt"; push @options, "--recipient", $gpg_fingerprint; push @options, "--recipient", $_ foreach @gpg_recipients; } - push @options, "--sign" if $profile{$prof}{sign}; + push @options, "--sign" if $profile{$prof}{L_SIGN}; push @options, "--verbose" if $options{verbose}; say "\nEncrypt/Sign: $file"; @@ -184,8 +181,8 @@ sub encrypt_sign { $? # We assume non-zero is an error. ? die "Encrypt/Sign failed :: $?\n" : print "\nOutput: $file.gpg"; - print " [Encrypted]" if $profile{$prof}{encrypt}; - print " [Signed]" if $profile{$prof}{sign}; + print " [Encrypted]" if $profile{$prof}{L_ENCRYPT}; + print " [Signed]" if $profile{$prof}{L_SIGN}; print "\n"; unlink $file and say "$file deleted." @@ -222,35 +219,22 @@ sub signify { sub HelpMessage { say qq{Backup files to $backup_dir. ++ means included +- means excluded + Profile:}; foreach my $prof (sort keys %profile) { print " $prof"; - print " [Encrypt]" if $profile{$prof}{encrypt}; - print " [Sign]" if $profile{$prof}{sign}; - print " [Signify]" if $profile{$prof}{signify}; - print " [gzip]" if $profile{$prof}{gzip}; + 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}{backup}->@*; + print " - $_\n" foreach $profile{$prof}{exclude}->@*; print "\n"; } print qq{Options: - --encrypt }; - print "[Enabled]" if $options{encrypt}; - print qq{ - Encrypt files with $gpg_fingerprint\n - --sign }; - print "[Enabled]" if $options{sign}; - print qq{ - Sign files with $gpg_fingerprint\n - --signify }; - print "[Enabled]" if $options{signify}; - print qq{ - Sign with signify(1)\n - --gzip }; - print "[Enabled]" if $options{gzip}; - print qq{ - Compress with gzip(1) - --version [$version] --verbose --help @@ -260,22 +244,4 @@ Profile:}; sub tar_create { run3 ["/bin/tar", "cf", @_]; } sub tar_list { run3 ["/bin/tar", "tvf", @_]; } -sub date { - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = - gmtime(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]; - - # Pad by 2 zeros. - $mday = sprintf "%02d", $mday; - $hour = sprintf "%02d", $hour; - $min = sprintf "%02d", $min; - $sec = sprintf "%02d", $sec; - - return "$year-$month-${mday}T${hour}:${min}:${sec}Z"; -} +sub date { return strftime '%FT%T%z', gmtime() } diff --git a/share/leo.conf b/share/leo.conf index 75e9d0a..e46a61e 100644 --- a/share/leo.conf +++ b/share/leo.conf @@ -9,15 +9,14 @@ gpg_bin = gpg2 signify_seckey = /home/andinus/.totally_not_my_key.sec # Options. -encrypt = 1 -sign = 1 +L_ENCRYPT = 1 +L_SIGN = 1 # Profile names in []. [journal] # Local options. -encrypt = 0 -sign = 0 -signify = 1 +L_ENCRYPT = 0 +L_SIGNIFY = 1 # Paths to backup. '=' after path is important. /home/andinus/documents/not_important.org.gpg = @@ -25,11 +24,13 @@ signify = 1 [emacs] # compress this archive -gzip = 1 +L_GZIP = 1 /home/andinus/.emacs.d = -/home/andinus/.elfeed = -/home/andinus/.org-timestamps = +/home/andinus/.emacs.d/elpa = exclude + +[emacs/elpa] +/home/andinus/.emacs.d/elpa = [projects] /home/andinus/projects = -- cgit 1.4.1-2-gfad0