diff options
Diffstat (limited to 'hgext/mq.py')
-rw-r--r-- | hgext/mq.py | 704 |
1 files changed, 197 insertions, 507 deletions
diff --git a/hgext/mq.py b/hgext/mq.py index 33a31c4..a1b4e81 100644 --- a/hgext/mq.py +++ b/hgext/mq.py @@ -38,32 +38,15 @@ preserving existing git patches upon qrefresh. If set to 'yes' or 'no', mq will override the [diff] section and always generate git or regular patches, possibly losing data in the second case. -It may be desirable for mq changesets to be kept in the secret phase (see -:hg:`help phases`), which can be enabled with the following setting:: - - [mq] - secret = True - You will by default be managing a patch queue named "patches". You can create other, independent patch queues with the :hg:`qqueue` command. - -If the working directory contains uncommitted files, qpush, qpop and -qgoto abort immediately. If -f/--force is used, the changes are -discarded. Setting:: - - [mq] - keepchanges = True - -make them behave as if --keep-changes were passed, and non-conflicting -local changes will be tolerated and preserved. If incompatible options -such as -f/--force or --exact are passed, this setting is ignored. ''' from mercurial.i18n import _ 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, phases +from mercurial import repair, extensions, url, error from mercurial import patch as patchmod import os, re, errno, shutil @@ -73,7 +56,6 @@ seriesopts = [('s', 'summary', None, _('print first line of patch header'))] cmdtable = {} command = cmdutil.command(cmdtable) -testedwith = 'internal' # Patch names looks like unix-file names. # They must be joinable with queue directory and result in the patch path. @@ -269,32 +251,6 @@ class patchheader(object): ci += 1 del self.comments[ci] -def newcommit(repo, phase, *args, **kwargs): - """helper dedicated to ensure a commit respect mq.secret setting - - It should be used instead of repo.commit inside the mq source for operation - creating new changeset. - """ - if phase is None: - if repo.ui.configbool('mq', 'secret', False): - phase = phases.secret - if phase is not None: - backup = repo.ui.backupconfig('phases', 'new-commit') - # Marking the repository as committing an mq patch can be used - # to optimize operations like _branchtags(). - repo._committingpatch = True - try: - if phase is not None: - repo.ui.setconfig('phases', 'new-commit', phase) - return repo.commit(*args, **kwargs) - finally: - repo._committingpatch = False - if phase is not None: - repo.ui.restoreconfig(backup) - -class AbortNoCleanup(error.Abort): - pass - class queue(object): def __init__(self, ui, path, patchdir=None): self.basepath = path @@ -311,8 +267,8 @@ class queue(object): self.path = patchdir or curpath self.opener = scmutil.opener(self.path) self.ui = ui - self.applieddirty = False - self.seriesdirty = False + self.applieddirty = 0 + self.seriesdirty = 0 self.added = [] self.seriespath = "series" self.statuspath = "status" @@ -323,7 +279,7 @@ class queue(object): try: gitmode = ui.configbool('mq', 'git', None) if gitmode is None: - raise error.ConfigError + raise error.ConfigError() self.gitmode = gitmode and 'yes' or 'no' except error.ConfigError: self.gitmode = ui.config('mq', 'git', 'auto').lower() @@ -331,31 +287,25 @@ class queue(object): @util.propertycache def applied(self): - def parselines(lines): - for l in lines: - entry = l.split(':', 1) - if len(entry) > 1: - n, name = entry - yield statusentry(bin(n), name) - elif l.strip(): - self.ui.warn(_('malformated mq status line: %s\n') % entry) - # else we ignore empty lines - try: + if os.path.exists(self.join(self.statuspath)): + def parselines(lines): + for l in lines: + entry = l.split(':', 1) + if len(entry) > 1: + n, name = entry + yield statusentry(bin(n), name) + elif l.strip(): + self.ui.warn(_('malformated mq status line: %s\n') % entry) + # else we ignore empty lines lines = self.opener.read(self.statuspath).splitlines() return list(parselines(lines)) - except IOError, e: - if e.errno == errno.ENOENT: - return [] - raise + return [] @util.propertycache def fullseries(self): - try: + if os.path.exists(self.join(self.seriespath)): return self.opener.read(self.seriespath).splitlines() - except IOError, e: - if e.errno == errno.ENOENT: - return [] - raise + return [] @util.propertycache def series(self): @@ -371,8 +321,8 @@ class queue(object): for a in 'applied fullseries series seriesguards'.split(): if a in self.__dict__: delattr(self, a) - self.applieddirty = False - self.seriesdirty = False + self.applieddirty = 0 + self.seriesdirty = 0 self.guardsdirty = False self.activeguards = None @@ -547,13 +497,10 @@ class queue(object): fp.close() if self.applieddirty: writelist(map(str, self.applied), self.statuspath) - self.applieddirty = False if self.seriesdirty: writelist(self.fullseries, self.seriespath) - self.seriesdirty = False if self.guardsdirty: writelist(self.activeguards, self.guardspath) - self.guardsdirty = False if self.added: qrepo = self.qrepo() if qrepo: @@ -569,18 +516,6 @@ class queue(object): except OSError, inst: self.ui.warn(_('error removing undo: %s\n') % str(inst)) - def backup(self, repo, files, copy=False): - # backup local changes in --force case - for f in sorted(files): - absf = repo.wjoin(f) - if os.path.lexists(absf): - self.ui.note(_('saving current version of %s as %s\n') % - (f, f + '.orig')) - if copy: - util.copyfile(absf, absf + '.orig') - else: - util.rename(absf, absf + '.orig') - def printdiff(self, repo, diffopts, node1, node2=None, files=None, fp=None, changes=None, opts={}): stat = opts.get('stat') @@ -609,12 +544,12 @@ class queue(object): ret = hg.merge(repo, rev) if ret: raise util.Abort(_("update returned %d") % ret) - n = newcommit(repo, None, ctx.description(), ctx.user(), force=True) + n = repo.commit(ctx.description(), ctx.user(), force=True) if n is None: raise util.Abort(_("repo commit failed")) try: ph = patchheader(mergeq.join(patch), self.plainmode) - except Exception: + except: raise util.Abort(_("unable to read %s") % patch) diffopts = self.patchopts(diffopts, patch) @@ -649,10 +584,10 @@ class queue(object): # the first patch in the queue is never a merge patch # pname = ".hg.patches.merge.marker" - n = newcommit(repo, None, '[mq]: merge marker', force=True) + n = repo.commit('[mq]: merge marker', force=True) self.removeundo(repo) self.applied.append(statusentry(n, pname)) - self.applieddirty = True + self.applieddirty = 1 head = self.qparents(repo) @@ -673,7 +608,7 @@ class queue(object): err, head = self.mergeone(repo, mergeq, head, patch, rev, diffopts) if head: self.applied.append(statusentry(head, patch)) - self.applieddirty = True + self.applieddirty = 1 if err: return (err, head) self.savedirty() @@ -691,12 +626,10 @@ class queue(object): self.ui.note(str(inst) + '\n') if not self.ui.verbose: self.ui.warn(_("patch failed, unable to continue (try -v)\n")) - self.ui.traceback() return (False, list(files), False) def apply(self, repo, series, list=False, update_status=True, - strict=False, patchdir=None, merge=None, all_files=None, - tobackup=None, keepchanges=False): + strict=False, patchdir=None, merge=None, all_files=None): wlock = lock = tr = None try: wlock = repo.wlock() @@ -704,36 +637,25 @@ class queue(object): tr = repo.transaction("qpush") try: ret = self._apply(repo, series, list, update_status, - strict, patchdir, merge, all_files=all_files, - tobackup=tobackup, keepchanges=keepchanges) + strict, patchdir, merge, all_files=all_files) tr.close() self.savedirty() return ret - except AbortNoCleanup: - tr.close() - self.savedirty() - return 2, repo.dirstate.p1() - except: # re-raises + except: try: tr.abort() finally: repo.invalidate() repo.dirstate.invalidate() - self.invalidate() raise finally: release(tr, lock, wlock) self.removeundo(repo) def _apply(self, repo, series, list=False, update_status=True, - strict=False, patchdir=None, merge=None, all_files=None, - tobackup=None, keepchanges=False): - """returns (error, hash) - - error = 1 for unable to read, 2 for patch failed, 3 for patch - fuzz. tobackup is None or a set of files to backup before they - are modified by a patch. - """ + strict=False, patchdir=None, merge=None, all_files=None): + '''returns (error, hash) + error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz''' # TODO unify with commands.py if not patchdir: patchdir = self.path @@ -765,14 +687,6 @@ class queue(object): message = '\n'.join(message) if ph.haspatch: - if tobackup: - touched = patchmod.changedfiles(self.ui, repo, pf) - touched = set(touched) & tobackup - if touched and keepchanges: - raise AbortNoCleanup( - _("local changes found, refresh first")) - self.backup(repo, touched, copy=True) - tobackup = tobackup - touched (patcherr, files, fuzz) = self.patch(repo, pf) if all_files is not None: all_files.update(files) @@ -795,14 +709,11 @@ class queue(object): for f in merged: repo.dirstate.merge(f) p1, p2 = repo.dirstate.parents() - repo.setparents(p1, merge) + repo.dirstate.setparents(p1, merge) match = scmutil.matchfiles(repo, files or []) - oldtip = repo['tip'] - n = newcommit(repo, None, message, ph.user, ph.date, match=match, - force=True) - if repo['tip'] == oldtip: - raise util.Abort(_("qpush exactly duplicates child changeset")) + n = repo.commit(message, ph.user, ph.date, match=match, force=True) + if n is None: raise util.Abort(_("repository commit failed")) @@ -828,11 +739,10 @@ class queue(object): for p in patches: os.unlink(self.join(p)) - qfinished = [] if numrevs: qfinished = self.applied[:numrevs] del self.applied[:numrevs] - self.applieddirty = True + self.applieddirty = 1 unknown = [] @@ -854,8 +764,7 @@ class queue(object): raise util.Abort(''.join(msg % p for p in unknown)) self.parseseries() - self.seriesdirty = True - return [entry.node for entry in qfinished] + self.seriesdirty = 1 def _revpatches(self, repo, revs): firstrev = repo[self.applied[0].node].rev() @@ -882,17 +791,8 @@ class queue(object): return patches def finish(self, repo, revs): - # Manually trigger phase computation to ensure phasedefaults is - # executed before we remove the patches. - repo._phasecache patches = self._revpatches(repo, sorted(revs)) - qfinished = self._cleanup(patches, len(patches)) - if qfinished and repo.ui.configbool('mq', 'secret', False): - # only use this logic when the secret option is added - oldqbase = repo[qfinished[0]] - tphase = repo.ui.config('phases', 'new-commit', phases.draft) - if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase: - phases.advanceboundary(repo, tphase, qfinished) + self._cleanup(patches, len(patches)) def delete(self, repo, patches, opts): if not patches and not opts.get('rev'): @@ -933,35 +833,19 @@ class queue(object): return top, patch return None, None - def checksubstate(self, repo, baserev=None): + def checksubstate(self, repo): '''return list of subrepos at a different revision than substate. Abort if any subrepos have uncommitted changes.''' inclsubs = [] wctx = repo[None] - if baserev: - bctx = repo[baserev] - else: - bctx = wctx.parents()[0] for s in wctx.substate: if wctx.sub(s).dirty(True): raise util.Abort( _("uncommitted changes in subrepository %s") % s) - elif s not in bctx.substate or bctx.sub(s).dirty(): + elif wctx.sub(s).dirty(): inclsubs.append(s) return inclsubs - def putsubstate2changes(self, substatestate, changes): - for files in changes[:3]: - if '.hgsubstate' in files: - return # already listed up - # not yet listed up - if substatestate in 'a?': - changes[1].append('.hgsubstate') - elif substatestate in 'r': - changes[2].append('.hgsubstate') - else: # modified - changes[0].append('.hgsubstate') - def localchangesfound(self, refresh=True): if refresh: raise util.Abort(_("local changes found, refresh first")) @@ -997,10 +881,6 @@ class queue(object): else: raise util.Abort(_('patch "%s" already exists') % name) - def checkkeepchanges(self, keepchanges, force): - if force and keepchanges: - raise util.Abort(_('cannot use both --force and --keep-changes')) - def new(self, repo, patchfn, *pats, **opts): """options: msg: a string or a no-argument function returning a string @@ -1016,7 +896,6 @@ class queue(object): inclsubs = self.checksubstate(repo) if inclsubs: inclsubs.append('.hgsubstate') - substatestate = repo.dirstate['.hgsubstate'] if opts.get('include') or opts.get('exclude') or pats: if inclsubs: pats = list(pats or []) + inclsubs @@ -1026,12 +905,10 @@ class queue(object): if f != '.hgsubstate': # .hgsubstate is auto-created raise util.Abort('%s: %s' % (f, msg)) match.bad = badfn - changes = repo.status(match=match) - m, a, r, d = changes[:4] + m, a, r, d = repo.status(match=match)[:4] else: - changes = self.checklocalchanges(repo, force=True) - m, a, r, d = changes - match = scmutil.matchfiles(repo, m + a + r + inclsubs) + m, a, r, d = self.checklocalchanges(repo, force=True) + match = scmutil.matchfiles(repo, m + a + r + inclsubs) if len(repo[None].parents()) > 1: raise util.Abort(_('cannot manage merge changesets')) commitfiles = m + a + r @@ -1061,42 +938,41 @@ class queue(object): p.write("# User " + user + "\n") if date: p.write("# Date %s %s\n\n" % date) - if util.safehasattr(msg, '__call__'): + if hasattr(msg, '__call__'): msg = msg() commitmsg = msg and msg or ("[mq]: %s" % patchfn) - n = newcommit(repo, None, commitmsg, user, date, match=match, - force=True) + n = repo.commit(commitmsg, user, date, match=match, force=True) if n is None: raise util.Abort(_("repo commit failed")) try: self.fullseries[insert:insert] = [patchfn] self.applied.append(statusentry(n, patchfn)) self.parseseries() - self.seriesdirty = True - self.applieddirty = True + self.seriesdirty = 1 + self.applieddirty = 1 if msg: msg = msg + "\n\n" p.write(msg) if commitfiles: parent = self.qparents(repo, n) - if inclsubs: - self.putsubstate2changes(substatestate, changes) chunks = patchmod.diff(repo, node1=parent, node2=n, - changes=changes, opts=diffopts) + match=match, opts=diffopts) for chunk in chunks: p.write(chunk) p.close() + wlock.release() + wlock = None r = self.qrepo() if r: r[None].add([patchfn]) - except: # re-raises + except: repo.rollback() raise except Exception: patchpath = self.join(patchfn) try: os.unlink(patchpath) - except OSError: + except: self.ui.warn(_('error unlinking %s\n') % patchpath) raise self.removeundo(repo) @@ -1115,7 +991,12 @@ class queue(object): hg.clean(repo, urev) repo.dirstate.write() - repair.strip(self.ui, repo, revs, backup) + self.removeundo(repo) + for rev in revs: + repair.strip(self.ui, repo, rev, backup) + # strip may have unbundled a set of backed up revisions after + # the actual strip + self.removeundo(repo) finally: release(lock, wlock) @@ -1129,10 +1010,12 @@ class queue(object): # if the exact patch name does not exist, we try a few # variations. If strict is passed, we try only #1 # - # 1) a number (as string) to indicate an offset in the series file + # 1) a number to indicate an offset in the series file # 2) a unique substring of the patch name was given # 3) patchname[-+]num to indicate an offset in the series file def lookup(self, patch, strict=False): + patch = patch and str(patch) + def partialname(s): if s in self.series: return s @@ -1151,6 +1034,8 @@ class queue(object): return self.series[0] return None + if patch is None: + return None if patch in self.series: return patch @@ -1193,10 +1078,8 @@ class queue(object): return self.series[i + off] raise util.Abort(_("patch %s not in series") % patch) - def push(self, repo, patch=None, force=False, list=False, mergeq=None, - all=False, move=False, exact=False, nobackup=False, - keepchanges=False): - self.checkkeepchanges(keepchanges, force) + def push(self, repo, patch=None, force=False, list=False, + mergeq=None, all=False, move=False, exact=False): diffopts = self.diffopts() wlock = repo.wlock() try: @@ -1212,12 +1095,12 @@ class queue(object): self.ui.warn(_('no patches in series\n')) return 0 + patch = self.lookup(patch) # Suppose our series file is: A B C and the current 'top' # patch is B. qpush C should be performed (moving forward) # qpush B is a NOP (no change) qpush A is an error (can't # go backwards with qpush) if patch: - patch = self.lookup(patch) info = self.isapplied(patch) if info and info[0] >= len(self.applied) - 1: self.ui.warn( @@ -1251,47 +1134,37 @@ class queue(object): if start == len(self.series): self.ui.warn(_('patch series already fully applied\n')) return 1 - if not force and not keepchanges: + if not force: self.checklocalchanges(repo, refresh=self.applied) if exact: - if keepchanges: - raise util.Abort( - _("cannot use --exact and --keep-changes together")) if move: - raise util.Abort(_('cannot use --exact and --move ' - 'together')) + raise util.Abort(_("cannot use --exact and --move together")) if self.applied: - raise util.Abort(_('cannot push --exact with applied ' - 'patches')) + raise util.Abort(_("cannot push --exact with applied patches")) root = self.series[start] target = patchheader(self.join(root), self.plainmode).parent if not target: - raise util.Abort( - _("%s does not have a parent recorded") % root) + raise util.Abort(_("%s does not have a parent recorded" % root)) if not repo[target] == repo['.']: hg.update(repo, target) if move: if not patch: raise util.Abort(_("please specify the patch to move")) - for fullstart, rpn in enumerate(self.fullseries): - # strip markers for patch guards - if self.guard_re.split(rpn, 1)[0] == self.series[start]: - break - for i, rpn in enumerate(self.fullseries[fullstart:]): + for i, rpn in enumerate(self.fullseries[start:]): # strip markers for patch guards if self.guard_re.split(rpn, 1)[0] == patch: break - index = fullstart + i + index = start + i assert index < len(self.fullseries) fullpatch = self.fullseries[index] del self.fullseries[index] - self.fullseries.insert(fullstart, fullpatch) + self.fullseries.insert(start, fullpatch) self.parseseries() - self.seriesdirty = True + self.seriesdirty = 1 - self.applieddirty = True + self.applieddirty = 1 if start > 0: self.checktoppatch(repo) if not patch: @@ -1300,23 +1173,14 @@ class queue(object): else: end = self.series.index(patch, start) + 1 - tobackup = set() - if (not nobackup and force) or keepchanges: - m, a, r, d = self.checklocalchanges(repo, force=True) - if keepchanges: - tobackup.update(m + a + r + d) - else: - tobackup.update(m + a) - s = self.series[start:end] all_files = set() try: if mergeq: ret = self.mergepatch(repo, mergeq, s, diffopts) else: - ret = self.apply(repo, s, list, all_files=all_files, - tobackup=tobackup, keepchanges=keepchanges) - except: # re-raises + ret = self.apply(repo, s, list, all_files=all_files) + except: self.ui.warn(_('cleaning up working directory...')) node = repo.dirstate.p1() hg.revert(repo, node, None) @@ -1345,9 +1209,7 @@ class queue(object): finally: wlock.release() - def pop(self, repo, patch=None, force=False, update=True, all=False, - nobackup=False, keepchanges=False): - self.checkkeepchanges(keepchanges, force) + def pop(self, repo, patch=None, force=False, update=True, all=False): wlock = repo.wlock() try: if patch: @@ -1392,17 +1254,10 @@ class queue(object): break update = needupdate - tobackup = set() - if update: - m, a, r, d = self.checklocalchanges( - repo, force=force or keepchanges) - if force: - if not nobackup: - tobackup.update(m + a) - elif keepchanges: - tobackup.update(m + a + r + d) - - self.applieddirty = True + if not force and update: + self.checklocalchanges(repo) + + self.applieddirty = 1 end = len(self.applied) rev = self.applied[start].node if update: @@ -1417,10 +1272,6 @@ class queue(object): if heads != [self.applied[-1].node]: raise util.Abort(_("popping would remove a revision not " "managed by this patch queue")) - if not repo[self.applied[-1].node].mutable(): - raise util.Abort( - _("popping would remove an immutable revision"), - hint=_('see "hg help phases" for details')) # we know there are no local changes, so we can make a simplified # form of hg.update. @@ -1430,12 +1281,6 @@ class queue(object): m, a, r, d = repo.status(qp, top)[:4] if d: raise util.Abort(_("deletions found between repo revs")) - - tobackup = set(a + m + r) & tobackup - if keepchanges and tobackup: - self.localchangesfound() - self.backup(repo, tobackup) - for f in a: try: util.unlinkpath(repo.wjoin(f)) @@ -1447,7 +1292,7 @@ class queue(object): fctx = ctx[f] repo.wwrite(f, fctx.data(), fctx.flags()) repo.dirstate.normal(f) - repo.setparents(qp, nullid) + repo.dirstate.setparents(qp, nullid) for patch in reversed(self.applied[start:end]): self.ui.status(_("popping %s\n") % patch.name) del self.applied[start:end] @@ -1488,18 +1333,11 @@ class queue(object): (top, patchfn) = (self.applied[-1].node, self.applied[-1].name) if repo.changelog.heads(top) != [top]: raise util.Abort(_("cannot refresh a revision with children")) - if not repo[top].mutable(): - raise util.Abort(_("cannot refresh immutable revision"), - hint=_('see "hg help phases" for details')) + + inclsubs = self.checksubstate(repo) cparents = repo.changelog.parents(top) patchparent = self.qparents(repo, top) - - inclsubs = self.checksubstate(repo, hex(patchparent)) - if inclsubs: - inclsubs.append('.hgsubstate') - substatestate = repo.dirstate['.hgsubstate'] - ph = patchheader(self.join(patchfn), self.plainmode) diffopts = self.diffopts({'git': opts.get('git')}, patchfn) if msg: @@ -1577,6 +1415,10 @@ class queue(object): a = list(aa) c = [filter(matchfn, l) for l in (m, a, r)] match = scmutil.matchfiles(repo, set(c[0] + c[1] + c[2] + inclsubs)) + chunks = patchmod.diff(repo, patchparent, match=match, + changes=c, opts=diffopts) + for chunk in chunks: + patchf.write(chunk) try: if diffopts.git or diffopts.upgrade: @@ -1635,35 +1477,24 @@ class queue(object): user = ph.user or changes[1] - oldphase = repo[top].phase() - # assumes strip can roll itself back if interrupted - repo.setparents(*cparents) + repo.dirstate.setparents(*cparents) self.applied.pop() - self.applieddirty = True + self.applieddirty = 1 self.strip(repo, [top], update=False, backup='strip') - except: # re-raises + except: repo.dirstate.invalidate() raise try: # might be nice to attempt to roll back strip after this - - # Ensure we create a new changeset in the same phase than - # the old one. - n = newcommit(repo, oldphase, message, user, ph.date, - match=match, force=True) + n = repo.commit(message, user, ph.date, match=match, + force=True) # only write patch after a successful commit - if inclsubs: - self.putsubstate2changes(substatestate, c) - chunks = patchmod.diff(repo, patchparent, - changes=c, opts=diffopts) - for chunk in chunks: - patchf.write(chunk) - patchf.close() + patchf.rename() self.applied.append(statusentry(n, patchfn)) - except: # re-raises + except: ctx = repo[cparents[0]] repo.dirstate.rebuild(ctx.node(), ctx.manifest()) self.savedirty() @@ -1790,14 +1621,14 @@ class queue(object): else: series.append(l) if datastart is None: - self.ui.warn(_("no saved patch data found\n")) + self.ui.warn(_("No saved patch data found\n")) return 1 self.ui.warn(_("restoring status: %s\n") % lines[0]) self.fullseries = series self.applied = applied self.parseseries() - self.seriesdirty = True - self.applieddirty = True + self.seriesdirty = 1 + self.applieddirty = 1 heads = repo.changelog.heads() if delete: if rev not in heads: @@ -1817,7 +1648,7 @@ class queue(object): self.ui.status(_("updating queue directory\n")) r = self.qrepo() if not r: - self.ui.warn(_("unable to load queue repository\n")) + self.ui.warn(_("Unable to load queue repository\n")) return 1 hg.clean(r, qpp[0]) @@ -1845,7 +1676,7 @@ class queue(object): self.ui.warn(_("repo commit failed\n")) return 1 self.applied.append(statusentry(n, '.hg.patches.save.line')) - self.applieddirty = True + self.applieddirty = 1 self.removeundo(repo) def fullseriesend(self): @@ -1869,9 +1700,9 @@ class queue(object): for i in xrange(start, len(self.series)): p, reason = self.pushable(i) if p: - return i + break self.explainpushable(i) - return len(self.series) + return i if self.applied: p = self.applied[-1].name try: @@ -1902,12 +1733,9 @@ class queue(object): 'files')) rev = scmutil.revrange(repo, rev) rev.sort(reverse=True) - elif not files: - raise util.Abort(_('no files or revisions specified')) if (len(files) > 1 or len(rev) > 1) and patchname: raise util.Abort(_('option "-n" not valid when importing multiple ' 'patches')) - imported = [] if rev: # If mq patches are applied, we can only import revisions # that form a linear path to qbase. @@ -1934,9 +1762,6 @@ class queue(object): diffopts = self.diffopts({'git': git}) for r in rev: - if not repo[r].mutable(): - raise util.Abort(_('revision %d is not mutable') % r, - hint=_('see "hg help phases" for details')) p1, p2 = repo.changelog.parentrevs(r) n = repo.changelog.node(r) if p2 != nullrev: @@ -1960,13 +1785,9 @@ class queue(object): self.applied.insert(0, se) self.added.append(patchname) - imported.append(patchname) patchname = None - if rev and repo.ui.configbool('mq', 'secret', False): - # if we added anything with --rev, we must move the secret root - phases.retractboundary(repo, phases.secret, [n]) self.parseseries() - self.applieddirty = True + self.applieddirty = 1 self.seriesdirty = True for i, filename in enumerate(files): @@ -2015,19 +1836,9 @@ class queue(object): self.seriesdirty = True self.ui.warn(_("adding %s to series file\n") % patchname) self.added.append(patchname) - imported.append(patchname) patchname = None self.removeundo(repo) - return imported - -def fixkeepchangesopts(ui, opts): - if (not ui.configbool('mq', 'keepchanges') or opts.get('force') - or opts.get('exact')): - return opts - opts = dict(opts) - opts['keep_changes'] = True - return opts @command("qdelete|qremove|qrm", [('k', 'keep', None, _('keep patch file')), @@ -2037,9 +1848,8 @@ def fixkeepchangesopts(ui, opts): def delete(ui, repo, *patches, **opts): """remove patches from queue - The patches must not be applied, and at least one patch is required. Exact - patch identifiers must be given. With -k/--keep, the patch files are - preserved in the patch directory. + The patches must not be applied, and at least one patch is required. With + -k/--keep, the patch files are preserved in the patch directory. To stop managing a patch and move it into permanent history, use the :hg:`qfinish` command.""" @@ -2049,7 +1859,7 @@ def delete(ui, repo, *patches, **opts): return 0 @command("qapplied", - [('1', 'last', None, _('show only the preceding applied patch')) + [('1', 'last', None, _('show only the last patch')) ] + seriesopts, _('hg qapplied [-1] [-s] [PATCH]')) def applied(ui, repo, patch=None, **opts): @@ -2115,9 +1925,9 @@ def unapplied(ui, repo, patch=None, **opts): _('place existing revisions under mq control'), _('REV')), ('g', 'git', None, _('use git extended diff format')), ('P', 'push', None, _('qpush after importing'))], - _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... [FILE]...')) + _('hg qimport [-e] [-n NAME] [-f] [-g] [-P] [-r REV]... FILE...')) def qimport(ui, repo, *filename, **opts): - """import a patch or existing changeset + """import a patch The patch is inserted into the series after the last applied patch. If no patches have been applied, qimport prepends the patch @@ -2149,21 +1959,16 @@ def qimport(ui, repo, *filename, **opts): Returns 0 if import succeeded. """ - lock = repo.lock() # cause this may move phase + q = repo.mq try: - q = repo.mq - try: - imported = q.qimport( - repo, filename, patchname=opts.get('name'), - existing=opts.get('existing'), force=opts.get('force'), - rev=opts.get('rev'), git=opts.get('git')) - finally: - q.savedirty() + q.qimport(repo, filename, patchname=opts.get('name'), + existing=opts.get('existing'), force=opts.get('force'), + rev=opts.get('rev'), git=opts.get('git')) finally: - lock.release() + q.savedirty() - if imported and opts.get('push') and not opts.get('rev'): - return q.push(repo, imported[-1]) + if opts.get('push') and not opts.get('rev'): + return q.push(repo, None) return 0 def qinit(ui, repo, create): @@ -2210,8 +2015,7 @@ def init(ui, repo, **opts): @command("qclone", [('', 'pull', None, _('use pull protocol to copy metadata')), - ('U', 'noupdate', None, - _('do not update the new working directories')), + ('U', 'noupdate', None, _('do not update the new working directories')), ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')), ('p', 'patches', '', @@ -2236,63 +2040,53 @@ def clone(ui, source, dest=None, **opts): Return 0 on success. ''' def patchdir(repo): - """compute a patch repo url from a repo object""" url = repo.url() if url.endswith('/'): url = url[:-1] return url + '/.hg/patches' - - # main repo (destination and sources) if dest is None: dest = hg.defaultdest(source) - sr = hg.peer(ui, opts, ui.expandpath(source)) - - # patches repo (source only) + sr = hg.repository(hg.remoteui(ui, opts), ui.expandpath(source)) if opts.get('patches'): patchespath = ui.expandpath(opts.get('patches')) else: patchespath = patchdir(sr) try: - hg.peer(ui, opts, patchespath) + hg.repository(ui, patchespath) except error.RepoError: raise util.Abort(_('versioned patch repository not found' ' (see init --mq)')) qbase, destrev = None, None if sr.local(): - repo = sr.local() - if repo.mq.applied and repo[qbase].phase() != phases.secret: - qbase = repo.mq.applied[0].node + if sr.mq.applied: + qbase = sr.mq.applied[0].node if not hg.islocal(dest): - heads = set(repo.heads()) - destrev = list(heads.difference(repo.heads(qbase))) - destrev.append(repo.changelog.parents(qbase)[0]) + heads = set(sr.heads()) + destrev = list(heads.difference(sr.heads(qbase))) + destrev.append(sr.changelog.parents(qbase)[0]) elif sr.capable('lookup'): try: qbase = sr.lookup('qbase') except error.RepoError: pass - ui.note(_('cloning main repository\n')) sr, dr = hg.clone(ui, opts, sr.url(), dest, pull=opts.get('pull'), rev=destrev, update=False, stream=opts.get('uncompressed')) - ui.note(_('cloning patch repository\n')) hg.clone(ui, opts, opts.get('patches') or patchdir(sr), patchdir(dr), pull=opts.get('pull'), update=not opts.get('noupdate'), stream=opts.get('uncompressed')) - if dr.local(): - repo = dr.local() if qbase: ui.note(_('stripping applied patches from destination ' 'repository\n')) - repo.mq.strip(repo, [qbase], update=False, backup=None) + dr.mq.strip(dr, [qbase], update=False, backup=None) if not opts.get('noupdate'): ui.note(_('updating destination repository\n')) - hg.update(repo, repo.changelog.tip()) + hg.update(dr, dr.changelog.tip()) @command("qcommit|qci", commands.table["^commit|ci"][1], @@ -2315,8 +2109,7 @@ def series(ui, repo, **opts): """print the entire series file Returns 0 on success.""" - repo.mq.qseries(repo, missing=opts.get('missing'), - summary=opts.get('summary')) + repo.mq.qseries(repo, missing=opts.get('missing'), summary=opts.get('summary')) return 0 @command("qtop", seriesopts, _('hg qtop [-s]')) @@ -2335,7 +2128,7 @@ def top(ui, repo, **opts): @command("qnext", seriesopts, _('hg qnext [-s]')) def next(ui, repo, **opts): - """print the name of the next pushable patch + """print the name of the next patch Returns 0 on success.""" q = repo.mq @@ -2347,7 +2140,7 @@ def next(ui, repo, **opts): @command("qprev", seriesopts, _('hg qprev [-s]')) def prev(ui, repo, **opts): - """print the name of the preceding applied patch + """print the name of the previous patch Returns 0 on success.""" q = repo.mq @@ -2358,8 +2151,7 @@ def prev(ui, repo, **opts): if not l: ui.write(_("no patches applied\n")) return 1 - idx = q.series.index(q.applied[-2].name) - q.qseries(repo, start=idx, length=1, status='A', + q.qseries(repo, start=l - 2, length=1, status='A', summary=opts.get('summary')) def setupheaderopts(ui, opts): @@ -2517,7 +2309,9 @@ def fold(ui, repo, *files, **opts): current patch header, separated by a line of ``* * *``. Returns 0 on success.""" + q = repo.mq + if not files: raise util.Abort(_('qfold requires at least one patch name')) if not q.checktoppatch(repo)[0]: @@ -2535,10 +2329,9 @@ def fold(ui, repo, *files, **opts): for f in files: p = q.lookup(f) if p in patches or p == parent: - ui.warn(_('skipping already folded patch %s\n') % p) + ui.warn(_('Skipping already folded patch %s\n') % p) if q.isapplied(p): - raise util.Abort(_('qfold cannot fold already applied patch %s') - % p) + raise util.Abort(_('qfold cannot fold already applied patch %s') % p) patches.append(p) for p in patches: @@ -2572,26 +2365,18 @@ def fold(ui, repo, *files, **opts): wlock.release() @command("qgoto", - [('', 'keep-changes', None, - _('tolerate non-conflicting local changes')), - ('f', 'force', None, _('overwrite any local changes')), - ('', 'no-backup', None, _('do not save backup copies of files'))], + [('f', 'force', None, _('overwrite any local changes'))], _('hg qgoto [OPTION]... PATCH')) def goto(ui, repo, patch, **opts): '''push or pop patches until named patch is at top of stack Returns 0 on success.''' - opts = fixkeepchangesopts(ui, opts) q = repo.mq patch = q.lookup(patch) - nobackup = opts.get('no_backup') - keepchanges = opts.get('keep_changes') if q.isapplied(patch): - ret = q.pop(repo, patch, force=opts.get('force'), nobackup=nobackup, - keepchanges=keepchanges) + ret = q.pop(repo, patch, force=opts.get('force')) else: - ret = q.push(repo, patch, force=opts.get('force'), nobackup=nobackup, - keepchanges=keepchanges) + ret = q.push(repo, patch, force=opts.get('force')) q.savedirty() return ret @@ -2647,8 +2432,7 @@ def guard(ui, repo, *args, **opts): args = list(args) if opts.get('list'): if args or opts.get('none'): - raise util.Abort(_('cannot mix -l/--list with options or ' - 'arguments')) + raise util.Abort(_('cannot mix -l/--list with options or arguments')) for i in xrange(len(q.series)): status(i) return @@ -2712,34 +2496,26 @@ def savename(path): return newpath @command("^qpush", - [('', 'keep-changes', None, - _('tolerate non-conflicting local changes')), - ('f', 'force', None, _('apply on top of local changes')), - ('e', 'exact', None, - _('apply the target patch to its recorded parent')), + [('f', 'force', None, _('apply on top of local changes')), + ('e', 'exact', None, _('apply the target patch to its recorded parent')), ('l', 'list', None, _('list patch name in commit text')), ('a', 'all', None, _('apply all patches')), ('m', 'merge', None, _('merge from another queue (DEPRECATED)')), ('n', 'name', '', _('merge queue name (DEPRECATED)'), _('NAME')), - ('', 'move', None, - _('reorder patch series and apply only the patch')), - ('', 'no-backup', None, _('do not save backup copies of files'))], + ('', 'move', None, _('reorder patch series and apply only the patch'))], _('hg qpush [-f] [-l] [-a] [--move] [PATCH | INDEX]')) def push(ui, repo, patch=None, **opts): """push the next patch onto the stack - By default, abort if the working directory contains uncommitted - changes. With --keep-changes, abort only if the uncommitted files - overlap with patched files. With -f/--force, backup and patch over - uncommitted changes. + When -f/--force is applied, all local changes in patched files + will be lost. Return 0 on success. """ q = repo.mq mergeq = None - opts = fixkeepchangesopts(ui, opts) if opts.get('merge'): if opts.get('name'): newpath = repo.join(opts.get('name')) @@ -2748,48 +2524,37 @@ def push(ui, repo, patch=None, **opts): if not newpath: ui.warn(_("no saved queues found, please use -n\n")) return 1 - mergeq = queue(ui, repo.path, newpath) + mergeq = queue(ui, repo.join(""), newpath) ui.warn(_("merging with queue at: %s\n") % mergeq.path) ret = q.push(repo, patch, force=opts.get('force'), list=opts.get('list'), mergeq=mergeq, all=opts.get('all'), move=opts.get('move'), - exact=opts.get('exact'), nobackup=opts.get('no_backup'), - keepchanges=opts.get('keep_changes')) + exact=opts.get('exact')) return ret @command("^qpop", [('a', 'all', None, _('pop all patches')), ('n', 'name', '', _('queue name to pop (DEPRECATED)'), _('NAME')), - ('', 'keep-changes', None, - _('tolerate non-conflicting local changes')), - ('f', 'force', None, _('forget any local changes to patched files')), - ('', 'no-backup', None, _('do not save backup copies of files'))], + ('f', 'force', None, _('forget any local changes to patched files'))], _('hg qpop [-a] [-f] [PATCH | INDEX]')) def pop(ui, repo, patch=None, **opts): """pop the current patch off the stack - Without argument, pops off the top of the patch stack. If given a - patch name, keeps popping off patches until the named patch is at - the top of the stack. - - By default, abort if the working directory contains uncommitted - changes. With --keep-changes, abort only if the uncommitted files - overlap with patched files. With -f/--force, backup and discard - changes made to such files. + By default, pops off the top of the patch stack. If given a patch + name, keeps popping off patches until the named patch is at the + top of the stack. Return 0 on success. """ - opts = fixkeepchangesopts(ui, opts) localupdate = True if opts.get('name'): - q = queue(ui, repo.path, repo.join(opts.get('name'))) + q = queue(ui, repo.join(""), repo.join(opts.get('name'))) ui.warn(_('using patch queue: %s\n') % q.path) localupdate = False else: q = repo.mq ret = q.pop(repo, patch, force=opts.get('force'), update=localupdate, - all=opts.get('all'), nobackup=opts.get('no_backup'), - keepchanges=opts.get('keep_changes')) + all=opts.get('all')) q.savedirty() return ret @@ -2801,7 +2566,9 @@ def rename(ui, repo, patch, name=None, **opts): With two arguments, renames PATCH1 to PATCH2. Returns 0 on success.""" + q = repo.mq + if not name: name = patch patch = None @@ -2824,12 +2591,12 @@ def rename(ui, repo, patch, name=None, **opts): guards = q.guard_re.findall(q.fullseries[i]) q.fullseries[i] = name + ''.join([' #' + g for g in guards]) q.parseseries() - q.seriesdirty = True + q.seriesdirty = 1 info = q.isapplied(patch) if info: q.applied[info[0]] = statusentry(info[1], name) - q.applieddirty = True + q.applieddirty = 1 destdir = os.path.dirname(absdest) if not os.path.isdir(destdir): @@ -2844,6 +2611,8 @@ def rename(ui, repo, patch, name=None, **opts): r.dirstate.drop(patch) r.dirstate.add(name) else: + if r.dirstate[name] == 'r': + wctx.undelete([name]) wctx.copy(patch, name) wctx.forget([patch]) finally: @@ -2882,7 +2651,7 @@ def save(ui, repo, **opts): ret = q.save(repo, msg=message) if ret: return ret - q.savedirty() # save to .hg/patches before copying + q.savedirty() if opts.get('copy'): path = q.path if opts.get('name'): @@ -2899,28 +2668,22 @@ def save(ui, repo, **opts): ui.warn(_("copy %s to %s\n") % (path, newpath)) util.copyfiles(path, newpath) if opts.get('empty'): - del q.applied[:] - q.applieddirty = True - q.savedirty() + try: + os.unlink(q.join(q.statuspath)) + except: + pass return 0 @command("strip", - [ - ('r', 'rev', [], _('strip specified revision (optional, ' - 'can specify revisions without this ' - 'option)'), _('REV')), - ('f', 'force', None, _('force removal of changesets, discard ' + [('f', 'force', None, _('force removal of changesets, discard ' 'uncommitted changes (no backup)')), ('b', 'backup', None, _('bundle only changesets with local revision' ' number greater than REV which are not' ' descendants of REV (DEPRECATED)')), - ('', 'no-backup', None, _('no backups')), + ('n', 'no-backup', None, _('no backups')), ('', 'nobackup', None, _('no backups (DEPRECATED)')), - ('n', '', None, _('ignored (DEPRECATED)')), - ('k', 'keep', None, _("do not modify working copy during strip")), - ('B', 'bookmark', '', _("remove revs only reachable from given" - " bookmark"))], - _('hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...')) + ('k', 'keep', None, _("do not modify working copy during strip"))], + _('hg strip [-k] [-f] [-n] REV...')) def strip(ui, repo, *revs, **opts): """strip changesets and all their descendants from the repository @@ -2944,10 +2707,6 @@ def strip(ui, repo, *revs, **opts): Use the --no-backup option to discard the backup bundle once the operation completes. - Strip is not a history-rewriting operation and can be used on - changesets in the public phase. But if the stripped changesets have - been pushed to a remote repository you will likely pull them again. - Return 0 on success. """ backup = 'all' @@ -2957,38 +2716,11 @@ def strip(ui, repo, *revs, **opts): backup = 'none' cl = repo.changelog - revs = list(revs) + opts.get('rev') revs = set(scmutil.revrange(repo, revs)) - - if opts.get('bookmark'): - mark = opts.get('bookmark') - marks = repo._bookmarks - if mark not in marks: - raise util.Abort(_("bookmark '%s' not found") % mark) - - # If the requested bookmark is not the only one pointing to a - # a revision we have to only delete the bookmark and not strip - # anything. revsets cannot detect that case. - uniquebm = True - for m, n in marks.iteritems(): - if m != mark and n == repo[mark].node(): - uniquebm = False - break - if uniquebm: - rsrevs = repo.revs("ancestors(bookmark(%s)) - " - "ancestors(head() and not bookmark(%s)) - " - "ancestors(bookmark() and not bookmark(%s))", - mark, mark, mark) - revs.update(set(rsrevs)) - if not revs: - del marks[mark] - repo._writebookmarks(mark) - ui.write(_("bookmark '%s' deleted\n") % mark) - if not revs: raise util.Abort(_('empty revision set')) - descendants = set(cl.descendants(revs)) + descendants = set(cl.descendants(*revs)) strippedrevs = revs.union(descendants) roots = revs.difference(descendants) @@ -3030,14 +2762,8 @@ def strip(ui, repo, *revs, **opts): finally: wlock.release() - if opts.get('bookmark'): - del marks[mark] - repo._writebookmarks(marks) - ui.write(_("bookmark '%s' deleted\n") % mark) - repo.mq.strip(repo, revs, backup=backup, update=update, force=opts.get('force')) - return 0 @command("qselect", @@ -3141,7 +2867,7 @@ def select(ui, repo, *args, **opts): if i == 0: q.pop(repo, all=True) else: - q.pop(repo, str(i - 1)) + q.pop(repo, i - 1) break if popped: try: @@ -3183,22 +2909,12 @@ def finish(ui, repo, *revrange, **opts): return 0 revs = scmutil.revrange(repo, revrange) - if repo['.'].rev() in revs and repo[None].files(): - ui.warn(_('warning: uncommitted changes in the working directory\n')) - # queue.finish may changes phases but leave the responsability to lock the - # repo to the caller to avoid deadlock with wlock. This command code is - # responsability for this locking. - lock = repo.lock() - try: - q.finish(repo, revs) - q.savedirty() - finally: - lock.release() + q.finish(repo, revs) + q.savedirty() return 0 @command("qqueue", [('l', 'list', False, _('list all available queues')), - ('', 'active', False, _('print name of active queue')), ('c', 'create', False, _('create new queue')), ('', 'rename', False, _('rename active queue')), ('', 'delete', False, _('delete reference to queue')), @@ -3213,8 +2929,7 @@ def qqueue(ui, repo, name=None, **opts): Omitting a queue name or specifying -l/--list will show you the registered queues - by default the "normal" patches queue is registered. The currently - active queue will be marked with "(active)". Specifying --active will print - only the name of the active queue. + active queue will be marked with "(active)". To create a new queue, use -c/--create. The queue is automatically made active, except in the case where there are applied patches from the @@ -3226,7 +2941,9 @@ def qqueue(ui, repo, name=None, **opts): Returns 0 on success. ''' + q = repo.mq + _defaultqueue = 'patches' _allqueues = 'patches.queues' _activequeue = 'patches.queue' @@ -3305,11 +3022,8 @@ def qqueue(ui, repo, name=None, **opts): fh.close() util.rename(repo.join('patches.queues.new'), repo.join(_allqueues)) - if not name or opts.get('list') or opts.get('active'): + if not name or opts.get('list'): current = _getcurrent() - if opts.get('active'): - ui.write('%s\n' % (current,)) - return for queue in _getqueues(): ui.write('%s' % (queue,)) if queue == current and not ui.quiet: @@ -3369,22 +3083,11 @@ def qqueue(ui, repo, name=None, **opts): raise util.Abort(_('use --create to create a new queue')) _setactive(name) -def mqphasedefaults(repo, roots): - """callback used to set mq changeset as secret when no phase data exists""" - if repo.mq.applied: - if repo.ui.configbool('mq', 'secret', False): - mqphase = phases.secret - else: - mqphase = phases.draft - qbase = repo[repo.mq.applied[0].node] - roots[mqphase].add(qbase.node()) - return roots - def reposetup(ui, repo): class mqrepo(repo.__class__): @util.propertycache def mq(self): - return queue(self.ui, self.path) + return queue(self.ui, self.join("")) def abortifwdirpatched(self, errmsg, force=False): if self.mq.applied and not force: @@ -3404,22 +3107,15 @@ def reposetup(ui, repo): def checkpush(self, force, revs): if self.mq.applied and not force: - outapplied = [e.node for e in self.mq.applied] + haspatches = True if revs: - # Assume applied patches have no non-patch descendants and - # are not on remote already. Filtering any changeset not - # pushed. - heads = set(revs) - for node in reversed(outapplied): - if node in heads: - break - else: - outapplied.pop() - # looking for pushed and shared changeset - for node in outapplied: - if repo[node].phase() < phases.secret: - raise util.Abort(_('source has mq patches applied')) - # no non-secret patches pushed + # Assume applied patches have no non-patch descendants + # and are not on remote already. If they appear in the + # set of resolved 'revs', bail out. + applied = set(e.node for e in self.mq.applied) + haspatches = bool([n for n in revs if n in applied]) + if haspatches: + raise util.Abort(_('source has mq patches applied')) super(mqrepo, self).checkpush(force, revs) def _findtags(self): @@ -3445,8 +3141,8 @@ def reposetup(ui, repo): tags = result[0] for patch in mqtags: if patch[1] in tags: - self.ui.warn(_('tag %s overrides mq patch of the same ' - 'name\n') % patch[1]) + self.ui.warn(_('Tag %s overrides mq patch of the same name\n') + % patch[1]) else: tags[patch[1]] = patch[0] @@ -3454,20 +3150,16 @@ def reposetup(ui, repo): def _branchtags(self, partial, lrev): q = self.mq - cl = self.changelog - qbase = None if not q.applied: - if getattr(self, '_committingpatch', False): - # Committing a new patch, must be tip - qbase = len(cl) - 1 - else: - qbasenode = q.applied[0].node - try: - qbase = cl.rev(qbasenode) - except error.LookupError: - self.ui.warn(_('mq status file refers to unknown node %s\n') - % short(qbasenode)) - if qbase is None: + return super(mqrepo, self)._branchtags(partial, lrev) + + cl = self.changelog + qbasenode = q.applied[0].node + try: + qbase = cl.rev(qbasenode) + except error.LookupError: + self.ui.warn(_('mq status file refers to unknown node %s\n') + % short(qbasenode)) return super(mqrepo, self)._branchtags(partial, lrev) start = lrev + 1 @@ -3490,10 +3182,8 @@ def reposetup(ui, repo): if repo.local(): repo.__class__ = mqrepo - repo._phasedefaults.append(mqphasedefaults) - def mqimport(orig, ui, repo, *args, **kwargs): - if (util.safehasattr(repo, 'abortifwdirpatched') + if (hasattr(repo, 'abortifwdirpatched') and not kwargs.get('no_commit', False)): repo.abortifwdirpatched(_('cannot import over an applied patch'), kwargs.get('force')) @@ -3556,12 +3246,13 @@ def revsetmq(repo, subset, x): applied = set([repo[r.node].rev() for r in repo.mq.applied]) return [r for r in subset if r in applied] +def extsetup(ui): + revset.symbols['mq'] = revsetmq + # tell hggettext to extract docstrings from these functions: i18nfunctions = [revsetmq] -def extsetup(ui): - # Ensure mq wrappers are called first, regardless of extension load order by - # NOT wrapping in uisetup() and instead deferring to init stage two here. +def uisetup(ui): mqopt = [('', 'mq', None, _("operate on patch repository"))] extensions.wrapcommand(commands.table, 'import', mqimport) @@ -3586,7 +3277,6 @@ def extsetup(ui): if extmodule.__file__ != __file__: dotable(getattr(extmodule, 'cmdtable', {})) - revset.symbols['mq'] = revsetmq colortable = {'qguard.negative': 'red', 'qguard.positive': 'yellow', |