Commits

Jason Harris committed f12e51d

- Upgrade to Mercurial 1.5.4

Comments (0)

Files changed (464)

LocalMercurial/hgext/acl.py

 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
-#
+# GNU General Public License version 2 or any later version.
 
 '''hooks for controlling repository access
 
 To use this hook, configure the acl extension in your hgrc like this::
 
   [extensions]
-  hgext.acl =
+  acl =
 
   [hooks]
   pretxnchangegroup.acl = python:hgext.acl.hook
         return None
 
     pats = [pat for pat, users in ui.configitems(key)
-            if user in users.replace(',', ' ').split()]
+            if users == '*' or user in users.replace(',', ' ').split()]
     ui.debug('acl: %s enabled, %d entries for user %s\n' %
              (key, len(pats), user))
     if pats:

LocalMercurial/hgext/acl.pyc

Binary file modified.

LocalMercurial/hgext/acl.pyo

Binary file modified.

LocalMercurial/hgext/bookmarks.py

 # Copyright 2008 David Soria Parra <dsp@php.net>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 '''track a line of development with movable markers
 
 
 from mercurial.i18n import _
 from mercurial.node import nullid, nullrev, hex, short
-from mercurial import util, commands, localrepo, repair, extensions
+from mercurial import util, commands, repair, extensions
 import os
 
-def parse(repo):
-    '''Parse .hg/bookmarks file and return a dictionary
-
-    Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
-    in the .hg/bookmarks file. They are read by the parse() method and
-    returned as a dictionary with name => hash values.
-
-    The parsed dictionary is cached until a write() operation is done.
-    '''
-    try:
-        if repo._bookmarks:
-            return repo._bookmarks
-        repo._bookmarks = {}
-        for line in repo.opener('bookmarks'):
-            sha, refspec = line.strip().split(' ', 1)
-            repo._bookmarks[refspec] = repo.lookup(sha)
-    except:
-        pass
-    return repo._bookmarks
-
-def write(repo, refs):
+def write(repo):
     '''Write bookmarks
 
     Write the given bookmark => hash dictionary to the .hg/bookmarks file
     We also store a backup of the previous state in undo.bookmarks that
     can be copied back on rollback.
     '''
+    refs = repo._bookmarks
     if os.path.exists(repo.join('bookmarks')):
         util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks'))
-    if current(repo) not in refs:
+    if repo._bookmarkcurrent not in refs:
         setcurrent(repo, None)
     wlock = repo.wlock()
     try:
     finally:
         wlock.release()
 
-def current(repo):
-    '''Get the current bookmark
-
-    If we use gittishsh branches we have a current bookmark that
-    we are on. This function returns the name of the bookmark. It
-    is stored in .hg/bookmarks.current
-    '''
-    if repo._bookmarkcurrent:
-        return repo._bookmarkcurrent
-    mark = None
-    if os.path.exists(repo.join('bookmarks.current')):
-        file = repo.opener('bookmarks.current')
-        # No readline() in posixfile_nt, reading everything is cheap
-        mark = (file.readlines() or [''])[0]
-        if mark == '':
-            mark = None
-        file.close()
-    repo._bookmarkcurrent = mark
-    return mark
-
 def setcurrent(repo, mark):
     '''Set the name of the bookmark that we are currently on
 
     Set the name of the bookmark that we are on (hg update <bookmark>).
     The name is recorded in .hg/bookmarks.current
     '''
-    if current(repo) == mark:
+    current = repo._bookmarkcurrent
+    if current == mark:
         return
 
-    refs = parse(repo)
+    refs = repo._bookmarks
 
     # do not update if we do update to a rev equal to the current bookmark
     if (mark and mark not in refs and
-        current(repo) and refs[current(repo)] == repo.changectx('.').node()):
+        current and refs[current] == repo.changectx('.').node()):
         return
     if mark not in refs:
         mark = ''
     the bookmark is assigned to that revision.
     '''
     hexfn = ui.debugflag and hex or short
-    marks = parse(repo)
+    marks = repo._bookmarks
     cur   = repo.changectx('.').node()
 
     if rename:
             raise util.Abort(_("new bookmark name required"))
         marks[mark] = marks[rename]
         del marks[rename]
-        if current(repo) == rename:
+        if repo._bookmarkcurrent == rename:
             setcurrent(repo, mark)
-        write(repo, marks)
+        write(repo)
         return
 
     if delete:
             raise util.Abort(_("bookmark name required"))
         if mark not in marks:
             raise util.Abort(_("a bookmark of this name does not exist"))
-        if mark == current(repo):
+        if mark == repo._bookmarkcurrent:
             setcurrent(repo, None)
         del marks[mark]
-        write(repo, marks)
+        write(repo)
         return
 
     if mark != None:
         else:
             marks[mark] = repo.changectx('.').node()
             setcurrent(repo, mark)
-        write(repo, marks)
+        write(repo)
         return
 
     if mark is None:
         if rev:
             raise util.Abort(_("bookmark name required"))
         if len(marks) == 0:
-            ui.status("no bookmarks set\n")
+            ui.status(_("no bookmarks set\n"))
         else:
             for bmark, n in marks.iteritems():
                 if ui.configbool('bookmarks', 'track.current'):
-                    prefix = (bmark == current(repo) and n == cur) and '*' or ' '
+                    current = repo._bookmarkcurrent
+                    prefix = (bmark == current and n == cur) and '*' or ' '
                 else:
                     prefix = (n == cur) and '*' or ' '
 
     the mercurial.strip method. This usually happens during
     qpush and qpop"""
     revisions = _revstostrip(repo.changelog, node)
-    marks = parse(repo)
+    marks = repo._bookmarks
     update = []
     for mark, n in marks.iteritems():
         if repo.changelog.rev(n) in revisions:
     if len(update) > 0:
         for m in update:
             marks[m] = repo.changectx('.').node()
-        write(repo, marks)
+        write(repo)
 
 def reposetup(ui, repo):
     if not repo.local():
         return
 
-    # init a bookmark cache as otherwise we would get a infinite reading
-    # in lookup()
-    repo._bookmarks = None
-    repo._bookmarkcurrent = None
+    class bookmark_repo(repo.__class__):
 
-    class bookmark_repo(repo.__class__):
+        @util.propertycache
+        def _bookmarks(self):
+            '''Parse .hg/bookmarks file and return a dictionary
+
+            Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values
+            in the .hg/bookmarks file. They are read returned as a dictionary
+            with name => hash values.
+            '''
+            try:
+                bookmarks = {}
+                for line in self.opener('bookmarks'):
+                    sha, refspec = line.strip().split(' ', 1)
+                    bookmarks[refspec] = super(bookmark_repo, self).lookup(sha)
+            except:
+                pass
+            return bookmarks
+
+        @util.propertycache
+        def _bookmarkcurrent(self):
+            '''Get the current bookmark
+
+            If we use gittishsh branches we have a current bookmark that
+            we are on. This function returns the name of the bookmark. It
+            is stored in .hg/bookmarks.current
+            '''
+            mark = None
+            if os.path.exists(self.join('bookmarks.current')):
+                file = self.opener('bookmarks.current')
+                # No readline() in posixfile_nt, reading everything is cheap
+                mark = (file.readlines() or [''])[0]
+                if mark == '':
+                    mark = None
+                file.close()
+            return mark
+
         def rollback(self):
             if os.path.exists(self.join('undo.bookmarks')):
                 util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
             return super(bookmark_repo, self).rollback()
 
         def lookup(self, key):
-            if self._bookmarks is None:
-                self._bookmarks = parse(self)
             if key in self._bookmarks:
                 key = self._bookmarks[key]
             return super(bookmark_repo, self).lookup(key)
 
+        def _bookmarksupdate(self, parents, node):
+            marks = self._bookmarks
+            update = False
+            if ui.configbool('bookmarks', 'track.current'):
+                mark = self._bookmarkcurrent
+                if mark and marks[mark] in parents:
+                    marks[mark] = node
+                    update = True
+            else:
+                for mark, n in marks.items():
+                    if n in parents:
+                        marks[mark] = node
+                        update = True
+            if update:
+                write(self)
+
         def commitctx(self, ctx, error=False):
             """Add a revision to the repository and
             move the bookmark"""
                 parents = self.changelog.parents(node)
                 if parents[1] == nullid:
                     parents = (parents[0],)
-                marks = parse(self)
-                update = False
-                if ui.configbool('bookmarks', 'track.current'):
-                    mark = current(self)
-                    if mark and marks[mark] in parents:
-                        marks[mark] = node
-                        update = True
-                else:
-                    for mark, n in marks.items():
-                        if n in parents:
-                            marks[mark] = node
-                            update = True
-                if update:
-                    write(self, marks)
+
+                self._bookmarksupdate(parents, node)
                 return node
             finally:
                 wlock.release()
                 # We have more heads than before
                 return result
             node = self.changelog.tip()
-            marks = parse(self)
-            update = False
-            if ui.configbool('bookmarks', 'track.current'):
-                mark = current(self)
-                if mark and marks[mark] in parents:
-                    marks[mark] = node
-                    update = True
-            else:
-                for mark, n in marks.items():
-                    if n in parents:
-                        marks[mark] = node
-                        update = True
-            if update:
-                write(self, marks)
+
+            self._bookmarksupdate(parents, node)
             return result
 
         def _findtags(self):
             """Merge bookmarks with normal tags"""
             (tags, tagtypes) = super(bookmark_repo, self)._findtags()
-            tags.update(parse(self))
+            tags.update(self._bookmarks)
             return (tags, tagtypes)
 
+        if hasattr(repo, 'invalidate'):
+            def invalidate(self):
+                super(bookmark_repo, self).invalidate()
+                for attr in ('_bookmarks', '_bookmarkcurrent'):
+                    if attr in self.__dict__:
+                        delattr(repo, attr)
+
     repo.__class__ = bookmark_repo
 
 def uisetup(ui):

LocalMercurial/hgext/bookmarks.pyc

Binary file modified.

LocalMercurial/hgext/bookmarks.pyo

Binary file modified.

LocalMercurial/hgext/bugzilla.py

 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 '''hooks for integrating with the Bugzilla bug tracker
 
 Activating the extension::
 
     [extensions]
-    hgext.bugzilla =
+    bugzilla =
 
     [hooks]
     # run bugzilla hook on every change pulled or pushed in here
 
     def __init__(self, ui):
         bugzilla_2_16.__init__(self, ui)
-        self.default_notify = "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s"
+        self.default_notify = \
+            "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s"
 
 class bugzilla_3_0(bugzilla_2_18):
     '''support for bugzilla 3.0 series.'''
                 break
             start = m.end()
             for id in bugzilla._split_re.split(m.group(1)):
-                if not id: continue
+                if not id:
+                    continue
                 ids.add(int(id))
         if ids:
             ids = self.filter_real_bug_ids(ids)
                 c = root.find('/')
                 if c == -1:
                     break
-                root = root[c+1:]
+                root = root[c + 1:]
                 count -= 1
             return root
 

LocalMercurial/hgext/bugzilla.pyc

Binary file modified.

LocalMercurial/hgext/bugzilla.pyo

Binary file modified.

LocalMercurial/hgext/children.py

 # Thomas Arendsen Hein <thomas@intevation.de>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 '''command to display child changesets'''
 
     displayer = cmdutil.show_changeset(ui, repo, opts)
     for cctx in ctx.children():
         displayer.show(cctx)
-
+    displayer.close()
 
 cmdtable = {
     "children":

LocalMercurial/hgext/children.pyc

Binary file modified.

LocalMercurial/hgext/children.pyo

Binary file modified.

LocalMercurial/hgext/churn.py

 # Copyright 2008 Alexander Solovyov <piranha@piranha.org.ua>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 '''command to display statistics about repository history'''
 
                                     '*' * charnum(sum(count)))
 
     def charnum(count):
-        return int(round(count*width/maxcount))
+        return int(round(count * width / maxcount))
 
     for name, count in rate:
         ui.write(format(name, count))
         (churn,
          [('r', 'rev', [], _('count rate for the specified revision or range')),
           ('d', 'date', '', _('count rate for revisions matching date spec')),
-          ('t', 'template', '{author|email}', _('template to group changesets')),
+          ('t', 'template', '{author|email}',
+           _('template to group changesets')),
           ('f', 'dateformat', '',
               _('strftime-compatible format for grouping by date')),
           ('c', 'changesets', False, _('count rate by number of changesets')),

LocalMercurial/hgext/churn.pyc

Binary file modified.

LocalMercurial/hgext/churn.pyo

Binary file modified.

LocalMercurial/hgext/collapse.py

-# collapse.py - collapse feature for mercurial
-#
-# Copyright 2009 Colin Caughie <c.caughie at indigovision dot com>
-#
-# This software may be used and distributed according to the terms
-# of the GNU General Public License, incorporated herein by reference.
-
-'''collapse multiple revisions into one
-'''
-
-from mercurial import util, repair, merge, cmdutil, commands
-from mercurial.node import nullrev
-from mercurial.i18n import _
-import re
-
-def collapse(ui, repo, **opts):
-    """collapse multiple revisions into one
-
-    Collapse combines multiple consecutive changesets into a single changeset,
-    preserving any descendants of the final changeset. The commit messages for
-    the collapsed changesets are concatenated and may be edited before the
-    collapse is completed.
-    """
-
-    rng = cmdutil.revrange(repo, opts['rev'])
-    if not rng:
-        raise util.Abort(_('no revisions specified'))
-
-    first = rng[0]
-    last = rng[-1]
-    revs = inbetween(repo, first, last)
-
-    if not revs:
-        raise util.Abort(_('revision %s is not an ancestor of revision %s\n') %
-                            (first, last))
-    elif len(revs) == 1:
-        raise util.Abort(_('only one revision specified'))
-
-    ui.debug(_('Collapsing revisions %s\n') % revs)
-
-    for r in revs:
-        if repo[r].user() != ui.username() and not opts['force']:
-            raise util.Abort(_('revision %s does not belong to %s\n') %
-                (r, ui.username()))
-        if r != last:
-            children = repo[r].children()
-            if len(children) > 1:
-                for c in children:
-                    if not c.rev() in revs:
-                        raise util.Abort(_('revision %s has child %s not '
-                            'being collapsed, please rebase\n') % (r, c.rev()))
-        if r != first:
-            parents = repo[r].parents()
-            if len(parents) > 1:
-                for p in parents:
-                    if not p.rev() in revs:
-                        raise util.Abort(_('revision %s has parent %s not '
-                            'being collapsed.') % (r, p.rev()))
-
-    if len(repo[first].parents()) > 1:
-        raise util.Abort(_('start revision %s has multiple parents, '
-            'won\'t collapse.') % first)
-
-    cmdutil.bail_if_changed(repo)
-
-    parent = repo[first].parents()[0]
-    tomove = list(repo.changelog.descendants(last))
-    movemap = dict.fromkeys(tomove, nullrev)
-    ui.debug(_('will move revisions: %s\n') % tomove)
-
-    origparent = repo['.'].rev()
-    collapsed = None
-
-    try:
-        collapsed = makecollapsed(ui, repo, parent, revs, opts)
-        movemap[max(revs)] = collapsed
-        movedescendants(ui, repo, collapsed, tomove, movemap)
-    except:
-        merge.update(repo, repo[origparent].rev(), False, True, False)
-        if collapsed:
-            repair.strip(ui, repo, collapsed.node(), "strip")
-        raise
-
-    if not opts['keep']:
-        ui.debug(_('stripping revision %d\n') % first)
-        repair.strip(ui, repo, repo[first].node(), "strip")
-
-    ui.status(_('collapse completed\n'))
-
-def makecollapsed(ui, repo, parent, revs, opts):
-    'Creates the collapsed revision on top of parent'
-
-    last = max(revs)
-    ui.debug(_('updating to revision %d\n') % parent)
-    merge.update(repo, parent.node(), False, False, False)
-    ui.debug(_('reverting to revision %d\n') % last)
-    commands.revert(ui, repo, rev=last, all=True, date=None)
-    msg = ''
-    if opts['message'] != "" :
-        msg = opts['message']
-    else:
-        first = True
-        for r in revs:
-            if not first:
-                msg += '----------------\n'
-            first = False
-            msg += repo[r].description() + "\n"
-
-        msg += "\nHG: Enter commit message.  Lines beginning with 'HG:' are removed.\n"
-        msg += "HG: Remove all lines to abort the collapse operation.\n"
-
-        if ui.config('ui', 'interactive') != 'off':
-            msg = ui.edit(msg, ui.username())
-
-        pattern = re.compile("^HG:.*\n", re.MULTILINE);
-        msg  = re.sub(pattern, "", msg).strip();
-
-    if not msg:
-        raise util.Abort(_('empty commit message, collapse won\'t proceed'))
-
-    newrev = repo.commit(
-        text=msg,
-        user=repo[last].user(),
-        date=repo[last].date())
-
-    return repo[newrev]
-
-def movedescendants(ui, repo, collapsed, tomove, movemap):
-    'Moves the descendants of the source revisions to the collapsed revision'
-
-    sorted_tomove = list(tomove)
-    sorted_tomove.sort()
-
-    for r in sorted_tomove:
-        ui.debug(_('moving revision %r\n') % r)
-        parents = [p.rev() for p in repo[r].parents()]
-        if len(parents) == 1:
-            ui.debug(_('setting parent to %d\n') % movemap[parents[0]].rev())
-            repo.dirstate.setparents(movemap[parents[0]].node())
-        else:
-            ui.debug(_('setting parents to %d and %d\n') %
-                (movemap[parents[0]].rev(), movemap[parents[1]].rev()))
-            repo.dirstate.setparents(movemap[parents[0]].node(),
-                movemap[parents[1]].node())
-
-        repo.dirstate.write()
-
-        ui.debug(_('reverting to revision %d\n') % r)
-        commands.revert(ui, repo, rev=r, all=True, date=None)
-        newrev = repo.commit(text=repo[r].description(), user=repo[r].user(),
-                            date=repo[r].date())
-        ctx = repo[newrev]
-        movemap[r] = ctx
-
-def inbetween(repo, first, last):
-    'Return all revisions between first and last, inclusive'
-
-    if first == last:
-        return set([first])
-    elif last < first:
-        return set()
-
-    parents = [p.rev() for p in repo[last].parents()]
-
-    if not parents:
-        return set()
-
-    result = inbetween(repo, first, parents[0])
-    if len(parents) == 2:
-        result = result | inbetween(repo, first, parents[1])
-
-    if result:
-        result.add(last)
-
-    return result
-
-cmdtable = {
-"collapse":
-        (collapse,
-        [
-        ('r', 'rev', [], _('revisions to collapse')),
-        ('', 'keep', False, _('keep original revisions')),
-        ('f', 'force', False, _('force collapse of changes from different users')),
-        ('m', 'message', "", _('use <text> as combined commit message'))
-        ],
-        _('hg collapse -r REVS [--keep | --keepbranches]')),
-}

LocalMercurial/hgext/color.py

 
 '''colorize output from some commands
 
-This extension modifies the status command to add color to its output
-to reflect file status, the qseries command to add color to reflect
+This extension modifies the status and resolve commands to add color to their
+output to reflect file status, the qseries command to add color to reflect
 patch status (applied, unapplied, missing), and to diff-related
 commands to highlight additions, removals, diff headers, and trailing
 whitespace.
   diff.inserted = green
   diff.changed = white
   diff.trailingwhitespace = bold red_background
+
+  resolve.unresolved = red bold
+  resolve.resolved = green bold
+
+  bookmarks.current = green
 '''
 
 import os, sys
 
-from mercurial import cmdutil, commands, extensions, error
+from mercurial import cmdutil, commands, extensions
 from mercurial.i18n import _
 
 # start and stop parameters for effects
     stop = '\033[' + str(_effect_params['none']) + 'm'
     return ''.join([start, text, stop])
 
-def colorstatus(orig, ui, repo, *pats, **opts):
-    '''run the status command with colored output'''
-
-    delimiter = opts['print0'] and '\0' or '\n'
+def _colorstatuslike(abbreviations, effectdefs, orig, ui, repo, *pats, **opts):
+    '''run a status-like command with colorized output'''
+    delimiter = opts.get('print0') and '\0' or '\n'
 
     nostatus = opts.get('no_status')
     opts['no_status'] = False
-    # run status and capture its output
+    # run original command and capture its output
     ui.pushbuffer()
     retval = orig(ui, repo, *pats, **opts)
     # filter out empty strings
-    lines_with_status = [ line for line in ui.popbuffer().split(delimiter) if line ]
+    lines_with_status = [line for line in ui.popbuffer().split(delimiter) if line]
 
     if nostatus:
         lines = [l[2:] for l in lines_with_status]
 
     # apply color to output and display it
     for i in xrange(len(lines)):
-        status = _status_abbreviations[lines_with_status[i][0]]
-        effects = _status_effects[status]
-        if effects:
-            lines[i] = render_effects(lines[i], effects)
+        try:
+            status = abbreviations[lines_with_status[i][0]]
+        except KeyError:
+            # Ignore lines with invalid codes, especially in the case of
+            # of unknown filenames containing newlines (issue2036).
+            pass
+        else:
+            effects = effectdefs[status]
+            if effects:
+                lines[i] = render_effects(lines[i], effects)
         ui.write(lines[i] + delimiter)
     return retval
 
+
 _status_abbreviations = { 'M': 'modified',
                           'A': 'added',
                           'R': 'removed',
                     'clean': ['none'],
                     'copied': ['none'], }
 
+def colorstatus(orig, ui, repo, *pats, **opts):
+    '''run the status command with colored output'''
+    return _colorstatuslike(_status_abbreviations, _status_effects,
+                            orig, ui, repo, *pats, **opts)
+
+
+_resolve_abbreviations = { 'U': 'unresolved',
+                           'R': 'resolved', }
+
+_resolve_effects = { 'unresolved': ['red', 'bold'],
+                     'resolved': ['green', 'bold'], }
+
+def colorresolve(orig, ui, repo, *pats, **opts):
+    '''run the resolve command with colored output'''
+    if not opts.get('list'):
+        # only colorize for resolve -l
+        return orig(ui, repo, *pats, **opts)
+    return _colorstatuslike(_resolve_abbreviations, _resolve_effects,
+                            orig, ui, repo, *pats, **opts)
+
+
+_bookmark_effects = { 'current': ['green'] }
+
+def colorbookmarks(orig, ui, repo, *pats, **opts):
+    def colorize(orig, s):
+        lines = s.split('\n')
+        for i, line in enumerate(lines):
+            if line.startswith(" *"):
+                lines[i] = render_effects(line, _bookmark_effects['current'])
+        orig('\n'.join(lines))
+    oldwrite = extensions.wrapfunction(ui, 'write', colorize)
+    try:
+        orig(ui, repo, *pats, **opts)
+    finally:
+        ui.write = oldwrite
+
 def colorqseries(orig, ui, repo, *dummy, **opts):
     '''run the qseries command with colored output'''
     ui.pushbuffer()
         if opts['missing']:
             effects = _patch_effects['missing']
         # Determine if patch is applied.
-        elif [ applied for applied in repo.mq.applied
-               if patchname == applied.name ]:
+        elif [applied for applied in repo.mq.applied
+               if patchname == applied.name]:
             effects = _patch_effects['applied']
         else:
             effects = _patch_effects['unapplied']
     finally:
         ui.write = oldwrite
 
+def colorchurn(orig, ui, repo, *pats, **opts):
+    '''run the churn command with colored output'''
+    if not opts.get('diffstat'):
+        return orig(ui, repo, *pats, **opts)
+    oldwrite = extensions.wrapfunction(ui, 'write', colordiffstat)
+    try:
+        orig(ui, repo, *pats, **opts)
+    finally:
+        ui.write = oldwrite
+
 _diff_prefixes = [('diff', 'diffline'),
                   ('copy', 'extended'),
                   ('rename', 'extended'),
     _setupcmd(ui, 'outgoing', commands.table, None, _diff_effects)
     _setupcmd(ui, 'tip', commands.table, None, _diff_effects)
     _setupcmd(ui, 'status', commands.table, colorstatus, _status_effects)
+    _setupcmd(ui, 'resolve', commands.table, colorresolve, _resolve_effects)
 
     try:
         mq = extensions.find('mq')
 
     if mq and rec:
         _setupcmd(ui, 'qrecord', rec.cmdtable, colordiff, _diff_effects)
+    try:
+        churn = extensions.find('churn')
+        _setupcmd(ui, 'churn', churn.cmdtable, colorchurn, _diff_effects)
+    except KeyError:
+        churn = None
 
+    try:
+        bookmarks = extensions.find('bookmarks')
+        _setupcmd(ui, 'bookmarks', bookmarks.cmdtable, colorbookmarks,
+                  _bookmark_effects)
+    except KeyError:
+        # The bookmarks extension is not enabled
+        pass
 
 def _setupcmd(ui, cmd, table, func, effectsmap):
     '''patch in command to command table and load effect map'''
+    # check isatty() before anything else changes it (like pager)
+    isatty = sys.__stdout__.isatty()
+
     def nocolor(orig, *args, **opts):
 
         if (opts['no_color'] or opts['color'] == 'never' or
             (opts['color'] == 'auto' and (os.environ.get('TERM') == 'dumb'
-                                          or not sys.__stdout__.isatty()))):
+                                          or not isatty))):
+            del opts['no_color']
+            del opts['color']
             return orig(*args, **opts)
 
         oldshowpatch = extensions.wrapfunction(cmdutil.changeset_printer,
                                                'showpatch', colorshowpatch)
+        del opts['no_color']
+        del opts['color']
         try:
             if func is not None:
                 return func(orig, *args, **opts)

LocalMercurial/hgext/color.pyc

Binary file modified.

LocalMercurial/hgext/color.pyo

Binary file modified.

LocalMercurial/hgext/convert/__init__.py

 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 '''import revisions from foreign VCS repositories into Mercurial'''
 
         matched. If a match occurs, then the conversion process will
         add the most recent revision on the branch indicated in the
         regex as the second parent of the changeset.
+    --config hook.cvslog
+        Specify a Python function to be called at the end of gathering
+        the CVS log. The function is passed a list with the log entries,
+        and can modify the entries in-place, or add or delete them.
+    --config hook.cvschangesets
+        Specify a Python function to be called after the changesets
+        are calculated from the the CVS log. The function is passed
+        a list with the changeset entries, and can modify the changesets
+        in-place, or add or delete them.
 
     An additional "debugcvsps" Mercurial command allows the builtin
     changeset merging code to be run without doing a conversion. Its
           # Main options shared with cvsps-2.1
           ('b', 'branches', [], _('only return changes on specified branches')),
           ('p', 'prefix', '', _('prefix to remove from file names')),
-          ('r', 'revisions', [], _('only return changes after or between specified tags')),
+          ('r', 'revisions', [],
+           _('only return changes after or between specified tags')),
           ('u', 'update-cache', None, _("update cvs log cache")),
           ('x', 'new-cache', None, _("create new cvs log cache")),
           ('z', 'fuzz', 60, _('set commit time fuzz in seconds')),

LocalMercurial/hgext/convert/__init__.pyc

Binary file modified.

LocalMercurial/hgext/convert/__init__.pyo

Binary file modified.

LocalMercurial/hgext/convert/bzr.py

 #  Copyright 2008, 2009 Marek Kubica <marek@xivilization.net> and others
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 # This module is for handling 'bzr', that was formerly known as Bazaar-NG;
 # it cannot access 'bar' repositories, but they were never used very much
 demandimport.ignore.extend([
         'bzrlib.transactions',
         'bzrlib.urlutils',
+        'ElementPath',
     ])
 
 from mercurial.i18n import _
         super(bzr_source, self).__init__(ui, path, rev=rev)
 
         if not os.path.exists(os.path.join(path, '.bzr')):
-            raise NoRepo('%s does not look like a Bazaar repo' % path)
+            raise NoRepo(_('%s does not look like a Bazaar repository')
+                         % path)
 
         try:
             # access bzrlib stuff
             branch
         except NameError:
-            raise NoRepo('Bazaar modules could not be loaded')
+            raise NoRepo(_('Bazaar modules could not be loaded'))
 
         path = os.path.abspath(path)
         self._checkrepotype(path)
         return changes
 
     def _gettreechanges(self, current, origin):
-        revid = current._revision_id;
+        revid = current._revision_id
         changes = []
         renames = {}
         for (fileid, paths, changed_content, versioned, parent, name,
                         changes.append((frompath, revid))
                         changes.append((topath, revid))
                         # add to mode cache
-                        mode = ((entry.executable and 'x') or (entry.kind == 'symlink' and 's')
+                        mode = ((entry.executable and 'x')
+                                or (entry.kind == 'symlink' and 's')
                                 or '')
                         self._modecache[(topath, revid)] = mode
                         # register the change as move

LocalMercurial/hgext/convert/bzr.pyc

Binary file modified.

LocalMercurial/hgext/convert/bzr.pyo

Binary file modified.

LocalMercurial/hgext/convert/common.py

 #  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 import base64, errno
 import os
     s = base64.decodestring(s)
     return pickle.loads(s)
 
-class MissingTool(Exception): pass
+class MissingTool(Exception):
+    pass
 
 def checktool(exe, name=None, abort=True):
     name = name or exe
         exc = abort and util.Abort or MissingTool
         raise exc(_('cannot find required "%s" tool') % name)
 
-class NoRepo(Exception): pass
+class NoRepo(Exception):
+    pass
 
 SKIPREV = 'SKIP'
 
         # Since ARG_MAX is for command line _and_ environment, lower our limit
         # (and make happy Windows shells while doing this).
 
-        self._argmax = self._argmax/2 - 1
+        self._argmax = self._argmax / 2 - 1
         return self._argmax
 
     def limit_arglist(self, arglist, cmd, *args, **kwargs):
             try:
                 key, value = line.splitlines()[0].rsplit(' ', 1)
             except ValueError:
-                raise util.Abort(_('syntax error in %s(%d): key/value pair expected')
-                                 % (self.path, i+1))
+                raise util.Abort(
+                    _('syntax error in %s(%d): key/value pair expected')
+                    % (self.path, i + 1))
             if key not in self:
                 self.order.append(key)
             super(mapfile, self).__setitem__(key, value)

LocalMercurial/hgext/convert/common.pyc

Binary file modified.

LocalMercurial/hgext/convert/common.pyo

Binary file modified.

LocalMercurial/hgext/convert/convcmd.py

 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 from common import NoRepo, MissingTool, SKIPREV, mapfile
 from cvs import convert_cvs
 
 def convertsource(ui, path, type, rev):
     exceptions = []
+    if type and type not in [s[0] for s in source_converters]:
+        raise util.Abort(_('%s: invalid source repository type') % type)
     for name, source, sortmode in source_converters:
         try:
             if not type or name == type:
     raise util.Abort(_('%s: missing or unsupported repository') % path)
 
 def convertsink(ui, path, type):
+    if type and type not in [s[0] for s in sink_converters]:
+        raise util.Abort(_('%s: invalid destination repository type') % type)
     for name, sink in sink_converters:
         try:
             if not type or name == type:
         parents = {}
         while visit:
             n = visit.pop(0)
-            if n in known or n in self.map: continue
+            if n in known or n in self.map:
+                continue
             known.add(n)
             commit = self.cachecommit(n)
             parents[n] = []

LocalMercurial/hgext/convert/convcmd.pyc

Binary file modified.

LocalMercurial/hgext/convert/convcmd.pyo

Binary file modified.

LocalMercurial/hgext/convert/cvs.py

 #  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 import os, locale, re, socket, errno
 from cStringIO import StringIO
 
         cvs = os.path.join(path, "CVS")
         if not os.path.exists(cvs):
-            raise NoRepo("%s does not look like a CVS checkout" % path)
+            raise NoRepo(_("%s does not look like a CVS checkout") % path)
 
         checktool('cvs')
 
                 # patchset number?
                 maxrev = int(self.rev)
             except ValueError:
-                raise util.Abort(_('revision %s is not a patchset number') % self.rev)
+                raise util.Abort(_('revision %s is not a patchset number')
+                                 % self.rev)
 
         d = os.getcwd()
         try:
                 mergefrom=self.ui.config('convert', 'cvsps.mergefrom', None))
 
             for cs in db:
-                if maxrev and cs.id>maxrev:
+                if maxrev and cs.id > maxrev:
                     break
                 id = str(cs.id)
                 cs.author = self.recode(cs.author)
 
                 files = {}
                 for f in cs.entries:
-                    files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
+                    files[f.file] = "%s%s" % ('.'.join([str(x)
+                                                        for x in f.revision]),
                                               ['', '(DEAD)'][f.dead])
 
                 # add current commit to set
         self.writep.flush()
         r = self.readp.readline()
         if not r.startswith("Valid-requests"):
-            raise util.Abort(_("unexpected response from CVS server "
-                               "(expected \"Valid-requests\", but got %r)")
+            raise util.Abort(_('unexpected response from CVS server '
+                               '(expected "Valid-requests", but got %r)')
                              % r)
         if "UseUnchanged" in r:
             self.writep.write("UseUnchanged\n")
             while count > 0:
                 data = fp.read(min(count, chunksize))
                 if not data:
-                    raise util.Abort(_("%d bytes missing from remote file") % count)
+                    raise util.Abort(_("%d bytes missing from remote file")
+                                     % count)
                 count -= len(data)
                 output.write(data)
             return output.getvalue()
         self.writep.flush()
 
         data = ""
+        mode = None
         while 1:
             line = self.readp.readline()
             if line.startswith("Created ") or line.startswith("Updated "):
                 data = chunkedread(self.readp, count)
             else:
                 if line == "ok\n":
+                    if mode is None:
+                        raise util.Abort(_('malformed response from CVS'))
                     return (data, "x" in mode and "x" or "")
                 elif line.startswith("E "):
                     self.ui.warn(_("cvs server: %s\n") % line[2:])

LocalMercurial/hgext/convert/cvs.pyc

Binary file modified.

LocalMercurial/hgext/convert/cvs.pyo

Binary file modified.

LocalMercurial/hgext/convert/cvsps.py

-#
 # Mercurial built-in replacement for cvsps.
 #
 # Copyright 2008, Frank Kingswood <frank@kingswood-consulting.co.uk>
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 import os
 import re
 import cPickle as pickle
 from mercurial import util
 from mercurial.i18n import _
+from mercurial import hook
 
 class logentry(object):
     '''Class logentry has the following attributes:
         .branchpoints- the branches that start at the current entry
     '''
     def __init__(self, **entries):
+        self.synthetic = False
         self.__dict__.update(entries)
 
     def __repr__(self):
         # Get the real directory in the repository
         try:
             prefix = open(os.path.join('CVS','Repository')).read().strip()
+            directory = prefix
             if prefix == ".":
                 prefix = ""
-            directory = prefix
         except IOError:
-            raise logerror('Not a CVS sandbox')
+            raise logerror(_('not a CVS sandbox'))
 
         if prefix and not prefix.endswith(os.sep):
             prefix += os.sep
         p = util.normpath(getrepopath(root))
         if not p.endswith('/'):
             p += '/'
-        prefix = p + util.normpath(prefix)
+        if prefix:
+            # looks like normpath replaces "" by "."
+            prefix = p + util.normpath(prefix)
+        else:
+            prefix = p
     cmd.append(['log', 'rlog'][rlog])
     if date:
         # no space between option and date string
             assert match, _('expected revision number')
             e = logentry(rcs=scache(rcs), file=scache(filename),
                     revision=tuple([int(x) for x in match.group(1).split('.')]),
-                    branches=[], parent=None,
-                    synthetic=False)
+                    branches=[], parent=None)
             state = 6
 
         elif state == 6:
             branchpoints = set()
             for branch, revision in branchmap.iteritems():
                 revparts = tuple([int(i) for i in revision.split('.')])
+                if len(revparts) < 2: # bad tags
+                    continue
                 if revparts[-2] == 0 and revparts[-1] % 2 == 0:
                     # normal branch
                     if revparts[:-2] == e.revision:
                         branchpoints.add(branch)
-                elif revparts == (1,1,1): # vendor branch
+                elif revparts == (1, 1, 1): # vendor branch
                     if revparts in e.branches:
                         branchpoints.add(branch)
             e.branchpoints = branchpoints
             log.sort(key=lambda x: x.date)
 
             if oldlog and oldlog[-1].date >= log[0].date:
-                raise logerror('Log cache overlaps with new log entries,'
-                               ' re-run without cache.')
+                raise logerror(_('log cache overlaps with new log entries,'
+                                 ' re-run without cache.'))
 
             log = oldlog + log
 
 
     ui.status(_('%d log entries\n') % len(log))
 
+    hook.hook(ui, None, "cvslog", True, log=log)
+
     return log
 
 
         .branchpoints- the branches that start at the current entry
     '''
     def __init__(self, **entries):
+        self.synthetic = False
         self.__dict__.update(entries)
 
     def __repr__(self):
         #   "File file4 was added on branch ..." (synthetic, 1 entry)
         #   "Add file3 and file4 to fix ..."     (real, 2 entries)
         # Hence the check for 1 entry here.
-        synth = getattr(c.entries[0], 'synthetic', None)
-        c.synthetic = (len(c.entries) == 1 and synth)
+        c.synthetic = len(c.entries) == 1 and c.entries[0].synthetic
 
     # Sort files in each changeset
 
     branches = {}    # changeset index where we saw a branch
     n = len(changesets)
     i = 0
-    while i<n:
+    while i < n:
         c = changesets[i]
 
         for f in c.entries:
                     m = None   # if no group found then merge to HEAD
                 if m in branches and c.branch != m:
                     # insert empty changeset for merge
-                    cc = changeset(author=c.author, branch=m, date=c.date,
-                            comment='convert-repo: CVS merge from branch %s' % c.branch,
-                            entries=[], tags=[], parents=[changesets[branches[m]], c])
+                    cc = changeset(
+                        author=c.author, branch=m, date=c.date,
+                        comment='convert-repo: CVS merge from branch %s'
+                        % c.branch,
+                        entries=[], tags=[],
+                        parents=[changesets[branches[m]], c])
                     changesets.insert(i + 1, cc)
                     branches[m] = i + 1
 
 
     ui.status(_('%d changeset entries\n') % len(changesets))
 
+    hook.hook(ui, None, "cvschangesets", True, changesets=changesets)
+
     return changesets
 
 
 
         if opts["ancestors"]:
             if cs.branch not in branches and cs.parents and cs.parents[0].id:
-                ancestors[cs.branch] = (changesets[cs.parents[0].id-1].branch,
+                ancestors[cs.branch] = (changesets[cs.parents[0].id - 1].branch,
                                         cs.parents[0].id)
             branches[cs.branch] = cs.id
 
                                                  '%Y/%m/%d %H:%M:%S %1%2'))
             ui.write('Author: %s\n' % cs.author)
             ui.write('Branch: %s\n' % (cs.branch or 'HEAD'))
-            ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags)>1],
+            ui.write('Tag%s: %s \n' % (['', 's'][len(cs.tags) > 1],
                                   ','.join(cs.tags) or '(none)'))
             branchpoints = getattr(cs, 'branchpoints', None)
             if branchpoints:
                 ui.write('Branchpoints: %s \n' % ', '.join(branchpoints))
             if opts["parents"] and cs.parents:
-                if len(cs.parents)>1:
-                    ui.write('Parents: %s\n' % (','.join([str(p.id) for p in cs.parents])))
+                if len(cs.parents) > 1:
+                    ui.write('Parents: %s\n' %
+                             (','.join([str(p.id) for p in cs.parents])))
                 else:
                     ui.write('Parent: %d\n' % cs.parents[0].id)
 
                 fn = f.file
                 if fn.startswith(opts["prefix"]):
                     fn = fn[len(opts["prefix"]):]
-                ui.write('\t%s:%s->%s%s \n' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL',
-                                          '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead]))
+                ui.write('\t%s:%s->%s%s \n' % (
+                        fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL',
+                        '.'.join([str(x) for x in f.revision]),
+                        ['', '(DEAD)'][f.dead]))
             ui.write('\n')
 
         # have we seen the start tag?
                 off = False
 
         # see if we reached the end tag
-        if len(revisions)>1 and not off:
+        if len(revisions) > 1 and not off:
             if revisions[1] == str(cs.id) or \
                 revisions[1] in cs.tags:
                 break

LocalMercurial/hgext/convert/cvsps.pyc

Binary file modified.

LocalMercurial/hgext/convert/cvsps.pyo

Binary file modified.

LocalMercurial/hgext/convert/darcs.py

 #  Copyright 2007-2009 Matt Mackall <mpm@selenic.com> and others
 #
 # This software may be used and distributed according to the terms of the
-# GNU General Public License version 2, incorporated herein by reference.
+# GNU General Public License version 2 or any later version.
 
 from common import NoRepo, checktool, commandline, commit, converter_source
 from mercurial.i18n import _
 
 # The naming drift of ElementTree is fun!
 
-try: from xml.etree.cElementTree import ElementTree
+try:
+    from xml.etree.cElementTree import ElementTree
 except ImportError:
-    try: from xml.etree.ElementTree import ElementTree
+    try:
+        from xml.etree.ElementTree import ElementTree
     except ImportError:
-        try: from elementtree.cElementTree import ElementTree
+        try:
+            from elementtree.cElementTree import ElementTree
         except ImportError:
-            try: from elementtree.ElementTree import ElementTree
-            except ImportError: ElementTree = None
-
+            try:
+                from elementtree.ElementTree import ElementTree
+            except ImportError:
+                ElementTree = None
 
 class darcs_source(converter_source, commandline):
     def __init__(self, ui, path, rev=None):
         # check for _darcs, ElementTree, _darcs/inventory so that we can
         # easily skip test-convert-darcs if ElementTree is not around
         if not os.path.exists(os.path.join(path, '_darcs', 'inventories')):
-            raise NoRepo("%s does not look like a darcs repo" % path)
+            raise NoRepo(_("%s does not look like a darcs repository") % path)
 
         if not os.path.exists(os.path.join(path, '_darcs')):
-            raise NoRepo("%s does not look like a darcs repo" % path)
+            raise NoRepo(_("%s does not look like a darcs repository") % path)
 
         checktool('darcs')
         version = self.run0('--version').splitlines()[0].strip()

LocalMercurial/hgext/convert/darcs.pyc

Binary file modified.

LocalMercurial/hgext/convert/darcs.pyo

Binary file modified.

LocalMercurial/hgext/convert/filemap.py