diff hgext/mq.py @ 9325:74e717a21779

Merge with mpm
author Bryan O'Sullivan <bos@serpentine.com>
date Thu, 06 Aug 2009 18:48:00 -0700
parents 53fdf18fd63b 061eeb602354
children 9a69ab6d7cf7
line wrap: on
line diff
--- a/hgext/mq.py	Wed Aug 05 17:19:37 2009 +0200
+++ b/hgext/mq.py	Thu Aug 06 18:48:00 2009 -0700
@@ -8,25 +8,25 @@
 '''manage a stack of patches
 
 This extension lets you work with a stack of patches in a Mercurial
-repository. It manages two stacks of patches - all known patches, and
-applied patches (subset of known patches).
+repository. It manages two stacks of patches - all known patches, and applied
+patches (subset of known patches).
 
-Known patches are represented as patch files in the .hg/patches
-directory. Applied patches are both patch files and changesets.
+Known patches are represented as patch files in the .hg/patches directory.
+Applied patches are both patch files and changesets.
 
-Common tasks (use "hg help command" for more details):
+Common tasks (use "hg help command" for more details)::
 
-prepare repository to work with patches   qinit
-create new patch                          qnew
-import existing patch                     qimport
+  prepare repository to work with patches   qinit
+  create new patch                          qnew
+  import existing patch                     qimport
 
-print patch series                        qseries
-print applied patches                     qapplied
-print name of top applied patch           qtop
+  print patch series                        qseries
+  print applied patches                     qapplied
+  print name of top applied patch           qtop
 
-add known patch to applied stack          qpush
-remove patch from applied stack           qpop
-refresh contents of top applied patch     qrefresh
+  add known patch to applied stack          qpush
+  remove patch from applied stack           qpop
+  refresh contents of top applied patch     qrefresh
 '''
 
 from mercurial.i18n import _
@@ -556,7 +556,7 @@
             if not pushable:
                 self.explain_pushable(patchname, all_patches=True)
                 continue
-            self.ui.warn(_("applying %s\n") % patchname)
+            self.ui.status(_("applying %s\n") % patchname)
             pf = os.path.join(patchdir, patchname)
 
             try:
@@ -1081,6 +1081,8 @@
                     except: pass
                     repo.dirstate.forget(f)
                 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]
             self.strip(repo, rev, update=False, backup='strip')
             if len(self.applied):
@@ -1344,19 +1346,24 @@
 
     def qseries(self, repo, missing=None, start=0, length=None, status=None,
                 summary=False):
-        def displayname(patchname):
+        def displayname(pfx, patchname):
             if summary:
                 ph = patchheader(self.join(patchname))
                 msg = ph.message
                 msg = msg and ': ' + msg[0] or ': '
             else:
                 msg = ''
-            return '%s%s' % (patchname, msg)
+            msg = "%s%s%s" % (pfx, patchname, msg)
+            if self.ui.interactive():
+                msg = util.ellipsis(msg, util.termwidth())
+            self.ui.write(msg + '\n')
 
         applied = set([p.name for p in self.applied])
         if length is None:
             length = len(self.series) - start
         if not missing:
+            if self.ui.verbose:
+                idxwidth = len(str(start+length - 1))
             for i in xrange(start, start+length):
                 patch = self.series[i]
                 if patch in applied:
@@ -1367,10 +1374,10 @@
                     stat = 'G'
                 pfx = ''
                 if self.ui.verbose:
-                    pfx = '%d %s ' % (i, stat)
+                    pfx = '%*d %s ' % (idxwidth, i, stat)
                 elif status and status != stat:
                     continue
-                self.ui.write('%s%s\n' % (pfx, displayname(patch)))
+                displayname(pfx, patch)
         else:
             msng_list = []
             for root, dirs, files in os.walk(self.path):
@@ -1384,7 +1391,7 @@
                         msng_list.append(fl)
             for x in sorted(msng_list):
                 pfx = self.ui.verbose and ('D ') or ''
-                self.ui.write("%s%s\n" % (pfx, displayname(x)))
+                displayname(pfx, x)
 
     def issaveline(self, l):
         if l.name == '.hg.patches.save.line':
@@ -1537,7 +1544,7 @@
                 raise util.Abort(_('option "-r" not valid when importing '
                                    'files'))
             rev = cmdutil.revrange(repo, rev)
-            rev.sort(lambda x, y: cmp(y, x))
+            rev.sort(reverse=True)
         if (len(files) > 1 or len(rev) > 1) and patchname:
             raise util.Abort(_('option "-n" not valid when importing multiple '
                                'patches'))
@@ -1677,29 +1684,26 @@
 def qimport(ui, repo, *filename, **opts):
     """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
-    to the series.
+    The patch is inserted into the series after the last applied patch. If no
+    patches have been applied, qimport prepends the patch to the series.
 
-    The patch will have the same name as its source file unless you
-    give it a new one with -n/--name.
+    The patch will have the same name as its source file unless you give it a
+    new one with -n/--name.
 
-    You can register an existing patch inside the patch directory with
-    the -e/--existing flag.
+    You can register an existing patch inside the patch directory with the
+    -e/--existing flag.
 
-    With -f/--force, an existing patch of the same name will be
-    overwritten.
+    With -f/--force, an existing patch of the same name will be overwritten.
 
-    An existing changeset may be placed under mq control with -r/--rev
-    (e.g. qimport --rev tip -n patch will place tip under mq control).
-    With -g/--git, patches imported with --rev will use the git diff
-    format. See the diffs help topic for information on why this is
-    important for preserving rename/copy information and permission
-    changes.
+    An existing changeset may be placed under mq control with -r/--rev (e.g.
+    qimport --rev tip -n patch will place tip under mq control). With
+    -g/--git, patches imported with --rev will use the git diff format. See
+    the diffs help topic for information on why this is important for
+    preserving rename/copy information and permission changes.
 
-    To import a patch from standard input, pass - as the patch file.
-    When importing from standard input, a patch name must be specified
-    using the --name flag.
+    To import a patch from standard input, pass - as the patch file. When
+    importing from standard input, a patch name must be specified using the
+    --name flag.
     """
     q = repo.mq
     q.qimport(repo, filename, patchname=opts['name'],
@@ -1714,11 +1718,12 @@
 def init(ui, repo, **opts):
     """init a new queue repository
 
-    The queue repository is unversioned by default. If
-    -c/--create-repo is specified, qinit will create a separate nested
-    repository for patches (qinit -c may also be run later to convert
-    an unversioned patch repository into a versioned one). You can use
-    qcommit to commit changes to this queue repository."""
+    The queue repository is unversioned by default. If -c/--create-repo is
+    specified, qinit will create a separate nested repository for patches
+    (qinit -c may also be run later to convert an unversioned patch repository
+    into a versioned one). You can use qcommit to commit changes to this queue
+    repository.
+    """
     q = repo.mq
     r = q.init(repo, create=opts['create_repo'])
     q.save_dirty()
@@ -1740,17 +1745,16 @@
 def clone(ui, source, dest=None, **opts):
     '''clone main and patch repository at same time
 
-    If source is local, destination will have no patches applied. If
-    source is remote, this command can not check if patches are
-    applied in source, so cannot guarantee that patches are not
-    applied in destination. If you clone remote repository, be sure
-    before that it has no patches applied.
+    If source is local, destination will have no patches applied. If source is
+    remote, this command can not check if patches are applied in source, so
+    cannot guarantee that patches are not applied in destination. If you clone
+    remote repository, be sure before that it has no patches applied.
 
-    Source patch repository is looked for in <src>/.hg/patches by
-    default. Use -p <url> to change.
+    Source patch repository is looked for in <src>/.hg/patches by default. Use
+    -p <url> to change.
 
-    The patch directory must be a nested Mercurial repository, as
-    would be created by qinit -c.
+    The patch directory must be a nested Mercurial repository, as would be
+    created by qinit -c.
     '''
     def patchdir(repo):
         url = repo.url()
@@ -1847,7 +1851,7 @@
                      summary=opts.get('summary'))
 
 def setupheaderopts(ui, opts):
-    def do(opt,val):
+    def do(opt, val):
         if not opts[opt] and opts['current' + opt]:
             opts[opt] = val
     do('user', ui.username())
@@ -1856,26 +1860,24 @@
 def new(ui, repo, patch, *args, **opts):
     """create a new patch
 
-    qnew creates a new patch on top of the currently-applied patch (if
-    any). It will refuse to run if there are any outstanding changes
-    unless -f/--force is specified, in which case the patch will be
-    initialized with them. You may also use -I/--include,
-    -X/--exclude, and/or a list of files after the patch name to add
-    only changes to matching files to the new patch, leaving the rest
-    as uncommitted modifications.
+    qnew creates a new patch on top of the currently-applied patch (if any).
+    It will refuse to run if there are any outstanding changes unless
+    -f/--force is specified, in which case the patch will be initialized with
+    them. You may also use -I/--include, -X/--exclude, and/or a list of files
+    after the patch name to add only changes to matching files to the new
+    patch, leaving the rest as uncommitted modifications.
 
-    -u/--user and -d/--date can be used to set the (given) user and
-    date, respectively. -U/--currentuser and -D/--currentdate set user
-    to current user and date to current date.
+    -u/--user and -d/--date can be used to set the (given) user and date,
+    respectively. -U/--currentuser and -D/--currentdate set user to current
+    user and date to current date.
 
-    -e/--edit, -m/--message or -l/--logfile set the patch header as
-    well as the commit message. If none is specified, the header is
-    empty and the commit message is '[mq]: PATCH'.
+    -e/--edit, -m/--message or -l/--logfile set the patch header as well as
+    the commit message. If none is specified, the header is empty and the
+    commit message is '[mq]: PATCH'.
 
-    Use the -g/--git option to keep the patch in the git extended diff
-    format. Read the diffs help topic for more information on why this
-    is important for preserving permission changes and copy/rename
-    information.
+    Use the -g/--git option to keep the patch in the git extended diff format.
+    Read the diffs help topic for more information on why this is important
+    for preserving permission changes and copy/rename information.
     """
     msg = cmdutil.logmessage(opts)
     def getmsg(): return ui.edit(msg, ui.username())
@@ -1893,17 +1895,16 @@
 def refresh(ui, repo, *pats, **opts):
     """update the current patch
 
-    If any file patterns are provided, the refreshed patch will
-    contain only the modifications that match those patterns; the
-    remaining modifications will remain in the working directory.
+    If any file patterns are provided, the refreshed patch will contain only
+    the modifications that match those patterns; the remaining modifications
+    will remain in the working directory.
 
-    If -s/--short is specified, files currently included in the patch
-    will be refreshed just like matched files and remain in the patch.
+    If -s/--short is specified, files currently included in the patch will be
+    refreshed just like matched files and remain in the patch.
 
-    hg add/remove/copy/rename work as usual, though you might want to
-    use git-style patches (-g/--git or [diff] git=1) to track copies
-    and renames. See the diffs help topic for more information on the
-    git diff format.
+    hg add/remove/copy/rename work as usual, though you might want to use
+    git-style patches (-g/--git or [diff] git=1) to track copies and renames.
+    See the diffs help topic for more information on the git diff format.
     """
     q = repo.mq
     message = cmdutil.logmessage(opts)
@@ -1924,15 +1925,13 @@
 def diff(ui, repo, *pats, **opts):
     """diff of the current patch and subsequent modifications
 
-    Shows a diff which includes the current patch as well as any
-    changes which have been made in the working directory since the
-    last refresh (thus showing what the current patch would become
-    after a qrefresh).
+    Shows a diff which includes the current patch as well as any changes which
+    have been made in the working directory since the last refresh (thus
+    showing what the current patch would become after a qrefresh).
 
-    Use 'hg diff' if you only want to see the changes made since the
-    last qrefresh, or 'hg export qtip' if you want to see changes made
-    by the current patch without including changes made since the
-    qrefresh.
+    Use 'hg diff' if you only want to see the changes made since the last
+    qrefresh, or 'hg export qtip' if you want to see changes made by the
+    current patch without including changes made since the qrefresh.
     """
     repo.mq.diff(repo, pats, opts)
     return 0
@@ -1940,15 +1939,15 @@
 def fold(ui, repo, *files, **opts):
     """fold the named patches into the current patch
 
-    Patches must not yet be applied. Each patch will be successively
-    applied to the current patch in the order given. If all the
-    patches apply successfully, the current patch will be refreshed
-    with the new cumulative patch, and the folded patches will be
-    deleted. With -k/--keep, the folded patch files will not be
-    removed afterwards.
+    Patches must not yet be applied. Each patch will be successively applied
+    to the current patch in the order given. If all the patches apply
+    successfully, the current patch will be refreshed with the new cumulative
+    patch, and the folded patches will be deleted. With -k/--keep, the folded
+    patch files will not be removed afterwards.
 
-    The header for each folded patch will be concatenated with the
-    current patch header, separated by a line of '* * *'."""
+    The header for each folded patch will be concatenated with the current
+    patch header, separated by a line of '* * *'.
+    """
 
     q = repo.mq
 
@@ -2014,14 +2013,13 @@
 def guard(ui, repo, *args, **opts):
     '''set or print guards for a patch
 
-    Guards control whether a patch can be pushed. A patch with no
-    guards is always pushed. A patch with a positive guard ("+foo") is
-    pushed only if the qselect command has activated it. A patch with
-    a negative guard ("-foo") is never pushed if the qselect command
-    has activated it.
+    Guards control whether a patch can be pushed. A patch with no guards is
+    always pushed. A patch with a positive guard ("+foo") is pushed only if
+    the qselect command has activated it. A patch with a negative guard
+    ("-foo") is never pushed if the qselect command has activated it.
 
-    With no arguments, print the currently active guards.
-    With arguments, set guards for the named patch.
+    With no arguments, print the currently active guards. With arguments, set
+    guards for the named patch.
     NOTE: Specifying negative guards now requires '--'.
 
     To set guards on another patch:
@@ -2098,8 +2096,8 @@
 def push(ui, repo, patch=None, **opts):
     """push the next patch onto the stack
 
-    When -f/--force is applied, all local changes in patched files
-    will be lost.
+    When -f/--force is applied, all local changes in patched files will be
+    lost.
     """
     q = repo.mq
     mergeq = None
@@ -2121,9 +2119,9 @@
 def pop(ui, repo, patch=None, **opts):
     """pop the current patch off the stack
 
-    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.
+    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.
     """
     localupdate = True
     if opts['name']:
@@ -2240,8 +2238,7 @@
     """strip a revision and all its descendants from the repository
 
     If one of the working directory's parent revisions is stripped, the
-    working directory will be updated to the parent of the stripped
-    revision.
+    working directory will be updated to the parent of the stripped revision.
     """
     backup = 'all'
     if opts['backup']:
@@ -2266,35 +2263,33 @@
 def select(ui, repo, *args, **opts):
     '''set or print guarded patches to push
 
-    Use the qguard command to set or print guards on patch, then use
-    qselect to tell mq which guards to use. A patch will be pushed if
-    it has no guards or any positive guards match the currently
-    selected guard, but will not be pushed if any negative guards
-    match the current guard. For example:
+    Use the qguard command to set or print guards on patch, then use qselect
+    to tell mq which guards to use. A patch will be pushed if it has no guards
+    or any positive guards match the currently selected guard, but will not be
+    pushed if any negative guards match the current guard. For example:
 
         qguard foo.patch -stable    (negative guard)
         qguard bar.patch +stable    (positive guard)
         qselect stable
 
-    This activates the "stable" guard. mq will skip foo.patch (because
-    it has a negative match) but push bar.patch (because it has a
-    positive match).
+    This activates the "stable" guard. mq will skip foo.patch (because it has
+    a negative match) but push bar.patch (because it has a positive match).
 
-    With no arguments, prints the currently active guards.
-    With one argument, sets the active guard.
+    With no arguments, prints the currently active guards. With one argument,
+    sets the active guard.
 
-    Use -n/--none to deactivate guards (no other arguments needed).
-    When no guards are active, patches with positive guards are
-    skipped and patches with negative guards are pushed.
+    Use -n/--none to deactivate guards (no other arguments needed). When no
+    guards are active, patches with positive guards are skipped and patches
+    with negative guards are pushed.
 
-    qselect can change the guards on applied patches. It does not pop
-    guarded patches by default. Use --pop to pop back to the last
-    applied patch that is not guarded. Use --reapply (which implies
-    --pop) to push back to the current patch afterwards, but skip
-    guarded patches.
+    qselect can change the guards on applied patches. It does not pop guarded
+    patches by default. Use --pop to pop back to the last applied patch that
+    is not guarded. Use --reapply (which implies --pop) to push back to the
+    current patch afterwards, but skip guarded patches.
 
-    Use -s/--series to print a list of all guards in the series file
-    (no other arguments needed). Use -v for more information.'''
+    Use -s/--series to print a list of all guards in the series file (no other
+    arguments needed). Use -v for more information.
+    '''
 
     q = repo.mq
     guards = q.active()
@@ -2330,7 +2325,7 @@
         if ui.verbose:
             guards['NONE'] = noguards
         guards = guards.items()
-        guards.sort(lambda a, b: cmp(a[0][1:], b[0][1:]))
+        guards.sort(key=lambda x: x[0][1:])
         if guards:
             ui.note(_('guards in series file:\n'))
             for guard, count in guards:
@@ -2369,18 +2364,16 @@
 def finish(ui, repo, *revrange, **opts):
     """move applied patches into repository history
 
-    Finishes the specified revisions (corresponding to applied
-    patches) by moving them out of mq control into regular repository
-    history.
+    Finishes the specified revisions (corresponding to applied patches) by
+    moving them out of mq control into regular repository history.
 
-    Accepts a revision range or the -a/--applied option. If --applied
-    is specified, all applied mq revisions are removed from mq
-    control. Otherwise, the given revisions must be at the base of the
-    stack of applied patches.
+    Accepts a revision range or the -a/--applied option. If --applied is
+    specified, all applied mq revisions are removed from mq control.
+    Otherwise, the given revisions must be at the base of the stack of applied
+    patches.
 
-    This can be especially useful if your changes have been applied to
-    an upstream repository, or if you are about to push your changes
-    to upstream.
+    This can be especially useful if your changes have been applied to an
+    upstream repository, or if you are about to push your changes to upstream.
     """
     if not opts['applied'] and not revrange:
         raise util.Abort(_('no revisions specified'))
@@ -2423,34 +2416,33 @@
                 raise util.Abort(_('source has mq patches applied'))
             return super(mqrepo, self).push(remote, force, revs)
 
-        def tags(self):
-            if self.tagscache:
-                return self.tagscache
-
-            tagscache = super(mqrepo, self).tags()
+        def _findtags(self):
+            '''augment tags from base class with patch tags'''
+            result = super(mqrepo, self)._findtags()
 
             q = self.mq
             if not q.applied:
-                return tagscache
+                return result
 
             mqtags = [(bin(patch.rev), patch.name) for patch in q.applied]
 
             if mqtags[-1][0] not in self.changelog.nodemap:
                 self.ui.warn(_('mq status file refers to unknown node %s\n')
                              % short(mqtags[-1][0]))
-                return tagscache
+                return result
 
             mqtags.append((mqtags[-1][0], 'qtip'))
             mqtags.append((mqtags[0][0], 'qbase'))
             mqtags.append((self.changelog.parents(mqtags[0][0])[0], 'qparent'))
+            tags = result[0]
             for patch in mqtags:
-                if patch[1] in tagscache:
+                if patch[1] in tags:
                     self.ui.warn(_('Tag %s overrides mq patch of the same name\n')
                                  % patch[1])
                 else:
-                    tagscache[patch[1]] = patch[0]
+                    tags[patch[1]] = patch[0]
 
-            return tagscache
+            return result
 
         def _branchtags(self, partial, lrev):
             q = self.mq