Mercurial > hg-onsub
view 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 source
# onsub.py - execute commands recursively on subrepositories # # Copyright 2010, 2011 aragost Trifork # # This software may be used and distributed according to the terms of # the GNU General Public License version 2 or any later version. import os from mercurial.i18n import _ from mercurial import extensions, subrepo, util """execute a command in each subrepository""" def onsub(ui, repo, *args, **opts): """execute a command in each subrepository Executes CMD with the current working directory set to the root of each subrepository. By default, execution stops if CMD returns a non-zero exit code. Use --ignore-errors to override this. Use --verbose/-v to print the command being run and the subrepo name for each run of CMD in a subrepo. Alternately, use --print0/-0 to print just the subrepo name followed by a NUL character instead of a newline. This can be useful in combination with :hg:`status --print0`. The command has access to the following environment variables: ``HG_REPO``: Absolute path to the top-level repository in which the onsub command was executed. ``HG_SUBPATH``: Relative path to the current subrepository from the top-level repository. ``HG_SUBURL``: URL for the current subrepository as specified in the containing repository's ``.hgsub`` file. ``HG_SUBSTATE``: State of the current subrepository as specified in the containing repository's ``.hgsubstate`` file. """ 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'), opts.get('root_repo')) 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") 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: (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, _('continue execution despite errors')), ('0', 'print0', None, _('end subrepository names with NUL, for use with xargs'))], _('[-b] [-0] [--ignore-errors] CMD')) }