Skip to content

Commit

Permalink
After pruning, run attic's consistency checks on all archives.
Browse files Browse the repository at this point in the history
  • Loading branch information
witten committed Feb 14, 2015
1 parent b1113d5 commit eaf2bd2
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 11 deletions.
3 changes: 2 additions & 1 deletion 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.

Expand Down
13 changes: 8 additions & 5 deletions README.md
Expand Up @@ -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:

Expand Down Expand Up @@ -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:
Expand Down
18 changes: 17 additions & 1 deletion atticmatic/attic.py
@@ -1,5 +1,5 @@
from datetime import datetime

import os
import platform
import subprocess

Expand Down Expand Up @@ -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)
6 changes: 4 additions & 2 deletions atticmatic/command.py
Expand Up @@ -3,7 +3,7 @@
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


Expand Down Expand Up @@ -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)
35 changes: 33 additions & 2 deletions atticmatic/tests/unit/test_attic.py
Expand Up @@ -5,9 +5,9 @@
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


Expand Down Expand Up @@ -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',
)

0 comments on commit eaf2bd2

Please sign in to comment.