|
@@ -3,6 +3,7 @@ from .support import argparse # see support/__init__.py docstring
|
|
|
|
|
|
from binascii import hexlify
|
|
|
from datetime import datetime
|
|
|
+from hashlib import sha256
|
|
|
from operator import attrgetter
|
|
|
import functools
|
|
|
import inspect
|
|
@@ -17,7 +18,7 @@ import traceback
|
|
|
from . import __version__
|
|
|
from .helpers import Error, location_validator, format_time, format_file_size, \
|
|
|
format_file_mode, ExcludePattern, IncludePattern, exclude_path, adjust_patterns, to_localtime, timestamp, \
|
|
|
- get_cache_dir, get_keys_dir, prune_within, prune_split, \
|
|
|
+ get_cache_dir, get_keys_dir, prune_within, prune_split, unhexlify, \
|
|
|
Manifest, remove_surrogates, update_excludes, format_archive, check_extension_modules, Statistics, \
|
|
|
is_cachedir, bigint_to_int, ChunkerParams, CompressionSpec, have_cython, is_slow_msgpack, yes, \
|
|
|
EXIT_SUCCESS, EXIT_WARNING, EXIT_ERROR
|
|
@@ -502,6 +503,75 @@ class Archiver:
|
|
|
print("warning: %s" % e)
|
|
|
return self.exit_code
|
|
|
|
|
|
+ def do_debug_dump_archive_items(self, args):
|
|
|
+ """dump (decrypted, decompressed) archive items metadata (not: data)"""
|
|
|
+ repository = self.open_repository(args.archive)
|
|
|
+ manifest, key = Manifest.load(repository)
|
|
|
+ archive = Archive(repository, key, manifest, args.archive.archive)
|
|
|
+ for i, item_id in enumerate(archive.metadata[b'items']):
|
|
|
+ data = key.decrypt(item_id, repository.get(item_id))
|
|
|
+ filename = '%06d_%s.items' %(i, hexlify(item_id).decode('ascii'))
|
|
|
+ print('Dumping', filename)
|
|
|
+ with open(filename, 'wb') as fd:
|
|
|
+ fd.write(data)
|
|
|
+ print('Done.')
|
|
|
+ return EXIT_SUCCESS
|
|
|
+
|
|
|
+ def do_debug_get_obj(self, args):
|
|
|
+ """get object contents from the repository and write it into file"""
|
|
|
+ repository = self.open_repository(args.repository)
|
|
|
+ manifest, key = Manifest.load(repository)
|
|
|
+ hex_id = args.id
|
|
|
+ try:
|
|
|
+ id = unhexlify(hex_id)
|
|
|
+ except ValueError:
|
|
|
+ print("object id %s is invalid." % hex_id)
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ data =repository.get(id)
|
|
|
+ except repository.ObjectNotFound:
|
|
|
+ print("object %s not found." % hex_id)
|
|
|
+ else:
|
|
|
+ with open(args.path, "wb") as f:
|
|
|
+ f.write(data)
|
|
|
+ print("object %s fetched." % hex_id)
|
|
|
+ return EXIT_SUCCESS
|
|
|
+
|
|
|
+ def do_debug_put_obj(self, args):
|
|
|
+ """put file(s) contents into the repository"""
|
|
|
+ repository = self.open_repository(args.repository)
|
|
|
+ manifest, key = Manifest.load(repository)
|
|
|
+ for path in args.paths:
|
|
|
+ with open(path, "rb") as f:
|
|
|
+ data = f.read()
|
|
|
+ h = sha256(data) # XXX hardcoded
|
|
|
+ repository.put(h.digest(), data)
|
|
|
+ print("object %s put." % h.hexdigest())
|
|
|
+ repository.commit()
|
|
|
+ return EXIT_SUCCESS
|
|
|
+
|
|
|
+ def do_debug_delete_obj(self, args):
|
|
|
+ """delete the objects with the given IDs from the repo"""
|
|
|
+ repository = self.open_repository(args.repository)
|
|
|
+ manifest, key = Manifest.load(repository)
|
|
|
+ modified = False
|
|
|
+ for hex_id in args.ids:
|
|
|
+ try:
|
|
|
+ id = unhexlify(hex_id)
|
|
|
+ except ValueError:
|
|
|
+ print("object id %s is invalid." % hex_id)
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ repository.delete(id)
|
|
|
+ modified = True
|
|
|
+ print("object %s deleted." % hex_id)
|
|
|
+ except repository.ObjectNotFound:
|
|
|
+ print("object %s not found." % hex_id)
|
|
|
+ if modified:
|
|
|
+ repository.commit()
|
|
|
+ print('Done.')
|
|
|
+ return EXIT_SUCCESS
|
|
|
+
|
|
|
helptext = {}
|
|
|
helptext['patterns'] = '''
|
|
|
Exclude patterns use a variant of shell pattern syntax, with '*' matching any
|
|
@@ -990,6 +1060,62 @@ class Archiver:
|
|
|
subparser.set_defaults(func=functools.partial(self.do_help, parser, subparsers.choices))
|
|
|
subparser.add_argument('topic', metavar='TOPIC', type=str, nargs='?',
|
|
|
help='additional help on TOPIC')
|
|
|
+
|
|
|
+ debug_dump_archive_items_epilog = textwrap.dedent("""
|
|
|
+ This command dumps raw (but decrypted and decompressed) archive items (only metadata) to files.
|
|
|
+ """)
|
|
|
+ subparser = subparsers.add_parser('debug-dump-archive-items', parents=[common_parser],
|
|
|
+ description=self.do_debug_dump_archive_items.__doc__,
|
|
|
+ epilog=debug_dump_archive_items_epilog,
|
|
|
+ formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
+ subparser.set_defaults(func=self.do_debug_dump_archive_items)
|
|
|
+ subparser.add_argument('archive', metavar='ARCHIVE',
|
|
|
+ type=location_validator(archive=True),
|
|
|
+ help='archive to dump')
|
|
|
+
|
|
|
+ debug_get_obj_epilog = textwrap.dedent("""
|
|
|
+ This command gets an object from the repository.
|
|
|
+ """)
|
|
|
+ subparser = subparsers.add_parser('debug-get-obj', parents=[common_parser],
|
|
|
+ description=self.do_debug_get_obj.__doc__,
|
|
|
+ epilog=debug_get_obj_epilog,
|
|
|
+ formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
+ subparser.set_defaults(func=self.do_debug_get_obj)
|
|
|
+ subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
+ type=location_validator(archive=False),
|
|
|
+ help='repository to use')
|
|
|
+ subparser.add_argument('id', metavar='ID', type=str,
|
|
|
+ help='hex object ID to get from the repo')
|
|
|
+ subparser.add_argument('path', metavar='PATH', type=str,
|
|
|
+ help='file to write object data into')
|
|
|
+
|
|
|
+ debug_put_obj_epilog = textwrap.dedent("""
|
|
|
+ This command puts objects into the repository.
|
|
|
+ """)
|
|
|
+ subparser = subparsers.add_parser('debug-put-obj', parents=[common_parser],
|
|
|
+ description=self.do_debug_put_obj.__doc__,
|
|
|
+ epilog=debug_put_obj_epilog,
|
|
|
+ formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
+ subparser.set_defaults(func=self.do_debug_put_obj)
|
|
|
+ subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
+ type=location_validator(archive=False),
|
|
|
+ help='repository to use')
|
|
|
+ subparser.add_argument('paths', metavar='PATH', nargs='+', type=str,
|
|
|
+ help='file(s) to read and create object(s) from')
|
|
|
+
|
|
|
+ debug_delete_obj_epilog = textwrap.dedent("""
|
|
|
+ This command deletes objects from the repository.
|
|
|
+ """)
|
|
|
+ subparser = subparsers.add_parser('debug-delete-obj', parents=[common_parser],
|
|
|
+ description=self.do_debug_delete_obj.__doc__,
|
|
|
+ epilog=debug_delete_obj_epilog,
|
|
|
+ formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
|
+ subparser.set_defaults(func=self.do_debug_delete_obj)
|
|
|
+ subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
+ type=location_validator(archive=False),
|
|
|
+ help='repository to use')
|
|
|
+ subparser.add_argument('ids', metavar='IDs', nargs='+', type=str,
|
|
|
+ help='hex object ID(s) to delete from the repo')
|
|
|
return parser
|
|
|
|
|
|
def parse_args(self, args=None):
|