Compare commits

...

802 Commits
1.8.10 ... main

Author SHA1 Message Date
345b4cfb09 Add support for new Borg placeholder "{unixtime}".
All checks were successful
build / test (push) Successful in 11m36s
build / docs (push) Successful in 1m21s
2025-04-23 10:07:33 -07:00
5465b60d37 Bump version for release.
All checks were successful
build / test (push) Successful in 6m41s
build / docs (push) Successful in 1m3s
2025-04-22 14:11:36 -07:00
e2b5972c09 Fix end-to-end tests (#1072).
All checks were successful
build / test (push) Successful in 6m43s
build / docs (push) Successful in 1m30s
2025-04-21 23:11:38 -07:00
9bf316e28f If the exact same "everything" command hook is present in multiple configuration files, borgmatic only runs it once (#1080).
Some checks failed
build / test (push) Failing after 6m40s
build / docs (push) Has been skipped
2025-04-21 19:19:36 -07:00
3847f31939 Fix path rewriting for non-root patterns in the ZFS, Btrfs, and LVM hooks (#1072).
Some checks failed
build / test (push) Failing after 11m12s
build / docs (push) Has been skipped
2025-04-21 10:07:46 -07:00
a815d2dfdb Clarify the documentation about when an "after: error" command hook runs and how it differs from other hooks (#1073).
All checks were successful
build / test (push) Successful in 6m44s
build / docs (push) Successful in 1m2s
2025-04-20 16:00:14 -07:00
6ebfd60e21 Fix an incorrect warning about Borg placeholders being unsupported in a command hook (#1075).
All checks were successful
build / test (push) Successful in 10m53s
build / docs (push) Successful in 1m20s
2025-04-20 15:06:21 -07:00
c3c37dee13 Only build and deploy docs on pushes to main, not for pull requests.
All checks were successful
build / test (push) Successful in 8m8s
build / docs (push) Successful in 1m22s
2025-04-17 20:51:40 -07:00
13d49fda9b Bump version for release.
All checks were successful
build / test (push) Successful in 6m45s
build / docs (push) Successful in 1m19s
2025-04-14 22:53:23 -07:00
b01b8498aa Fix an error in the LVM hook when removing a snapshot directory (#1071).
Some checks failed
build / docs (push) Has been cancelled
build / test (push) Has been cancelled
2025-04-14 22:48:36 -07:00
a573e606a5 Add a "states" option to command hooks, so you can optionally skip an "after" hook if borgmatic encounters an error (#1066).
All checks were successful
build / test (push) Successful in 11m14s
build / docs (push) Successful in 1m25s
2025-04-12 15:02:47 -07:00
81db67c759 Fix a regression in monitoring hooks in which an error pinged the finish state instead of the fail state (#1065).
All checks were successful
build / test (push) Successful in 11m14s
build / docs (push) Successful in 1m19s
2025-04-09 11:32:59 -07:00
0b4aff9277 Bump version for release.
All checks were successful
build / test (push) Successful in 6m46s
build / docs (push) Successful in 59s
2025-04-08 12:07:16 -07:00
7de1c2121c List the configured "when" action names in the log entries for command hooks (#1063).
All checks were successful
build / test (push) Successful in 6m36s
build / docs (push) Successful in 1m8s
2025-04-08 12:04:10 -07:00
2c8dc5858f Fix a regression that broke environment variable interpolation (#1062).
Some checks failed
build / test (push) Failing after 2m1s
build / docs (push) Has been skipped
2025-04-08 11:55:26 -07:00
f27a96e22d Display a nicer error message when the "recreate" action encounters an archive that already exists (#1053).
All checks were successful
build / test (push) Successful in 6m34s
build / docs (push) Successful in 1m0s
2025-04-08 10:58:53 -07:00
a892a308bd Display a nicer error message when running the "recreate" action on a leftover temporary archive from a prior recreate run (#1053).
All checks were successful
build / test (push) Successful in 6m33s
build / docs (push) Successful in 1m13s
2025-04-08 10:13:04 -07:00
2db023f785 Don't run action command hooks for actions listed in the "skip_actions" option (#1060).
All checks were successful
build / test (push) Successful in 6m33s
build / docs (push) Successful in 1m19s
2025-04-07 23:10:59 -07:00
edaca2b3cd Fix command hooks getting run too many times when multiple borgmatic actions are executed (#1060).
Some checks failed
build / docs (push) Has been cancelled
build / test (push) Has been cancelled
2025-04-07 23:00:29 -07:00
bc79eafb0b Document potential performance issues and workarounds with the ZFS, Btrfs, and LVM hooks (#1035).
All checks were successful
build / test (push) Successful in 6m30s
build / docs (push) Successful in 1m2s
2025-04-07 13:51:20 -07:00
68fafffe99 Fix a regression in which soft failure exit codes in command hooks were not respected (#1059).
All checks were successful
build / test (push) Successful in 6m30s
build / docs (push) Successful in 1m5s
2025-04-07 10:29:51 -07:00
6c068a297a Update README to use new command hooks in the example.
All checks were successful
build / test (push) Successful in 6m36s
build / docs (push) Successful in 1m7s
2025-04-06 23:29:12 -07:00
06a6444c86 Expand test that checks whether schema actions correspond to supported actions.
All checks were successful
build / test (push) Successful in 6m34s
build / docs (push) Successful in 1m0s
2025-04-06 21:25:06 -07:00
f6de79060e Omit "pattern" from missing actions test (#1056).
All checks were successful
build / test (push) Successful in 13m36s
build / docs (push) Successful in 1m22s
2025-04-06 20:57:15 -07:00
0d94a6587a Move pattern and flag functions from create.py into their own module (#1056).
Some checks failed
build / test (push) Failing after 3s
build / docs (push) Has been skipped
Reviewed-on: #1056
Reviewed-by: Dan Helfman <witten@torsion.org>
2025-04-07 03:51:36 +00:00
2f535056ee Removing asterisk escaping from release script, which apparently breaks Gitea changelog posting.
All checks were successful
build / test (push) Successful in 6m34s
build / docs (push) Successful in 1m10s
2025-04-06 15:27:58 -07:00
074db68a1b Bump version for release.
Some checks failed
build / test (push) Successful in 6m37s
build / docs (push) Has been cancelled
2025-04-06 15:21:03 -07:00
3cd5c1290d Fix argument parsing to avoid using Python 3.12+ string features (#1057). 2025-04-06 15:20:29 -07:00
66a636e994 Add more escaping to release script changelog output.
All checks were successful
build / test (push) Successful in 6m37s
build / docs (push) Successful in 59s
2025-04-06 09:04:54 -07:00
Vandal
360156e3b1 refactor codebase 2025-04-06 21:34:04 +05:30
b25bfbe913 Bump version for release.
All checks were successful
build / test (push) Successful in 10m51s
build / docs (push) Successful in 1m18s
2025-04-06 08:22:28 -07:00
acb9aace1d Include pull requests in build action, so they're covered by CI.
All checks were successful
build / test (push) Successful in 6m31s
build / docs (push) Successful in 1m0s
2025-04-05 20:20:45 -07:00
e6ae0b73d4 Rephrase NEWS entry. 2025-04-05 16:59:40 -07:00
7ee0d3563b Add configuration options for all verbosity and logging flags (#793).
All checks were successful
build / test (push) Successful in 10m48s
build / docs (push) Successful in 1m18s
Reviewed-on: #1055
2025-04-05 23:13:17 +00:00
edee3c3788 Fix broken monitoring verbosity (#793). 2025-04-05 16:11:42 -07:00
445f700b09 Fix log file format example. 2025-04-05 14:42:16 -07:00
732634f7ba Add an additional test (#793). 2025-04-04 18:49:20 -07:00
ad9f037ec5 Add documentation for verbosity/logging configuration options (#793). 2025-04-04 18:29:51 -07:00
c0adc4f9df Add test coverage for new code (#793). 2025-04-04 17:19:14 -07:00
49839e884a Add configuration options for logging and verbosity (#793). 2025-04-04 10:11:00 -07:00
828ada085b Add a deprecated, top-level "color" option back in for backwards compatibility. 2025-04-03 19:52:00 -07:00
93b1172266 Remove merge conflict artifacts. 2025-04-03 17:31:06 -07:00
c6ce9c70ab Merge branch 'main' into logging-verbosity-config. 2025-04-03 17:29:59 -07:00
929d343214 Add CLI flags for every config option and add config options for many action flags (#303).
All checks were successful
build / test (push) Successful in 6m25s
build / docs (push) Successful in 1m12s
Reviewed-on: #1040
2025-04-03 23:48:49 +00:00
9ea55d9aa3 Add a documentation note about a limitation: You can't pass flags as values to flags (#303). 2025-04-03 16:38:17 -07:00
3eabda45f2 If a boolean option name already starts with "no_", don't add a "--no-no-..." CLI flag (#303). 2025-04-03 16:21:22 -07:00
09212961a4 Add action "--help" note about running compact after recreate (#1053).
All checks were successful
build / test (push) Successful in 5m49s
build / docs (push) Successful in 1m4s
2025-04-03 12:55:26 -07:00
3f25f3f0ff Merge branch 'main' into config-command-line. 2025-04-03 11:47:29 -07:00
e8542f3613 Fix KeePassXC error when "keepassxc:" option is not present, add new options to NEWS (#1047).
All checks were successful
build / test (push) Successful in 5m51s
build / docs (push) Successful in 1m13s
2025-04-03 11:41:58 -07:00
9407f24674 Fix setting of "--checks" on the command-line (#303). 2025-04-03 11:28:32 -07:00
1c9d25b892 Add "key-file" and "yubikey" options to KeePassXC credential hook (#1047).
Some checks failed
build / test (push) Failing after 5m52s
build / docs (push) Has been skipped
Reviewed-on: #1049
2025-04-03 18:28:08 +00:00
248999c23e Final 2025-04-03 17:10:52 +00:00
d0a5aa63be Add a TL;DR to NEWS since 2.0.0 is such a huge release and ain't nobody got time for reading a huge changelog. 2025-04-03 09:24:47 -07:00
d2c3ed26a9 Make a CLI flag for any config option that's a list of scalars (#303). 2025-04-02 23:15:21 -07:00
bbf6f27715 For boolean configuration options, add separate "--foo" and "--no-foo" CLI flags (#303). 2025-04-02 17:08:04 -07:00
9301ab13cc Merge branch 'main' into config-command-line. 2025-04-02 09:55:33 -07:00
d5d04b89dc Add configuration filename to "Successfully ran configuration file" log message (#1051).
All checks were successful
build / test (push) Successful in 10m4s
build / docs (push) Successful in 1m14s
2025-04-02 09:50:31 -07:00
364200c65a Fix incorrect matching of non-zero array index flags with dashed names (#303). 2025-04-02 09:37:52 -07:00
4e55547235 Command Restructuring 2025-04-02 15:35:12 +00:00
96ec66de79 Applied changes 2025-04-02 10:50:25 +00:00
7a0c56878b Applied changes 2025-04-02 10:47:35 +00:00
4065c5d0f7 Fix use of dashed command-line flags like "--repositories[2].append-only" generated from configuration (#303). 2025-04-01 23:04:53 -07:00
affe7cdc1b Expose propertyless YAML objects from configuration (e.g. "constants") as command-line flags (#303). 2025-04-01 21:05:44 -07:00
017cbae4f9 Fix for the example not showing up in generated config for empty YAML objects (#303). 2025-04-01 19:44:47 -07:00
e96db2e100 Fix "progress" option with the "transfer" action (#303). 2025-04-01 19:43:56 -07:00
af97b95e2b Merge branch 'main' into config-command-line. 2025-04-01 12:09:54 -07:00
6a61259f1a Fix a failure in the "spot" check when the archive contains a symlink (#1050).
All checks were successful
build / test (push) Successful in 10m19s
build / docs (push) Successful in 1m14s
2025-04-01 11:49:47 -07:00
5490a83d77 Merge branch 'main' into config-command-line. 2025-03-31 17:13:20 -07:00
8c907bb5a3 Fix broken "recreate" action with Borg 1.4 (#610).
All checks were successful
build / test (push) Successful in 9m49s
build / docs (push) Successful in 1m14s
2025-03-31 17:11:37 -07:00
f166111b9b Fix new "repositories:" sub-options ("append_only", "make_parent_directories", etc.) (#303). 2025-03-31 15:26:24 -07:00
10fb02c40a Fix bootstrap --progress flag (#303). 2025-03-31 13:33:39 -07:00
cf477bdc1c Fix broken list_details, progress, and statistics options (#303). 2025-03-31 11:33:56 -07:00
6f07402407 Fix end-to-end tests and don't stat() directories that don't exist (#1048).
All checks were successful
build / test (push) Successful in 5m52s
build / docs (push) Successful in 55s
2025-03-30 19:04:36 -07:00
ab01e97a5e Fix a "no such file or directory" error in ZFS, Btrfs, and LVM hooks with nested directories that reside on separate devices/filesystems (#1048).
Some checks failed
build / test (push) Failing after 5m40s
build / docs (push) Has been skipped
2025-03-30 14:55:54 -07:00
92ebc77597 2nd Draft 2025-03-30 16:19:56 +00:00
863c954144 added schema.yaml 2025-03-30 15:57:42 +00:00
f7e4d38762 First Draft 2025-03-30 14:02:56 +00:00
de4d7af507 Merge branch 'main' into config-command-line. 2025-03-29 22:52:40 -07:00
5cea1e1b72 Fix flake error (#262).
All checks were successful
build / test (push) Successful in 5m52s
build / docs (push) Successful in 1m15s
2025-03-29 22:52:17 -07:00
fd8c11eb0a Add documentation for "native" command-line overrides without --override (#303). 2025-03-29 21:59:47 -07:00
92de539bf9 Merge branch 'main' into config-command-line. 2025-03-29 19:55:03 -07:00
5716e61f8f Code formatting (#262).
Some checks failed
build / test (push) Failing after 1m49s
build / docs (push) Has been skipped
2025-03-29 19:54:40 -07:00
3e05eeb4de Merge branch 'main' into config-command-line. 2025-03-29 19:03:29 -07:00
65d1b9235d Add "default_actions" to NEWS (#262).
Some checks failed
build / test (push) Failing after 1m43s
build / docs (push) Has been skipped
2025-03-29 19:02:11 -07:00
cffb8e88da Merge branch 'main' of ssh://projects.torsion.org:3022/borgmatic-collective/borgmatic into config-command-line 2025-03-29 18:58:12 -07:00
a8362f2618 borgmatic without arguments/parameters should show usage help instead of starting a backup (#262).
Some checks failed
build / test (push) Failing after 1m42s
build / docs (push) Has been skipped
Reviewed-on: #1046
2025-03-30 01:57:11 +00:00
36265eea7d Docs update 2025-03-30 01:34:30 +00:00
8101e5c56f Add "list_details" config option support to new "recreate" action (#303). 2025-03-29 15:24:37 -07:00
c7feb16ab5 Merge branch 'main' into config-command-line. 2025-03-29 15:16:29 -07:00
da324ebeb7 Add "recreate" action to NEWS and docs (#610).
All checks were successful
build / test (push) Successful in 5m48s
build / docs (push) Successful in 1m15s
2025-03-29 15:15:36 -07:00
59f9d56aae Add a recreate action (#1030).
Some checks failed
build / docs (push) Has been cancelled
build / test (push) Has been cancelled
Reviewed-on: #1030
2025-03-29 22:07:52 +00:00
Vandal
dbf2e78f62 help changes 2025-03-30 03:05:46 +05:30
f6929f8891 Add last couple of missing tests after audit (#303). 2025-03-29 14:26:54 -07:00
Vandal
2716d9d0b0 add to schema 2025-03-29 23:25:50 +05:30
668f767bfc Adding some missing tests and fixing related flag vs. config logic (#303). 2025-03-28 23:11:15 -07:00
0182dbd914 Added 2 new unit tests and updated docs 2025-03-29 03:43:58 +00:00
1c27e0dadc Add an end-to-end test for command-line flags of configuration options (#303). 2025-03-28 13:46:58 -07:00
Vandal
8b3a682edf add tests and minor fixes 2025-03-29 01:26:20 +05:30
975a6e4540 Add additional tests for complete coverage (#303). 2025-03-28 11:37:48 -07:00
Vandal
7020f0530a update existing tests 2025-03-28 22:22:19 +05:30
5bf2f546b9 More automated tests (#303). 2025-03-27 21:01:56 -07:00
b4c558d013 Add tests for CLI arguments from schema logic (#303). 2025-03-27 16:49:14 -07:00
79bf641668 Set the action type when cloning an argument for a list index flag (#303). 2025-03-27 12:42:49 -07:00
50beb334dc Add tests for adding array element arguments and fix the code under test (#303). 2025-03-27 11:07:25 -07:00
Vandal
26fd41da92 add rest of flags 2025-03-27 22:18:34 +05:30
088da19012 Added Unit Tests 2025-03-27 11:26:56 +00:00
4c6674e0ad Merge branch 'main' into config-command-line. 2025-03-26 22:14:36 -07:00
486bec698d Add "key import" to reference documentation (#345).
All checks were successful
build / test (push) Successful in 9m59s
build / docs (push) Successful in 1m14s
2025-03-26 22:13:30 -07:00
7a766c717e 2nd Draft 2025-03-27 02:55:16 +00:00
520fb78a00 Clarify Btrfs documentation: borgmatic expects subvolume mount points in "source_directories" (#1043).
All checks were successful
build / test (push) Successful in 5m49s
build / docs (push) Successful in 59s
2025-03-26 11:39:16 -07:00
Vandal
acc2814f11 add archive timestamp filter 2025-03-26 23:39:06 +05:30
996b037946 1st 2025-03-26 17:39:10 +00:00
Vandal
9356924418 add archive options 2025-03-26 22:30:11 +05:30
79e4e089ee Fix typo in NEWS (#1044).
All checks were successful
build / test (push) Successful in 5m50s
build / docs (push) Successful in 1m0s
2025-03-26 09:57:53 -07:00
d2714cb706 Fix an error in the systemd credential hook when the credential name contains a "." chararcter (#1044).
Some checks failed
build / test (push) Failing after 1m48s
build / docs (push) Has been skipped
2025-03-26 09:53:52 -07:00
5a0430b9c8 Merge branch 'main' into config-command-line. 2025-03-25 22:39:51 -07:00
23efbb8df3 Fix line wrapping / code style (#837).
All checks were successful
build / test (push) Successful in 8m7s
build / docs (push) Successful in 1m12s
2025-03-25 22:31:50 -07:00
9e694e4df9 Add MongoDB custom command options to NEWS (#837).
Some checks failed
build / docs (push) Has been cancelled
build / test (push) Has been cancelled
2025-03-25 22:28:14 -07:00
76f7c53a1c Add custom command options for MongoDB hook (#837).
Some checks failed
build / docs (push) Has been cancelled
build / test (push) Has been cancelled
Reviewed-on: #1041
2025-03-26 05:27:03 +00:00
Vandal
203e84b91f hotfix 2025-03-25 21:57:06 +05:30
Vandal
ea5a2d8a46 add tests for the flags 2025-03-25 20:39:02 +05:30
Vandal
a8726c408a add tests 2025-03-25 19:35:15 +05:30
Vandal
3542673446 add test recreate with skip action 2025-03-25 11:36:06 +05:30
532a97623c Added test_build_restore_command_prevents_shell_injection() 2025-03-25 04:50:45 +00:00
e1fdfe4c2f Add credential hook directory expansion to NEWS (#422).
All checks were successful
build / test (push) Successful in 8m40s
build / docs (push) Successful in 1m15s
2025-03-24 13:00:38 -07:00
83a56a3fef Add directory expansion for file-based and KeyPassXC credential hooks (#1042).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #1042
2025-03-24 19:57:18 +00:00
Vandal
b60cf2449a add recreate to schema 2025-03-25 00:48:27 +05:30
Vandal
e7f14bca87 add tests and requested changes 2025-03-25 00:16:20 +05:30
Nish_
4bca7bb198 add directory expansion for file-based and KeyPassXC credentials
Signed-off-by: Nish_ <120EE0980@nitrkl.ac.in>
2025-03-24 21:04:55 +05:30
Vandal
fa3b140590 add patterns 2025-03-24 12:09:08 +05:30
Vandal
a1d2f7f221 add path 2025-03-24 11:51:33 +05:30
6a470be924 Made some changes in test file 2025-03-24 03:53:42 +00:00
d651813601 Custom command options for MongoDB hook #837 2025-03-24 03:39:26 +00:00
65b1d8e8b2 Clarify NEWS items (#303). 2025-03-23 19:13:07 -07:00
16a1121649 Get existing end-to-end tests passing (#303). 2025-03-23 18:45:49 -07:00
423627e67b Get existing unit/integration tests passing (#303). 2025-03-23 17:00:04 -07:00
9f7c71265e Add Bash completion for completing flags like "--foo[3].bar". 2025-03-23 16:32:31 -07:00
ba75958a2f Fix missing argument descriptions (#303). 2025-03-23 11:26:49 -07:00
57721937a3 Factor out schema type comparion in config generation and get several tests passing (#303). 2025-03-23 11:24:36 -07:00
f222bf2c1a Organizational refactoring (#303). 2025-03-22 22:52:23 -07:00
dc9da3832d Bold "not yet released" in docs to prevent confusion (#303). 2025-03-22 14:03:44 -07:00
f8eda92379 Code formatting (#303). 2025-03-22 14:01:39 -07:00
cc14421460 Fix list examples in generated configuration. 2025-03-22 13:58:42 -07:00
Vandal
a750d58a2d add recreate action 2025-03-22 21:18:28 +05:30
2045706faa merge upstream 2025-03-22 13:00:07 +00:00
976fb8f343 Add "compact_threshold" option, overridden by "compact --threshold" flag (#303). 2025-03-21 22:44:49 -07:00
5246a10b99 Merge branch 'main' into config-command-line. 2025-03-21 15:44:12 -07:00
524ec6b3cb Add "extract" action fix to NEWS (#1037).
All checks were successful
build / test (push) Successful in 8m11s
build / docs (push) Successful in 1m22s
2025-03-21 15:43:05 -07:00
6f1c77bc7d Merge branch 'main' of ssh://projects.torsion.org:3022/borgmatic-collective/borgmatic into config-command-line 2025-03-21 15:40:27 -07:00
7904ffb641 Fix extracting from remote repositories with working_directory defined (#1037).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #1038
Reviewed-by: Dan Helfman <witten@torsion.org>
2025-03-21 22:40:18 +00:00
cd5ba81748 Fix docs: Crontabs aren't executable (#1039).
All checks were successful
build / test (push) Successful in 5m59s
build / docs (push) Successful in 59s
Reviewed-on: #1039
2025-03-21 21:32:38 +00:00
5c11052b8c Merge branch 'main' into config-command-line 2025-03-21 14:30:39 -07:00
514ade6609 Fix inconsistent quotes in one documentation file (#790).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-03-21 14:27:40 -07:00
201469e2c2 Add "key import" action to NEWS (#345).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-03-21 14:26:01 -07:00
9ac2a2e286 Add key import action to import a copy of repository key from backup (#345).
Some checks failed
build / test (push) Failing after 1m41s
build / docs (push) Has been skipped
Reviewed-on: #1036
Reviewed-by: Dan Helfman <witten@torsion.org>
2025-03-21 21:22:50 +00:00
Benjamin Bock
a16d138afc Crontabs aren't executable 2025-03-21 21:58:02 +01:00
Benjamin Bock
81a3a99578 Fix extracting from remote repositories with working_directory defined 2025-03-21 21:34:46 +01:00
f3cc3b1b65 Merge branch 'main' into config-command-line 2025-03-21 11:10:19 -07:00
587d31de7c Run all command hooks respecting the "working_directory" option if configured (#790).
All checks were successful
build / test (push) Successful in 10m15s
build / docs (push) Successful in 1m14s
2025-03-21 10:53:06 -07:00
cbfc0bead1 Exclude --match-archives from global flags since it already exists on several actions (#303). 2025-03-21 09:56:42 -07:00
Nish_
8aaa5ba8a6 minor changes
Signed-off-by: Nish_ <120EE0980@nitrkl.ac.in>
2025-03-21 19:26:12 +05:30
7d989f727d Don't auto-add CLI flags for configuration options that already have per-action CLI flags (#303). 2025-03-20 12:23:00 -07:00
Nish_
5525b467ef add key import command
Signed-off-by: Nish_ <120EE0980@nitrkl.ac.in>
2025-03-21 00:47:45 +05:30
89c98de122 Merge branch 'main' into config-command-line. 2025-03-20 11:37:04 -07:00
c2409d9968 Remove the "dump_data_sources" command hook, as it doesn't really solve the use case and works differently than all the other command hooks (#790).
All checks were successful
build / test (push) Successful in 5m47s
build / docs (push) Successful in 1m6s
2025-03-20 11:13:37 -07:00
624a7de622 Document "after" command hooks running in case of error and make sure that happens in case of "before" hook error (#790).
All checks were successful
build / test (push) Successful in 10m16s
build / docs (push) Successful in 1m22s
2025-03-20 10:57:39 -07:00
3119c924b4 In configuration option descriptions, remove mention of corresponding CLI flags because it looks dumb on the command-line help (#303). 2025-03-19 23:08:26 -07:00
ed6022d4a9 Add "list" option to configuration, corresponding to "--list" (#303). 2025-03-19 23:05:38 -07:00
3e21cdb579 Add "stats" option to configuration (#303). 2025-03-19 19:43:04 -07:00
d02d31f445 Use schema defaults instead of a flag name whitelist to make valueless boolean flags (#303). 2025-03-19 11:37:17 -07:00
1097a6576f Add "progress" option to configuration (#303). 2025-03-19 11:06:36 -07:00
63b0c69794 Add additional options under "repositories:" for parity with repo-create #303. 2025-03-18 20:54:14 -07:00
Vandal
4e2805918d update borg/recreate.py 2025-03-18 23:19:33 +05:30
711f5fa6cb UX nicety to make default-false boolean options into valueless CLI flags (#303). 2025-03-17 22:58:25 -07:00
93e7da823c Add an encryption option to repositories (#303). 2025-03-17 22:24:01 -07:00
903308864c Factor out schema type parsing (#303). 2025-03-17 10:46:02 -07:00
d75c8609c5 Merge branch 'main' into config-command-line 2025-03-17 10:34:20 -07:00
c926f0bd5d Clarify documentation for dump_data_sources command hook (#790).
All checks were successful
build / test (push) Successful in 10m21s
build / docs (push) Successful in 1m14s
2025-03-17 10:31:34 -07:00
7b14e8c7f2 Add feature to NEWS (#303). 2025-03-17 10:17:04 -07:00
87b9ad5aea Code formatting (#303). 2025-03-17 10:02:25 -07:00
eca78fbc2c Support setting whole lists and dicts from the command-line (#303). 2025-03-17 09:57:25 -07:00
Vandal
6adb0fd44c add borg recreate 2025-03-17 22:24:53 +05:30
05900c188f Expand docstrings (#303). 2025-03-15 22:58:39 -07:00
1d5713c4c5 Updated outdated schema comment referencing ~/.borgmatic path (#836).
All checks were successful
build / test (push) Successful in 6m7s
build / docs (push) Successful in 1m13s
2025-03-15 21:42:45 -07:00
f9612cc685 Add SQLite custom command option to NEWS (#836). 2025-03-15 21:37:23 -07:00
5742a1a2d9 Add custom command option for SQLite hook (#836).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #1027
2025-03-16 04:34:15 +00:00
Nish_
c84815bfb0 add custom dump and restore commands for sqlite hook
Signed-off-by: Nish_ <120EE0980@nitrkl.ac.in>
2025-03-16 09:07:49 +05:30
e1ff51ff1e Merge branch 'main' into config-command-line. 2025-03-15 10:03:59 -07:00
1c92d84e09 Add Borg 2 "prune --stats" flag change to NEWS (#1010).
All checks were successful
build / test (push) Successful in 9m59s
build / docs (push) Successful in 1m33s
2025-03-15 10:02:47 -07:00
1d94fb501f Conditionally pass --stats to prune based on Borg version (#1010).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #1026
2025-03-15 16:59:50 +00:00
92279d3c71 Initial work on command-line flags for all configuration (#303). 2025-03-14 22:59:43 -07:00
Nish_
1b4c94ad1e Add feature toggle to pass --stats to prune on Borg 1, but not Borg 2
Signed-off-by: Nish_ <120EE0980@nitrkl.ac.in>
2025-03-15 09:56:14 +05:30
901e668c76 Document a database use case involving a temporary database client container (#1020).
All checks were successful
build / test (push) Successful in 7m37s
build / docs (push) Successful in 1m30s
2025-03-12 17:10:35 -07:00
bcb224a243 Claim another implemented ticket in NEWS (#821).
All checks were successful
build / test (push) Successful in 7m35s
build / docs (push) Successful in 1m25s
2025-03-12 14:31:13 -07:00
6b6e1e0336 Make the "configuration" command hook support "error" hooks and also pinging monitoring on failure (#790).
All checks were successful
build / test (push) Successful in 12m18s
build / docs (push) Successful in 1m53s
2025-03-12 14:13:29 -07:00
f5c9bc4fa9 Add a "not yet released" note on 2.0.0 in docs (#790).
All checks were successful
build / test (push) Successful in 7m15s
build / docs (push) Successful in 1m35s
2025-03-11 16:46:07 -07:00
cdd0e6f052 Fix incorrect kwarg in LVM hook (#790).
All checks were successful
build / test (push) Successful in 7m3s
build / docs (push) Successful in 1m36s
2025-03-11 14:42:25 -07:00
7bdbadbac2 Deprecate all "before_*", "after_*" and "on_error" command hooks in favor of more flexible "commands:" (#790).
Some checks failed
build / test (push) Failing after 15m7s
build / docs (push) Has been skipped
Reviewed-on: #1019
2025-03-11 21:22:33 +00:00
d3413e0907 Documentation clarification (#1019). 2025-03-11 14:20:42 -07:00
8a20ee7304 Fix typo in documentation (#1019). 2025-03-11 14:08:53 -07:00
325f53c286 Context tweaks + mention configuration upgrade in command hook documentation (#1019). 2025-03-11 14:07:06 -07:00
b4d24798bf More command hook documentation updates (#1019). 2025-03-11 13:03:58 -07:00
7965eb9de3 Correctly handle errors in command hooks (#1019). 2025-03-11 11:36:28 -07:00
8817364e6d Documentation on command hooks (#1019). 2025-03-10 22:38:48 -07:00
965740c778 Update version of command hooks since they didn't get released in 1.9.14 (#1019). 2025-03-10 10:37:09 -07:00
2a0319f02f Merge branch 'main' into unified-command-hooks. 2025-03-10 10:35:36 -07:00
fbdb09b87d Bump version for release.
All checks were successful
build / test (push) Successful in 6m42s
build / docs (push) Successful in 1m19s
2025-03-10 10:17:36 -07:00
bec5a0c0ca Fix end-to-end tests for Btrfs (#1023).
All checks were successful
build / test (push) Successful in 6m50s
build / docs (push) Successful in 1m38s
2025-03-10 10:15:23 -07:00
4ee7f72696 Fix an error in the Btrfs hook when attempting to snapshot a read-only subvolume (#1023).
Some checks failed
build / test (push) Failing after 6m54s
build / docs (push) Has been skipped
2025-03-09 23:04:55 -07:00
9941d7dc57 More docs and command hook context tweaks (#1019). 2025-03-09 17:01:46 -07:00
ec88bb2e9c Merge branch 'main' into unified-command-hooks. 2025-03-09 13:37:17 -07:00
68b6d01071 Fix a regression in which the "exclude_patterns" option didn't expand "~" (#1021).
All checks were successful
build / test (push) Successful in 7m11s
build / docs (push) Successful in 1m31s
2025-03-09 13:35:22 -07:00
b52339652f Initial command hooks documentation work (#1019). 2025-03-09 09:57:13 -07:00
4fd22b2df0 Merge branch 'main' into unified-command-hooks. 2025-03-08 21:02:04 -08:00
86b138e73b Clarify command hook documentation.
All checks were successful
build / test (push) Successful in 11m29s
build / docs (push) Successful in 1m44s
2025-03-08 21:00:58 -08:00
5ab766b51c Add a few more missing tests (#1019). 2025-03-08 20:55:13 -08:00
45c114973c Add missing test coverage for new/changed code (#1019). 2025-03-08 18:31:16 -08:00
6a96a78cf1 Fix existing tests (#1019). 2025-03-07 22:58:25 -08:00
e06c6740f2 Switch to context manager for running "dump_data_sources" before/after hooks (#790). 2025-03-07 10:33:39 -08:00
10bd1c7b41 Remove restore_data_source_dump as a command hook for now (#790). 2025-03-06 22:53:19 -08:00
d4f48a3a9e Initial work on unified command hooks (#790). 2025-03-06 11:23:24 -08:00
c76a108422 Link to Zabbix documentation from NEWS. 2025-03-06 10:37:00 -08:00
eb5dc128bf Fix incorrect test name (#1017).
All checks were successful
build / test (push) Successful in 7m10s
build / docs (push) Successful in 1m32s
2025-03-06 10:34:28 -08:00
1d486d024b Fix a regression in which some MariaDB/MySQL passwords were not escaped correctly (#1017).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-03-06 10:32:38 -08:00
5a8f27d75c Add single quotes around the MariaDB password (#1017).
All checks were successful
build / test (push) Successful in 11m51s
build / docs (push) Successful in 1m41s
Reviewed-on: #1017
2025-03-06 18:01:43 +00:00
a926b413bc Updating automated test, and fixing linting errors. 2025-03-06 09:00:33 -03:30
18ffd96d62 Add single quotes around the password.
When the DB password uses some special characters, the
defaults-extra-file can be incorrect. In the case of a password with
the # symbol, anything after that is considered a comment. The single
quotes around the password rectify this.
2025-03-05 22:51:41 -03:30
c0135864c2 With the PagerDuty monitoring hook, send borgmatic logs to PagerDuty so they show up in the incident UI (#409).
All checks were successful
build / test (push) Successful in 10m48s
build / docs (push) Successful in 2m50s
2025-03-04 08:55:09 -08:00
ddfd3c6ca1 Clarify Zabbix monitoring hook documentation about creating items (#936).
All checks were successful
build / test (push) Successful in 7m54s
build / docs (push) Successful in 1m40s
2025-03-03 16:02:22 -08:00
dbe82ff11e Bump version for release.
All checks were successful
build / test (push) Successful in 6m46s
build / docs (push) Successful in 1m14s
2025-03-03 10:21:15 -08:00
55c0ab1610 Add "tls" options to the MariaDB and MySQL database hooks.
All checks were successful
build / test (push) Successful in 10m58s
build / docs (push) Successful in 1m43s
2025-03-03 10:07:03 -08:00
1f86100f26 NEWS wording tweaks. 2025-03-02 20:10:20 -08:00
2a16ffab1b When ctrl-C is pressed, ensure Borg actually exits (#1015).
All checks were successful
build / test (push) Successful in 7m0s
build / docs (push) Successful in 1m38s
2025-03-02 10:32:57 -08:00
4b2f7e03af Fix broken "config generate" (#975).
All checks were successful
build / test (push) Successful in 6m52s
build / docs (push) Successful in 1m42s
2025-03-01 21:02:32 -08:00
024006f4c0 Title case Borg.
Some checks failed
build / test (push) Failing after 4m35s
build / docs (push) Has been skipped
2025-03-01 20:56:40 -08:00
4c71e600ca Expand a little on the specifics of backups of an LVM volume (#1014).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #1014
2025-03-02 04:55:13 +00:00
114f5702b2 Expand a little on the specifics of backups of an LVM volume. 2025-03-02 14:22:57 +11:00
54afe87a9f Add a "compression" option to the PostgreSQL database hook (#975).
Some checks failed
build / test (push) Failing after 4m32s
build / docs (push) Has been skipped
2025-03-01 17:29:16 -08:00
25b6a49df7 Send database passwords to MongoDB via anonymous pipe (#1013).
All checks were successful
build / test (push) Successful in 6m27s
build / docs (push) Successful in 1m26s
2025-03-01 10:04:04 -08:00
b97372adf2 Add MariaDB and MySQL anonymous pipe to NEWS (#1009).
All checks were successful
build / test (push) Successful in 6m42s
build / docs (push) Successful in 1m25s
2025-03-01 08:49:42 -08:00
6bc9a592d9 Send MariaDB and MySQL passwords via anonymous pipe instead of environment variable (#1009).
All checks were successful
build / test (push) Successful in 11m27s
build / docs (push) Successful in 1m49s
Reviewed-on: #1011
2025-03-01 03:33:08 +00:00
839862cff0 Update documentation link text about providing database passwords from external sources (#1009). 2025-02-28 19:31:22 -08:00
06b065cb09 Add missing test coverage (#1009). 2025-02-28 18:28:09 -08:00
1e5c256d54 Get tests passing again (#1009). 2025-02-28 14:40:00 -08:00
baf5fec78d If the user supplies their own --defaults-extra-file, include it from the one we generate (#1009). 2025-02-28 10:53:17 -08:00
48a4fbaa89 Add missing test coverage for defaults file function (#1009). 2025-02-28 09:21:01 -08:00
1e274d7153 Add some missing test mocking (#1009). 2025-02-28 08:59:38 -08:00
c41b743819 Get existing unit tests passing (#1009). 2025-02-28 08:37:03 -08:00
36d0073375 Send MySQL passwords via anonymous pipe instead of environment variable (#1009). 2025-02-27 10:42:47 -08:00
0bd418836e Send MariaDB passwords via anonymous pipe instead of environment variable (#1009) 2025-02-27 10:15:45 -08:00
923fa7d82f Include contributors of closed tickets in "recent contributors" documentation.
All checks were successful
build / test (push) Successful in 7m15s
build / docs (push) Successful in 1m32s
2025-02-27 09:23:08 -08:00
dce0528057 In the Zabbix monitoring hook, support Zabbix 7.2's authentication changes (#1003).
All checks were successful
build / test (push) Successful in 11m21s
build / docs (push) Successful in 1m35s
2025-02-26 22:33:01 -08:00
8a6c6c84d2 Add Uptime Kuma "verify_tls" option to NEWS.
All checks were successful
build / test (push) Successful in 6m32s
build / docs (push) Successful in 24s
2025-02-24 11:30:16 -08:00
1e21c8f97b
Add "verify_tls" option to Uptime Kuma hook.
Merge pull request #90 from columbarius/uptimekuma-verify-tls
2025-02-24 11:28:18 -08:00
columbarius
2eab74a521 Add "verify_tls" option to Uptime Kuma hook. 2025-02-24 20:12:47 +01:00
3bca686707 Fix a ZFS error during snapshot cleanup (#1001).
All checks were successful
build / test (push) Successful in 6m38s
build / docs (push) Successful in 1m13s
2025-02-23 17:01:35 -08:00
8854b9ad20 Backing out a ZFS change that hasn't been confirmed working quite yet.
Some checks failed
build / test (push) Failing after 1s
build / docs (push) Has been skipped
2025-02-23 15:49:12 -08:00
bcc463688a When getting all ZFS dataset mount points, deduplicate and filter out "none".
Some checks failed
build / test (push) Failing after 23s
build / docs (push) Has been skipped
2025-02-23 15:46:39 -08:00
596305e3de Bump version for release.
All checks were successful
build / test (push) Successful in 6m34s
build / docs (push) Successful in 1m11s
2025-02-23 09:59:53 -08:00
c462f0c84c Fix Python < 3.12 compatibility issue (#1005).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-02-23 09:59:19 -08:00
4f0142c3c5 Fix Python < 3.12 compatibility issue (#1005).
All checks were successful
build / test (push) Successful in 8m48s
build / docs (push) Successful in 1m29s
2025-02-23 09:09:47 -08:00
4f88018558 Bump version for release.
All checks were successful
build / test (push) Successful in 6m17s
build / docs (push) Successful in 1m21s
2025-02-22 14:39:45 -08:00
3642687ab5 Fix broken tests (#999).
All checks were successful
build / test (push) Successful in 6m20s
build / docs (push) Successful in 1m17s
2025-02-22 14:32:32 -08:00
5d9c111910 Fix a runtime directory error from a conflict between "extra_borg_options" and special file detection (#999).
Some checks failed
build / test (push) Failing after 2m0s
build / docs (push) Has been skipped
2025-02-22 14:26:21 -08:00
3cf19dd1b0 Send the "encryption_passphrase" option to Borg via an anonymous pipe (#998).
All checks were successful
build / test (push) Successful in 6m50s
build / docs (push) Successful in 1m30s
Reviewed-on: #998
2025-02-22 17:57:37 +00:00
ad3392ca15 Ignore the BORG_PASSCOMMAND environment variable when the "encryption_passphase" option is set. 2025-02-22 09:55:07 -08:00
087b7f5c7b Merge branch 'main' into passphrase-via-file-descriptor 2025-02-22 09:27:39 -08:00
34bb09e9be Document Zabbix server version compatibility (#1003).
All checks were successful
build / test (push) Successful in 6m33s
build / docs (push) Successful in 1m30s
2025-02-22 09:26:08 -08:00
a61eba8c79 Add PR number to NEWS item. 2025-02-21 22:30:31 -08:00
2280bb26b6 Fix a few tests to mock more accurately. 2025-02-21 22:08:08 -08:00
4ee2603fef Merge branch 'main' into passphrase-via-file-descriptor 2025-02-21 20:26:48 -08:00
cc2ede70ac Fix ZFS mount errors (#1001).
All checks were successful
build / test (push) Successful in 8m26s
build / docs (push) Successful in 1m29s
Reviewed-on: #1002
2025-02-22 04:13:35 +00:00
02d8ecd66e Document the root pattern requirement for snapshotting (#1001). 2025-02-21 18:08:34 -08:00
9ba78fa33b Don't try to unmount empty directories (#1001). 2025-02-21 17:59:45 -08:00
a3e34d63e9 Remove debugging prints (#1001). 2025-02-21 16:36:12 -08:00
bc25ac4eea Fix Btrfs end-to-end-test (#1001). 2025-02-21 16:32:07 -08:00
e69c686abf Get all unit/integration tests passing (#1001). 2025-02-21 11:32:57 -08:00
0210bf76bc Fix ZFS and Btrfs tests (#1001). 2025-02-20 22:58:05 -08:00
e69cce7e51 Document ZFS snapshotting exclusion of "canmount=off" datasets (#1001). 2025-02-20 14:04:23 -08:00
3655e8784a Add NEWS items for filesystem hook fixes/changes (#1001). 2025-02-20 13:25:09 -08:00
58aed0892c Initial work on fixing ZFS mount errors (#1001). 2025-02-19 22:49:14 -08:00
0e65169503 Improve clarity of comments and variable names of runtime directory exclude detection logic (#999).
All checks were successful
build / test (push) Successful in 9m1s
build / docs (push) Successful in 1m48s
2025-02-17 14:12:55 -08:00
07ecc0ffd6 Send the "encryption_passphrase" option to Borg via an anonymous pipe. 2025-02-17 11:03:36 -08:00
37ad398aff Add a ticket number to NEWS for (some of) the credential hook work.
All checks were successful
build / test (push) Successful in 8m51s
build / docs (push) Successful in 1m40s
2025-02-16 09:12:52 -08:00
056dfc6d33 Add Btrfs "/" subvolume fix to NEWS.
All checks were successful
build / test (push) Successful in 6m33s
build / docs (push) Successful in 1m34s
2025-02-15 09:56:46 -08:00
bf850b9d38
Fix path handling error when handling btrfs '/' subvolume.
Merge pull request #89 from dmitry-t7ko/btrfs-root-submodule-fix
2025-02-15 09:49:13 -08:00
7f22612bf1 Add credential loading from file, KeePassXC, and Docker/Podman secrets.
All checks were successful
build / test (push) Successful in 8m40s
build / docs (push) Successful in 1m31s
Reviewed-on: #994
2025-02-15 04:20:11 +00:00
e02a0e6322 Support working directory for container and file credential hooks. 2025-02-14 19:35:12 -08:00
2ca23b629c Add end-to-end tests for new credential hooks, along with some related configuration options. 2025-02-14 15:33:30 -08:00
b283e379d0 Actually pass the current configuration to credential hooks. 2025-02-14 10:15:52 -08:00
5dda9c8ee5 Add unit tests for new credential hooks. 2025-02-13 16:38:50 -08:00
Dmitrii Tishchenko
653d8c0946 Remove unneeded 'continue' 2025-02-13 21:44:45 +00:00
Dmitrii Tishchenko
92e87d839d Fix path handling error when handling btrfs '/' submodule 2025-02-13 17:12:23 +00:00
d6cf48544a Get existing tests passing. 2025-02-12 22:49:16 -08:00
8745b9939d Add documentation for new credential hooks. 2025-02-12 21:44:17 -08:00
5661b67cde Merge branch 'main' into keepassxc-docker-podman-file-credentials 2025-02-12 09:14:49 -08:00
aa4a9de3b2 Fix the "create" action to omit the repository label prefix from Borg's output when databases are enabled (#996).
All checks were successful
build / test (push) Successful in 8m19s
build / docs (push) Successful in 1m38s
2025-02-12 09:12:59 -08:00
f9ea45493d Add missing dev0 tag to version. 2025-02-11 23:00:26 -08:00
a0ba5b673b Add credential loading from file, KeePassXC, and Docker/Podman secrets. 2025-02-11 22:54:07 -08:00
50096296da Revamp systemd credential syntax to be more consistent with constants (#966).
All checks were successful
build / test (push) Successful in 8m19s
build / docs (push) Successful in 1m39s
2025-02-10 22:01:23 -08:00
3bc14ba364 Bump version for release. 2025-02-10 14:21:33 -08:00
c9c6913547 Add a "!credential" tag for loading systemd credentials into borgmatic configuration (#966).
All checks were successful
build / test (push) Successful in 6m1s
build / docs (push) Successful in 1m28s
Reviewed-on: #993
2025-02-10 22:18:43 +00:00
779f51f40a Fix favicon on non-home pages.
All checks were successful
build / test (push) Successful in 7m41s
build / docs (push) Successful in 1m34s
2025-02-10 13:24:27 -08:00
24b846e9ca Additional test coverage (#966). 2025-02-10 10:05:51 -08:00
73fe29b055 Add additional test coverage for credential tag (#966). 2025-02-10 09:52:07 -08:00
775385e688 Get unit tests passing again (#966). 2025-02-09 22:44:38 -08:00
efdbee934a Update documentation to describe delayed !credential tag approach (#966). 2025-02-09 15:27:58 -08:00
49719dc309 Load credentials from database hooks (#966). 2025-02-09 11:35:26 -08:00
b7e3ee8277 Revamped the credentials to load them much closer to where they're used (#966). 2025-02-09 11:12:40 -08:00
97fe1a2c50 Flake fixes (#966). 2025-02-08 19:28:03 -08:00
66abf38b39 Add end-to-end tests for the systemd credential hook (#966). 2025-02-08 17:50:59 -08:00
5baf091853 Add automated tests for the systemd credential hook (#966). 2025-02-08 10:42:11 -08:00
c5abcc1fdf Add documentation for the "!credential" tag (#966). 2025-02-07 16:04:10 -08:00
9a9a8fd1c6 Add a "!credential" tag for loading systemd credentials into borgmatic configuration (#966). 2025-02-07 14:09:26 -08:00
ab9e8d06ee Add a delayed logging handler that delays anything logged before logging is actually configured.
All checks were successful
build / test (push) Successful in 8m26s
build / docs (push) Successful in 1m47s
2025-02-07 09:50:05 -08:00
21cef267c1 Merge branch 'main' into logging-verbosity-config 2025-02-07 09:33:12 -08:00
5a2cd1b261 Add support for Python 3.13.
All checks were successful
build / test (push) Successful in 5m14s
build / docs (push) Successful in 1m24s
2025-02-06 14:21:36 -08:00
ffaa99ba15 With the "max_duration" option or the "--max-duration" flag, run the archives and repository checks separately so they don't interfere with one another (#988).
All checks were successful
build / test (push) Successful in 7m14s
build / docs (push) Successful in 1m18s
2025-02-06 11:52:16 -08:00
5dc0b08f22 Fix the log message code to avoid using Python 3.10+ logging features (#989).
All checks were successful
build / test (push) Successful in 5m55s
build / docs (push) Successful in 2m26s
2025-02-04 11:51:39 -08:00
23009e22aa When both "encryption_passcommand" and "encryption_passphrase" are configured, prefer "encryption_passphrase" even if it's an empty value (#987).
All checks were successful
build / test (push) Successful in 6m27s
build / docs (push) Successful in 1m43s
2025-02-03 23:20:31 -08:00
6cfa10fb7e Fix a "list" action error when the "encryption_passcommand" option is set (#987).
Some checks failed
build / test (push) Successful in 8m21s
build / docs (push) Has been cancelled
2025-02-03 23:11:59 -08:00
d29d0bc1c6 NEWS wording tweaks for clarity.
All checks were successful
build / test (push) Successful in 6m37s
build / docs (push) Successful in 1m30s
2025-02-03 11:22:54 -08:00
c3f4f94190 Bump version for release. 2025-02-03 11:20:13 -08:00
b2d61ade4e Change the default value for the "--original-hostname" flag from "localhost" to no host specified (#985).
Some checks failed
build / test (push) Successful in 7m49s
build / docs (push) Has been cancelled
2025-02-03 11:17:21 -08:00
cfad4200a9 Initial work on putting logging and verbosity options into configuration. 2025-02-02 11:04:37 -08:00
cca9039863 Move the passcommand logic out of a hook to prevent future security issues (e.g., passphrase exfiltration attacks) if a user invokes a credential hook from an arbitrary configuration value (#961).
All checks were successful
build / test (push) Successful in 8m55s
build / docs (push) Successful in 2m8s
2025-01-31 22:15:53 -08:00
afcf253318 Fix flake errors (#961).
All checks were successful
build / test (push) Successful in 5m56s
build / docs (push) Successful in 1m58s
2025-01-31 10:27:20 -08:00
76533c7db5 Add a clarifying comment to the NEWS entry (#961).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-01-31 10:26:05 -08:00
0073366dfc Add a passcommand hook so borgmatic can collect the encryption passphrase once and pass it to Borg multiple times (#961).
Some checks failed
build / test (push) Failing after 4m12s
build / docs (push) Has been skipped
Reviewed-on: #984
2025-01-31 18:13:38 +00:00
13acaa47e4 Add an end-to-end test for the passcommand hook (#961). 2025-01-30 22:50:13 -08:00
cf326a98a5 Add test coverage for new code (#961). 2025-01-30 21:29:52 -08:00
355eef186e Get existing tests passing again (#961). 2025-01-30 20:18:03 -08:00
c392e4914c Add documentation (#961). 2025-01-30 10:20:24 -08:00
8fed8e0695 Add a passcommand hook to NEWS (#961). 2025-01-30 09:55:32 -08:00
52189490a2 Docstring typo (#961). 2025-01-30 09:48:55 -08:00
26b44699ba Add a passphrase hook so borgmatic can collect the encryption passphrase once and pass it to Borg multiple times (#961). 2025-01-30 09:35:20 -08:00
09933c3dc7 Log the repository path or label on every relevant log message, not just some logs (#635).
All checks were successful
build / test (push) Successful in 5m18s
build / docs (push) Successful in 1m11s
Reviewed-on: #980
2025-01-29 18:39:49 +00:00
c702dca8da Merge branch 'main' into log-repository-everywhere 2025-01-29 10:31:30 -08:00
62003c58ea Fix the Btrfs hook to support subvolumes with names like "@home", different from their mount points (#983).
All checks were successful
build / test (push) Successful in 6m44s
build / docs (push) Successful in 1m55s
2025-01-29 09:46:39 -08:00
67c22e464a Code formatting (#635). 2025-01-29 08:00:42 -08:00
5a9066940f Add monitoring end-to-end tests (#635). 2025-01-28 23:06:22 -08:00
61f0987051 Merge branch 'main' into log-repository-everywhere 2025-01-27 22:03:35 -08:00
63c39be55f Fix flaking issues (#635). 2025-01-27 12:28:36 -08:00
7e344e6e0a Complete test coverage for new code (#635). 2025-01-27 12:25:28 -08:00
b02ff8b6e5 Fix "spot" check file count delta error (#981).
All checks were successful
build / test (push) Successful in 4m38s
build / docs (push) Successful in 1m14s
2025-01-27 10:51:06 -08:00
b6ff242d3a Fix for borgmatic "exclude_patterns" and "exclude_from" recursing into excluded subdirectories (#982).
All checks were successful
build / test (push) Successful in 6m37s
build / docs (push) Successful in 2m2s
2025-01-27 10:07:19 -08:00
71f1819f05 Some additional test coverage (#635). 2025-01-27 09:27:12 -08:00
31b6e21139 Fix end-to-end tests and update more log messages (#635). 2025-01-26 19:03:40 -08:00
7d56641f56 Get existing unit tests passing (#635). 2025-01-26 12:13:29 -08:00
1ad6be2077 Add missing test coverage and fix incorrect test expectations (#855).
All checks were successful
build / test (push) Successful in 6m18s
build / docs (push) Successful in 1m58s
2025-01-26 09:29:54 -08:00
803361b850 Some text fixes (#635). 2025-01-26 09:12:18 -08:00
e0059de711 Add log prefix context manager to make prefix cleanup/restoration easier (#635). 2025-01-25 21:56:41 -08:00
b9ec9bb873 Don't prefix command output (like Borg output) with the global log prefix (#635). 2025-01-25 14:49:39 -08:00
8c5db19490 Code formatting (#635). 2025-01-25 14:14:48 -08:00
cc7e01be68 Log the repository path or label on every relevant log message, not just some logs (#635). 2025-01-25 14:01:25 -08:00
1232ba8045 Revert "Log the repository path or label on every relevant log message, not just some logs (#635)."
All checks were successful
build / test (push) Successful in 4m4s
build / docs (push) Successful in 7s
This reverts commit 90c1161a8c3c52474f76ee0a96808ea5f0b21719.
2025-01-25 13:57:56 -08:00
90c1161a8c Log the repository path or label on every relevant log message, not just some logs (#635).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-01-25 13:55:58 -08:00
02451a8b30 Further database container dump documentation clarifications (#978).
All checks were successful
build / test (push) Successful in 3m55s
build / docs (push) Successful in 59s
2025-01-25 09:17:13 -08:00
730350b31a Fix incorrect option name within schema description.
All checks were successful
build / test (push) Successful in 3m56s
build / docs (push) Successful in 1m6s
2025-01-25 08:04:13 -08:00
203e1f4e99 Bump version for release. 2025-01-25 08:01:34 -08:00
4c35a564ef Fix root patterns so they don't have an invalid "sh:" prefix before getting passed to Borg (#979).
All checks were successful
build / test (push) Successful in 5m44s
build / docs (push) Successful in 1m38s
2025-01-25 07:59:53 -08:00
7551810ea6 Clarify/correct documentation about dumping databases when using containers (#978).
All checks were successful
build / test (push) Successful in 6m26s
build / docs (push) Successful in 1m39s
2025-01-24 14:31:38 -08:00
ce523eeed6 Add a blurb about recent contributors.
All checks were successful
build / test (push) Successful in 11m15s
build / docs (push) Successful in 1m15s
2025-01-23 15:11:54 -08:00
3c0def6d6d Expand the recent contributors documentation section to ticket submitters.
All checks were successful
build / test (push) Successful in 4m12s
build / docs (push) Successful in 1m1s
2025-01-23 14:41:26 -08:00
f08014e3be Code formatting.
All checks were successful
build / test (push) Successful in 4m23s
build / docs (push) Successful in 1m36s
2025-01-23 12:11:27 -08:00
86ad93676d Bump version for release. 2025-01-23 12:09:20 -08:00
e1825d2bcb Add #977 to NEWS. 2025-01-23 12:08:34 -08:00
92b8c0230e Fix exclude patterns parsing to support pattern styles (#977).
Some checks failed
build / test (push) Failing after 3m37s
build / docs (push) Has been skipped
Reviewed-on: #976
2025-01-23 20:06:11 +00:00
Pavel Andreev
73c196aa70 Fix according to review comments 2025-01-23 19:49:10 +00:00
Pavel Andreev
5d390d7953 Fix patterns parsing 2025-01-23 15:58:43 +00:00
ffb342780b Link to Sentry's DSN documentation (#855).
All checks were successful
build / test (push) Successful in 4m24s
build / docs (push) Successful in 1m42s
2025-01-21 17:28:32 -08:00
9871267f97 Add a Sentry monitoring hook (#855).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-01-21 17:23:56 -08:00
914c2b17e9 Add a Sentry monitoring hook (#855). 2025-01-21 17:23:18 -08:00
804455ac9f Fix for "exclude_from" files being completely ignored (#971).
All checks were successful
build / test (push) Successful in 5m44s
build / docs (push) Successful in 1m34s
2025-01-19 10:27:13 -08:00
4fe0fd1576 Fix version number in NEWS.
All checks were successful
build / test (push) Successful in 4m3s
build / docs (push) Successful in 1m34s
2025-01-18 09:55:03 -08:00
e3d40125cb Fix for a "spot" check error when a filename in the most recent archive contains a newline (#968).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-01-18 09:54:30 -08:00
e66df22a6e Fix for an error when a blank line occurs in the configured patterns or excludes (#970).
Some checks failed
build / test (push) Failing after 3m15s
build / docs (push) Has been skipped
2025-01-18 09:25:29 -08:00
e789de0851 Bump version for release.
All checks were successful
build / test (push) Successful in 3m52s
build / docs (push) Successful in 54s
2025-01-17 13:50:22 -08:00
f1cac95b9c Fix the "restore" action to work on database dumps without a port when a default port is configured (#969). 2025-01-17 13:46:18 -08:00
f183800009 For the LVM hook, add support for nested logical volumes (#962).
All checks were successful
build / test (push) Successful in 5m46s
build / docs (push) Successful in 57s
2025-01-17 09:38:49 -08:00
b7362bfbac Apply snapshot path rewriting to excludes and patterns, not just source directories (#962).
All checks were successful
build / test (push) Successful in 5m48s
build / docs (push) Successful in 1m35s
Reviewed-on: #964
2025-01-17 03:23:41 +00:00
2467518d4e Add even more missing test coverage (#962). 2025-01-16 15:11:59 -08:00
3bda843139 Fix the "spot" check to have a nicer error when there are no source paths to compare. 2025-01-15 19:48:08 -08:00
44efca2be9 Update patterns schema comment (#962). 2025-01-15 12:37:44 -08:00
cfeeb87bbe Fix pattern expansion/normalization bug with working directory (#962). 2025-01-15 11:26:26 -08:00
bb2e986c9d Fix end-to-end tests (#962). 2025-01-15 10:52:09 -08:00
67ac70354b Merge branch 'main' into snapshot-excludes-and-patterns 2025-01-15 10:37:36 -08:00
8c1d5dbfe1 Revert end-to-end script change.
All checks were successful
build / test (push) Successful in 4m4s
build / docs (push) Successful in 1m36s
2025-01-15 10:37:04 -08:00
a3aeb36159 Merge branch 'main' into snapshot-excludes-and-patterns 2025-01-15 10:35:45 -08:00
c702a988bd Add a basic end-to-end test for patterns (#962).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2025-01-15 10:33:38 -08:00
bbf1c3d55e Add test coverage for new code. 2025-01-14 23:01:39 -08:00
0b17fb2d3f Get all existing tests passing (#962). 2025-01-14 13:48:20 -08:00
ca54da1067 Getting additional tests passing (#962). 2025-01-13 20:51:27 -08:00
661041da04 Fix check tests (#962). 2025-01-13 10:22:32 -08:00
ad14ff3ee5 Fix tests for remaining hooks (#962). 2025-01-13 10:07:25 -08:00
b72b9aaf13 Fix several tests (#962). 2025-01-12 22:42:58 -08:00
a70fd30cb1 Merge branch 'main' into snapshot-excludes-and-patterns 2025-01-12 11:38:50 -08:00
5560f30aa6 Fix a borgmatic runtime directory error when running the "spot" check with a database hook enabled (#965).
All checks were successful
build / test (push) Successful in 5m56s
build / docs (push) Successful in 1m55s
2025-01-12 09:36:24 -08:00
256ed4170b Minor comment clarifications (#962). 2025-01-10 22:20:49 -08:00
071d8d945a Strip comments from patterns (#962). 2025-01-10 12:33:25 -08:00
926c26315a Add documentation for patterns and snapshot hooks (#962). 2025-01-10 12:22:37 -08:00
120a29ab4d Initial work on applying snapshot path rewriting to excludes and patterns (#962). 2025-01-10 10:38:27 -08:00
8573660ff0 Clarify error message to mention patterns, not just excludes (#947).
All checks were successful
build / test (push) Successful in 5m59s
build / docs (push) Successful in 1m54s
2025-01-10 08:41:56 -08:00
0b9f3ae8a1 Fix comment typo. 2025-01-04 20:18:18 -08:00
2c70ad81ec Fix the "spot" check to support relative source directory paths (#960). Fix the "spot" check to no longer consider pipe files within an archive for file comparisons. Fix auto-excluding of special files (when databases are configured) to support relative source directory paths.
All checks were successful
build / test (push) Successful in 6m4s
build / docs (push) Successful in 1m58s
2025-01-01 15:00:36 -08:00
d6c3ec05aa Reduce duplication (#960).
All checks were successful
build / test (push) Successful in 4m5s
build / docs (push) Successful in 1m6s
2024-12-29 22:00:25 -08:00
a4954cc7a3 Fix for archives storing relative source directory paths such that they contain the working directory (#960).
All checks were successful
build / test (push) Successful in 5m53s
build / docs (push) Successful in 2m1s
2024-12-29 20:09:13 -08:00
a6b6dd32c1 Upgrade dependencies and containers for end-to-end tests.
All checks were successful
build / test (push) Successful in 5m48s
build / docs (push) Successful in 1m57s
2024-12-29 09:33:25 -08:00
d3409df84c Fix an error in the Btrfs hook when a "/" subvolume is configured in borgmatic's source directories (#959).
All checks were successful
build / test (push) Successful in 6m59s
build / docs (push) Successful in 2m7s
2024-12-28 09:57:33 -08:00
87e77ff2b7 Bump version for release.
All checks were successful
build / test (push) Successful in 7m31s
build / docs (push) Successful in 2m1s
2024-12-27 08:54:53 -08:00
3517d9d4f3 Indentation tweak. 2024-12-26 19:11:45 -08:00
d3c7279dad Backup and restore databases that have the same name but with different ports, hostnames, or hooks (#418).
All checks were successful
build / test (push) Successful in 5m30s
build / docs (push) Successful in 1m12s
Reviewed-on: #952
2024-12-26 23:17:58 +00:00
a99c48c115 Documentation / CLI help clarifications around "--original-port" (#418). 2024-12-26 15:16:29 -08:00
94cedd4cf8 Merge branch 'main' into same-named-databases 2024-12-25 23:04:45 -08:00
a4baf4623b Drop colorama as a library dependency (#958).
All checks were successful
build / test (push) Successful in 7m15s
build / docs (push) Successful in 1m58s
2024-12-25 23:02:38 -08:00
77df425bd1 Minor edits and clarifying comments (#418). 2024-12-25 21:59:10 -08:00
69476a4fab Documentation clarifications (#418). 2024-12-24 23:25:26 -08:00
be6b865a81 Add even more missing test coverage (#418). 2024-12-24 23:09:44 -08:00
b58a52e03f Merge branch 'main' into same-named-databases 2024-12-24 15:25:57 -08:00
9b85c5bc61 Add missing restore test coverage (#418). 2024-12-24 15:24:09 -08:00
b8041f5c39 Fix end-to-end tests broken by new database config checks during restore (#418). 2024-12-24 09:13:42 -08:00
d9d6d3f7f2 Simplify logic to get configured data sources during restoration (#418). 2024-12-23 22:12:47 -08:00
0844cd0d4f Fix the printing of a color reset code at exit even when color is disabled (#956).
All checks were successful
build / test (push) Successful in 8m17s
build / docs (push) Successful in 2m42s
2024-12-23 19:53:57 -08:00
d4705602fa Handle more edge cases by erroring (#418). 2024-12-22 22:02:53 -08:00
5174a78109 Get existing tests passing (#418). 2024-12-21 13:35:00 -08:00
3db79b4352 Simplified dump metadata comparison logic and got a few tests passing (#418). 2024-12-20 22:40:20 -08:00
d6732d9abb Merge branch 'main' into same-named-databases 2024-12-19 21:07:44 -08:00
267af5b372 To avoid a hang in the database hooks, error and exit when the borgmatic runtime directory overlaps with the configured excludes (#947).
All checks were successful
build / test (push) Successful in 7m11s
build / docs (push) Successful in 2m6s
2024-12-19 20:59:57 -08:00
d53ea09adb In tests, account for some function renames (#418). 2024-12-17 16:28:59 -08:00
8696cbfa22 Clarify some comments (#418). 2024-12-17 12:02:31 -08:00
48dca28c74 When the ZFS, Btrfs, or LVM hooks aren't configured, don't try to cleanup snapshots for them.
All checks were successful
build / test (push) Successful in 6m47s
build / docs (push) Successful in 1m49s
2024-12-17 11:00:19 -08:00
36bcbd0592 Documentation about restoring datebases with the same name (#418). 2024-12-17 08:51:04 -08:00
ebb3bca4b3 Fix findmnt command error in the Btrfs hook by switching to parsing JSON output (#954).
All checks were successful
build / test (push) Successful in 9m15s
build / docs (push) Successful in 2m17s
2024-12-12 11:58:18 -08:00
b1e343f15c Initial work on supporting same-named database with different ports, hosts, or hooks (#418). 2024-12-09 08:48:34 -08:00
cb7f98192c Updates to out-of-date documentation on database dumps.
All checks were successful
build / test (push) Successful in 4m37s
build / docs (push) Successful in 1m1s
2024-12-07 12:25:39 -08:00
3ceb4f554f Fix out-of-date schema comments about databases and one_file_system.
All checks were successful
build / test (push) Successful in 4m34s
build / docs (push) Successful in 1m9s
2024-12-07 11:42:41 -08:00
4b18c0bc81 Make LVM snapshots read-only.
All checks were successful
build / test (push) Successful in 4m33s
build / docs (push) Successful in 55s
2024-12-07 09:41:50 -08:00
2ce09dbf82 Snapshot documentation clarifications.
All checks were successful
build / test (push) Successful in 4m35s
build / docs (push) Successful in 57s
2024-12-07 09:10:52 -08:00
8a4f3b8f1a Add word missing from docs (#80).
All checks were successful
build / test (push) Successful in 4m34s
build / docs (push) Successful in 1m5s
2024-12-06 20:39:50 -08:00
81cd03cbbf Bump version for release. 2024-12-06 20:29:16 -08:00
f2455527fc Fix spelling in comment (#80).
All checks were successful
build / test (push) Successful in 4m37s
build / docs (push) Successful in 1m41s
2024-12-06 20:22:45 -08:00
62d67cde0a LVM snapshots + ZFS and Btrfs improvements (#80).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #949
2024-12-07 04:21:22 +00:00
ae8a9db27d Fix flake issues (#80). 2024-12-06 16:12:01 -08:00
8979f8918d Organize imports (#80). 2024-12-06 16:05:46 -08:00
eb97708092 Completed tests for LVM (#80). 2024-12-06 16:02:33 -08:00
f2d93b85b4 Lots of LVM unit tests + code formatting (#80). 2024-12-06 13:59:38 -08:00
b999d2dc4d Add some missing test coverage (#80). 2024-12-06 10:27:47 -08:00
7f2e38d061 Fix file permissions (#80). 2024-12-06 09:40:32 -08:00
140fc248b6 Fix LVM end-to-end tests (#80). 2024-12-06 09:39:24 -08:00
ec9e1a8223 LVM hook end-to-end tests, not quite working yet (#80). 2024-12-05 22:46:50 -08:00
03bbe77dd9 Add an end-to-end test for the Btrfs hook using a fake Btrfs binary (#80). 2024-12-05 17:35:44 -08:00
f1c5f11422 Add an end-to-end test for the ZFS hook using a fake ZFS binary (#80). 2024-12-05 11:18:53 -08:00
f8df06fb92 Remove divison by zero (#80). 2024-12-04 20:33:59 -08:00
d95707ff9b Get existing tests passing (#80). 2024-12-04 20:22:59 -08:00
51a7f50e3a Add ZFS snapshot unmount error fix to NEWS (#950). 2024-12-04 15:43:05 -08:00
49b8b693af Don't try to unmount a ZFS snapshot if it's already deleted (#80). 2024-12-04 15:39:04 -08:00
d0e92493f6 Fix broken ZFS tests (#80). 2024-12-04 14:48:13 -08:00
9afdaca985 Before unmounting, remove the snapshot mount path instead of the parent snapshot directory (#80). 2024-12-03 19:19:22 -08:00
cc11ed78e0 Put LVM snapshots into a data structure for convenience (#80). 2024-12-03 19:12:41 -08:00
87f3746881 Fix a ZFS edge case in which the hook tries to unmounted a non-mounted directory (#80). 2024-12-03 15:56:03 -08:00
347a4c3dd5 Fix breakage of ZFS user property auto-backup (#80). 2024-12-03 15:43:50 -08:00
399bb6ef68 Add recent LVM and ZFS work to NEWS (#80). 2024-12-03 12:22:43 -08:00
9b9ecad299 Port the parent directory discovery logic from LVM to Btrfs (#80). 2024-12-03 12:15:34 -08:00
8c4b899a13 Use a namedtuple for logical volume metadata (#80). 2024-12-03 11:12:27 -08:00
9b77de3d66 Port the parent directory discovery logic from LVM to ZFS (#80). 2024-12-03 11:05:45 -08:00
bfeea5d394 Code formatting (#80). 2024-12-03 08:52:05 -08:00
8a6225b7c2 Factor out logic for finding contained source directories in a parent directory (#80). 2024-12-03 08:51:10 -08:00
9aaa3c925f Code formatting (#80). 2024-12-02 21:01:34 -08:00
88fd1ae454 Discover parent/grandparent/etc. logical volumes of source directories (#80). 2024-12-02 20:58:50 -08:00
27305ec2bf Clarify the path rewriting for LVM (but also ZFS + Btrfs) (#80). 2024-12-02 12:01:04 -08:00
4453c2d49c Add LVM logo to integrations docs. 2024-12-02 11:28:57 -08:00
6367a00013 Add snapshot_size option (#80). 2024-12-02 11:09:07 -08:00
cd654cbb57 Fix a few docstring typos (#80). 2024-12-01 21:00:11 -08:00
1e8f73779f Fix typo in schema comment (#80). 2024-12-01 20:25:16 -08:00
27d167b071 LVM snapshots WIP (#80). 2024-12-01 20:13:02 -08:00
cfff6c6855 Btrfs snapshotting (#251).
All checks were successful
build / test (push) Successful in 5m46s
build / docs (push) Successful in 1m38s
Reviewed-on: #946
2024-11-30 19:19:09 +00:00
37efaeae88 Warn if Btrfs is configured but there are no Btrfs subvolumes detected (#251). 2024-11-30 10:55:30 -08:00
0978c669ad A little more Btrfs error handling (#251). 2024-11-30 10:25:01 -08:00
1366269586 Add a couple of missing tests (#251). 2024-11-30 09:44:55 -08:00
a9a0910817 Add Btrfs logo to integrations docs (#251). 2024-11-30 09:36:52 -08:00
5bcc7b60c8 Tests for Btrfs (#251). 2024-11-30 09:32:50 -08:00
84a0552277 Improve Btrfs hook factoring/organization (#251). 2024-11-29 09:36:46 -08:00
d4a02f73b5 Create Btrfs snapshots as read-only (#251). 2024-11-28 22:18:44 -08:00
3f901c0a52 Btrfs hook documentation (#251). 2024-11-28 20:32:12 -08:00
b5b5c1fafa Initial work on a Btrfs hook (#251). 2024-11-28 18:47:15 -08:00
86e5085acc Fix incorrect documentation links to source.
All checks were successful
build / test (push) Successful in 4m5s
build / docs (push) Successful in 1m38s
2024-11-27 08:54:19 -08:00
08a5e8717b Merge branch 'main' of ssh://projects.torsion.org:3022/borgmatic-collective/borgmatic
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-11-27 08:51:00 -08:00
6b2f2b2ac4 Reorganize data source and monitoring hooks to make developing new hooks easier. 2024-11-27 08:50:34 -08:00
a07cf9e699 Revert temporary reversion of 1.9.4.dev0.
All checks were successful
build / test (push) Successful in 4m9s
build / docs (push) Successful in 6s
revert Temporary revert of 1.9.4.dev0 changeset so we can re-build 1.9.3 (which never actually got built).

revert Fix library error when running within a PyInstaller bundle (#926).
2024-11-26 16:20:06 +00:00
bf40b01077 Temporary revert of 1.9.4.dev0 changeset so we can re-build 1.9.3 (which never actually got built).
All checks were successful
build / test (push) Successful in 4m8s
build / docs (push) Successful in 55s
revert Fix library error when running within a PyInstaller bundle (#926).
2024-11-26 16:13:39 +00:00
a5c6a2fe1c Fix library error when running within a PyInstaller bundle (#926).
All checks were successful
build / test (push) Successful in 5m47s
build / docs (push) Successful in 1m39s
2024-11-25 20:14:18 -08:00
82141fe981 Bump version for release. 2024-11-25 07:49:11 -08:00
228a83978d Check docs clarifications.
All checks were successful
build / test (push) Successful in 4m19s
build / docs (push) Successful in 1m38s
2024-11-24 19:40:00 -08:00
638db3770b Clarify how frequent default checks run.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-11-24 19:38:20 -08:00
98df5c3af2 Fix docs about the relative speeds of different checks (#945).
All checks were successful
build / test (push) Successful in 4m9s
build / docs (push) Successful in 1m2s
Reviewed-on: #945
2024-11-25 03:23:39 +00:00
b0e906c0e7 NEWS clarifications.
All checks were successful
build / test (push) Successful in 4m9s
build / docs (push) Successful in 59s
2024-11-24 19:05:11 -08:00
e8dccbf1c1 Promote the "spot" check from a beta feature to stable.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-11-24 19:03:05 -08:00
4a997bc234 Add rclone to the integrations.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-11-24 18:59:21 -08:00
3197178b3d Fix flake errors.
All checks were successful
build / test (push) Successful in 4m10s
build / docs (push) Successful in 1m9s
2024-11-24 16:32:48 -08:00
5e618154d0 Clarify error message.
Some checks failed
build / test (push) Failing after 1m50s
build / docs (push) Has been skipped
2024-11-24 16:18:29 -08:00
84f611ae4f Require the runtime directory to be an absolute path.
Some checks failed
build / test (push) Failing after 1m51s
build / docs (push) Has been skipped
2024-11-24 16:15:19 -08:00
5dc8450c8e Adding missing bootstrap files. 2024-11-24 16:15:12 -08:00
689643e5fa Move bootstrap manifest file creation into a hook so it can actually clean up after itself.
Some checks failed
build / test (push) Failing after 1m9s
build / docs (push) Has been skipped
2024-11-24 16:00:33 -08:00
0a3d87eaea
docs: repository check means full CRC check -> slow
Ref: https://borgbackup.readthedocs.io/en/stable/usage/check.html#description
2024-11-24 18:04:58 +01:00
b45b62cd38 Don't recursively snapshot ZFS datasets, since we're not mounting them recursively (#261).
All checks were successful
build / test (push) Successful in 4m9s
build / docs (push) Successful in 56s
2024-11-23 22:37:46 -08:00
8de7094691 ZFS snapshots (#261).
All checks were successful
build / test (push) Successful in 6m1s
build / docs (push) Successful in 1m40s
Reviewed-on: #944
2024-11-24 04:42:19 +00:00
8c7e68305e A few clarifications to the ZFS docs (#261). 2024-11-23 20:41:43 -08:00
65a323433c Add comment (#261). 2024-11-23 20:12:40 -08:00
b5a3589471 A little more error handling (#261). 2024-11-23 18:09:59 -08:00
f4a736bdfe Deduplicate directories again after hooks have their way with them (#261). 2024-11-23 14:33:41 -08:00
eab0ec15ef Expand ZFS NEWS entry (#261). 2024-11-23 11:46:39 -08:00
c65aa24001 Add test coverage for ZFS hook (#261). 2024-11-23 10:50:58 -08:00
5a24bf2037 Get tests passing (#261). 2024-11-22 20:16:18 -08:00
324dbc3a79 Swallow temporary directory removal errors (#261). 2024-11-22 10:56:07 -08:00
9fe7db320a Consider ZFS hook as a beta feature (#261). 2024-11-22 09:53:46 -08:00
4d19596616 Add ZFS documentation (#261). 2024-11-22 08:33:24 -08:00
5cec2bf3d9 Don't unmount directories that don't exist. 2024-11-21 22:16:05 -08:00
06e0f98fd8 More refactoring for better organization of ZFS hook (#261). 2024-11-21 22:09:18 -08:00
87f36caf8d Factoring out some utility functions (#261). 2024-11-21 20:17:57 -08:00
ab7acceff6 Unmount and remove mounted snapshot directories, not just for the current process but for previous borgmatic runs as well (#261). 2024-11-21 19:09:30 -08:00
1b2b0c3020 Update out-of-date ZFS hook comments (#261). 2024-11-21 16:49:25 -08:00
289d178581 Also support discovery of ZFS datasets tagged with a borgmatic-specific user property (#261). 2024-11-21 16:45:44 -08:00
1e7f6d9f41 ZFS hook support for borgmatic's --dry-run (#261). 2024-11-21 11:55:45 -08:00
d0c90389fb Remove ZFS "enabled" option and fix override command options. 2024-11-21 10:52:00 -08:00
f9e920dce9 Prevent ZFS snapshots from ending up in the Borg archive twice (#261). 2024-11-21 10:23:27 -08:00
0ed52bbc4a Proceed gracefully in ZFS data source removal if ZFS isn't installed (#261). 2024-11-21 08:59:59 -08:00
da8278b566 Use os.path.normpath() instead of custom list comprehension (#261). 2024-11-21 08:36:15 -08:00
2af3522902 Fix broken check action (#261). 2024-11-21 08:32:02 -08:00
5e4784991a Comment tweaks and additional TODOs (#261). 2024-11-20 22:33:23 -08:00
ab43ef00ce ZFS snapshots WIP (#261). 2024-11-20 22:21:27 -08:00
47a8a95b29 Test path fix for finding schema file.
All checks were successful
build / test (push) Successful in 4m7s
build / docs (push) Successful in 58s
2024-11-20 08:18:06 -08:00
7c90c04ce0 Add a "--deleted" flag to the "repo-list" action (Borg 2 only).
All checks were successful
build / test (push) Successful in 5m49s
build / docs (push) Successful in 1m39s
2024-11-19 22:33:15 -08:00
97305cc3ce Fix broken tests when NO_COLOR=1 is set (#943).
All checks were successful
build / test (push) Successful in 4m7s
build / docs (push) Successful in 56s
2024-11-19 08:48:21 -08:00
4985b805b4 Bump version for release. 2024-11-18 20:40:51 -08:00
d09b4c72a9 Fix a few remaining Pushover issues from the PR.
All checks were successful
build / test (push) Successful in 5m45s
build / docs (push) Successful in 1m39s
2024-11-18 20:32:17 -08:00
9807549f88
Add a Pushover monitoring hook.
Merge pull request #86 from tony1661/pushover-branch.
2024-11-18 20:17:28 -08:00
30c821120e Fix borgmatic ignoring the "BORG_RELOCATED_REPO_ACCESS_IS_OK" and "BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK" environment variables (#939).
All checks were successful
build / test (push) Successful in 4m5s
build / docs (push) Successful in 55s
2024-11-18 09:46:52 -08:00
13884bd448 Apply the "umask" option to all relevant actions, not just some of them (#441).
All checks were successful
build / test (push) Successful in 4m5s
build / docs (push) Successful in 56s
2024-11-18 09:07:29 -08:00
6bce4c4a0d changed version release to 1.9.2 2024-11-18 07:56:00 -05:00
25572c98d7 better fuction name 2024-11-18 07:52:19 -05:00
dab0dfcb32 added test for value error 2024-11-18 07:49:53 -05:00
851c454ef0 Remove the restriction that the "extract" and "mount" actions must match a single repository (#722).
All checks were successful
build / test (push) Successful in 5m47s
build / docs (push) Successful in 1m40s
2024-11-17 21:39:59 -08:00
c7a0cebaf7 Add a documentation link to NEWS (#934).
All checks were successful
build / test (push) Successful in 4m5s
build / docs (push) Successful in 56s
2024-11-17 12:46:58 -08:00
76cfeda290 Update the logic that probes for the borgmatic runtime directory to support more platforms and use cases (#934).
All checks were successful
build / test (push) Successful in 5m45s
build / docs (push) Successful in 1m40s
Reviewed-on: #937
2024-11-17 19:57:09 +00:00
afdf831c59 Fix broken restore/bootstrap when using Borg 1.2 and a randomly named temporary directory (#934). 2024-11-17 11:55:10 -08:00
9ac3087304 Before creating a temp file in a directory, make sure the directory exists (#934). 2024-11-17 10:30:17 -08:00
7cca83b698 Log the path of the borgmatic runtime directory used (#934). 2024-11-17 10:15:58 -08:00
4b5df7117a Fix documentation type (#934). 2024-11-17 09:01:58 -08:00
57decfa4db Document the fact that the config bootstrap feature writes to the runtime directory (#934). 2024-11-16 16:45:49 -08:00
b80f60a731 Create the borgmatic runtime directory if it doesn't exist (#934). 2024-11-16 16:03:18 -08:00
8f5ea95348 Fix use of borgmatic runtime directory in the restore action (#934). 2024-11-16 12:19:20 -08:00
b0cad58d6c Add a dash to the prefix of the randomly named temporary directory to improve readability (#937). 2024-11-16 11:26:24 -08:00
073d6bddf6 Fix outdated comment (#934). 2024-11-16 07:26:23 -08:00
810b65589f Documentation for runtime/state directory changes (#934). 2024-11-15 22:23:49 -08:00
295bfb0c57 Update the logic that probes for the borgmatic streaming database dump, bootstrap metadata, and check state directories to support more platforms and use cases (#934). 2024-11-15 18:15:32 -08:00
5f3d4f9b03 final fix for true/false and 1/0 2024-11-13 15:27:25 -05:00
5321301708 fix for true/false to 1/0 2024-11-13 15:23:47 -05:00
a939a66fb4 raise ValueError on priprity 2 with retry or expire 2024-11-13 15:20:52 -05:00
c0721a8cad Fix misleading example for user_runtime_directory.
All checks were successful
build / test (push) Successful in 5m45s
build / docs (push) Successful in 1m40s
2024-11-13 11:17:40 -08:00
ea47704d86 added missing tests to get 100% test coverage 2024-11-13 12:09:25 -05:00
61e4eeff6c converted html to a boolean and updated documentation and schema 2024-11-13 11:52:08 -05:00
3ab4b45041 added test for early exit when state is not in config 2024-11-13 09:07:47 -05:00
4e1f256b48 added dryrun test case with minimum config 2024-11-12 10:15:19 -05:00
96bb402837 fix test 2 2024-11-12 10:10:13 -05:00
97949266b3 fix test 2024-11-12 10:09:23 -05:00
e69d2385fc better name for test 2024-11-12 10:08:13 -05:00
6d9340ebb2 better comment blocks 2024-11-12 10:05:57 -05:00
0441e79b41 "fail" -> "fails" 2024-11-12 10:00:34 -05:00
b1af304125 better data dict creation 2024-11-12 09:59:02 -05:00
eb8f7e0329 better description for expire and retry 2024-11-12 09:55:07 -05:00
bf978f2db4 Fix missing build backend setting in pyproject.toml to allow Fedora builds (#932).
All checks were successful
build / test (push) Successful in 4m3s
build / docs (push) Successful in 56s
2024-11-10 17:09:10 -08:00
22776b123d Bump version for release.
All checks were successful
build / test (push) Successful in 10m24s
build / docs (push) Successful in 1m37s
2024-11-10 08:13:18 -08:00
ef66349674 small fixed for some failing tests 2024-11-08 20:02:29 -05:00
51b885e7db added global constant for priority 2024-11-08 19:49:23 -05:00
1781787305 better schema description for retry and expire 2024-11-08 19:43:40 -05:00
46ebb0cebb removed redundant code 2024-11-08 18:45:46 -05:00
3e0fa57860 removed tests that are not needed 2024-11-08 17:44:27 -05:00
59f8722e05 better spacing for comments 2024-11-08 17:42:46 -05:00
4ba42e8905 better wording. Added 'by default' 2024-11-08 17:41:18 -05:00
3b79482b24 better wording 2024-11-08 17:38:58 -05:00
7eb19cb0a7 added period 2024-11-08 17:38:20 -05:00
a4fabb8521 fix version 2024-11-08 17:37:26 -05:00
85ea8f4f45 fix 10min in seconds 2024-11-08 15:03:38 -05:00
290559116d better logic for priority 2024-11-08 15:01:28 -05:00
72b27b0858 better message description in schema 2024-11-08 14:57:44 -05:00
0fdee067c7 double space fix 2024-11-08 14:45:36 -05:00
0dca5eeafc fix title wordwrap 2024-11-08 14:09:03 -05:00
02ce3ba190 fix url_title word wrap 2024-11-08 14:07:49 -05:00
dc78bf4d6b fix TTL wordwrap 2024-11-08 14:06:39 -05:00
4b7fbce291 fix sound word wrap 2024-11-08 14:05:27 -05:00
1817b9a9ea fix wordwrap for html 2024-11-08 13:50:22 -05:00
009055c61a device description rewrap 2024-11-08 13:48:21 -05:00
54884da8fa priority word wrap 2024-11-08 13:46:19 -05:00
1177385e08 fix expire description 2024-11-08 13:44:12 -05:00
a45ba8553c removed duplicate type:object 2024-11-08 13:42:19 -05:00
d7d6e30178 moved checks from hook to schema 2024-11-08 13:40:23 -05:00
56304fdcad Add NEWS entry for multiple system credentials fix (#930).
All checks were successful
build / test (push) Successful in 4m10s
build / docs (push) Successful in 1m37s
2024-11-07 20:20:41 -08:00
3f75e9931f Only support a single systemd credential by default (#930).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #930
Reviewed-by: Dan Helfman <witten@torsion.org>
2024-11-08 04:18:56 +00:00
227f475e17 Fix an error when implicitly upgrading the check state directory across filesystems (#931).
All checks were successful
build / test (push) Successful in 5m48s
build / docs (push) Successful in 1m38s
2024-11-07 19:19:56 -08:00
467ddd0e93 creds: Only support single credential by default 2024-11-08 00:36:24 +01:00
be08e889f0 Fix the user runtime directory location on macOS (and possibly Cygwin) (#928).
All checks were successful
build / test (push) Successful in 6m31s
build / docs (push) Successful in 2m5s
2024-11-03 21:44:11 -08:00
94c8a56373 Reorder NEWS items. 2024-11-03 13:58:04 -08:00
cecf04aa69 Bump version for release.
All checks were successful
build / test (push) Successful in 6m48s
build / docs (push) Successful in 2m5s
2024-11-03 13:23:57 -08:00
814cdb4b87 Deprecate the "borgmatic_source_directory" option in favor of "user_runtime_directory" and "user_state_directory" (#562). Move the default borgmatic streaming database dump and bootstrap metadata location on disk (#562). With Borg 1.4+, store database dumps and bootstrap metadata in a "/borgmatic" directory within a backup archive (#838). Add "--local-path", "--remote-path", and "--user-runtime-directory" flags to the "config bootstrap" action. 2024-11-03 13:14:05 -08:00
13878be254 Move the default check state directory (#562, #638). Deprecate the "borgmatic_source_directory" option in favor of "borgmatic_runtime_directory" and "borgmatic_state_directory" (#562).
All checks were successful
build / test (push) Successful in 6m56s
build / docs (push) Successful in 2m17s
2024-10-30 22:36:43 -07:00
94db527500 finalized support for Pushover 2024-10-30 15:43:06 -04:00
2849f54932 initial pushover commit 2024-10-30 11:25:26 -04:00
129f3e753c Flesh out the Zabbix monitoring hook tests, add a logo to the documentation, etc.
All checks were successful
build / test (push) Successful in 6m8s
build / docs (push) Successful in 2m9s
2024-10-29 10:33:19 -07:00
c85bf46ad9
Add Zabbix monitoring hook.
Merge pull request #85 from tony1661/zabbix-hook
2024-10-29 09:01:15 -07:00
fa6a4734d4 added auth tests with item id 2024-10-29 09:00:06 -04:00
e52e29444f added user/pass auth test 2024-10-29 08:54:25 -04:00
f713f1df7e better function names and comments 2024-10-29 08:21:52 -04:00
87d824553d converted constants to capitals 2024-10-29 08:05:05 -04:00
52fbf8cb24 capital 2024-10-28 09:54:07 -04:00
f758374772 adjustment in docs to reflect changes in 385ef2d 2024-10-28 09:52:20 -04:00
60c5949c23 adjusted to accept integers and strings 2024-10-28 09:51:08 -04:00
d11c517f67 better schema descriptions 2024-10-28 09:41:34 -04:00
237999cc81 fix word-wrap 2024-10-28 09:40:14 -04:00
d060f8d77a fix log for dry_run_label 2024-10-28 09:38:17 -04:00
385ef2d012 fixes and first unit test attempt 2024-10-28 09:36:30 -04:00
02a2e77315 Add Documentation=... to sample systemd service files.
All checks were successful
build / test (push) Successful in 5m5s
build / docs (push) Successful in 1m14s
2024-10-27 16:31:08 -07:00
9b623a8a8e Move docs exporting to a separate script in the hopes it'll actually work there.
All checks were successful
build / test (push) Successful in 4m57s
build / docs (push) Successful in 1m12s
2024-10-27 14:48:17 -07:00
e1f60e4b09 Fix podman create command to use correct image name.
Some checks failed
build / test (push) Successful in 4m48s
build / docs (push) Failing after 1m11s
2024-10-27 14:33:58 -07:00
269c00b240 Yet another attempt at making a docs tarball from a container image.
Some checks failed
build / test (push) Successful in 4m50s
build / docs (push) Failing after 1m6s
2024-10-27 14:26:00 -07:00
48f008d720 Fix image name of docs export.
Some checks failed
build / test (push) Successful in 5m2s
build / docs (push) Failing after 1m14s
2024-10-27 13:51:12 -07:00
53d9ffd1d3 Attempt to make a borgmatic docs tarball package in CI.
Some checks failed
build / test (push) Successful in 5m4s
build / docs (push) Failing after 1m16s
2024-10-27 13:26:41 -07:00
d7323e08ac Fix isort invocation referring to gone setup.cfg file (#922).
All checks were successful
build / test (push) Successful in 5m4s
build / docs (push) Successful in 2m4s
2024-10-26 20:44:14 -07:00
fc7a2852e0 Code formatting.
Some checks failed
build / test (push) Failing after 2m27s
build / docs (push) Has been skipped
2024-10-26 20:34:48 -07:00
f8c9d985e8 Add pyproject.toml transitin to NEWS.
Some checks failed
build / test (push) Failing after 2m44s
build / docs (push) Has been skipped
2024-10-26 16:40:15 -07:00
c7ca9bf844 Replace setup.py with pyproject.toml.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #922
2024-10-26 23:38:34 +00:00
7a117d5cc9 Add support for Borg 2's "sftp://" repository URLs.
All checks were successful
build / test (push) Successful in 4m51s
build / docs (push) Successful in 1m10s
2024-10-26 11:58:26 -07:00
bd9751586c Merge blake8 conf to tox.ini 2024-10-26 20:11:39 +02:00
fe0fe27c36 Adjust for Borg 2's change from "rclone://" repository URLs to just "rclone:".
All checks were successful
build / test (push) Successful in 4m55s
build / docs (push) Successful in 1m11s
2024-10-26 09:41:01 -07:00
1426859e1c Mention required borgmatic version in docs about Borg 2.x series changes.
All checks were successful
build / test (push) Successful in 6m48s
build / docs (push) Successful in 2m15s
2024-10-25 22:33:22 -07:00
ffb431e3ab minor improvement 2024-10-25 17:34:33 -04:00
11fee81486 converted string to dictionary as requested 2024-10-25 17:28:02 -04:00
83bc737185 Borg 2 changes: Default the "archive_name_format" option to just "{hostname}". Update the "--match-archives"/"--archive" flags to support series names / archive hashes. Add a "--match-archives" flag to the "prune" action.
All checks were successful
build / test (push) Successful in 5m38s
build / docs (push) Successful in 2m1s
2024-10-25 14:26:31 -07:00
cda83310c8 fixed version number 2024-10-25 08:10:25 -04:00
90ccbecf07 better documatation description 2024-10-25 08:08:38 -04:00
ccbf668bea fix for if logic 2024-10-24 09:01:10 -04:00
f18219a768 changes made with 'tox - e isort' 2024-10-24 08:00:14 -04:00
9ba8ca24eb changes made with 'tox -e black' 2024-10-24 07:52:32 -04:00
b42793a2dc convert concat to fstring 2024-10-23 18:26:22 -04:00
2877c1ad0d added spaces after commas 2024-10-23 18:10:58 -04:00
1b9f95ca47 better description in schema for server 2024-10-23 18:04:28 -04:00
7aff22536d better itemid description in schema 2024-10-23 17:53:07 -04:00
d6e1cc3e12 better wording 2024-10-23 17:43:54 -04:00
c1a08edca2 subheader formatting 2024-10-23 17:42:11 -04:00
02a219fac2 it will 2024-10-23 17:40:24 -04:00
78f81c7b73 changed verison to 1.9 - zabbix hook 2024-10-23 17:39:36 -04:00
8edb40a8e9 added dryrun check 2024-10-23 17:38:24 -04:00
f2d7687ca3 removed unused variable 2024-10-23 17:34:21 -04:00
b5fb0c8247 added returns when expected values are not provided 2024-10-23 17:33:09 -04:00
9b2ac961d7 capitalized Zabbix in logging 2024-10-23 17:30:28 -04:00
38ce98771b removed spaces before logging 2024-10-23 17:28:54 -04:00
f616284ffb better description for server string 2024-10-23 17:24:20 -04:00
5da898003f removed unnecessary parentheses here and below 2024-10-23 17:21:30 -04:00
5a464b3186 better logic for run_states 2024-10-23 17:19:51 -04:00
42fb8c38e0 better comments and logging 2024-10-23 17:15:55 -04:00
80839566d6 better wording for API key 2024-10-23 17:12:18 -04:00
702e55e6f7 formatting fix for key 2024-10-23 17:08:37 -04:00
1a8e8835c1 added quotes and period for host description 2024-10-23 17:00:31 -04:00
9abc5c60d4 its 2024-10-23 16:53:18 -04:00
fc87b74ab0 capital fixed 2024-10-23 16:52:45 -04:00
ad21eb41ae Add support for Borg 2's "rclone://" repository URLs.
All checks were successful
build / test (push) Successful in 6m5s
build / docs (push) Successful in 1m38s
2024-10-23 11:10:40 -07:00
601e393ec7 Fixed package discovery in pyproject.toml 2024-10-22 22:04:33 +02:00
e391fd196d Add loading of systemd credentials to NEWS (#902).
All checks were successful
build / test (push) Successful in 4m8s
build / docs (push) Successful in 1m39s
2024-10-22 09:01:18 -07:00
5f387b3991 Fix documentation URL in YAML (#902). 2024-10-22 08:59:13 -07:00
ed957a940a Load systemd encrypted credentials (#902).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #902
Reviewed-by: Dan Helfman <witten@torsion.org>
2024-10-22 15:58:41 +00:00
bd4c672382 Apply the "working_directory" option to all actions, not just "create". Also fix the glob expansion of "source_directories" values to respect the "working_directory" option (#609).
All checks were successful
build / test (push) Successful in 5m44s
build / docs (push) Successful in 1m36s
2024-10-20 16:04:41 -07:00
c71da46963 Fix change-passphrase to actually prompt for a new passphrase when an old one is configured (#911). 2024-10-19 09:58:32 -07:00
3da7471fe6 added note about zabbix 7.0+ 2024-10-18 18:00:14 -04:00
b874e7e66f zabbix hook added 2024-10-18 17:57:37 -04:00
b029d1cb67 Add codespell to pyproject.toml 2024-10-15 12:52:05 +02:00
33b1101ce1 Add isort to pyproject.toml 2024-10-15 12:51:33 +02:00
d96c5f79fb Add pytest to pyproject.toml 2024-10-14 18:30:39 +02:00
9e29ce788f Fixed release script 2024-10-14 18:17:22 +02:00
4658c5d1cb Moving to pyproject.toml 2024-10-14 18:17:14 +02:00
5280de86ff Load encrypted systemd credentials 2024-10-13 15:42:07 +02:00
29d5b36a78 Change soft failure command hooks to skip only the current repository (#921).
All checks were successful
build / test (push) Successful in 4m48s
build / docs (push) Successful in 1m16s
2024-10-06 17:39:02 -07:00
29f214a269 Change borgmatic 1.8.15 (unreleased) to 1.9.0 due to breaking changes.
All checks were successful
build / test (push) Successful in 6m20s
build / docs (push) Successful in 1m57s
2024-10-06 16:07:14 -07:00
6fdce2a4a6 Fix a confusing apparent hang when when the repository location changes, and instead show a helpful error message (#914).
All checks were successful
build / test (push) Successful in 5m1s
build / docs (push) Successful in 1m15s
2024-10-03 16:48:34 -07:00
a4b65cf710 Update Borg 2 beta links.
All checks were successful
build / test (push) Successful in 6m30s
build / docs (push) Successful in 1m57s
2024-10-03 08:03:47 -07:00
79725d2ff7 Document a policy for versioning and breaking changes (#919).
All checks were successful
build / test (push) Successful in 4m47s
build / docs (push) Successful in 1m14s
2024-10-02 09:10:12 -07:00
f7e8a2c1d1 Clarify the command-line help for the "--config" flag (#919).
All checks were successful
build / test (push) Successful in 6m25s
build / docs (push) Successful in 2m2s
2024-10-02 08:47:52 -07:00
f54d566edc Fixes to make the inclusive language linter happy.
All checks were successful
build / test (push) Successful in 5m0s
build / docs (push) Successful in 1m24s
2024-10-01 13:37:31 -07:00
b7efa0d3f0 When databases are configured, don't auto-enable the "one_file_system" option (#918).
All checks were successful
build / test (push) Successful in 5m0s
build / docs (push) Successful in 1m17s
2024-10-01 10:16:30 -07:00
88b945dcb9 Add missing test (#911).
All checks were successful
build / test (push) Successful in 5m8s
build / docs (push) Successful in 1m57s
2024-10-01 09:31:03 -07:00
34305d686c Revert "Add missing test (#911)" which accidentally included unrelated changes.
This reverts commit bf1e8bc44ec460980fad19372c04eb37c039fa1f.
2024-10-01 09:28:39 -07:00
bf1e8bc44e Add missing test (#911).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-10-01 09:26:00 -07:00
fd4f69f6c3 Rename repository actions for compatibility with recent Borg 2 changes (#915).
All checks were successful
build / test (push) Successful in 6m23s
build / docs (push) Successful in 1m59s
2024-09-09 10:05:32 -07:00
1fe6ae83a8 Add a "key change-passphrase" action to change the passphrase protecting a repository key (#911).
All checks were successful
build / test (push) Successful in 6m22s
build / docs (push) Successful in 1m53s
2024-09-01 11:13:39 -07:00
1197d6d0f6 Bump version for release. 2024-08-29 17:41:02 -07:00
288a4bf243 : Add documentation details for how to run custom database dump commands using binaries from running containers (#906).
All checks were successful
build / test (push) Successful in 4m3s
build / docs (push) Successful in 1m6s
2024-08-20 15:03:49 -07:00
1fb943e5f1 Documentation and config schema update about ~/.borgmatic volume mount (#906).
All checks were successful
build / test (push) Successful in 4m3s
build / docs (push) Successful in 1m5s
Reviewed-on: #907
2024-08-20 21:51:51 +00:00
e0298685a1 Fix the "source_directories_must_exist" option to work with relative "source_directories" paths when a "working_directory" is set (#905).
All checks were successful
build / test (push) Successful in 4m3s
build / docs (push) Successful in 53s
2024-08-20 13:52:06 -07:00
c5633227bf Add glob ("*") support to the "--repository" flag (#898).
All checks were successful
build / test (push) Successful in 5m49s
build / docs (push) Successful in 1m38s
2024-08-20 12:49:50 -07:00
6087c12e09 docs: typo 2024-08-16 14:36:28 +02:00
9d83f02e24 fix(config/schema.yaml): Add note about mounting .borgmatic folder inside container db backups 2024-08-16 14:25:11 +02:00
b6ccde6757 fix(docs): Add note about mounting .borgmatic folder inside container db backups 2024-08-16 14:23:59 +02:00
548aceb3d5 Fix config validation broken by schema change (#904).
All checks were successful
build / test (push) Successful in 4m5s
build / docs (push) Successful in 1m37s
2024-08-12 23:09:55 -07:00
2bd63bbdd2 Clarify the configuration reference about the "spot" check options (#904).
Some checks failed
build / test (push) Failing after 5m26s
build / docs (push) Has been skipped
2024-08-12 22:50:58 -07:00
9b4fed64a6 Upgrade run-full-tests dependencies.
All checks were successful
build / test (push) Successful in 4m3s
build / docs (push) Successful in 1m35s
2024-08-11 20:41:43 -07:00
ff1001a5f5 Fix NEWS typo.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-08-11 20:38:38 -07:00
e7f1c3eda5 Add "color" option regression fix to NEWS.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-08-11 20:35:54 -07:00
21e343a948
Fix broken color configuration option.
Merge pull request #83 from TheoBrigitte/main
2024-08-11 20:32:43 -07:00
Theo Brigitte
4c4fd92013
update logger unit tests
* update color config structure
  * add check for color: True in config
  * ensure interactive_console is called wherever it should
2024-08-09 00:07:46 +02:00
Theo Brigitte
37735e464c
Fix color configuration directive 2024-08-05 16:38:49 +02:00
424cc6b66c Fix for a "bad character" Borg error in which the "spot" check fed Borg an invalid pattern (#899).
All checks were successful
build / test (push) Successful in 6m5s
build / docs (push) Successful in 1m32s
2024-07-25 11:34:09 -07:00
e128a3e0a9 Add a ticket number onto the traceback fix in NEWS.
All checks were successful
build / test (push) Successful in 5m59s
build / docs (push) Successful in 1m35s
2024-07-19 22:22:19 -07:00
27e7ece2f5 More fix for a potential traceback (TypeError) during the handling of another error.
All checks were successful
build / test (push) Successful in 5m55s
build / docs (push) Successful in 1m33s
2024-07-15 14:45:21 -07:00
d44dc93509 Fix for a potential traceback (TypeError) during the handling of another error.
All checks were successful
build / test (push) Successful in 5m56s
build / docs (push) Successful in 1m32s
2024-07-14 10:07:15 -07:00
31778fd3bf Fix error in borgmatic rcreate/init on empty repository directory with Borg 1.4 (#896).
All checks were successful
build / test (push) Successful in 4m17s
build / docs (push) Successful in 51s
2024-07-08 11:24:48 -07:00
4313f90dd8 Add a couple of more code style guidelines.
All checks were successful
build / test (push) Successful in 5m55s
build / docs (push) Successful in 1m35s
2024-07-07 20:49:27 -07:00
1f82ea2798 Attempt to fix documentation build.
All checks were successful
build / test (push) Successful in 4m15s
build / docs (push) Successful in 52s
2024-07-06 10:23:10 -07:00
148536d867 Upgrade certifi in test requirements.
Some checks failed
build / test (push) Successful in 4m17s
build / docs (push) Has been cancelled
2024-07-06 10:17:53 -07:00
197f0a521d Add a recent contributors section to the documentation.
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-07-06 10:15:16 -07:00
0d8e352033 Update documentation link to Borg 1.4.0 exit codes.
All checks were successful
build / test (push) Successful in 4m14s
build / docs (push) Successful in 52s
2024-07-04 20:21:40 -07:00
20a3995977 Bump version for release.
All checks were successful
build / test (push) Successful in 4m14s
build / docs (push) Successful in 50s
2024-07-04 08:54:09 -07:00
66aa953371 Add additional tests (#298).
All checks were successful
build / test (push) Successful in 4m15s
build / docs (push) Successful in 50s
2024-07-04 08:42:05 -07:00
ba053de8f7 Add delete and rdelete actions (#298).
All checks were successful
build / test (push) Successful in 6m3s
build / docs (push) Successful in 1m20s
Reviewed-on: #893
2024-07-04 06:07:30 +00:00
2f844d65d5 Automated tests complete (#298). 2024-07-02 23:11:58 -07:00
2dca5e1834 Initial automated tests for delete action (#298). 2024-07-02 20:26:29 -07:00
36197ce027 Dry run support for delete/rdelete actions (#298). 2024-06-28 20:56:42 -07:00
e9a0226ee0 Initial work on delete/rdelete actions (#298). 2024-06-28 16:20:10 -07:00
fc3b4a653e Add a development documentation note about using fully qualified imports. 2024-06-28 15:00:25 -07:00
3673abb01e Update documentation links that link to beta versions of Borg docs.
All checks were successful
build / test (push) Successful in 4m17s
build / docs (push) Successful in 51s
2024-06-27 14:42:53 -07:00
ac4277d36c Add "new in version" label to Uptime Kuma documentation (#885).
All checks were successful
build / test (push) Successful in 4m15s
build / docs (push) Successful in 1m19s
2024-06-27 09:29:53 -07:00
21cbc99d9e Fix uptime_kuma monitor not being called after name change (#891).
Some checks failed
build / test (push) Successful in 6m3s
build / docs (push) Has been cancelled
Reviewed-on: #891
2024-06-27 16:27:07 +00:00
Paul Wilde
d080bf2ae9 [bugfix] uptime_kuma monitor is not called after name change 2024-06-27 12:49:07 +01:00
2a1c790655 Minor reorganization of borgmatic source code reference.
All checks were successful
build / test (push) Successful in 4m17s
build / docs (push) Successful in 52s
2024-06-26 19:39:32 -07:00
410204a70d Formatting, whitespace, and minor fixes for Uptime Kuma hook (#885).
All checks were successful
build / test (push) Successful in 4m16s
build / docs (push) Successful in 1m0s
2024-06-26 16:09:14 -07:00
4a0c167c1c Add Uptime Kuma monitoring hook (#885).
All checks were successful
build / test (push) Successful in 4m15s
build / docs (push) Successful in 1m2s
Reviewed-on: #885
Reviewed-by: Dan Helfman <witten@torsion.org>
2024-06-26 22:50:11 +00:00
593c956d33 Add an "only_run_on" option to consistency checks so you can limit a check to running on particular days of the week (#785).
All checks were successful
build / test (push) Successful in 6m0s
build / docs (push) Successful in 1m28s
2024-06-26 14:57:59 -07:00
d18cb89493 Merge branch 'main' into main 2024-06-26 19:58:56 +00:00
Paul Wilde
067c79c606 renamed push_monitor back to ping_monitor in uptime kuma hook 2024-06-26 20:57:37 +01:00
ebde88ccaa Fix the Healthchecks ping body size limit, restoring it to the documented 100,000 bytes (#889).
All checks were successful
build / test (push) Successful in 6m0s
build / docs (push) Successful in 1m28s
2024-06-25 12:45:44 -07:00
cc402487d9 Minor development documentation clarifications.
All checks were successful
build / test (push) Successful in 5m55s
build / docs (push) Successful in 1m29s
2024-06-24 10:48:13 -07:00
d108e6102b some minor corrections in how to uptime kuma docs 2024-06-24 12:00:22 +01:00
3e60043632 some minor corrections in how to uptime kuma docs 2024-06-24 11:57:12 +01:00
a8d691169a some minor corrections in how to uptime kuma docs 2024-06-24 11:54:34 +01:00
939c2f6718 some minor corrections in how to uptime kuma docs 2024-06-24 11:54:12 +01:00
0837059e21 some minor corrections in how to uptime kuma docs 2024-06-24 11:51:41 +01:00
0ee166fdf0 added Uptime Kuma how-to docs 2024-06-24 11:46:38 +01:00
b50996b864 change uptimekuma method names to 'push_*' instead of 'ping' 2024-06-24 11:07:09 +01:00
8f423c7293 black formatting on uptimekuma hook 2024-06-24 10:46:04 +01:00
14ce88e04b black formatting on test_uptimekuma.py 2024-06-24 10:37:44 +01:00
f97968b72d variable renaming 2024-06-24 10:34:52 +01:00
612f867ea8 Merge remote-tracking branch 'upstream/main' 2024-06-24 10:28:02 +01:00
303d6609e4 removed unecessary tests for 'default urls' as these would never really be used anyway 2024-06-24 10:27:23 +01:00
bf7b163ccd added early out for dry run 2024-06-24 10:25:08 +01:00
4bd798f0ad alpha ordered dispatch monitor hook names (including loki) 2024-06-24 10:22:27 +01:00
52aa7c5d21 switched to using full 'push_url' instead of separate 'server' and 'push_code' 2024-06-24 10:21:31 +01:00
f5a1dd31c8 Fix PagerDuty hook traceback with Python < 3.10 (#886).
All checks were successful
build / test (push) Successful in 4m17s
build / docs (push) Successful in 50s
2024-06-23 18:28:41 -07:00
c41000a4b1 Bump version for release.
Some checks failed
build / test (push) Failing after 1m19s
build / docs (push) Has been skipped
2024-06-23 17:02:13 -07:00
c3f8b05a68 Fix test warning in PagerDuty hook. 2024-06-23 17:01:54 -07:00
f4fcf92bd6 Add an "upload_buffer_size" option to set the size of the upload buffer used in "create" action (#865).
All checks were successful
build / test (push) Successful in 6m17s
build / docs (push) Successful in 1m28s
2024-06-23 16:26:22 -07:00
a2c139245d Add a "--max-duration" flag to the "check" action and a "max_duration" option to the repository check configuration (#817).
All checks were successful
build / test (push) Successful in 6m14s
build / docs (push) Successful in 1m29s
2024-06-22 16:19:06 -07:00
Paul Wilde
a509cdedd5 Added Uptime Kuma tests 2024-06-22 10:46:17 +01:00
Paul Wilde
dcbc30b164 WIP add uptime kuma tests 2024-06-22 10:19:34 +01:00
Paul Wilde
5ab99b4cc0 Added Uptime Kuma image to readme 2024-06-21 21:21:04 +01:00
Paul Wilde
27c90b7cf1 Added Uptime Kuma hook 2024-06-21 21:10:14 +01:00
Paul Wilde
6eb76454bb WIP added some schema info for uptime kuma 2024-06-21 17:00:44 +01:00
Paul Wilde
83bcea98dc WIP added some schema info for uptime kuma 2024-06-21 16:57:20 +01:00
Paul Wilde
4db09a73b3 WIP implement Uptime Kuma hook 2024-06-21 16:47:51 +01:00
45a9e3bfc3 Document that "borgmatic borg create" bypasses monitoring hooks (#882).
All checks were successful
build / test (push) Successful in 4m23s
build / docs (push) Successful in 53s
2024-06-20 14:25:20 -07:00
bd40015e1c Added missing word to NEWS entry (#881).
All checks were successful
build / test (push) Successful in 4m37s
build / docs (push) Successful in 1m29s
2024-06-20 13:33:34 -07:00
7894600408 Fix "Unrecognized argument" error when the same value is with different command-line flags (#881).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-06-20 11:53:52 -07:00
df4668754d Fix "Argument list too long" error in the "spot" check when checking 100k+ files (#866).
All checks were successful
build / test (push) Successful in 6m20s
build / docs (push) Successful in 1m29s
2024-06-09 22:53:56 -07:00
08d6f83b2e In the "spot" check, don't try to hash symlinked directories.
All checks were successful
build / test (push) Successful in 4m25s
build / docs (push) Successful in 51s
2024-06-09 15:58:16 -07:00
c58f510054 Minor spot check documentation clarification (#868).
All checks were successful
build / test (push) Successful in 6m7s
build / docs (push) Successful in 1m30s
2024-06-09 15:28:28 -07:00
c2879d054a Alpha ordering in docs (#874).
All checks were successful
build / test (push) Successful in 4m29s
build / docs (push) Successful in 53s
2024-06-05 14:58:43 -07:00
f821d2c909 Calling interpolated variable "repository_label" instead of "label" for clarity (#874).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-06-05 14:56:21 -07:00
1ef2218919 Remove obsolute "version:" from Docker Compose files. 2024-06-05 14:50:52 -07:00
177c958572 Add configured repository "label" to the interpolated variables passed to command hooks (#874).
All checks were successful
build / test (push) Successful in 4m26s
build / docs (push) Successful in 52s
2024-06-05 14:47:37 -07:00
b5ab1ff0cd Use (current) default action order whenever actions are mentioned (#873).
All checks were successful
build / test (push) Successful in 6m9s
build / docs (push) Successful in 1m30s
2024-06-05 11:21:51 -07:00
70a978b83d Upgrade test requirements.
All checks were successful
build / test (push) Successful in 5m46s
build / docs (push) Successful in 1m15s
2024-05-21 13:57:06 -07:00
2037810c6b Avoid requiring network in test_healthchecks.py (#869).
All checks were successful
build / test (push) Successful in 7m26s
build / docs (push) Successful in 2m27s
Reviewed-on: #869
2024-05-21 20:33:21 +00:00
de304f83de
Avoid requiring network in test_healthchecks.py
Some test environments (e.g., the one of the Nix build system) don't
allow network requests while building and testing.
2024-05-16 16:11:40 +02:00
5752373009 When color output is disabled (explicitly or implicitly), don't prefix each log line with the log level (#863).
All checks were successful
build / test (push) Successful in 7m59s
build / docs (push) Successful in 2m26s
2024-05-11 22:40:13 -07:00
fecae39fcd To avoid duplicate install, update docs to uninstall borgmatic before re-installing with Apprise (#862).
All checks were successful
build / test (push) Successful in 7m57s
build / docs (push) Successful in 2m23s
2024-05-03 16:48:35 -07:00
38bc4fbfe2 Fix interaction between environment variable interpolation in constants and shell escaping (#860).
All checks were successful
build / test (push) Successful in 7m52s
build / docs (push) Successful in 2m19s
2024-04-30 09:36:26 -07:00
92ed7573d4 Fix NEWS formatting.
All checks were successful
build / test (push) Successful in 7m22s
build / docs (push) Successful in 2m7s
2024-04-29 09:39:40 -07:00
80f0e92462 Bump version for release. 2024-04-29 09:38:02 -07:00
5f10b1b2ca Clarify database limitations.
All checks were successful
build / test (push) Successful in 6m10s
build / docs (push) Successful in 1m23s
2024-04-28 16:55:24 -07:00
4f83b1e6b3 [Documentation] Add compression level explanation and example.
All checks were successful
build / test (push) Successful in 7m24s
build / docs (push) Successful in 2m27s
Reviewed-on: #859
2024-04-28 16:50:09 +00:00
15d5a687fb
make parenthetical its own sentence 2024-04-28 18:41:05 +02:00
eb1fce3787
documentation: add compression level explanation and example 2024-04-28 18:24:23 +02:00
7f735cbe59 Fix a traceback with "check --only spot" when the "spot" check is unconfigured (#857).
All checks were successful
build / test (push) Successful in 7m42s
build / docs (push) Successful in 2m10s
2024-04-24 16:12:58 -07:00
a690ea4016 Add Healtchecks auto-provisioning to NEWS (#815).
All checks were successful
build / test (push) Successful in 5m49s
build / docs (push) Successful in 2m16s
2024-04-23 09:25:29 -07:00
7a110c7acd Add Healthchecks auto-provisionning (#815).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
Reviewed-on: #852
Reviewed-by: Dan Helfman <witten@torsion.org>
2024-04-23 16:23:26 +00:00
407bb33359 Fix schema.yaml to comply with maximum line length 2024-04-22 20:47:03 +02:00
4b7f7bba04 Issue warning if using UUID URL scheme with create_slug 2024-04-22 20:45:36 +02:00
cfdc0a1f2a Fix Healthchecks UUID regex 2024-04-22 20:44:31 +02:00
f926055e67 Fix a traceback when the "data" consistency check is used (#854).
All checks were successful
build / test (push) Successful in 7m36s
build / docs (push) Successful in 2m26s
2024-04-21 14:55:02 -07:00
058af95d70 Document limitation about using database hooks and "one_file_system" (#853).
All checks were successful
build / test (push) Successful in 4m20s
build / docs (push) Successful in 52s
2024-04-20 14:53:41 -07:00
54facdc391 Clarify Apprise states configuration.
All checks were successful
build / test (push) Successful in 6m2s
build / docs (push) Successful in 1m29s
2024-04-20 08:26:06 -07:00
2e4c0cc7e7 Support for healthchecks auto provisionning 2024-04-19 10:43:45 +02:00
cb2fd7c5e8 Fix lack of file extraction when using "extract --strip-components all" on a path with a leading slash (#851).
All checks were successful
build / test (push) Successful in 6m0s
build / docs (push) Successful in 1m30s
2024-04-17 16:50:09 -07:00
94133cc8b1 Add note about running spot check on a separate schedule (#656).
All checks were successful
build / test (push) Successful in 4m15s
build / docs (push) Successful in 52s
2024-04-16 10:57:34 -07:00
dcec89be90 Wording tweak (#656).
Some checks failed
build / test (push) Successful in 4m17s
build / docs (push) Has been cancelled
2024-04-16 10:52:56 -07:00
fefd5d1d0e Wording tweak (#656).
Some checks failed
build / docs (push) Blocked by required conditions
build / test (push) Has been cancelled
2024-04-16 10:50:37 -07:00
306 changed files with 37447 additions and 9271 deletions

View File

@ -1 +0,0 @@
select = Q0

View File

@ -3,6 +3,8 @@ run-name: ${{ gitea.actor }} is building
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
@ -15,6 +17,7 @@ jobs:
docs:
needs: [test]
runs-on: host
if: gitea.event_name == 'push'
env:
IMAGE_NAME: projects.torsion.org/borgmatic-collective/borgmatic:docs
@ -26,3 +29,5 @@ jobs:
PASSWORD: "${{ secrets.REGISTRY_PASSWORD }}"
- run: podman build --tag "$IMAGE_NAME" --file docs/Dockerfile --storage-opt "overlay.mount_program=/usr/bin/fuse-overlayfs" .
- run: podman push "$IMAGE_NAME"
- run: scripts/export-docs-from-image
- run: curl --user "${{ secrets.REGISTRY_USERNAME }}:${{ secrets.REGISTRY_PASSWORD }}" --upload-file borgmatic-docs.tar.gz https://projects.torsion.org/api/packages/borgmatic-collective/generic/borgmatic-docs/$(head --lines=1 NEWS)/borgmatic-docs.tar.gz

353
NEWS
View File

@ -1,3 +1,356 @@
2.0.4
* #1072: Fix path rewriting for non-root patterns in the ZFS, Btrfs, and LVM hooks.
* #1073: Clarify the documentation about when an "after: error" command hook runs and how it
differs from other hooks:
https://torsion.org/borgmatic/docs/how-to/add-preparation-and-cleanup-steps-to-backups/
* #1075: Fix an incorrect warning about Borg placeholders being unsupported in a command hook.
* #1080: If the exact same "everything" command hook is present in multiple configuration files,
only run it once.
2.0.3
* #1065: Fix a regression in monitoring hooks in which an error pinged the finish state instead of
the fail state.
* #1066: Add a "states" option to command hooks, so you can optionally skip an "after" hook if
borgmatic encounters an error.
* #1071: Fix an error in the LVM hook when removing a snapshot directory.
2.0.2
* #1035: Document potential performance issues and workarounds with the ZFS, Btrfs, and LVM hooks:
https://torsion.org/borgmatic/docs/how-to/snapshot-your-filesystems/
* #1053: Display a nicer error message when the "recreate" action encounters an archive that
already exists.
* #1059: Fix a regression in which soft failure exit codes in command hooks were not respected.
* #1060: Fix action command hooks getting run too many times when multiple borgmatic actions are
executed (implicitly or explicitly).
* #1060: Don't run action command hooks for actions listed in the "skip_actions" option.
* #1062: Fix a regression that broke environment variable interpolation.
* #1063: List the configured "when" action names in the log entries for command hooks.
2.0.1
* #1057: Fix argument parsing to avoid using Python 3.12+ string features. Now borgmatic will
work with Python 3.9, 3.10, and 3.11 again.
2.0.0
* TL;DR: More flexible, completely revamped command hooks. All configuration options settable on
the command-line. New configuration options for many command-line flags (including verbosity!).
New "key import" and "recreate" actions. Almost everything is backwards compatible—but mind those
deprecation warnings!
* #262: Add a "default_actions" option that supports disabling default actions when borgmatic is
run without any command-line arguments.
* #303: Deprecate the "--override" flag in favor of direct command-line flags for every borgmatic
configuration option. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/make-per-application-backups/#configuration-overrides
* #303: Add configuration options that serve as defaults for some (but not all) command-line
action flags. For example, each entry in "repositories:" now has an "encryption" option that
applies to the "repo-create" action, serving as a default for the "--encryption" flag. See the
documentation for more information: https://torsion.org/borgmatic/docs/reference/configuration/
* #345: Add a "key import" action to import a repository key from backup.
* #422: Add home directory expansion to file-based and KeePassXC credential hooks.
* #610: Add a "recreate" action for recreating archives, for instance for retroactively excluding
particular files from existing archives.
* #790, #821: Deprecate all "before_*", "after_*" and "on_error" command hooks in favor of more
flexible "commands:". See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/add-preparation-and-cleanup-steps-to-backups/
* #790: BREAKING: For both new and deprecated command hooks, run a configured "after" hook even if
an error occurs first. This allows you to perform cleanup steps that correspond to "before"
preparation commands—even when something goes wrong.
* #790: BREAKING: Run all command hooks (both new and deprecated) respecting the
"working_directory" option if configured, meaning that hook commands are run in that directory.
* #793: Add configuration options for all verbosity and logging flags, so you don't have to set
them on the command-line.
* #836: Add a custom command option for the SQLite hook.
* #837: Add custom command options for the MongoDB hook.
* #1010: When using Borg 2, don't pass the "--stats" flag to "borg prune".
* #1020: Document a database use case involving a temporary database client container:
https://torsion.org/borgmatic/docs/how-to/backup-your-databases/#containers
* #1037: Fix an error with the "extract" action when both a remote repository and a
"working_directory" are used.
* #1044: Fix an error in the systemd credential hook when the credential name contains a "."
character.
* #1047: Add "key-file" and "yubikey" options to the KeePassXC credential hook.
* #1048: Fix a "no such file or directory" error in ZFS, Btrfs, and LVM hooks with nested
directories that reside on separate devices/filesystems.
* #1050: Fix a failure in the "spot" check when the archive contains a symlink.
* #1051: Add configuration filename to the "Successfully ran configuration file" log message.
1.9.14
* #409: With the PagerDuty monitoring hook, send borgmatic logs to PagerDuty so they show up in the
incident UI. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pagerduty-hook
* #936: Clarify Zabbix monitoring hook documentation about creating items:
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#zabbix-hook
* #1017: Fix a regression in which some MariaDB/MySQL passwords were not escaped correctly.
* #1021: Fix a regression in which the "exclude_patterns" option didn't expand "~" (the user's
home directory). This fix means that all "patterns" and "patterns_from" also now expand "~".
* #1023: Fix an error in the Btrfs hook when attempting to snapshot a read-only subvolume. Now,
read-only subvolumes are ignored since Btrfs can't actually snapshot them.
1.9.13
* #975: Add a "compression" option to the PostgreSQL database hook.
* #1001: Fix a ZFS error during snapshot cleanup.
* #1003: In the Zabbix monitoring hook, support Zabbix 7.2's authentication changes.
* #1009: Send database passwords to MariaDB and MySQL via anonymous pipe, which is more secure than
using an environment variable.
* #1013: Send database passwords to MongoDB via anonymous pipe, which is more secure than using
"--password" on the command-line!
* #1015: When ctrl-C is pressed, more strongly encourage Borg to actually exit.
* Add a "verify_tls" option to the Uptime Kuma monitoring hook for disabling TLS verification.
* Add "tls" options to the MariaDB and MySQL database hooks to enable or disable TLS encryption
between client and server.
1.9.12
* #1005: Fix the credential hooks to avoid using Python 3.12+ string features. Now borgmatic will
work with Python 3.9, 3.10, and 3.11 again.
1.9.11
* #795: Add credential loading from file, KeePassXC, and Docker/Podman secrets. See the
documentation for more information:
https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/
* #996: Fix the "create" action to omit the repository label prefix from Borg's output when
databases are enabled.
* #998: Send the "encryption_passphrase" option to Borg via an anonymous pipe, which is more secure
than using an environment variable.
* #999: Fix a runtime directory error from a conflict between "extra_borg_options" and special file
detection.
* #1001: For the ZFS, Btrfs, and LVM hooks, only make snapshots for root patterns that come from
a borgmatic configuration option (e.g. "source_directories")—not from other hooks within
borgmatic.
* #1001: Fix a ZFS/LVM error due to colliding snapshot mount points for nested datasets or logical
volumes.
* #1001: Don't try to snapshot ZFS datasets that have the "canmount=off" property.
* Fix another error in the Btrfs hook when a subvolume mounted at "/" is configured in borgmatic's
source directories.
1.9.10
* #966: Add a "{credential ...}" syntax for loading systemd credentials into borgmatic
configuration files. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/
* #987: Fix a "list" action error when the "encryption_passcommand" option is set.
* #987: When both "encryption_passcommand" and "encryption_passphrase" are configured, prefer
"encryption_passphrase" even if it's an empty value.
* #988: With the "max_duration" option or the "--max-duration" flag, run the archives and
repository checks separately so they don't interfere with one another. Previously, borgmatic
refused to run checks in this situation.
* #989: Fix the log message code to avoid using Python 3.10+ logging features. Now borgmatic will
work with Python 3.9 again.
* Capture and delay any log records produced before logging is fully configured, so early log
records don't get lost.
* Add support for Python 3.13.
1.9.9
* #635: Log the repository path or label on every relevant log message, not just some logs.
* #961: When the "encryption_passcommand" option is set, call the command once from borgmatic to
collect the encryption passphrase and then pass it to Borg multiple times. See the documentation
for more information: https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/
* #981: Fix a "spot" check file count delta error.
* #982: Fix for borgmatic "exclude_patterns" and "exclude_from" recursing into excluded
subdirectories.
* #983: Fix the Btrfs hook to support subvolumes with names like "@home" different from their
mount points.
* #985: Change the default value for the "--original-hostname" flag from "localhost" to no host
specified. This way, the "restore" action works without a hostname if there's a single matching
database dump.
1.9.8
* #979: Fix root patterns so they don't have an invalid "sh:" prefix before getting passed to Borg.
* Expand the recent contributors documentation section to include ticket submitters—not just code
contributors—because there are multiple ways to contribute to the project! See:
https://torsion.org/borgmatic/#recent-contributors
1.9.7
* #855: Add a Sentry monitoring hook. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#sentry-hook
* #968: Fix for a "spot" check error when a filename in the most recent archive contains a newline.
* #970: Fix for an error when there's a blank line in the configured patterns or excludes.
* #971: Fix for "exclude_from" files being completely ignored.
* #977: Fix for "exclude_patterns" and "exclude_from" not supporting explicit pattern styles (e.g.,
"sh:" or "re:").
1.9.6
* #959: Fix an error in the Btrfs hook when a subvolume mounted at "/" is configured in borgmatic's
source directories.
* #960: Fix for archives storing relative source directory paths such that they contain the working
directory.
* #960: Fix the "spot" check to support relative source directory paths.
* #962: For the ZFS, Btrfs, and LVM hooks, perform path rewriting for excludes and patterns in
addition to the existing source directories rewriting.
* #962: Under the hood, merge all configured source directories, excludes, and patterns into a
unified temporary patterns file for passing to Borg. The borgmatic configuration options remain
unchanged.
* #962: For the LVM hook, add support for nested logical volumes.
* #965: Fix a borgmatic runtime directory error when running the "spot" check with a database hook
enabled.
* #969: Fix the "restore" action to work on database dumps without a port when a default port is
present in configuration.
* Fix the "spot" check to no longer consider pipe files within an archive for file comparisons.
* Fix the "spot" check to have a nicer error when there are no source paths to compare.
* Fix auto-excluding of special files (when databases are configured) to support relative source
directory paths.
* Drop support for Python 3.8, which has been end-of-lifed.
1.9.5
* #418: Backup and restore databases that have the same name but with different ports, hostnames,
or hooks.
* #947: To avoid a hang in the database hooks, error and exit when the borgmatic runtime
directory overlaps with the configured excludes.
* #954: Fix a findmnt command error in the Btrfs hook by switching to parsing JSON output.
* #956: Fix the printing of a color reset code even when color is disabled.
* #958: Drop colorama as a library dependency.
* When the ZFS, Btrfs, or LVM hooks aren't configured, don't try to cleanup snapshots for them.
1.9.4
* #80 (beta): Add an LVM hook for snapshotting and backing up LVM logical volumes. See the
documentation for more information:
https://torsion.org/borgmatic/docs/how-to/snapshot-your-filesystems/
* #251 (beta): Add a Btrfs hook for snapshotting and backing up Btrfs subvolumes. See the
documentation for more information:
https://torsion.org/borgmatic/docs/how-to/snapshot-your-filesystems/
* #926: Fix a library error when running within a PyInstaller bundle.
* #950: Fix a snapshot unmount error in the ZFS hook when using nested datasets.
* Update the ZFS hook to discover and snapshot ZFS datasets even if they are parent/grandparent
directories of your source directories.
* Reorganize data source and monitoring hooks to make developing new hooks easier.
1.9.3
* #261 (beta): Add a ZFS hook for snapshotting and backing up ZFS datasets. See the documentation
for more information: https://torsion.org/borgmatic/docs/how-to/snapshot-your-filesystems/
* Remove any temporary copies of the manifest file created in support of the "bootstrap" action.
* Deprecate the "store_config_files" option at the global scope and move it under the "bootstrap"
hook. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/extract-a-backup/#extract-the-configuration-files-used-to-create-an-archive
* Require the runtime directory to be an absolute path.
* Add a "--deleted" flag to the "repo-list" action for listing deleted archives that haven't
yet been compacted (Borg 2 only).
* Promote the "spot" check from a beta feature to stable.
1.9.2
* #441: Apply the "umask" option to all relevant actions, not just some of them.
* #722: Remove the restriction that the "extract" and "mount" actions must match a single
repository. Now they work more like other actions, where each repository is applied in turn.
* #932: Fix the missing build backend setting in pyproject.toml to allow Fedora builds.
* #934: Update the logic that probes for the borgmatic streaming database dump, bootstrap
metadata, and check state directories to support more platforms and use cases. See the
documentation for more information:
https://torsion.org/borgmatic/docs/how-to/backup-your-databases/#runtime-directory
* #934: Add the "RuntimeDirectory" and "StateDirectory" options to the sample systemd service
file to support the new runtime and state directory logic.
* #939: Fix borgmatic ignoring the "BORG_RELOCATED_REPO_ACCESS_IS_OK" and
"BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK" environment variables.
* Add a Pushover monitoring hook. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pushover-hook
1.9.1
* #928: Fix the user runtime directory location on macOS (and possibly Cygwin).
* #930: Fix an error with the sample systemd service when no credentials are configured.
* #931: Fix an error when implicitly upgrading the check state directory from ~/.borgmatic to
~/.local/state/borgmatic across filesystems.
1.9.0
* #609: Fix the glob expansion of "source_directories" values to respect the "working_directory"
option.
* #609: BREAKING: Apply the "working_directory" option to all actions, not just "create". This
includes repository paths, destination paths, mount points, etc.
* #562: Deprecate the "borgmatic_source_directory" option in favor of "user_runtime_directory"
and "user_state_directory".
* #562: BREAKING: Move the default borgmatic streaming database dump and bootstrap metadata
directory from ~/.borgmatic to /run/user/$UID/borgmatic, which is more XDG-compliant. You can
override this location with the new "user_runtime_directory" option. Existing archives with
database dumps at the old location are still restorable.
* #562, #638: Move the default check state directory from ~/.borgmatic to
~/.local/state/borgmatic. This is more XDG-compliant and also prevents these state files from
getting backed up (unless you explicitly include them). You can override this location with the
new "user_state_directory" option. After the first time you run the "check" action with borgmatic
1.9.0, you can safely delete the ~/.borgmatic directory.
* #838: BREAKING: With Borg 1.4+, store database dumps and bootstrap metadata in a "/borgmatic"
directory within a backup archive, so the path doesn't depend on the current user. This means
that you can now backup as one user and restore or bootstrap as another user, among other use
cases.
* #902: Add loading of encrypted systemd credentials. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/#using-systemd-service-credentials
* #911: Add a "key change-passphrase" action to change the passphrase protecting a repository key.
* #914: Fix a confusing apparent hang when when the repository location changes, and instead
show a helpful error message.
* #915: BREAKING: Rename repository actions like "rcreate" to more explicit names like
"repo-create" for compatibility with recent changes in Borg 2.0.0b10.
* #918: BREAKING: When databases are configured, don't auto-enable the "one_file_system" option,
as existing auto-excludes of special files should be sufficient to prevent Borg from hanging on
them. But if this change causes problems for you, you can always enable "one_file_system"
explicitly.
* #919: Clarify the command-line help for the "--config" flag.
* #919: Document a policy for versioning and breaking changes:
https://torsion.org/borgmatic/docs/how-to/upgrade/#versioning-and-breaking-changes
* #921: BREAKING: Change soft failure command hooks to skip only the current repository rather than
all repositories in the configuration file.
* #922: Replace setup.py (Python packaging metadata) with the more modern pyproject.toml.
* When using Borg 2, default the "archive_name_format" option to just "{hostname}", as Borg 2 does
not require unique archive names; identical archive names form a common "series" that can be
targeted together. See the Borg 2 documentation for more information:
https://borgbackup.readthedocs.io/en/2.0.0b13/changes.html#borg-1-2-x-1-4-x-to-borg-2-0
* Add support for Borg 2's "rclone:" repository URLs, so you can backup to 70+ cloud storage
services whether or not they support Borg explicitly.
* Add support for Borg 2's "sftp://" repository URLs.
* Update the "--match-archives" and "--archive" flags to support Borg 2 series names or archive
hashes.
* Add a "--match-archives" flag to the "prune" action.
* Add "--local-path" and "--remote-path" flags to the "config bootstrap" action for setting the
Borg executable paths used for bootstrapping.
* Add a "--user-runtime-directory" flag to the "config bootstrap" action for helping borgmatic
locate the bootstrap metadata stored in an archive.
* Add a Zabbix monitoring hook. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#zabbix-hook
* Add a tarball of borgmatic's HTML documentation to the packages on the project page.
1.8.14
* #896: Fix an error in borgmatic rcreate/init on an empty repository directory with Borg 1.4.
* #898: Add glob ("*") support to the "--repository" flag. Just quote any values containing
globs so your shell doesn't interpret them.
* #899: Fix for a "bad character" Borg error in which the "spot" check fed Borg an invalid pattern.
* #900: Fix for a potential traceback (TypeError) during the handling of another error.
* #904: Clarify the configuration reference about the "spot" check options:
https://torsion.org/borgmatic/docs/reference/configuration/
* #905: Fix the "source_directories_must_exist" option to work with relative "source_directories"
paths when a "working_directory" is set.
* #906: Add documentation details for how to run custom database dump commands using binaries from
running containers:
https://torsion.org/borgmatic/docs/how-to/backup-your-databases/#containers
* Fix a regression in which the "color" option had no effect.
* Add a recent contributors section to the documentation, because credit where credit's due! See:
https://torsion.org/borgmatic/#recent-contributors
1.8.13
* #298: Add "delete" and "rdelete" actions to delete archives or entire repositories.
* #785: Add an "only_run_on" option to consistency checks so you can limit a check to running on
particular days of the week. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/deal-with-very-large-backups/#check-days
* #885: Add an Uptime Kuma monitoring hook. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#uptime-kuma-hook
* #886: Fix a PagerDuty hook traceback with Python < 3.10.
* #889: Fix the Healthchecks ping body size limit, restoring it to the documented 100,000 bytes.
1.8.12
* #817: Add a "--max-duration" flag to the "check" action and a "max_duration" option to the
repository check configuration. This tells Borg to interrupt a repository check after a certain
duration.
* #860: Fix interaction between environment variable interpolation in constants and shell escaping.
* #863: When color output is disabled (explicitly or implicitly), don't prefix each log line with
the log level.
* #865: Add an "upload_buffer_size" option to set the size of the upload buffer used in "create"
action.
* #866: Fix "Argument list too long" error in the "spot" check when checking hundreds of thousands
of files at once.
* #874: Add the configured repository label as "repository_label" to the interpolated variables
passed to before/after command hooks.
* #881: Fix "Unrecognized argument" error when the same value is used with different command-line
flags.
* In the "spot" check, don't try to hash symlinked directories.
1.8.11
* #815: Add optional Healthchecks auto-provisioning via "create_slug" option.
* #851: Fix lack of file extraction when using "extract --strip-components all" on a path with a
leading slash.
* #854: Fix a traceback when the "data" consistency check is used.
* #857: Fix a traceback with "check --only spot" when the "spot" check is unconfigured.
1.8.10
* #656 (beta): Add a "spot" consistency check that compares file counts and contents between your
source files and the latest archive, ensuring they fall within configured tolerances. This can

View File

@ -40,8 +40,10 @@ checks:
frequency: 2 weeks
# Custom preparation scripts to run.
before_backup:
- prepare-for-backup.sh
commands:
- before: action
when: [create]
run: [prepare-for-backup.sh]
# Databases to dump and include in backups.
postgresql_databases:
@ -56,19 +58,41 @@ borgmatic is powered by [Borg Backup](https://www.borgbackup.org/).
## Integrations
### Data
<a href="https://www.postgresql.org/"><img src="docs/static/postgresql.png" alt="PostgreSQL" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.mysql.com/"><img src="docs/static/mysql.png" alt="MySQL" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://mariadb.com/"><img src="docs/static/mariadb.png" alt="MariaDB" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.mongodb.com/"><img src="docs/static/mongodb.png" alt="MongoDB" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://sqlite.org/"><img src="docs/static/sqlite.png" alt="SQLite" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://openzfs.org/"><img src="docs/static/openzfs.png" alt="OpenZFS" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://btrfs.readthedocs.io/"><img src="docs/static/btrfs.png" alt="Btrfs" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://sourceware.org/lvm2/"><img src="docs/static/lvm.png" alt="LVM" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://rclone.org"><img src="docs/static/rclone.png" alt="rclone" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.borgbase.com/?utm_source=borgmatic"><img src="docs/static/borgbase.png" alt="BorgBase" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
### Monitoring
<a href="https://healthchecks.io/"><img src="docs/static/healthchecks.png" alt="Healthchecks" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://uptime.kuma.pet/"><img src="docs/static/uptimekuma.png" alt="Uptime Kuma" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://cronitor.io/"><img src="docs/static/cronitor.png" alt="Cronitor" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://cronhub.io/"><img src="docs/static/cronhub.png" alt="Cronhub" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.pagerduty.com/"><img src="docs/static/pagerduty.png" alt="PagerDuty" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.pushover.net/"><img src="docs/static/pushover.png" alt="Pushover" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://ntfy.sh/"><img src="docs/static/ntfy.png" alt="ntfy" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://grafana.com/oss/loki/"><img src="docs/static/loki.png" alt="Loki" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://github.com/caronc/apprise/wiki"><img src="docs/static/apprise.png" alt="Apprise" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.borgbase.com/?utm_source=borgmatic"><img src="docs/static/borgbase.png" alt="BorgBase" height="60px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.zabbix.com/"><img src="docs/static/zabbix.png" alt="Zabbix" height="40px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://sentry.io/"><img src="docs/static/sentry.png" alt="Sentry" height="40px" style="margin-bottom:20px; margin-right:20px;"></a>
### Credentials
<a href="https://systemd.io/"><img src="docs/static/systemd.png" alt="Sentry" height="40px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://www.docker.com/"><img src="docs/static/docker.png" alt="Docker" height="40px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://podman.io/"><img src="docs/static/podman.png" alt="Podman" height="40px" style="margin-bottom:20px; margin-right:20px;"></a>
<a href="https://keepassxc.org/"><img src="docs/static/keepassxc.png" alt="Podman" height="40px" style="margin-bottom:20px; margin-right:20px;"></a>
## Getting started
@ -154,3 +178,11 @@ general, contributions are very welcome. We don't bite!
Also, please check out the [borgmatic development
how-to](https://torsion.org/borgmatic/docs/how-to/develop-on-borgmatic/) for
info on cloning source code, running tests, etc.
### Recent contributors
Thanks to all borgmatic contributors! There are multiple ways to contribute to
this project, so the following includes those who have fixed bugs, contributed
features, *or* filed tickets.
{% include borgmatic/contributors.html %}

View File

@ -1,7 +1,7 @@
import logging
import borgmatic.borg.borg
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.validate
logger = logging.getLogger(__name__)
@ -22,10 +22,8 @@ def run_borg(
if borg_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, borg_arguments.repository
):
logger.info(
f'{repository.get("label", repository["path"])}: Running arbitrary Borg command'
)
archive_name = borgmatic.borg.rlist.resolve_archive_name(
logger.info('Running arbitrary Borg command')
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
borg_arguments.archive,
config,

View File

@ -21,9 +21,7 @@ def run_break_lock(
if break_lock_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, break_lock_arguments.repository
):
logger.info(
f'{repository.get("label", repository["path"])}: Breaking repository and cache locks'
)
logger.info('Breaking repository and cache locks')
borgmatic.borg.break_lock.break_lock(
repository['path'],
config,

View File

@ -0,0 +1,36 @@
import logging
import borgmatic.borg.change_passphrase
import borgmatic.config.validate
logger = logging.getLogger(__name__)
def run_change_passphrase(
repository,
config,
local_borg_version,
change_passphrase_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "key change-passphrase" action for the given repository.
'''
if (
change_passphrase_arguments.repository is None
or borgmatic.config.validate.repositories_match(
repository, change_passphrase_arguments.repository
)
):
logger.info('Changing repository passphrase')
borgmatic.borg.change_passphrase.change_passphrase(
repository['path'],
config,
local_borg_version,
change_passphrase_arguments,
global_arguments,
local_path=local_path,
remote_path=remote_path,
)

View File

@ -1,3 +1,4 @@
import calendar
import datetime
import hashlib
import itertools
@ -5,14 +6,17 @@ import logging
import os
import pathlib
import random
import shutil
import borgmatic.actions.pattern
import borgmatic.borg.check
import borgmatic.borg.create
import borgmatic.borg.environment
import borgmatic.borg.extract
import borgmatic.borg.list
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.borg.state
import borgmatic.config.paths
import borgmatic.config.validate
import borgmatic.execute
import borgmatic.hooks.command
@ -99,12 +103,17 @@ def parse_frequency(frequency):
raise ValueError(f"Could not parse consistency check frequency '{frequency}'")
WEEKDAY_DAYS = calendar.day_name[0:5]
WEEKEND_DAYS = calendar.day_name[5:7]
def filter_checks_on_frequency(
config,
borg_repository_id,
checks,
force,
archives_check_id=None,
datetime_now=datetime.datetime.now,
):
'''
Given a configuration dict with a "checks" sequence of dicts, a Borg repository ID, a sequence
@ -143,6 +152,29 @@ def filter_checks_on_frequency(
if checks and check not in checks:
continue
only_run_on = check_config.get('only_run_on')
if only_run_on:
# Use a dict instead of a set to preserve ordering.
days = dict.fromkeys(only_run_on)
if 'weekday' in days:
days = {
**dict.fromkeys(day for day in days if day != 'weekday'),
**dict.fromkeys(WEEKDAY_DAYS),
}
if 'weekend' in days:
days = {
**dict.fromkeys(day for day in days if day != 'weekend'),
**dict.fromkeys(WEEKEND_DAYS),
}
if calendar.day_name[datetime_now().weekday()] not in days:
logger.info(
f"Skipping {check} check due to day of the week; check only runs on {'/'.join(day.title() for day in days)} (use --force to check anyway)"
)
filtered_checks.remove(check)
continue
frequency_delta = parse_frequency(check_config.get('frequency'))
if not frequency_delta:
continue
@ -153,8 +185,8 @@ def filter_checks_on_frequency(
# If we've not yet reached the time when the frequency dictates we're ready for another
# check, skip this check.
if datetime.datetime.now() < check_time + frequency_delta:
remaining = check_time + frequency_delta - datetime.datetime.now()
if datetime_now() < check_time + frequency_delta:
remaining = check_time + frequency_delta - datetime_now()
logger.info(
f'Skipping {check} check due to configured frequency; {remaining} until next check (use --force to check anyway)'
)
@ -180,15 +212,11 @@ def make_check_time_path(config, borg_repository_id, check_type, archives_check_
"archives", etc.), and a unique hash of the archives filter flags, return a path for recording
that check's time (the time of that check last occurring).
'''
borgmatic_source_directory = os.path.expanduser(
config.get(
'borgmatic_source_directory', borgmatic.borg.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
)
)
borgmatic_state_directory = borgmatic.config.paths.get_borgmatic_state_directory(config)
if check_type in ('archives', 'data'):
return os.path.join(
borgmatic_source_directory,
borgmatic_state_directory,
'checks',
borg_repository_id,
check_type,
@ -196,7 +224,7 @@ def make_check_time_path(config, borg_repository_id, check_type, archives_check_
)
return os.path.join(
borgmatic_source_directory,
borgmatic_state_directory,
'checks',
borg_repository_id,
check_type,
@ -229,7 +257,7 @@ def read_check_time(path):
def probe_for_check_time(config, borg_repository_id, check, archives_check_id):
'''
Given a configuration dict, a Borg repository ID, the name of a check type ("repository",
"archives", etc.), and a unique hash of the archives filter flags, return a the corresponding
"archives", etc.), and a unique hash of the archives filter flags, return the corresponding
check time or None if such a check time does not exist.
When the check type is "archives" or "data", this function probes two different paths to find
@ -267,14 +295,37 @@ def upgrade_check_times(config, borg_repository_id):
Given a configuration dict and a Borg repository ID, upgrade any corresponding check times on
disk from old-style paths to new-style paths.
Currently, the only upgrade performed is renaming an archive or data check path that looks like:
One upgrade performed is moving the checks directory from:
~/.borgmatic/checks/1234567890/archives
{borgmatic_source_directory}/checks (e.g., ~/.borgmatic/checks)
to:
~/.borgmatic/checks/1234567890/archives/all
{borgmatic_state_directory}/checks (e.g. ~/.local/state/borgmatic)
Another upgrade is renaming an archive or data check path that looks like:
{borgmatic_state_directory}/checks/1234567890/archives
to:
{borgmatic_state_directory}/checks/1234567890/archives/all
'''
borgmatic_source_checks_path = os.path.join(
borgmatic.config.paths.get_borgmatic_source_directory(config), 'checks'
)
borgmatic_state_path = borgmatic.config.paths.get_borgmatic_state_directory(config)
borgmatic_state_checks_path = os.path.join(borgmatic_state_path, 'checks')
if os.path.exists(borgmatic_source_checks_path) and not os.path.exists(
borgmatic_state_checks_path
):
logger.debug(
f'Upgrading archives check times directory from {borgmatic_source_checks_path} to {borgmatic_state_checks_path}'
)
os.makedirs(borgmatic_state_path, mode=0o700, exist_ok=True)
shutil.move(borgmatic_source_checks_path, borgmatic_state_checks_path)
for check_type in ('archives', 'data'):
new_path = make_check_time_path(config, borg_repository_id, check_type, 'all')
old_path = os.path.dirname(new_path)
@ -283,92 +334,103 @@ def upgrade_check_times(config, borg_repository_id):
if not os.path.isfile(old_path) and not os.path.isfile(temporary_path):
continue
logger.debug(f'Upgrading archives check time from {old_path} to {new_path}')
logger.debug(f'Upgrading archives check time file from {old_path} to {new_path}')
try:
os.rename(old_path, temporary_path)
shutil.move(old_path, temporary_path)
except FileNotFoundError:
pass
os.mkdir(old_path)
os.rename(temporary_path, new_path)
shutil.move(temporary_path, new_path)
def collect_spot_check_source_paths(
repository, config, local_borg_version, global_arguments, local_path, remote_path
repository,
config,
local_borg_version,
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
):
'''
Given a repository configuration dict, a configuration dict, the local Borg version, global
arguments as an argparse.Namespace instance, the local Borg path, and the remote Borg path,
collect the source paths that Borg would use in an actual create (but only include files and
symlinks).
collect the source paths that Borg would use in an actual create (but only include files).
'''
stream_processes = any(
borgmatic.hooks.dispatch.call_hooks(
'use_streaming',
config,
repository['path'],
borgmatic.hooks.dump.DATA_SOURCE_HOOK_NAMES,
borgmatic.hooks.dispatch.Hook_type.DATA_SOURCE,
).values()
)
working_directory = borgmatic.config.paths.get_working_directory(config)
(create_flags, create_positional_arguments, pattern_file, exclude_file) = (
(create_flags, create_positional_arguments, pattern_file) = (
borgmatic.borg.create.make_base_create_command(
dry_run=True,
repository_path=repository['path'],
config=config,
config_paths=(),
config=dict(config, list_details=True),
patterns=borgmatic.actions.pattern.process_patterns(
borgmatic.actions.pattern.collect_patterns(config),
working_directory,
),
local_borg_version=local_borg_version,
global_arguments=global_arguments,
borgmatic_source_directories=(),
borgmatic_runtime_directory=borgmatic_runtime_directory,
local_path=local_path,
remote_path=remote_path,
list_files=True,
stream_processes=stream_processes,
)
)
borg_environment = borgmatic.borg.environment.make_environment(config)
try:
working_directory = os.path.expanduser(config.get('working_directory'))
except TypeError:
working_directory = None
working_directory = borgmatic.config.paths.get_working_directory(config)
paths_output = borgmatic.execute.execute_command_and_capture_output(
create_flags + create_positional_arguments,
capture_stderr=True,
environment=borgmatic.borg.environment.make_environment(config),
working_directory=working_directory,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
paths = tuple(
path_line.split(' ', 1)[1]
for path_line in paths_output.split('\n')
for path_line in paths_output.splitlines()
if path_line and path_line.startswith('- ') or path_line.startswith('+ ')
)
return tuple(path for path in paths if os.path.isfile(path) or os.path.islink(path))
return tuple(
path for path in paths if os.path.isfile(os.path.join(working_directory or '', path))
)
BORG_DIRECTORY_FILE_TYPE = 'd'
BORG_PIPE_FILE_TYPE = 'p'
def collect_spot_check_archive_paths(
repository, archive, config, local_borg_version, global_arguments, local_path, remote_path
repository,
archive,
config,
local_borg_version,
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
):
'''
Given a repository configuration dict, the name of the latest archive, a configuration dict, the
local Borg version, global arguments as an argparse.Namespace instance, the local Borg path, and
the remote Borg path, collect the paths from the given archive (but only include files and
symlinks).
local Borg version, global arguments as an argparse.Namespace instance, the local Borg path, the
remote Borg path, and the borgmatic runtime directory, collect the paths from the given archive
(but only include files and symlinks and exclude borgmatic runtime directories).
These paths do not have a leading slash, as that's how Borg stores them. As a result, we don't
know whether they came from absolute or relative source directories.
'''
borgmatic_source_directory = os.path.expanduser(
config.get(
'borgmatic_source_directory', borgmatic.borg.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
)
)
borgmatic_source_directory = borgmatic.config.paths.get_borgmatic_source_directory(config)
return tuple(
path
@ -378,16 +440,23 @@ def collect_spot_check_archive_paths(
config,
local_borg_version,
global_arguments,
path_format='{type} /{path}{NL}', # noqa: FS003
path_format='{type} {path}{NUL}', # noqa: FS003
local_path=local_path,
remote_path=remote_path,
)
for (file_type, path) in (line.split(' ', 1),)
if file_type != BORG_DIRECTORY_FILE_TYPE
if pathlib.Path(borgmatic_source_directory) not in pathlib.Path(path).parents
if file_type not in (BORG_DIRECTORY_FILE_TYPE, BORG_PIPE_FILE_TYPE)
if pathlib.Path('borgmatic') not in pathlib.Path(path).parents
if pathlib.Path(borgmatic_source_directory.lstrip(os.path.sep))
not in pathlib.Path(path).parents
if pathlib.Path(borgmatic_runtime_directory.lstrip(os.path.sep))
not in pathlib.Path(path).parents
)
SAMPLE_PATHS_SUBSET_COUNT = 10000
def compare_spot_check_hashes(
repository,
archive,
@ -396,15 +465,14 @@ def compare_spot_check_hashes(
global_arguments,
local_path,
remote_path,
log_label,
source_paths,
):
'''
Given a repository configuration dict, the name of the latest archive, a configuration dict, the
local Borg version, global arguments as an argparse.Namespace instance, the local Borg path, the
remote Borg path, a log label, and spot check source paths, compare the hashes for a sampling of
the source paths with hashes from corresponding paths in the given archive. Return a sequence of
the paths that fail that hash comparison.
remote Borg path, and spot check source paths, compare the hashes for a sampling of the source
paths with hashes from corresponding paths in the given archive. Return a sequence of the paths
that fail that hash comparison.
'''
# Based on the configured sample percentage, come up with a list of random sample files from the
# source directories.
@ -413,45 +481,78 @@ def compare_spot_check_hashes(
int(len(source_paths) * (min(spot_check_config['data_sample_percentage'], 100) / 100)), 1
)
source_sample_paths = tuple(random.sample(source_paths, sample_count))
existing_source_sample_paths = {
source_path for source_path in source_sample_paths if os.path.exists(source_path)
working_directory = borgmatic.config.paths.get_working_directory(config)
hashable_source_sample_path = {
source_path
for source_path in source_sample_paths
for full_source_path in (os.path.join(working_directory or '', source_path),)
if os.path.exists(full_source_path)
if not os.path.islink(full_source_path)
}
logger.debug(
f'{log_label}: Sampling {sample_count} source paths (~{spot_check_config["data_sample_percentage"]}%) for spot check'
f'Sampling {sample_count} source paths (~{spot_check_config["data_sample_percentage"]}%) for spot check'
)
# Hash each file in the sample paths (if it exists).
hash_output = borgmatic.execute.execute_command_and_capture_output(
(spot_check_config.get('xxh64sum_command', 'xxh64sum'),)
+ tuple(path for path in source_sample_paths if path in existing_source_sample_paths)
)
source_sample_paths_iterator = iter(source_sample_paths)
source_hashes = {}
archive_hashes = {}
source_hashes = dict(
(reversed(line.split(' ', 1)) for line in hash_output.splitlines()),
**{path: '' for path in source_sample_paths if path not in existing_source_sample_paths},
)
archive_hashes = dict(
reversed(line.split(' ', 1))
for line in borgmatic.borg.list.capture_archive_listing(
repository['path'],
archive,
config,
local_borg_version,
global_arguments,
list_paths=source_sample_paths,
path_format='{xxh64} /{path}{NL}', # noqa: FS003
local_path=local_path,
remote_path=remote_path,
# Only hash a few thousand files at a time (a subset of the total paths) to avoid an "Argument
# list too long" shell error.
while True:
# Hash each file in the sample paths (if it exists).
source_sample_paths_subset = tuple(
itertools.islice(source_sample_paths_iterator, SAMPLE_PATHS_SUBSET_COUNT)
)
if not source_sample_paths_subset:
break
hash_output = borgmatic.execute.execute_command_and_capture_output(
(spot_check_config.get('xxh64sum_command', 'xxh64sum'),)
+ tuple(
path for path in source_sample_paths_subset if path in hashable_source_sample_path
),
working_directory=working_directory,
)
source_hashes.update(
**dict(
(reversed(line.split(' ', 1)) for line in hash_output.splitlines()),
# Represent non-existent files as having empty hashes so the comparison below still
# works. Same thing for filesystem links, since Borg produces empty archive hashes
# for them.
**{
path: ''
for path in source_sample_paths_subset
if path not in hashable_source_sample_path
},
)
)
# Get the hash for each file in the archive.
archive_hashes.update(
**dict(
reversed(line.split(' ', 1))
for line in borgmatic.borg.list.capture_archive_listing(
repository['path'],
archive,
config,
local_borg_version,
global_arguments,
list_paths=source_sample_paths_subset,
path_format='{xxh64} {path}{NUL}', # noqa: FS003
local_path=local_path,
remote_path=remote_path,
)
if line
)
)
if line
)
# Compare the source hashes with the archive hashes to see how many match.
failing_paths = []
for path, source_hash in source_hashes.items():
archive_hash = archive_hashes.get(path)
archive_hash = archive_hashes.get(path.lstrip(os.path.sep))
if archive_hash is not None and archive_hash == source_hash:
continue
@ -468,19 +569,25 @@ def spot_check(
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
):
'''
Given a repository dict, a loaded configuration dict, the local Borg version, global arguments
as an argparse.Namespace instance, the local Borg path, and the remote Borg path, perform a spot
check for the latest archive in the given repository.
as an argparse.Namespace instance, the local Borg path, the remote Borg path, and the borgmatic
runtime directory, perform a spot check for the latest archive in the given repository.
A spot check compares file counts and also the hashes for a random sampling of source files on
disk to those stored in the latest archive. If any differences are beyond configured tolerances,
then the check fails.
'''
log_label = f'{repository.get("label", repository["path"])}'
logger.debug(f'{log_label}: Running spot check')
spot_check_config = next(check for check in config['checks'] if check['name'] == 'spot')
logger.debug('Running spot check')
try:
spot_check_config = next(
check for check in config.get('checks', ()) if check.get('name') == 'spot'
)
except StopIteration:
raise ValueError('Cannot run spot check because it is unconfigured')
if spot_check_config['data_tolerance_percentage'] > spot_check_config['data_sample_percentage']:
raise ValueError(
@ -494,10 +601,11 @@ def spot_check(
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
)
logger.debug(f'{log_label}: {len(source_paths)} total source paths for spot check')
logger.debug(f'{len(source_paths)} total source paths for spot check')
archive = borgmatic.borg.rlist.resolve_archive_name(
archive = borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
'latest',
config,
@ -506,7 +614,7 @@ def spot_check(
local_path,
remote_path,
)
logger.debug(f'{log_label}: Using archive {archive} for spot check')
logger.debug(f'Using archive {archive} for spot check')
archive_paths = collect_spot_check_archive_paths(
repository,
@ -516,19 +624,29 @@ def spot_check(
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
)
logger.debug(f'{log_label}: {len(archive_paths)} total archive paths for spot check')
logger.debug(f'{len(archive_paths)} total archive paths for spot check')
if len(source_paths) == 0:
logger.debug(
f'Paths in latest archive but not source paths: {", ".join(set(archive_paths)) or "none"}'
)
raise ValueError(
'Spot check failed: There are no source paths to compare against the archive'
)
# Calculate the percentage delta between the source paths count and the archive paths count, and
# compare that delta to the configured count tolerance percentage.
count_delta_percentage = abs(len(source_paths) - len(archive_paths)) / len(source_paths) * 100
if count_delta_percentage > spot_check_config['count_tolerance_percentage']:
rootless_source_paths = set(path.lstrip(os.path.sep) for path in source_paths)
logger.debug(
f'{log_label}: Paths in source paths but not latest archive: {", ".join(set(source_paths) - set(archive_paths)) or "none"}'
f'Paths in source paths but not latest archive: {", ".join(rootless_source_paths - set(archive_paths)) or "none"}'
)
logger.debug(
f'{log_label}: Paths in latest archive but not source paths: {", ".join(set(archive_paths) - set(source_paths)) or "none"}'
f'Paths in latest archive but not source paths: {", ".join(set(archive_paths) - rootless_source_paths) or "none"}'
)
raise ValueError(
f'Spot check failed: {count_delta_percentage:.2f}% file count delta between source paths and latest archive (tolerance is {spot_check_config["count_tolerance_percentage"]}%)'
@ -542,25 +660,24 @@ def spot_check(
global_arguments,
local_path,
remote_path,
log_label,
source_paths,
)
# Error if the percentage of failing hashes exceeds the configured tolerance percentage.
logger.debug(f'{log_label}: {len(failing_paths)} non-matching spot check hashes')
logger.debug(f'{len(failing_paths)} non-matching spot check hashes')
data_tolerance_percentage = spot_check_config['data_tolerance_percentage']
failing_percentage = (len(failing_paths) / len(source_paths)) * 100
if failing_percentage > data_tolerance_percentage:
logger.debug(
f'{log_label}: Source paths with data not matching the latest archive: {", ".join(failing_paths)}'
f'Source paths with data not matching the latest archive: {", ".join(failing_paths)}'
)
raise ValueError(
f'Spot check failed: {failing_percentage:.2f}% of source paths with data not matching the latest archive (tolerance is {data_tolerance_percentage}%)'
)
logger.info(
f'{log_label}: Spot check passed with a {count_delta_percentage:.2f}% file count delta and a {failing_percentage:.2f}% file data delta'
f'Spot check passed with a {count_delta_percentage:.2f}% file count delta and a {failing_percentage:.2f}% file data delta'
)
@ -568,7 +685,6 @@ def run_check(
config_filename,
repository,
config,
hook_context,
local_borg_version,
check_arguments,
global_arguments,
@ -585,16 +701,8 @@ def run_check(
):
return
borgmatic.hooks.command.execute_hook(
config.get('before_check'),
config.get('umask'),
config_filename,
'pre-check',
global_arguments.dry_run,
**hook_context,
)
logger.info('Running consistency checks')
logger.info(f'{repository.get("label", repository["path"])}: Running consistency checks')
repository_id = borgmatic.borg.check.get_repository_id(
repository['path'],
config,
@ -646,21 +754,14 @@ def run_check(
write_check_time(make_check_time_path(config, repository_id, 'extract'))
if 'spot' in checks:
spot_check(
repository,
config,
local_borg_version,
global_arguments,
local_path,
remote_path,
)
with borgmatic.config.paths.Runtime_directory(config) as borgmatic_runtime_directory:
spot_check(
repository,
config,
local_borg_version,
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
)
write_check_time(make_check_time_path(config, repository_id, 'spot'))
borgmatic.hooks.command.execute_hook(
config.get('after_check'),
config.get('umask'),
config_filename,
'post-check',
global_arguments.dry_run,
**hook_context,
)

View File

@ -12,7 +12,6 @@ def run_compact(
config_filename,
repository,
config,
hook_context,
local_borg_version,
compact_arguments,
global_arguments,
@ -28,18 +27,8 @@ def run_compact(
):
return
borgmatic.hooks.command.execute_hook(
config.get('before_compact'),
config.get('umask'),
config_filename,
'pre-compact',
global_arguments.dry_run,
**hook_context,
)
if borgmatic.borg.feature.available(borgmatic.borg.feature.Feature.COMPACT, local_borg_version):
logger.info(
f'{repository.get("label", repository["path"])}: Compacting segments{dry_run_label}'
)
logger.info(f'Compacting segments{dry_run_label}')
borgmatic.borg.compact.compact_segments(
global_arguments.dry_run,
repository['path'],
@ -48,19 +37,7 @@ def run_compact(
global_arguments,
local_path=local_path,
remote_path=remote_path,
progress=compact_arguments.progress,
cleanup_commits=compact_arguments.cleanup_commits,
threshold=compact_arguments.threshold,
)
else: # pragma: nocover
logger.info(
f'{repository.get("label", repository["path"])}: Skipping compact (only available/needed in Borg 1.2+)'
)
borgmatic.hooks.command.execute_hook(
config.get('after_compact'),
config.get('umask'),
config_filename,
'post-compact',
global_arguments.dry_run,
**hook_context,
)
logger.info('Skipping compact (only available/needed in Borg 1.2+)')

View File

@ -3,55 +3,78 @@ import logging
import os
import borgmatic.borg.extract
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.paths
import borgmatic.config.validate
import borgmatic.hooks.command
from borgmatic.borg.state import DEFAULT_BORGMATIC_SOURCE_DIRECTORY
logger = logging.getLogger(__name__)
def get_config_paths(bootstrap_arguments, global_arguments, local_borg_version):
def make_bootstrap_config(bootstrap_arguments):
'''
Given the bootstrap arguments as an argparse.Namespace (containing the repository and archive
name, borgmatic source directory, destination directory, and whether to strip components), the
global arguments as an argparse.Namespace (containing the dry run flag and the local borg
version), return the config paths from the manifest.json file in the borgmatic source directory
after extracting it from the repository.
Given the bootstrap arguments as an argparse.Namespace, return a corresponding config dict.
'''
return {
'ssh_command': bootstrap_arguments.ssh_command,
# In case the repo has been moved or is accessed from a different path at the point of
# bootstrapping.
'relocated_repo_access_is_ok': True,
}
def get_config_paths(archive_name, bootstrap_arguments, global_arguments, local_borg_version):
'''
Given an archive name, the bootstrap arguments as an argparse.Namespace (containing the
repository and archive name, Borg local path, Borg remote path, borgmatic runtime directory,
borgmatic source directory, destination directory, and whether to strip components), the global
arguments as an argparse.Namespace (containing the dry run flag and the local borg version),
return the config paths from the manifest.json file in the borgmatic source directory or runtime
directory after extracting it from the repository archive.
Raise ValueError if the manifest JSON is missing, can't be decoded, or doesn't contain the
expected configuration path data.
'''
borgmatic_source_directory = (
bootstrap_arguments.borgmatic_source_directory or DEFAULT_BORGMATIC_SOURCE_DIRECTORY
borgmatic_source_directory = borgmatic.config.paths.get_borgmatic_source_directory(
{'borgmatic_source_directory': bootstrap_arguments.borgmatic_source_directory}
)
borgmatic_manifest_path = os.path.expanduser(
os.path.join(borgmatic_source_directory, 'bootstrap', 'manifest.json')
)
config = {'ssh_command': bootstrap_arguments.ssh_command}
config = make_bootstrap_config(bootstrap_arguments)
extract_process = borgmatic.borg.extract.extract_archive(
global_arguments.dry_run,
bootstrap_arguments.repository,
borgmatic.borg.rlist.resolve_archive_name(
bootstrap_arguments.repository,
bootstrap_arguments.archive,
config,
local_borg_version,
global_arguments,
),
[borgmatic_manifest_path],
config,
local_borg_version,
global_arguments,
extract_to_stdout=True,
)
manifest_json = extract_process.stdout.read()
# Probe for the manifest file in multiple locations, as the default location has moved to the
# borgmatic runtime directory (which gets stored as just "/borgmatic" with Borg 1.4+). But we
# still want to support reading the manifest from previously created archives as well.
with borgmatic.config.paths.Runtime_directory(
{'user_runtime_directory': bootstrap_arguments.user_runtime_directory},
) as borgmatic_runtime_directory:
for base_directory in (
'borgmatic',
borgmatic.config.paths.make_runtime_directory_glob(borgmatic_runtime_directory),
borgmatic_source_directory,
):
borgmatic_manifest_path = 'sh:' + os.path.join(
base_directory, 'bootstrap', 'manifest.json'
)
if not manifest_json:
raise ValueError(
'Cannot read configuration paths from archive due to missing bootstrap manifest'
)
extract_process = borgmatic.borg.extract.extract_archive(
global_arguments.dry_run,
bootstrap_arguments.repository,
archive_name,
[borgmatic_manifest_path],
config,
local_borg_version,
global_arguments,
local_path=bootstrap_arguments.local_path,
remote_path=bootstrap_arguments.remote_path,
extract_to_stdout=True,
)
manifest_json = extract_process.stdout.read()
if manifest_json:
break
else:
raise ValueError(
'Cannot read configuration paths from archive due to missing bootstrap manifest'
)
try:
manifest_data = json.loads(manifest_json)
@ -75,29 +98,35 @@ def run_bootstrap(bootstrap_arguments, global_arguments, local_borg_version):
Raise ValueError if the bootstrap configuration could not be loaded.
Raise CalledProcessError or OSError if Borg could not be run.
'''
manifest_config_paths = get_config_paths(
bootstrap_arguments, global_arguments, local_borg_version
config = make_bootstrap_config(bootstrap_arguments)
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
bootstrap_arguments.repository,
bootstrap_arguments.archive,
config,
local_borg_version,
global_arguments,
local_path=bootstrap_arguments.local_path,
remote_path=bootstrap_arguments.remote_path,
)
manifest_config_paths = get_config_paths(
archive_name, bootstrap_arguments, global_arguments, local_borg_version
)
config = {'ssh_command': bootstrap_arguments.ssh_command}
logger.info(f"Bootstrapping config paths: {', '.join(manifest_config_paths)}")
borgmatic.borg.extract.extract_archive(
global_arguments.dry_run,
bootstrap_arguments.repository,
borgmatic.borg.rlist.resolve_archive_name(
bootstrap_arguments.repository,
bootstrap_arguments.archive,
config,
local_borg_version,
global_arguments,
),
archive_name,
[config_path.lstrip(os.path.sep) for config_path in manifest_config_paths],
config,
# Only add progress here and not the extract_archive() call above, because progress
# conflicts with extract_to_stdout.
dict(config, progress=bootstrap_arguments.progress or False),
local_borg_version,
global_arguments,
local_path=bootstrap_arguments.local_path,
remote_path=bootstrap_arguments.remote_path,
extract_to_stdout=False,
destination_path=bootstrap_arguments.destination,
strip_components=bootstrap_arguments.strip_components,
progress=bootstrap_arguments.progress,
)

View File

@ -1,54 +1,20 @@
import importlib.metadata
import json
import logging
import os
import borgmatic.actions.json
import borgmatic.borg.create
import borgmatic.borg.state
import borgmatic.config.paths
import borgmatic.config.validate
import borgmatic.hooks.command
import borgmatic.hooks.dispatch
import borgmatic.hooks.dump
from borgmatic.actions import pattern
logger = logging.getLogger(__name__)
def create_borgmatic_manifest(config, config_paths, dry_run):
'''
Create a borgmatic manifest file to store the paths to the configuration files used to create
the archive.
'''
if dry_run:
return
borgmatic_source_directory = config.get(
'borgmatic_source_directory', borgmatic.borg.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
)
borgmatic_manifest_path = os.path.expanduser(
os.path.join(borgmatic_source_directory, 'bootstrap', 'manifest.json')
)
if not os.path.exists(borgmatic_manifest_path):
os.makedirs(os.path.dirname(borgmatic_manifest_path), exist_ok=True)
with open(borgmatic_manifest_path, 'w') as config_list_file:
json.dump(
{
'borgmatic_version': importlib.metadata.version('borgmatic'),
'config_paths': config_paths,
},
config_list_file,
)
def run_create(
config_filename,
repository,
config,
config_paths,
hook_context,
local_borg_version,
create_arguments,
global_arguments,
@ -66,67 +32,67 @@ def run_create(
):
return
borgmatic.hooks.command.execute_hook(
config.get('before_backup'),
config.get('umask'),
config_filename,
'pre-backup',
global_arguments.dry_run,
**hook_context,
)
logger.info(f'{repository.get("label", repository["path"])}: Creating archive{dry_run_label}')
borgmatic.hooks.dispatch.call_hooks_even_if_unconfigured(
'remove_data_source_dumps',
config,
repository['path'],
borgmatic.hooks.dump.DATA_SOURCE_HOOK_NAMES,
global_arguments.dry_run,
)
active_dumps = borgmatic.hooks.dispatch.call_hooks(
'dump_data_sources',
config,
repository['path'],
borgmatic.hooks.dump.DATA_SOURCE_HOOK_NAMES,
global_arguments.dry_run,
)
if config.get('store_config_files', True):
create_borgmatic_manifest(
if config.get('list_details') and config.get('progress'):
raise ValueError(
'With the create action, only one of --list/--files/list_details and --progress/progress can be used.'
)
if config.get('list_details') and create_arguments.json:
raise ValueError(
'With the create action, only one of --list/--files/list_details and --json can be used.'
)
logger.info(f'Creating archive{dry_run_label}')
working_directory = borgmatic.config.paths.get_working_directory(config)
with borgmatic.config.paths.Runtime_directory(config) as borgmatic_runtime_directory:
borgmatic.hooks.dispatch.call_hooks_even_if_unconfigured(
'remove_data_source_dumps',
config,
config_paths,
borgmatic.hooks.dispatch.Hook_type.DATA_SOURCE,
borgmatic_runtime_directory,
global_arguments.dry_run,
)
patterns = pattern.process_patterns(pattern.collect_patterns(config), working_directory)
active_dumps = borgmatic.hooks.dispatch.call_hooks(
'dump_data_sources',
config,
borgmatic.hooks.dispatch.Hook_type.DATA_SOURCE,
config_paths,
borgmatic_runtime_directory,
patterns,
global_arguments.dry_run,
)
stream_processes = [process for processes in active_dumps.values() for process in processes]
json_output = borgmatic.borg.create.create_archive(
global_arguments.dry_run,
repository['path'],
config,
config_paths,
local_borg_version,
global_arguments,
local_path=local_path,
remote_path=remote_path,
progress=create_arguments.progress,
stats=create_arguments.stats,
json=create_arguments.json,
list_files=create_arguments.list_files,
stream_processes=stream_processes,
)
if json_output:
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
# Process the patterns again in case any data source hooks updated them. Without this step,
# we could end up with duplicate paths that cause Borg to hang when it tries to read from
# the same named pipe twice.
patterns = pattern.process_patterns(
patterns, working_directory, skip_expand_paths=config_paths
)
stream_processes = [process for processes in active_dumps.values() for process in processes]
borgmatic.hooks.dispatch.call_hooks_even_if_unconfigured(
'remove_data_source_dumps',
config,
config_filename,
borgmatic.hooks.dump.DATA_SOURCE_HOOK_NAMES,
global_arguments.dry_run,
)
borgmatic.hooks.command.execute_hook(
config.get('after_backup'),
config.get('umask'),
config_filename,
'post-backup',
global_arguments.dry_run,
**hook_context,
)
json_output = borgmatic.borg.create.create_archive(
global_arguments.dry_run,
repository['path'],
config,
patterns,
local_borg_version,
global_arguments,
borgmatic_runtime_directory,
local_path=local_path,
remote_path=remote_path,
json=create_arguments.json,
stream_processes=stream_processes,
)
if json_output:
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))
borgmatic.hooks.dispatch.call_hooks_even_if_unconfigured(
'remove_data_source_dumps',
config,
borgmatic.hooks.dispatch.Hook_type.DATA_SOURCE,
borgmatic_runtime_directory,
global_arguments.dry_run,
)

View File

@ -0,0 +1,50 @@
import logging
import borgmatic.actions.arguments
import borgmatic.borg.delete
import borgmatic.borg.repo_delete
import borgmatic.borg.repo_list
logger = logging.getLogger(__name__)
def run_delete(
repository,
config,
local_borg_version,
delete_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "delete" action for the given repository and archive(s).
'''
if delete_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, delete_arguments.repository
):
logger.answer('Deleting archives')
archive_name = (
borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
delete_arguments.archive,
config,
local_borg_version,
global_arguments,
local_path,
remote_path,
)
if delete_arguments.archive
else None
)
borgmatic.borg.delete.delete_archives(
repository,
config,
local_borg_version,
borgmatic.actions.arguments.update_arguments(delete_arguments, archive=archive_name),
global_arguments,
local_path,
remote_path,
)

View File

@ -21,7 +21,7 @@ def run_export_key(
if export_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, export_arguments.repository
):
logger.info(f'{repository.get("label", repository["path"])}: Exporting repository key')
logger.info('Exporting repository key')
borgmatic.borg.export_key.export_key(
repository['path'],
config,

View File

@ -1,7 +1,7 @@
import logging
import borgmatic.borg.export_tar
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.validate
logger = logging.getLogger(__name__)
@ -22,13 +22,11 @@ def run_export_tar(
if export_tar_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, export_tar_arguments.repository
):
logger.info(
f'{repository["path"]}: Exporting archive {export_tar_arguments.archive} as tar file'
)
logger.info(f'Exporting archive {export_tar_arguments.archive} as tar file')
borgmatic.borg.export_tar.export_tar_archive(
global_arguments.dry_run,
repository['path'],
borgmatic.borg.rlist.resolve_archive_name(
borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
export_tar_arguments.archive,
config,
@ -45,6 +43,5 @@ def run_export_tar(
local_path=local_path,
remote_path=remote_path,
tar_filter=export_tar_arguments.tar_filter,
list_files=export_tar_arguments.list_files,
strip_components=export_tar_arguments.strip_components,
)

View File

@ -1,7 +1,7 @@
import logging
import borgmatic.borg.extract
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.validate
import borgmatic.hooks.command
@ -12,7 +12,6 @@ def run_extract(
config_filename,
repository,
config,
hook_context,
local_borg_version,
extract_arguments,
global_arguments,
@ -22,24 +21,14 @@ def run_extract(
'''
Run the "extract" action for the given repository.
'''
borgmatic.hooks.command.execute_hook(
config.get('before_extract'),
config.get('umask'),
config_filename,
'pre-extract',
global_arguments.dry_run,
**hook_context,
)
if extract_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, extract_arguments.repository
):
logger.info(
f'{repository.get("label", repository["path"])}: Extracting archive {extract_arguments.archive}'
)
logger.info(f'Extracting archive {extract_arguments.archive}')
borgmatic.borg.extract.extract_archive(
global_arguments.dry_run,
repository['path'],
borgmatic.borg.rlist.resolve_archive_name(
borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
extract_arguments.archive,
config,
@ -56,13 +45,4 @@ def run_extract(
remote_path=remote_path,
destination_path=extract_arguments.destination,
strip_components=extract_arguments.strip_components,
progress=extract_arguments.progress,
)
borgmatic.hooks.command.execute_hook(
config.get('after_extract'),
config.get('umask'),
config_filename,
'post-extract',
global_arguments.dry_run,
**hook_context,
)

View File

@ -0,0 +1,33 @@
import logging
import borgmatic.borg.import_key
import borgmatic.config.validate
logger = logging.getLogger(__name__)
def run_import_key(
repository,
config,
local_borg_version,
import_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "key import" action for the given repository.
'''
if import_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, import_arguments.repository
):
logger.info('Importing repository key')
borgmatic.borg.import_key.import_key(
repository['path'],
config,
local_borg_version,
import_arguments,
global_arguments,
local_path=local_path,
remote_path=remote_path,
)

View File

@ -3,7 +3,7 @@ import logging
import borgmatic.actions.arguments
import borgmatic.actions.json
import borgmatic.borg.info
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.validate
logger = logging.getLogger(__name__)
@ -27,10 +27,8 @@ def run_info(
repository, info_arguments.repository
):
if not info_arguments.json:
logger.answer(
f'{repository.get("label", repository["path"])}: Displaying archive summary information'
)
archive_name = borgmatic.borg.rlist.resolve_archive_name(
logger.answer('Displaying archive summary information')
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
info_arguments.archive,
config,

View File

@ -27,11 +27,11 @@ def run_list(
):
if not list_arguments.json:
if list_arguments.find_paths: # pragma: no cover
logger.answer(f'{repository.get("label", repository["path"])}: Searching archives')
logger.answer('Searching archives')
elif not list_arguments.archive: # pragma: no cover
logger.answer(f'{repository.get("label", repository["path"])}: Listing archives')
logger.answer('Listing archives')
archive_name = borgmatic.borg.rlist.resolve_archive_name(
archive_name = borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
list_arguments.archive,
config,

View File

@ -1,7 +1,7 @@
import logging
import borgmatic.borg.mount
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.validate
logger = logging.getLogger(__name__)
@ -23,15 +23,13 @@ def run_mount(
repository, mount_arguments.repository
):
if mount_arguments.archive:
logger.info(
f'{repository.get("label", repository["path"])}: Mounting archive {mount_arguments.archive}'
)
logger.info(f'Mounting archive {mount_arguments.archive}')
else: # pragma: nocover
logger.info(f'{repository.get("label", repository["path"])}: Mounting repository')
logger.info('Mounting repository')
borgmatic.borg.mount.mount_archive(
repository['path'],
borgmatic.borg.rlist.resolve_archive_name(
borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
mount_arguments.archive,
config,

View File

@ -0,0 +1,292 @@
import glob
import itertools
import logging
import os
import pathlib
import borgmatic.borg.pattern
logger = logging.getLogger(__name__)
def parse_pattern(pattern_line, default_style=borgmatic.borg.pattern.Pattern_style.NONE):
'''
Given a Borg pattern as a string, parse it into a borgmatic.borg.pattern.Pattern instance and
return it.
'''
try:
(pattern_type, remainder) = pattern_line.split(' ', maxsplit=1)
except ValueError:
raise ValueError(f'Invalid pattern: {pattern_line}')
try:
(parsed_pattern_style, path) = remainder.split(':', maxsplit=1)
pattern_style = borgmatic.borg.pattern.Pattern_style(parsed_pattern_style)
except ValueError:
pattern_style = default_style
path = remainder
return borgmatic.borg.pattern.Pattern(
path,
borgmatic.borg.pattern.Pattern_type(pattern_type),
borgmatic.borg.pattern.Pattern_style(pattern_style),
source=borgmatic.borg.pattern.Pattern_source.CONFIG,
)
def collect_patterns(config):
'''
Given a configuration dict, produce a single sequence of patterns comprised of the configured
source directories, patterns, excludes, pattern files, and exclude files.
The idea is that Borg has all these different ways of specifying includes, excludes, source
directories, etc., but we'd like to collapse them all down to one common format (patterns) for
ease of manipulation within borgmatic.
'''
try:
return (
tuple(
borgmatic.borg.pattern.Pattern(
source_directory, source=borgmatic.borg.pattern.Pattern_source.CONFIG
)
for source_directory in config.get('source_directories', ())
)
+ tuple(
parse_pattern(pattern_line.strip())
for pattern_line in config.get('patterns', ())
if not pattern_line.lstrip().startswith('#')
if pattern_line.strip()
)
+ tuple(
parse_pattern(
f'{borgmatic.borg.pattern.Pattern_type.NO_RECURSE.value} {exclude_line.strip()}',
borgmatic.borg.pattern.Pattern_style.FNMATCH,
)
for exclude_line in config.get('exclude_patterns', ())
)
+ tuple(
parse_pattern(pattern_line.strip())
for filename in config.get('patterns_from', ())
for pattern_line in open(filename).readlines()
if not pattern_line.lstrip().startswith('#')
if pattern_line.strip()
)
+ tuple(
parse_pattern(
f'{borgmatic.borg.pattern.Pattern_type.NO_RECURSE.value} {exclude_line.strip()}',
borgmatic.borg.pattern.Pattern_style.FNMATCH,
)
for filename in config.get('exclude_from', ())
for exclude_line in open(filename).readlines()
if not exclude_line.lstrip().startswith('#')
if exclude_line.strip()
)
)
except (FileNotFoundError, OSError) as error:
logger.debug(error)
raise ValueError(f'Cannot read patterns_from/exclude_from file: {error.filename}')
def expand_directory(directory, working_directory):
'''
Given a directory path, expand any tilde (representing a user's home directory) and any globs
therein. Return a list of one or more resulting paths.
Take into account the given working directory so that relative paths are supported.
'''
expanded_directory = os.path.expanduser(directory)
# This would be a lot easier to do with glob(..., root_dir=working_directory), but root_dir is
# only available in Python 3.10+.
normalized_directory = os.path.join(working_directory or '', expanded_directory)
glob_paths = glob.glob(normalized_directory)
if not glob_paths:
return [expanded_directory]
working_directory_prefix = os.path.join(working_directory or '', '')
return [
(
glob_path
# If these are equal, that means we didn't add any working directory prefix above.
if normalized_directory == expanded_directory
# Remove the working directory prefix that we added above in order to make glob() work.
# We can't use os.path.relpath() here because it collapses any use of Borg's slashdot
# hack.
else glob_path.removeprefix(working_directory_prefix)
)
for glob_path in glob_paths
]
def expand_patterns(patterns, working_directory=None, skip_paths=None):
'''
Given a sequence of borgmatic.borg.pattern.Pattern instances and an optional working directory,
expand tildes and globs in each root pattern and expand just tildes in each non-root pattern.
The idea is that non-root patterns may be regular expressions or other pattern styles containing
"*" that borgmatic should not expand as a shell glob.
Return all the resulting patterns as a tuple.
If a set of paths are given to skip, then don't expand any patterns matching them.
'''
if patterns is None:
return ()
return tuple(
itertools.chain.from_iterable(
(
(
borgmatic.borg.pattern.Pattern(
expanded_path,
pattern.type,
pattern.style,
pattern.device,
pattern.source,
)
for expanded_path in expand_directory(pattern.path, working_directory)
)
if pattern.type == borgmatic.borg.pattern.Pattern_type.ROOT
and pattern.path not in (skip_paths or ())
else (
borgmatic.borg.pattern.Pattern(
os.path.expanduser(pattern.path),
pattern.type,
pattern.style,
pattern.device,
pattern.source,
),
)
)
for pattern in patterns
)
)
def get_existent_path_or_parent(path):
'''
Given a path, return it if it exists. Otherwise, return the longest parent directory of the path
that exists. Return None if none of these paths exist.
This is used below for finding an existent path prefix of pattern's path, which is necessary if
the path contain globs or other special characters that we don't want to try to interpret
(because we want to leave that responsibility to Borg).
'''
if path.startswith('/e2e/'):
return None
try:
return next(
candidate_path
for candidate_path in (path,)
+ tuple(str(parent) for parent in pathlib.PurePath(path).parents)
if os.path.exists(candidate_path)
)
except StopIteration:
return None
def device_map_patterns(patterns, working_directory=None):
'''
Given a sequence of borgmatic.borg.pattern.Pattern instances and an optional working directory,
determine the identifier for the device on which the pattern's path resides—or None if the path
doesn't exist or is from a non-root pattern. Return an updated sequence of patterns with the
device field populated. But if the device field is already set, don't bother setting it again.
This is handy for determining whether two different pattern paths are on the same filesystem
(have the same device identifier).
This function only considers the start of a pattern's path—from the start of the path up until
there's a path component with a glob or other non-literal character. If there are no such
characters, the whole path is considered. The rationale is that it's not feasible for borgmatic
to interpret Borg's patterns to see which actual files (and therefore devices) they map to. So
for instance, a pattern with a path of "/var/log/*/data" would end up with its device set to the
device of "/var/log"—ignoring the "/*/data" part due to that glob.
The one exception is that if a regular expression pattern path starts with "^", that will get
stripped off for purposes of determining its device.
'''
return tuple(
borgmatic.borg.pattern.Pattern(
pattern.path,
pattern.type,
pattern.style,
device=pattern.device or (os.stat(existent_path).st_dev if existent_path else None),
source=pattern.source,
)
for pattern in patterns
for existent_path in (
get_existent_path_or_parent(
os.path.join(working_directory or '', pattern.path.lstrip('^'))
),
)
)
def deduplicate_patterns(patterns):
'''
Given a sequence of borgmatic.borg.pattern.Pattern instances, return them with all duplicate
root child patterns removed. For instance, if two root patterns are given with paths "/foo" and
"/foo/bar", return just the one with "/foo". Non-root patterns are passed through without
modification.
The one exception to deduplication is two paths are on different filesystems (devices). In that
case, they won't get deduplicated, in case they both need to be passed to Borg (e.g. the
one_file_system option is true).
The idea is that if Borg is given a root parent pattern, then it doesn't also need to be given
child patterns, because it will naturally spider the contents of the parent pattern's path. And
there are cases where Borg coming across the same file twice will result in duplicate reads and
even hangs, e.g. when a database hook is using a named pipe for streaming database dumps to
Borg.
'''
deduplicated = {} # Use just the keys as an ordered set.
for pattern in patterns:
if pattern.type != borgmatic.borg.pattern.Pattern_type.ROOT:
deduplicated[pattern] = True
continue
parents = pathlib.PurePath(pattern.path).parents
# If another directory in the given list is a parent of current directory (even n levels up)
# and both are on the same filesystem, then the current directory is a duplicate.
for other_pattern in patterns:
if other_pattern.type != borgmatic.borg.pattern.Pattern_type.ROOT:
continue
if any(
pathlib.PurePath(other_pattern.path) == parent
and pattern.device is not None
and other_pattern.device == pattern.device
for parent in parents
):
break
else:
deduplicated[pattern] = True
return tuple(deduplicated.keys())
def process_patterns(patterns, working_directory, skip_expand_paths=None):
'''
Given a sequence of Borg patterns and a configured working directory, expand and deduplicate any
"root" patterns, returning the resulting root and non-root patterns as a list.
If any paths are given to skip, don't expand them.
'''
skip_paths = set(skip_expand_paths or ())
return list(
deduplicate_patterns(
device_map_patterns(
expand_patterns(
patterns,
working_directory=working_directory,
skip_paths=skip_paths,
)
)
)
)

View File

@ -11,7 +11,6 @@ def run_prune(
config_filename,
repository,
config,
hook_context,
local_borg_version,
prune_arguments,
global_arguments,
@ -27,15 +26,7 @@ def run_prune(
):
return
borgmatic.hooks.command.execute_hook(
config.get('before_prune'),
config.get('umask'),
config_filename,
'pre-prune',
global_arguments.dry_run,
**hook_context,
)
logger.info(f'{repository.get("label", repository["path"])}: Pruning archives{dry_run_label}')
logger.info(f'Pruning archives{dry_run_label}')
borgmatic.borg.prune.prune_archives(
global_arguments.dry_run,
repository['path'],
@ -46,11 +37,3 @@ def run_prune(
local_path=local_path,
remote_path=remote_path,
)
borgmatic.hooks.command.execute_hook(
config.get('after_prune'),
config.get('umask'),
config_filename,
'post-prune',
global_arguments.dry_run,
**hook_context,
)

View File

@ -1,41 +0,0 @@
import logging
import borgmatic.borg.rcreate
import borgmatic.config.validate
logger = logging.getLogger(__name__)
def run_rcreate(
repository,
config,
local_borg_version,
rcreate_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "rcreate" action for the given repository.
'''
if rcreate_arguments.repository and not borgmatic.config.validate.repositories_match(
repository, rcreate_arguments.repository
):
return
logger.info(f'{repository.get("label", repository["path"])}: Creating repository')
borgmatic.borg.rcreate.create_repository(
global_arguments.dry_run,
repository['path'],
config,
local_borg_version,
global_arguments,
rcreate_arguments.encryption_mode,
rcreate_arguments.source_repository,
rcreate_arguments.copy_crypt_key,
rcreate_arguments.append_only,
rcreate_arguments.storage_quota,
rcreate_arguments.make_parent_dirs,
local_path=local_path,
remote_path=remote_path,
)

View File

@ -0,0 +1,84 @@
import logging
import subprocess
import borgmatic.borg.info
import borgmatic.borg.recreate
import borgmatic.borg.repo_list
import borgmatic.config.validate
from borgmatic.actions.pattern import collect_patterns, process_patterns
logger = logging.getLogger(__name__)
BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS = 30
def run_recreate(
repository,
config,
local_borg_version,
recreate_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "recreate" action for the given repository.
'''
if recreate_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, recreate_arguments.repository
):
if recreate_arguments.archive:
logger.answer(f'Recreating archive {recreate_arguments.archive}')
else:
logger.answer('Recreating repository')
# Collect and process patterns.
processed_patterns = process_patterns(
collect_patterns(config), borgmatic.config.paths.get_working_directory(config)
)
archive = borgmatic.borg.repo_list.resolve_archive_name(
repository['path'],
recreate_arguments.archive,
config,
local_borg_version,
global_arguments,
local_path,
remote_path,
)
if archive and archive.endswith('.recreate'):
if recreate_arguments.archive == 'latest':
raise ValueError(
f'The latest archive "{archive}" is leftover from a prior recreate. Delete it first or select a different archive.'
)
else:
raise ValueError(
f'The archive "{recreate_arguments.archive}" is leftover from a prior recreate. Select a different archive.'
)
try:
borgmatic.borg.recreate.recreate_archive(
repository['path'],
archive,
config,
local_borg_version,
recreate_arguments,
global_arguments,
local_path=local_path,
remote_path=remote_path,
patterns=processed_patterns,
)
except subprocess.CalledProcessError as error:
if error.returncode == BORG_EXIT_CODE_ARCHIVE_ALREADY_EXISTS:
if recreate_arguments.target:
raise ValueError(
f'The archive "{recreate_arguments.target}" already exists. Delete it first or set a different target archive name.'
)
elif archive:
raise ValueError(
f'The archive "{archive}.recreate" is leftover from a prior recreate. Delete it first or select a different archive.'
)
raise

View File

@ -0,0 +1,61 @@
import logging
import borgmatic.borg.repo_create
import borgmatic.config.validate
logger = logging.getLogger(__name__)
def run_repo_create(
repository,
config,
local_borg_version,
repo_create_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "repo-create" action for the given repository.
'''
if repo_create_arguments.repository and not borgmatic.config.validate.repositories_match(
repository, repo_create_arguments.repository
):
return
logger.info('Creating repository')
encryption_mode = repo_create_arguments.encryption_mode or repository.get('encryption')
if not encryption_mode:
raise ValueError(
'With the repo-create action, either the --encryption flag or the repository encryption option is required.'
)
borgmatic.borg.repo_create.create_repository(
global_arguments.dry_run,
repository['path'],
config,
local_borg_version,
global_arguments,
encryption_mode,
repo_create_arguments.source_repository,
repo_create_arguments.copy_crypt_key,
(
repository.get('append_only')
if repo_create_arguments.append_only is None
else repo_create_arguments.append_only
),
(
repository.get('storage_quota')
if repo_create_arguments.storage_quota is None
else repo_create_arguments.storage_quota
),
(
repository.get('make_parent_directories')
if repo_create_arguments.make_parent_directories is None
else repo_create_arguments.make_parent_directories
),
local_path=local_path,
remote_path=remote_path,
)

View File

@ -0,0 +1,35 @@
import logging
import borgmatic.borg.repo_delete
logger = logging.getLogger(__name__)
def run_repo_delete(
repository,
config,
local_borg_version,
repo_delete_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "repo-delete" action for the given repository.
'''
if repo_delete_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, repo_delete_arguments.repository
):
logger.answer(
'Deleting repository' + (' cache' if repo_delete_arguments.cache_only else '')
)
borgmatic.borg.repo_delete.delete_repository(
repository,
config,
local_borg_version,
repo_delete_arguments,
global_arguments,
local_path,
remote_path,
)

View File

@ -0,0 +1,40 @@
import logging
import borgmatic.actions.json
import borgmatic.borg.repo_info
import borgmatic.config.validate
logger = logging.getLogger(__name__)
def run_repo_info(
repository,
config,
local_borg_version,
repo_info_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "repo-info" action for the given repository.
If repo_info_arguments.json is True, yield the JSON output from the info for the repository.
'''
if repo_info_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, repo_info_arguments.repository
):
if not repo_info_arguments.json:
logger.answer('Displaying repository summary information')
json_output = borgmatic.borg.repo_info.display_repository_info(
repository['path'],
config,
local_borg_version,
repo_info_arguments=repo_info_arguments,
global_arguments=global_arguments,
local_path=local_path,
remote_path=remote_path,
)
if json_output:
yield borgmatic.actions.json.parse_json(json_output, repository.get('label'))

View File

@ -1,37 +1,37 @@
import logging
import borgmatic.actions.json
import borgmatic.borg.rlist
import borgmatic.borg.repo_list
import borgmatic.config.validate
logger = logging.getLogger(__name__)
def run_rlist(
def run_repo_list(
repository,
config,
local_borg_version,
rlist_arguments,
repo_list_arguments,
global_arguments,
local_path,
remote_path,
):
'''
Run the "rlist" action for the given repository.
Run the "repo-list" action for the given repository.
If rlist_arguments.json is True, yield the JSON output from listing the repository.
If repo_list_arguments.json is True, yield the JSON output from listing the repository.
'''
if rlist_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, rlist_arguments.repository
if repo_list_arguments.repository is None or borgmatic.config.validate.repositories_match(
repository, repo_list_arguments.repository
):
if not rlist_arguments.json:
logger.answer(f'{repository.get("label", repository["path"])}: Listing repository')
if not repo_list_arguments.json:
logger.answer('Listing repository')
json_output = borgmatic.borg.rlist.list_repository(
json_output = borgmatic.borg.repo_list.list_repository(
repository['path'],
config,
local_borg_version,
rlist_arguments=rlist_arguments,
repo_list_arguments=repo_list_arguments,
global_arguments=global_arguments,
local_path=local_path,
remote_path=remote_path,

View File

@ -1,67 +1,156 @@
import copy
import collections
import logging
import os
import pathlib
import shutil
import tempfile
import borgmatic.borg.extract
import borgmatic.borg.list
import borgmatic.borg.mount
import borgmatic.borg.rlist
import borgmatic.borg.state
import borgmatic.borg.repo_list
import borgmatic.config.paths
import borgmatic.config.validate
import borgmatic.hooks.data_source.dump
import borgmatic.hooks.dispatch
import borgmatic.hooks.dump
logger = logging.getLogger(__name__)
UNSPECIFIED_HOOK = object()
UNSPECIFIED = object()
def get_configured_data_source(
config,
archive_data_source_names,
hook_name,
data_source_name,
configuration_data_source_name=None,
):
Dump = collections.namedtuple(
'Dump',
('hook_name', 'data_source_name', 'hostname', 'port'),
defaults=('localhost', None),
)
def dumps_match(first, second, default_port=None):
'''
Find the first data source with the given hook name and data source name in the configuration
dict and the given archive data source names dict (from hook name to data source names contained
in a particular backup archive). If UNSPECIFIED_HOOK is given as the hook name, search all data
source hooks for the named data source. If a configuration data source name is given, use that
instead of the data source name to lookup the data source in the given hooks configuration.
Return the found data source as a tuple of (found hook name, data source configuration dict) or
(None, None) if not found.
Compare two Dump instances for equality while supporting a field value of UNSPECIFIED, which
indicates that the field should match any value. If a default port is given, then consider any
dump having that port to match with a dump having a None port.
'''
if not configuration_data_source_name:
configuration_data_source_name = data_source_name
for field_name in first._fields:
first_value = getattr(first, field_name)
second_value = getattr(second, field_name)
if hook_name == UNSPECIFIED_HOOK:
hooks_to_search = {
hook_name: value
for (hook_name, value) in config.items()
if hook_name in borgmatic.hooks.dump.DATA_SOURCE_HOOK_NAMES
}
if default_port is not None and field_name == 'port':
if first_value == default_port and second_value is None:
continue
if second_value == default_port and first_value is None:
continue
if first_value == UNSPECIFIED or second_value == UNSPECIFIED:
continue
if first_value != second_value:
return False
return True
def render_dump_metadata(dump):
'''
Given a Dump instance, make a display string describing it for use in log messages.
'''
name = 'unspecified' if dump.data_source_name is UNSPECIFIED else dump.data_source_name
hostname = dump.hostname or UNSPECIFIED
port = None if dump.port is UNSPECIFIED else dump.port
if port:
metadata = f'{name}@:{port}' if hostname is UNSPECIFIED else f'{name}@{hostname}:{port}'
else:
try:
hooks_to_search = {hook_name: config[hook_name]}
except KeyError:
return (None, None)
metadata = f'{name}' if hostname is UNSPECIFIED else f'{name}@{hostname}'
return next(
(
(name, hook_data_source)
for (name, hook) in hooks_to_search.items()
for hook_data_source in hook
if hook_data_source['name'] == configuration_data_source_name
and data_source_name in archive_data_source_names.get(name, [])
),
(None, None),
if dump.hook_name not in (None, UNSPECIFIED):
return f'{metadata} ({dump.hook_name})'
return metadata
def get_configured_data_source(config, restore_dump):
'''
Search in the given configuration dict for dumps corresponding to the given dump to restore. If
there are multiple matches, error.
Return the found data source as a data source configuration dict or None if not found.
'''
try:
hooks_to_search = {restore_dump.hook_name: config[restore_dump.hook_name]}
except KeyError:
return None
matching_dumps = tuple(
hook_data_source
for (hook_name, hook_config) in hooks_to_search.items()
for hook_data_source in hook_config
for default_port in (
borgmatic.hooks.dispatch.call_hook(
function_name='get_default_port',
config=config,
hook_name=hook_name,
),
)
if dumps_match(
Dump(
hook_name,
hook_data_source.get('name'),
hook_data_source.get('hostname', 'localhost'),
hook_data_source.get('port'),
),
restore_dump,
default_port,
)
)
if not matching_dumps:
return None
def restore_single_data_source(
if len(matching_dumps) > 1:
raise ValueError(
f'Cannot restore data source {render_dump_metadata(restore_dump)} because there are multiple matching data sources configured'
)
return matching_dumps[0]
def strip_path_prefix_from_extracted_dump_destination(
destination_path, borgmatic_runtime_directory
):
'''
Directory-format dump files get extracted into a temporary directory containing a path prefix
that depends how the files were stored in the archive. So, given the destination path where the
dump was extracted and the borgmatic runtime directory, move the dump files such that the
restore doesn't have to deal with that varying path prefix.
For instance, if the dump was extracted to:
/run/user/0/borgmatic/tmp1234/borgmatic/postgresql_databases/test/...
or:
/run/user/0/borgmatic/tmp1234/root/.borgmatic/postgresql_databases/test/...
then this function moves it to:
/run/user/0/borgmatic/postgresql_databases/test/...
'''
for subdirectory_path, _, _ in os.walk(destination_path):
databases_directory = os.path.basename(subdirectory_path)
if not databases_directory.endswith('_databases'):
continue
shutil.move(
subdirectory_path, os.path.join(borgmatic_runtime_directory, databases_directory)
)
break
def restore_single_dump(
repository,
config,
local_borg_version,
@ -72,55 +161,78 @@ def restore_single_data_source(
hook_name,
data_source,
connection_params,
): # pragma: no cover
borgmatic_runtime_directory,
):
'''
Given (among other things) an archive name, a data source hook name, the hostname, port,
username/password as connection params, and a configured data source configuration dict, restore
that data source from the archive.
'''
logger.info(
f'{repository.get("label", repository["path"])}: Restoring data source {data_source["name"]}'
dump_metadata = render_dump_metadata(
Dump(hook_name, data_source['name'], data_source.get('hostname'), data_source.get('port'))
)
dump_pattern = borgmatic.hooks.dispatch.call_hooks(
'make_data_source_dump_pattern',
logger.info(f'Restoring data source {dump_metadata}')
dump_patterns = borgmatic.hooks.dispatch.call_hooks(
'make_data_source_dump_patterns',
config,
repository['path'],
borgmatic.hooks.dump.DATA_SOURCE_HOOK_NAMES,
borgmatic.hooks.dispatch.Hook_type.DATA_SOURCE,
borgmatic_runtime_directory,
data_source['name'],
)[hook_name]
)[hook_name.split('_databases', 1)[0]]
# Kick off a single data source extract to stdout.
extract_process = borgmatic.borg.extract.extract_archive(
dry_run=global_arguments.dry_run,
repository=repository['path'],
archive=archive_name,
paths=borgmatic.hooks.dump.convert_glob_patterns_to_borg_patterns([dump_pattern]),
config=config,
local_borg_version=local_borg_version,
global_arguments=global_arguments,
local_path=local_path,
remote_path=remote_path,
destination_path='/',
# A directory format dump isn't a single file, and therefore can't extract
# to stdout. In this case, the extract_process return value is None.
extract_to_stdout=bool(data_source.get('format') != 'directory'),
destination_path = (
tempfile.mkdtemp(dir=borgmatic_runtime_directory)
if data_source.get('format') == 'directory'
else None
)
try:
# Kick off a single data source extract. If using a directory format, extract to a temporary
# directory. Otherwise extract the single dump file to stdout.
extract_process = borgmatic.borg.extract.extract_archive(
dry_run=global_arguments.dry_run,
repository=repository['path'],
archive=archive_name,
paths=[
borgmatic.hooks.data_source.dump.convert_glob_patterns_to_borg_pattern(
dump_patterns
)
],
config=config,
local_borg_version=local_borg_version,
global_arguments=global_arguments,
local_path=local_path,
remote_path=remote_path,
destination_path=destination_path,
# A directory format dump isn't a single file, and therefore can't extract
# to stdout. In this case, the extract_process return value is None.
extract_to_stdout=bool(data_source.get('format') != 'directory'),
)
if destination_path and not global_arguments.dry_run:
strip_path_prefix_from_extracted_dump_destination(
destination_path, borgmatic_runtime_directory
)
finally:
if destination_path and not global_arguments.dry_run:
shutil.rmtree(destination_path, ignore_errors=True)
# Run a single data source restore, consuming the extract stdout (if any).
borgmatic.hooks.dispatch.call_hooks(
borgmatic.hooks.dispatch.call_hook(
function_name='restore_data_source_dump',
config=config,
log_prefix=repository['path'],
hook_names=[hook_name],
hook_name=hook_name,
data_source=data_source,
dry_run=global_arguments.dry_run,
extract_process=extract_process,
connection_params=connection_params,
borgmatic_runtime_directory=borgmatic_runtime_directory,
)
def collect_archive_data_source_names(
def collect_dumps_from_archive(
repository,
archive,
config,
@ -128,18 +240,21 @@ def collect_archive_data_source_names(
global_arguments,
local_path,
remote_path,
borgmatic_runtime_directory,
):
'''
Given a local or remote repository path, a resolved archive name, a configuration dict, the
local Borg version, global_arguments an argparse.Namespace, and local and remote Borg paths,
query the archive for the names of data sources it contains as dumps and return them as a dict
from hook name to a sequence of data source names.
local Borg version, global arguments an argparse.Namespace, local and remote Borg paths, and the
borgmatic runtime directory, query the archive for the names of data sources dumps it contains
and return them as a set of Dump instances.