--- 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()