Switch to side-by-side view

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