Patchwork [4,of,4] bundle2: implement the mandatory/advisory logic for parameter

login
register
mail settings
Submitter Pierre-Yves David
Date March 21, 2014, 10:12 p.m.
Message ID <44a929f82fbb399bf24d.1395439976@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/4034/
State Accepted
Commit 2631204d73052c8e2b8113083a90bc3f9a0ebf18
Headers show

Comments

Pierre-Yves David - March 21, 2014, 10:12 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1395276825 25200
#      Wed Mar 19 17:53:45 2014 -0700
# Node ID 44a929f82fbb399bf24d6a8484cfda1175a91634
# Parent  8d47c765129239116a52caffbdc61e21171cdf9c
bundle2: implement the mandatory/advisory logic for parameter

Parameter starting with an upper case are mandatory, the one starting with a
lower case are advisory and may be ignored.
Matt Mackall - March 27, 2014, 1:56 a.m.
On Fri, 2014-03-21 at 15:12 -0700, pierre-yves.david@ens-lyon.org wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@fb.com>
> # Date 1395276825 25200
> #      Wed Mar 19 17:53:45 2014 -0700
> # Node ID 44a929f82fbb399bf24d6a8484cfda1175a91634
> # Parent  8d47c765129239116a52caffbdc61e21171cdf9c
> bundle2: implement the mandatory/advisory logic for parameter

These are queued for default, thanks.

Patch

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -45,13 +45,14 @@  Binary format is as follow
   The blob contains a space separated list of parameters. parameter with value
   are stored in the form `<name>=<value>`. Both name and value are urlquoted.
 
   Empty name are obviously forbidden.
 
-  Name MUST start with a letter. This first character has to be capitalizable.
-  The capitalisation of the first letter will be used to know if an option is
-  advisory or mandatory. This is not implemented yet.
+  Name MUST start with a letter. If this first letter is lower case, the
+  parameter is advisory and can be safefly ignored. However when the first
+  letter is capital, the parameter is mandatory and the bundling process MUST
+  stop if he is not able to proceed it.
 
   Stream parameters use a simple textual format for two main reasons:
 
   - Stream level parameters should remains simple and we want to discourage any
     crazy usage.
@@ -171,13 +172,36 @@  class unbundle20(object):
             for p in self._readexact(paramssize).split(' '):
                 p = p.split('=', 1)
                 p = [urllib.unquote(i) for i in p]
                 if len(p) < 2:
                     p.append(None)
+                self._processparam(*p)
                 params[p[0]] = p[1]
         return params
 
+    def _processparam(self, name, value):
+        """process a parameter, applying its effect if needed
+
+        Parameter starting with a lower case letter are advisory and will be
+        ignored when unknown.  Those starting with an upper case letter are
+        mandatory and will this function will raise a KeyError when unknown.
+
+        Note: no option are currently supported. Any input will be either
+              ignored or failing.
+        """
+        if not name:
+            raise ValueError('empty parameter name')
+        if name[0] not in string.letters:
+            raise ValueError('non letter first character: %r' % name)
+        # Some logic will be later added here to try to process the option for
+        # a dict of known parameter.
+        if name[0].islower():
+            self.ui.debug("ignoring unknown parameter %r\n" % name)
+        else:
+            raise KeyError(name)
+
+
     def __iter__(self):
         """yield all parts contained in the stream"""
         # make sure param have been loaded
         self.params
         self.ui.debug('start extraction of bundle2 parts\n')
diff --git a/tests/test-bundle2.t b/tests/test-bundle2.t
--- a/tests/test-bundle2.t
+++ b/tests/test-bundle2.t
@@ -38,14 +38,18 @@  Create an extension to test bundle2 API
   > 
   > @command('unbundle2', [], '')
   > def cmdunbundle2(ui, repo):
   >     """read a bundle2 container from standard input"""
   >     unbundler = bundle2.unbundle20(ui, sys.stdin)
-  >     ui.write('options count: %i\n' % len(unbundler.params))
-  >     for key in sorted(unbundler.params):
+  >     try:
+  >         params = unbundler.params
+  >     except KeyError, exc:
+  >        raise util.Abort('unknown parameters: %s' % exc)
+  >     ui.write('options count: %i\n' % len(params))
+  >     for key in sorted(params):
   >         ui.write('- %s\n' % key)
-  >         value = unbundler.params[key]
+  >         value = params[key]
   >         if value is not None:
   >             ui.write('    %s\n' % value)
   >     parts = list(unbundler)
   >     ui.write('parts count:   %i\n' % len(parts))
   > EOF
@@ -157,10 +161,17 @@  Test unbundling
   - e|! 7/
       babar%#==tutu
   - simple
   parts count:   0
 
+Test unknown mandatory option
+---------------------------------------------------
+
+  $ hg bundle2 --param 'Gravity' | hg unbundle2
+  abort: unknown parameters: 'Gravity'
+  [255]
+
 Test debug output
 ---------------------------------------------------
 
 bundling debug
 
@@ -177,10 +188,12 @@  file content is ok
 unbundling debug
 
   $ hg unbundle2 --debug < ../out.hg2
   start processing of HG20 stream
   reading bundle2 stream parameters
+  ignoring unknown parameter 'e|! 7/'
+  ignoring unknown parameter 'simple'
   options count: 2
   - e|! 7/
       babar%#==tutu
   - simple
   start extraction of bundle2 parts