merge with crew
authorMatt Mackall <mpm@selenic.com>
Thu, 13 Feb 2014 15:33:24 -0600
changeset 20492 d0bca0649c7f
parent 20489 7b5ec1c7e8e2 (diff)
parent 20491 da64679bfc8a (current diff)
child 20493 b5f43dbf64ca
merge with crew
--- a/mercurial/exchange.py	Thu Feb 13 13:08:50 2014 +0100
+++ b/mercurial/exchange.py	Thu Feb 13 15:33:24 2014 -0600
@@ -395,6 +395,25 @@
         self._trname = 'pull\n' + util.hidepassword(remote.url())
         # hold the transaction once created
         self._tr = None
+        # set of common changeset between local and remote before pull
+        self.common = None
+        # set of pulled head
+        self.rheads = None
+        # list of missing changeset to fetch remotly
+        self.fetch = None
+
+    @util.propertycache
+    def pulledsubset(self):
+        """heads of the set of changeset target by the pull"""
+        # compute target subset
+        if self.heads is None:
+            # We pulled every thing possible
+            # sync on everything common
+            return self.common + self.rheads
+        else:
+            # We pulled a specific subset
+            # sync on this subset
+            return self.heads
 
     def gettransaction(self):
         """get appropriate pull transaction, creating it if needed"""
@@ -428,62 +447,14 @@
                                            pullop.remote,
                                            heads=pullop.heads,
                                            force=force)
-        common, fetch, rheads = tmp
-        if not fetch:
+        pullop.common, pullop.fetch, pullop.rheads = tmp
+        if not pullop.fetch:
             pullop.repo.ui.status(_("no changes found\n"))
             result = 0
         else:
-            # We delay the open of the transaction as late as possible so we
-            # don't open transaction for nothing or you break future useful
-            # rollback call
-            pullop.gettransaction()
-            if pullop.heads is None and list(common) == [nullid]:
-                pullop.repo.ui.status(_("requesting all changes\n"))
-            elif (pullop.heads is None
-                  and pullop.remote.capable('changegroupsubset')):
-                # issue1320, avoid a race if remote changed after discovery
-                pullop.heads = rheads
+            result = _pullchangeset(pullop)
 
-            if pullop.remote.capable('getbundle'):
-                # TODO: get bundlecaps from remote
-                cg = pullop.remote.getbundle('pull', common=common,
-                                             heads=pullop.heads or rheads)
-            elif pullop.heads is None:
-                cg = pullop.remote.changegroup(fetch, 'pull')
-            elif not pullop.remote.capable('changegroupsubset'):
-                raise util.Abort(_("partial pull cannot be done because "
-                                       "other repository doesn't support "
-                                       "changegroupsubset."))
-            else:
-                cg = pullop.remote.changegroupsubset(fetch, pullop.heads,
-                                                     'pull')
-            result = pullop.repo.addchangegroup(cg, 'pull',
-                                                pullop.remote.url())
-
-        # compute target subset
-        if pullop.heads is None:
-            # We pulled every thing possible
-            # sync on everything common
-            subset = common + rheads
-        else:
-            # We pulled a specific subset
-            # sync on this subset
-            subset = pullop.heads
-
-        # Get remote phases data from remote
-        remotephases = pullop.remote.listkeys('phases')
-        publishing = bool(remotephases.get('publishing', False))
-        if remotephases and not publishing:
-            # remote is new and unpublishing
-            pheads, _dr = phases.analyzeremotephases(pullop.repo, subset,
-                                                     remotephases)
-            phases.advanceboundary(pullop.repo, phases.public, pheads)
-            phases.advanceboundary(pullop.repo, phases.draft, subset)
-        else:
-            # Remote is old or publishing all common changesets
-            # should be seen as public
-            phases.advanceboundary(pullop.repo, phases.public, subset)
-
+        _pullphase(pullop)
         _pullobsolete(pullop)
         pullop.closetransaction()
     finally:
@@ -492,6 +463,50 @@
 
     return result
 
+def _pullchangeset(pullop):
+    """pull changeset from unbundle into the local repo"""
+    # We delay the open of the transaction as late as possible so we
+    # don't open transaction for nothing or you break future useful
+    # rollback call
+    pullop.gettransaction()
+    if pullop.heads is None and list(pullop.common) == [nullid]:
+        pullop.repo.ui.status(_("requesting all changes\n"))
+    elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
+        # issue1320, avoid a race if remote changed after discovery
+        pullop.heads = pullop.rheads
+
+    if pullop.remote.capable('getbundle'):
+        # TODO: get bundlecaps from remote
+        cg = pullop.remote.getbundle('pull', common=pullop.common,
+                                     heads=pullop.heads or pullop.rheads)
+    elif pullop.heads is None:
+        cg = pullop.remote.changegroup(pullop.fetch, 'pull')
+    elif not pullop.remote.capable('changegroupsubset'):
+        raise util.Abort(_("partial pull cannot be done because "
+                                   "other repository doesn't support "
+                                   "changegroupsubset."))
+    else:
+        cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
+    return pullop.repo.addchangegroup(cg, 'pull', pullop.remote.url())
+
+def _pullphase(pullop):
+    # Get remote phases data from remote
+    remotephases = pullop.remote.listkeys('phases')
+    publishing = bool(remotephases.get('publishing', False))
+    if remotephases and not publishing:
+        # remote is new and unpublishing
+        pheads, _dr = phases.analyzeremotephases(pullop.repo,
+                                                 pullop.pulledsubset,
+                                                 remotephases)
+        phases.advanceboundary(pullop.repo, phases.public, pheads)
+        phases.advanceboundary(pullop.repo, phases.draft,
+                               pullop.pulledsubset)
+    else:
+        # Remote is old or publishing all common changesets
+        # should be seen as public
+        phases.advanceboundary(pullop.repo, phases.public,
+                               pullop.pulledsubset)
+
 def _pullobsolete(pullop):
     """utility function to pull obsolete markers from a remote
 
--- a/mercurial/revset.py	Thu Feb 13 13:08:50 2014 +0100
+++ b/mercurial/revset.py	Thu Feb 13 15:33:24 2014 -0600
@@ -522,7 +522,7 @@
     """
     # i18n: "closed" is a keyword
     getargs(x, 0, 0, _("closed takes no arguments"))
-    return baseset([r for r in subset if repo[r].closesbranch()])
+    return lazyset(subset, lambda r: repo[r].closesbranch())
 
 def contains(repo, subset, x):
     """``contains(pattern)``
@@ -571,7 +571,7 @@
         source = repo[r].extra().get('convert_revision', None)
         return source is not None and (rev is None or source.startswith(rev))
 
-    return baseset([r for r in subset if _matchvalue(r)])
+    return lazyset(subset, lambda r: _matchvalue(r))
 
 def date(repo, subset, x):
     """``date(interval)``
@@ -708,7 +708,7 @@
         extra = repo[r].extra()
         return label in extra and (value is None or matcher(extra[label]))
 
-    return baseset([r for r in subset if _matchvalue(r)])
+    return lazyset(subset, lambda r: _matchvalue(r))
 
 def filelog(repo, subset, x):
     """``filelog(pattern)``
@@ -2129,5 +2129,57 @@
     def set(self):
         return set([r for r in self])
 
+class spanset(object):
+    """Duck type for baseset class which represents a range of revisions and
+    can work lazily and without having all the range in memory
+    """
+    def __init__(self, start, end):
+        self._start = start
+        self._end = end
+
+    def __iter__(self):
+        if self._start <= self._end:
+            for r in xrange(self._start, self._end):
+                yield r
+        else:
+            for r in xrange(self._start, self._end, -1):
+                yield r
+
+    def __contains__(self, x):
+        return (x <= self._start and x > self._end) or (x >= self._start and x<
+                self._end)
+
+    def __and__(self, x):
+        return lazyset(self, lambda r: r in x)
+
+    def __sub__(self, x):
+        return lazyset(self, lambda r: r not in x)
+
+    def __add__(self, x):
+        l = baseset(self)
+        return l + baseset(x)
+
+    def __len__(self):
+        return abs(self._end - self._start)
+
+    def __getitem__(self, x):
+        # Basic implementation to be changed in future patches.
+        l = baseset([r for r in self])
+        return l[x]
+
+    def sort(self, reverse=False):
+        # Basic implementation to be changed in future patches.
+        if reverse:
+            self.reverse()
+
+    def reverse(self):
+        if self._start <= self._end:
+            self._start, self._end = self._end - 1, self._start - 1
+        else:
+            self._start, self._end = self._end + 1, self._start + 1
+
+    def set(self):
+        return self
+
 # tell hggettext to extract docstrings from these functions:
 i18nfunctions = symbols.values()