changeset 26:546d3f11ac7a 1.0

Merge trailing whitespace removal from 0.12
author Christian Boos <cboos@edgewall.org>
date Thu, 06 Feb 2014 19:56:06 +0100
parents 8df754d9b36a (diff) 5b6010df7f43 (current diff)
children 7aaccb9f649a
files setup.py tracext/hg/backend.py
diffstat 6 files changed, 195 insertions(+), 115 deletions(-) [+]
line wrap: on
line diff
--- a/README	Thu Feb 06 19:27:21 2014 +0100
+++ b/README	Thu Feb 06 19:56:06 2014 +0100
@@ -8,16 +8,16 @@
 
 === Trac ===
 
-This plugin for Trac 0.12 doesn't yet work with Trac ''trunk'',
-but requires the ''multirepos'' branch (to be integrated in trunk 
-shortly):
+This plugin works with Trac 1.0.x.
+
+You can also use the trunk version (1.1.x):
 {{{
-svn co http://svn.edgewall.com/repos/trac/sandbox/multirepos
+svn co http://svn.edgewall.org/repos/trac/trunk
 }}}
 
 and install from there:
 {{{
-$ cd multirepos
+$ cd trunk
 $ python setup.py egg_info
 $ python setup.py install
 }}}
--- a/setup.py	Thu Feb 06 19:27:21 2014 +0100
+++ b/setup.py	Thu Feb 06 19:56:06 2014 +0100
@@ -36,16 +36,16 @@
 TracMercurial = 'http://trac.edgewall.org/wiki/TracMercurial'
 
 setup(name='TracMercurial',
-      install_requires='Trac >=0.12dev-r9125',
-      description='Mercurial plugin for Trac multirepos branch',
+      install_requires='Trac >=1.0dev',
+      description='Mercurial plugin for Trac (1.0 branch)',
       keywords='trac scm plugin mercurial hg',
-      version='0.12.0.31',
+      version='1.0.0.3',
       url=TracMercurial,
       license='GPL',
       author='Christian Boos',
       author_email='cboos@edgewall.org',
       long_description="""
-      This plugin for Trac 0.12 provides support for the Mercurial SCM.
+      This plugin for Trac 1.0 provides support for the Mercurial SCM.
 
       See %s for more details.
       """ % TracMercurial,
--- a/tracext/hg/backend.py	Thu Feb 06 19:27:21 2014 +0100
+++ b/tracext/hg/backend.py	Thu Feb 06 19:56:06 2014 +0100
@@ -15,6 +15,7 @@
 
 from bisect import bisect
 from datetime import datetime
+from heapq import heappop, heappush
 import os
 import time
 import posixpath
@@ -108,6 +109,7 @@
     else:
         from mercurial.scmutil import match
 
+    has_bookmarks = None
 
 except ImportError, e:
     hg_import_error = e
@@ -143,6 +145,15 @@
     if check(s):
         return s
 
+def get_bookmarks(ctx):
+    global has_bookmarks
+    if has_bookmarks:
+        return ctx.bookmarks()
+    if has_bookmarks is None:
+        has_bookmarks = hasattr(ctx, 'bookmarks')
+        if has_bookmarks:
+            return get_bookmarks(ctx)
+    return ()
 
 class trac_ui(ui):
     # Note: will be dropped in 0.13, see MercurialConnector._setup_ui
@@ -171,16 +182,34 @@
 
 ### Components
 
+def render_source_prop(repos, context, name, value):
+    try:
+        ctx = repos.changectx(value)
+        chgset = MercurialChangeset(repos, ctx)
+        href = context.href.changeset(ctx.hex(), repos.reponame)
+        link = tag.a(repos._display(ctx), class_="changeset",
+                     title=shorten_line(chgset.message), href=href)
+    except NoSuchChangeset:
+        link = tag.a(hex(value), class_="missing changeset",
+                     title=_("no such changeset"), rel="nofollow")
+    return RenderedProperty(name=name, content=link,
+                            name_attributes=[("class", "property")])
+
+
 class CsetPropertyRenderer(Component):
 
     implements(IPropertyRenderer)
 
     def match_property(self, name, mode):
         return (name.startswith('hg-') and
-                name[3:] in ('Parents', 'Children', 'Tags', 'Branch') and
+                name[3:] in ('Parents', 'Children', 'Tags', 'Branch',
+                             'Bookmarks', 'source') and
                 mode == 'revprop') and 4 or 0
 
     def render_property(self, name, mode, context, props):
+        if name == 'hg-source':
+            repos, value = props[name]
+            return render_source_prop(repos, context, _("Graft:"), value)
         return RenderedProperty(name=gettext(name[3:] + ':'),
                 name_attributes=[("class", "property")],
                 content=self._render_property(name, mode, context, props))
@@ -238,18 +267,7 @@
     def render_property(self, name, mode, context, props):
         repos, value = props[name]
         if name == 'hg-transplant_source':
-            try:
-                ctx = repos.changectx(value)
-                chgset = MercurialChangeset(repos, ctx)
-                href = context.href.changeset(ctx.hex(), repos.reponame)
-                link = tag.a(repos._display(ctx), class_="changeset",
-                             title=shorten_line(chgset.message), href=href)
-            except NoSuchChangeset:
-                link = tag.a(hex(value), class_="missing changeset",
-                             title=_("no such changeset"), rel="nofollow")
-            return RenderedProperty(name=_("Transplant:"), content=link,
-                                    name_attributes=[("class", "property")])
-
+            return render_source_prop(repos, context, _("Transplant:"), value)
         elif name == 'hg-convert_revision':
             text = repos.to_u(value)
             if value.startswith('svn:'):
@@ -725,6 +743,9 @@
         for c in ctx.children():
             return c.hex() # always follow first child
 
+    def parent_revs(self, rev):
+        return [p.hex() for p in self.changectx(rev).parents()]
+
     def rev_older_than(self, rev1, rev2):
         # FIXME use == and ancestors?
         return self.short_rev(rev1) < self.short_rev(rev2)
@@ -884,8 +905,8 @@
             if not dirctx:
                 # we need to find the most recent change for a file below dir
                 str_dir = str_path + '/'
-                dirctxs = self.find_dirctx(changectx.rev(), [str_dir,],
-                                           {str_dir: str_entries})
+                dirctxs = self._find_dirctx(changectx.rev(), [str_dir,],
+                                            {str_dir: str_entries})
                 dirctx = dirctxs.values()[0]
 
         if not kind:
@@ -906,13 +927,13 @@
         self.created_rev = created_rev
         self.data = None
 
-    def find_dirctx(self, max_rev, str_dirnames, str_entries):
+    def _find_dirctx(self, max_rev, str_dirnames, str_entries):
         """Find most recent modification for each given directory path.
 
         :param max_rev: find no revision more recent than this one
         :param str_dirnames: directory paths to consider
-                             (as `str` ending with '/')
-        :param str_entries: optionally maps directories to their file content
+                             (list of `str` ending with '/')
+        :param str_entries: maps each directory to the files it contains
 
         :return: a `dict` with `str_dirnames` as keys, `changectx` as values
 
@@ -929,46 +950,66 @@
            each directory; this is much faster but can still be slow
            if some folders are only modified in the distant past
 
-        It is possible to combine both approach, and this can yield
-        excellent results in some cases (e.g. browsing the Linux repos
-        @ 118733 takes several minutes with the first approach, 11s
-        with the second, but only 1.2s with the hybrid approach)
+        It is possible to combine both approaches, and this can
+        produce excellent results in some cases, for example browsing
+        the root of the Hg mirror of the Linux repository (at revision
+        118733) takes several minutes with the first approach, 11s
+        with the second, but only 1.2s with the hybrid approach.
 
         Note that the specialized scan of the changelog we do below is
-        more efficient than the general cmdutil.walkchangerevs here.
+        more efficient than the general cmdutil.walkchangerevs.
         """
         str_dirctxs = {}
         repo = self.repos.repo
         max_ctx = repo[max_rev]
-        for r in xrange(max_rev, -1, -1):
+        orevs = [-max_rev]
+        revs = set(orevs)
+        while orevs:
+            r = -heappop(orevs)
             ctx = repo[r]
+            for p in ctx.parents():
+                if p and p.rev() not in revs:
+                    revs.add(p.rev())
+                    heappush(orevs, -p.rev())
             # lookup changes to str_dirnames in current cset
             for str_file in ctx.files():
                 for str_dir in str_dirnames[:]:
                     if str_file.startswith(str_dir):
+                        # rev for str_dir was found using first strategy
                         str_dirctxs[str_dir] = ctx
                         str_dirnames.remove(str_dir)
-                        if not str_dirnames: # if nothing left to find
+                        if not str_dirnames: # nothing left to find
                             return str_dirctxs
-            # in parallel, try the filelog strategy (the 463, 2, 40
+
+            # In parallel, try the filelog strategy (the 463, 2, 40
             # values below look a bit like magic numbers; actually
             # they were selected by testing the plugin on the Linux
             # and NetBeans repositories)
-            if r % 463 == 0:
-                k = max(2, 40 / len(str_dirnames))
+
+            # only use the filelog strategy every `n` revs
+            n = 463
+
+            # k, the number of files to examine per directory,
+            # will be comprised between `min_files` and `max_files`
+            min_files = 2
+            max_files = 40 # (will be the max if there's only one dir left)
+
+            if r % n == 0:
+                k = max(min_files, max_files / len(str_dirnames))
                 for str_dir in str_dirnames[:]:
                     str_files = str_entries[str_dir]
                     dr = str_dirctxs.get(str_dir, 0)
                     for f in str_files[:k]:
-                        try:
-                            dr = max(dr, max_ctx.filectx(f).linkrev())
-                        except LookupError:
-                            pass # that file was not on this revision `r`
+                        dr = max(dr, max_ctx.filectx(f).linkrev())
                     str_files = str_files[k:]
                     if str_files:
+                        # not all files for str_dir seen yet,
+                        # store max rev found so far
                         str_entries[str_dir] = str_files
                         str_dirctxs[str_dir] = dr
                     else:
+                        # all files for str_dir were examined,
+                        # rev found using filelog strategy
                         str_dirctxs[str_dir] = repo[dr]
                         str_dirnames.remove(str_dir)
                         if not str_dirnames:
@@ -1032,14 +1073,13 @@
 
         # pre-computing the changectx for the last change in each sub-directory
         if str_dirnames:
-            dirctxs = self.find_dirctx(self.created_rev, str_dirnames,
-                                       str_entries)
+            dirctxs = self._find_dirctx(self.created_rev, str_dirnames,
+                                        str_entries)
         else:
             dirctxs = {}
 
         for str_entry in str_entries:
-            yield self.subnode(str_entry.rstrip('/'),
-                               dirctxs.get(str_entry, None))
+            yield self.subnode(str_entry.rstrip('/'), dirctxs.get(str_entry))
 
     def get_history(self, limit=None):
         repo = self.repos.repo
@@ -1171,7 +1211,8 @@
         Changeset.__init__(self, repos, ctx.hex(), desc, user, time)
 
     hg_properties = [
-        N_("Parents:"), N_("Children:"), N_("Branch:"), N_("Tags:")
+        N_("Parents:"), N_("Children:"), N_("Branch:"), N_("Tags:"),
+        N_("Bookmarks:")
     ]
 
     def get_properties(self):
@@ -1186,10 +1227,12 @@
                                          [c.hex() for c in children])
         if self.branch:
             properties['hg-Branch'] = (self.repos, [self.branch])
-        tags = self.ctx.tags()
+        tags = self.get_tags()
         if len(tags):
-            properties['hg-Tags'] = (self.repos,
-                                     [self.repos.to_u(t) for t in tags])
+            properties['hg-Tags'] = (self.repos, tags)
+        bookmarks = get_bookmarks(self.ctx)
+        if len(bookmarks):
+            properties['hg-Bookmarks'] = (self.repos, bookmarks)
         for k, v in self.ctx.extra().iteritems():
             if k != 'branch':
                 properties['hg-' + k] = (self.repos, v)
@@ -1241,5 +1284,9 @@
 
     def get_branches(self):
         """Yield branch names to which this changeset belong."""
-        return self.branch and [(self.branch,
-                                 len(self.ctx.children()) == 0)] or []
+        if self.branch:
+            yield (self.branch, len(self.ctx.children()) == 0)
+
+    def get_tags(self):
+        """Yield tag names to which this changeset belong."""
+        return [self.repos.to_u(t) for t in self.ctx.tags()]
--- a/tracext/hg/hooks.py	Thu Feb 06 19:27:21 2014 +0100
+++ b/tracext/hg/hooks.py	Thu Feb 06 19:56:06 2014 +0100
@@ -106,7 +106,7 @@
         try:
             revs_per_call = int(ui.config('trac', 'revs_per_call'))
         except (TypeError, ValueError):
-            revs_per_call = os.name == 'nt' and 160 or 1000
+            revs_per_call = 160 if os.name == 'nt' else 1000
 
         trac_admin = expand_path(trac_admin)
         for i in xrange(0, len(revs), revs_per_call):
--- a/tracext/hg/locale/fr/LC_MESSAGES/tracmercurial.po	Thu Feb 06 19:27:21 2014 +0100
+++ b/tracext/hg/locale/fr/LC_MESSAGES/tracmercurial.po	Thu Feb 06 19:56:06 2014 +0100
@@ -1,14 +1,15 @@
 # French (France) translations for TracMercurial.
-# Copyright (C) 2008 ORGANIZATION
+# Copyright (C) 2008-2012 Edgewall Software
 # This file is distributed under the same license as the TracMercurial
 # project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2008.
+#
+# Christian Boos <cboos@edgewall.org>, 2008-2012.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: TracMercurial 0.12.0.4\n"
 "Report-Msgid-Bugs-To: cboos@edgewall.org\n"
-"POT-Creation-Date: 2008-11-13 12:33+0100\n"
+"POT-Creation-Date: 2012-09-17 21:00+0200\n"
 "PO-Revision-Date: 2009-11-19 16:22+0100\n"
 "Last-Translator: Christian Boos <cboos@edgewall.org>\n"
 "Language-Team: fr_FR <LL@li.org>\n"
@@ -16,19 +17,27 @@
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 0.9.4\n"
+"Generated-By: Babel 1.0dev\n"
+
+#: tracext/hg/backend.py:184
+msgid "no such changeset"
+msgstr "pas de révision"
 
-#: tracext/hg/backend.py:99
+#: tracext/hg/backend.py:202
+msgid "Graft:"
+msgstr "Greffe :"
+
+#: tracext/hg/backend.py:203
 msgid ":"
-msgstr ""
+msgstr " :"
 
-#: tracext/hg/backend.py:114
+#: tracext/hg/backend.py:225
 msgid "Diff against this parent (show the changes merged from the other parents)"
 msgstr ""
 "Différences vis-à-vis de ce parent (montre les changements apportés par "
 "l'autre parent)"
 
-#: tracext/hg/backend.py:124
+#: tracext/hg/backend.py:235
 #, python-format
 msgid ""
 "Note: this is a %(merge)s changeset, the changes displayed below "
@@ -37,7 +46,7 @@
 "Note: ceci est un changeset de type %(merge)s, les modifications ci-"
 "dessous correspondent au merge lui-même."
 
-#: tracext/hg/backend.py:132
+#: tracext/hg/backend.py:243
 #, python-format
 msgid ""
 "Use the %(diff)s links above to see all the changes relative to each "
@@ -46,37 +55,42 @@
 "Utilisez les liens %(diff)s ci-dessus pour voir les modifications "
 "relatives à chaque parent."
 
-#: tracext/hg/backend.py:155
-msgid "no such changeset"
-msgstr "pas de révisio"
+#: tracext/hg/backend.py:260
+msgid "Transplant:"
+msgstr "Transplant :"
 
-#: tracext/hg/backend.py:156
-msgid "Transplant:"
-msgstr ""
+#: tracext/hg/backend.py:273
+msgid "Changeset in source repository"
+msgstr "Modification dans le dépôt d'origine"
 
-#: tracext/hg/backend.py:173
+#: tracext/hg/backend.py:275
+msgid "Convert:"
+msgstr "Conversion :"
+
+#: tracext/hg/backend.py:300
 msgid "(binary, size greater than 100 bytes)"
 msgstr "(binaire, taille supérieure à 100 octets)"
 
-#: tracext/hg/backend.py:285
+#: tracext/hg/backend.py:461
 #, python-format
 msgid "Repository '%(repo)s' not found"
-msgstr "Dépôt '%(repo)s' non trouvé"
+msgstr "Dépôt « %(repo)s »' non trouvé"
 
-#: tracext/hg/backend.py:344
+#: tracext/hg/backend.py:527
 #, python-format
-msgid "%(path)s does not appear to contain a Mercurial repository."
-msgstr "%(path)s ne semble pas contenir un dépôt Mercurial"
+msgid "Repository path '%(path)s' does not exist."
+msgstr "Chemin du dépôt « %(path)s » inexistant."
 
-#: tracext/hg/backend.py:566
-msgid "The Base for Diff is invalid"
+#: tracext/hg/backend.py:535
+#, python-format
+msgid ""
+"'%(path)s' does not appear to contain a repository (Mercurial %(version)s"
+" says %(error)s)"
 msgstr ""
+"%(path)s ne semble pas contenir un dépôt Mercurial (Mercurial %(version)s"
+" reporte l'erreur suivante : %(error)s)"
 
-#: tracext/hg/backend.py:571
-msgid "The Target for Diff is invalid"
-msgstr ""
-
-#: tracext/hg/backend.py:575
+#: tracext/hg/backend.py:764
 #, python-format
 msgid ""
 "Diff mismatch: Base is a %(okind)s (%(opath)s in revision %(orev)s) and "
@@ -86,24 +100,28 @@
 "révision %(orev)s) et Destination est un %(nkind)s (%(npath)s dans la "
 "révision %(nrev)s)."
 
-#: tracext/hg/backend.py:719
+#: tracext/hg/backend.py:1026
 #, python-format
 msgid "Can't read from directory %(path)s"
 msgstr "Lecture du répertoire %(path)s impossible"
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Parents:"
 msgstr "Ascendants :"
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Children:"
 msgstr "Descendants :"
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Branch:"
 msgstr "Branche :"
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Tags:"
 msgstr "Tags :"
 
+#: tracext/hg/backend.py:1205
+msgid "Bookmarks:"
+msgstr "Signets :"
+
--- a/tracext/hg/locale/messages.pot	Thu Feb 06 19:27:21 2014 +0100
+++ b/tracext/hg/locale/messages.pot	Thu Feb 06 19:56:06 2014 +0100
@@ -1,102 +1,117 @@
 # Translations template for TracMercurial.
-# Copyright (C) 2009 ORGANIZATION
+# Copyright (C) 2012 ORGANIZATION
 # This file is distributed under the same license as the TracMercurial
 # project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2009.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
 #
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: TracMercurial 0.12.0.9\n"
+"Project-Id-Version: TracMercurial 1.0.0.3\n"
 "Report-Msgid-Bugs-To: cboos@edgewall.org\n"
-"POT-Creation-Date: 2009-11-19 16:21+0100\n"
+"POT-Creation-Date: 2012-09-17 21:00+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 0.9.4\n"
+"Generated-By: Babel 1.0dev\n"
+
+#: tracext/hg/backend.py:184
+msgid "no such changeset"
+msgstr ""
 
-#: tracext/hg/backend.py:99
+#: tracext/hg/backend.py:202
+msgid "Graft:"
+msgstr ""
+
+#: tracext/hg/backend.py:203
 msgid ":"
 msgstr ""
 
-#: tracext/hg/backend.py:114
+#: tracext/hg/backend.py:225
 msgid ""
 "Diff against this parent (show the changes merged from the other "
 "parents)"
 msgstr ""
 
-#: tracext/hg/backend.py:124
+#: tracext/hg/backend.py:235
 #, python-format
 msgid ""
 "Note: this is a %(merge)s changeset, the changes displayed below "
 "correspond to the merge itself."
 msgstr ""
 
-#: tracext/hg/backend.py:132
+#: tracext/hg/backend.py:243
 #, python-format
 msgid ""
 "Use the %(diff)s links above to see all the changes relative to each "
 "parent."
 msgstr ""
 
-#: tracext/hg/backend.py:155
-msgid "no such changeset"
-msgstr ""
-
-#: tracext/hg/backend.py:156
+#: tracext/hg/backend.py:260
 msgid "Transplant:"
 msgstr ""
 
-#: tracext/hg/backend.py:173
+#: tracext/hg/backend.py:273
+msgid "Changeset in source repository"
+msgstr ""
+
+#: tracext/hg/backend.py:275
+msgid "Convert:"
+msgstr ""
+
+#: tracext/hg/backend.py:300
 msgid "(binary, size greater than 100 bytes)"
 msgstr ""
 
-#: tracext/hg/backend.py:285
+#: tracext/hg/backend.py:461
 #, python-format
 msgid "Repository '%(repo)s' not found"
 msgstr ""
 
-#: tracext/hg/backend.py:344
+#: tracext/hg/backend.py:527
 #, python-format
-msgid "%(path)s does not appear to contain a Mercurial repository."
+msgid "Repository path '%(path)s' does not exist."
 msgstr ""
 
-#: tracext/hg/backend.py:566
-msgid "The Base for Diff is invalid"
+#: tracext/hg/backend.py:535
+#, python-format
+msgid ""
+"'%(path)s' does not appear to contain a repository (Mercurial "
+"%(version)s says %(error)s)"
 msgstr ""
 
-#: tracext/hg/backend.py:571
-msgid "The Target for Diff is invalid"
-msgstr ""
-
-#: tracext/hg/backend.py:575
+#: tracext/hg/backend.py:764
 #, python-format
 msgid ""
 "Diff mismatch: Base is a %(okind)s (%(opath)s in revision %(orev)s) "
 "and Target is a %(nkind)s (%(npath)s in revision %(nrev)s)."
 msgstr ""
 
-#: tracext/hg/backend.py:719
+#: tracext/hg/backend.py:1026
 #, python-format
 msgid "Can't read from directory %(path)s"
 msgstr ""
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Parents:"
 msgstr ""
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Children:"
 msgstr ""
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Branch:"
 msgstr ""
 
-#: tracext/hg/backend.py:892
+#: tracext/hg/backend.py:1204
 msgid "Tags:"
 msgstr ""
 
+#: tracext/hg/backend.py:1205
+msgid "Bookmarks:"
+msgstr ""
+