@@ -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. |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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) |
@@ -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,7 +1,7 @@ | |||
from setuptools import setup, find_packages | |||
VERSION = '1.2.12.dev0' | |||
VERSION = '1.2.12' | |||
setup( |
@@ -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( |
@@ -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') |
@@ -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([]) |
@@ -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 |
@@ -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') |
@@ -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) | |||