mirror of
https://github.com/borgbackup/borg.git
synced 2026-05-28 04:03:21 -04:00
PR #251 - Merge branch 'rename_archive' into merge
This commit is contained in:
commit
3d2a3d11af
3 changed files with 66 additions and 4 deletions
|
|
@ -152,12 +152,16 @@ class Archive:
|
|||
info = self.manifest.archives[name]
|
||||
self.load(info[b'id'])
|
||||
|
||||
def _load_meta(self, id):
|
||||
data = self.key.decrypt(id, self.repository.get(id))
|
||||
metadata = msgpack.unpackb(data)
|
||||
if metadata[b'version'] != 1:
|
||||
raise Exception('Unknown archive metadata version')
|
||||
return metadata
|
||||
|
||||
def load(self, id):
|
||||
self.id = id
|
||||
data = self.key.decrypt(self.id, self.repository.get(self.id))
|
||||
self.metadata = msgpack.unpackb(data)
|
||||
if self.metadata[b'version'] != 1:
|
||||
raise Exception('Unknown archive metadata version')
|
||||
self.metadata = self._load_meta(self.id)
|
||||
decode_dict(self.metadata, (b'name', b'hostname', b'username', b'time'))
|
||||
self.metadata[b'cmdline'] = [arg.decode('utf-8', 'surrogateescape') for arg in self.metadata[b'cmdline']]
|
||||
self.name = self.metadata[b'name']
|
||||
|
|
@ -344,6 +348,18 @@ class Archive:
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
def rename(self, name):
|
||||
if name in self.manifest.archives:
|
||||
raise self.AlreadyExists(name)
|
||||
metadata = StableDict(self._load_meta(self.id))
|
||||
metadata[b'name'] = name
|
||||
data = msgpack.packb(metadata, unicode_errors='surrogateescape')
|
||||
new_id = self.key.id_hash(data)
|
||||
self.cache.add_chunk(new_id, data, self.stats)
|
||||
self.manifest.archives[name] = {'id': new_id, 'time': metadata[b'time']}
|
||||
self.cache.chunk_decref(self.id, self.stats)
|
||||
del self.manifest.archives[self.name]
|
||||
|
||||
def delete(self, stats):
|
||||
unpacker = msgpack.Unpacker(use_list=False)
|
||||
for items_id, data in zip(self.metadata[b'items'], self.repository.get_many(self.metadata[b'items'])):
|
||||
|
|
|
|||
|
|
@ -249,6 +249,18 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
|
|||
archive.extract_item(dirs.pop(-1))
|
||||
return self.exit_code
|
||||
|
||||
def do_rename(self, args):
|
||||
"""Rename an existing archive"""
|
||||
repository = self.open_repository(args.archive, exclusive=True)
|
||||
manifest, key = Manifest.load(repository)
|
||||
cache = Cache(repository, key, manifest)
|
||||
archive = Archive(repository, key, manifest, args.archive.archive, cache=cache)
|
||||
archive.rename(args.name)
|
||||
manifest.write()
|
||||
repository.commit()
|
||||
cache.commit()
|
||||
return self.exit_code
|
||||
|
||||
def do_delete(self, args):
|
||||
"""Delete an existing archive"""
|
||||
repository = self.open_repository(args.archive, exclusive=True)
|
||||
|
|
@ -631,6 +643,20 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
|
|||
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
||||
help='paths to extract')
|
||||
|
||||
rename_epilog = textwrap.dedent("""
|
||||
This command renames an archive in the repository.
|
||||
""")
|
||||
subparser = subparsers.add_parser('rename', parents=[common_parser],
|
||||
description=self.do_rename.__doc__,
|
||||
epilog=rename_epilog,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
subparser.set_defaults(func=self.do_rename)
|
||||
subparser.add_argument('archive', metavar='ARCHIVE',
|
||||
type=location_validator(archive=True),
|
||||
help='archive to rename')
|
||||
subparser.add_argument('name', metavar='NEWNAME', type=str,
|
||||
help='the new archive name to use')
|
||||
|
||||
delete_epilog = textwrap.dedent("""
|
||||
This command deletes an archive from the repository. Any disk space not
|
||||
shared with any other existing archive is also reclaimed.
|
||||
|
|
|
|||
|
|
@ -265,6 +265,26 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|||
with changedir('output'):
|
||||
self.attic('extract', self.repository_location + '::test', exit_code=1)
|
||||
|
||||
def test_rename(self):
|
||||
self.create_regular_file('file1', size=1024 * 80)
|
||||
self.create_regular_file('dir2/file2', size=1024 * 80)
|
||||
self.attic('init', self.repository_location)
|
||||
self.attic('create', self.repository_location + '::test', 'input')
|
||||
self.attic('create', self.repository_location + '::test.2', 'input')
|
||||
self.attic('extract', '--dry-run', self.repository_location + '::test')
|
||||
self.attic('extract', '--dry-run', self.repository_location + '::test.2')
|
||||
self.attic('rename', self.repository_location + '::test', 'test.3')
|
||||
self.attic('extract', '--dry-run', self.repository_location + '::test.2')
|
||||
self.attic('rename', self.repository_location + '::test.2', 'test.4')
|
||||
self.attic('extract', '--dry-run', self.repository_location + '::test.3')
|
||||
self.attic('extract', '--dry-run', self.repository_location + '::test.4')
|
||||
# Make sure both archives have been renamed
|
||||
repository = Repository(self.repository_path)
|
||||
manifest, key = Manifest.load(repository)
|
||||
self.assert_equal(len(manifest.archives), 2)
|
||||
self.assert_in('test.3', manifest.archives)
|
||||
self.assert_in('test.4', manifest.archives)
|
||||
|
||||
def test_delete(self):
|
||||
self.create_regular_file('file1', size=1024 * 80)
|
||||
self.create_regular_file('dir2/file2', size=1024 * 80)
|
||||
|
|
|
|||
Loading…
Reference in a new issue