1. edgewall
  2. Trac

Commits

Remy Blank  committed 25bf9c1

0.11-stable: Fixed the calculation of eligible merge revisions by considering the start of the target branch.

Patch by Christian Boos, part of #7715.

  • Participants
  • Parent commits 3568f7b
  • Branches 0.11-stable

Comments (0)

Files changed (4)

File trac/versioncontrol/cache.py

View file
  • Ignore whitespace
 #
 # Author: Christopher Lenz <cmlenz@gmx.de>
 
-import bisect
 from datetime import datetime
 import os
 import posixpath
     def get_node(self, path, rev=None):
         return self.repos.get_node(path, rev)
 
-    def _get_node_revs(self, path, rev=None):
-        """Return the revisions affecting `path` between its creation and
-        `rev`.
+    def _get_node_revs(self, path, last=None, first=None):
+        """Return the revisions affecting `path` between `first` and `last`
+        revisions.
         """
-        rev = self.normalize_rev(rev)
-        node = self.get_node(path, rev)     # Check node existence and perms
+        last = self.normalize_rev(last)
+        node = self.get_node(path, last)    # Check node existence and perms
         db = self.getdb()
         cursor = db.cursor()
+        rev_as_int = db.cast('rev', 'int')
+        if first is None:
+            cursor.execute("SELECT rev FROM node_change "
+                           "WHERE path = %%s "
+                           "  AND change_type IN ('A', 'C', 'M') "
+                           "  AND %s <= %%s "
+                           "ORDER BY %s DESC "
+                           "LIMIT 1" % ((rev_as_int,) * 2),
+                           (path, last))
+            first = 0
+            for row in cursor:
+                first = int(row[0])
         cursor.execute("SELECT DISTINCT rev FROM node_change "
                        "WHERE (path = %%s OR path %s) "
-                       "  AND %s <= %%s" % (db.like(), db.cast('rev', 'int')),
-                       (path, db.like_escape(path + '/') + '%', rev))
-        revs = [int(row[0]) for row in cursor]
-        revs.sort()
-        cursor.execute("SELECT rev FROM node_change "
-                       "WHERE path = %%s "
-                       "  AND change_type IN ('A', 'C', 'M') "
-                       "  AND %s <= %%s "
-                       "ORDER BY %s DESC "
-                       "LIMIT 1" % ((db.cast('rev', 'int'),) * 2),
-                       (path, rev))
-        created = 0
-        for row in cursor:
-            created = int(row[0])
-        return revs[bisect.bisect_left(revs, created):]
+                       " AND %s >= %%s AND %s <= %%s" % 
+                       (db.like(), rev_as_int, rev_as_int),
+                       (path, db.like_escape(path + '/') + '%', first, last))
+        return [int(row[0]) for row in cursor]
 
     def has_node(self, path, rev=None):
         return self.repos.has_node(path, rev)

File trac/versioncontrol/svn_fs.py

View file
  • Ignore whitespace
 
         return SubversionNode(path, rev, self, self.pool)
 
-    def _get_node_revs(self, path, rev=None):
-        """Return the revisions affecting `path` between its creation and
-        `rev`.
+    def _get_node_revs(self, path, last=None, first=None):
+        """Return the revisions affecting `path` between `first` and `last` 
+        revs. If `first` is not given, it goes down to the revision in which
+        the branch was created.
         """
-        node = self.get_node(path, rev)
+        node = self.get_node(path, last)
         revs = []
         for (p, r, chg) in node.get_history():
-            if p != path:
+            if p != path or (first and r < first):
                 break
             revs.append(r)
         return revs
         return fs.node_prop(self.root, self._scoped_path_utf8, name,
                             self.pool())
 
+    def get_copy_origin(self):
+        root_and_path = fs.closest_copy(self.root, self._scoped_path_utf8)
+        if root_and_path:
+            root, path = root_and_path
+            rev = fs.revision_root_revision(root)
+            if (path, rev) == (self.path, self.rev):
+                rev, path = fs.copied_from(root, path)
+            return SubversionNode(path, rev, self.repos, self.pool, root)
+
 
 class SubversionChangeset(Changeset):
 

File trac/versioncontrol/svn_prop.py

View file
  • Ignore whitespace
         revs_label = (_('merged'), _('blocked'))[name.endswith('blocked')]
         revs_cols = has_eligible and 2 or None
         repos = self.env.get_repository()
+        target_path = context.resource.id
+        target_rev = context.resource.version
+        if has_eligible:
+            branch_starts = {}
+            node = repos.get_node(target_path, target_rev)
+            while node:
+                node = node.get_copy_origin()
+                if node and node.path != target_path:
+                    branch_starts[node.path] = node.rev + 1
         rows = []
         for line in props[name].splitlines():
             path, revs = line.split(':', 1)
             deleted = False
             if 'LOG_VIEW' in context.perm('source', spath):
                 try:
-                    node = repos.get_node(spath, context.resource.version)
+                    node = repos.get_node(spath, target_rev)
                     row = [self._get_source_link(path, context),
                            self._get_revs_link(revs_label, context,
                                                spath, revs)]
                     if has_eligible:
-                        eligible = set(repos._get_node_revs(spath,
-                                                    context.resource.version))
+                        first_rev = branch_starts.get(path)
+                        eligible = set(repos._get_node_revs(spath, target_rev,
+                                                            first_rev))
                         eligible -= set(Ranges(revs))
                         blocked = self._get_blocked_revs(props, name, spath)
                         eligible -= set(Ranges(blocked))
             removed = old_revs - new_revs
             try:
                 all_revs = set(repos._get_node_revs(spath))
+                # TODO: also pass first_rev here, for getting smaller a set
+                #       (this is an optmization fix, result is already correct)
                 added &= all_revs
                 removed &= all_revs
             except NoSuchNode:

File trac/versioncontrol/web_ui/browser.py

View file
  • Ignore whitespace
         except NoSuchChangeset, e:
             raise ResourceNotFound(e.message, _('Invalid Changeset Number'))
 
-        context = Context.from_request(req, 'source', path, node.created_rev)
+        context = Context.from_request(req, 'source', path, rev_or_latest)
 
         path_links = get_path_links(req.href, path, rev, order, desc)
         if len(path_links) > 1: