Compare commits

..
30 Commits
Author SHA1 Message Date
Dan Helfman 31db6faa19 Set to release version. 2018-09-26 21:32:28 -07:00
Dan Helfman 872d8b695a Flesh out NEWS line item a bit. 2018-09-24 21:37:45 -07:00
Dan HelfmanandGitea 6db3e1dda5 Merge branch 'master' of floli/borgmatic into master 2018-09-25 04:36:09 +00:00
Florian Lindner 9aaf78b9dd Add --json option for --create command line.
Closes #94.
2018-09-24 21:53:09 +02:00
Dan Helfman 5d8ac158ce Merge ssh://projects.torsion.org:3022/witten/borgmatic 2018-09-17 22:34:08 -07:00
Dan Helfman d32a53d58f Mention log level fix in NEWS. 2018-09-17 22:33:34 -07:00
floliandGitea a836ec944f Limit argument range for --verbose, make default log level more explicit. (#93) 2018-09-18 05:31:27 +00:00
Dan Helfman e7b128e735 --read-special is now supported. 2018-09-09 11:21:06 -07:00
Dan Helfman ff3cb1d80f Attach #64 to logging rewrite in NEWS. 2018-09-09 11:18:26 -07:00
Dan Helfman c5ff08ee25 Remove now-gone verbosity parameter from test. 2018-09-09 11:14:33 -07:00
Dan Helfman 856db29180 Mention --read-special in NEWS. 2018-09-09 10:42:06 -07:00
Steve KerrisonandDan Helfman 20e09b4ea8 Support for Borg create --read-special via "read_special" option (#25). 2018-09-09 10:39:56 -07:00
Dan Helfman 1dd0682661 Merge branch 'master' of ssh://projects.torsion.org:3022/witten/borgmatic 2018-09-08 13:54:18 -07:00
floliandGitea 7252b8d614 Rework logging/verbosity system (#90)
Looks great, merged! Thanks again for all your hard work here.
2018-09-08 20:53:37 +00:00
grerrgandDan Helfman e5870a169b Add example for cron in Alpine Linux (#24) 2018-09-05 21:58:30 -07:00
Dan Helfman 94795a3560 Link to Borg home page instead of docs. 2018-09-02 22:06:57 -07:00
Dan 7705debab0 Switching back to table-like 11ty front matter. It looks less bad than JSON. 2018-09-01 22:45:13 -07:00
Dan f87df0527f Adding JSON front matter for 11ty. 2018-09-01 22:38:17 -07:00
Dan Helfman e4512a40e0 Removing 11ty front matter out of README since it renders as a table on GitHub. 2018-09-01 22:11:38 -07:00
Dan Helfman 1d4a9510b8 Upgrade pytest. 2018-09-01 20:29:05 -07:00
Dan Helfman 2648f07e7a Add missing syntax highlighting. 2018-08-29 23:01:11 -07:00
Dan Helfman 459bf1fcf6 Document --list and --info flags. 2018-08-29 22:57:32 -07:00
Dan 3930e63320 Merge branch 'master' of ssh://projects.torsion.org:3022/witten/borgmatic 2018-08-29 22:44:45 -07:00
Dan acecb1e397 README metadata changes to support 11ty static site generator. 2018-08-29 22:44:12 -07:00
Dan Helfman 9b48eb5a61 Clarify that --json can be used with --info command-line flag. 2018-08-19 12:57:52 -07:00
Dan Helfman 7d40a448cb Pass --show-rc option to Borg when at highest verbosity level (#89). 2018-08-19 12:44:40 -07:00
Dan Helfman da7aed3814 Support for Borg create --checkpoint-interval (#87). 2018-08-19 11:41:49 -07:00
Dan Helfman c7f4200417 Somewhat more robust mechanism to find unsupported Borg arguments. 2018-08-19 11:24:48 -07:00
Dan Helfman 5e2a5494af Fix declared pykwalify compatibility version range in setup.py (#88). 2018-08-18 14:07:18 -07:00
Dan Helfman 7b77fd2510 Fix compatibility issue between pykwalify and ruamel.yaml 0.15.52 (#85). 2018-08-11 13:59:27 -07:00
25 changed files with 263 additions and 190 deletions
+2 -1
View File
@@ -1,11 +1,12 @@
Dan Helfman <witten@torsion.org>: Main developer
Alexander Görtz: Python 3 compatibility
Florian Lindner: Logging rewrite
Henning Schroeder: Copy editing
Johannes Feichtner: Support for user hooks
Michele Lazzeri: Custom archive names
Nick Whyte: Support prefix filtering for archive consistency checks
newtonne: Read encryption password from external file
Robin `ypid` Schneider: Support additional options of Borg
Scott Squires: Custom archive names
Thomas LÉVEIL: Support for a keep_minutely prune option. Support for the --json option
Nick Whyte: Support prefix filtering for archive consistency checks
+16
View File
@@ -1,3 +1,19 @@
1.2.3
* #64, #90, #92: Rewrite of logging system. Now verbosity flags passed to Borg are derived from
borgmatic's log level. Note that the output of borgmatic might slightly change.
* Part of #80: Support for Borg create --read-special via "read_special" option in borgmatic's
location configuration.
* #87: Support for Borg create --checkpoint-interval via "checkpoint_interval" option in
borgmatic's storage configuration.
* #88: Fix declared pykwalify compatibility version range in setup.py to prevent use of ancient
versions of pykwalify with large version numbers.
* #89: Pass --show-rc option to Borg when at highest verbosity level.
* #94: Support for Borg --json option via borgmatic command-line to --create archives.
1.2.2
* #85: Fix compatibility issue between pykwalify and ruamel.yaml 0.15.52, which manifested in
borgmatic as a pykwalify RuleError.
1.2.1
* Skip before/after backup hooks when only doing --prune, --check, --list, and/or --info.
* #71: Support for XDG_CONFIG_HOME environment variable for specifying alternate user ~/.config/
+28 -10
View File
@@ -1,13 +1,17 @@
<img src="https://projects.torsion.org/witten/borgmatic/raw/branch/master/static/borgmatic.png" width="150px" style="float: right; padding-left: 1em;">
---
title: borgmatic
permalink: borgmatic/index.html
---
## Overview
borgmatic (formerly atticmatic) is a simple Python wrapper script for the
[Borg](https://borgbackup.readthedocs.org/en/stable/) backup software that
initiates a backup, prunes any old backups according to a retention policy,
and validates backups for consistency. The script supports specifying your
settings in a declarative configuration file rather than having to put them
all on the command-line, and handles common errors.
<img src="https://projects.torsion.org/witten/borgmatic/raw/branch/master/static/borgmatic.png" width="150px" style="float: right; padding-left: 1em;">
borgmatic is a simple Python wrapper script for the
[Borg](https://www.borgbackup.org/) backup software that initiates a backup,
prunes any old backups according to a retention policy, and validates backups
for consistency. The script supports specifying your settings in a declarative
configuration file rather than having to put them all on the command-line, and
handles common errors.
Here's an example config file:
@@ -157,7 +161,7 @@ borgmatic runs `on_error` hooks if an error occurs.
An important security note about hooks: borgmatic executes all hook commands
with the user permissions of borgmatic itself. So to prevent potential shell
injection or privilege escalation, do not forget to set secure permissions
(chmod 0700) on borgmatic configuration files and scripts invoked by hooks.
(`chmod 0700`) on borgmatic configuration files and scripts invoked by hooks.
See the sample generated configuration file mentioned above for specifics
about hook configuration syntax.
@@ -291,6 +295,20 @@ any number of them. This supports use cases like running consistency checks
from a different cron job with a different frequency, or running pruning with
a different verbosity level.
Additionally, borgmatic provides convenient flags for Borg's
[list](https://borgbackup.readthedocs.io/en/stable/usage/list.html) and
[info](https://borgbackup.readthedocs.io/en/stable/usage/info.html)
functionality:
```bash
borgmatic --list
borgmatic --info
```
You can include an optional `--json` flag with either `--list` or `--info` to
get the output formatted as JSON.
## Autopilot
@@ -369,7 +387,7 @@ the following deviations from it:
To get set up to hack on borgmatic, first clone master via HTTPS or SSH:
```
```bash
git clone https://projects.torsion.org/witten/borgmatic.git
```
+11 -11
View File
@@ -3,7 +3,6 @@ import os
import subprocess
from borgmatic.borg import extract
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
DEFAULT_CHECKS = ('repository', 'archives')
@@ -74,12 +73,10 @@ def _make_check_flags(checks, check_last=None, prefix=None):
) + last_flags + prefix_flags
def check_archives(verbosity, repository, storage_config, consistency_config, local_path='borg',
remote_path=None):
def check_archives(repository, storage_config, consistency_config, local_path='borg', remote_path=None):
'''
Given a verbosity flag, a local or remote repository path, a storage config dict, a consistency
config dict, and a local/remote commands to run, check the contained Borg archives for
consistency.
Given a local or remote repository path, a storage config dict, a consistency config dict,
and a local/remote commands to run, check the contained Borg archives for consistency.
If there are no consistency checks to run, skip running them.
'''
@@ -91,10 +88,13 @@ def check_archives(verbosity, repository, storage_config, consistency_config, lo
remote_path_flags = ('--remote-path', remote_path) if remote_path else ()
lock_wait = storage_config.get('lock_wait', None)
lock_wait_flags = ('--lock-wait', str(lock_wait)) if lock_wait else ()
verbosity_flags = {
VERBOSITY_SOME: ('--info',),
VERBOSITY_LOTS: ('--debug',),
}.get(verbosity, ())
verbosity_flags = ()
if logger.isEnabledFor(logging.INFO):
verbosity_flags = ('--info',)
if logger.isEnabledFor(logging.DEBUG):
verbosity_flags = ('--debug', '--show-rc')
prefix = consistency_config.get('prefix')
full_command = (
@@ -109,4 +109,4 @@ def check_archives(verbosity, repository, storage_config, consistency_config, lo
subprocess.check_call(full_command, stdout=stdout, stderr=subprocess.STDOUT)
if 'extract' in checks:
extract.extract_last_archive_dry_run(verbosity, repository, lock_wait, local_path, remote_path)
extract.extract_last_archive_dry_run(repository, lock_wait, local_path, remote_path)
+9 -8
View File
@@ -5,8 +5,6 @@ import os
import subprocess
import tempfile
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
logger = logging.getLogger(__name__)
@@ -105,8 +103,7 @@ def _make_exclude_flags(location_config, exclude_filename=None):
def create_archive(
verbosity, dry_run, repository, location_config, storage_config, local_path='borg', remote_path=None,
):
dry_run, repository, location_config, storage_config, local_path='borg', remote_path=None, json=False):
'''
Given vebosity/dry-run flags, a local or remote repository path, a location config dict, and a
storage config dict, create a Borg archive.
@@ -115,6 +112,7 @@ def create_archive(
pattern_file = _write_pattern_file(location_config.get('patterns'))
exclude_file = _write_pattern_file(_expand_directories(location_config.get('exclude_patterns')))
checkpoint_interval = storage_config.get('checkpoint_interval', None)
compression = storage_config.get('compression', None)
remote_rate_limit = storage_config.get('remote_rate_limit', None)
umask = storage_config.get('umask', None)
@@ -140,19 +138,22 @@ def create_archive(
location_config,
exclude_file.name if exclude_file else None,
)
+ (('--checkpoint-interval', str(checkpoint_interval)) if checkpoint_interval else ())
+ (('--compression', compression) if compression else ())
+ (('--remote-ratelimit', str(remote_rate_limit)) if remote_rate_limit else ())
+ (('--one-file-system',) if location_config.get('one_file_system') else ())
+ (('--read-special',) if location_config.get('read_special') else ())
+ (('--nobsdflags',) if location_config.get('bsd_flags') is False else ())
+ (('--files-cache', files_cache) if files_cache else ())
+ (('--remote-path', remote_path) if remote_path else ())
+ (('--umask', str(umask)) if umask else ())
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
+ {
VERBOSITY_SOME: ('--info',) if dry_run else ('--info', '--stats',),
VERBOSITY_LOTS: ('--debug', '--list',) if dry_run else ('--debug', '--list', '--stats',),
}.get(verbosity, ())
+ (('--list', '--filter', 'AME',) if logger.isEnabledFor(logging.INFO) else ())
+ (( '--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+ (('--stats',) if not dry_run and logger.isEnabledFor(logging.INFO) else ())
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
+ (('--dry-run',) if dry_run else ())
+ (('--json',) if json else ())
)
logger.debug(' '.join(full_command))
+8 -8
View File
@@ -2,23 +2,23 @@ import logging
import sys
import subprocess
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
logger = logging.getLogger(__name__)
def extract_last_archive_dry_run(verbosity, repository, lock_wait=None, local_path='borg', remote_path=None):
def extract_last_archive_dry_run(repository, lock_wait=None, local_path='borg', remote_path=None):
'''
Perform an extraction dry-run of just the most recent archive. If there are no archives, skip
the dry-run.
'''
remote_path_flags = ('--remote-path', remote_path) if remote_path else ()
lock_wait_flags = ('--lock-wait', str(lock_wait)) if lock_wait else ()
verbosity_flags = {
VERBOSITY_SOME: ('--info',),
VERBOSITY_LOTS: ('--debug',),
}.get(verbosity, ())
verbosity_flags = ()
if logger.isEnabledFor(logging.DEBUG):
verbosity_flags = ('--debug', '--show-rc')
elif logger.isEnabledFor(logging.INFO):
verbosity_flags = ('--info',)
full_list_command = (
local_path, 'list',
@@ -32,7 +32,7 @@ def extract_last_archive_dry_run(verbosity, repository, lock_wait=None, local_pa
if not last_archive_name:
return
list_flag = ('--list',) if verbosity == VERBOSITY_LOTS else ()
list_flag = ('--list',) if logger.isEnabledFor(logging.DEBUG) else ()
full_extract_command = (
local_path, 'extract',
'--dry-run',
+4 -10
View File
@@ -1,17 +1,13 @@
import logging
import subprocess
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
logger = logging.getLogger(__name__)
def display_archives_info(
verbosity, repository, storage_config, local_path='borg', remote_path=None, json=False
):
def display_archives_info(repository, storage_config, local_path='borg', remote_path=None, json=False):
'''
Given a verbosity flag, a local or remote repository path, and a storage config dict,
Given a local or remote repository path, and a storage config dict,
display summary information for Borg archives in the repository.
'''
lock_wait = storage_config.get('lock_wait', None)
@@ -20,11 +16,9 @@ def display_archives_info(
(local_path, 'info', repository)
+ (('--remote-path', remote_path) if remote_path else ())
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
+ (('--json',) if json else ())
+ {
VERBOSITY_SOME: ('--info',),
VERBOSITY_LOTS: ('--debug',),
}.get(verbosity, ())
)
logger.debug(' '.join(full_command))
+4 -11
View File
@@ -1,17 +1,13 @@
import logging
import subprocess
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
logger = logging.getLogger(__name__)
def list_archives(
verbosity, repository, storage_config, local_path='borg', remote_path=None, json=False
):
def list_archives(repository, storage_config, local_path='borg', remote_path=None, json=False):
'''
Given a verbosity flag, a local or remote repository path, and a storage config dict,
Given a local or remote repository path, and a storage config dict,
list Borg archives in the repository.
'''
lock_wait = storage_config.get('lock_wait', None)
@@ -20,13 +16,10 @@ def list_archives(
(local_path, 'list', repository)
+ (('--remote-path', remote_path) if remote_path else ())
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+ (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
+ (('--json',) if json else ())
+ {
VERBOSITY_SOME: ('--info',),
VERBOSITY_LOTS: ('--debug',),
}.get(verbosity, ())
)
logger.debug(' '.join(full_command))
output = subprocess.check_output(full_command)
+5 -8
View File
@@ -1,7 +1,6 @@
import logging
import subprocess
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
logger = logging.getLogger(__name__)
@@ -32,10 +31,9 @@ def _make_prune_flags(retention_config):
)
def prune_archives(verbosity, dry_run, repository, storage_config, retention_config,
local_path='borg', remote_path=None):
def prune_archives(dry_run, repository, storage_config, retention_config, local_path='borg', remote_path=None):
'''
Given verbosity/dry-run flags, a local or remote repository path, a storage config dict, and a
Given dry-run flag, a local or remote repository path, a storage config dict, and a
retention config dict, prune Borg archives according to the retention policy specified in that
configuration.
'''
@@ -54,10 +52,9 @@ def prune_archives(verbosity, dry_run, repository, storage_config, retention_con
+ (('--remote-path', remote_path) if remote_path else ())
+ (('--umask', str(umask)) if umask else ())
+ (('--lock-wait', str(lock_wait)) if lock_wait else ())
+ {
VERBOSITY_SOME: ('--info', '--stats',),
VERBOSITY_LOTS: ('--debug', '--stats', '--list'),
}.get(verbosity, ())
+ (('--stats',) if not dry_run and logger.isEnabledFor(logging.INFO) else ())
+ (( '--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+ (('--debug', '--list', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
+ (('--dry-run',) if dry_run else ())
)
+7 -9
View File
@@ -10,7 +10,7 @@ from borgmatic.borg import check as borg_check, create as borg_create, prune as
from borgmatic.commands import hook
from borgmatic.config import collect, convert, validate
from borgmatic.signals import configure_signals
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS, verbosity_to_log_level
from borgmatic.verbosity import verbosity_to_log_level
logger = logging.getLogger(__name__)
@@ -81,7 +81,7 @@ def parse_arguments(*arguments):
dest='json',
default=False,
action='store_true',
help='Output results from the --list option as json',
help='Output results from the --list or --info options as json',
)
parser.add_argument(
'-n', '--dry-run',
@@ -92,13 +92,15 @@ def parse_arguments(*arguments):
parser.add_argument(
'-v', '--verbosity',
type=int,
choices=range(0,3),
default=0,
help='Display verbose progress (1 for some, 2 for lots)',
)
args = parser.parse_args(arguments)
if args.json and not (args.list or args.info):
raise ValueError('The --json option can only be used with the --list or --info options')
if args.json and not (args.create or args.list or args.info):
raise ValueError('The --json option can only be used with the --create, --list or --info options')
if args.json and args.list and args.info:
raise ValueError(
@@ -165,7 +167,6 @@ def _run_commands_on_repository(
if args.prune:
logger.info('{}: Pruning archives{}'.format(repository, dry_run_label))
borg_prune.prune_archives(
args.verbosity,
args.dry_run,
repository,
storage,
@@ -176,7 +177,6 @@ def _run_commands_on_repository(
if args.create:
logger.info('{}: Creating archive{}'.format(repository, dry_run_label))
borg_create.create_archive(
args.verbosity,
args.dry_run,
repository,
location,
@@ -187,17 +187,16 @@ def _run_commands_on_repository(
if args.check:
logger.info('{}: Running consistency checks'.format(repository))
borg_check.check_archives(
args.verbosity,
repository,
storage,
consistency,
local_path=local_path,
remote_path=remote_path,
json=args.json
)
if args.list:
logger.info('{}: Listing archives'.format(repository))
output = borg_list.list_archives(
args.verbosity,
repository,
storage,
local_path=local_path,
@@ -211,7 +210,6 @@ def _run_commands_on_repository(
if args.info:
logger.info('{}: Displaying summary info for archives'.format(repository))
output = borg_info.display_archives_info(
args.verbosity,
repository,
storage,
local_path=local_path,
+14
View File
@@ -22,6 +22,13 @@ map:
type: bool
desc: Stay in same file system (do not cross mount points).
example: true
read_special:
type: bool
desc: |
Use Borg's --read-special flag to allow backup of block and other special
devices. Use with caution, as it will lead to problems if used when
backing up special devices such as /dev/zero.
example: false
bsd_flags:
type: bool
desc: Record bsdflags (e.g. NODUMP, IMMUTABLE) in archive. Defaults to true.
@@ -124,6 +131,13 @@ map:
punctuation, so it parses correctly. And backslash any quote or backslash
literals as well.
example: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
checkpoint_interval:
type: int
desc: |
Number of seconds between each checkpoint during a long-running backup. See
https://borgbackup.readthedocs.io/en/stable/faq.html#if-a-backup-stops-mid-way-does-the-already-backed-up-data-stay-there
for details. Defaults to checkpoints every 1800 seconds (30 minutes).
example: 1800
compression:
type: scalar
desc: |
+2 -2
View File
@@ -74,8 +74,8 @@ def parse_configuration(config_filename, schema_filename):
logging.getLogger('pykwalify').setLevel(logging.ERROR)
try:
config = yaml.round_trip_load(open(config_filename))
schema = yaml.round_trip_load(open(schema_filename))
config = yaml.safe_load(open(config_filename))
schema = yaml.safe_load(open(schema_filename))
except yaml.error.YAMLError as error:
raise Validation_error(config_filename, (str(error),))
@@ -14,7 +14,7 @@ def test_parse_arguments_with_no_arguments_uses_defaults():
assert parser.config_paths == config_paths
assert parser.excludes_filename == None
assert parser.verbosity is None
assert parser.verbosity is 0
assert parser.json is False
@@ -25,7 +25,7 @@ def test_parse_arguments_with_path_arguments_overrides_defaults():
assert parser.config_paths == ['myconfig']
assert parser.excludes_filename == 'myexcludes'
assert parser.verbosity is None
assert parser.verbosity is 0
def test_parse_arguments_with_multiple_config_paths_parses_as_list():
@@ -34,7 +34,7 @@ def test_parse_arguments_with_multiple_config_paths_parses_as_list():
parser = module.parse_arguments('--config', 'myconfig', 'otherconfig')
assert parser.config_paths == ['myconfig', 'otherconfig']
assert parser.verbosity is None
assert parser.verbosity is 0
def test_parse_arguments_with_verbosity_flag_overrides_default():
+7 -15
View File
@@ -1,12 +1,11 @@
from subprocess import STDOUT
import sys
import logging, sys
from flexmock import flexmock
import pytest
from borgmatic.borg import check as module
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
from borgmatic.tests.unit.test_verbosity import insert_logging_mock
def insert_subprocess_mock(check_call_command, **kwargs):
subprocess = flexmock(module.subprocess)
@@ -125,7 +124,6 @@ def test_check_archives_calls_borg_with_parameters(checks):
flexmock(module.os).should_receive('devnull')
module.check_archives(
verbosity=None,
repository='repo',
storage_config={},
consistency_config=consistency_config,
@@ -142,43 +140,42 @@ def test_check_archives_with_extract_check_calls_extract_only():
insert_subprocess_never()
module.check_archives(
verbosity=None,
repository='repo',
storage_config={},
consistency_config=consistency_config,
)
def test_check_archives_with_verbosity_some_calls_borg_with_info_parameter():
def test_check_archives_with_log_info_calls_borg_with_info_parameter():
checks = ('repository',)
consistency_config = {'check_last': None}
flexmock(module).should_receive('_parse_checks').and_return(checks)
flexmock(module).should_receive('_make_check_flags').and_return(())
insert_logging_mock(logging.INFO)
insert_subprocess_mock(
('borg', 'check', 'repo', '--info'),
stdout=None, stderr=STDOUT,
)
module.check_archives(
verbosity=VERBOSITY_SOME,
repository='repo',
storage_config={},
consistency_config=consistency_config,
)
def test_check_archives_with_verbosity_lots_calls_borg_with_debug_parameter():
def test_check_archives_with_log_debug_calls_borg_with_debug_parameter():
checks = ('repository',)
consistency_config = {'check_last': None}
flexmock(module).should_receive('_parse_checks').and_return(checks)
flexmock(module).should_receive('_make_check_flags').and_return(())
insert_logging_mock(logging.DEBUG)
insert_subprocess_mock(
('borg', 'check', 'repo', '--debug'),
('borg', 'check', 'repo', '--debug', '--show-rc'),
stdout=None, stderr=STDOUT,
)
module.check_archives(
verbosity=VERBOSITY_LOTS,
repository='repo',
storage_config={},
consistency_config=consistency_config,
@@ -191,7 +188,6 @@ def test_check_archives_without_any_checks_bails():
insert_subprocess_never()
module.check_archives(
verbosity=None,
repository='repo',
storage_config={},
consistency_config=consistency_config,
@@ -213,7 +209,6 @@ def test_check_archives_with_local_path_calls_borg_via_local_path():
flexmock(module.os).should_receive('devnull')
module.check_archives(
verbosity=None,
repository='repo',
storage_config={},
consistency_config=consistency_config,
@@ -236,7 +231,6 @@ def test_check_archives_with_remote_path_calls_borg_with_remote_path_parameters(
flexmock(module.os).should_receive('devnull')
module.check_archives(
verbosity=None,
repository='repo',
storage_config={},
consistency_config=consistency_config,
@@ -259,7 +253,6 @@ def test_check_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
flexmock(module.os).should_receive('devnull')
module.check_archives(
verbosity=None,
repository='repo',
storage_config={'lock_wait': 5},
consistency_config=consistency_config,
@@ -283,7 +276,6 @@ def test_check_archives_with_retention_prefix():
flexmock(module.os).should_receive('devnull')
module.check_archives(
verbosity=None,
repository='repo',
storage_config={},
consistency_config=consistency_config,
+78 -34
View File
@@ -1,9 +1,9 @@
import os
import logging, os
from flexmock import flexmock
from borgmatic.borg import create as module
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
from borgmatic.tests.unit.test_verbosity import insert_logging_mock
def test_initialize_environment_with_passcommand_should_set_environment():
@@ -216,7 +216,6 @@ def test_create_archive_calls_borg_with_parameters():
insert_subprocess_mock(CREATE_COMMAND)
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -237,7 +236,6 @@ def test_create_archive_with_patterns_calls_borg_with_patterns():
insert_subprocess_mock(CREATE_COMMAND + pattern_flags)
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -258,7 +256,6 @@ def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
insert_subprocess_mock(CREATE_COMMAND + exclude_flags)
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -270,16 +267,16 @@ def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
)
def test_create_archive_with_verbosity_some_calls_borg_with_info_parameter():
def test_create_archive_with_log_info_calls_borg_with_info_parameter():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--info', '--stats',))
insert_subprocess_mock(CREATE_COMMAND + ('--list', '--filter', 'AME', '--info', '--stats',))
insert_logging_mock(logging.INFO)
module.create_archive(
verbosity=VERBOSITY_SOME,
dry_run=False,
repository='repo',
location_config={
@@ -291,15 +288,15 @@ def test_create_archive_with_verbosity_some_calls_borg_with_info_parameter():
)
def test_create_archive_with_verbosity_lots_calls_borg_with_debug_parameter():
def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--debug', '--list', '--stats'))
insert_subprocess_mock(CREATE_COMMAND + ('--list', '--filter', 'AME','--stats', '--debug', '--show-rc'))
insert_logging_mock(logging.DEBUG)
module.create_archive(
verbosity=VERBOSITY_LOTS,
dry_run=False,
repository='repo',
location_config={
@@ -320,7 +317,6 @@ def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
insert_subprocess_mock(CREATE_COMMAND + ('--dry-run',))
module.create_archive(
verbosity=None,
dry_run=True,
repository='repo',
location_config={
@@ -332,16 +328,18 @@ def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
)
def test_create_archive_with_dry_run_and_verbosity_some_calls_borg_without_stats_parameter():
def test_create_archive_with_dry_run_and_log_info_calls_borg_without_stats_parameter():
""" --dry-run and --stats are mutually exclusive, see:
https://borgbackup.readthedocs.io/en/stable/usage/create.html#description """
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--info', '--dry-run'))
insert_subprocess_mock(CREATE_COMMAND + ('--list', '--filter', 'AME', '--info', '--dry-run'))
insert_logging_mock(logging.INFO)
module.create_archive(
verbosity=VERBOSITY_SOME,
dry_run=True,
repository='repo',
location_config={
@@ -353,16 +351,18 @@ def test_create_archive_with_dry_run_and_verbosity_some_calls_borg_without_stats
)
def test_create_archive_with_dry_run_and_verbosity_lots_calls_borg_without_stats_parameter():
def test_create_archive_with_dry_run_and_log_debug_calls_borg_without_stats_parameter():
""" --dry-run and --stats are mutually exclusive, see:
https://borgbackup.readthedocs.io/en/stable/usage/create.html#description """
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--debug', '--list', '--dry-run'))
insert_subprocess_mock(CREATE_COMMAND + ('--list', '--filter', 'AME', '--debug', '--show-rc', '--dry-run'))
insert_logging_mock(logging.DEBUG)
module.create_archive(
verbosity=VERBOSITY_LOTS,
dry_run=True,
repository='repo',
location_config={
@@ -374,6 +374,25 @@ def test_create_archive_with_dry_run_and_verbosity_lots_calls_borg_without_stats
)
def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_interval_parameters():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--checkpoint-interval', '600'))
module.create_archive(
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
'repositories': ['repo'],
'exclude_patterns': None,
},
storage_config={'checkpoint_interval': 600},
)
def test_create_archive_with_compression_calls_borg_with_compression_parameters():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
@@ -382,7 +401,6 @@ def test_create_archive_with_compression_calls_borg_with_compression_parameters(
insert_subprocess_mock(CREATE_COMMAND + ('--compression', 'rle'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -402,7 +420,6 @@ def test_create_archive_with_remote_rate_limit_calls_borg_with_remote_ratelimit_
insert_subprocess_mock(CREATE_COMMAND + ('--remote-ratelimit', '100'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -422,7 +439,6 @@ def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_par
insert_subprocess_mock(CREATE_COMMAND + ('--one-file-system',))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -435,6 +451,26 @@ def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_par
)
def test_create_archive_with_read_special_calls_borg_with_read_special_parameter():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--read-special',))
module.create_archive(
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
'repositories': ['repo'],
'read_special': True,
'exclude_patterns': None,
},
storage_config={},
)
def test_create_archive_with_bsd_flags_true_calls_borg_without_nobsdflags_parameter():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
@@ -443,7 +479,6 @@ def test_create_archive_with_bsd_flags_true_calls_borg_without_nobsdflags_parame
insert_subprocess_mock(CREATE_COMMAND)
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -464,7 +499,6 @@ def test_create_archive_with_bsd_flags_false_calls_borg_with_nobsdflags_paramete
insert_subprocess_mock(CREATE_COMMAND + ('--nobsdflags',))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -485,7 +519,6 @@ def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters(
insert_subprocess_mock(CREATE_COMMAND + ('--files-cache', 'ctime,size'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -506,7 +539,6 @@ def test_create_archive_with_local_path_calls_borg_via_local_path():
insert_subprocess_mock(('borg1',) + CREATE_COMMAND[1:])
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -527,7 +559,6 @@ def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters(
insert_subprocess_mock(CREATE_COMMAND + ('--remote-path', 'borg1'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -548,7 +579,6 @@ def test_create_archive_with_umask_calls_borg_with_umask_parameters():
insert_subprocess_mock(CREATE_COMMAND + ('--umask', '740'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -568,7 +598,6 @@ def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
insert_subprocess_mock(CREATE_COMMAND + ('--lock-wait', '5'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -580,6 +609,26 @@ def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
)
def test_create_archive_with_json_calls_borg_with_json_parameter():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
flexmock(module).should_receive('_make_pattern_flags').and_return(())
flexmock(module).should_receive('_make_exclude_flags').and_return(())
insert_subprocess_mock(CREATE_COMMAND + ('--json',))
module.create_archive(
dry_run=False,
repository='repo',
location_config={
'source_directories': ['foo', 'bar'],
'repositories': ['repo'],
'exclude_patterns': None,
},
storage_config={},
json=True
)
def test_create_archive_with_source_directories_glob_expands():
flexmock(module).should_receive('_expand_directories').and_return(('foo', 'food')).and_return(())
flexmock(module).should_receive('_write_pattern_file').and_return(None)
@@ -589,7 +638,6 @@ def test_create_archive_with_source_directories_glob_expands():
flexmock(module.glob).should_receive('glob').with_args('foo*').and_return(['foo', 'food'])
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -610,7 +658,6 @@ def test_create_archive_with_non_matching_source_directories_glob_passes_through
flexmock(module.glob).should_receive('glob').with_args('foo*').and_return([])
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -630,7 +677,6 @@ def test_create_archive_with_glob_calls_borg_with_expanded_directories():
insert_subprocess_mock(('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -650,7 +696,6 @@ def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
insert_subprocess_mock(('borg', 'create', 'repo::ARCHIVE_NAME', 'foo', 'bar'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
@@ -672,7 +717,6 @@ def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
insert_subprocess_mock(('borg', 'create', 'repo::Documents_{hostname}-{now}', 'foo', 'bar'))
module.create_archive(
verbosity=None,
dry_run=False,
repository='repo',
location_config={
+8 -12
View File
@@ -1,9 +1,10 @@
import sys
import logging, sys
from flexmock import flexmock
from borgmatic.borg import extract as module
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
from borgmatic.tests.unit.test_verbosity import insert_logging_mock
def insert_subprocess_mock(check_call_command, **kwargs):
@@ -32,7 +33,6 @@ def test_extract_last_archive_dry_run_should_call_borg_with_last_archive():
)
module.extract_last_archive_dry_run(
verbosity=None,
repository='repo',
lock_wait=None,
)
@@ -47,13 +47,12 @@ def test_extract_last_archive_dry_run_without_any_archives_should_bail():
insert_subprocess_never()
module.extract_last_archive_dry_run(
verbosity=None,
repository='repo',
lock_wait=None,
)
def test_extract_last_archive_dry_run_with_verbosity_some_should_call_borg_with_info_parameter():
def test_extract_last_archive_dry_run_with_log_info_should_call_borg_with_info_parameter():
flexmock(sys.stdout).encoding = 'utf-8'
insert_subprocess_check_output_mock(
('borg', 'list', '--short', 'repo', '--info'),
@@ -62,26 +61,26 @@ def test_extract_last_archive_dry_run_with_verbosity_some_should_call_borg_with_
insert_subprocess_mock(
('borg', 'extract', '--dry-run', 'repo::archive2', '--info'),
)
insert_logging_mock(logging.INFO)
module.extract_last_archive_dry_run(
verbosity=VERBOSITY_SOME,
repository='repo',
lock_wait=None,
)
def test_extract_last_archive_dry_run_with_verbosity_lots_should_call_borg_with_debug_parameter():
def test_extract_last_archive_dry_run_with_log_debug_should_call_borg_with_debug_parameter():
flexmock(sys.stdout).encoding = 'utf-8'
insert_subprocess_check_output_mock(
('borg', 'list', '--short', 'repo', '--debug'),
('borg', 'list', '--short', 'repo', '--debug', '--show-rc'),
result='archive1\narchive2\n'.encode('utf-8'),
)
insert_subprocess_mock(
('borg', 'extract', '--dry-run', 'repo::archive2', '--debug', '--list'),
('borg', 'extract', '--dry-run', 'repo::archive2', '--debug', '--show-rc', '--list'),
)
insert_logging_mock(logging.DEBUG)
module.extract_last_archive_dry_run(
verbosity=VERBOSITY_LOTS,
repository='repo',
lock_wait=None,
)
@@ -98,7 +97,6 @@ def test_extract_last_archive_dry_run_should_call_borg_via_local_path():
)
module.extract_last_archive_dry_run(
verbosity=None,
repository='repo',
lock_wait=None,
local_path='borg1',
@@ -116,7 +114,6 @@ def test_extract_last_archive_dry_run_should_call_borg_with_remote_path_paramete
)
module.extract_last_archive_dry_run(
verbosity=None,
repository='repo',
lock_wait=None,
remote_path='borg1',
@@ -134,7 +131,6 @@ def test_extract_last_archive_dry_run_should_call_borg_with_lock_wait_parameters
)
module.extract_last_archive_dry_run(
verbosity=None,
repository='repo',
lock_wait=5,
)
+7 -12
View File
@@ -1,9 +1,10 @@
import logging
from collections import OrderedDict
from flexmock import flexmock
from borgmatic.borg import info as module
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
from borgmatic.tests.unit.test_verbosity import insert_logging_mock
def insert_subprocess_mock(check_call_command, **kwargs):
@@ -18,29 +19,27 @@ def test_display_archives_info_calls_borg_with_parameters():
insert_subprocess_mock(INFO_COMMAND)
module.display_archives_info(
verbosity=None,
repository='repo',
storage_config={},
)
def test_display_archives_info_with_verbosity_some_calls_borg_with_info_parameter():
def test_display_archives_info_with_log_info_calls_borg_with_info_parameter():
insert_subprocess_mock(INFO_COMMAND + ('--info',))
insert_logging_mock(logging.INFO)
module.display_archives_info(
repository='repo',
storage_config={},
verbosity=VERBOSITY_SOME,
)
def test_display_archives_info_with_verbosity_lots_calls_borg_with_debug_parameter():
insert_subprocess_mock(INFO_COMMAND + ('--debug',))
def test_display_archives_info_with_log_debug_calls_borg_with_debug_parameter():
insert_subprocess_mock(INFO_COMMAND + ('--debug', '--show-rc'))
insert_logging_mock(logging.DEBUG)
module.display_archives_info(
repository='repo',
storage_config={},
verbosity=VERBOSITY_LOTS,
)
@@ -48,7 +47,6 @@ def test_display_archives_info_with_json_calls_borg_with_json_parameter():
insert_subprocess_mock(INFO_COMMAND + ('--json',))
module.display_archives_info(
verbosity=None,
repository='repo',
storage_config={},
json=True,
@@ -59,7 +57,6 @@ def test_display_archives_info_with_local_path_calls_borg_via_local_path():
insert_subprocess_mock(('borg1',) + INFO_COMMAND[1:])
module.display_archives_info(
verbosity=None,
repository='repo',
storage_config={},
local_path='borg1',
@@ -70,7 +67,6 @@ def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_para
insert_subprocess_mock(INFO_COMMAND + ('--remote-path', 'borg1'))
module.display_archives_info(
verbosity=None,
repository='repo',
storage_config={},
remote_path='borg1',
@@ -82,7 +78,6 @@ def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_paramete
insert_subprocess_mock(INFO_COMMAND + ('--lock-wait', '5'))
module.display_archives_info(
verbosity=None,
repository='repo',
storage_config=storage_config,
)
+7 -11
View File
@@ -1,9 +1,10 @@
import logging
from collections import OrderedDict
from flexmock import flexmock
from borgmatic.borg import list as module
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
from borgmatic.tests.unit.test_verbosity import insert_logging_mock
def insert_subprocess_mock(check_call_command, **kwargs):
@@ -18,29 +19,28 @@ def test_list_archives_calls_borg_with_parameters():
insert_subprocess_mock(LIST_COMMAND)
module.list_archives(
verbosity=None,
repository='repo',
storage_config={},
)
def test_list_archives_with_verbosity_some_calls_borg_with_info_parameter():
def test_list_archives_with_log_info_calls_borg_with_info_parameter():
insert_subprocess_mock(LIST_COMMAND + ('--info',))
insert_logging_mock(logging.INFO)
module.list_archives(
repository='repo',
storage_config={},
verbosity=VERBOSITY_SOME,
)
def test_list_archives_with_verbosity_lots_calls_borg_with_debug_parameter():
insert_subprocess_mock(LIST_COMMAND + ('--debug',))
def test_list_archives_with_log_debug_calls_borg_with_debug_parameter():
insert_subprocess_mock(LIST_COMMAND + ('--debug', '--show-rc'))
insert_logging_mock(logging.DEBUG)
module.list_archives(
repository='repo',
storage_config={},
verbosity=VERBOSITY_LOTS,
)
@@ -48,7 +48,6 @@ def test_list_archives_with_json_calls_borg_with_json_parameter():
insert_subprocess_mock(LIST_COMMAND + ('--json',))
module.list_archives(
verbosity=None,
repository='repo',
storage_config={},
json=True,
@@ -59,7 +58,6 @@ def test_list_archives_with_local_path_calls_borg_via_local_path():
insert_subprocess_mock(('borg1',) + LIST_COMMAND[1:])
module.list_archives(
verbosity=None,
repository='repo',
storage_config={},
local_path='borg1',
@@ -70,7 +68,6 @@ def test_list_archives_with_remote_path_calls_borg_with_remote_path_parameters()
insert_subprocess_mock(LIST_COMMAND + ('--remote-path', 'borg1'))
module.list_archives(
verbosity=None,
repository='repo',
storage_config={},
remote_path='borg1',
@@ -82,7 +79,6 @@ def test_list_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
insert_subprocess_mock(LIST_COMMAND + ('--lock-wait', '5'))
module.list_archives(
verbosity=None,
repository='repo',
storage_config=storage_config,
)
+9 -13
View File
@@ -1,9 +1,10 @@
import logging
from collections import OrderedDict
from flexmock import flexmock
from borgmatic.borg import prune as module
from borgmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
from borgmatic.tests.unit.test_verbosity import insert_logging_mock
def insert_subprocess_mock(check_call_command, **kwargs):
@@ -11,6 +12,7 @@ def insert_subprocess_mock(check_call_command, **kwargs):
subprocess.should_receive('check_call').with_args(check_call_command, **kwargs).once()
BASE_PRUNE_FLAGS = (
('--keep-daily', '1'),
('--keep-weekly', '2'),
@@ -63,7 +65,6 @@ def test_prune_archives_calls_borg_with_parameters():
insert_subprocess_mock(PRUNE_COMMAND)
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
storage_config={},
@@ -71,33 +72,33 @@ def test_prune_archives_calls_borg_with_parameters():
)
def test_prune_archives_with_verbosity_some_calls_borg_with_info_parameter():
def test_prune_archives_with_log_info_calls_borg_with_info_parameter():
retention_config = flexmock()
flexmock(module).should_receive('_make_prune_flags').with_args(retention_config).and_return(
BASE_PRUNE_FLAGS,
)
insert_subprocess_mock(PRUNE_COMMAND + ('--info', '--stats',))
insert_subprocess_mock(PRUNE_COMMAND + ('--stats', '--info',))
insert_logging_mock(logging.INFO)
module.prune_archives(
repository='repo',
storage_config={},
verbosity=VERBOSITY_SOME,
dry_run=False,
retention_config=retention_config,
)
def test_prune_archives_with_verbosity_lots_calls_borg_with_debug_parameter():
def test_prune_archives_with_log_debug_calls_borg_with_debug_parameter():
retention_config = flexmock()
flexmock(module).should_receive('_make_prune_flags').with_args(retention_config).and_return(
BASE_PRUNE_FLAGS,
)
insert_subprocess_mock(PRUNE_COMMAND + ('--debug', '--stats', '--list'))
insert_subprocess_mock(PRUNE_COMMAND + ('--stats', '--debug', '--list', '--show-rc'))
insert_logging_mock(logging.DEBUG)
module.prune_archives(
repository='repo',
storage_config={},
verbosity=VERBOSITY_LOTS,
dry_run=False,
retention_config=retention_config,
)
@@ -113,7 +114,6 @@ def test_prune_archives_with_dry_run_calls_borg_with_dry_run_parameter():
module.prune_archives(
repository='repo',
storage_config={},
verbosity=None,
dry_run=True,
retention_config=retention_config,
)
@@ -127,7 +127,6 @@ def test_prune_archives_with_local_path_calls_borg_via_local_path():
insert_subprocess_mock(('borg1',) + PRUNE_COMMAND[1:])
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
storage_config={},
@@ -144,7 +143,6 @@ def test_prune_archives_with_remote_path_calls_borg_with_remote_path_parameters(
insert_subprocess_mock(PRUNE_COMMAND + ('--remote-path', 'borg1'))
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
storage_config={},
@@ -162,7 +160,6 @@ def test_prune_archives_with_umask_calls_borg_with_umask_parameters():
insert_subprocess_mock(PRUNE_COMMAND + ('--umask', '077'))
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
storage_config=storage_config,
@@ -179,7 +176,6 @@ def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
insert_subprocess_mock(PRUNE_COMMAND + ('--lock-wait', '5'))
module.prune_archives(
verbosity=None,
dry_run=False,
repository='repo',
storage_config=storage_config,
+9
View File
@@ -1,10 +1,19 @@
import logging
from flexmock import flexmock
from borgmatic import verbosity as module
def insert_logging_mock(log_level):
""" Mocks the isEnabledFor from python logging. """
logging = flexmock(module.logging.Logger)
logging.should_receive('isEnabledFor').replace_with(lambda lvl : lvl >= log_level)
logging.should_receive('getEffectiveLevel').replace_with(lambda: log_level)
def test_verbosity_to_log_level_maps_known_verbosity_to_log_level():
assert module.verbosity_to_log_level(module.VERBOSITY_SOME) == logging.INFO
assert module.verbosity_to_log_level(module.VERBOSITY_LOTS) == logging.DEBUG
def test_verbosity_to_log_level_maps_unknown_verbosity_to_warning_level():
+2
View File
@@ -1,6 +1,7 @@
import logging
VERBOSITY_WARNING = 0
VERBOSITY_SOME = 1
VERBOSITY_LOTS = 2
@@ -10,6 +11,7 @@ def verbosity_to_log_level(verbosity):
Given a borgmatic verbosity value, return the corresponding Python log level.
'''
return {
VERBOSITY_WARNING: logging.WARNING,
VERBOSITY_SOME: logging.INFO,
VERBOSITY_LOTS: logging.DEBUG,
}.get(verbosity, logging.WARNING)
+3
View File
@@ -0,0 +1,3 @@
# You can drop this file into /etc/cron.d/ to run borgmatic nightly.
0 3 * * * PATH=$PATH:/usr/bin /usr/bin/borgmatic
+17 -9
View File
@@ -22,22 +22,30 @@ for sub_command in prune create check list info; do
sort borgmatic_borg_flags > borgmatic_borg_flags.sorted
mv borgmatic_borg_flags.sorted borgmatic_borg_flags
for line in $(borg $sub_command --help | awk -v RS= '/^usage:/') ; do
for word in $(borg $sub_command --help | grep '^ -') ; do
# Exclude a bunch of flags that borgmatic actually supports, but don't get exercised by the
# generated sample config, and also flags that don't make sense to support.
echo "$line" | grep -- -- | sed -r 's/(\[|\])//g' \
| grep -v '^-h$' \
echo "$word" | grep ^-- | sed -e 's/,$//' \
| grep -v '^--archives-only$' \
| grep -v '^--repository-only$' \
| grep -v '^--stats$' \
| grep -v '^--list$' \
| grep -v '^--critical$' \
| grep -v '^--error$' \
| grep -v '^--warning$' \
| grep -v '^--info$' \
| grep -v '^--debug$' \
| grep -v '^--dry-run$' \
| grep -v '^--error$' \
| grep -v '^--help$' \
| grep -v '^--info$' \
| grep -v '^--list$' \
| grep -v '^--nobsdflags$' \
| grep -v '^--pattern$' \
| grep -v '^--read-special$' \
| grep -v '^--repository-only$' \
| grep -v '^--show-rc$' \
| grep -v '^--stats$' \
| grep -v '^--verbose$' \
| grep -v '^--warning$' \
| grep -v '^-h$' \
>> all_borg_flags
done
sort all_borg_flags > all_borg_flags.sorted
mv all_borg_flags.sorted all_borg_flags
+2 -2
View File
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
VERSION = '1.2.1'
VERSION = '1.2.3'
setup(
@@ -32,7 +32,7 @@ setup(
'atticmatic',
],
install_requires=(
'pykwalify>=1.6.0',
'pykwalify>=1.6.0,<14.06',
'ruamel.yaml>0.15.0,<0.16.0',
'setuptools',
),
+1 -1
View File
@@ -1,5 +1,5 @@
flexmock==0.10.2
pykwalify==1.6.1
pytest==3.6.3
pytest==3.7.4
pytest-cov==2.5.1
ruamel.yaml>0.15.0,<0.16.0