diff onsub.py @ 12:90b54c4fe4fe

onsub extension: pre and post order
author jakob krainz <jakob@hawo-net.de>
date Tue, 06 Mar 2012 12:55:40 +0100
parents ecc4fd16555d
children 34aa014b5989
line wrap: on
line diff
--- a/onsub.py	Tue Mar 06 12:22:06 2012 +0100
+++ b/onsub.py	Tue Mar 06 12:55:40 2012 +0100
@@ -42,65 +42,133 @@
         State of the current subrepository as specified in the
         containing repository's ``.hgsubstate`` file.
     """
-    cmd = ' '.join(args)
-    foreach(ui, repo, cmd, 
+    if len(args) == 2:
+        precmd = args[0]
+        postcmd = args[1]
+        if opts.get('breadth_first') or opts.get('post_order'):
+            raise util.Abort(_("onsub: '-b' and '-p' imply the use of only one command"))
+    elif len(args) == 1:
+        if opts.get('post_order'):
+            precmd = None
+            postcmd = args[0]
+        else:
+            precmd = args[0]
+            postcmd = None
+    elif len(args) == 0:
+        # cmd == '' means only do print0
+        if opts.get('post_order'):
+            precmd = None
+            postcmd = ''
+        else:
+            precmd = ''
+            postcmd = None
+    else:
+        raise util.Abort(_("onsub: at most 2 command arguments required"))
+    if opts.get('post_order') and opts.get('breadth_first'):
+        raise util.Abort(_("onsub: '-b' and '-p' are mutually exclusive"))
+    foreach(ui, repo, precmd, postcmd,
             not opts.get('breadth_first'),
             opts.get('max_depth'),
             opts.get('print0'),
-            opts.get('ignore_errors'))
-
-def foreach(ui, repo, cmd, depthfirst, maxdepth, print0, ignoreerrors):
-    """execute cmd in repo.root and in each subrepository"""
-    ctx = repo['.']
-    work = [(1, ctx.sub(subpath)) for subpath in sorted(ctx.substate)]
-    if depthfirst:
-        work.reverse()
+            opts.get('ignore_errors'),
+            opts.get('root_repo'))
 
-    while work:
-        if depthfirst:
-            (depth, sub) = work.pop()
-        else:
-            (depth, sub) = work.pop(0)
-        if depth > maxdepth >= 0:
-            continue
-
+def execCmd(ui, rootrepo, sub, doaction, print0, cmd, inroot, ignoreerrors):
+    """ if doaction, execute cmd; else, do nothing.  if inroot,
+    then command is executed inside rootrepo; else, inside sub
+    
+    If cmd == None, do nothing. If cmd == '', do only the print0 (if needed). 
+    Else, do either print0 or the debugging message, then execute the command.
+    """
+    if not doaction:
+        return
+    if inroot:
+        envargdict = dict(HG_SUBPATH='.',
+                          HG_SUBURL='.',
+                          HG_SUBSTATE=rootrepo['.'].hex(),
+                          HG_REPO=rootrepo.root)
+        relpath = '.'
+        cmdwd = rootrepo.root
+    else:
         # subrepo.relpath was renamed to subrepo.subrelpath in
         # 18b5b6392fcf.
         if hasattr(subrepo, 'relpath'):
             relpath = subrepo.relpath(sub)
         else:
             relpath = subrepo.subrelpath(sub)
-
+        envargdict = dict(HG_SUBPATH=relpath,
+                          HG_SUBURL=sub._path,
+                          HG_SUBSTATE=sub._state[1],
+                          HG_REPO=rootrepo.root)
+        cmdwd = os.path.join(rootrepo.root, relpath)
+    if ignoreerrors:
+        onerr = None
+    else:
+        onerr = util.Abort
+    if cmd != None:
         if print0:
             ui.write(relpath, "\0")
-        else:
-            ui.note(_("executing '%s' in %s\n") % (cmd, relpath))
-        if ignoreerrors:
-            onerr = None
+        if cmd != '':
+            if not print0: ui.note(_("executing '%s' in %s\n") % (cmd, relpath))
+            util.system(cmd, environ=envargdict, cwd=cmdwd, onerr=onerr,
+                        errprefix=_('terminated onsub in %s') % relpath)
+    
+
+
+def foreach(ui, repo, precmd, postcmd, depthfirst, maxdepth, print0, ignoreerrors, includeroot):
+    """execute (pre/post)cmd in repo.root and in each subrepository"""
+    seen = set()
+    execCmd(ui=ui, rootrepo=repo, sub=None, doaction=includeroot, 
+            print0=print0, cmd=precmd, inroot=True, ignoreerrors=ignoreerrors) 
+    ctx = repo['.']
+    work = [(1, ctx.sub(subpath)) for subpath in sorted(ctx.substate)]
+    if depthfirst:
+        work.reverse()
+    while work:
+        if depthfirst:
+            (depth, sub) = work[-1]
+            if sub in seen:
+                dopreaction = False
+                dopostaction = True
+                doaddchildren = False
+                work.pop()
+            else:
+                dopreaction = True
+                dopostaction = False
+                doaddchildren = True
+                seen.add(sub)
         else:
-            onerr = util.Abort
-        util.system(cmd, environ=dict(HG_SUBPATH=relpath,
-                                      HG_SUBURL=sub._path,
-                                      HG_SUBSTATE=sub._state[1],
-                                      HG_REPO=repo.root),
-                    cwd=os.path.join(repo.root, relpath),
-                    onerr=onerr,
-                    errprefix=_('terminated onsub in %s') % relpath)
-
-        if isinstance(sub, subrepo.hgsubrepo):
-            rev = sub._state[1]
-            ctx = sub._repo[rev]
-            w = [(depth + 1, ctx.sub(subpath)) 
-                 for subpath in sorted(ctx.substate)]
-            if depthfirst:
-                w.reverse()
-            work.extend(w)
-
+            (depth, sub) = work.pop(0)
+            dopreaction = True
+            dopostaction = False
+            doaddchildren = True
+        if depth > maxdepth >= 0:
+            continue
+        execCmd(ui=ui, rootrepo=repo, sub=sub, doaction=dopreaction, 
+                print0=print0, cmd=precmd, inroot=False, ignoreerrors=ignoreerrors) 
+        if doaddchildren:
+            if isinstance(sub, subrepo.hgsubrepo):
+                rev = sub._state[1]
+                ctx = sub._repo[rev]
+                w = [(depth + 1, ctx.sub(subpath)) 
+                     for subpath in sorted(ctx.substate)]
+                if depthfirst:
+                    w.reverse()
+                work.extend(w)
+        execCmd(ui=ui, rootrepo=repo, sub=sub, doaction=dopostaction, 
+                print0=print0, cmd=postcmd, inroot=False, ignoreerrors=ignoreerrors) 
+    execCmd(ui=ui, rootrepo=repo, sub=None, doaction=includeroot, 
+            print0=print0, cmd=postcmd, inroot=True, ignoreerrors=ignoreerrors) 
+            
 cmdtable = {
     "onsub":
         (onsub,
          [('b', 'breadth-first', None,
            _('use breadth-first traversal')),
+          ('p', 'post-order', None,
+           _('use post-order depth-first traversal')),
+          ('', 'root-repo', None,
+           _('include root repository in traversal')),
           ('', 'max-depth', -1,
            _('limit recursion to N levels (negative for no limit)'), 'N'),
           ('', 'ignore-errors', None,