comparison mercurial/exchange.py @ 26640:b13fdcc4e700

exchange: refactor bundle specification parsing The old code was tailored to `hg bundle` usage and not appropriate for use as a general API, which clone bundles will require. The code has been rewritten to make it more generally suitable. We introduce dedicated error types to represent invalid and unsupported bundle specifications. The reason we need dedicated error types (rather than error.Abort) is because clone bundles will want to catch these exception as part of filtering entries. We don't want to swallow error.Abort on principle.
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 13 Oct 2015 10:57:54 -0700
parents 92d67e5729b9
children d2e16419d3f4
comparison
equal deleted inserted replaced
26639:92d67e5729b9 26640:b13fdcc4e700
13 import lock as lockmod 13 import lock as lockmod
14 import streamclone 14 import streamclone
15 import tags 15 import tags
16 import url as urlmod 16 import url as urlmod
17 17
18 _bundlecompspecs = {'none': None, 18 # Maps bundle compression human names to internal representation.
19 'bzip2': 'BZ', 19 _bundlespeccompressions = {'none': None,
20 'gzip': 'GZ', 20 'bzip2': 'BZ',
21 } 21 'gzip': 'GZ',
22 22 }
23 _bundleversionspecs = {'v1': '01', 23
24 'v2': '02', 24 # Maps bundle version human names to changegroup versions.
25 'bundle2': '02', #legacy 25 _bundlespeccgversions = {'v1': '01',
26 } 26 'v2': '02',
27 27 'bundle2': '02', #legacy
28 def parsebundlespec(repo, spec): 28 }
29 """return the internal bundle type to use from a user input 29
30 30 def parsebundlespec(repo, spec, strict=True):
31 This is parsing user specified bundle type as accepted in: 31 """Parse a bundle string specification into parts.
32 32
33 'hg bundle --type TYPE'. 33 Bundle specifications denote a well-defined bundle/exchange format.
34 34 The content of a given specification should not change over time in
35 It accept format in the form [compression][-version]|[version] 35 order to ensure that bundles produced by a newer version of Mercurial are
36 36 readable from an older version.
37 Consensus about extensions of the format for various bundle2 feature 37
38 is to prefix any feature with "+". eg "+treemanifest" or "gzip+phases" 38 The string currently has the form:
39
40 <compression>-<type>
41
42 Where <compression> is one of the supported compression formats
43 and <type> is (currently) a version string.
44
45 If ``strict`` is True (the default) <compression> is required. Otherwise,
46 it is optional.
47
48 Returns a 2-tuple of (compression, version). Compression will be ``None``
49 if not in strict mode and a compression isn't defined.
50
51 An ``InvalidBundleSpecification`` is raised when the specification is
52 not syntactically well formed.
53
54 An ``UnsupportedBundleSpecification`` is raised when the compression or
55 bundle type/version is not recognized.
56
57 Note: this function will likely eventually return a more complex data
58 structure, including bundle2 part information.
39 """ 59 """
40 comp, version = None, None 60 if strict and '-' not in spec:
61 raise error.InvalidBundleSpecification(
62 _('invalid bundle specification; '
63 'must be prefixed with compression: %s') % spec)
41 64
42 if '-' in spec: 65 if '-' in spec:
43 comp, version = spec.split('-', 1) 66 compression, version = spec.split('-', 1)
44 elif spec in _bundlecompspecs: 67
45 comp = spec 68 if compression not in _bundlespeccompressions:
46 elif spec in _bundleversionspecs: 69 raise error.UnsupportedBundleSpecification(
47 version = spec 70 _('%s compression is not supported') % compression)
71
72 if version not in _bundlespeccgversions:
73 raise error.UnsupportedBundleSpecification(
74 _('%s is not a recognized bundle version') % version)
48 else: 75 else:
49 raise error.Abort(_('unknown bundle type specified with --type')) 76 # Value could be just the compression or just the version, in which
50 77 # case some defaults are assumed (but only when not in strict mode).
51 if comp is None: 78 assert not strict
52 comp = 'BZ' 79
53 else: 80 if spec in _bundlespeccompressions:
54 try: 81 compression = spec
55 comp = _bundlecompspecs[comp] 82 version = 'v1'
56 except KeyError: 83 if 'generaldelta' in repo.requirements:
57 raise error.Abort(_('unknown bundle type specified with --type')) 84 version = 'v2'
58 85 elif spec in _bundlespeccgversions:
59 if version is None: 86 compression = 'bzip2'
60 version = '01' 87 version = spec
61 if 'generaldelta' in repo.requirements: 88 else:
62 version = '02' 89 raise error.UnsupportedBundleSpecification(
63 else: 90 _('%s is not a recognized bundle specification') % spec)
64 try: 91
65 version = _bundleversionspecs[version] 92 compression = _bundlespeccompressions[compression]
66 except KeyError: 93 version = _bundlespeccgversions[version]
67 raise error.Abort(_('unknown bundle type specified with --type')) 94 return compression, version
68
69 return version, comp
70 95
71 def readbundle(ui, fh, fname, vfs=None): 96 def readbundle(ui, fh, fname, vfs=None):
72 header = changegroup.readexactly(fh, 4) 97 header = changegroup.readexactly(fh, 4)
73 98
74 alg = None 99 alg = None