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()