Browse Source

Improve attic check documentation

Closes #24.
Jonas Borgström 11 years ago
parent
commit
3982c34e6c
6 changed files with 43 additions and 37 deletions
  1. 3 6
      attic/archive.py
  2. 22 19
      attic/archiver.py
  3. 2 2
      attic/remote.py
  4. 3 4
      attic/repository.py
  5. 13 2
      attic/testsuite/archiver.py
  6. 0 4
      docs/usage.rst

+ 3 - 6
attic/archive.py

@@ -451,17 +451,15 @@ class ArchiveChecker:
 
     def __init__(self):
         self.error_found = False
-        self.progress = True
         self.possibly_superseded = set()
         self.tmpdir = tempfile.mkdtemp()
 
     def __del__(self):
         shutil.rmtree(self.tmpdir)
 
-    def check(self, repository, progress=True, repair=False):
+    def check(self, repository, repair=False):
         self.report_progress('Starting archive consistency check...')
         self.repair = repair
-        self.progress = progress
         self.repository = repository
         self.init_chunks()
         self.key = self.identify_key(repository)
@@ -494,9 +492,8 @@ class ArchiveChecker:
     def report_progress(self, msg, error=False):
         if error:
             self.error_found = True
-        if error or self.progress:
-            print(msg, file=sys.stderr)
-            sys.stderr.flush()
+        print(msg, file=sys.stderr)
+        sys.stderr.flush()
 
     def identify_key(self, repository):
         cdata = repository.get(next(self.chunks.iteritems())[0])

+ 22 - 19
attic/archiver.py

@@ -6,6 +6,7 @@ import io
 import os
 import stat
 import sys
+import textwrap
 
 from attic import __version__
 from attic.archive import Archive, ArchiveChecker
@@ -72,13 +73,10 @@ in data loss.
 Type "Yes I am sure" if you understand this and want to continue.\n""")
                 if input('Do you want to continue? ') == 'Yes I am sure':
                     break
-        if args.progress is None:
-            args.progress = sys.stdout.isatty() or args.verbose
-        if not repository.check(progress=args.progress, repair=args.repair):
-            return 1
-
-        if not ArchiveChecker().check(repository, progress=args.progress, repair=args.repair):
-            return 1
+        if args.phase in ('all', 'repository') and not repository.check(repair=args.repair):
+                return 1
+        if args.phase in ('all', 'archive') and not ArchiveChecker().check(repository, repair=args.repair):
+                return 1
         return 0
 
     def do_change_passphrase(self, args):
@@ -429,26 +427,31 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
                                choices=('none', 'passphrase', 'keyfile'), default='none',
                                help='select encryption method')
 
-        check_epilog = """
-        Progress status will be reported on the standard error stream by default when
-        it is attached to a terminal. Any problems found are printed to the standard error
-        stream and the command will have a non zero exit code.
-        """
+        check_epilog = textwrap.dedent("""
+        The check command verifies the consistency of a repository and corresponding
+        archives. The check is performed in two phases. In the first phase the
+        checksums of the underlying repository segment files are verified to detect
+        bit rot and other types of damage. In the second phase the consistency and
+        correctness of the archive metadata is verified.
+
+        A specific check phase can be selected using the --phase=repository|archive
+        option. This can be useful since the "archive" phase can be time consuming
+        and requires access to the key file and/or passphrase if encryption is enabled.
+        """)
         subparser = subparsers.add_parser('check', parents=[common_parser],
                                           description=self.do_check.__doc__,
-                                          epilog=check_epilog)
+                                          epilog=check_epilog,
+                                          formatter_class=argparse.RawDescriptionHelpFormatter)
         subparser.set_defaults(func=self.do_check)
         subparser.add_argument('repository', metavar='REPOSITORY',
                                type=location_validator(archive=False),
                                help='repository to check consistency of')
-        subparser.add_argument('--progress', dest='progress', action='store_true',
-                               default=None,
-                               help='Report progress status to standard output stream')
-        subparser.add_argument('--no-progress', dest='progress', action='store_false',
-                               help='Disable progress reporting')
+        subparser.add_argument('--phase', dest='phase', choices=['repository', 'archive', 'all'],
+                               default='all',
+                               help='which checks to perform (default: all)')
         subparser.add_argument('--repair', dest='repair', action='store_true',
                                default=False,
-                               help='Attempt to repair any inconsistencies found')
+                               help='attempt to repair any inconsistencies found')
 
         subparser = subparsers.add_parser('change-passphrase', parents=[common_parser],
                                           description=self.do_change_passphrase.__doc__)

+ 2 - 2
attic/remote.py

@@ -182,8 +182,8 @@ class RemoteRepository(object):
                     w_fds = []
         self.ignore_responses |= set(waiting_for)
 
-    def check(self, progress=False, repair=False):
-        return self.call('check', progress, repair)
+    def check(self, repair=False):
+        return self.call('check', repair)
 
     def commit(self, *args):
         return self.call('commit')

+ 3 - 4
attic/repository.py

@@ -233,7 +233,7 @@ class Repository(object):
         self.write_index()
         self.rollback()
 
-    def check(self, progress=False, repair=False):
+    def check(self, repair=False):
         """Check repository consistency
 
         This method verifies all segment checksums and makes sure
@@ -244,9 +244,8 @@ class Repository(object):
             nonlocal error_found
             if error:
                 error_found = True
-            if error or progress:
-                print(msg, file=sys.stderr)
-                sys.stderr.flush()
+            print(msg, file=sys.stderr)
+            sys.stderr.flush()
 
         assert not self._active_txn
         report_progress('Starting repository check...')

+ 13 - 2
attic/testsuite/archiver.py

@@ -340,6 +340,17 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase):
         archive = Archive(repository, key, manifest, name)
         return archive, repository
 
+    def test_check_usage(self):
+        output = self.attic('check', self.repository_location, exit_code=0)
+        self.assert_in('Starting repository check', output)
+        self.assert_in('Starting archive consistency check', output)
+        output = self.attic('check', '--phase', 'repository', self.repository_location, exit_code=0)
+        self.assert_in('Starting repository check', output)
+        self.assert_not_in('Starting archive consistency check', output)
+        output = self.attic('check', '--phase', 'archive', self.repository_location, exit_code=0)
+        self.assert_not_in('Starting repository check', output)
+        self.assert_in('Starting archive consistency check', output)
+
     def test_missing_file_chunk(self):
         archive, repository = self.open_archive('archive1')
         for item in archive.iter_items():
@@ -372,8 +383,8 @@ class ArchiverCheckTestCase(ArchiverTestCaseBase):
         repository.delete(Manifest.MANIFEST_ID)
         repository.commit()
         self.attic('check', self.repository_location, exit_code=1)
-        self.attic('check', '--repair', '--progress', self.repository_location, exit_code=0)
-        self.attic('check', '--progress', self.repository_location, exit_code=0)
+        self.attic('check', '--repair', self.repository_location, exit_code=0)
+        self.attic('check', self.repository_location, exit_code=0)
 
     def test_extra_chunks(self):
         self.attic('check', self.repository_location, exit_code=0)

+ 0 - 4
docs/usage.rst

@@ -86,10 +86,6 @@ Examples
 
 .. include:: usage/check.rst.inc
 
-The check command verifies the consistency of a repository. Any inconsistencies
-found are reported to the standard error stream and the command will have a
-non zero exit code.
-
 .. include:: usage/delete.rst.inc
 
 This command deletes an archive from the repository. Any disk space not