updated readme with some delete/forget options

This commit is contained in:
Paul Wilde 2024-08-23 14:08:14 +01:00
parent 53a956bdfa
commit eaa47c9356
10 changed files with 84 additions and 25 deletions

View file

@ -23,7 +23,7 @@ proc checkRepo(nc: NorgConfig, repo: Repository): int =
echo "Not Yet Implemented." echo "Not Yet Implemented."
discard discard
proc execute*(nc: NorgConfig, repo: Repository) = proc execute*(nc: NorgConfig, repo: Repository): int {.discardable.} =
case nc.args.command case nc.args.command
of INIT: of INIT:
echo "Initializing repo: ", repo.label echo "Initializing repo: ", repo.label
@ -51,6 +51,9 @@ proc execute*(nc: NorgConfig, repo: Repository) =
echo "Pruning repo: ", repo.label echo "Pruning repo: ", repo.label
discard pruneRepo(nc, repo) discard pruneRepo(nc, repo)
run_actions(norg_config.actions.after_prune) run_actions(norg_config.actions.after_prune)
of DELETE:
echo "Deleting Archive ", nc.args.archive
discard deleteArchive(nc, repo)
of COMPACT: of COMPACT:
run_actions(norg_config.actions.before_compact) run_actions(norg_config.actions.before_compact)
discard compactRepo(nc, repo) discard compactRepo(nc, repo)

View file

@ -10,3 +10,8 @@ proc genCommand*(cmd: string, repo: string, further_args: seq[string]): string =
let cmd = fmt"{BORG_BIN} {cmd} {repo} {args}" let cmd = fmt"{BORG_BIN} {cmd} {repo} {args}"
return cmd 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

View file

@ -10,8 +10,8 @@ proc isEmpty(dir: string): bool =
return count == 0 return count == 0
proc extractArchive*(nc: NorgConfig, repo: Repository): int = proc extractArchive*(nc: NorgConfig, repo: Repository): int =
let archive = fmt"{repo.path}::{nc.args.further_args[0]}" let archive = fmt"{repo.path}::{nc.args.archive}"
var further_args = nc.args.further_args[1..^1] var further_args = nc.args.further_args
if nc.args.extract_destination != "": if nc.args.extract_destination != "":
discard existsOrCreateDir(nc.args.extract_destination) discard existsOrCreateDir(nc.args.extract_destination)
setCurrentDir(nc.args.extract_destination) setCurrentDir(nc.args.extract_destination)

View file

@ -3,8 +3,8 @@ import execute
import strformat import strformat
proc mountArchive*(nc: NorgConfig, repo: Repository): int = proc mountArchive*(nc: NorgConfig, repo: Repository): int =
let archive = repo.path & "::" & nc.args.further_args[0] let archive = fmt"{repo.path}::{nc.args.archive}"
let further_args = nc.args.further_args[1..^1] let further_args = nc.args.further_args
let ok = runDiscard genCommand(cmd = "mount", repo = archive, further_args = further_args) let ok = runDiscard genCommand(cmd = "mount", repo = archive, further_args = further_args)
if ok == 0: if ok == 0:
echo fmt"Mounted {archive} at {further_args[0]}" echo fmt"Mounted {archive} at {further_args[0]}"

View file

@ -1,19 +1,12 @@
import ../model/config_type import ../model/config_type
import strformat
import execute 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 = proc pruneRepo*(nc: NorgConfig, repo: Repository): int =
var cmd = genCommand(cmd = "prune", repo = repo.path, further_args = nc.args.further_args) var cmd = genCommand(cmd = "prune", repo = repo.path, further_args = nc.args.further_args)
cmd.addPruneOptions(nc.maintenance) cmd.addPruneOptions(nc.maintenance)
return run cmd 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

View file

@ -7,6 +7,7 @@ type
extract_destination*: string extract_destination*: string
command*: Command command*: Command
repository*: string repository*: string
archive*: string
further_args*: seq[string] further_args*: seq[string]
var norg_args*: NorgArgs = NorgArgs() var norg_args*: NorgArgs = NorgArgs()
@ -17,6 +18,7 @@ proc parseArgs*() =
option("-c", "--config", help="Config file to use.", required = true) option("-c", "--config", help="Config file to use.", required = true)
option("-d", "--destination", help="Destination when extracting backup", required = false) 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("-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("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.") arg("further_args", nargs = -1, help="Any further arguments to send onto borg or restic.")
try: try:
@ -25,6 +27,7 @@ proc parseArgs*() =
norg_args.extract_destination = opts.destination norg_args.extract_destination = opts.destination
norg_args.command = opts.command.toCommand() norg_args.command = opts.command.toCommand()
norg_args.repository = opts.repository norg_args.repository = opts.repository
norg_args.archive = opts.archive
norg_args.further_args = opts.further_args norg_args.further_args = opts.further_args
except ShortCircuit as err: except ShortCircuit as err:
if err.flag == "argparse_help": if err.flag == "argparse_help":

View file

@ -10,6 +10,7 @@ type
MOUNT = "mount", MOUNT = "mount",
UMOUNT = "umount", UMOUNT = "umount",
PRUNE = "prune", PRUNE = "prune",
DELETE = "delete"
CHECK = "check", CHECK = "check",
COMPACT = "compact" COMPACT = "compact"
@ -20,5 +21,6 @@ proc toCommand*(str: string): Command =
of "backup": return CREATE of "backup": return CREATE
of "snapshots","archives": return LIST of "snapshots","archives": return LIST
of "restore": return EXTRACT of "restore": return EXTRACT
of "forget": return DELETE

View file

@ -10,8 +10,8 @@ proc isEmpty(dir: string): bool =
return count == 0 return count == 0
proc restoreSnapshot*(nc: NorgConfig, repo: Repository): int = proc restoreSnapshot*(nc: NorgConfig, repo: Repository): int =
let repo_snapshot = fmt"{repo.path} {nc.args.further_args[0]}" let repo_snapshot = fmt"{repo.path} {nc.args.archive}"
var further_args = nc.args.further_args[1..^1] var further_args = nc.args.further_args
if nc.args.extract_destination != "": if nc.args.extract_destination != "":
discard existsOrCreateDir(nc.args.extract_destination) discard existsOrCreateDir(nc.args.extract_destination)
setCurrentDir(nc.args.extract_destination) setCurrentDir(nc.args.extract_destination)

View file

@ -1,6 +1,9 @@
import strformat import strformat
import osproc import osproc
import ../model/maintenance_type
proc run*(cmd: string): int = proc run*(cmd: string): int =
echo fmt"Trying to run : {cmd}" echo fmt"Trying to run : {cmd}"
try: try:
@ -18,3 +21,12 @@ proc runDiscard*(cmd: string): int =
except: except:
echo getCurrentExceptionMsg() echo getCurrentExceptionMsg()
return 1 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} \
"""

View file

@ -12,7 +12,7 @@ source_directories = [
"/home/me/Pictures" "/home/me/Pictures"
] ]
[[repositories]] [[repositories]]
label = "A Repository" label = "MyBorgRepo"
path = "/my/backup/location" path = "/my/backup/location"
[[repositories]] [[repositories]]
@ -33,7 +33,7 @@ base_url = "https://uptime.kuma.url/api/push/1234abcd"
states = ["Success","Failure", "Running"] 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** **Using BorgBackup**
```sh ```sh
@ -47,16 +47,24 @@ norg -c myconfig.toml create
norg -c myconfig.toml list norg -c myconfig.toml list
# Mount an Archive # 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 # Unmount an Archive
norg -c myconfig.toml umount /home/me/mnt norg -c myconfig.toml umount -r MyBorgRepo /home/me/mnt
# Extract an Archive # Extract an Archive
# You must be in an empty folder for this to work # 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 # 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_ **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 norg -c myconfig.toml mount -r MyResticRepo /home/me/mnt
# Restore an Archive (restore destination must be empty) # 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 # Build from Source
Download and build from source Download and build from source
```sh ```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). 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". 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? ## Why create this when Borgmatic exists?
`Borgmatic` is absolutely fantastic, and I love it dearly. I even implemented `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 the `Uptime Kuma` hook that is in it. However, I got a little impatient waiting