diff --git a/borg/converter.py b/borg/converter.py index 573411584..899979900 100644 --- a/borg/converter.py +++ b/borg/converter.py @@ -18,6 +18,8 @@ class AtticRepositoryConverter(Repository): caches, the latter being optional, as they will be rebuilt if missing.""" print("reading segments from attic repository using borg") + # we need to open it to load the configuration and other fields + self.open(self.path, exclusive=False) segments = [ filename for i, filename in self.io.segment_iterator() ] try: keyfile = self.find_attic_keyfile() @@ -31,10 +33,10 @@ class AtticRepositoryConverter(Repository): exclusive=True).acquire() try: self.convert_segments(segments, dryrun) + self.convert_cache(dryrun) finally: self.lock.release() self.lock = None - self.convert_cache(dryrun) @staticmethod def convert_segments(segments, dryrun): @@ -54,14 +56,19 @@ class AtticRepositoryConverter(Repository): if dryrun: time.sleep(0.001) else: - with open(filename, 'r+b') as segment: - segment.seek(0) - # only write if necessary - if (segment.read(len(ATTIC_MAGIC)) == ATTIC_MAGIC): - segment.seek(0) - segment.write(MAGIC) + AtticRepositoryConverter.header_replace(filename, ATTIC_MAGIC, MAGIC) print() + @staticmethod + def header_replace(filename, old_magic, new_magic): + print("changing header on %s" % filename) + with open(filename, 'r+b') as segment: + segment.seek(0) + # only write if necessary + if (segment.read(len(old_magic)) == old_magic): + segment.seek(0) + segment.write(new_magic) + def find_attic_keyfile(self): """find the attic keyfiles @@ -123,7 +130,16 @@ class AtticRepositoryConverter(Repository): `Cache.open()`, edit in place and then `Cache.close()` to make sure we have locking right """ - raise NotImplementedError('cache conversion not implemented, next borg backup will take longer to rebuild those caches. use borg check --repair to rebuild now') + caches = [] + transaction_id = self.get_index_transaction_id() + if transaction_id is None: + print('no index file found for repository %s' % self.path) + else: + caches += [os.path.join(self.path, 'index.%d' % transaction_id).encode('utf-8')] + for cache in caches: + print("converting cache %s" % cache) + AtticRepositoryConverter.header_replace(cache, b'ATTICIDX', b'BORG_IDX') + class AtticKeyfileKey(KeyfileKey): """backwards compatible Attic key file parser""" diff --git a/borg/testsuite/convert.py b/borg/testsuite/convert.py index 5596f4e65..b57e77097 100644 --- a/borg/testsuite/convert.py +++ b/borg/testsuite/convert.py @@ -59,6 +59,7 @@ def attic_repo(tmpdir): # throw some stuff in that repo, copied from `RepositoryTestCase.test1` for x in range(100): attic_repo.put(('%-32d' % x).encode('ascii'), b'SOMEDATA') + attic_repo.commit() attic_repo.close() return attic_repo @@ -82,6 +83,7 @@ def test_convert_segments(tmpdir, attic_repo): segments = [filename for i, filename in repo.io.segment_iterator()] repo.close() repo.convert_segments(segments, dryrun=False) + repo.convert_cache(dryrun=False) assert repo_valid(tmpdir) @@ -157,7 +159,6 @@ def test_convert_all(tmpdir, attic_repo, attic_key_file): assert not repo_valid(tmpdir) print("opening attic repository with borg and converting") repo = AtticRepositoryConverter(str(tmpdir), create=False) - with pytest.raises(NotImplementedError): - repo.convert(dryrun=False) + repo.convert(dryrun=False) assert key_valid(attic_key_file.path) assert repo_valid(tmpdir)