--- 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."""
--- 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
--- 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)