rename convert command to upgrade

convert is too generic for the Attic conversion: we may have other
converters, from other, more foreign systems that will require
different options and different upgrade mechanisms that convert could
never cover appropriately. we are more likely to use an approach
similar to "git fast-import" instead here, and have the conversion
tools be external tool that feed standard data into borg during
conversion.

upgrade seems like a more natural fit: Attic could be considered like
a pre-historic version of Borg that requires invasive changes for borg
to be able to use the repository. we may require such changes in the
future of borg as well: if we make backwards-incompatible changes to
the repository layout or data format, it is possible that we require
such changes to be performed on the repository before it is usable
again. instead of scattering those conversions all over the code, we
should simply have assertions that check the layout is correct and
point the user to upgrade if it is not.

upgrade should eventually automatically detect the repository format
or version and perform appropriate conversions. Attic is only the
first one. we still need to implement an adequate API for
auto-detection and upgrade, only the seeds of that are present for now.

of course, changes to the upgrade command should be thoroughly
documented in the release notes and an eventual upgrade manual.
This commit is contained in:
Antoine Beaupré 2015-10-03 12:36:52 -04:00
parent 48b7c8cea3
commit c91c5d0029
3 changed files with 36 additions and 25 deletions

View File

@ -17,7 +17,7 @@ import traceback
from . import __version__
from .archive import Archive, ArchiveChecker, CHUNKER_PARAMS
from .compress import Compressor, COMPR_BUFFER
from .converter import AtticRepositoryConverter
from .upgrader import AtticRepositoryUpgrader
from .repository import Repository
from .cache import Cache
from .key import key_creator
@ -463,11 +463,20 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
stats.print_('Deleted data:', cache)
return self.exit_code
def do_convert(self, args):
"""convert a repository from attic to borg"""
repo = AtticRepositoryConverter(args.repository.path, create=False)
def do_upgrade(self, args):
"""upgrade a repository from a previous version"""
# XXX: currently only upgrades from Attic repositories, but may
# eventually be extended to deal with major upgrades for borg
# itself.
#
# in this case, it should auto-detect the current repository
# format and fire up necessary upgrade mechanism. this remains
# to be implemented.
# XXX: should auto-detect if it is an attic repository here
repo = AtticRepositoryUpgrader(args.repository.path, create=False)
try:
repo.convert(args.dry_run)
repo.upgrade(args.dry_run)
except NotImplementedError as e:
print("warning: %s" % e)
return self.exit_code
@ -906,8 +915,10 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
type=location_validator(archive=False),
help='repository to prune')
convert_epilog = textwrap.dedent("""
convert will convert an existing Attic repository to Borg in place.
upgrade_epilog = textwrap.dedent("""
upgrade an existing Borg repository in place. this currently
only support converting an Attic repository, but may
eventually be extended to cover major Borg upgrades as well.
it will change the magic strings in the repository's segments
to match the new Borg magic strings. the keyfiles found in
@ -928,21 +939,21 @@ Type "Yes I am sure" if you understand this and want to continue.\n""")
repository, in case something goes wrong, for example:
cp -a attic borg
borg convert -n borg
borg convert borg
borg upgrade -n borg
borg upgrade borg
you have been warned.""")
subparser = subparsers.add_parser('convert', parents=[common_parser],
description=self.do_convert.__doc__,
epilog=convert_epilog,
subparser = subparsers.add_parser('upgrade', parents=[common_parser],
description=self.do_upgrade.__doc__,
epilog=upgrade_epilog,
formatter_class=argparse.RawDescriptionHelpFormatter)
subparser.set_defaults(func=self.do_convert)
subparser.set_defaults(func=self.do_upgrade)
subparser.add_argument('-n', '--dry-run', dest='dry_run',
default=False, action='store_true',
help='do not change repository')
subparser.add_argument('repository', metavar='REPOSITORY', nargs='?', default='',
type=location_validator(archive=False),
help='path to the attic repository to be converted')
help='path to the repository to be upgraded')
subparser = subparsers.add_parser('help', parents=[common_parser],
description='Extra help')

View File

@ -11,7 +11,7 @@ try:
except ImportError:
attic = None
from ..converter import AtticRepositoryConverter, AtticKeyfileKey
from ..upgrader import AtticRepositoryUpgrader, AtticKeyfileKey
from ..helpers import get_keys_dir
from ..key import KeyfileKey
from ..repository import Repository, MAGIC
@ -78,7 +78,7 @@ def test_convert_segments(tmpdir, attic_repo):
# check should fail because of magic number
assert not repo_valid(tmpdir)
print("opening attic repository with borg and converting")
repo = AtticRepositoryConverter(str(tmpdir), create=False)
repo = AtticRepositoryUpgrader(str(tmpdir), create=False)
segments = [filename for i, filename in repo.io.segment_iterator()]
repo.close()
repo.convert_segments(segments, dryrun=False)
@ -136,9 +136,9 @@ def test_keys(tmpdir, attic_repo, attic_key_file):
define above)
:param attic_key_file: an attic.key.KeyfileKey (fixture created above)
"""
repository = AtticRepositoryConverter(str(tmpdir), create=False)
repository = AtticRepositoryUpgrader(str(tmpdir), create=False)
keyfile = AtticKeyfileKey.find_key_file(repository)
AtticRepositoryConverter.convert_keyfiles(keyfile, dryrun=False)
AtticRepositoryUpgrader.convert_keyfiles(keyfile, dryrun=False)
assert key_valid(attic_key_file.path)
@ -157,7 +157,7 @@ def test_convert_all(tmpdir, attic_repo, attic_key_file):
# check should fail because of magic number
assert not repo_valid(tmpdir)
print("opening attic repository with borg and converting")
repo = AtticRepositoryConverter(str(tmpdir), create=False)
repo.convert(dryrun=False)
repo = AtticRepositoryUpgrader(str(tmpdir), create=False)
repo.upgrade(dryrun=False)
assert key_valid(attic_key_file.path)
assert repo_valid(tmpdir)

View File

@ -11,11 +11,11 @@ from .key import KeyfileKey, KeyfileNotFoundError
ATTIC_MAGIC = b'ATTICSEG'
class AtticRepositoryConverter(Repository):
def convert(self, dryrun=True):
class AtticRepositoryUpgrader(Repository):
def upgrade(self, dryrun=True):
"""convert an attic repository to a borg repository
those are the files that need to be converted here, from most
those are the files that need to be upgraded here, from most
important to least important: segments, key files, and various
caches, the latter being optional, as they will be rebuilt if
missing.
@ -62,7 +62,7 @@ class AtticRepositoryConverter(Repository):
if dryrun:
time.sleep(0.001)
else:
AtticRepositoryConverter.header_replace(filename, ATTIC_MAGIC, MAGIC)
AtticRepositoryUpgrader.header_replace(filename, ATTIC_MAGIC, MAGIC)
print()
@staticmethod
@ -197,7 +197,7 @@ class AtticRepositoryConverter(Repository):
for cache in caches:
print("converting cache %s" % cache)
if not dryrun:
AtticRepositoryConverter.header_replace(cache, b'ATTICIDX', b'BORG_IDX')
AtticRepositoryUpgrader.header_replace(cache, b'ATTICIDX', b'BORG_IDX')
class AtticKeyfileKey(KeyfileKey):