[PATCH 2 of 2 V2] exchange: refactor bundle specification parsing

Gregory Szorc gregory.szorc at gmail.com
Tue Oct 13 12:49:32 CDT 2015


Please drop this one since Python 2.6 doesn't like e.message.

On Tue, Oct 13, 2015 at 10:15 AM, Gregory Szorc <gregory.szorc at gmail.com>
wrote:

> # HG changeset patch
> # User Gregory Szorc <gregory.szorc at gmail.com>
> # Date 1444756406 25200
> #      Tue Oct 13 10:13:26 2015 -0700
> # Node ID 0f386c4467f46f2c863f4dabc3bd6c4ca558a9f7
> # Parent  d93dfcd4e505405756891a3418ad26891ffbcfa4
> 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.
>
> diff --git a/mercurial/commands.py b/mercurial/commands.py
> --- a/mercurial/commands.py
> +++ b/mercurial/commands.py
> @@ -1241,10 +1241,15 @@ def bundle(ui, repo, fname, dest=None, *
>      if 'rev' in opts:
>          revs = scmutil.revrange(repo, opts['rev'])
>
>      bundletype = opts.get('type', 'bzip2').lower()
> -    cgversion, bcompression = exchange.parsebundlespecification(repo,
> -
> bundletype)
> +    try:
> +        bcompression, cgversion = exchange.parsebundlespecification(
> +                repo, bundletype, strict=False)
> +    except error.UnsupportedBundleSpecification as e:
> +        raise error.Abort(e.message,
> +                          hint=_('see "hg help bundle" for supported '
> +                                 'values for --type'))
>
>      if opts.get('all'):
>          base = ['null']
>      else:
> diff --git a/mercurial/error.py b/mercurial/error.py
> --- a/mercurial/error.py
> +++ b/mercurial/error.py
> @@ -200,4 +200,13 @@ class CensoredBaseError(RevlogError):
>      A delta based on a censored revision must be formed as single patch
>      operation which replaces the entire base with new content. This
> ensures
>      the delta may be applied by clones which have not censored the base.
>      """
> +
> +class InvalidBundleSpecification(Exception):
> +    """error raised when a bundle specification is invalid.
> +
> +    This is used for syntax errors as opposed to support errors.
> +    """
> +
> +class UnsupportedBundleSpecification(Exception):
> +    """error raised when a bundle specification is not supported."""
> diff --git a/mercurial/exchange.py b/mercurial/exchange.py
> --- a/mercurial/exchange.py
> +++ b/mercurial/exchange.py
> @@ -13,60 +13,86 @@ import discovery, phases, obsolete, book
>  import lock as lockmod
>  import streamclone
>  import tags
>
> -_bundlecompspecs = {'none': None,
> -                    'bzip2': 'BZ',
> -                    'gzip': 'GZ',
> -                   }
> +# Maps bundle compression human names to internal representation.
> +_bundlespeccompressions = {'none': None,
> +                           'bzip2': 'BZ',
> +                           'gzip': 'GZ',
> +                          }
>
> -_bundleversionspecs = {'v1': '01',
> -                       'v2': '02',
> -                       'bundle2': '02', #legacy
> -                      }
> +# Maps bundle version human names to changegroup versions.
> +_bundlespeccgversions = {'v1': '01',
> +                         'v2': '02',
> +                         'bundle2': '02', #legacy
> +                        }
>
> -def parsebundlespecification(repo, spec):
> -    """return the internal bundle type to use from a user input
> +def parsebundlespecification(repo, spec, strict=True):
> +    """Parse a bundle string specification into parts.
>
> -    This is parsing user specified bundle type as accepted in:
> +    Bundle specifications denote a well-defined bundle/exchange format.
> +    The content of a given specification should not change over time in
> +    order to ensure that bundles produced by a newer version of Mercurial
> are
> +    readable from an older version.
>
> -        'hg bundle --type TYPE'.
> +    The string currently has the form:
>
> -    It accept format in the form [compression][-version]|[version]
> +       <compression>-<type>
>
> -    Consensus about extensions of the format for various bundle2 feature
> -    is to prefix any feature with "+". eg "+treemanifest" or "gzip+phases"
> +    Where <compression> is one of the supported compression formats
> +    and <type> is (currently) a version string.
> +
> +    If ``strict`` is True (the default) <compression> is required.
> Otherwise,
> +    it is optional.
> +
> +    Returns a 2-tuple of (compression, version). Compression will be
> ``None``
> +    if not in strict mode and a compression isn't defined.
> +
> +    An ``InvalidBundleSpecification`` is raised when the specification is
> +    not syntactically well formed.
> +
> +    An ``UnsupportedBundleSpecification`` is raised when the compression
> or
> +    bundle type/version is not recognized.
> +
> +    Note: this function will likely eventually return a more complex data
> +    structure, including bundle2 part information.
>      """
> -    comp, version = None, None
> +    if strict and '-' not in spec:
> +        raise error.InvalidBundleSpecification(
> +                _('invalid bundle specification; '
> +                  'must be prefixed with compression: %s') % spec)
>
>      if '-' in spec:
> -        comp, version = spec.split('-', 1)
> -    elif spec in _bundlecompspecs:
> -        comp = spec
> -    elif spec in _bundleversionspecs:
> -        version = spec
> +        compression, version = spec.split('-', 1)
> +
> +        if compression not in _bundlespeccompressions:
> +            raise error.UnsupportedBundleSpecification(
> +                    _('%s compression is not supported') % compression)
> +
> +        if version not in _bundlespeccgversions:
> +            raise error.UnsupportedBundleSpecification(
> +                    _('%s is not a recognized bundle version') % version)
>      else:
> -        raise error.Abort(_('unknown bundle type specified with --type'))
> +        # Value could be just the compression or just the version, in
> which
> +        # case some defaults are assumed (but only when not in strict
> mode).
> +        assert not strict
>
> -    if comp is None:
> -        comp = 'BZ'
> -    else:
> -        try:
> -            comp = _bundlecompspecs[comp]
> -        except KeyError:
> -            raise error.Abort(_('unknown bundle type specified with
> --type'))
> +        if spec in _bundlespeccompressions:
> +            compression = spec
> +            version = 'v1'
> +            if 'generaldelta' in repo.requirements:
> +                version = 'v2'
> +        elif spec in _bundlespeccgversions:
> +            compression = 'bzip2'
> +            version = spec
> +        else:
> +            raise error.UnsupportedBundleSpecification(
> +                    _('%s is not a recognized bundle specification') %
> spec)
>
> -    if version is None:
> -        version = '01'
> -        if 'generaldelta' in repo.requirements:
> -            version = '02'
> -    else:
> -        try:
> -            version = _bundleversionspecs[version]
> -        except KeyError:
> -            raise error.Abort(_('unknown bundle type specified with
> --type'))
> +    compression = _bundlespeccompressions[compression]
> +    version = _bundlespeccgversions[version]
> +    return compression, version
>
> -    return version, comp
>  def readbundle(ui, fh, fname, vfs=None):
>      header = changegroup.readexactly(fh, 4)
>
>      alg = None
> diff --git a/tests/test-bundle-type.t b/tests/test-bundle-type.t
> --- a/tests/test-bundle-type.t
> +++ b/tests/test-bundle-type.t
> @@ -101,7 +101,8 @@ test garbage file
>  test invalid bundle type
>
>    $ cd t1
>    $ hg bundle -a -t garbage ../bgarbage
> -  abort: unknown bundle type specified with --type
> +  abort: garbage is not a recognized bundle specification
> +  (see "hg help bundle" for supported values for --type)
>    [255]
>    $ cd ..
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://selenic.com/pipermail/mercurial-devel/attachments/20151013/d62070ac/attachment.html>


More information about the Mercurial-devel mailing list