incubator-allura-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From john...@apache.org
Subject [1/2] git commit: [squash] Partial commit, refactor
Date Tue, 27 Nov 2012 16:18:54 GMT
Updated Branches:
  refs/heads/cj/4691 2f274d78b -> 6aecbb1dd (forced update)


[squash] Partial commit, refactor


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/6aecbb1d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/6aecbb1d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/6aecbb1d

Branch: refs/heads/cj/4691
Commit: 6aecbb1ddcc19f43bda481f042104876c419c9f1
Parents: e4e9fe8
Author: Cory Johns <johnsca@geek.net>
Authored: Tue Nov 27 16:18:29 2012 +0000
Committer: Cory Johns <johnsca@geek.net>
Committed: Tue Nov 27 16:18:29 2012 +0000

----------------------------------------------------------------------
 Allura/allura/model/repo.py            |  186 +++++++++++++--------------
 Allura/allura/tests/model/test_repo.py |    9 +-
 2 files changed, 98 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6aecbb1d/Allura/allura/model/repo.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repo.py b/Allura/allura/model/repo.py
index bb9784f..dbf9bee 100644
--- a/Allura/allura/model/repo.py
+++ b/Allura/allura/model/repo.py
@@ -349,13 +349,30 @@ class Commit(RepoObject):
             cur = cur[part]
         return cur
 
-    def changed(self, path):
-        '''Test whether a given path was changed in this commit.'''
-        di = DiffInfoDoc.m.get(_id=self._id)
-        for change in di.differences:
-            if change.name.strip('/') == path.strip('/'):
-                return True
-        return False
+    @LazyProperty
+    def changed_paths(self):
+        '''
+        Returns a list of paths changed in this commit.
+        Leading and trailing slashes are removed, and
+        the list is complete, meaning that if a sub-path
+        is changed, all of the parent paths are included
+        (including '' to represent the root path).
+
+        Example:
+
+            If the file /foo/bar is changed in the commit,
+            this would return ['', 'foo', 'foo/bar']
+        '''
+        diff_info = DiffInfoDoc.m.get(_id=self._id)
+        diffs = set()
+        for d in diff_info.differences:
+            diffs.add(d.name.strip('/'))
+            node_path = os.path.dirname(d.name)
+            while node_path:
+                diffs.add(node_path)
+                node_path = os.path.dirname(node_path)
+            diffs.add('')  # include '/' if there are any changes
+        return diffs
 
     @LazyProperty
     def info(self):
@@ -633,87 +650,81 @@ class Blob(object):
 
 class LastCommit(RepoObject):
     @classmethod
-    def build(cls, tree):
+    def get(cls, tree):
+        '''Find the LastCommitDoc for the given tree.
+
+        Climbs the commit tree until either:
+
+        1) An LCD is found for the given tree.  (If the LCD was not found for the
+           tree's commit, the commits traversed while searching for it are
+           added to the LCD for faster retrieval in the future.)
+
+        2) The commit in which the tree was most recently modified is found.
+           In this case, we know that the LCD hasn't been constructed for this
+           (chain of) commit(s), and it will have to be built.
         '''
-        We need a LCD for this tree, for which there are two possibilities:
-
-          1) This tree was modified in an ancestor commit but the commit ID chain
-             was not filled in.  In this case, as we walk back up the tree, we'll
-             find a LCD record when or before we find the commit in which this tree
-             was changed.  If we find this, we save the new commit IDs in the LCD
-             record for faster access in the future.
-
-          2) The LCD record for the commit in which this tree was changed does not
-             exist.  We'll find the commit and still not have a LCD record, which
-             means we have to construct it.  The LCD record will only contain the
-             commit IDs up to the commit where the tree was most recently changed.
-
-             Constructing it differs for SVN and Git / Hg.  SVN can pull all the info
-             from a single SVN call.  Git / Hg have to walk up the tree.  (SVN could
-             walk up the tree as well, except that the TreesDoc and DiffInfoDoc
-             records are not correctly populated, making it hard to tell when a tree
-             was changed in a given commit, plus it's unnecessary.)
-
-             To walk up the tree, we have to keep track of which entries we still
-             need info about.  At each step of the walk, we check the following:
-
-               1) If the current tree has a LCD record, we can pull all the remaining
-                  info we need from it, and we're done.
-
-               2) If the tree was modified in this commit, then we pull the info for
-                  all changed entries, then making the parent tree the new active
-                  tree and continuing the walk.  Once we have data for all entries,
-                  we're done.
+        path = tree.path().strip('/')
+        commit_ids = []
+        for commit in tree.commit.climb_commit_tree():
+            last_commit = cls.query.get(
+                    commit_ids=commit._id,
+                    path=path,
+                )
+            if last_commit:
+                # found our LCD; add any traversed commits to it
+                if commit_ids:
+                    last_commit.commit_ids.extend(commit_ids)
+                    session(last_commit).flush(last_commit)
+                return last_commit
+            commit_ids.append(commit._id)
+            if path in commit.changed_paths:
+                # tree was changed but no LCD found; have to build
+                tree = commit.tree.get_obj_by_path(path)
+                return cls.build(tree, commit_ids)
+
+    @classmethod
+    def build(cls, tree, commit_ids=[]):
+        '''
+          Build the LCD record, presuming that this tree is where it was most
+          recently changed.
+
+          To build the LCD, we climb the commit tree, keeping track of which
+          entries we still need info about.  (For multi-parent commits, it
+          doesn't matter which parent we follow because those would be merge
+          commits and ought to have the diff info populated for any file
+          touched by the merge.)  At each step of the walk, we check the following:
+
+            1) If the current tree has an LCD record, we can pull all the remaining
+               info we need from it, and we're done.
+
+            2) If the tree was modified in this commit, then we pull the info for
+               all changed entries, then continue up the tree.  Once we have data
+               for all entries, we're done.
+
+          (It may be possible to optimize this for SVN, if SVN can return all of
+          the LCD info from a single call and if that turns out to be more efficient
+          than walking up the tree.  It is unclear if those hold without testing.)
         '''
         unfilled = set([n.name for n in chain(tree.tree_ids, tree.blob_ids, tree.other_ids)])
         tree_nodes = set([n.name for n in tree.tree_ids])
-        entires = []
-        commit_ids = []
-        commit = tree.commit
         path = tree.path().strip('/')
-        lcd = None
-        has_changes = False
-        for commit in commit.climb_commit_tree():
-            last_commit = LastCommitDoc.m.get(
+        lcd = cls(
+                    commit_ids=commit_ids,
+                    path=path,
+                    entries=dict(),
+                )
+        for commit in tree.commit.climb_commit_tree():
+            partial_lcd = cls.query.get(
                     commit_ids=commit._id,
                     path=path,
                 )
-            if not has_changes:
-                # no changes found yet, so look to see if we have a matching LCD
-                # that just doesn't have all the commit_ids filled in
-                if last_commit:
-                    # found a complete LCD for our tree
-                    last_commit.commit_ids.extend(commit_ids)
-                    last_commit.m.save()
-                    return last_commit
-                # LCD is only valid for the most recent commit
-                # that changed the tree, so once we have changes,
-                # stop recording commit_ids
-                commit_ids.append(commit._id)
-
-            # look for changes to the tree in this commit,
-            # meaning our LCD is missing and must be built
-            diff_info = DiffInfoDoc.m.get(_id=commit._id)
-            diffs = set()
-            for d in diff_info.differences:
-                diffs.add(d.name)
-                node_path = os.path.dirname(d.name)
-                while node_path:
-                    diffs.add(node_path)
-                    node_path = os.path.dirname(node_path)
-                diffs.add('')  # include '/' if there are any changes
-            #import ipdb; ipdb.set_trace()
-            if path in diffs:
-                has_changes = True
             for name in list(unfilled):
-                full_name = os.path.join(path, name)
-                if full_name in diffs:
-                    if lcd is None:
-                        lcd = LastCommitDoc(dict(
-                                    commit_ids=commit_ids,
-                                    path=path,
-                                    entries=dict(),
-                                ))
+                if partial_lcd:
+                    # the partial LCD should contain anything we're missing
+                    lcd.entries[name] = last_commit.entries[name]
+                    unfilled.remove(name)
+                elif '/'.join([path, name]) in commit.changed_paths:
+                    # no partial LCD to finish us, but changed in this commit, so gather
the data
                     lcd.entries[name] = dict(
                             type=name in tree_nodes and 'DIR' or 'BLOB',
                             name=name,
@@ -721,22 +732,9 @@ class LastCommit(RepoObject):
                         )
                     unfilled.remove(name)
 
-            # if we have changes but this commit has an LCD for our
-            # path, it should have all the remaining info we need
-            if last_commit:
-                for name in list(unfilled):
-                    lcd.entries[name] = last_commit.entries[name]
-                    unfilled.remove(name)
-
-            if has_changes and not unfilled:
+            if not unfilled:
                 break
-        if lcd is None:
-            lcd = LastCommitDoc(dict(
-                        commit_ids=commit_ids,
-                        path=path,
-                        entries=dict(),
-                    ))
-        lcd.m.save()
+        session(lcd).flush()
         return lcd
 
 mapper(Commit, CommitDoc, repository_orm_session)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6aecbb1d/Allura/allura/tests/model/test_repo.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_repo.py b/Allura/allura/tests/model/test_repo.py
index 484b7d1..5be3fc6 100644
--- a/Allura/allura/tests/model/test_repo.py
+++ b/Allura/allura/tests/model/test_repo.py
@@ -128,7 +128,7 @@ class TestLastCommit(unittest.TestCase):
                 'file1',
                 'dir1/file2',
             ])
-        lcd = M.repo.LastCommit.build(commit1.tree)
+        lcd = M.repo.LastCommit.build(commit1.tree, [commit1._id])
         self.assertEqual([self.repo._commits[c].message for c in lcd.commit_ids], [commit1.message])
         self.assertEqual(lcd.path, '')
         self.assertEqual(lcd.entries, {
@@ -409,8 +409,11 @@ class TestLastCommit(unittest.TestCase):
                 },
             )
         session(prev_lcd).flush()
-        tree = self._build_tree(commit3, '/dir1', ['file1', 'file2'])
-        lcd = M.repo.LastCommit.build(tree)
+        tree2 = self._build_tree(commit2, '/dir1', ['file1', 'file2'])
+        tree3 = self._build_tree(commit3, '/dir1', ['file1', 'file2'])
+        with mock.patch('allura.model.repo.Commit.tree') as get_tree:
+            get_tree.get_obj_by_path.return_value = tree2
+            lcd = M.repo.LastCommit.get(tree3)
         self.assertEqual(lcd._id, prev_lcd._id)
         self.assertEqual([self.repo._commits[c].message for c in lcd.commit_ids], [commit2.message,
commit3.message])
         self.assertEqual(lcd.path, 'dir1')


Mime
View raw message