Commits

Jun Omae  committed 3ced9bf

1.0.2dev: `log:` generates a link with named revisions which be consistent with `browser:` link and the log page works with named revision ranges on Subversion (fixed #11438)

  • Participants
  • Parent commits a062f49
  • Branches 1.0-stable

Comments (0)

Files changed (3)

File trac/versioncontrol/tests/functional.py

         tc.find('The repository directory must be an absolute path.')
 
 
+class RegressionTestTicket11438(FunctionalTwillTestCaseSetup):
+    def runTest(self):
+        """Test for regression of http://trac.edgewall.org/ticket/11438
+        fix for log: link with revision ranges included "head" keyword
+        """
+        rev = self._testenv.svn_mkdir(['ticket11438'], '')
+        rev = self._testenv.svn_add('ticket11438/file1.txt', '')
+        rev = self._testenv.svn_add('ticket11438/file2.txt', '')
+        tc.go(self._tester.url + '/intertrac/log:@%d:head' % (rev - 1))
+        tc.url(self._tester.url + r'/log/\?revs=' + str(rev - 1) + '%3Ahead')
+        tc.notfind('@%d' % (rev + 1))
+        tc.find('@%d' % rev)
+        tc.find('@%d' % (rev - 1))
+        tc.notfind('@%d' % (rev - 2))
+
+
 def functionalSuite(suite=None):
     if not suite:
         import trac.tests.functional
         suite.addTest(RegressionTestTicket11186Alias())
         suite.addTest(RegressionTestTicket11194())
         suite.addTest(RegressionTestTicket11346())
+        suite.addTest(RegressionTestTicket11438())
         suite.addTest(RegressionTestRev5877())
     else:
         print "SKIP: versioncontrol/tests/functional.py (no svn bindings)"

File trac/versioncontrol/web_ui/log.py

         revranges = None
         if revs:
             try:
-                revranges = Ranges(revs)
+                revranges = self._normalize_ranges(repos, path, revs)
                 rev = revranges.b
             except ValueError:
                 pass
                     repos = rm.get_repository(reponame)
 
             if repos:
-                revranges = None
-                if any(c in revs for c in ':-,'):
-                    revranges = self._normalize_ranges(repos, path, revs)
-                    if revranges:
-                        revs = None
                 if 'LOG_VIEW' in formatter.perm:
+                    revranges = None
+                    if any(c in revs for c in ':-,'):
+                        try:
+                            # try to parse into integer rev ranges
+                            revranges = Ranges(revs.replace(':', '-'),
+                                               reorder=True)
+                            revs = str(revranges)
+                        except ValueError:
+                            revranges = self._normalize_ranges(repos, path,
+                                                               revs)
                     if revranges:
                         href = formatter.href.log(repos.reponame or None,
                                                   path or '/',
-                                                  revs=str(revranges))
+                                                  revs=revs)
                     else:
-                        rev = repos.normalize_rev(revs)
+                        repos.normalize_rev(revs)  # verify revision
                         href = formatter.href.log(repos.reponame or None,
-                                                  path or '/', rev=rev)
+                                                  path or '/',
+                                                  rev=revs or None)
                     if query and '?' in href:
                         query = '&' + query[1:]
                     return tag.a(label, class_='source',
     LOG_LINK_RE = re.compile(r"([^@:]*)[@:]%s?" % REV_RANGE)
 
     def _normalize_ranges(self, repos, path, revs):
-        ranges = revs.replace(':', '-')
         try:
             # fast path; only numbers
-            return Ranges(ranges, reorder=True)
+            return Ranges(revs.replace(':', '-'), reorder=True)
         except ValueError:
             # slow path, normalize each rev
-            splitted_ranges = re.split(r'([-,])', ranges)
-            revs = [repos.normalize_rev(r) for r in splitted_ranges[::2]]
-            seps = splitted_ranges[1::2] + ['']
-            ranges = ''.join([str(rev)+sep for rev, sep in zip(revs, seps)])
+            ranges = []
+            for range in revs.split(','):
+                try:
+                    a, b = range.replace(':', '-').split('-')
+                    range = (a, b)
+                except ValueError:
+                    range = (range,)
+                ranges.append('-'.join(str(repos.normalize_rev(r))
+                                       for r in range))
+            ranges = ','.join(ranges)
             try:
                 return Ranges(ranges)
             except ValueError:

File trac/versioncontrol/web_ui/tests/wikisyntax.py

 ============================== log: link resolver
 log:@12
 log:trunk
+log:trunk@head
 log:trunk@12
 log:trunk@12:23
 log:trunk@12-23
 log:trunk:12:23
 log:trunk:12-23
+log:trunk@12:head
 log:trunk:12-head
 log:trunk:12@23
 ------------------------------
 <p>
 <a class="source" href="/log/?rev=12">log:@12</a>
-<a class="source" href="/log/trunk?rev=200">log:trunk</a>
+<a class="source" href="/log/trunk">log:trunk</a>
+<a class="source" href="/log/trunk?rev=head">log:trunk@head</a>
 <a class="source" href="/log/trunk?rev=12">log:trunk@12</a>
 <a class="source" href="/log/trunk?revs=12-23">log:trunk@12:23</a>
 <a class="source" href="/log/trunk?revs=12-23">log:trunk@12-23</a>
 <a class="source" href="/log/trunk?revs=12-23">log:trunk:12:23</a>
 <a class="source" href="/log/trunk?revs=12-23">log:trunk:12-23</a>
-<a class="source" href="/log/trunk?revs=12-200">log:trunk:12-head</a>
+<a class="source" href="/log/trunk?revs=12%3Ahead">log:trunk@12:head</a>
+<a class="source" href="/log/trunk?revs=12-head">log:trunk:12-head</a>
 <a class="missing source" title="No changeset 12@23 in the repository">log:trunk:12@23</a>
 </p>
 ------------------------------
 [10:20/trunk?verbose=yes&format=changelog]
 ------------------------------
 <p>
-<a class="source" href="/log/?rev=200&amp;limit=10">log:?limit=10</a>
+<a class="source" href="/log/?limit=10">log:?limit=10</a>
 <a class="source" href="/log/?rev=12&amp;limit=10">log:@12?limit=10</a>
-<a class="source" href="/log/trunk?rev=200&amp;limit=10">log:trunk?limit=10</a>
+<a class="source" href="/log/trunk?limit=10">log:trunk?limit=10</a>
 <a class="source" href="/log/trunk?rev=12&amp;limit=10">log:trunk@12?limit=10</a>
 <a class="source" href="/log/?revs=10-20&amp;verbose=yes&amp;format=changelog">[10:20?verbose=yes&amp;format=changelog]</a>
 <a class="source" href="/log/trunk?revs=10-20&amp;verbose=yes&amp;format=changelog">[10:20/trunk?verbose=yes&amp;format=changelog]</a>
 ------------------------------
 <p>
 <a class="missing source" title="No changeset 10-20-30 in the repository">log:@10-20-30</a>
-<a class="missing source" title="No changeset 10,20-30,40-50-60 in the repository">log:@10,20-30,40-50-60</a>
+<a class="missing source" title="No changeset 40-50-60 in the repository">log:@10,20-30,40-50-60</a>
 <a class="missing source" title="No changeset 10:20:30 in the repository">log:@10:20:30</a>
 [10-20-30]
 [10:20:30]