浏览代码

Support for Borg repository initialization via borgmatic --init command-line flag (#110).

tags/1.2.12
Dan Helfman 9 个月前
父节点
当前提交
cc9dbb1def

+ 4
- 2
NEWS 查看文件

@@ -1,7 +1,9 @@
1.2.12.dev0
1.2.12
* #110: Support for Borg repository initialization via borgmatic --init command-line flag.
* #111: Update Borg create --filter values so a dry run lists files to back up.
* #113: Update README with link to a new/forked Docker image.
* Error when deprecated --excludes command-line option is used.
* Prevent deprecated --excludes command-line option from being used.
* Refactor README a bit to flow better for first-time users.

1.2.11
* #108: Support for Borg create --progress via borgmatic command-line flag.

+ 159
- 128
README.md 查看文件

@@ -58,28 +58,9 @@ href="https://asciinema.org/a/203761" target="_blank">screencast</a>.

To get up and running, first [install
Borg](https://borgbackup.readthedocs.io/en/latest/installation.html), at
least version 1.1. Then, follow the [Borg Quick
Start](https://borgbackup.readthedocs.org/en/latest/quickstart.html) to create
a repository on a local or remote host.
least version 1.1.

Note that if you plan to run borgmatic on a schedule with cron, and you
encrypt your Borg repository with a passphrase instead of a key file, you'll
either need to set the borgmatic `encryption_passphrase` configuration
variable or set the `BORG_PASSPHRASE` environment variable. See the
[repository encryption
section](https://borgbackup.readthedocs.io/en/latest/quickstart.html#repository-encryption)
of the Quick Start for more info.

Alternatively, the passphrase can be specified programatically by setting
either the borgmatic `encryption_passcommand` configuration variable or the
`BORG_PASSCOMMAND` environment variable. See the [Borg Security
FAQ](http://borgbackup.readthedocs.io/en/stable/faq.html#how-can-i-specify-the-encryption-passphrase-programmatically)
for more info.

If the repository is on a remote host, make sure that your local root user has
key-based ssh access to the desired user account on the remote host.

To install borgmatic, run the following command to download and install it:
Then, run the following command to download and install borgmatic:

```bash
sudo pip3 install --upgrade borgmatic
@@ -88,6 +69,7 @@ sudo pip3 install --upgrade borgmatic
Note that your pip binary may have a different name than "pip3". Make sure
you're using Python 3, as borgmatic does not support Python 2.


### Other ways to install

* [A borgmatic Docker image](https://hub.docker.com/r/monachus/borgmatic/) based
@@ -101,6 +83,7 @@ you're using Python 3, as borgmatic does not support Python 2.
* [A borgmatic package for OpenBSD](http://ports.su/sysutils/borgmatic).
<br><br>


## Configuration

After you install borgmatic, generate a sample configuration file:
@@ -124,6 +107,161 @@ borgmatic has added new options since you originally created your
configuration file.


### Encryption

Note that if you plan to run borgmatic on a schedule with cron, and you
encrypt your Borg repository with a passphrase instead of a key file, you'll
either need to set the borgmatic `encryption_passphrase` configuration
variable or set the `BORG_PASSPHRASE` environment variable. See the
[repository encryption
section](https://borgbackup.readthedocs.io/en/latest/quickstart.html#repository-encryption)
of the Quick Start for more info.

Alternatively, the passphrase can be specified programatically by setting
either the borgmatic `encryption_passcommand` configuration variable or the
`BORG_PASSCOMMAND` environment variable. See the [Borg Security
FAQ](http://borgbackup.readthedocs.io/en/stable/faq.html#how-can-i-specify-the-encryption-passphrase-programmatically)
for more info.


## Usage

### Initialization

Before you can create backups with borgmatic, you first need to initialize a
Borg repository so you have a destination for your backup archives. (But skip
this step if you already have a Borg repository.) To create a repository, run
a command like the following:

```bash
borgmatic --init --encryption repokey
```

This uses the borgmatic configuration file you created above to determine
which local or remote repository to create, and encrypts it with the
encryption passphrase specified there if one is provided. Read about [Borg
encryption
modes](https://borgbackup.readthedocs.io/en/latest/usage/init.html#encryption-modes)
for the menu of available encryption modes.

Also, optionally check out the [Borg Quick
Start](https://borgbackup.readthedocs.org/en/latest/quickstart.html) for more
background about repository initialization.

If the repository is on a remote host, make sure that your local user has
key-based SSH access to the desired user account on the remote host.


### Backups

You can run borgmatic and start a backup simply by invoking it without
arguments:

```bash
borgmatic
```

This will also prune any old backups as per the configured retention policy,
and check backups for consistency problems due to things like file damage.

If you'd like to see the available command-line arguments, view the help:

```bash
borgmatic --help
```

Note that borgmatic prunes archives *before* creating an archive, so as to
free up space for archiving. This means that when a borgmatic run finishes,
there may still be prune-able archives. Not to worry, as they will get cleaned
up at the start of the next run.


### Verbosity

By default, the backup will proceed silently except in the case of errors. But
if you'd like to to get additional information about the progress of the
backup as it proceeds, use the verbosity option:

```bash
borgmatic --verbosity 1
```

Or, for even more progress spew:

```bash
borgmatic --verbosity 2
```

### À la carte

If you want to run borgmatic with only pruning, creating, or checking enabled,
the following optional flags are available:

```bash
borgmatic --prune
borgmatic --create
borgmatic --check
```

You can run with only one of these flags provided, or you can mix and match
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 `--create`, `--list`, or
`--info` to get the output formatted as JSON.


## Autopilot

If you want to run borgmatic automatically, say once a day, the you can
configure a job runner to invoke it periodically.

### cron

If you're using cron, download the [sample cron
file](https://projects.torsion.org/witten/borgmatic/src/master/sample/cron/borgmatic).
Then, from the directory where you downloaded it:

```bash
sudo mv borgmatic /etc/cron.d/borgmatic
sudo chmod +x /etc/cron.d/borgmatic
```

You can modify the cron file if you'd like to run borgmatic more or less frequently.

### systemd

If you're using systemd instead of cron to run jobs, download the [sample
systemd service
file](https://projects.torsion.org/witten/borgmatic/src/master/sample/systemd/borgmatic.service)
and the [sample systemd timer
file](https://projects.torsion.org/witten/borgmatic/src/master/sample/systemd/borgmatic.timer).
Then, from the directory where you downloaded them:

```bash
sudo mv borgmatic.service borgmatic.timer /etc/systemd/system/
sudo systemctl enable borgmatic.timer
sudo systemctl start borgmatic.timer
```

Feel free to modify the timer file based on how frequently you'd like
borgmatic to run.


## Advanced configuration

### Multiple configuration files

A more advanced usage is to create multiple separate configuration files and
@@ -247,113 +385,6 @@ That's it! borgmatic will continue using your /etc/borgmatic configuration
files.


## Usage

You can run borgmatic and start a backup simply by invoking it without
arguments:

```bash
borgmatic
```

This will also prune any old backups as per the configured retention policy,
and check backups for consistency problems due to things like file damage.

If you'd like to see the available command-line arguments, view the help:

```bash
borgmatic --help
```

Note that borgmatic prunes archives *before* creating an archive, so as to
free up space for archiving. This means that when a borgmatic run finishes,
there may still be prune-able archives. Not to worry, as they will get cleaned
up at the start of the next run.

### Verbosity

By default, the backup will proceed silently except in the case of errors. But
if you'd like to to get additional information about the progress of the
backup as it proceeds, use the verbosity option:

```bash
borgmatic --verbosity 1
```

Or, for even more progress spew:

```bash
borgmatic --verbosity 2
```

### À la carte

If you want to run borgmatic with only pruning, creating, or checking enabled,
the following optional flags are available:

```bash
borgmatic --prune
borgmatic --create
borgmatic --check
```

You can run with only one of these flags provided, or you can mix and match
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 `--create`, `--list`, or
`--info` to get the output formatted as JSON.


## Autopilot

If you want to run borgmatic automatically, say once a day, the you can
configure a job runner to invoke it periodically.

### cron

If you're using cron, download the [sample cron
file](https://projects.torsion.org/witten/borgmatic/src/master/sample/cron/borgmatic).
Then, from the directory where you downloaded it:

```bash
sudo mv borgmatic /etc/cron.d/borgmatic
sudo chmod +x /etc/cron.d/borgmatic
```

You can modify the cron file if you'd like to run borgmatic more or less frequently.

### systemd

If you're using systemd instead of cron to run jobs, download the [sample
systemd service
file](https://projects.torsion.org/witten/borgmatic/src/master/sample/systemd/borgmatic.service)
and the [sample systemd timer
file](https://projects.torsion.org/witten/borgmatic/src/master/sample/systemd/borgmatic.timer).
Then, from the directory where you downloaded them:

```bash
sudo mv borgmatic.service borgmatic.timer /etc/systemd/system/
sudo systemctl enable borgmatic.timer
sudo systemctl start borgmatic.timer
```

Feel free to modify the timer file based on how frequently you'd like
borgmatic to run.


## Support and contributing

### Issues

+ 0
- 14
borgmatic/borg/create.py 查看文件

@@ -9,20 +9,6 @@ import tempfile
logger = logging.getLogger(__name__)


def initialize_environment(storage_config):
passcommand = storage_config.get('encryption_passcommand')
if passcommand:
os.environ['BORG_PASSCOMMAND'] = passcommand

passphrase = storage_config.get('encryption_passphrase')
if passphrase:
os.environ['BORG_PASSPHRASE'] = passphrase

ssh_command = storage_config.get('ssh_command')
if ssh_command:
os.environ['BORG_RSH'] = ssh_command


def _expand_directory(directory):
'''
Given a directory path, expand any tilde (representing a user's home directory) and any globs

+ 15
- 0
borgmatic/borg/environment.py 查看文件

@@ -0,0 +1,15 @@
import os


def initialize(storage_config):
passcommand = storage_config.get('encryption_passcommand')
if passcommand:
os.environ['BORG_PASSCOMMAND'] = passcommand

passphrase = storage_config.get('encryption_passphrase')
if passphrase:
os.environ['BORG_PASSPHRASE'] = passphrase

ssh_command = storage_config.get('ssh_command')
if ssh_command:
os.environ['BORG_RSH'] = ssh_command

+ 31
- 0
borgmatic/borg/init.py 查看文件

@@ -0,0 +1,31 @@
import logging
import subprocess


logger = logging.getLogger(__name__)


def initialize_repository(
repository,
encryption_mode,
append_only=None,
storage_quota=None,
local_path='borg',
remote_path=None,
):
'''
Given a local or remote repository path, a Borg encryption mode, whether the repository should
be append-only, and the storage quota to use, initialize the repository.
'''
full_command = (
(local_path, 'init', repository)
+ (('--encryption', encryption_mode) if encryption_mode else ())
+ (('--append-only',) if append_only else ())
+ (('--storage-quota', storage_quota) if storage_quota else ())
+ (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
+ (('--debug',) if logger.isEnabledFor(logging.DEBUG) else ())
+ (('--remote-path', remote_path) if remote_path else ())
)

logger.debug(' '.join(full_command))
subprocess.check_call(full_command)

+ 49
- 3
borgmatic/commands/borgmatic.py 查看文件

@@ -8,9 +8,11 @@ import sys
from borgmatic.borg import (
check as borg_check,
create as borg_create,
environment as borg_environment,
prune as borg_prune,
list as borg_list,
info as borg_info,
init as borg_init,
)
from borgmatic.commands import hook
from borgmatic.config import checks, collect, convert, validate
@@ -53,6 +55,26 @@ def parse_arguments(*arguments):
dest='excludes_filename',
help='Deprecated in favor of exclude_patterns within configuration',
)
parser.add_argument(
'-I', '--init', dest='init', action='store_true', help='Initialize an empty Borg repository'
)
parser.add_argument(
'-e',
'--encryption',
dest='encryption_mode',
help='Borg repository encryption mode (for use with --init)',
)
parser.add_argument(
'--append-only',
dest='append_only',
action='store_true',
help='Create an append-only repository (for use with --init)',
)
parser.add_argument(
'--storage-quota',
dest='storage_quota',
help='Create a repository with a fixed storage quota (for use with --init)',
)
parser.add_argument(
'-p',
'--prune',
@@ -111,7 +133,21 @@ def parse_arguments(*arguments):
args = parser.parse_args(arguments)

if args.excludes_filename:
raise ValueError('The --excludes option has been replaced with exclude_patterns in configuration')
raise ValueError(
'The --excludes option has been replaced with exclude_patterns in configuration'
)

if (args.encryption_mode or args.append_only or args.storage_quota) and not args.init:
raise ValueError(
'The --encryption, --append-only, and --storage-quota options can only be used with the --init option'
)

if args.init and (args.prune or args.create or args.dry_run):
raise ValueError(
'The --init option cannot be used with the --prune, --create, or --dry-run options'
)
if args.init and not args.encryption_mode:
raise ValueError('The --encryption option is required with the --init option')

if args.progress and not args.create:
raise ValueError('The --progress option can only be used with the --create option')
@@ -128,7 +164,7 @@ def parse_arguments(*arguments):

# If any of the action flags are explicitly requested, leave them as-is. Otherwise, assume
# defaults: Mutate the given arguments to enable the default actions.
if args.prune or args.create or args.check or args.list or args.info:
if args.init or args.prune or args.create or args.check or args.list or args.info:
return args

args.prune = True
@@ -152,7 +188,7 @@ def run_configuration(config_filename, args): # pragma: no cover
try:
local_path = location.get('local_path', 'borg')
remote_path = location.get('remote_path')
borg_create.initialize_environment(storage)
borg_environment.initialize(storage)

if args.create:
hook.execute_hook(hooks.get('before_backup'), config_filename, 'pre-backup')
@@ -206,6 +242,16 @@ def _run_commands_on_repository(
): # pragma: no cover
repository = os.path.expanduser(unexpanded_repository)
dry_run_label = ' (dry run; not making any changes)' if args.dry_run else ''
if args.init:
logger.info('{}: Initializing repository'.format(repository))
borg_init.initialize_repository(
repository,
args.encryption_mode,
args.append_only,
args.storage_quota,
local_path=local_path,
remote_path=remote_path,
)
if args.prune:
logger.info('{}: Pruning archives{}'.format(repository, dry_run_label))
borg_prune.prune_archives(

+ 1
- 1
setup.py 查看文件

@@ -1,7 +1,7 @@
from setuptools import setup, find_packages


VERSION = '1.2.12.dev0'
VERSION = '1.2.12'


setup(

+ 7
- 6
tests/end-to-end/test_borgmatic.py 查看文件

@@ -9,7 +9,8 @@ import tempfile
def generate_configuration(config_path, repository_path):
'''
Generate borgmatic configuration into a file at the config path, and update the defaults so as
to work for testing (including injecting the given repository path).
to work for testing (including injecting the given repository path and tacking on an encryption
passphrase).
'''
subprocess.check_call(
'generate-borgmatic-config --destination {}'.format(config_path).split(' ')
@@ -21,6 +22,7 @@ def generate_configuration(config_path, repository_path):
.replace('- /home', '- {}'.format(config_path))
.replace('- /etc', '')
.replace('- /var/log/syslog*', '')
+ 'storage:\n encryption_passphrase: "test"'
)
config_file = open(config_path, 'w')
config_file.write(config)
@@ -33,14 +35,13 @@ def test_borgmatic_command():
repository_path = os.path.join(temporary_directory, 'test.borg')

try:
subprocess.check_call(
'borg init --encryption repokey {}'.format(repository_path).split(' '),
env={'BORG_PASSPHRASE': '', **os.environ},
)

config_path = os.path.join(temporary_directory, 'test.yaml')
generate_configuration(config_path, repository_path)

subprocess.check_call(
'borgmatic -v 2 --config {} --init --encryption repokey'.format(config_path).split(' ')
)

# Run borgmatic to generate a backup archive, and then list it to make sure it exists.
subprocess.check_call('borgmatic --config {}'.format(config_path).split(' '))
output = subprocess.check_output(

+ 63
- 14
tests/integration/commands/test_borgmatic.py 查看文件

@@ -16,13 +16,6 @@ def test_parse_arguments_with_no_arguments_uses_defaults():
assert parser.json is False


def test_parse_arguments_disallows_deprecated_excludes_option():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--excludes', 'myexcludes')


def test_parse_arguments_with_multiple_config_paths_parses_as_list():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

@@ -32,7 +25,7 @@ def test_parse_arguments_with_multiple_config_paths_parses_as_list():
assert parser.verbosity is 0


def test_parse_arguments_with_verbosity_flag_overrides_default():
def test_parse_arguments_with_verbosity_overrides_default():
config_paths = ['default']
flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)

@@ -43,7 +36,7 @@ def test_parse_arguments_with_verbosity_flag_overrides_default():
assert parser.verbosity == 1


def test_parse_arguments_with_json_flag_overrides_default():
def test_parse_arguments_with_json_overrides_default():
parser = module.parse_arguments('--list', '--json')
assert parser.json is True

@@ -85,25 +78,81 @@ def test_parse_arguments_with_invalid_arguments_exits():
module.parse_arguments('--posix-me-harder')


def test_parse_arguments_with_progress_and_create_flags_does_not_raise():
def test_parse_arguments_disallows_deprecated_excludes_option():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--excludes', 'myexcludes')


def test_parse_arguments_disallows_encryption_mode_without_init():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--encryption', 'repokey')


def test_parse_arguments_requires_encryption_mode_with_init():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--init')


def test_parse_arguments_disallows_append_only_without_init():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--append-only')


def test_parse_arguments_disallows_storage_quota_without_init():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--storage-quota', '5G')


def test_parse_arguments_disallows_init_and_prune():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--init', '--prune')


def test_parse_arguments_disallows_init_and_create():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--init', '--create')


def test_parse_arguments_disallows_init_and_dry_run():
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])

with pytest.raises(ValueError):
module.parse_arguments('--config', 'myconfig', '--init', '--dry-run')


def test_parse_arguments_allows_progress_and_create():
module.parse_arguments('--progress', '--create', '--list')


def test_parse_arguments_with_progress_flag_but_no_create_flag_raises_value_error():
def test_parse_arguments_disallows_progress_without_create():
with pytest.raises(ValueError):
module.parse_arguments('--progress', '--list')


def test_parse_arguments_with_json_flag_with_list_or_info_flag_does_not_raise_any_error():
def test_parse_arguments_allows_json_with_list_or_info():
module.parse_arguments('--list', '--json')
module.parse_arguments('--info', '--json')


def test_parse_arguments_with_json_flag_but_no_list_or_info_flag_raises_value_error():
def test_parse_arguments_disallows_json_without_list_or_info():
with pytest.raises(ValueError):
module.parse_arguments('--json')


def test_parse_arguments_with_json_flag_and_both_list_and_info_flag_raises_value_error():
def test_parse_arguments_disallows_json_with_both_list_and_info():
with pytest.raises(ValueError):
module.parse_arguments('--list', '--info', '--json')

+ 0
- 47
tests/unit/borg/test_create.py 查看文件

@@ -1,5 +1,4 @@
import logging
import os

from flexmock import flexmock

@@ -7,52 +6,6 @@ from borgmatic.borg import create as module
from ..test_verbosity import insert_logging_mock


def test_initialize_environment_with_passcommand_should_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize_environment({'encryption_passcommand': 'command'})
assert os.environ.get('BORG_PASSCOMMAND') == 'command'
finally:
os.environ = orig_environ


def test_initialize_environment_with_passphrase_should_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize_environment({'encryption_passphrase': 'pass'})
assert os.environ.get('BORG_PASSPHRASE') == 'pass'
finally:
os.environ = orig_environ


def test_initialize_environment_with_ssh_command_should_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize_environment({'ssh_command': 'ssh -C'})
assert os.environ.get('BORG_RSH') == 'ssh -C'
finally:
os.environ = orig_environ


def test_initialize_environment_without_configuration_should_not_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize_environment({})
assert os.environ.get('BORG_PASSCOMMAND') is None
assert os.environ.get('BORG_PASSPHRASE') is None
assert os.environ.get('BORG_RSH') is None
finally:
os.environ = orig_environ


def test_expand_directory_with_basic_path_passes_it_through():
flexmock(module.os.path).should_receive('expanduser').and_return('foo')
flexmock(module.glob).should_receive('glob').and_return([])

+ 49
- 0
tests/unit/borg/test_environment.py 查看文件

@@ -0,0 +1,49 @@
import os

from borgmatic.borg import environment as module


def test_initialize_with_passcommand_should_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize({'encryption_passcommand': 'command'})
assert os.environ.get('BORG_PASSCOMMAND') == 'command'
finally:
os.environ = orig_environ


def test_initialize_with_passphrase_should_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize({'encryption_passphrase': 'pass'})
assert os.environ.get('BORG_PASSPHRASE') == 'pass'
finally:
os.environ = orig_environ


def test_initialize_with_ssh_command_should_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize({'ssh_command': 'ssh -C'})
assert os.environ.get('BORG_RSH') == 'ssh -C'
finally:
os.environ = orig_environ


def test_initialize_without_configuration_should_not_set_environment():
orig_environ = os.environ

try:
os.environ = {}
module.initialize({})
assert os.environ.get('BORG_PASSCOMMAND') is None
assert os.environ.get('BORG_PASSPHRASE') is None
assert os.environ.get('BORG_RSH') is None
finally:
os.environ = orig_environ

+ 58
- 0
tests/unit/borg/test_init.py 查看文件

@@ -0,0 +1,58 @@
import logging

from flexmock import flexmock

from borgmatic.borg import init as module
from ..test_verbosity import insert_logging_mock


def insert_subprocess_mock(check_call_command, **kwargs):
subprocess = flexmock(module.subprocess)
subprocess.should_receive('check_call').with_args(check_call_command, **kwargs).once()


INIT_COMMAND = ('borg', 'init', 'repo', '--encryption', 'repokey')


def test_initialize_repository_calls_borg_with_parameters():
insert_subprocess_mock(INIT_COMMAND)

module.initialize_repository(repository='repo', encryption_mode='repokey')


def test_initialize_repository_with_append_only_calls_borg_with_append_only_parameter():
insert_subprocess_mock(INIT_COMMAND + ('--append-only',))

module.initialize_repository(repository='repo', encryption_mode='repokey', append_only=True)


def test_initialize_repository_with_storage_quota_calls_borg_with_storage_quota_parameter():
insert_subprocess_mock(INIT_COMMAND + ('--storage-quota', '5G'))

module.initialize_repository(repository='repo', encryption_mode='repokey', storage_quota='5G')


def test_initialize_repository_with_log_info_calls_borg_with_info_parameter():
insert_subprocess_mock(INIT_COMMAND + ('--info',))
insert_logging_mock(logging.INFO)

module.initialize_repository(repository='repo', encryption_mode='repokey')


def test_initialize_repository_with_log_debug_calls_borg_with_debug_parameter():
insert_subprocess_mock(INIT_COMMAND + ('--debug',))
insert_logging_mock(logging.DEBUG)

module.initialize_repository(repository='repo', encryption_mode='repokey')


def test_initialize_repository_with_local_path_calls_borg_via_local_path():
insert_subprocess_mock(('borg1',) + INIT_COMMAND[1:])

module.initialize_repository(repository='repo', encryption_mode='repokey', local_path='borg1')


def test_initialize_repository_with_remote_path_calls_borg_with_remote_path_parameter():
insert_subprocess_mock(INIT_COMMAND + ('--remote-path', 'borg1'))

module.initialize_repository(repository='repo', encryption_mode='repokey', remote_path='borg1')

+ 4
- 2
tests/unit/test_verbosity.py 查看文件

@@ -6,9 +6,11 @@ from borgmatic import verbosity as module


def insert_logging_mock(log_level):
""" Mocks the isEnabledFor from python logging. """
'''
Mock the isEnabledFor from Python logging.
'''
logging = flexmock(module.logging.Logger)
logging.should_receive('isEnabledFor').replace_with(lambda lvl: lvl >= log_level)
logging.should_receive('isEnabledFor').replace_with(lambda level: level >= log_level)
logging.should_receive('getEffectiveLevel').replace_with(lambda: log_level)



正在加载...
取消
保存