--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -80,33 +80,6 @@
allura.tasks.repo_tasks.refresh.post()
return self._impl.commit(last_id)
- def get_last_commit(self, obj):
- lc, isnew = M.LastCommitFor.upsert(repo_id=self._id, object_id=obj.object_id)
- if not isnew and lc.last_commit.id:
- return lc.last_commit
- try:
- info = self._impl._svn.info2(
- self._impl._url + obj.path(),
- revision=self._impl._revision(obj.commit.object_id),
- depth=pysvn.depth.empty)[0][1]
- lc.last_commit.author = lc.last_commit.author_email = info.last_changed_author
- lc.last_commit.date = datetime.utcfromtimestamp(info.last_changed_date)
- lc.last_commit.id = self._impl._oid(info.last_changed_rev.number)
- lc.last_commit.href = '%s%d/' % (self.url(), info.last_changed_rev.number)
- lc.last_commit.shortlink = '[r%d]' % info.last_changed_rev.number
- lc.last_commit.summary = ''
- return lc.last_commit
- except:
- log.exception('Cannot get last commit for %s', obj)
- return dict(
- author=None,
- author_email=None,
- author_url=None,
- date=None,
- id=None,
- href=None,
- shortlink=None,
- summary=None)
class SVNCalledProcessError(Exception):
def __init__(self, cmd, returncode, stdout, stderr):
@@ -119,6 +92,7 @@
return "Command: '%s' returned non-zero exit status %s\nSTDOUT: %s\nSTDERR: %s" % \
(self.cmd, self.returncode, self.stdout, self.stderr)
+
class SVNImplementation(M.RepositoryImplementation):
post_receive_template = string.Template(
'#!/bin/bash\n'
@@ -143,7 +117,7 @@
if isinstance(commit, basestring):
object_id = commit
else:
- object_id = commit.object_id
+ object_id = commit._id
return '%s%d/' % (
self._repo.url(), self._revno(object_id))
@@ -223,7 +197,7 @@
oid = self._oid(rev)
else:
oid = rev
- result = M.Commit.query.get(object_id=oid)
+ result = M.repo.Commit.query.get(_id=oid)
if result is None: return None
result.set_context(self._repo)
return result
@@ -239,78 +213,23 @@
return oids
# Find max commit id -- everything greater than that will be "unknown"
prefix = self._oid('')
- q = M.Commit.query.find(
+ q = M.repo.Commit.query.find(
dict(
type='commit',
- object_id={'$gt':prefix},
+ _id={'$gt':prefix},
),
- dict(object_id=True)
+ dict(_id=True)
)
seen_oids = set()
for d in q.ming_cursor.cursor:
- oid = d['object_id']
+ oid = d['_id']
if not oid.startswith(prefix): break
seen_oids.add(oid)
return [
oid for oid in oids if oid not in seen_oids ]
- def commit_context(self, commit):
- revno = int(commit.object_id.split(':')[1])
- prev,next=[],[]
- if revno > 1:
- prev = [ self.commit(revno - 1) ]
- if revno < self._revno(self._repo.heads[0].object_id):
- next = [ self.commit(revno + 1) ]
- return dict(prev=prev, next=next)
-
- def refresh_commit(self, ci, seen_object_ids=None, lazy=True):
- if seen_object_ids is None: seen_object_ids = set()
- log.info('Refresh %r %r', ci, self._repo)
- revno = self._revno(ci.object_id)
- rev = self._revision(ci.object_id)
- try:
- log_entry = self._svn.log(
- self._url,
- revision_start=rev,
- limit=1,
- discover_changed_paths=True)[0]
- except pysvn.ClientError:
- log.info('ClientError processing %r %r, treating as empty', ci, self._repo, exc_info=True)
- log_entry = Object(date=0, message='', changed_paths=[])
- # Save commit metadata
- log_date = None
- if hasattr(log_entry, 'date'):
- log_date = datetime.utcfromtimestamp(log_entry.date)
- ci.committed = Object(
- name=log_entry.get('author', '--none--'),
- email='',
- date=log_date)
- ci.authored=Object(ci.committed)
- ci.message=log_entry.get("message", "--none--")
- if revno > 1:
- parent_oid = self._oid(revno - 1)
- ci.parent_ids = [ parent_oid ]
- # Save diff info
- ci.diffs.added = []
- ci.diffs.removed = []
- ci.diffs.changed = []
- ci.diffs.copied = []
- lst = dict(
- A=ci.diffs.added,
- D=ci.diffs.removed,
- M=ci.diffs.changed,
- R=ci.diffs.changed)
- if hasattr(log_entry, 'changed_paths'):
- for path in log_entry.changed_paths:
- if path.copyfrom_path:
- ci.diffs.copied.append(dict(
- old=h.really_unicode(path.copyfrom_path),
- new=h.really_unicode(path.path)))
- continue
- lst[path.action].append(h.really_unicode(path.path))
-
def refresh_commit_info(self, oid, seen_object_ids, lazy=True):
- from allura.model.repo import CommitDoc
+ from allura.model.repo import CommitDoc, DiffInfoDoc
ci_doc = CommitDoc.m.get(_id=oid)
if ci_doc and lazy: return False
revno = self._revno(oid)
@@ -349,53 +268,49 @@
ci_doc.m.insert(safe=True)
except DuplicateKeyError:
if lazy: return False
+ # Save diff info
+ di = DiffInfoDoc.make(dict(_id=ci_doc._id, differences=[]))
+ for path in log_entry.changed_paths:
+ if path.action in ('A', 'M', 'R'):
+ rhs_info = self._svn.info2(
+ self._url + h.really_unicode(path.path),
+ revision=self._revision(ci_doc._id),
+ recurse=False)[0][1]
+ rhs_id = self._obj_oid(ci_doc._id, rhs_info)
+ else:
+ rhs_id = None
+ if path.action in ('D', 'M', 'R'):
+ try:
+ lhs_info = self._svn.info2(
+ self._url + h.really_unicode(path.path),
+ revision=self._revision(ci_doc.parent_ids[0]),
+ recurse=False)[0][1]
+ lhs_id = self._obj_oid(ci_doc._id, lhs_info)
+ except pysvn.ClientError, e:
+ # pysvn will sometimes report new files as 'M'odified,
+ # causing info2() to raise ClientError since the file
+ # doesn't exist in the parent revision. Set lhs_id = None
+ # to treat like a newly added file.
+ log.debug(e)
+ lhs_id = None
+ else:
+ lhs_id = None
+ di.differences.append(dict(
+ name=h.really_unicode(path.path),
+ lhs_id=lhs_id,
+ rhs_id=rhs_id))
+ di.m.save()
return True
-
- def compute_tree(self, commit, tree_path='/'):
- tree_path = tree_path[:-1]
- tree_id = self._tree_oid(commit.object_id, tree_path)
- tree, isnew = M.Tree.upsert(tree_id)
- if not isnew: return tree_id
- log.debug('Computing tree for %s: %s',
- self._revno(commit.object_id), tree_path)
- rev = self._revision(commit.object_id)
- try:
- infos = self._svn.info2(
- self._url + tree_path,
- revision=rev,
- depth=pysvn.depth.immediates)
- except pysvn.ClientError:
- log.exception('Error computing tree for %s: %s(%s)',
- self._repo, commit, tree_path)
- tree.delete()
- return None
- gl_tree = GitLikeTree()
- log.debug('Compute tree for %d paths', len(infos))
- for path, info in infos[1:]:
- if info.kind == pysvn.node_kind.dir:
- oid = self._tree_oid(commit.object_id, path)
- gl_tree.set_blob(path, oid)
- elif info.kind == pysvn.node_kind.file:
- oid = self._blob_oid(commit.object_id, path)
- gl_tree.set_blob(path, oid)
- M.Blob.upsert(oid)
- else:
- assert False
- tree.object_ids = [
- Object(object_id=oid, name=name)
- for name, oid in gl_tree.blobs.iteritems() ]
- session(tree).flush(tree)
- return tree_id
def compute_tree_new(self, commit, tree_path='/'):
from allura.model import repo as RM
tree_path = tree_path[:-1]
- tree_id = self._tree_oid(commit.object_id, tree_path)
+ tree_id = self._tree_oid(commit._id, tree_path)
tree, isnew = RM.Tree.upsert(tree_id)
if not isnew: return tree_id
log.debug('Computing tree for %s: %s',
- self._revno(commit.object_id), tree_path)
- rev = self._revision(commit.object_id)
+ self._revno(commit._id), tree_path)
+ rev = self._revision(commit._id)
try:
infos = self._svn.info2(
self._url + tree_path,
@@ -408,13 +323,19 @@
return None
log.debug('Compute tree for %d paths', len(infos))
for path, info in infos[1:]:
+ last_commit_id = self._oid(info['last_changed_rev'].number)
+ last_commit = M.repo.Commit.query.get(_id=last_commit_id)
+ M.repo_refresh.set_last_commit(
+ self._repo._id,
+ self._tree_oid(commit._id, path),
+ M.repo_refresh.get_commit_info(last_commit))
if info.kind == pysvn.node_kind.dir:
tree.tree_ids.append(Object(
- id=self._tree_oid(commit.object_id, path),
+ id=self._tree_oid(commit._id, path),
name=path))
elif info.kind == pysvn.node_kind.file:
tree.blob_ids.append(Object(
- id=self._tree_oid(commit.object_id, path),
+ id=self._tree_oid(commit._id, path),
name=path))
else:
assert False
@@ -428,6 +349,13 @@
def _blob_oid(self, commit_id, path):
data = 'blob\n%s\n%s' % (commit_id, h.really_unicode(path))
return sha1(data.encode('utf-8')).hexdigest()
+
+ def _obj_oid(self, commit_id, info):
+ path = info.URL[len(info.repos_root_URL):]
+ if info.kind == pysvn.node_kind.dir:
+ return self._tree_oid(commit_id, path)
+ else:
+ return self._blob_oid(commit_id, path)
def log(self, object_id, skip, count):
revno = self._revno(object_id)
@@ -447,7 +375,7 @@
def open_blob(self, blob):
data = self._svn.cat(
self._url + blob.path(),
- revision=self._revision(blob.commit.object_id))
+ revision=self._revision(blob.commit._id))
return StringIO(data)
def blob_size(self, blob):