[PATCH 1 of 5 V2] pull: add --subrepos flag
Angel Ezquerra
angel.ezquerra at gmail.com
Sun Mar 3 15:05:45 CST 2013
# HG changeset patch
# User Angel Ezquerra <angel.ezquerra at gmail.com>
# Date 1360519226 -3600
# Node ID c5e164d3282a4a2fb54171e6246b3b2e8a520080
# Parent a07be895373394be66ba38b1ff111e26aca03ac8
pull: add --subrepos flag
The purpose of this new flag is to ensure that you are able to update to any
incoming revision without requiring any network access. The idea is to make sure
that the repository is self-contained after doing hg pull --subrepos, as long as
it was already self-contained before the pull.
When the --subrepos flag is enabled, pull will also pull (or clone) all subrepos
that are present on the current revision and those that are referenced by any of
the incoming revisions. Pulls are recursive (i.e. subrepos withing subrepos will
be also pulled as needed), but clones are not recursive yet (it requires adding
a similar --subrepos flag to clone, which will be done on another patch).
If the incoming revisions refer to subrepos that are not on the working
directory yet they will be cloned. If any of the subrepositories changes its
pull source (as defined on the .hgsub file) it will be pulled from the current
and the new source.
This first patch only supports mercurial subrepos (a NotImplementedError
exception will be raised for all other subrepo types). Future patches will add
support for other subrepo types.
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -4654,6 +4654,8 @@
('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
('b', 'branch', [], _('a specific branch you would like to pull'),
_('BRANCH')),
+ ('S', 'subrepos', None,
+ _('pull current and incoming subrepos recursively')),
] + remoteopts,
_('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
def pull(ui, repo, source="default", **opts):
@@ -4698,7 +4700,9 @@
"so a rev cannot be specified.")
raise util.Abort(err)
- modheads = repo.pull(other, heads=revs, force=opts.get('force'))
+ modheads = repo.pull(other, heads=revs, force=opts.get('force'),
+ subrepos=opts.get('subrepos'))
+
bookmarks.updatefromremote(ui, repo, other, source)
if checkout:
checkout = str(repo.changelog.rev(other.lookup(checkout)))
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -10,12 +10,14 @@
import changelog, dirstate, filelog, manifest, context, bookmarks, phases
import lock, transaction, store, encoding, base85
import scmutil, util, extensions, hook, error, revset
+import config
import match as matchmod
import merge as mergemod
import tags as tagsmod
from lock import release
import weakref, errno, os, time, inspect
import branchmap
+import itertools
propertycache = util.propertycache
filecache = scmutil.filecache
@@ -1646,11 +1648,13 @@
return r
- def pull(self, remote, heads=None, force=False):
+ def pull(self, remote, heads=None, force=False, subrepos=False):
# don't open transaction for nothing or you break future useful
# rollback call
tr = None
trname = 'pull\n' + util.hidepassword(remote.url())
+ if subrepos:
+ oldtip = len(self)
lock = self.lock()
try:
tmp = discovery.findcommonincoming(self, remote, heads=heads,
@@ -1730,8 +1734,43 @@
tr.release()
lock.release()
+ # update current and new subrepos
+ if subrepos:
+ # pull (or clone) the subrepos that are referenced by the
+ # current revision or by any of the incoming revisions
+ revstocheck = itertools.chain(['.'], self.changelog.revs(oldtip))
+ self.getsubrepos(revs=revstocheck, source=remote.url())
+
return result
+ def getsubrepos(self, revs=None, source=None):
+ """Get (clone or pull) the subrepos that are referenced
+ on any of the revisions on the given revision list
+ """
+ if revs is None:
+ # check all revisions
+ revs = self.changelog.revs()
+ # use a sortdict to make sure that we get the subrepos
+ # in the order they are found
+ substopull = config.sortdict()
+ for rev in revs:
+ ctx = self[rev]
+ # read the substate items in alphabetical order to ensure
+ # that we always process the subrepos in the same order
+ for sname in sorted(ctx.substate):
+ sinfo = ctx.substate[sname]
+ substopull[(sname, sinfo[0], sinfo[2])] = ctx
+ try:
+ self._subtoppath = source
+ for (sname, ssource, stype), ctx in substopull.items():
+ try:
+ ctx.sub(sname).pull(ssource)
+ except (error.RepoError, urllib2.HTTPError), ex:
+ self.ui.warn(_('could not pull subrepo %s from %s (%s)\n')
+ % (sname, ssource, str(ex)))
+ finally:
+ del self._subtoppath
+
def checkpush(self, force, revs):
"""Extensions can override this function if additional checks have
to be performed before pushing, or call it if they override push
diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py
--- a/mercurial/subrepo.py
+++ b/mercurial/subrepo.py
@@ -330,6 +330,11 @@
"""
raise NotImplementedError
+ def pull(self, source):
+ """pull from the given parent repository source
+ """
+ raise NotImplementedError
+
def get(self, state, overwrite=False):
"""run whatever commands are needed to put the subrepo into
this state
@@ -528,8 +533,13 @@
self._repo.ui.note(_('removing subrepo %s\n') % subrelpath(self))
hg.clean(self._repo, node.nullid, False)
+ def pull(self, source):
+ state = (source, None, 'hg')
+ return self._get(state)
+
def _get(self, state):
source, revision, kind = state
+ subrepos = revision is None
if revision not in self._repo:
self._repo._subsource = source
srcurl = _abssource(self._repo)
@@ -547,7 +557,7 @@
else:
self._repo.ui.status(_('pulling subrepo %s from %s\n')
% (subrelpath(self), srcurl))
- self._repo.pull(other)
+ self._repo.pull(other, subrepos=subrepos)
bookmarks.updatefromremote(self._repo.ui, self._repo, other,
srcurl)
diff --git a/tests/test-debugcomplete.t b/tests/test-debugcomplete.t
--- a/tests/test-debugcomplete.t
+++ b/tests/test-debugcomplete.t
@@ -204,7 +204,7 @@
init: ssh, remotecmd, insecure
log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
merge: force, rev, preview, tool
- pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
+ pull: update, force, rev, bookmark, branch, subrepos, ssh, remotecmd, insecure
push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
remove: after, force, include, exclude
serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
More information about the Mercurial-devel
mailing list