changeset 15838:7299e09a85a2

phases: make outgoing object and discovery aware of exclusion The outgoing object gains an "excluded" members holding all changesets which were excluded because there where secret. The core discovery code now remove secret changeset from discovery by default. This means that any command relying on discovery will exclude secret changeset. Most notable one are outgoing and bundle. (But bundle with and explicit ``--base`` still allow to bundle outgoing changeset.
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
date Wed, 11 Jan 2012 00:27:46 +0100
parents cd956049fc14
children 43317af36d28
files mercurial/discovery.py tests/test-check-code-hg.t tests/test-phases.t
diffstat 3 files changed, 67 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/discovery.py	Mon Jan 09 03:47:16 2012 +0100
+++ b/mercurial/discovery.py	Wed Jan 11 00:27:46 2012 +0100
@@ -7,7 +7,7 @@
 
 from node import nullid, short
 from i18n import _
-import util, setdiscovery, treediscovery
+import util, setdiscovery, treediscovery, phases
 
 def findcommonincoming(repo, remote, heads=None, force=False):
     """Return a tuple (common, anyincoming, heads) used to identify the common
@@ -54,6 +54,7 @@
 
       missing is a list of all nodes present in local but not in remote.
       common is a list of all nodes shared between the two repos.
+      excluded is the list of missing changeset that shouldn't be sent remotely.
       missingheads is the list of heads of missing.
       commonheads is the list of heads of common.
 
@@ -66,6 +67,7 @@
         self._revlog = revlog
         self._common = None
         self._missing = None
+        self.excluded = []
 
     def _computecommonmissing(self):
         sets = self._revlog.findcommonmissing(self.commonheads,
@@ -94,8 +96,41 @@
 
     If commoninc is given, it must the the result of a prior call to
     findcommonincoming(repo, other, force) to avoid recomputing it here.'''
-    common, _any, _hds = commoninc or findcommonincoming(repo, other, force=force)
-    return outgoing(repo.changelog, common, onlyheads or repo.heads())
+    # declare an empty outgoing object to be filled later
+    og = outgoing(repo.changelog, None, None)
+
+    # get common set if not provided
+    if commoninc is None:
+        commoninc = findcommonincoming(repo, other, force=force)
+    og.commonheads, _any, _hds = commoninc
+
+    # compute outgoing
+    if not repo._phaseroots[phases.secret]:
+        og.missingheads = onlyheads or repo.heads()
+    elif onlyheads is None:
+        # use visible heads as it should be cached
+        og.missingheads = phases.visibleheads(repo)
+        og.excluded = [ctx.node() for ctx in repo.set('secret()')]
+    else:
+        # compute common, missing and exclude secret stuff
+        sets = repo.changelog.findcommonmissing(og.commonheads, onlyheads)
+        og._common, allmissing = sets
+        og._missing = missing = []
+        og._excluded = excluded = []
+        for node in allmissing:
+            if repo[node].phase() >= phases.secret:
+                excluded.append(node)
+            else:
+                missing.append(node)
+        if excluded:
+            # update missing heads
+            rset = repo.set('heads(%ln)', missing)
+            missingheads = [ctx.node() for ctx in rset]
+        else:
+            missingheads = onlyheads
+        og.missingheads = missingheads
+
+    return og
 
 def prepush(repo, remote, force, revs, newbranch):
     '''Analyze the local and remote repositories and determine which
@@ -121,29 +156,17 @@
     _common, inc, remoteheads = commoninc
 
     cl = repo.changelog
-    alloutg = outgoing.missing
+    outg = outgoing.missing
     common = outgoing.commonheads
-    outg = []
-    secret = []
-    for o in alloutg:
-        if repo[o].phase() >= 2:
-            secret.append(o)
-        else:
-            outg.append(o)
 
     if not outg:
-        if secret:
+        if outgoing.excluded:
             repo.ui.status(_("no changes to push but %i secret changesets\n")
-                           % len(secret))
+                           % len(outgoing.excluded))
         else:
             repo.ui.status(_("no changes found\n"))
         return None, 1, common
 
-    if secret:
-        # recompute target revs
-        revs = [ctx.node() for ctx in repo.set('heads(::(%ld))',
-                                               map(repo.changelog.rev, outg))]
-
     if not force and remoteheads != [nullid]:
         if remote.capable('branchmap'):
             # Check for each named branch if we're creating new remote heads.
@@ -241,7 +264,8 @@
         if unsynced:
             repo.ui.warn(_("note: unsynced remote changes!\n"))
 
-    if revs is None:
+    if revs is None and not outgoing.excluded:
+        # push everything,
         # use the fast path, no race possible on push
         cg = repo._changegroup(outg, 'push')
     else:
--- a/tests/test-check-code-hg.t	Mon Jan 09 03:47:16 2012 +0100
+++ b/tests/test-check-code-hg.t	Wed Jan 11 00:27:46 2012 +0100
@@ -351,9 +351,6 @@
    >     If onlyheads is given, only nodes ancestral to nodes in onlyheads (inclusive)
    warning: line over 80 characters
   mercurial/discovery.py:0:
-   >     common, _any, _hds = commoninc or findcommonincoming(repo, other, force=force)
-   warning: line over 80 characters
-  mercurial/discovery.py:0:
    > def findcommonoutgoing(repo, other, onlyheads=None, force=False, commoninc=None):
    warning: line over 80 characters
   mercurial/dispatch.py:0:
--- a/tests/test-phases.t	Mon Jan 09 03:47:16 2012 +0100
+++ b/tests/test-phases.t	Wed Jan 11 00:27:46 2012 +0100
@@ -95,6 +95,23 @@
   > [phases]
   > publish=False
   > EOF
+  $ hg outgoing ../push-dest --template='{rev} {phase} {desc|firstline}\n'
+  comparing with ../push-dest
+  searching for changes
+  0 public A
+  1 public B
+  2 draft C
+  3 draft D
+  6 draft B'
+  $ hg outgoing -r default ../push-dest --template='{rev} {phase} {desc|firstline}\n'
+  comparing with ../push-dest
+  searching for changes
+  0 public A
+  1 public B
+  2 draft C
+  3 draft D
+  6 draft B'
+
   $ hg push ../push-dest -f # force because we push multiple heads
   pushing to ../push-dest
   searching for changes
@@ -140,6 +157,13 @@
   0 0 A
   $ cd ..
 
+But secret can still be bundled explicitly
+
+  $ cd initialrepo
+  $ hg bundle --base '4^' -r 'children(4)' ../secret-bundle.hg
+  4 changesets found
+  $ cd ..
+
 Test revset
 
   $ cd initialrepo