kjkmadness 2014-01-29
code: new feature - revision compare
@4544c088215ab121f5301abf4ca788611a57feef
 
app/controllers/CompareApp.java (added)
+++ app/controllers/CompareApp.java
@@ -0,0 +1,65 @@
+/**
+ * Yobi, Project Hosting SW
+ *
+ * Copyright 2013 NAVER Corp.
+ * http://yobi.io
+ *
+ * @Author kjkmadness
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package controllers;
+
+import java.util.List;
+
+import controllers.annotation.IsAllowed;
+import models.Project;
+import models.enumeration.Operation;
+import play.mvc.Controller;
+import play.mvc.Result;
+import playRepository.Commit;
+import playRepository.FileDiff;
+import playRepository.PlayRepository;
+import playRepository.RepositoryService;
+import utils.ErrorViews;
+import views.html.code.compare_svn;
+import views.html.code.compare;
+
+public class CompareApp extends Controller {
+    @IsAllowed(Operation.READ)
+    public static Result compare(String ownerName, String projectName, String revA, String revB)
+            throws Exception {
+        Project project = Project.findByOwnerAndProjectName(ownerName, projectName);
+        PlayRepository repository = RepositoryService.getRepository(project);
+        Commit commitA = repository.getCommit(revA);
+        Commit commitB = repository.getCommit(revB);
+
+        if (commitA == null || commitB == null) {
+            return notFound(ErrorViews.NotFound.render("error.notfound.commit", project));
+        }
+
+        if (RepositoryService.VCS_SUBVERSION.equals(project.vcs)) {
+            String patch = repository.getPatch(revA, revB);
+            if (patch == null) {
+                return notFound(ErrorViews.NotFound.render("error.notfound", project));
+            }
+            return ok(compare_svn.render(project, commitA, commitB, patch));
+        } else {
+            List<FileDiff> diffs = repository.getDiff(revA, revB);
+            if (diffs == null) {
+                return notFound(ErrorViews.NotFound.render("error.notfound", project));
+            }
+            return ok(compare.render(project, commitA, commitB, diffs));
+        }
+    }
+}
app/playRepository/GitRepository.java
--- app/playRepository/GitRepository.java
+++ app/playRepository/GitRepository.java
@@ -576,32 +576,55 @@
      */
     @Override
     public String getPatch(String rev) throws IOException {
-        // Get the trees, from current commit and its parent, as treeWalk.
-        ObjectId commitId = repository.resolve(rev);
+        RevCommit commit = getRevCommit(rev);
 
-        if (commitId == null) {
+        if (commit == null) {
             return null;
         }
 
-        TreeWalk treeWalk = new TreeWalk(repository);
-        RevWalk revWalk = new RevWalk(repository);
-        RevCommit commit = revWalk.parseCommit(commitId);
+        RevCommit parent = null;
         if (commit.getParentCount() > 0) {
-            RevTree tree = revWalk.parseCommit(commit.getParent(0).getId()).getTree();
-            treeWalk.addTree(tree);
-        } else {
-            treeWalk.addTree(new EmptyTreeIterator());
+            parent = commit.getParent(0);
         }
-        treeWalk.addTree(commit.getTree());
 
-        // Render the difference from treeWalk which has two trees.
+        return getPatch(parent, commit);
+    }
+
+    @Override
+    public String getPatch(String revA, String revB) throws IOException {
+        RevCommit commitA = getRevCommit(revA);
+        RevCommit commitB = getRevCommit(revB);
+
+        if (commitA == null || commitB == null) {
+            return null;
+        }
+
+        return getPatch(commitA, commitB);
+    }
+
+    /*
+     * Render the difference from treeWalk which has two trees.
+     */
+    private String getPatch(RevCommit commitA, RevCommit commitB) throws IOException {
+        TreeWalk treeWalk = new TreeWalk(repository);
+        addTree(treeWalk, commitA);
+        addTree(treeWalk, commitB);
+        treeWalk.setRecursive(true);
+
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         DiffFormatter diffFormatter = new DiffFormatter(out);
         diffFormatter.setRepository(repository);
-        treeWalk.setRecursive(true);
         diffFormatter.format(DiffEntry.scan(treeWalk));
 
         return out.toString("UTF-8");
+    }
+
+    private void addTree(TreeWalk treeWalk, RevCommit commit) throws IOException {
+        if (commit == null) {
+            treeWalk.addTree(new EmptyTreeIterator());
+        } else {
+            treeWalk.addTree(commit.getTree());
+        }
     }
 
     /**
@@ -1352,6 +1375,7 @@
         return getDiff(repository, revA, repository, revB);
     }
 
+    @Override
     public List<FileDiff> getDiff(String revA, String revB) throws IOException {
         return getDiff(this.repository, revA, revB);
     }
app/playRepository/PlayRepository.java
--- app/playRepository/PlayRepository.java
+++ app/playRepository/PlayRepository.java
@@ -71,8 +71,12 @@
      */
     public abstract String getPatch(String commitId) throws IOException, SVNException;
 
+    String getPatch(String revA, String revB) throws IOException, SVNException;
+
     public abstract List<FileDiff> getDiff(String commitId) throws IOException;
 
+    List<FileDiff> getDiff(String revA, String revB) throws IOException;
+
     /**
      * {@code untilRevName}에 해당하는 리비전까지의 커밋 목록을 반환한다.
      *
app/playRepository/SVNRepository.java
--- app/playRepository/SVNRepository.java
+++ app/playRepository/SVNRepository.java
@@ -227,9 +227,18 @@
 
     @Override
     public String getPatch(String commitId) throws SVNException {
+        long rev = Integer.parseInt(commitId);
+        return getPatch(rev - 1, rev);
+    }
+
+    @Override
+    public String getPatch(String revA, String revB) throws SVNException {
+        return getPatch(Long.parseLong(revA), Long.parseLong(revB));
+    }
+
+    private String getPatch(long revA, long revB) throws SVNException {
         // Prepare required arguments.
         SVNURL svnURL = SVNURL.fromFile(new File(getRepoPrefix() + ownerName + "/" + projectName));
-        long rev = Integer.parseInt(commitId);
 
         // Get diffClient.
         SVNClientManager clientManager = SVNClientManager.newInstance();
@@ -238,9 +247,8 @@
         // Using diffClient, write the changes by commitId into
         // byteArrayOutputStream, as unified format.
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        diffClient.doDiff(svnURL, null, SVNRevision.create(rev - 1), SVNRevision.create(rev),
+        diffClient.doDiff(svnURL, null, SVNRevision.create(revA), SVNRevision.create(revB),
                 SVNDepth.INFINITY, true, byteArrayOutputStream);
-
 
         return byteArrayOutputStream.toString();
     }
@@ -251,6 +259,11 @@
     }
 
     @Override
+    public List<FileDiff> getDiff(String revA, String revB) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public List<Commit> getHistory(int page, int limit, String until, String path) throws
             IOException, GitAPIException, SVNException {
         // Get the repository
 
app/views/code/compare.scala.html (added)
+++ app/views/code/compare.scala.html
@@ -0,0 +1,45 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2013 NAVER Corp.
+* http://yobi.io
+*
+* @Author kjkmadness
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+@(project: Project, commitA: playRepository.Commit, commitB: playRepository.Commit, diff: List[playRepository.FileDiff])
+@projectLayout(commitA.getId + ".." + commitB.getId, project, utils.MenuType.CODE) {
+@projectMenu(project, utils.MenuType.CODE, "main-menu-only")
+<div class="project-page-wrap">
+    <div class="code-browse-wrap">
+        <p class="commitInfo">
+            <strong class="commitId">@{"@"}@commitA.getId..@commitB.getId</strong>
+        </p>
+        @if(diff.isEmpty){
+          <div class="alert">@Messages("code.noChanges")</div>
+        } else {
+          <div class="diff-body">
+          @views.html.partial_diff(diff, null, project, project)
+          </div>
+        }
+    </div>
+</div>
+<script type="text/javascript">
+    $(document).ready(function(){
+        $yobi.loadModule("code.Diff", {
+            "bCommentable": false,
+        });
+    });
+</script>
+}
 
app/views/code/compare_svn.scala.html (added)
+++ app/views/code/compare_svn.scala.html
@@ -0,0 +1,53 @@
+@**
+* Yobi, Project Hosting SW
+*
+* Copyright 2013 NAVER Corp.
+* http://yobi.io
+*
+* @Author kjkmadness
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+**@
+@(project: Project, commitA: playRepository.Commit, commitB: playRepository.Commit, patch: String)
+
+@import org.apache.commons.lang3.StringUtils
+
+@projectLayout(commitA.getId + ".." + commitB.getId, project, utils.MenuType.CODE) {
+@projectMenu(project, utils.MenuType.CODE, "main-menu-only")
+<div class="project-page-wrap">
+    <div class="code-browse-wrap">
+        <p class="commitInfo">
+            <strong class="commitId">@{"@"}@commitA.getId..@commitB.getId</strong>
+        </p>
+        @if(StringUtils.isEmpty(patch)){
+          <div class="alert">@Messages("code.noChanges")</div>
+        } else {
+          <div class="diff-wrap">
+              <div id="commit" data-commit-origin="true" class="diff-body hide">@patch</div>
+          </div>
+        }
+    </div>
+</div>
+@common.mergely()
+<script type="text/javascript">
+    $(document).ready(function(){
+        $yobi.loadModule("code.SvnDiff", {
+            "bCommentable"   : false,
+            "sParentCommitId": "@commitA.getId",
+            "sCommitId"      : "@commitB.getId",
+            "sTplFileURL"    : "@routes.CodeApp.codeBrowserWithBranch(project.owner, project.name, "${commitId}", "${path}")",
+            "sTplRawURL"     : "@routes.CodeApp.showRawFile(project.owner, project.name, "${commitId}", "${path}")"
+        });
+    });
+</script>
+}
conf/routes
--- conf/routes
+++ conf/routes
@@ -238,5 +238,8 @@
 POST           /:user/:project/pullRequest/:number/review                             controllers.ReviewApp.review(user, project, number: Long)
 POST           /:user/:project/pullRequest/:number/unreview                           controllers.ReviewApp.unreview(user, project, number: Long)
 
+# Compare
+GET            /:user/:project/compare/:revA..:revB                                             controllers.CompareApp.compare(user, project, revA, revB)
+
 # remove trailing slash - must be the bottom of this file
 GET            /*paths                                                                controllers.Application.removeTrailer(paths)
Add a comment
List