Răsfoiți Sursa

Flag for multiple levels of verbosity: some, and lots.

Dan Helfman 10 ani în urmă
părinte
comite
b501a568aa

+ 2 - 1
NEWS

@@ -1,5 +1,6 @@
-0.0.7-dev
+0.0.7
 
+ * Flag for multiple levels of verbosity: some, and lots.
  * Improved mocking of Python builtins in unit tests.
 
 0.0.6

+ 6 - 2
README.md

@@ -78,9 +78,13 @@ 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:
+backup as it proceeds, use the verbosity option:
 
-    atticmattic --verbose
+    atticmattic --verbosity 1
+
+Or, for even more progress spew:
+
+    atticmattic --verbosity 2
 
 If you'd like to see the available command-line arguments, view the help:
 

+ 23 - 9
atticmatic/attic.py

@@ -3,13 +3,19 @@ import os
 import platform
 import subprocess
 
+from atticmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
 
-def create_archive(excludes_filename, verbose, source_directories, repository):
+
+def create_archive(excludes_filename, verbosity, source_directories, repository):
     '''
     Given an excludes filename, a vebosity flag, a space-separated list of source directories, and
     a local or remote repository path, create an attic archive.
     '''
     sources = tuple(source_directories.split(' '))
+    verbosity_flags = {
+        VERBOSITY_SOME: ('--stats',),
+        VERBOSITY_LOTS: ('--verbose', '--stats'),
+    }.get(verbosity, ())
 
     command = (
         'attic', 'create',
@@ -19,9 +25,7 @@ def create_archive(excludes_filename, verbose, source_directories, repository):
             hostname=platform.node(),
             timestamp=datetime.now().isoformat(),
         ),
-    ) + sources + (
-        ('--verbose', '--stats') if verbose else ()
-    )
+    ) + sources + verbosity_flags
 
     subprocess.check_call(command)
 
@@ -48,11 +52,16 @@ def _make_prune_flags(retention_config):
     )
 
 
-def prune_archives(verbose, repository, retention_config):
+def prune_archives(verbosity, repository, retention_config):
     '''
     Given a verbosity flag, a local or remote repository path, and a retention config dict, prune
     attic archives according the the retention policy specified in that configuration.
     '''
+    verbosity_flags = {
+        VERBOSITY_SOME: ('--stats',),
+        VERBOSITY_LOTS: ('--verbose', '--stats'),
+    }.get(verbosity, ())
+
     command = (
         'attic', 'prune',
         repository,
@@ -60,7 +69,7 @@ def prune_archives(verbose, repository, retention_config):
         element
         for pair in _make_prune_flags(retention_config)
         for element in pair
-    ) + (('--verbose',) if verbose else ())
+    ) + verbosity_flags
 
     subprocess.check_call(command)
 
@@ -114,7 +123,7 @@ def _make_check_flags(checks):
     )
 
 
-def check_archives(verbose, repository, consistency_config):
+def check_archives(verbosity, repository, consistency_config):
     '''
     Given a verbosity flag, a local or remote repository path, and a consistency config dict, check
     the contained attic archives for consistency.
@@ -125,12 +134,17 @@ def check_archives(verbose, repository, consistency_config):
     if not checks:
         return
 
+    verbosity_flags = {
+        VERBOSITY_SOME: ('--verbose',),
+        VERBOSITY_LOTS: ('--verbose',),
+    }.get(verbosity, ())
+
     command = (
         'attic', 'check',
         repository,
-    ) + _make_check_flags(checks) + (('--verbose',) if verbose else ())
+    ) + _make_check_flags(checks) + verbosity_flags
 
     # Attic's check command spews to stdout even without the verbose flag. Suppress it.
-    stdout = None if verbose else open(os.devnull, 'w')
+    stdout = None if verbosity_flags else open(os.devnull, 'w')
 
     subprocess.check_call(command, stdout=stdout)

+ 6 - 6
atticmatic/command.py

@@ -29,9 +29,9 @@ def parse_arguments(*arguments):
         help='Excludes filename',
     )
     parser.add_argument(
-        '-v', '--verbose',
-        action='store_true',
-        help='Display verbose progress information',
+        '-v', '--verbosity',
+        type=int,
+        help='Display verbose progress (1 for some, 2 for lots)',
     )
 
     return parser.parse_args(arguments)
@@ -43,9 +43,9 @@ def main():
         config = parse_configuration(args.config_filename)
         repository = config.location['repository']
 
-        create_archive(args.excludes_filename, args.verbose, **config.location)
-        prune_archives(args.verbose, repository, config.retention)
-        check_archives(args.verbose, repository, config.consistency)
+        create_archive(args.excludes_filename, args.verbosity, **config.location)
+        prune_archives(args.verbosity, repository, config.retention)
+        check_archives(args.verbosity, repository, config.consistency)
     except (ValueError, IOError, CalledProcessError) as error:
         print(error, file=sys.stderr)
         sys.exit(1)

+ 5 - 5
atticmatic/tests/integration/test_command.py

@@ -10,7 +10,7 @@ def test_parse_arguments_with_no_arguments_uses_defaults():
 
     assert parser.config_filename == module.DEFAULT_CONFIG_FILENAME
     assert parser.excludes_filename == module.DEFAULT_EXCLUDES_FILENAME
-    assert parser.verbose == False
+    assert parser.verbosity == None
 
 
 def test_parse_arguments_with_filename_arguments_overrides_defaults():
@@ -18,15 +18,15 @@ def test_parse_arguments_with_filename_arguments_overrides_defaults():
 
     assert parser.config_filename == 'myconfig'
     assert parser.excludes_filename == 'myexcludes'
-    assert parser.verbose == False
+    assert parser.verbosity == None
 
 
-def test_parse_arguments_with_verbose_flag_overrides_default():
-    parser = module.parse_arguments('--verbose')
+def test_parse_arguments_with_verbosity_flag_overrides_default():
+    parser = module.parse_arguments('--verbosity', '1')
 
     assert parser.config_filename == module.DEFAULT_CONFIG_FILENAME
     assert parser.excludes_filename == module.DEFAULT_EXCLUDES_FILENAME
-    assert parser.verbose == True
+    assert parser.verbosity == 1
 
 
 def test_parse_arguments_with_invalid_arguments_exits():

+ 66 - 29
atticmatic/tests/unit/test_attic.py

@@ -4,6 +4,7 @@ from flexmock import flexmock
 
 from atticmatic import attic as module
 from atticmatic.tests.builtins import builtins_mock
+from atticmatic.verbosity import VERBOSITY_SOME, VERBOSITY_LOTS
 
 
 def insert_subprocess_mock(check_call_command, **kwargs):
@@ -28,34 +29,43 @@ def insert_datetime_mock():
     ).mock
 
 
+CREATE_COMMAND = ('attic', 'create', '--exclude-from', 'excludes', 'repo::host-now', 'foo', 'bar')
+
+
 def test_create_archive_should_call_attic_with_parameters():
-    insert_subprocess_mock(
-        ('attic', 'create', '--exclude-from', 'excludes', 'repo::host-now', 'foo', 'bar'),
-    )
+    insert_subprocess_mock(CREATE_COMMAND)
     insert_platform_mock()
     insert_datetime_mock()
 
     module.create_archive(
         excludes_filename='excludes',
-        verbose=False,
+        verbosity=None,
         source_directories='foo bar',
         repository='repo',
     )
 
 
-def test_create_archive_with_verbose_should_call_attic_with_verbose_parameters():
-    insert_subprocess_mock(
-        (
-            'attic', 'create', '--exclude-from', 'excludes', 'repo::host-now', 'foo', 'bar',
-            '--verbose', '--stats',
-        ),
+def test_create_archive_with_verbosity_some_should_call_attic_with_stats_parameter():
+    insert_subprocess_mock(CREATE_COMMAND + ('--stats',))
+    insert_platform_mock()
+    insert_datetime_mock()
+
+    module.create_archive(
+        excludes_filename='excludes',
+        verbosity=VERBOSITY_SOME,
+        source_directories='foo bar',
+        repository='repo',
     )
+
+
+def test_create_archive_with_verbosity_lots_should_call_attic_with_verbose_parameter():
+    insert_subprocess_mock(CREATE_COMMAND + ('--verbose', '--stats'))
     insert_platform_mock()
     insert_datetime_mock()
 
     module.create_archive(
         excludes_filename='excludes',
-        verbose=True,
+        verbosity=VERBOSITY_LOTS,
         source_directories='foo bar',
         repository='repo',
     )
@@ -82,40 +92,49 @@ def test_make_prune_flags_should_return_flags_from_config():
     assert tuple(result) == BASE_PRUNE_FLAGS
 
 
+PRUNE_COMMAND = (
+    'attic', 'prune', 'repo', '--keep-daily', '1', '--keep-weekly', '2', '--keep-monthly', '3',
+)
+
+
 def test_prune_archives_should_call_attic_with_parameters():
     retention_config = flexmock()
     flexmock(module).should_receive('_make_prune_flags').with_args(retention_config).and_return(
         BASE_PRUNE_FLAGS,
     )
-    insert_subprocess_mock(
-        (
-            'attic', 'prune', 'repo', '--keep-daily', '1', '--keep-weekly', '2', '--keep-monthly',
-            '3',
-        ),
-    )
+    insert_subprocess_mock(PRUNE_COMMAND)
 
     module.prune_archives(
-        verbose=False,
+        verbosity=None,
         repository='repo',
         retention_config=retention_config,
     )
 
 
-def test_prune_archives_with_verbose_should_call_attic_with_verbose_parameters():
+def test_prune_archives_with_verbosity_some_should_call_attic_with_stats_parameter():
     retention_config = flexmock()
     flexmock(module).should_receive('_make_prune_flags').with_args(retention_config).and_return(
         BASE_PRUNE_FLAGS,
     )
-    insert_subprocess_mock(
-        (
-            'attic', 'prune', 'repo', '--keep-daily', '1', '--keep-weekly', '2', '--keep-monthly',
-            '3', '--verbose',
-        ),
+    insert_subprocess_mock(PRUNE_COMMAND + ('--stats',))
+
+    module.prune_archives(
+        repository='repo',
+        verbosity=VERBOSITY_SOME,
+        retention_config=retention_config,
+    )
+
+
+def test_prune_archives_with_verbosity_lots_should_call_attic_with_verbose_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 + ('--verbose', '--stats',))
 
     module.prune_archives(
         repository='repo',
-        verbose=True,
+        verbosity=VERBOSITY_LOTS,
         retention_config=retention_config,
     )
 
@@ -171,13 +190,31 @@ def test_check_archives_should_call_attic_with_parameters():
     flexmock(module.os).should_receive('devnull')
 
     module.check_archives(
-        verbose=False,
+        verbosity=None,
+        repository='repo',
+        consistency_config=consistency_config,
+    )
+
+
+def test_check_archives_with_verbosity_some_should_call_attic_with_verbose_parameter():
+    consistency_config = flexmock()
+    flexmock(module).should_receive('_parse_checks').and_return(flexmock())
+    flexmock(module).should_receive('_make_check_flags').and_return(())
+    insert_subprocess_mock(
+        ('attic', 'check', 'repo', '--verbose'),
+        stdout=None,
+    )
+    insert_platform_mock()
+    insert_datetime_mock()
+
+    module.check_archives(
+        verbosity=VERBOSITY_SOME,
         repository='repo',
         consistency_config=consistency_config,
     )
 
 
-def test_check_archives_with_verbose_should_call_attic_with_verbose_parameters():
+def test_check_archives_with_verbosity_lots_should_call_attic_with_verbose_parameter():
     consistency_config = flexmock()
     flexmock(module).should_receive('_parse_checks').and_return(flexmock())
     flexmock(module).should_receive('_make_check_flags').and_return(())
@@ -189,7 +226,7 @@ def test_check_archives_with_verbose_should_call_attic_with_verbose_parameters()
     insert_datetime_mock()
 
     module.check_archives(
-        verbose=True,
+        verbosity=VERBOSITY_LOTS,
         repository='repo',
         consistency_config=consistency_config,
     )
@@ -201,7 +238,7 @@ def test_check_archives_without_any_checks_should_bail():
     insert_subprocess_never()
 
     module.check_archives(
-        verbose=False,
+        verbosity=None,
         repository='repo',
         consistency_config=consistency_config,
     )

+ 2 - 0
atticmatic/verbosity.py

@@ -0,0 +1,2 @@
+VERBOSITY_SOME = 1
+VERBOSITY_LOTS = 2

+ 1 - 1
setup.py

@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
 
 setup(
     name='atticmatic',
-    version='0.0.6',
+    version='0.0.7',
     description='A wrapper script for Attic backup software that creates and prunes backups',
     author='Dan Helfman',
     author_email='witten@torsion.org',