Switch to side-by-side view

--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -10,23 +10,25 @@
 from collections import defaultdict
 
 import tg
-from pylons import c,g
+from paste.deploy.converters import asbool
+from pylons import c,g, request
 import pymongo.errors
 
 from ming import schema as S
+from ming.base import Object
 from ming.utils import LazyProperty
 from ming.orm import FieldProperty, session, Mapper
 from ming.orm.declarative import MappedClass
 
-
 from allura.lib.patience import SequenceMatcher
 from allura.lib import helpers as h
 from allura.lib import utils
 
 from .artifact import Artifact, VersionedArtifact, Feed
 from .auth import User
-from .session import repository_orm_session, project_orm_session
+from .session import repository_orm_session, project_orm_session, main_doc_session
 from .notification import Notification
+from .repo_refresh import refresh_repo
 
 log = logging.getLogger(__name__)
 config = utils.ConfigProxy(
@@ -35,7 +37,6 @@
 
 README_RE = re.compile('^README(\.[^.]*)?$', re.IGNORECASE)
 
-
 class RepositoryImplementation(object):
 
     # Repository-specific code
@@ -48,10 +49,21 @@
     def commit(self, revision): # pragma no cover
         raise NotImplementedError, 'commit'
 
+    def all_commit_ids(self): # pragma no cover
+        raise NotImplementedError, 'all_commit_ids'
+
     def new_commits(self, all_commits=False): # pragma no cover
-        '''Return any commit object_ids in the native repo that are not (yet) stored
-        in the database in topological order (parents first)'''
-        raise NotImplementedError, 'commit'
+        '''Return a list of native commits in topological order (heads first).
+
+        "commit" is a repo-native object, NOT a Commit object.
+        If all_commits is False, only return commits not already indexed.
+        '''
+        raise NotImplementedError, 'new_commits'
+
+    def commit_parents(self, commit):
+        '''Return a list of native commits for the parents of the given (native)
+        commit'''
+        raise NotImplementedError, 'commit_parents'
 
     def commit_context(self, object_id): # pragma no cover
         '''Returns {'prev':Commit, 'next':Commit}'''
@@ -64,6 +76,10 @@
     def refresh_commit(self, ci, seen_object_ids): # pragma no cover
         '''Refresh the data in the commit object 'ci' with data from the repo'''
         raise NotImplementedError, 'refresh_commit'
+
+    def refresh_commit_info(self, oid): # pragma no cover
+        '''Refresh the data in the commit with id oid'''
+        raise NotImplementedError, 'refresh_commit_info'
 
     def _setup_hooks(self): # pragma no cover
         '''Install a hook in the repository that will ping the refresh url for
@@ -71,22 +87,27 @@
         raise NotImplementedError, '_setup_hooks'
 
     def log(self, object_id, skip, count): # pragma no cover
-        '''Return a list of object_ids beginning at the given commit ID and continuing
+        '''Return a list of (object_id, ci) beginning at the given commit ID and continuing
         to the parent nodes in a breadth-first traversal.  Also return a list of 'next commit' options
         (these are candidates for he next commit after 'count' commits have been
         exhausted).'''
-        raise NotImplementedError, '_log'
+        raise NotImplementedError, 'log'
 
     def compute_tree(self, commit, path='/'):
         '''Used in hg and svn to compute a git-like-tree lazily'''
         raise NotImplementedError, 'compute_tree'
 
+    def compute_tree_new(self, commit, path='/'):
+        '''Used in hg and svn to compute a git-like-tree lazily with the new models'''
+        raise NotImplementedError, 'compute_tree'
+
     def open_blob(self, blob): # pragma no cover
         '''Return a file-like object that contains the contents of the blob'''
         raise NotImplementedError, 'open_blob'
 
-    def shorthand_for_commit(self, commit):
-        return '[%s]' % commit.object_id[:6]
+    @classmethod
+    def shorthand_for_commit(cls, oid):
+        return '[%s]' % oid[:6]
 
     def symbolics_for_commit(self, commit):
         '''Return symbolic branch and tag names for a commit.
@@ -97,7 +118,12 @@
         return branches, tags
 
     def url_for_commit(self, commit):
-        return '%sci/%s/' % (self._repo.url(), commit.object_id)
+        'return an URL, given either a commit or object id'
+        if isinstance(commit, basestring):
+            object_id = commit
+        else:
+            object_id = commit.object_id
+        return '%sci/%s/' % (self._repo.url(), object_id)
 
     def _setup_paths(self, create_repo_dir=True):
         if not self._repo.fs_path.endswith('/'): self._repo.fs_path += '/'
@@ -167,18 +193,24 @@
         return self._impl.init()
     def commit(self, rev):
         return self._impl.commit(rev)
+    def all_commit_ids(self):
+        return self._impl.all_commit_ids()
+    def refresh_commit_info(self, oid, seen):
+        return self._impl.refresh_commit_info(oid, seen)
     def commit_context(self, commit):
         return self._impl.commit_context(commit)
     def open_blob(self, blob):
         return self._impl.open_blob(blob)
-    def shorthand_for_commit(self, commit):
-        return self._impl.shorthand_for_commit(commit)
+    def shorthand_for_commit(self, oid):
+        return self._impl.shorthand_for_commit(oid)
     def symbolics_for_commit(self, commit):
         return self._impl.symbolics_for_commit(commit)
     def url_for_commit(self, commit):
         return self._impl.url_for_commit(commit)
     def compute_tree(self, commit, path='/'):
         return self._impl.compute_tree(commit, path)
+    def compute_tree_new(self, commit, path='/'):
+        return self._impl.compute_tree_new(commit, path)
 
     def _log(self, rev, skip, max_count):
         ci = self.commit(rev)
@@ -284,6 +316,10 @@
     def refresh(self, all_commits=False, notify=True):
         '''Find any new commits in the repository and update'''
         self._impl.refresh_heads()
+        if asbool(tg.config.get('scm.new_refresh')):
+            refresh_repo(self, all_commits, notify)
+            notify = False # don't double notify
+
         self.status = 'analyzing'
         session(self).flush()
         sess = session(Commit)
@@ -291,16 +327,15 @@
         commit_ids = self._impl.new_commits(all_commits)
         log.info('... %d new commits', len(commit_ids))
         # Refresh history
-        i=0
         seen_object_ids = set()
         commit_msgs = []
+        i=0
         for i, oid in enumerate(commit_ids):
             if len(seen_object_ids) > 10000: # pragma no cover
                 log.info('... flushing seen object cache')
                 seen_object_ids = set()
             ci, isnew = Commit.upsert(oid)
             if not isnew and not all_commits:
-                 # race condition, let the other proc handle it
                 sess.expunge(ci)
                 continue
             ci.set_context(self)
@@ -339,7 +374,7 @@
                 subject=subject,
                 text=text)
         log.info('...... flushing %d commits (%d total)',
-                 i % self.BATCH_SIZE, i)
+                 (i+1) % self.BATCH_SIZE, i+1)
         sess.flush()
         sess.clear()
         # Mark all commits in this repo as being in this repo
@@ -378,7 +413,7 @@
                 sess.flush()
                 sess.clear()
         log.info('...... flushing %d commits (%d total)',
-                 i % self.BATCH_SIZE, i)
+                 (i+1) % self.BATCH_SIZE, i+1)
         sess.flush()
         sess.clear()
 
@@ -700,7 +735,7 @@
         return self.tree.get_blob(path_parts[-1], path_parts[:-1])
 
     def shorthand_id(self):
-        return self.repo.shorthand_for_commit(self)
+        return self.repo.shorthand_for_commit(self.object_id)
 
     @LazyProperty
     def symbolic_ids(self):
@@ -784,7 +819,7 @@
     '''
     A representation of files & directories.  E.g. what is present at a single commit
 
-    :var object_ids: dict(object_id: name)  Set by _refresh_tree in the scm implementation
+    :var object_ids: dict(object_id: name)  Set by refresh_tree in the scm implementation
     '''
     class __mongometa__:
         polymorphic_identity='tree'