# HG changeset patch # User Matt Mackall # Date 1245051938 18000 # Node ID db3c1ab0e6328211eac06c744cbc11d27017e7ec # Parent 859f841937d08b16bce2d41e2382b101ec999867 commit: recurse into subrepositories diff -r 859f841937d0 -r db3c1ab0e632 mercurial/context.py --- a/mercurial/context.py Mon Jun 15 02:45:38 2009 -0500 +++ b/mercurial/context.py Mon Jun 15 02:45:38 2009 -0500 @@ -184,6 +184,9 @@ if match.bad(fn, 'No such file in rev ' + str(self)) and match(fn): yield fn + def sub(self, path): + return subrepo.subrepo(self, path) + class filectx(object): """A filecontext object makes access to data related to a particular filerevision convenient.""" diff -r 859f841937d0 -r db3c1ab0e632 mercurial/localrepo.py --- a/mercurial/localrepo.py Mon Jun 15 02:45:38 2009 -0500 +++ b/mercurial/localrepo.py Mon Jun 15 02:45:38 2009 -0500 @@ -7,7 +7,7 @@ from node import bin, hex, nullid, nullrev, short from i18n import _ -import repo, changegroup +import repo, changegroup, subrepo import changelog, dirstate, filelog, manifest, context import lock, transaction, store, encoding import util, extensions, hook, error @@ -807,6 +807,7 @@ wlock = self.wlock() try: p1, p2 = self.dirstate.parents() + wctx = self[None] if (not force and p2 != nullid and match and (match.files() or match.anypats())): @@ -817,12 +818,20 @@ if force: changes[0].extend(changes[6]) # mq may commit unchanged files + # check subrepos + subs = [] + for s in wctx.substate: + if match(s) and wctx.sub(s).dirty(): + subs.append(s) + if subs and '.hgsubstate' not in changes[0]: + changes[0].insert(0, '.hgsubstate') + # make sure all explicit patterns are matched if not force and match.files(): matched = set(changes[0] + changes[1] + changes[2]) for f in match.files(): - if f == '.' or f in matched: # matched + if f == '.' or f in matched or f in wctx.substate: continue if f in changes[3]: # missing fail(f, _('file not found!')) @@ -852,6 +861,16 @@ extra, changes) if editor: cctx._text = editor(self, cctx) + + # commit subs + if subs: + state = wctx.substate.copy() + for s in subs: + self.ui.status(_('committing subrepository %s\n') % s) + sr = wctx.sub(s).commit(cctx._text, user, date) + state[s] = (state[s][0], sr) + subrepo.writestate(self, state) + ret = self.commitctx(cctx, True) # update dirstate and mergestate diff -r 859f841937d0 -r db3c1ab0e632 mercurial/subrepo.py --- a/mercurial/subrepo.py Mon Jun 15 02:45:38 2009 -0500 +++ b/mercurial/subrepo.py Mon Jun 15 02:45:38 2009 -0500 @@ -5,7 +5,11 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2, incorporated herein by reference. -import config, util, errno +import errno, os +import config, util, node, error +localrepo = None + +nullstate = ('', '') def state(ctx): p = config.config() @@ -33,3 +37,46 @@ state[path] = (src, rev.get(path, '')) return state + +def writestate(repo, state): + repo.wwrite('.hgsubstate', + ''.join(['%s %s\n' % (state[s][1], s) + for s in sorted(state)]), '') + +def subrepo(ctx, path): + # subrepo inherently violates our import layering rules + # because it wants to make repo objects from deep inside the stack + # so we manually delay the circular imports to not break + # scripts that don't use our demand-loading + global localrepo + import localrepo as l + localrepo = l + + state = ctx.substate.get(path, nullstate) + if state[0].startswith('['): # future expansion + raise error.Abort('unknown subrepo source %s' % state[0]) + return hgsubrepo(ctx, path, state) + +class hgsubrepo(object): + def __init__(self, ctx, path, state): + self._parent = ctx + self._path = path + self._state = state + r = ctx._repo + root = r.wjoin(path) + self._repo = localrepo.localrepository(r.ui, root) + + def dirty(self): + r = self._state[1] + if r == '': + return True + w = self._repo[None] + if w.p1() != self._repo[r]: # version checked out changed + return True + return w.dirty() # working directory changed + + def commit(self, text, user, date): + n = self._repo.commit(text, user, date) + if not n: + return self._repo['.'].hex() # different version checked out + return node.hex(n)