|
@@ -34,6 +34,9 @@ from .remote import RepositoryServer, RemoteRepository
|
|
|
|
|
|
has_lchflags = hasattr(os, 'lchflags')
|
|
has_lchflags = hasattr(os, 'lchflags')
|
|
|
|
|
|
|
|
+# default umask, overriden by --umask, defaults to read/write only for owner
|
|
|
|
+UMASK_DEFAULT = 0o077
|
|
|
|
+
|
|
|
|
|
|
class ToggleAction(argparse.Action):
|
|
class ToggleAction(argparse.Action):
|
|
"""argparse action to handle "toggle" flags easily
|
|
"""argparse action to handle "toggle" flags easily
|
|
@@ -55,9 +58,10 @@ class Archiver:
|
|
self.exit_code = EXIT_SUCCESS
|
|
self.exit_code = EXIT_SUCCESS
|
|
self.lock_wait = lock_wait
|
|
self.lock_wait = lock_wait
|
|
|
|
|
|
- def open_repository(self, location, create=False, exclusive=False, lock=True):
|
|
|
|
|
|
+ def open_repository(self, args, create=False, exclusive=False, lock=True):
|
|
|
|
+ location = args.location # note: 'location' must be always present in args
|
|
if location.proto == 'ssh':
|
|
if location.proto == 'ssh':
|
|
- repository = RemoteRepository(location, create=create, lock_wait=self.lock_wait, lock=lock)
|
|
|
|
|
|
+ repository = RemoteRepository(location, create=create, lock_wait=self.lock_wait, lock=lock, args=args)
|
|
else:
|
|
else:
|
|
repository = Repository(location.path, create=create, exclusive=exclusive, lock_wait=self.lock_wait, lock=lock)
|
|
repository = Repository(location.path, create=create, exclusive=exclusive, lock_wait=self.lock_wait, lock=lock)
|
|
repository._location = location
|
|
repository._location = location
|
|
@@ -84,8 +88,8 @@ class Archiver:
|
|
|
|
|
|
def do_init(self, args):
|
|
def do_init(self, args):
|
|
"""Initialize an empty repository"""
|
|
"""Initialize an empty repository"""
|
|
- logger.info('Initializing repository at "%s"' % args.repository.canonical_path())
|
|
|
|
- repository = self.open_repository(args.repository, create=True, exclusive=True)
|
|
|
|
|
|
+ logger.info('Initializing repository at "%s"' % args.location.canonical_path())
|
|
|
|
+ repository = self.open_repository(args, create=True, exclusive=True)
|
|
key = key_creator(repository, args)
|
|
key = key_creator(repository, args)
|
|
manifest = Manifest(key, repository)
|
|
manifest = Manifest(key, repository)
|
|
manifest.key = key
|
|
manifest.key = key
|
|
@@ -96,7 +100,7 @@ class Archiver:
|
|
|
|
|
|
def do_check(self, args):
|
|
def do_check(self, args):
|
|
"""Check repository consistency"""
|
|
"""Check repository consistency"""
|
|
- repository = self.open_repository(args.repository, exclusive=args.repair)
|
|
|
|
|
|
+ repository = self.open_repository(args, exclusive=args.repair)
|
|
if args.repair:
|
|
if args.repair:
|
|
msg = ("'check --repair' is an experimental feature that might result in data loss." +
|
|
msg = ("'check --repair' is an experimental feature that might result in data loss." +
|
|
"\n" +
|
|
"\n" +
|
|
@@ -108,14 +112,14 @@ class Archiver:
|
|
if not repository.check(repair=args.repair, save_space=args.save_space):
|
|
if not repository.check(repair=args.repair, save_space=args.save_space):
|
|
return EXIT_WARNING
|
|
return EXIT_WARNING
|
|
if not args.repo_only and not ArchiveChecker().check(
|
|
if not args.repo_only and not ArchiveChecker().check(
|
|
- repository, repair=args.repair, archive=args.repository.archive,
|
|
|
|
|
|
+ repository, repair=args.repair, archive=args.location.archive,
|
|
last=args.last, save_space=args.save_space):
|
|
last=args.last, save_space=args.save_space):
|
|
return EXIT_WARNING
|
|
return EXIT_WARNING
|
|
return EXIT_SUCCESS
|
|
return EXIT_SUCCESS
|
|
|
|
|
|
def do_change_passphrase(self, args):
|
|
def do_change_passphrase(self, args):
|
|
"""Change repository key file passphrase"""
|
|
"""Change repository key file passphrase"""
|
|
- repository = self.open_repository(args.repository)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
key.change_passphrase()
|
|
key.change_passphrase()
|
|
return EXIT_SUCCESS
|
|
return EXIT_SUCCESS
|
|
@@ -126,13 +130,13 @@ class Archiver:
|
|
dry_run = args.dry_run
|
|
dry_run = args.dry_run
|
|
t0 = datetime.now()
|
|
t0 = datetime.now()
|
|
if not dry_run:
|
|
if not dry_run:
|
|
- repository = self.open_repository(args.archive, exclusive=True)
|
|
|
|
|
|
+ repository = self.open_repository(args, exclusive=True)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
compr_args = dict(buffer=COMPR_BUFFER)
|
|
compr_args = dict(buffer=COMPR_BUFFER)
|
|
compr_args.update(args.compression)
|
|
compr_args.update(args.compression)
|
|
key.compressor = Compressor(**compr_args)
|
|
key.compressor = Compressor(**compr_args)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
- archive = Archive(repository, key, manifest, args.archive.archive, cache=cache,
|
|
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive, cache=cache,
|
|
create=True, checkpoint_interval=args.checkpoint_interval,
|
|
create=True, checkpoint_interval=args.checkpoint_interval,
|
|
numeric_owner=args.numeric_owner, progress=args.progress,
|
|
numeric_owner=args.numeric_owner, progress=args.progress,
|
|
chunker_params=args.chunker_params, start=t0)
|
|
chunker_params=args.chunker_params, start=t0)
|
|
@@ -146,9 +150,9 @@ class Archiver:
|
|
except IOError:
|
|
except IOError:
|
|
pass
|
|
pass
|
|
# Add local repository dir to inode_skip list
|
|
# Add local repository dir to inode_skip list
|
|
- if not args.archive.host:
|
|
|
|
|
|
+ if not args.location.host:
|
|
try:
|
|
try:
|
|
- st = os.stat(args.archive.path)
|
|
|
|
|
|
+ st = os.stat(args.location.path)
|
|
skip_inodes.add((st.st_ino, st.st_dev))
|
|
skip_inodes.add((st.st_ino, st.st_dev))
|
|
except IOError:
|
|
except IOError:
|
|
pass
|
|
pass
|
|
@@ -271,9 +275,9 @@ class Archiver:
|
|
logger.warning('Warning: File system encoding is "ascii", extracting non-ascii filenames will not be supported.')
|
|
logger.warning('Warning: File system encoding is "ascii", extracting non-ascii filenames will not be supported.')
|
|
if sys.platform.startswith(('linux', 'freebsd', 'netbsd', 'openbsd', 'darwin', )):
|
|
if sys.platform.startswith(('linux', 'freebsd', 'netbsd', 'openbsd', 'darwin', )):
|
|
logger.warning('Hint: You likely need to fix your locale setup. E.g. install locales and use: LANG=en_US.UTF-8')
|
|
logger.warning('Hint: You likely need to fix your locale setup. E.g. install locales and use: LANG=en_US.UTF-8')
|
|
- repository = self.open_repository(args.archive)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
- archive = Archive(repository, key, manifest, args.archive.archive,
|
|
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive,
|
|
numeric_owner=args.numeric_owner)
|
|
numeric_owner=args.numeric_owner)
|
|
patterns = adjust_patterns(args.paths, args.excludes)
|
|
patterns = adjust_patterns(args.paths, args.excludes)
|
|
dry_run = args.dry_run
|
|
dry_run = args.dry_run
|
|
@@ -313,10 +317,10 @@ class Archiver:
|
|
|
|
|
|
def do_rename(self, args):
|
|
def do_rename(self, args):
|
|
"""Rename an existing archive"""
|
|
"""Rename an existing archive"""
|
|
- repository = self.open_repository(args.archive, exclusive=True)
|
|
|
|
|
|
+ repository = self.open_repository(args, exclusive=True)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
cache = Cache(repository, key, manifest, lock_wait=self.lock_wait)
|
|
cache = Cache(repository, key, manifest, lock_wait=self.lock_wait)
|
|
- archive = Archive(repository, key, manifest, args.archive.archive, cache=cache)
|
|
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive, cache=cache)
|
|
archive.rename(args.name)
|
|
archive.rename(args.name)
|
|
manifest.write()
|
|
manifest.write()
|
|
repository.commit()
|
|
repository.commit()
|
|
@@ -325,11 +329,11 @@ class Archiver:
|
|
|
|
|
|
def do_delete(self, args):
|
|
def do_delete(self, args):
|
|
"""Delete an existing repository or archive"""
|
|
"""Delete an existing repository or archive"""
|
|
- repository = self.open_repository(args.target, exclusive=True)
|
|
|
|
|
|
+ repository = self.open_repository(args, exclusive=True)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
- if args.target.archive:
|
|
|
|
- archive = Archive(repository, key, manifest, args.target.archive, cache=cache)
|
|
|
|
|
|
+ if args.location.archive:
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive, cache=cache)
|
|
stats = Statistics()
|
|
stats = Statistics()
|
|
archive.delete(stats)
|
|
archive.delete(stats)
|
|
manifest.write()
|
|
manifest.write()
|
|
@@ -368,11 +372,11 @@ class Archiver:
|
|
self.print_error('%s: Mountpoint must be a writable directory' % args.mountpoint)
|
|
self.print_error('%s: Mountpoint must be a writable directory' % args.mountpoint)
|
|
return self.exit_code
|
|
return self.exit_code
|
|
|
|
|
|
- repository = self.open_repository(args.src)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
try:
|
|
try:
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
- if args.src.archive:
|
|
|
|
- archive = Archive(repository, key, manifest, args.src.archive)
|
|
|
|
|
|
+ if args.location.archive:
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive)
|
|
else:
|
|
else:
|
|
archive = None
|
|
archive = None
|
|
operations = FuseOperations(key, repository, manifest, archive)
|
|
operations = FuseOperations(key, repository, manifest, archive)
|
|
@@ -388,10 +392,10 @@ class Archiver:
|
|
|
|
|
|
def do_list(self, args):
|
|
def do_list(self, args):
|
|
"""List archive or repository contents"""
|
|
"""List archive or repository contents"""
|
|
- repository = self.open_repository(args.src)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
- if args.src.archive:
|
|
|
|
- archive = Archive(repository, key, manifest, args.src.archive)
|
|
|
|
|
|
+ if args.location.archive:
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive)
|
|
if args.short:
|
|
if args.short:
|
|
for item in archive.iter_items():
|
|
for item in archive.iter_items():
|
|
print(remove_surrogates(item[b'path']))
|
|
print(remove_surrogates(item[b'path']))
|
|
@@ -432,10 +436,10 @@ class Archiver:
|
|
|
|
|
|
def do_info(self, args):
|
|
def do_info(self, args):
|
|
"""Show archive details such as disk space used"""
|
|
"""Show archive details such as disk space used"""
|
|
- repository = self.open_repository(args.archive)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
- archive = Archive(repository, key, manifest, args.archive.archive, cache=cache)
|
|
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive, cache=cache)
|
|
stats = archive.calc_stats(cache)
|
|
stats = archive.calc_stats(cache)
|
|
print('Name:', archive.name)
|
|
print('Name:', archive.name)
|
|
print('Fingerprint: %s' % hexlify(archive.id).decode('ascii'))
|
|
print('Fingerprint: %s' % hexlify(archive.id).decode('ascii'))
|
|
@@ -451,7 +455,7 @@ class Archiver:
|
|
|
|
|
|
def do_prune(self, args):
|
|
def do_prune(self, args):
|
|
"""Prune repository archives according to specified rules"""
|
|
"""Prune repository archives according to specified rules"""
|
|
- repository = self.open_repository(args.repository, exclusive=True)
|
|
|
|
|
|
+ repository = self.open_repository(args, exclusive=True)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
cache = Cache(repository, key, manifest, do_files=args.cache_files, lock_wait=self.lock_wait)
|
|
archives = manifest.list_archive_infos(sort_by='ts', reverse=True) # just a ArchiveInfo list
|
|
archives = manifest.list_archive_infos(sort_by='ts', reverse=True) # just a ArchiveInfo list
|
|
@@ -506,7 +510,7 @@ class Archiver:
|
|
# to be implemented.
|
|
# to be implemented.
|
|
|
|
|
|
# XXX: should auto-detect if it is an attic repository here
|
|
# XXX: should auto-detect if it is an attic repository here
|
|
- repo = AtticRepositoryUpgrader(args.repository.path, create=False)
|
|
|
|
|
|
+ repo = AtticRepositoryUpgrader(args.location.path, create=False)
|
|
try:
|
|
try:
|
|
repo.upgrade(args.dry_run, inplace=args.inplace)
|
|
repo.upgrade(args.dry_run, inplace=args.inplace)
|
|
except NotImplementedError as e:
|
|
except NotImplementedError as e:
|
|
@@ -515,9 +519,9 @@ class Archiver:
|
|
|
|
|
|
def do_debug_dump_archive_items(self, args):
|
|
def do_debug_dump_archive_items(self, args):
|
|
"""dump (decrypted, decompressed) archive items metadata (not: data)"""
|
|
"""dump (decrypted, decompressed) archive items metadata (not: data)"""
|
|
- repository = self.open_repository(args.archive)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
- archive = Archive(repository, key, manifest, args.archive.archive)
|
|
|
|
|
|
+ archive = Archive(repository, key, manifest, args.location.archive)
|
|
for i, item_id in enumerate(archive.metadata[b'items']):
|
|
for i, item_id in enumerate(archive.metadata[b'items']):
|
|
data = key.decrypt(item_id, repository.get(item_id))
|
|
data = key.decrypt(item_id, repository.get(item_id))
|
|
filename = '%06d_%s.items' %(i, hexlify(item_id).decode('ascii'))
|
|
filename = '%06d_%s.items' %(i, hexlify(item_id).decode('ascii'))
|
|
@@ -529,7 +533,7 @@ class Archiver:
|
|
|
|
|
|
def do_debug_get_obj(self, args):
|
|
def do_debug_get_obj(self, args):
|
|
"""get object contents from the repository and write it into file"""
|
|
"""get object contents from the repository and write it into file"""
|
|
- repository = self.open_repository(args.repository)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
hex_id = args.id
|
|
hex_id = args.id
|
|
try:
|
|
try:
|
|
@@ -549,7 +553,7 @@ class Archiver:
|
|
|
|
|
|
def do_debug_put_obj(self, args):
|
|
def do_debug_put_obj(self, args):
|
|
"""put file(s) contents into the repository"""
|
|
"""put file(s) contents into the repository"""
|
|
- repository = self.open_repository(args.repository)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
for path in args.paths:
|
|
for path in args.paths:
|
|
with open(path, "rb") as f:
|
|
with open(path, "rb") as f:
|
|
@@ -562,7 +566,7 @@ class Archiver:
|
|
|
|
|
|
def do_debug_delete_obj(self, args):
|
|
def do_debug_delete_obj(self, args):
|
|
"""delete the objects with the given IDs from the repo"""
|
|
"""delete the objects with the given IDs from the repo"""
|
|
- repository = self.open_repository(args.repository)
|
|
|
|
|
|
+ repository = self.open_repository(args)
|
|
manifest, key = Manifest.load(repository)
|
|
manifest, key = Manifest.load(repository)
|
|
modified = False
|
|
modified = False
|
|
for hex_id in args.ids:
|
|
for hex_id in args.ids:
|
|
@@ -584,7 +588,7 @@ class Archiver:
|
|
|
|
|
|
def do_break_lock(self, args):
|
|
def do_break_lock(self, args):
|
|
"""Break the repository lock (e.g. in case it was left by a dead borg."""
|
|
"""Break the repository lock (e.g. in case it was left by a dead borg."""
|
|
- repository = self.open_repository(args.repository, lock=False)
|
|
|
|
|
|
+ repository = self.open_repository(args, lock=False)
|
|
try:
|
|
try:
|
|
repository.break_lock()
|
|
repository.break_lock()
|
|
Cache.break_lock(repository)
|
|
Cache.break_lock(repository)
|
|
@@ -673,9 +677,9 @@ class Archiver:
|
|
help='show/log the return code (rc)')
|
|
help='show/log the return code (rc)')
|
|
common_parser.add_argument('--no-files-cache', dest='cache_files', action='store_false',
|
|
common_parser.add_argument('--no-files-cache', dest='cache_files', action='store_false',
|
|
help='do not load/update the file metadata cache used to detect unchanged files')
|
|
help='do not load/update the file metadata cache used to detect unchanged files')
|
|
- common_parser.add_argument('--umask', dest='umask', type=lambda s: int(s, 8), default=RemoteRepository.umask, metavar='M',
|
|
|
|
|
|
+ common_parser.add_argument('--umask', dest='umask', type=lambda s: int(s, 8), default=UMASK_DEFAULT, metavar='M',
|
|
help='set umask to M (local and remote, default: %(default)04o)')
|
|
help='set umask to M (local and remote, default: %(default)04o)')
|
|
- common_parser.add_argument('--remote-path', dest='remote_path', default=RemoteRepository.remote_path, metavar='PATH',
|
|
|
|
|
|
+ common_parser.add_argument('--remote-path', dest='remote_path', default='borg', metavar='PATH',
|
|
help='set remote path to executable (default: "%(default)s")')
|
|
help='set remote path to executable (default: "%(default)s")')
|
|
|
|
|
|
parser = argparse.ArgumentParser(prog=prog, description='Borg - Deduplicated Backups')
|
|
parser = argparse.ArgumentParser(prog=prog, description='Borg - Deduplicated Backups')
|
|
@@ -703,7 +707,7 @@ class Archiver:
|
|
description=self.do_init.__doc__, epilog=init_epilog,
|
|
description=self.do_init.__doc__, epilog=init_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_init)
|
|
subparser.set_defaults(func=self.do_init)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='repository to create')
|
|
help='repository to create')
|
|
subparser.add_argument('-e', '--encryption', dest='encryption',
|
|
subparser.add_argument('-e', '--encryption', dest='encryption',
|
|
@@ -751,7 +755,7 @@ class Archiver:
|
|
epilog=check_epilog,
|
|
epilog=check_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_check)
|
|
subparser.set_defaults(func=self.do_check)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='',
|
|
type=location_validator(),
|
|
type=location_validator(),
|
|
help='repository or archive to check consistency of')
|
|
help='repository or archive to check consistency of')
|
|
subparser.add_argument('--repository-only', dest='repo_only', action='store_true',
|
|
subparser.add_argument('--repository-only', dest='repo_only', action='store_true',
|
|
@@ -779,7 +783,7 @@ class Archiver:
|
|
epilog=change_passphrase_epilog,
|
|
epilog=change_passphrase_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_change_passphrase)
|
|
subparser.set_defaults(func=self.do_change_passphrase)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False))
|
|
type=location_validator(archive=False))
|
|
|
|
|
|
create_epilog = textwrap.dedent("""
|
|
create_epilog = textwrap.dedent("""
|
|
@@ -853,7 +857,7 @@ class Archiver:
|
|
subparser.add_argument('-n', '--dry-run', dest='dry_run',
|
|
subparser.add_argument('-n', '--dry-run', dest='dry_run',
|
|
action='store_true', default=False,
|
|
action='store_true', default=False,
|
|
help='do not create a backup archive')
|
|
help='do not create a backup archive')
|
|
- subparser.add_argument('archive', metavar='ARCHIVE',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='ARCHIVE',
|
|
type=location_validator(archive=True),
|
|
type=location_validator(archive=True),
|
|
help='name of archive to create (must be also a valid directory name)')
|
|
help='name of archive to create (must be also a valid directory name)')
|
|
subparser.add_argument('paths', metavar='PATH', nargs='+', type=str,
|
|
subparser.add_argument('paths', metavar='PATH', nargs='+', type=str,
|
|
@@ -893,7 +897,7 @@ class Archiver:
|
|
subparser.add_argument('--sparse', dest='sparse',
|
|
subparser.add_argument('--sparse', dest='sparse',
|
|
action='store_true', default=False,
|
|
action='store_true', default=False,
|
|
help='create holes in output sparse file from all-zero chunks')
|
|
help='create holes in output sparse file from all-zero chunks')
|
|
- subparser.add_argument('archive', metavar='ARCHIVE',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='ARCHIVE',
|
|
type=location_validator(archive=True),
|
|
type=location_validator(archive=True),
|
|
help='archive to extract')
|
|
help='archive to extract')
|
|
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
|
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
|
@@ -907,7 +911,7 @@ class Archiver:
|
|
epilog=rename_epilog,
|
|
epilog=rename_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_rename)
|
|
subparser.set_defaults(func=self.do_rename)
|
|
- subparser.add_argument('archive', metavar='ARCHIVE',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='ARCHIVE',
|
|
type=location_validator(archive=True),
|
|
type=location_validator(archive=True),
|
|
help='archive to rename')
|
|
help='archive to rename')
|
|
subparser.add_argument('name', metavar='NEWNAME', type=str,
|
|
subparser.add_argument('name', metavar='NEWNAME', type=str,
|
|
@@ -932,7 +936,7 @@ class Archiver:
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
default=False,
|
|
default=False,
|
|
help='work slower, but using less space')
|
|
help='work slower, but using less space')
|
|
- subparser.add_argument('target', metavar='TARGET', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='TARGET', nargs='?', default='',
|
|
type=location_validator(),
|
|
type=location_validator(),
|
|
help='archive or repository to delete')
|
|
help='archive or repository to delete')
|
|
|
|
|
|
@@ -949,7 +953,7 @@ class Archiver:
|
|
help='only print file/directory names, nothing else')
|
|
help='only print file/directory names, nothing else')
|
|
subparser.add_argument('-p', '--prefix', dest='prefix', type=str,
|
|
subparser.add_argument('-p', '--prefix', dest='prefix', type=str,
|
|
help='only consider archive names starting with this prefix')
|
|
help='only consider archive names starting with this prefix')
|
|
- subparser.add_argument('src', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='',
|
|
type=location_validator(),
|
|
type=location_validator(),
|
|
help='repository/archive to list contents of')
|
|
help='repository/archive to list contents of')
|
|
|
|
|
|
@@ -964,7 +968,7 @@ class Archiver:
|
|
epilog=mount_epilog,
|
|
epilog=mount_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_mount)
|
|
subparser.set_defaults(func=self.do_mount)
|
|
- subparser.add_argument('src', metavar='REPOSITORY_OR_ARCHIVE', type=location_validator(),
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', type=location_validator(),
|
|
help='repository/archive to mount')
|
|
help='repository/archive to mount')
|
|
subparser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str,
|
|
subparser.add_argument('mountpoint', metavar='MOUNTPOINT', type=str,
|
|
help='where to mount filesystem')
|
|
help='where to mount filesystem')
|
|
@@ -982,7 +986,7 @@ class Archiver:
|
|
epilog=info_epilog,
|
|
epilog=info_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_info)
|
|
subparser.set_defaults(func=self.do_info)
|
|
- subparser.add_argument('archive', metavar='ARCHIVE',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='ARCHIVE',
|
|
type=location_validator(archive=True),
|
|
type=location_validator(archive=True),
|
|
help='archive to display information about')
|
|
help='archive to display information about')
|
|
|
|
|
|
@@ -996,7 +1000,7 @@ class Archiver:
|
|
epilog=break_lock_epilog,
|
|
epilog=break_lock_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_break_lock)
|
|
subparser.set_defaults(func=self.do_break_lock)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='repository for which to break the locks')
|
|
help='repository for which to break the locks')
|
|
|
|
|
|
@@ -1052,7 +1056,7 @@ class Archiver:
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
|
default=False,
|
|
default=False,
|
|
help='work slower, but using less space')
|
|
help='work slower, but using less space')
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='repository to prune')
|
|
help='repository to prune')
|
|
|
|
|
|
@@ -1104,7 +1108,7 @@ class Archiver:
|
|
default=False, action='store_true',
|
|
default=False, action='store_true',
|
|
help="""rewrite repository in place, with no chance of going back to older
|
|
help="""rewrite repository in place, with no chance of going back to older
|
|
versions of the repository.""")
|
|
versions of the repository.""")
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='path to the repository to be upgraded')
|
|
help='path to the repository to be upgraded')
|
|
|
|
|
|
@@ -1126,7 +1130,7 @@ class Archiver:
|
|
epilog=debug_dump_archive_items_epilog,
|
|
epilog=debug_dump_archive_items_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_debug_dump_archive_items)
|
|
subparser.set_defaults(func=self.do_debug_dump_archive_items)
|
|
- subparser.add_argument('archive', metavar='ARCHIVE',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='ARCHIVE',
|
|
type=location_validator(archive=True),
|
|
type=location_validator(archive=True),
|
|
help='archive to dump')
|
|
help='archive to dump')
|
|
|
|
|
|
@@ -1138,7 +1142,7 @@ class Archiver:
|
|
epilog=debug_get_obj_epilog,
|
|
epilog=debug_get_obj_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_debug_get_obj)
|
|
subparser.set_defaults(func=self.do_debug_get_obj)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='repository to use')
|
|
help='repository to use')
|
|
subparser.add_argument('id', metavar='ID', type=str,
|
|
subparser.add_argument('id', metavar='ID', type=str,
|
|
@@ -1154,7 +1158,7 @@ class Archiver:
|
|
epilog=debug_put_obj_epilog,
|
|
epilog=debug_put_obj_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_debug_put_obj)
|
|
subparser.set_defaults(func=self.do_debug_put_obj)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='repository to use')
|
|
help='repository to use')
|
|
subparser.add_argument('paths', metavar='PATH', nargs='+', type=str,
|
|
subparser.add_argument('paths', metavar='PATH', nargs='+', type=str,
|
|
@@ -1168,7 +1172,7 @@ class Archiver:
|
|
epilog=debug_delete_obj_epilog,
|
|
epilog=debug_delete_obj_epilog,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
subparser.set_defaults(func=self.do_debug_delete_obj)
|
|
subparser.set_defaults(func=self.do_debug_delete_obj)
|
|
- subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
|
|
|
|
|
|
+ subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='',
|
|
type=location_validator(archive=False),
|
|
type=location_validator(archive=False),
|
|
help='repository to use')
|
|
help='repository to use')
|
|
subparser.add_argument('ids', metavar='IDs', nargs='+', type=str,
|
|
subparser.add_argument('ids', metavar='IDs', nargs='+', type=str,
|
|
@@ -1187,9 +1191,7 @@ class Archiver:
|
|
def run(self, args):
|
|
def run(self, args):
|
|
os.umask(args.umask) # early, before opening files
|
|
os.umask(args.umask) # early, before opening files
|
|
self.lock_wait = args.lock_wait
|
|
self.lock_wait = args.lock_wait
|
|
- RemoteRepository.remote_path = args.remote_path
|
|
|
|
- RemoteRepository.umask = args.umask
|
|
|
|
- setup_logging(level=args.log_level) # do not use loggers before this!
|
|
|
|
|
|
+ setup_logging(level=args.log_level, is_serve=args.func == self.do_serve) # do not use loggers before this!
|
|
check_extension_modules()
|
|
check_extension_modules()
|
|
keys_dir = get_keys_dir()
|
|
keys_dir = get_keys_dir()
|
|
if not os.path.exists(keys_dir):
|
|
if not os.path.exists(keys_dir):
|
|
@@ -1261,7 +1263,7 @@ def main(): # pragma: no cover
|
|
msg += "\n%s\n%s" % (traceback.format_exc(), sysinfo())
|
|
msg += "\n%s\n%s" % (traceback.format_exc(), sysinfo())
|
|
exit_code = e.exit_code
|
|
exit_code = e.exit_code
|
|
except RemoteRepository.RPCError as e:
|
|
except RemoteRepository.RPCError as e:
|
|
- msg = 'Remote Exception.\n%s\n%s' % (str(e), sysinfo())
|
|
|
|
|
|
+ msg = '%s\n%s' % (str(e), sysinfo())
|
|
exit_code = EXIT_ERROR
|
|
exit_code = EXIT_ERROR
|
|
except Exception:
|
|
except Exception:
|
|
msg = 'Local Exception.\n%s\n%s' % (traceback.format_exc(), sysinfo())
|
|
msg = 'Local Exception.\n%s\n%s' % (traceback.format_exc(), sysinfo())
|