# HG changeset patch # User Christian Boos # Date 1391712966 -3600 # Node ID 546d3f11ac7a1653c331f94e5c75e0e4227ecfd1 # Parent 8df754d9b36a8bd5c7385f8ebebbf0069d2088d6# Parent 5b6010df7f43900b14893a4f767c82fa9c8de863 Merge trailing whitespace removal from 0.12 diff -r 5b6010df7f43 -r 546d3f11ac7a README --- 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 }}} diff -r 5b6010df7f43 -r 546d3f11ac7a setup.py --- 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, diff -r 5b6010df7f43 -r 546d3f11ac7a tracext/hg/backend.py --- 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()] diff -r 5b6010df7f43 -r 546d3f11ac7a tracext/hg/hooks.py --- 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): diff -r 5b6010df7f43 -r 546d3f11ac7a tracext/hg/locale/fr/LC_MESSAGES/tracmercurial.po --- 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 , 2008. +# +# Christian Boos , 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 \n" "Language-Team: fr_FR \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 :" + diff -r 5b6010df7f43 -r 546d3f11ac7a tracext/hg/locale/messages.pot --- 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 , 2009. +# FIRST AUTHOR , 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 \n" "Language-Team: LANGUAGE \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 "" +