Patchwork [STABLE] changegroup: fix pulling to treemanifest repo from flat repo (issue5066)

login
register
mail settings
Submitter Martin von Zweigbergk
Date Jan. 28, 2016, 6:50 p.m.
Message ID <798557f9b388175637a6.1454007036@waste.org>
Download mbox | patch
Permalink /patch/12902/
State Superseded
Commit 88609cfa37455815e4d6acd45e2a8893720c065b
Headers show

Comments

Martin von Zweigbergk - Jan. 28, 2016, 6:50 p.m.
# HG changeset patch
# User Martin von Zweigbergk <martinvonz@google.com>
# Date 1453914448 28800
#      Wed Jan 27 09:07:28 2016 -0800
# Branch stable
# Node ID 798557f9b388175637a61a35503e3bc528ccf894
# Parent  4511e8dac4c798e5fed91e629aa9802b01c2b6c3
changegroup: fix pulling to treemanifest repo from flat repo (issue5066)

In c0f11347b107 (changegroup: don't support versions 01 and 02 with
treemanifests, 2016-01-19), I stopped supporting use of cg1 and cg2
with treemanifest repos. What I had not considered was that it's
perfectly safe to pull *to* a treemanifest repo using any changegroup
version. As reported in issue5066, I therefore broke pull from old
repos into a treemanifest repo. It was not covered by the test case,
because that pulled from a local repo while enabling treemanifests,
which enabled treemanifests on the source repo as well. After
switching to pulling via HTTP, it breaks.

Fix by splitting up changegroup.supportedversions() into
supportedincomingversions() and supportedoutgoingversions().
Martin von Zweigbergk - Jan. 28, 2016, 8 p.m.
I realized I should also make sure that pushing from flat to tree works.
Will add tests (and fixes if necessary) and resend after lunch

On Thu, Jan 28, 2016, 10:51 Martin von Zweigbergk <martinvonz@google.com>
wrote:

> # HG changeset patch
> # User Martin von Zweigbergk <martinvonz@google.com>
> # Date 1453914448 28800
> #      Wed Jan 27 09:07:28 2016 -0800
> # Branch stable
> # Node ID 798557f9b388175637a61a35503e3bc528ccf894
> # Parent  4511e8dac4c798e5fed91e629aa9802b01c2b6c3
> changegroup: fix pulling to treemanifest repo from flat repo (issue5066)
>
> In c0f11347b107 (changegroup: don't support versions 01 and 02 with
> treemanifests, 2016-01-19), I stopped supporting use of cg1 and cg2
> with treemanifest repos. What I had not considered was that it's
> perfectly safe to pull *to* a treemanifest repo using any changegroup
> version. As reported in issue5066, I therefore broke pull from old
> repos into a treemanifest repo. It was not covered by the test case,
> because that pulled from a local repo while enabling treemanifests,
> which enabled treemanifests on the source repo as well. After
> switching to pulling via HTTP, it breaks.
>
> Fix by splitting up changegroup.supportedversions() into
> supportedincomingversions() and supportedoutgoingversions().
>
> diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
> --- a/mercurial/bundle2.py
> +++ b/mercurial/bundle2.py
> @@ -1242,7 +1242,8 @@
>      Exists to allow extensions (like evolution) to mutate the
> capabilities.
>      """
>      caps = capabilities.copy()
> -    caps['changegroup'] =
> tuple(sorted(changegroup.supportedversions(repo)))
> +    caps['changegroup'] = tuple(sorted(
> +        changegroup.supportedincomingversions(repo)))
>      if obsolete.isenabled(repo, obsolete.exchangeopt):
>          supportedformat = tuple('V%i' % v for v in obsolete.formats)
>          caps['obsmarkers'] = supportedformat
> diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
> --- a/mercurial/bundlerepo.py
> +++ b/mercurial/bundlerepo.py
> @@ -282,7 +282,7 @@
>                                                    "multiple changegroups")
>                      cgstream = part
>                      version = part.params.get('version', '01')
> -                    if version not in changegroup.supportedversions(self):
> +                    if version not in
> changegroup.allsupportedversions(ui):
>                          msg = _('Unsupported changegroup version: %s')
>                          raise error.Abort(msg % version)
>                      if self.bundle.compressed():
> diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
> --- a/mercurial/changegroup.py
> +++ b/mercurial/changegroup.py
> @@ -946,10 +946,25 @@
>               '03': (cg3packer, cg3unpacker),
>  }
>
> -def supportedversions(repo):
> +def allsupportedversions(ui):
>      versions = set(_packermap.keys())
> -    if ('treemanifest' in repo.requirements or
> -        repo.ui.configbool('experimental', 'treemanifest')):
> +    versions.discard('03')
> +    if (ui.configbool('experimental', 'changegroup3') or
> +        ui.configbool('experimental', 'treemanifest')):
> +        versions.add('03')
> +    return versions
> +
> +# Changegroup versions that can be applied to the repo
> +def supportedincomingversions(repo):
> +    versions = allsupportedversions(repo.ui)
> +    if 'treemanifest' in repo.requirements:
> +        versions.add('03')
> +    return versions
> +
> +# Changegroup versions that can be created from the repo
> +def supportedoutgoingversions(repo):
> +    versions = allsupportedversions(repo.ui)
> +    if 'treemanifest' in repo.requirements:
>          # Versions 01 and 02 support only flat manifests and it's just too
>          # expensive to convert between the flat manifest and tree
> manifest on
>          # the fly. Since tree manifests are hashed differently, all of
> history
> @@ -957,22 +972,21 @@
>          # support versions 01 and 02.
>          versions.discard('01')
>          versions.discard('02')
> -    elif not repo.ui.configbool('experimental', 'changegroup3'):
> -        versions.discard('03')
> +        versions.add('03')
>      return versions
>
>  def safeversion(repo):
>      # Finds the smallest version that it's safe to assume clients of the
> repo
>      # will support. For example, all hg versions that support
> generaldelta also
>      # support changegroup 02.
> -    versions = supportedversions(repo)
> +    versions = supportedoutgoingversions(repo)
>      if 'generaldelta' in repo.requirements:
>          versions.discard('01')
>      assert versions
>      return min(versions)
>
>  def getbundler(version, repo, bundlecaps=None):
> -    assert version in supportedversions(repo)
> +    assert version in supportedoutgoingversions(repo)
>      return _packermap[version][0](repo, bundlecaps)
>
>  def getunbundler(version, fh, alg):
> diff --git a/mercurial/exchange.py b/mercurial/exchange.py
> --- a/mercurial/exchange.py
> +++ b/mercurial/exchange.py
> @@ -707,7 +707,8 @@
>                                                  pushop.outgoing)
>      else:
>          cgversions = [v for v in cgversions
> -                      if v in changegroup.supportedversions(pushop.repo)]
> +                      if v in changegroup.supportedoutgoingversions(
> +                          pushop.repo)]
>          if not cgversions:
>              raise ValueError(_('no common changegroup version'))
>          version = max(cgversions)
> @@ -1562,7 +1563,7 @@
>          getcgkwargs = {}
>          if cgversions:  # 3.1 and 3.2 ship with an empty value
>              cgversions = [v for v in cgversions
> -                          if v in changegroup.supportedversions(repo)]
> +                          if v in
> changegroup.supportedoutgoingversions(repo)]
>              if not cgversions:
>                  raise ValueError(_('no common changegroup version'))
>              version = getcgkwargs['version'] = max(cgversions)
> diff --git a/tests/test-treemanifest.t b/tests/test-treemanifest.t
> --- a/tests/test-treemanifest.t
> +++ b/tests/test-treemanifest.t
> @@ -202,11 +202,14 @@
>    3 files updated, 0 files merged, 0 files removed, 0 files unresolved
>    (branch merge, don't forget to commit)
>    $ hg ci -m 'merge of flat manifests to new flat manifest'
> +  $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
> +  $ cat hg.pid >> $DAEMON_PIDS
>
>  Create clone with tree manifests enabled
>
>    $ cd ..
> -  $ hg clone --pull --config experimental.treemanifest=1 repo-flat
> repo-mixed
> +  $ hg clone --config experimental.treemanifest=1 \
> +  >   http://localhost:$HGPORT repo-mixed
>    requesting all changes
>    adding changesets
>    adding manifests
> @@ -441,13 +444,13 @@
>    $ hg ci -m troz
>
>  Test cloning a treemanifest repo over http.
> -  $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
> +  $ hg serve -p $HGPORT2 -d --pid-file=hg.pid --errorlog=errors.log
>    $ cat hg.pid >> $DAEMON_PIDS
>    $ cd ..
>  We can clone even with the knob turned off and we'll get a treemanifest
> repo.
>    $ hg clone --config experimental.treemanifest=False \
>    >   --config experimental.changegroup3=True \
> -  >   http://localhost:$HGPORT deepclone
> +  >   http://localhost:$HGPORT2 deepclone
>    requesting all changes
>    adding changesets
>    adding manifests
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel
>

Patch

diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
--- a/mercurial/bundle2.py
+++ b/mercurial/bundle2.py
@@ -1242,7 +1242,8 @@ 
     Exists to allow extensions (like evolution) to mutate the capabilities.
     """
     caps = capabilities.copy()
-    caps['changegroup'] = tuple(sorted(changegroup.supportedversions(repo)))
+    caps['changegroup'] = tuple(sorted(
+        changegroup.supportedincomingversions(repo)))
     if obsolete.isenabled(repo, obsolete.exchangeopt):
         supportedformat = tuple('V%i' % v for v in obsolete.formats)
         caps['obsmarkers'] = supportedformat
diff --git a/mercurial/bundlerepo.py b/mercurial/bundlerepo.py
--- a/mercurial/bundlerepo.py
+++ b/mercurial/bundlerepo.py
@@ -282,7 +282,7 @@ 
                                                   "multiple changegroups")
                     cgstream = part
                     version = part.params.get('version', '01')
-                    if version not in changegroup.supportedversions(self):
+                    if version not in changegroup.allsupportedversions(ui):
                         msg = _('Unsupported changegroup version: %s')
                         raise error.Abort(msg % version)
                     if self.bundle.compressed():
diff --git a/mercurial/changegroup.py b/mercurial/changegroup.py
--- a/mercurial/changegroup.py
+++ b/mercurial/changegroup.py
@@ -946,10 +946,25 @@ 
              '03': (cg3packer, cg3unpacker),
 }
 
-def supportedversions(repo):
+def allsupportedversions(ui):
     versions = set(_packermap.keys())
-    if ('treemanifest' in repo.requirements or
-        repo.ui.configbool('experimental', 'treemanifest')):
+    versions.discard('03')
+    if (ui.configbool('experimental', 'changegroup3') or
+        ui.configbool('experimental', 'treemanifest')):
+        versions.add('03')
+    return versions
+
+# Changegroup versions that can be applied to the repo
+def supportedincomingversions(repo):
+    versions = allsupportedversions(repo.ui)
+    if 'treemanifest' in repo.requirements:
+        versions.add('03')
+    return versions
+
+# Changegroup versions that can be created from the repo
+def supportedoutgoingversions(repo):
+    versions = allsupportedversions(repo.ui)
+    if 'treemanifest' in repo.requirements:
         # Versions 01 and 02 support only flat manifests and it's just too
         # expensive to convert between the flat manifest and tree manifest on
         # the fly. Since tree manifests are hashed differently, all of history
@@ -957,22 +972,21 @@ 
         # support versions 01 and 02.
         versions.discard('01')
         versions.discard('02')
-    elif not repo.ui.configbool('experimental', 'changegroup3'):
-        versions.discard('03')
+        versions.add('03')
     return versions
 
 def safeversion(repo):
     # Finds the smallest version that it's safe to assume clients of the repo
     # will support. For example, all hg versions that support generaldelta also
     # support changegroup 02.
-    versions = supportedversions(repo)
+    versions = supportedoutgoingversions(repo)
     if 'generaldelta' in repo.requirements:
         versions.discard('01')
     assert versions
     return min(versions)
 
 def getbundler(version, repo, bundlecaps=None):
-    assert version in supportedversions(repo)
+    assert version in supportedoutgoingversions(repo)
     return _packermap[version][0](repo, bundlecaps)
 
 def getunbundler(version, fh, alg):
diff --git a/mercurial/exchange.py b/mercurial/exchange.py
--- a/mercurial/exchange.py
+++ b/mercurial/exchange.py
@@ -707,7 +707,8 @@ 
                                                 pushop.outgoing)
     else:
         cgversions = [v for v in cgversions
-                      if v in changegroup.supportedversions(pushop.repo)]
+                      if v in changegroup.supportedoutgoingversions(
+                          pushop.repo)]
         if not cgversions:
             raise ValueError(_('no common changegroup version'))
         version = max(cgversions)
@@ -1562,7 +1563,7 @@ 
         getcgkwargs = {}
         if cgversions:  # 3.1 and 3.2 ship with an empty value
             cgversions = [v for v in cgversions
-                          if v in changegroup.supportedversions(repo)]
+                          if v in changegroup.supportedoutgoingversions(repo)]
             if not cgversions:
                 raise ValueError(_('no common changegroup version'))
             version = getcgkwargs['version'] = max(cgversions)
diff --git a/tests/test-treemanifest.t b/tests/test-treemanifest.t
--- a/tests/test-treemanifest.t
+++ b/tests/test-treemanifest.t
@@ -202,11 +202,14 @@ 
   3 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (branch merge, don't forget to commit)
   $ hg ci -m 'merge of flat manifests to new flat manifest'
+  $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
+  $ cat hg.pid >> $DAEMON_PIDS
 
 Create clone with tree manifests enabled
 
   $ cd ..
-  $ hg clone --pull --config experimental.treemanifest=1 repo-flat repo-mixed
+  $ hg clone --config experimental.treemanifest=1 \
+  >   http://localhost:$HGPORT repo-mixed
   requesting all changes
   adding changesets
   adding manifests
@@ -441,13 +444,13 @@ 
   $ hg ci -m troz
 
 Test cloning a treemanifest repo over http.
-  $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
+  $ hg serve -p $HGPORT2 -d --pid-file=hg.pid --errorlog=errors.log
   $ cat hg.pid >> $DAEMON_PIDS
   $ cd ..
 We can clone even with the knob turned off and we'll get a treemanifest repo.
   $ hg clone --config experimental.treemanifest=False \
   >   --config experimental.changegroup3=True \
-  >   http://localhost:$HGPORT deepclone
+  >   http://localhost:$HGPORT2 deepclone
   requesting all changes
   adding changesets
   adding manifests