mirror of https://github.com/borgbackup/borg.git
Merge branch '1.0-maint' into master
This commit is contained in:
commit
1bad3fc552
|
@ -73,13 +73,16 @@ def with_repository(fake=False, create=False, lock=True, exclusive=False, manife
|
||||||
@functools.wraps(method)
|
@functools.wraps(method)
|
||||||
def wrapper(self, args, **kwargs):
|
def wrapper(self, args, **kwargs):
|
||||||
location = args.location # note: 'location' must be always present in args
|
location = args.location # note: 'location' must be always present in args
|
||||||
|
append_only = getattr(args, 'append_only', False)
|
||||||
if argument(args, fake):
|
if argument(args, fake):
|
||||||
return method(self, args, repository=None, **kwargs)
|
return method(self, args, repository=None, **kwargs)
|
||||||
elif location.proto == 'ssh':
|
elif location.proto == 'ssh':
|
||||||
repository = RemoteRepository(location, create=create, lock_wait=self.lock_wait, lock=lock, args=args)
|
repository = RemoteRepository(location, create=create, lock_wait=self.lock_wait, lock=lock,
|
||||||
|
append_only=append_only, args=args)
|
||||||
else:
|
else:
|
||||||
repository = Repository(location.path, create=create, exclusive=argument(args, exclusive),
|
repository = Repository(location.path, create=create, exclusive=argument(args, exclusive),
|
||||||
lock_wait=self.lock_wait, lock=lock)
|
lock_wait=self.lock_wait, lock=lock,
|
||||||
|
append_only=append_only)
|
||||||
with repository:
|
with repository:
|
||||||
if manifest or cache:
|
if manifest or cache:
|
||||||
kwargs['manifest'], kwargs['key'] = Manifest.load(repository)
|
kwargs['manifest'], kwargs['key'] = Manifest.load(repository)
|
||||||
|
@ -1304,6 +1307,8 @@ class Archiver:
|
||||||
subparser.add_argument('-e', '--encryption', dest='encryption',
|
subparser.add_argument('-e', '--encryption', dest='encryption',
|
||||||
choices=('none', 'keyfile', 'repokey'), default='repokey',
|
choices=('none', 'keyfile', 'repokey'), default='repokey',
|
||||||
help='select encryption key mode (default: "%(default)s")')
|
help='select encryption key mode (default: "%(default)s")')
|
||||||
|
subparser.add_argument('-a', '--append-only', dest='append_only', action='store_true',
|
||||||
|
help='create an append-only mode repository')
|
||||||
|
|
||||||
check_epilog = textwrap.dedent("""
|
check_epilog = textwrap.dedent("""
|
||||||
The check command verifies the consistency of a repository and the corresponding archives.
|
The check command verifies the consistency of a repository and the corresponding archives.
|
||||||
|
|
|
@ -117,7 +117,7 @@ class RepositoryServer: # pragma: no cover
|
||||||
def negotiate(self, versions):
|
def negotiate(self, versions):
|
||||||
return RPC_PROTOCOL_VERSION
|
return RPC_PROTOCOL_VERSION
|
||||||
|
|
||||||
def open(self, path, create=False, lock_wait=None, lock=True):
|
def open(self, path, create=False, lock_wait=None, lock=True, append_only=False):
|
||||||
path = os.fsdecode(path)
|
path = os.fsdecode(path)
|
||||||
if path.startswith('/~'):
|
if path.startswith('/~'):
|
||||||
path = os.path.join(get_home_dir(), path[2:])
|
path = os.path.join(get_home_dir(), path[2:])
|
||||||
|
@ -128,7 +128,7 @@ class RepositoryServer: # pragma: no cover
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise PathNotAllowed(path)
|
raise PathNotAllowed(path)
|
||||||
self.repository = Repository(path, create, lock_wait=lock_wait, lock=lock, append_only=self.append_only)
|
self.repository = Repository(path, create, lock_wait=lock_wait, lock=lock, append_only=self.append_only or append_only)
|
||||||
self.repository.__enter__() # clean exit handled by serve() method
|
self.repository.__enter__() # clean exit handled by serve() method
|
||||||
return self.repository.id
|
return self.repository.id
|
||||||
|
|
||||||
|
@ -137,10 +137,14 @@ class RemoteRepository:
|
||||||
extra_test_args = []
|
extra_test_args = []
|
||||||
|
|
||||||
class RPCError(Exception):
|
class RPCError(Exception):
|
||||||
def __init__(self, name):
|
def __init__(self, name, remote_type):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
self.remote_type = remote_type
|
||||||
|
|
||||||
def __init__(self, location, create=False, lock_wait=None, lock=True, args=None):
|
class NoAppendOnlyOnServer(Error):
|
||||||
|
"""Server does not support --append-only."""
|
||||||
|
|
||||||
|
def __init__(self, location, create=False, lock_wait=None, lock=True, append_only=False, args=None):
|
||||||
self.location = self._location = location
|
self.location = self._location = location
|
||||||
self.preload_ids = []
|
self.preload_ids = []
|
||||||
self.msgid = 0
|
self.msgid = 0
|
||||||
|
@ -176,6 +180,16 @@ class RemoteRepository:
|
||||||
if version != RPC_PROTOCOL_VERSION:
|
if version != RPC_PROTOCOL_VERSION:
|
||||||
raise Exception('Server insisted on using unsupported protocol version %d' % version)
|
raise Exception('Server insisted on using unsupported protocol version %d' % version)
|
||||||
try:
|
try:
|
||||||
|
# Because of protocol versions, only send append_only if necessary
|
||||||
|
if append_only:
|
||||||
|
try:
|
||||||
|
self.id = self.call('open', self.location.path, create, lock_wait, lock, append_only)
|
||||||
|
except self.RPCError as err:
|
||||||
|
if err.remote_type == 'TypeError':
|
||||||
|
raise self.NoAppendOnlyOnServer() from err
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
self.id = self.call('open', self.location.path, create, lock_wait, lock)
|
self.id = self.call('open', self.location.path, create, lock_wait, lock)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.close()
|
self.close()
|
||||||
|
@ -272,7 +286,7 @@ class RemoteRepository:
|
||||||
elif error == b'InvalidRPCMethod':
|
elif error == b'InvalidRPCMethod':
|
||||||
raise InvalidRPCMethod(*res)
|
raise InvalidRPCMethod(*res)
|
||||||
else:
|
else:
|
||||||
raise self.RPCError(res.decode('utf-8'))
|
raise self.RPCError(res.decode('utf-8'), error.decode('utf-8'))
|
||||||
|
|
||||||
calls = list(calls)
|
calls = list(calls)
|
||||||
waiting_for = []
|
waiting_for = []
|
||||||
|
|
|
@ -154,7 +154,7 @@ class Repository:
|
||||||
config.set('repository', 'version', '1')
|
config.set('repository', 'version', '1')
|
||||||
config.set('repository', 'segments_per_dir', str(DEFAULT_SEGMENTS_PER_DIR))
|
config.set('repository', 'segments_per_dir', str(DEFAULT_SEGMENTS_PER_DIR))
|
||||||
config.set('repository', 'max_segment_size', str(DEFAULT_MAX_SEGMENT_SIZE))
|
config.set('repository', 'max_segment_size', str(DEFAULT_MAX_SEGMENT_SIZE))
|
||||||
config.set('repository', 'append_only', '0')
|
config.set('repository', 'append_only', str(int(self.append_only)))
|
||||||
config.set('repository', 'id', bin_to_hex(os.urandom(32)))
|
config.set('repository', 'id', bin_to_hex(os.urandom(32)))
|
||||||
self.save_config(path, config)
|
self.save_config(path, config)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue