|
... |
|
... |
16 |
from ming import schema as S
|
16 |
from ming import schema as S
|
17 |
from ming.utils import LazyProperty
|
17 |
from ming.utils import LazyProperty
|
18 |
from ming.orm import FieldProperty, session, Mapper
|
18 |
from ming.orm import FieldProperty, session, Mapper
|
19 |
from ming.orm.declarative import MappedClass
|
19 |
from ming.orm.declarative import MappedClass
|
20 |
|
20 |
|
21 |
|
|
|
22 |
from allura.lib.patience import SequenceMatcher
|
21 |
from allura.lib.patience import SequenceMatcher
|
23 |
from allura.lib import helpers as h
|
22 |
from allura.lib import helpers as h
|
24 |
from allura.lib import utils
|
23 |
from allura.lib import utils
|
25 |
|
24 |
|
26 |
from .artifact import Artifact, VersionedArtifact, Feed
|
25 |
from .artifact import Artifact, VersionedArtifact, Feed
|
27 |
from .auth import User
|
26 |
from .auth import User
|
28 |
from .session import repository_orm_session, project_orm_session
|
27 |
from .session import repository_orm_session, project_orm_session, main_doc_session
|
29 |
from .notification import Notification
|
28 |
from .notification import Notification
|
30 |
|
29 |
|
31 |
log = logging.getLogger(__name__)
|
30 |
log = logging.getLogger(__name__)
|
32 |
config = utils.ConfigProxy(
|
31 |
config = utils.ConfigProxy(
|
33 |
common_suffix='forgemail.domain',
|
32 |
common_suffix='forgemail.domain',
|
|
... |
|
... |
47 |
|
46 |
|
48 |
def commit(self, revision): # pragma no cover
|
47 |
def commit(self, revision): # pragma no cover
|
49 |
raise NotImplementedError, 'commit'
|
48 |
raise NotImplementedError, 'commit'
|
50 |
|
49 |
|
51 |
def new_commits(self, all_commits=False): # pragma no cover
|
50 |
def new_commits(self, all_commits=False): # pragma no cover
|
52 |
'''Return any commit object_ids in the native repo that are not (yet) stored
|
51 |
'''Return a list of (oid, commit) in topological order (heads first).
|
53 |
in the database in topological order (parents first)'''
|
52 |
|
|
|
53 |
"commit" is a repo-native object, NOT a Commit object.
|
|
|
54 |
If all_commits is False, only return commits not already indexed.
|
|
|
55 |
'''
|
54 |
raise NotImplementedError, 'commit'
|
56 |
raise NotImplementedError, 'new_commits'
|
|
|
57 |
|
|
|
58 |
def commit_parents(self, commit):
|
|
|
59 |
'''Return a list of (oid, commit) for the parents of the given (native)
|
|
|
60 |
commit'''
|
|
|
61 |
raise NotImplementedError, 'commit_parents'
|
55 |
|
62 |
|
56 |
def commit_context(self, object_id): # pragma no cover
|
63 |
def commit_context(self, object_id): # pragma no cover
|
57 |
'''Returns {'prev':Commit, 'next':Commit}'''
|
64 |
'''Returns {'prev':Commit, 'next':Commit}'''
|
58 |
raise NotImplementedError, 'context'
|
65 |
raise NotImplementedError, 'context'
|
59 |
|
66 |
|
|
... |
|
... |
279 |
content_type, encoding = 'text/plain', None
|
286 |
content_type, encoding = 'text/plain', None
|
280 |
if content_type is None:
|
287 |
if content_type is None:
|
281 |
content_type, encoding = 'application/octet-stream', None
|
288 |
content_type, encoding = 'application/octet-stream', None
|
282 |
return content_type, encoding
|
289 |
return content_type, encoding
|
283 |
|
290 |
|
|
|
291 |
def refresh_ancestor_graph(self, commits):
|
|
|
292 |
'''Make sure the CommitAncestor collection is up-to-date based on
|
|
|
293 |
the given list of (oid, native_commit) commits
|
|
|
294 |
'''
|
|
|
295 |
PAGESIZE = 1024
|
|
|
296 |
ca_doc = mapper(CommitAncestor).doc_cls
|
|
|
297 |
sess = main_doc_session
|
|
|
298 |
ancestor_cache = {} # ancestor_cache[oid] = [ a_oid0, a_oid1...]
|
|
|
299 |
def _ancestors(oid, ci, indent=''):
|
|
|
300 |
if oid in ancestor_cache:
|
|
|
301 |
return ancestor_cache[oid]
|
|
|
302 |
stored_ancestors = []
|
|
|
303 |
for ca in sess.find(ca_doc, dict(object_id=oid)):
|
|
|
304 |
stored_ancestors.extend(ca.ancestor_ids)
|
|
|
305 |
if stored_ancestors:
|
|
|
306 |
# Ancestors already stored in MongoDB
|
|
|
307 |
ancestor_cache[oid] = stored_ancestors
|
|
|
308 |
return stored_ancestors
|
|
|
309 |
ancestor_ids = set()
|
|
|
310 |
for p_oid, p_ci in self._impl.commit_parents(ci):
|
|
|
311 |
ancestor_ids.add(p_oid)
|
|
|
312 |
ancestor_ids.update(_ancestors(p_oid, p_ci, indent + ' '))
|
|
|
313 |
result = ancestor_cache[oid] = list(ancestor_ids)
|
|
|
314 |
for i in xrange(0, len(result), PAGESIZE):
|
|
|
315 |
sess.insert(ca_doc(
|
|
|
316 |
dict(
|
|
|
317 |
object_id=oid,
|
|
|
318 |
ancestor_ids=result[i:i+PAGESIZE])))
|
|
|
319 |
|
|
|
320 |
# Compute graph in chunks to save memory
|
|
|
321 |
for i, (oid, ci) in enumerate(reversed(commits)):
|
|
|
322 |
_ancestors(oid, ci)
|
|
|
323 |
if i and i % PAGESIZE == 0:
|
|
|
324 |
log.info('=== Clear ancestor cache === ')
|
|
|
325 |
ancestor_cache = {}
|
|
|
326 |
|
284 |
def refresh(self, all_commits=False, notify=True):
|
327 |
def refresh(self, all_commits=False, notify=True):
|
285 |
'''Find any new commits in the repository and update'''
|
328 |
'''Find any new commits in the repository and update'''
|
286 |
self._impl.refresh_heads()
|
329 |
self._impl.refresh_heads()
|
287 |
self.status = 'analyzing'
|
330 |
self.status = 'analyzing'
|
288 |
session(self).flush()
|
331 |
session(self).flush()
|
289 |
sess = session(Commit)
|
332 |
sess = session(Commit)
|
290 |
log.info('Refreshing repository %s', self)
|
333 |
log.info('Refreshing repository %s', self)
|
291 |
commit_ids = self._impl.new_commits(all_commits)
|
334 |
commits = self._impl.new_commits(all_commits)
|
292 |
log.info('... %d new commits', len(commit_ids))
|
335 |
log.info('... %d new commits', len(commits))
|
|
|
336 |
self.refresh_ancestor_graph(commits)
|
|
|
337 |
|
|
|
338 |
|
|
|
339 |
return
|
293 |
# Refresh history
|
340 |
# Refresh history
|
294 |
i=0
|
341 |
i=0
|
295 |
seen_object_ids = set()
|
342 |
seen_object_ids = set()
|
296 |
commit_msgs = []
|
343 |
commit_msgs = []
|
297 |
for i, oid in enumerate(commit_ids):
|
344 |
for i, oid in enumerate(commit_ids):
|
|
... |
|
... |
621 |
lc, new = cls.upsert('$' + object_id)
|
668 |
lc, new = cls.upsert('$' + object_id)
|
622 |
if not lc.object_ids:
|
669 |
if not lc.object_ids:
|
623 |
lc.object_ids, lc.candidates = repo._impl.log(object_id, 0, 50)
|
670 |
lc.object_ids, lc.candidates = repo._impl.log(object_id, 0, 50)
|
624 |
return lc
|
671 |
return lc
|
625 |
|
672 |
|
|
|
673 |
class CommitAncestor(MappedClass):
|
|
|
674 |
class __mongometa__:
|
|
|
675 |
session = repository_orm_session
|
|
|
676 |
name='commit_ancestor'
|
|
|
677 |
indexes = [
|
|
|
678 |
('object_id'), ('ancestor_id') ]
|
|
|
679 |
|
|
|
680 |
_id = FieldProperty(S.ObjectId)
|
|
|
681 |
object_id = FieldProperty(str)
|
|
|
682 |
ancestor_ids = FieldProperty([str])
|
|
|
683 |
|
|
|
684 |
@LazyProperty
|
|
|
685 |
def ancestor(self):
|
|
|
686 |
ci = Commit.query.get(object_id=self.ancestor_id)
|
|
|
687 |
if ci is None: return ci
|
|
|
688 |
ci.set_context(self.repo)
|
|
|
689 |
|
626 |
class Commit(RepoObject):
|
690 |
class Commit(RepoObject):
|
627 |
class __mongometa__:
|
691 |
class __mongometa__:
|
628 |
polymorphic_identity='commit'
|
692 |
polymorphic_identity='commit'
|
629 |
type_s = 'Commit'
|
693 |
type_s = 'Commit'
|
630 |
|
694 |
|