# HG changeset patch # User Matt Mackall # Date 1305313588 18000 # Node ID b33f3e35efb01e410d59f313e6f1b158206f1241 # Parent 1f46be4689ed5692f041bc5856aa6d11f6f38373 scmutil: move revsingle/pair/range from cmdutil This allows users at levels below the command layer to avoid import loops. diff -r 1f46be4689ed -r b33f3e35efb0 hgext/extdiff.py --- a/hgext/extdiff.py Fri May 13 12:57:27 2011 -0500 +++ b/hgext/extdiff.py Fri May 13 14:06:28 2011 -0500 @@ -123,10 +123,10 @@ msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: - node2 = cmdutil.revsingle(repo, change, None).node() + node2 = scmutil.revsingle(repo, change, None).node() node1a, node1b = repo.changelog.parents(node2) else: - node1a, node2 = cmdutil.revpair(repo, revs) + node1a, node2 = scmutil.revpair(repo, revs) if not revs: node1b = repo.dirstate.p2() else: diff -r 1f46be4689ed -r b33f3e35efb0 hgext/graphlog.py --- a/hgext/graphlog.py Fri May 13 12:57:27 2011 -0500 +++ b/hgext/graphlog.py Fri May 13 14:06:28 2011 -0500 @@ -12,11 +12,11 @@ revision graph is also shown. ''' -from mercurial.cmdutil import revrange, show_changeset +from mercurial.cmdutil import show_changeset from mercurial.commands import templateopts from mercurial.i18n import _ from mercurial.node import nullrev -from mercurial import cmdutil, commands, extensions +from mercurial import cmdutil, commands, extensions, scmutil from mercurial import hg, util, graphmod cmdtable = {} @@ -227,7 +227,7 @@ def get_revs(repo, rev_opt): if rev_opt: - revs = revrange(repo, rev_opt) + revs = scmutil.revrange(repo, rev_opt) if len(revs) == 0: return (nullrev, nullrev) return (max(revs), min(revs)) @@ -324,7 +324,7 @@ check_unsupported_flags(pats, opts) - revs = sorted(revrange(repo, [revset(pats, opts)]), reverse=1) + revs = sorted(scmutil.revrange(repo, [revset(pats, opts)]), reverse=1) limit = cmdutil.loglimit(opts) if limit is not None: revs = revs[:limit] diff -r 1f46be4689ed -r b33f3e35efb0 hgext/mq.py --- a/hgext/mq.py Fri May 13 12:57:27 2011 -0500 +++ b/hgext/mq.py Fri May 13 14:06:28 2011 -0500 @@ -46,7 +46,7 @@ from mercurial.node import bin, hex, short, nullid, nullrev from mercurial.lock import release from mercurial import commands, cmdutil, hg, scmutil, util, revset -from mercurial import repair, extensions, url, error +from mercurial import repair, extensions, url, error, scmutil from mercurial import patch as patchmod import os, sys, re, errno, shutil @@ -815,7 +815,7 @@ if opts.get('rev'): if not self.applied: raise util.Abort(_('no patches applied')) - revs = cmdutil.revrange(repo, opts.get('rev')) + revs = scmutil.revrange(repo, opts.get('rev')) if len(revs) > 1 and revs[0] > revs[1]: revs.reverse() revpatches = self._revpatches(repo, revs) @@ -1748,7 +1748,7 @@ if files: raise util.Abort(_('option "-r" not valid when importing ' 'files')) - rev = cmdutil.revrange(repo, rev) + rev = scmutil.revrange(repo, rev) rev.sort(reverse=True) if (len(files) > 1 or len(rev) > 1) and patchname: raise util.Abort(_('option "-n" not valid when importing multiple ' @@ -2736,7 +2736,7 @@ backup = 'none' cl = repo.changelog - revs = set(cmdutil.revrange(repo, revs)) + revs = set(scmutil.revrange(repo, revs)) if not revs: raise util.Abort(_('empty revision set')) @@ -2928,7 +2928,7 @@ ui.status(_('no patches applied\n')) return 0 - revs = cmdutil.revrange(repo, revrange) + revs = scmutil.revrange(repo, revrange) q.finish(repo, revs) q.save_dirty() return 0 diff -r 1f46be4689ed -r b33f3e35efb0 hgext/patchbomb.py --- a/hgext/patchbomb.py Fri May 13 12:57:27 2011 -0500 +++ b/hgext/patchbomb.py Fri May 13 14:06:28 2011 -0500 @@ -49,6 +49,7 @@ import email.MIMEMultipart, email.MIMEBase import email.Utils, email.Encoders, email.Generator from mercurial import cmdutil, commands, hg, mail, patch, util, discovery +from mercurial import scmutil from mercurial.i18n import _ from mercurial.node import bin @@ -286,7 +287,7 @@ return [str(repo.changelog.rev(r)) for r in o] def getpatches(revs): - for r in cmdutil.revrange(repo, revs): + for r in scmutil.revrange(repo, revs): output = cStringIO.StringIO() cmdutil.export(repo, [r], fp=output, opts=patch.diffopts(ui, opts)) diff -r 1f46be4689ed -r b33f3e35efb0 hgext/transplant.py --- a/hgext/transplant.py Fri May 13 12:57:27 2011 -0500 +++ b/hgext/transplant.py Fri May 13 14:06:28 2011 -0500 @@ -15,8 +15,8 @@ from mercurial.i18n import _ import os, tempfile -from mercurial import bundlerepo, cmdutil, hg, merge, match -from mercurial import patch, revlog, scmutil, util, error +from mercurial import bundlerepo, hg, merge, match +from mercurial import patch, revlog, scmutil, util, error, cmdutil from mercurial import revset, templatekw cmdtable = {} @@ -578,14 +578,14 @@ tf = tp.transplantfilter(repo, source, p1) if opts.get('prune'): prune = [source.lookup(r) - for r in cmdutil.revrange(source, opts.get('prune'))] + for r in scmutil.revrange(source, opts.get('prune'))] matchfn = lambda x: tf(x) and x not in prune else: matchfn = tf merges = map(source.lookup, opts.get('merge', ())) revmap = {} if revs: - for r in cmdutil.revrange(source, revs): + for r in scmutil.revrange(source, revs): revmap[int(r)] = source.lookup(r) elif opts.get('all') or not merges: if source != repo: diff -r 1f46be4689ed -r b33f3e35efb0 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Fri May 13 12:57:27 2011 -0500 +++ b/mercurial/cmdutil.py Fri May 13 14:06:28 2011 -0500 @@ -10,7 +10,7 @@ import os, sys, errno, re, tempfile import util, scmutil, templater, patch, error, templatekw, wdutil import match as matchmod -import revset, subrepo +import subrepo expandpats = wdutil.expandpats match = wdutil.match @@ -19,8 +19,6 @@ addremove = wdutil.addremove dirstatecopy = wdutil.dirstatecopy -revrangesep = ':' - def parsealiases(cmd): return cmd.lstrip("^").split("|") @@ -118,77 +116,6 @@ limit = None return limit -def revsingle(repo, revspec, default='.'): - if not revspec: - return repo[default] - - l = revrange(repo, [revspec]) - if len(l) < 1: - raise util.Abort(_('empty revision set')) - return repo[l[-1]] - -def revpair(repo, revs): - if not revs: - return repo.dirstate.p1(), None - - l = revrange(repo, revs) - - if len(l) == 0: - return repo.dirstate.p1(), None - - if len(l) == 1: - return repo.lookup(l[0]), None - - return repo.lookup(l[0]), repo.lookup(l[-1]) - -def revrange(repo, revs): - """Yield revision as strings from a list of revision specifications.""" - - def revfix(repo, val, defval): - if not val and val != 0 and defval is not None: - return defval - return repo.changelog.rev(repo.lookup(val)) - - seen, l = set(), [] - for spec in revs: - # attempt to parse old-style ranges first to deal with - # things like old-tag which contain query metacharacters - try: - if isinstance(spec, int): - seen.add(spec) - l.append(spec) - continue - - if revrangesep in spec: - start, end = spec.split(revrangesep, 1) - start = revfix(repo, start, 0) - end = revfix(repo, end, len(repo) - 1) - step = start > end and -1 or 1 - for rev in xrange(start, end + step, step): - if rev in seen: - continue - seen.add(rev) - l.append(rev) - continue - elif spec and spec in repo: # single unquoted rev - rev = revfix(repo, spec, None) - if rev in seen: - continue - seen.add(rev) - l.append(rev) - continue - except error.RepoLookupError: - pass - - # fall through to new-style queries if old-style fails - m = revset.match(repo.ui, spec) - for r in m(repo, range(len(repo))): - if r not in seen: - l.append(r) - seen.update(l) - - return l - def makefilename(repo, pat, node, total=None, seqno=None, revwidth=None, pathname=None): node_expander = { @@ -974,7 +901,7 @@ defrange = '%s:0' % repo['.'].rev() else: defrange = '-1:0' - revs = revrange(repo, opts['rev'] or [defrange]) + revs = scmutil.revrange(repo, opts['rev'] or [defrange]) if not revs: return [] wanted = set() diff -r 1f46be4689ed -r b33f3e35efb0 mercurial/commands.py --- a/mercurial/commands.py Fri May 13 12:57:27 2011 -0500 +++ b/mercurial/commands.py Fri May 13 14:06:28 2011 -0500 @@ -261,7 +261,7 @@ def bad(x, y): raise util.Abort("%s: %s" % (x, y)) - ctx = cmdutil.revsingle(repo, opts.get('rev')) + ctx = scmutil.revsingle(repo, opts.get('rev')) m = cmdutil.match(repo, pats, opts) m.bad = bad follow = not opts.get('no_follow') @@ -322,7 +322,7 @@ Returns 0 on success. ''' - ctx = cmdutil.revsingle(repo, opts.get('rev')) + ctx = scmutil.revsingle(repo, opts.get('rev')) if not ctx: raise util.Abort(_('no working directory: please specify a revision')) node = ctx.node() @@ -390,7 +390,7 @@ opts['date'] = util.parsedate(date) cmdutil.bailifchanged(repo) - node = cmdutil.revsingle(repo, rev).node() + node = scmutil.revsingle(repo, rev).node() op1, op2 = repo.dirstate.parents() a = repo.changelog.ancestor(op1, node) @@ -573,7 +573,7 @@ raise util.Abort(_("%s killed") % command) else: transition = "bad" - ctx = cmdutil.revsingle(repo, rev) + ctx = scmutil.revsingle(repo, rev) rev = None # clear for future iterations state[transition].append(ctx.node()) ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition)) @@ -591,7 +591,7 @@ # update state if rev: - nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])] + nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])] else: nodes = [repo.lookup('.')] @@ -876,12 +876,12 @@ """ revs = None if 'rev' in opts: - revs = cmdutil.revrange(repo, opts['rev']) + revs = scmutil.revrange(repo, opts['rev']) if opts.get('all'): base = ['null'] else: - base = cmdutil.revrange(repo, opts.get('base')) + base = scmutil.revrange(repo, opts.get('base')) if base: if dest: raise util.Abort(_("--base is incompatible with specifying " @@ -935,7 +935,7 @@ Returns 0 on success. """ - ctx = cmdutil.revsingle(repo, opts.get('rev')) + ctx = scmutil.revsingle(repo, opts.get('rev')) err = 1 m = cmdutil.match(repo, (file1,) + pats, opts) for abs in ctx.walk(m): @@ -1831,7 +1831,7 @@ _('[-r REV] [REV]')) def debugrebuildstate(ui, repo, rev="tip"): """rebuild the dirstate as it would look like for the given revision""" - ctx = cmdutil.revsingle(repo, rev) + ctx = scmutil.revsingle(repo, rev) wlock = repo.wlock() try: repo.dirstate.rebuild(ctx.node(), ctx.manifest()) @@ -1844,7 +1844,7 @@ def debugrename(ui, repo, file1, *pats, **opts): """dump rename information""" - ctx = cmdutil.revsingle(repo, opts.get('rev')) + ctx = scmutil.revsingle(repo, opts.get('rev')) m = cmdutil.match(repo, (file1,) + pats, opts) for abs in ctx.walk(m): fctx = ctx[abs] @@ -2018,8 +2018,8 @@ Returns 0 on success. """ - r1 = cmdutil.revsingle(repo, rev1).node() - r2 = cmdutil.revsingle(repo, rev2, 'null').node() + r1 = scmutil.revsingle(repo, rev1).node() + r2 = scmutil.revsingle(repo, rev2, 'null').node() wlock = repo.wlock() try: @@ -2064,7 +2064,7 @@ _('revision to check'), _('REV'))], _('[-r REV] [REV]')) def debugsub(ui, repo, rev=None): - ctx = cmdutil.revsingle(repo, rev, None) + ctx = scmutil.revsingle(repo, rev, None) for k, v in sorted(ctx.substate.items()): ui.write('path %s\n' % k) ui.write(' source %s\n' % v[0]) @@ -2150,10 +2150,10 @@ msg = _('cannot specify --rev and --change at the same time') raise util.Abort(msg) elif change: - node2 = cmdutil.revsingle(repo, change, None).node() + node2 = scmutil.revsingle(repo, change, None).node() node1 = repo[node2].p1().node() else: - node1, node2 = cmdutil.revpair(repo, revs) + node1, node2 = scmutil.revpair(repo, revs) if reverse: node1, node2 = node2, node1 @@ -2211,7 +2211,7 @@ changesets += tuple(opts.get('rev', [])) if not changesets: raise util.Abort(_("export requires at least one changeset")) - revs = cmdutil.revrange(repo, changesets) + revs = scmutil.revrange(repo, changesets) if len(revs) > 1: ui.note(_('exporting patches:\n')) else: @@ -2501,7 +2501,7 @@ start = None if 'rev' in opts: - start = cmdutil.revsingle(repo, opts['rev'], None).node() + start = scmutil.revsingle(repo, opts['rev'], None).node() if opts.get('topo'): heads = [repo[h] for h in repo.heads(start)] @@ -2944,7 +2944,7 @@ output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]), changed)) else: - ctx = cmdutil.revsingle(repo, rev) + ctx = scmutil.revsingle(repo, rev) if default or id: output = [hexfunc(ctx.node())] if num: @@ -3235,7 +3235,7 @@ Returns 0 if a match is found, 1 otherwise. """ end = opts.get('print0') and '\0' or '\n' - rev = cmdutil.revsingle(repo, opts.get('rev'), None).node() + rev = scmutil.revsingle(repo, opts.get('rev'), None).node() ret = 1 m = cmdutil.match(repo, pats, opts, default='relglob') @@ -3312,7 +3312,7 @@ endrev = None if opts.get('copies') and opts.get('rev'): - endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1 + endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1 df = False if opts["date"]: @@ -3395,7 +3395,7 @@ node = rev decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '} - ctx = cmdutil.revsingle(repo, node) + ctx = scmutil.revsingle(repo, node) for f in ctx: if ui.debugflag: ui.write("%40s " % hex(ctx.manifest()[f])) @@ -3471,7 +3471,7 @@ "explicit revision")) node = parent == bheads[0] and bheads[-1] or bheads[0] else: - node = cmdutil.revsingle(repo, node).node() + node = scmutil.revsingle(repo, node).node() if opts.get('preview'): # find nodes that are ancestors of p2 but not of p1 @@ -3543,7 +3543,7 @@ Returns 0 on success. """ - ctx = cmdutil.revsingle(repo, opts.get('rev'), None) + ctx = scmutil.revsingle(repo, opts.get('rev'), None) if file_: m = cmdutil.match(repo, (file_,), opts) @@ -4074,7 +4074,7 @@ raise util.Abort(_('no files or directories specified; ' 'use --all to revert the whole repo')) - ctx = cmdutil.revsingle(repo, opts.get('rev')) + ctx = scmutil.revsingle(repo, opts.get('rev')) node = ctx.node() mf = ctx.manifest() if node == parent: @@ -4519,7 +4519,7 @@ node2 = repo.lookup(change) node1 = repo[node2].p1().node() else: - node1, node2 = cmdutil.revpair(repo, revs) + node1, node2 = scmutil.revpair(repo, revs) cwd = (pats and repo.getcwd()) or '' end = opts.get('print0') and '\0' or '\n' @@ -4810,7 +4810,7 @@ bheads = repo.branchheads() if not opts.get('force') and bheads and p1 not in bheads: raise util.Abort(_('not at a branch head (use -f to force)')) - r = cmdutil.revsingle(repo, rev_).node() + r = scmutil.revsingle(repo, rev_).node() if not message: # we don't translate commit messages @@ -4961,7 +4961,7 @@ # if we defined a bookmark, we have to remember the original bookmark name brev = rev - rev = cmdutil.revsingle(repo, rev, rev).rev() + rev = scmutil.revsingle(repo, rev, rev).rev() if check and clean: raise util.Abort(_("cannot specify both -c/--check and -C/--clean")) diff -r 1f46be4689ed -r b33f3e35efb0 mercurial/scmutil.py --- a/mercurial/scmutil.py Fri May 13 12:57:27 2011 -0500 +++ b/mercurial/scmutil.py Fri May 13 14:06:28 2011 -0500 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from i18n import _ -import util, error, osutil +import util, error, osutil, revset import os, errno, stat, sys def checkfilename(f): @@ -463,3 +463,76 @@ path.append(os.path.join(userprofile, 'mercurial.ini')) path.append(os.path.join(userprofile, '.hgrc')) return path + +def revsingle(repo, revspec, default='.'): + if not revspec: + return repo[default] + + l = revrange(repo, [revspec]) + if len(l) < 1: + raise util.Abort(_('empty revision set')) + return repo[l[-1]] + +def revpair(repo, revs): + if not revs: + return repo.dirstate.p1(), None + + l = revrange(repo, revs) + + if len(l) == 0: + return repo.dirstate.p1(), None + + if len(l) == 1: + return repo.lookup(l[0]), None + + return repo.lookup(l[0]), repo.lookup(l[-1]) + +_revrangesep = ':' + +def revrange(repo, revs): + """Yield revision as strings from a list of revision specifications.""" + + def revfix(repo, val, defval): + if not val and val != 0 and defval is not None: + return defval + return repo.changelog.rev(repo.lookup(val)) + + seen, l = set(), [] + for spec in revs: + # attempt to parse old-style ranges first to deal with + # things like old-tag which contain query metacharacters + try: + if isinstance(spec, int): + seen.add(spec) + l.append(spec) + continue + + if _revrangesep in spec: + start, end = spec.split(_revrangesep, 1) + start = revfix(repo, start, 0) + end = revfix(repo, end, len(repo) - 1) + step = start > end and -1 or 1 + for rev in xrange(start, end + step, step): + if rev in seen: + continue + seen.add(rev) + l.append(rev) + continue + elif spec and spec in repo: # single unquoted rev + rev = revfix(repo, spec, None) + if rev in seen: + continue + seen.add(rev) + l.append(rev) + continue + except error.RepoLookupError: + pass + + # fall through to new-style queries if old-style fails + m = revset.match(repo.ui, spec) + for r in m(repo, range(len(repo))): + if r not in seen: + l.append(r) + seen.update(l) + + return l diff -r 1f46be4689ed -r b33f3e35efb0 tests/autodiff.py --- a/tests/autodiff.py Fri May 13 12:57:27 2011 -0500 +++ b/tests/autodiff.py Fri May 13 14:06:28 2011 -0500 @@ -1,7 +1,7 @@ # Extension dedicated to test patch.diff() upgrade modes # # -from mercurial import cmdutil, patch, util +from mercurial import cmdutil, scmutil, patch, util def autodiff(ui, repo, *pats, **opts): diffopts = patch.diffopts(ui, opts) @@ -28,7 +28,7 @@ else: raise util.Abort('--git must be yes, no or auto') - node1, node2 = cmdutil.revpair(repo, []) + node1, node2 = scmutil.revpair(repo, []) m = cmdutil.match(repo, pats, opts) it = patch.diff(repo, node1, node2, match=m, opts=diffopts, losedatafn=losedatafn)