From 541b8f0381eef7aa4646cfd8631a60b7d78f0500 Mon Sep 17 00:00:00 2001 From: wgroeneveld Date: Wed, 15 Mar 2023 10:07:26 +0100 Subject: [PATCH] update readme for Linux installations --- .gitignore | 1 + README.md | 31 +++++++++++++++++++++---------- TODO.md | 8 ++++---- img/linux.jpg | Bin 0 -> 20594 bytes 4 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 img/linux.jpg diff --git a/.gitignore b/.gitignore index 784bde5..e791638 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea/ on_exit_*.txt restictray +restictray.tar.* config.json restictray.app/ .DS_Store diff --git a/README.md b/README.md index 610c9ca..290d338 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ # Restictray -A macOS system tray wrapper around [Restic](https://restic.net/), the Go-powered cmd-line backup tool. +A macOS and Linux system tray wrapper around [Restic](https://restic.net/), the Go-powered cmd-line backup tool. With Restictray, you can monitor and trigger backups from the system tray: ![](img/restictray.jpg) +Also tested & working on Linux: + +![](img/linux.jpg) + Restictray is designed in such a way that it checks whether or not a backup is needed every hour by looking at the latest date in the `restic snapshot` output that's also part of the menu. If the backup command fails, the SFTP network goes down, or your laptop is offline, it will resume next time it's booted. It's also possible to trigger a backup manually. @@ -19,32 +23,34 @@ This was designed for my wife to access backups with a button press. Restictray currently expects the following files in `~/.restic/`: -1. `password.txt` as hardcoded `--password-file` argument -2. `excludes.txt` as hardcoded `--exclude-file` argument -3. `config.json` that configures the repository, the folder(s)/file(s) to backup, and the interval in hours: +1. `password.txt` as hardcoded `--password-file` argument. If not present, creates the file with password "password". +2. `excludes.txt` as hardcoded `--exclude-file` argument. If not present, creates an empty excludes file. +3. `config.json` that configures the repository, the folder(s)/file(s) to backup. If not present, creates these defaults: ```json { - "repository": "sftp:user@server:/somewhere/resticdir", + "repository": "/tmp", "backup": "/Users/username", "backupTimeInHours": 24 } ``` -Where `repository` is the restic `-r` argument and `backup` the folder(s)/file(s) fed into the `backup` command. +If `config.json` exists but the key `backupTimeInHours` is absent, it will default to **24**: backup once a day. + +Where `repository` is the restic `-r` argument and `backup` the folder(s)/file(s) fed into the `backup` command. That is, you can use SFTP or S3 or ... as you'd normally do, using for instance `sftp:user@server:/somewhere/resticdir` as a `repository` value. **The repository should already be initialized!** You'll have to do this yourself using `restic -r [repo] init`. -If `backupTimeInHours` is absent, it will default to **24**: backup once a day. - For more information on how the restic arguments themselves work, please see the restic docs at https://restic.readthedocs.io/en/stable/. ### Dev config -If environment variable `RESTICTRAY_DEV` is set, Restictray configures Zerolog to use stdout and the prettyprint formatter instead of the external log, plus it relies on the `restic` command in `$PATH` instead of looking for it in the currently executing folder. +If environment variable `RESTICTRAY_DEV` is set, Restictray configures Zerolog to use stdout and the prettyprint formatter instead of the external log. ## Deploying +### macOS + Restictray can be wrapped as a macOS `.app` folder that can be distributed. See `build.sh` on how to do this---I've used `fyne package`: see docs at https://developer.fyne.io/started/packaging. ![](img/restictray-app.jpg) @@ -53,6 +59,11 @@ The app also wraps the `restic` binary so no local install is needed. Please note that the current supplied one in `build/` is an ARM64 macOS-specific binary for that very reason. +### Linux + +Just `go build` and copy the binary to install. On Linux you will need to install Restic yourself using your favorite package manager or via the [Restic installation page](https://restic.net/#installation). + ## Troubleshooting -Restictray uses Lumberjack and Zerolog to log info to `~/.restic/log.txt`. If a command fails, it should be logged there. \ No newline at end of file +Restictray uses Lumberjack and Zerolog to log info to `~/.restic/log.txt`. If a command fails, it should be logged there. + diff --git a/TODO.md b/TODO.md index 3d62acd..597437a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,10 @@ # TODO -- [ ] Write README +- [X] Write README - [X] `restic backup` can take a long time: stream output to logging somehow to keep track of what it's doing. Stop using `--json` for `backup`, generates way too much JSON log info. -- [ ] Make Restictray non-dependent on existing config in `~/.restic`: - - [ ] Create default files if not existing? +- [X] Make Restictray non-dependent on existing config in `~/.restic`: + - [X] Create default files if not existing? - [ ] Create a config dialog in https://developer.fyne.io/ - [ ] Add additional resilience: - [X] What if SSH backup and network goes down? Do a `ping` before backup? Is there a timeout from the `restic` command itself? @@ -15,4 +15,4 @@ - [ ] `restic list locks` showed a dangling one; PID of already gone `restic` process. Why? Unable to reproduce? - [ ] Verify backups with `restic check`? If not okay, remove (snapshot/folder?) and rebackup? What's the plan then? - [ ] Implement `restic init`, reducing the need for an existing backup -- [ ] Cross-platform compatibility with Linux? Shouldn't be hard. \ No newline at end of file +- [X] Cross-platform compatibility with Linux? Shouldn't be hard. \ No newline at end of file diff --git a/img/linux.jpg b/img/linux.jpg new file mode 100644 index 0000000000000000000000000000000000000000..987c4e0af3980655091fa89f8c04e9a9f8ef505e GIT binary patch literal 20594 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 SaDL%rWgMc&ap|z<|C<2nb*T6N literal 0 HcmV?d00001