After pruning, run attic's consistency checks on all archives.
This commit is contained in:
parent
6d4e40a819
commit
e3fa18b892
5 changed files with 64 additions and 11 deletions
3
NEWS
3
NEWS
|
@ -1,5 +1,6 @@
|
|||
default
|
||||
0.0.3
|
||||
|
||||
* After pruning, run attic's consistency checks on all archives.
|
||||
* Integration tests for argument parsing.
|
||||
* Documentation updates about repository encryption.
|
||||
|
||||
|
|
13
README.md
13
README.md
|
@ -5,10 +5,11 @@ save_as: atticmatic/index.html
|
|||
## Overview
|
||||
|
||||
atticmatic is a simple Python wrapper script for the [Attic backup
|
||||
software](https://attic-backup.org/) that initiates a backup and prunes any
|
||||
old backups according to a retention policy. 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.
|
||||
software](https://attic-backup.org/) 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:
|
||||
|
||||
|
@ -68,7 +69,9 @@ arguments:
|
|||
|
||||
atticmatic
|
||||
|
||||
This will also prune any old backups as per the configured retention policy.
|
||||
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.
|
||||
|
||||
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 verbose option instead:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from datetime import datetime
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
|
@ -63,3 +63,19 @@ def prune_archives(verbose, repository, retention_config):
|
|||
) + (('--verbose',) if verbose else ())
|
||||
|
||||
subprocess.check_call(command)
|
||||
|
||||
|
||||
def check_archives(verbose, repository):
|
||||
'''
|
||||
Given a verbosity flag and a local or remote repository path, check the contained attic archives
|
||||
for consistency.
|
||||
'''
|
||||
command = (
|
||||
'attic', 'check',
|
||||
repository,
|
||||
) + (('--verbose',) if verbose else ())
|
||||
|
||||
# Attic's check command spews to stdout even without the verbose flag. Suppress it.
|
||||
stdout = None if verbose else open(os.devnull, 'w')
|
||||
|
||||
subprocess.check_call(command, stdout=stdout)
|
||||
|
|
|
@ -3,7 +3,7 @@ from argparse import ArgumentParser
|
|||
from subprocess import CalledProcessError
|
||||
import sys
|
||||
|
||||
from atticmatic.attic import create_archive, prune_archives
|
||||
from atticmatic.attic import check_archives, create_archive, prune_archives
|
||||
from atticmatic.config import parse_configuration
|
||||
|
||||
|
||||
|
@ -41,9 +41,11 @@ def main():
|
|||
try:
|
||||
args = parse_arguments(*sys.argv[1:])
|
||||
location_config, retention_config = parse_configuration(args.config_filename)
|
||||
repository = location_config['repository']
|
||||
|
||||
create_archive(args.excludes_filename, args.verbose, **location_config)
|
||||
prune_archives(args.verbose, location_config['repository'], retention_config)
|
||||
prune_archives(args.verbose, repository, retention_config)
|
||||
check_archives(args.verbose, repository)
|
||||
except (ValueError, IOError, CalledProcessError) as error:
|
||||
print(error, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
|
|
@ -5,9 +5,9 @@ from flexmock import flexmock
|
|||
from atticmatic import attic as module
|
||||
|
||||
|
||||
def insert_subprocess_mock(check_call_command):
|
||||
def insert_subprocess_mock(check_call_command, **kwargs):
|
||||
subprocess = flexmock()
|
||||
subprocess.should_receive('check_call').with_args(check_call_command).once()
|
||||
subprocess.should_receive('check_call').with_args(check_call_command, **kwargs).once()
|
||||
flexmock(module).subprocess = subprocess
|
||||
|
||||
|
||||
|
@ -111,3 +111,34 @@ def test_prune_archives_with_verbose_should_call_attic_with_verbose_parameters()
|
|||
verbose=True,
|
||||
retention_config=retention_config,
|
||||
)
|
||||
|
||||
|
||||
def test_check_archives_should_call_attic_with_parameters():
|
||||
stdout = flexmock()
|
||||
insert_subprocess_mock(
|
||||
('attic', 'check', 'repo'),
|
||||
stdout=stdout,
|
||||
)
|
||||
insert_platform_mock()
|
||||
insert_datetime_mock()
|
||||
flexmock(module).open = lambda filename, mode: stdout
|
||||
flexmock(module).os = flexmock().should_receive('devnull').mock
|
||||
|
||||
module.check_archives(
|
||||
verbose=False,
|
||||
repository='repo',
|
||||
)
|
||||
|
||||
|
||||
def test_check_archives_with_verbose_should_call_attic_with_verbose_parameters():
|
||||
insert_subprocess_mock(
|
||||
('attic', 'check', 'repo', '--verbose'),
|
||||
stdout=None,
|
||||
)
|
||||
insert_platform_mock()
|
||||
insert_datetime_mock()
|
||||
|
||||
module.check_archives(
|
||||
verbose=True,
|
||||
repository='repo',
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue