You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2012/10/10 04:28:29 UTC

git commit: Partial commit, WIP

Updated Branches:
  refs/heads/cj/4691 [created] 84577436f


Partial commit, WIP


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

Branch: refs/heads/cj/4691
Commit: 84577436fe684f942a446659e5843e4d74be518b
Parents: 0c25b52
Author: Cory Johns <jo...@geek.net>
Authored: Wed Oct 10 02:28:07 2012 +0000
Committer: Cory Johns <jo...@geek.net>
Committed: Wed Oct 10 02:28:07 2012 +0000

----------------------------------------------------------------------
 Allura/allura/model/repo.py                        |   60 +++++++++++----
 Allura/allura/model/repo_refresh.py                |   50 ++++++++++++
 Allura/allura/model/repository.py                  |   38 +++++++++-
 .../allura/templates/widgets/repo/tree_widget.html |   20 +++---
 ForgeGit/forgegit/model/git_repo.py                |    4 +
 ForgeHg/forgehg/model/hg.py                        |    4 +
 ForgeSVN/forgesvn/model/svn.py                     |    3 +
 7 files changed, 153 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/Allura/allura/model/repo.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repo.py b/Allura/allura/model/repo.py
index 2cbae4b..54d7c71 100644
--- a/Allura/allura/model/repo.py
+++ b/Allura/allura/model/repo.py
@@ -11,7 +11,7 @@ from difflib import SequenceMatcher, unified_diff
 from pylons import c
 import pymongo.errors
 
-from ming import Field, collection
+from ming import Field, collection, Index
 from ming import schema as S
 from ming.base import Object
 from ming.utils import LazyProperty
@@ -61,21 +61,24 @@ TreeDoc = collection(
     Field('blob_ids', [dict(name=str, id=str)]),
     Field('other_ids', [dict(name=str, id=str, type=SObjType)]))
 
-# Information about the last commit to touch a tree/blob
-# LastCommitDoc.object_id = TreeDoc._id
+# Information about the last commit to touch a tree
 LastCommitDoc = collection(
     'repo_last_commit', project_doc_session,
-    Field('_id', str),
-    Field('object_id', str, index=True),
-    Field('name', str),
-    Field('commit_info', dict(
-        id=str,
-        date=datetime,
-        author=str,
-        author_email=str,
-        author_url=str,
-        shortlink=str,
-        summary=str)))
+    Field('_id', S.ObjectId()),
+    Field('commit_ids', [str]),
+    Field('path', str),
+    Index('commit_ids', 'path'),
+    Field('entries', [dict(
+        type=str,
+        name=str,
+        commit_info=dict(
+            id=str,
+            date=datetime,
+            author=str,
+            author_email=str,
+            author_url=str,
+            shortlink=str,
+            summary=str))]))
 
 # List of all trees contained within a commit
 # TreesDoc._id = CommitDoc._id
@@ -343,6 +346,25 @@ class Commit(RepoObject):
             cur = cur[part]
         return cur
 
+    def get_parent(self, index=0):
+        '''Get the parent of this commit.
+
+        If there is no parent commit, or if an invalid index is given,
+        returns None.
+        '''
+        try:
+            return Commit.query.get(_id=self.parent_ids[index])
+        except IndexError as e:
+            return None
+
+    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
+
 class Tree(RepoObject):
     # Ephemeral attrs
     repo=None
@@ -413,6 +435,16 @@ class Tree(RepoObject):
         return None, None
 
     def ls(self):
+        last_commit = LastCommitDoc.m.find(dict(
+                commit_ids=self.commit._id,
+                tree_id=self._id,
+                path=self.path(),
+            )).first()
+        if not last_commit:
+            from .repo_refresh import build_last_commit
+            last_commit = build_last_commit_doc(self)
+        return last_commit.entries
+
         # Load last commit info
         id_re = re.compile("^{0}:{1}:".format(
             self.repo._id,

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/Allura/allura/model/repo_refresh.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repo_refresh.py b/Allura/allura/model/repo_refresh.py
index 4b8c1af..6de4aee 100644
--- a/Allura/allura/model/repo_refresh.py
+++ b/Allura/allura/model/repo_refresh.py
@@ -504,3 +504,53 @@ def last_known_commit_id(all_commit_ids, new_commit_ids):
     if not all_commit_ids: return None
     if not new_commit_ids: return all_commit_ids[-1]
     return all_commit_ids[all_commit_ids.index(new_commit_ids[0]) - 1]
+
+def build_last_commit_doc(tree):
+    '''
+    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.
+    '''
+    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()
+    while unfilled:
+        last_commit = LastCommitDoc.m.find(dict(
+                commit_ids=commit._id,
+                tree_id=tree._id,
+                path=path,
+            )).first()
+        if last_commit:
+            # found
+            last_commit.commit_ids.append(commit._id)
+            last_commit.m.save()
+            return last_commit

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 3635cbe..ac79a32 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -343,8 +343,42 @@ class Repository(Artifact, ActivityObject):
         with self.push_upstream_context():
             return MergeRequest.query.find(q).count()
 
-    def get_last_commit(self, obj):
-        from .repo import LastCommitDoc
+    def get_last_commit(self, tree):
+        '''Find the LastCommitDoc for the given tree.
+
+        Walks up the commit tree until either:
+
+        1) A 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.
+        '''
+        from .repo import Commit, LastCommitDoc
+        last_commit = None
+        commit = tree.commit
+        path = tree.path()
+        orig_tree = tree
+        other_commit_ids = []
+        while commit is not None:
+            last_commit = LastCommitDoc.m.find(dict(
+                    commit_ids=commit._id,
+                    path=path,
+                )).first()
+            if last_commit is not None:
+                # found our LCD; add any traversed commits to it
+                last_commit.commit_ids.append(commit_ids)
+                last_commit.m.save()
+                return last_commit
+            elif commit.changed(path):
+                # tree was changed but no LCD found; have to build
+                return self.compute_last_commit(commit, path, other_commit_ids)
+            else:
+                other_commit_ids.append(commit._id)
+                commit = commit.get_parent()
+
         lc = LastCommitDoc.m.get(
             repo_id=self._id, object_id=obj._id)
         if lc is None:

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/Allura/allura/templates/widgets/repo/tree_widget.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/repo/tree_widget.html b/Allura/allura/templates/widgets/repo/tree_widget.html
index 09b0758..a2d8024 100644
--- a/Allura/allura/templates/widgets/repo/tree_widget.html
+++ b/Allura/allura/templates/widgets/repo/tree_widget.html
@@ -25,24 +25,24 @@
     {% for dirent in tree.ls() %}
     <tr>
       <td class="nowrap">
-        <a href="{{h.urlquote(dirent.href)}}">
-          <b data-icon="{{dirent.kind == 'DIR' and 'o' or 'n'}}" class="ico {{dirent.kind == 'DIR' and 'folder' or 'table'}}"></b>
+        <a href="{{h.urlquote(dirent.name)}}">
+          <b data-icon="{{dirent.type == 'DIR' and 'o' or 'n'}}" class="ico {{dirent.type == 'DIR' and 'folder' or 'table'}}"></b>
           <span>{{h.really_unicode(dirent.name)}}</span>
         </a>
       </td>
-      <td class="nowrap">{{lib.abbr_date(dirent.last_commit.date)}}</td>
+      <td class="nowrap">{{lib.abbr_date(dirent.commit_info.date)}}</td>
       <td class="nowrap">
-        {% if dirent.last_commit.author_url %}
-          <a href="{{dirent.last_commit.author_url}}">{{lib.email_gravatar(dirent.last_commit.author_email, title=h.really_unicode(dirent.last_commit.author), size=16)}}</a>
-          <a href="{{dirent.last_commit.author_url}}">{{h.really_unicode(dirent.last_commit.author)}}</a>
+        {% if dirent.commit_info.author_url %}
+          <a href="{{dirent.commit_info.author_url}}">{{lib.email_gravatar(dirent.commit_info.author_email, title=h.really_unicode(dirent.commit_info.author), size=16)}}</a>
+          <a href="{{dirent.commit_info.author_url}}">{{h.really_unicode(dirent.commit_info.author)}}</a>
         {% else %}
-          {{lib.email_gravatar(dirent.last_commit.author_email, title=h.really_unicode(dirent.last_commit.author), size=16)}} {{h.really_unicode(dirent.last_commit.author)}}
+          {{lib.email_gravatar(dirent.commit_info.author_email, title=h.really_unicode(dirent.commit_info.author), size=16)}} {{h.really_unicode(dirent.commit_info.author)}}
         {% endif %}
       </td>
       <td>
-        <a href="{{dirent.last_commit.href}}">
-          {{dirent.last_commit.shortlink}}
-          {{dirent.last_commit.summary}}
+        <a href="{{dirent.commit_info.href}}">
+          {{dirent.commit_info.shortlink}}
+          {{dirent.commit_info.summary}}
         </a>
       </td>
     </tr>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/ForgeGit/forgegit/model/git_repo.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 68887af..95b4576 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -303,6 +303,10 @@ class GitImplementation(M.RepositoryImplementation):
         tree = self.refresh_tree_info(ci.tree, set())
         return tree._id
 
+    def compute_last_commit_info(self, commit, path, other_commit_ids=None):
+        if other_commit_ids is None:
+            other_commit_ids = []
+
 class _OpenedGitBlob(object):
     CHUNK_SIZE=4096
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/ForgeHg/forgehg/model/hg.py
----------------------------------------------------------------------
diff --git a/ForgeHg/forgehg/model/hg.py b/ForgeHg/forgehg/model/hg.py
index ebed574..59ca57b 100644
--- a/ForgeHg/forgehg/model/hg.py
+++ b/ForgeHg/forgehg/model/hg.py
@@ -338,4 +338,8 @@ class HgImplementation(M.RepositoryImplementation):
         tree = self.refresh_tree_info(fake_tree, set())
         return tree._id
 
+    def compute_last_commit_info(self, commit, path, other_commit_ids=None):
+        if other_commit_ids is None:
+            other_commit_ids = []
+
 Mapper.compile_all()

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/84577436/ForgeSVN/forgesvn/model/svn.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index 5e6cb81..998c747 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -366,6 +366,9 @@ class SVNImplementation(M.RepositoryImplementation):
         trees_doc.m.save(safe=False)
         return tree_id
 
+    def compute_last_commit_info(self, commit, path, other_commit_ids=None):
+        pass
+
     def _tree_oid(self, commit_id, path):
         data = 'tree\n%s\n%s' % (commit_id, h.really_unicode(path))
         return sha1(data.encode('utf-8')).hexdigest()