status: recurse into subrepositories with --subrepos/-S flag
authorMartin Geisler <mg@lazybytes.net>
Fri, 03 Sep 2010 12:58:51 +0200
changeset 12166 441a74b8def1
parent 12165 b7fbf24c8a93
child 12167 d2c5b0927c28
status: recurse into subrepositories with --subrepos/-S flag
mercurial/commands.py
mercurial/localrepo.py
mercurial/subrepo.py
tests/test-debugcomplete.t
tests/test-help.t
tests/test-subrepo-recursion.t
--- a/mercurial/commands.py	Fri Sep 03 12:58:51 2010 +0200
+++ b/mercurial/commands.py	Fri Sep 03 12:58:51 2010 +0200
@@ -3478,7 +3478,8 @@
         show = ui.quiet and states[:4] or states[:5]
 
     stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
-                       'ignored' in show, 'clean' in show, 'unknown' in show)
+                       'ignored' in show, 'clean' in show, 'unknown' in show,
+                       opts.get('subrepos'))
     changestates = zip(states, 'MAR!?IC', stat)
 
     if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
@@ -3991,6 +3992,11 @@
      _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
 ]
 
+subrepoopts = [
+    ('S', 'subrepos', None,
+     _('recurse into subrepositories'))
+]
+
 table = {
     "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
     "addremove":
@@ -4454,7 +4460,7 @@
            _('show difference from revision'), _('REV')),
           ('', 'change', '',
            _('list the changed files of a revision'), _('REV')),
-         ] + walkopts,
+         ] + walkopts + subrepoopts,
          _('[OPTION]... [FILE]...')),
     "tag":
         (tag,
--- a/mercurial/localrepo.py	Fri Sep 03 12:58:51 2010 +0200
+++ b/mercurial/localrepo.py	Fri Sep 03 12:58:51 2010 +0200
@@ -1052,7 +1052,8 @@
         return self[node].walk(match)
 
     def status(self, node1='.', node2=None, match=None,
-               ignored=False, clean=False, unknown=False):
+               ignored=False, clean=False, unknown=False,
+               listsubrepos=False):
         """return status of files between two nodes or node and working directory
 
         If node1 is None, use the first dirstate parent instead.
@@ -1158,6 +1159,25 @@
             removed = mf1.keys()
 
         r = modified, added, removed, deleted, unknown, ignored, clean
+
+        if listsubrepos:
+            for subpath in ctx1.substate:
+                sub = ctx1.sub(subpath)
+                if working:
+                    rev2 = None
+                else:
+                    rev2 = ctx2.substate[subpath][1]
+                try:
+                    submatch = matchmod.narrowmatcher(subpath, match)
+                    s = sub.status(rev2, match=submatch, ignored=listignored,
+                                   clean=listclean, unknown=listunknown,
+                                   listsubrepos=True)
+                    for rfiles, sfiles in zip(r, s):
+                        rfiles.extend("%s/%s" % (subpath, f) for f in sfiles)
+                except error.LookupError:
+                    self.ui.status(_("skipping missing subrepository: %s\n")
+                                   % subpath)
+
         [l.sort() for l in r]
         return r
 
--- a/mercurial/subrepo.py	Fri Sep 03 12:58:51 2010 +0200
+++ b/mercurial/subrepo.py	Fri Sep 03 12:58:51 2010 +0200
@@ -246,6 +246,9 @@
         raise NotImplementedError
 
 
+    def status(self, rev2, **opts):
+        return [], [], [], [], [], [], []
+
 class hgsubrepo(abstractsubrepo):
     def __init__(self, ctx, path, state):
         self._path = path
@@ -275,6 +278,17 @@
                 addpathconfig('default-push', defpushpath)
             fp.close()
 
+    def status(self, rev2, **opts):
+        try:
+            rev1 = self._state[1]
+            ctx1 = self._repo[rev1]
+            ctx2 = self._repo[rev2]
+            return self._repo.status(ctx1, ctx2, **opts)
+        except error.RepoLookupError, inst:
+            self._repo.ui.warn(_("warning: %s in %s\n")
+                               % (inst, relpath(self)))
+            return [], [], [], [], [], [], []
+
     def dirty(self):
         r = self._state[1]
         if r == '':
--- a/tests/test-debugcomplete.t	Fri Sep 03 12:58:51 2010 +0200
+++ b/tests/test-debugcomplete.t	Fri Sep 03 12:58:51 2010 +0200
@@ -190,7 +190,7 @@
   push: force, rev, branch, new-branch, ssh, remotecmd
   remove: after, force, include, exclude
   serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, templates, style, ipv6, certificate
-  status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude
+  status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
   summary: remote
   update: clean, check, date, rev
   addremove: similarity, include, exclude, dry-run
--- a/tests/test-help.t	Fri Sep 03 12:58:51 2010 +0200
+++ b/tests/test-help.t	Fri Sep 03 12:58:51 2010 +0200
@@ -532,6 +532,7 @@
       --change REV           list the changed files of a revision
    -I --include PATTERN [+]  include names matching the given patterns
    -X --exclude PATTERN [+]  exclude names matching the given patterns
+   -S --subrepos             recurse into subrepositories
   
   [+] marked option can be specified multiple times
   
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-subrepo-recursion.t	Fri Sep 03 12:58:51 2010 +0200
@@ -0,0 +1,97 @@
+Make status look into subrepositories by default:
+
+  $ echo '[defaults]' >> $HGRCPATH
+  $ echo 'status = -S' >> $HGRCPATH
+
+Create test repository:
+
+  $ hg init
+  $ echo x1 > x.txt
+  $ hg add x.txt
+
+  $ hg init foo
+  $ cd foo
+  $ echo y1 > y.txt
+  $ hg add y.txt
+
+  $ hg init bar
+  $ cd bar
+  $ echo z1 > z.txt
+  $ hg add z.txt
+
+  $ cd ..
+  $ echo 'bar = bar' > .hgsub
+  $ hg add .hgsub
+
+  $ cd ..
+  $ echo 'foo = foo' > .hgsub
+  $ hg add .hgsub
+
+  $ hg commit -m 0-0-0
+  committing subrepository foo
+  committing subrepository foo/bar
+
+  $ cd foo
+  $ echo y2 >> y.txt
+  $ hg commit -m 0-1-0
+
+  $ cd bar
+  $ echo z2 >> z.txt
+  $ hg commit -m 0-1-1
+
+  $ cd ..
+  $ hg commit -m 0-2-1
+  committing subrepository bar
+
+  $ cd ..
+  $ hg commit -m 1-2-1
+  committing subrepository foo
+
+Change working directory:
+
+  $ echo y3 >> foo/y.txt
+  $ echo z3 >> foo/bar/z.txt
+  $ hg status
+  M foo/bar/z.txt
+  M foo/y.txt
+
+Status call crossing repository boundaries:
+
+  $ hg status foo/bar/z.txt
+  M foo/bar/z.txt
+  $ hg status -I 'foo/?.txt'
+  M foo/y.txt
+  $ hg status -I '**/?.txt'
+  M foo/bar/z.txt
+  M foo/y.txt
+
+Status from within a subdirectory:
+
+  $ mkdir dir
+  $ cd dir
+  $ echo a1 > a.txt
+  $ hg status
+  M foo/bar/z.txt
+  M foo/y.txt
+  ? dir/a.txt
+
+Status with relative path:
+
+  $ hg status ..
+  M ../foo/bar/z.txt
+  M ../foo/y.txt
+  ? a.txt
+  $ cd ..
+
+Status between revisions:
+
+  $ rm -r dir
+  $ hg commit -m 2-2-1
+  committing subrepository foo
+  committing subrepository foo/bar
+  $ hg status
+  $ hg status --rev 0:1
+  M .hgsubstate
+  M foo/.hgsubstate
+  M foo/bar/z.txt
+  M foo/y.txt