From eaa47c93563f075a2740db6a14aa71489b6b40e8 Mon Sep 17 00:00:00 2001 From: Paul Wilde Date: Fri, 23 Aug 2024 14:08:14 +0100 Subject: [PATCH] updated readme with some delete/forget options --- norg/borg/borg.nim | 5 +++- norg/borg/execute.nim | 5 ++++ norg/borg/extract.nim | 4 +-- norg/borg/mount.nim | 4 +-- norg/borg/prune.nim | 15 +++------- norg/config/args.nim | 3 ++ norg/model/command_type.nim | 2 ++ norg/restic/restore.nim | 4 +-- norg/utils/run.nim | 12 ++++++++ readme.md | 55 ++++++++++++++++++++++++++++++++----- 10 files changed, 84 insertions(+), 25 deletions(-) diff --git a/norg/borg/borg.nim b/norg/borg/borg.nim index 819894a..4119631 100644 --- a/norg/borg/borg.nim +++ b/norg/borg/borg.nim @@ -23,7 +23,7 @@ proc checkRepo(nc: NorgConfig, repo: Repository): int = echo "Not Yet Implemented." discard -proc execute*(nc: NorgConfig, repo: Repository) = +proc execute*(nc: NorgConfig, repo: Repository): int {.discardable.} = case nc.args.command of INIT: echo "Initializing repo: ", repo.label @@ -51,6 +51,9 @@ proc execute*(nc: NorgConfig, repo: Repository) = echo "Pruning repo: ", repo.label discard pruneRepo(nc, repo) run_actions(norg_config.actions.after_prune) + of DELETE: + echo "Deleting Archive ", nc.args.archive + discard deleteArchive(nc, repo) of COMPACT: run_actions(norg_config.actions.before_compact) discard compactRepo(nc, repo) diff --git a/norg/borg/execute.nim b/norg/borg/execute.nim index ff48b70..37d8f48 100644 --- a/norg/borg/execute.nim +++ b/norg/borg/execute.nim @@ -10,3 +10,8 @@ proc genCommand*(cmd: string, repo: string, further_args: seq[string]): string = let cmd = fmt"{BORG_BIN} {cmd} {repo} {args}" return cmd +proc genDeleteCommand*(cmd: string, repo: string, archive: string, further_args: seq[string]): string = + let args = further_args.join(" ") + let cmd = fmt"{BORG_BIN} {cmd} {repo} {archive} {args}" + return cmd + diff --git a/norg/borg/extract.nim b/norg/borg/extract.nim index 0e02a17..17f9a6b 100644 --- a/norg/borg/extract.nim +++ b/norg/borg/extract.nim @@ -10,8 +10,8 @@ proc isEmpty(dir: string): bool = return count == 0 proc extractArchive*(nc: NorgConfig, repo: Repository): int = - let archive = fmt"{repo.path}::{nc.args.further_args[0]}" - var further_args = nc.args.further_args[1..^1] + let archive = fmt"{repo.path}::{nc.args.archive}" + var further_args = nc.args.further_args if nc.args.extract_destination != "": discard existsOrCreateDir(nc.args.extract_destination) setCurrentDir(nc.args.extract_destination) diff --git a/norg/borg/mount.nim b/norg/borg/mount.nim index 017c014..e4c132f 100644 --- a/norg/borg/mount.nim +++ b/norg/borg/mount.nim @@ -3,8 +3,8 @@ import execute import strformat proc mountArchive*(nc: NorgConfig, repo: Repository): int = - let archive = repo.path & "::" & nc.args.further_args[0] - let further_args = nc.args.further_args[1..^1] + let archive = fmt"{repo.path}::{nc.args.archive}" + let further_args = nc.args.further_args let ok = runDiscard genCommand(cmd = "mount", repo = archive, further_args = further_args) if ok == 0: echo fmt"Mounted {archive} at {further_args[0]}" diff --git a/norg/borg/prune.nim b/norg/borg/prune.nim index a48cb1a..44af103 100644 --- a/norg/borg/prune.nim +++ b/norg/borg/prune.nim @@ -1,19 +1,12 @@ import ../model/config_type -import strformat - import execute - -proc addPruneOptions(cmd: var string, maintenance: Maintenance) = - cmd = fmt"""{cmd} \ - --keep-hourly {maintenance.keep_hourly} \ - --keep-daily {maintenance.keep_daily} \ - --keep-weekly {maintenance.keep_weekly} \ - --keep-monthly {maintenance.keep_monthly} \ - --keep-yearly {maintenance.keep_yearly} \ - """ proc pruneRepo*(nc: NorgConfig, repo: Repository): int = var cmd = genCommand(cmd = "prune", repo = repo.path, further_args = nc.args.further_args) cmd.addPruneOptions(nc.maintenance) return run cmd + +proc deleteArchive*(nc: NorgConfig, repo: Repository): int = + var cmd = genDeleteCommand(cmd = "delete", repo = repo.path, archive = nc.args.archive, further_args = nc.args.further_args) + return run cmd diff --git a/norg/config/args.nim b/norg/config/args.nim index 4f0d33e..d8edf78 100644 --- a/norg/config/args.nim +++ b/norg/config/args.nim @@ -7,6 +7,7 @@ type extract_destination*: string command*: Command repository*: string + archive*: string further_args*: seq[string] var norg_args*: NorgArgs = NorgArgs() @@ -17,6 +18,7 @@ proc parseArgs*() = option("-c", "--config", help="Config file to use.", required = true) option("-d", "--destination", help="Destination when extracting backup", required = false) option("-r", "--repository", help="Define an explicit repository to work on by either label or path.", required = false) + option("-a", "--archive", help="The archive or snapshot to operate on", required = false) arg("command", help="The command to run, defaults to 'create' which will perform a backup.", default=some("create")) arg("further_args", nargs = -1, help="Any further arguments to send onto borg or restic.") try: @@ -25,6 +27,7 @@ proc parseArgs*() = norg_args.extract_destination = opts.destination norg_args.command = opts.command.toCommand() norg_args.repository = opts.repository + norg_args.archive = opts.archive norg_args.further_args = opts.further_args except ShortCircuit as err: if err.flag == "argparse_help": diff --git a/norg/model/command_type.nim b/norg/model/command_type.nim index 15b5962..4cb1175 100644 --- a/norg/model/command_type.nim +++ b/norg/model/command_type.nim @@ -10,6 +10,7 @@ type MOUNT = "mount", UMOUNT = "umount", PRUNE = "prune", + DELETE = "delete" CHECK = "check", COMPACT = "compact" @@ -20,5 +21,6 @@ proc toCommand*(str: string): Command = of "backup": return CREATE of "snapshots","archives": return LIST of "restore": return EXTRACT + of "forget": return DELETE diff --git a/norg/restic/restore.nim b/norg/restic/restore.nim index 4f1de51..c893add 100644 --- a/norg/restic/restore.nim +++ b/norg/restic/restore.nim @@ -10,8 +10,8 @@ proc isEmpty(dir: string): bool = return count == 0 proc restoreSnapshot*(nc: NorgConfig, repo: Repository): int = - let repo_snapshot = fmt"{repo.path} {nc.args.further_args[0]}" - var further_args = nc.args.further_args[1..^1] + let repo_snapshot = fmt"{repo.path} {nc.args.archive}" + var further_args = nc.args.further_args if nc.args.extract_destination != "": discard existsOrCreateDir(nc.args.extract_destination) setCurrentDir(nc.args.extract_destination) diff --git a/norg/utils/run.nim b/norg/utils/run.nim index cc22ccf..ed6bda3 100644 --- a/norg/utils/run.nim +++ b/norg/utils/run.nim @@ -1,6 +1,9 @@ import strformat import osproc +import ../model/maintenance_type + + proc run*(cmd: string): int = echo fmt"Trying to run : {cmd}" try: @@ -18,3 +21,12 @@ proc runDiscard*(cmd: string): int = except: echo getCurrentExceptionMsg() return 1 + +proc addPruneOptions*(cmd: var string, maintenance: Maintenance) = + cmd = fmt"""{cmd} \ + --keep-hourly {maintenance.keep_hourly} \ + --keep-daily {maintenance.keep_daily} \ + --keep-weekly {maintenance.keep_weekly} \ + --keep-monthly {maintenance.keep_monthly} \ + --keep-yearly {maintenance.keep_yearly} \ + """ diff --git a/readme.md b/readme.md index 47751a3..fe1efcf 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ source_directories = [ "/home/me/Pictures" ] [[repositories]] -label = "A Repository" +label = "MyBorgRepo" path = "/my/backup/location" [[repositories]] @@ -33,7 +33,7 @@ base_url = "https://uptime.kuma.url/api/push/1234abcd" states = ["Success","Failure", "Running"] ``` -You can then run the equivalent `borg` command to init, create, list, mount and extract your backups. +You can then run the equivalent `borg` or `restic` command to init, create, list, mount and extract your backups. **Using BorgBackup** ```sh @@ -47,16 +47,24 @@ norg -c myconfig.toml create norg -c myconfig.toml list # Mount an Archive -norg -c myconfig.toml mount pcname-2024-08-18T15:20:17773204 /home/me/mnt +norg -c myconfig.toml mount -r MyBorgRepo -a pcname-2024-08-18T15:20:17773204 /home/me/mnt # Unmount an Archive -norg -c myconfig.toml umount /home/me/mnt +norg -c myconfig.toml umount -r MyBorgRepo /home/me/mnt # Extract an Archive # You must be in an empty folder for this to work -norg -c myconfig.toml extract pcname-2024-08-18T15:20:17773204 +norg -c myconfig.toml extract -r MyBorgRepo -a pcname-2024-08-18T15:20:17773204 # Or You must set the destination to an empty folder -norg -c myconfig.toml extract pcname-2024-08-18T15:20:17773204 --destination /tmp/my_extracted_archive +norg -c myconfig.toml extract -r MyBorgRepo -a pcname-2024-08-18T15:20:17773204 --destination /tmp/my_extracted_archive + +# Prune all repos +norg -c myconfig.toml prune +# Or specify a particula repo +norg -c myconfig.toml prune -r MyBorgRepo + +# Delete an Archive +norg -c myconfig.toml delete -r MyBorgRepo -a pcname-2024-08-18T15:20:17773204 ``` **Using Restic** _New in v0.1.6_ @@ -83,9 +91,22 @@ norg -c myconfig.toml snapshots norg -c myconfig.toml mount -r MyResticRepo /home/me/mnt # Restore an Archive (restore destination must be empty) -norg -c myconfig.toml restore latest --destination /my/restore/location +norg -c myconfig.toml restore -a latest --destination /my/restore/location + +# Prune a repo +norg -c myconfig.toml prune + +# Forget a Snapshot +norg -c myconfig.toml forget -r MyBorgRepo -a a1b2c3d4 ``` +### Command line parameters + +* `-c`, `--config`: The configuration file to use +* `-r`, `--repository`: The repository to work on +* `-a`, `--archive`: The Archive to operate on (snapshots for restic) +* `-d`, `--destination`: When extracting/restoring, the destination for the extracted files + # Build from Source Download and build from source ```sh @@ -106,6 +127,26 @@ in line with the [Borg pseudo-species](https://memory-alpha.fandom.com/wiki/Borg Also, sometimes I feel my code has elements of inexperience but loads of potential... which reminded me of [Nog](https://memory-alpha.fandom.com/wiki/Nog). So, simply put, `Norg` is an portmanteau of "Borg" and "Nog". +## Borg and Restic Notes +I love both Borg and Restic tools, they are both great and both have their pros and cons. As [BorgBase](https://borgbase.com) has repos for both, I felt it only sensible to +provide a tool that can use both. +Providing implementation for both means you could have duplicate backups using +different tools which should provide a certain amount of protection over failures in +a particular tool. +Caution should be taken when using additional flags when you have repositories of +both types in the same configuration file. I have tried to cater for some common flags +that will be converted to the correct type for a particular tool, but this may not always be the case. If in any doubt, it is advised to use the `--repository` flag for any borg/restic specific flags so as not to cause one the other tool to fail. + +Some different yet similar commands should be converted to the correct type. A table below shows some of these: +| Borg Command | Restic Command | Result | +| create | backup | creates a backup | +| list | snapshots | lists archives/snapshots | +| extract | restore | restores/extracts a backup | +| delete | forget | removes a archive/snapshot | +| prune | forget (with --prune flag) | removes snapshots as per `--keep-*` config | + +You may specify either command and it will work with both except the `forget` command. This will only forget a single snapshot in restic. + ## Why create this when Borgmatic exists? `Borgmatic` is absolutely fantastic, and I love it dearly. I even implemented the `Uptime Kuma` hook that is in it. However, I got a little impatient waiting