diff --git a/src/main/scala/app/RepositoryViewerServlet.scala b/src/main/scala/app/RepositoryViewerServlet.scala index 4f25f8c..ac48549 100644 --- a/src/main/scala/app/RepositoryViewerServlet.scala +++ b/src/main/scala/app/RepositoryViewerServlet.scala @@ -7,7 +7,12 @@ import java.util.Date import org.eclipse.jgit.api.Git import org.eclipse.jgit.lib._ +import org.eclipse.jgit.revwalk._ import org.apache.commons.io.FileUtils +import org.eclipse.jgit.revwalk.RevWalk +import org.eclipse.jgit.treewalk.CanonicalTreeParser +import org.eclipse.jgit.diff.DiffEntry.ChangeType +import org.eclipse.jgit.errors.MissingObjectException case class RepositoryInfo(owner: String, name: String, url: String, branchList: List[String], tags: List[String]) @@ -15,6 +20,8 @@ case class CommitInfo(id: String, time: Date, committer: String, message: String) +case class DiffInfo(changeType: ChangeType, oldPath: String, newPath: String, oldContent: Option[String], newContent: Option[String]) + /** * The repository viewer. */ @@ -32,7 +39,7 @@ * Shows the file list of the repository root and the default branch. */ get("/:owner/:repository") { - val owner = params("owner") + val owner = params("owner") val repository = params("repository") fileList(owner, repository) @@ -42,7 +49,7 @@ * Shows the file list of the repository root and the specified branch. */ get("/:owner/:repository/tree/:branch") { - val owner = params("owner") + val owner = params("owner") val repository = params("repository") fileList(owner, repository, params("branch")) @@ -52,7 +59,7 @@ * Shows the file list of the specified path and branch. */ get("/:owner/:repository/tree/:branch/*") { - val owner = params("owner") + val owner = params("owner") val repository = params("repository") fileList(owner, repository, params("branch"), multiParams("splat").head) @@ -62,12 +69,11 @@ * Shows the commit list of the specified branch. */ get("/:owner/:repository/commits/:branch"){ - val owner = params("owner") + val owner = params("owner") val repository = params("repository") - val branchName = params("branch") - val page = params.getOrElse("page", "1").toInt - val dir = getBranchDir(owner, repository, branchName) + val page = params.getOrElse("page", "1").toInt + val dir = getBranchDir(owner, repository, branchName) // TODO Do recursive without var. val i = Git.open(dir).log.call.iterator @@ -91,14 +97,12 @@ * Shows the file content of the specified branch. */ get("/:owner/:repository/blob/:branch/*"){ - val owner = params("owner") + val owner = params("owner") val repository = params("repository") - val branchName = params("branch") - val path = multiParams("splat").head.replaceFirst("^tree/.+?/", "") - - val dir = getBranchDir(owner, repository, branchName) - val content = FileUtils.readFileToString(new File(dir, path), "UTF-8") + val path = multiParams("splat").head.replaceFirst("^tree/.+?/", "") + val dir = getBranchDir(owner, repository, branchName) + val content = FileUtils.readFileToString(new File(dir, path), "UTF-8") val git = Git.open(dir) val latestRev = git.log.addPath(path).call.iterator.next @@ -108,6 +112,54 @@ } /** + * Shows details of the specified commit. + */ + get("/:owner/:repository/commit/:id"){ + val owner = params("owner") + val repository = params("repository") + val id = params("id") + + val repositoryInfo = getRepositoryInfo(owner, repository) + + // get branch by commit id + val branch = repositoryInfo.branchList.find { branch => + val git = Git.open(getBranchDir(owner, repository, branch)) + git.log.add(ObjectId.fromString(id)).call.iterator.hasNext + }.get + + val dir = getBranchDir(owner, repository, branch) + val git = Git.open(dir) + val rev = git.log.add(ObjectId.fromString(id)).call.iterator.next + + // get diff + val reader = git.getRepository.newObjectReader + + val oldTreeIter = new CanonicalTreeParser + oldTreeIter.reset(reader, git.getRepository.resolve(id + "^{tree}")) + + // TODO specify previous commit + val newTreeIter = new CanonicalTreeParser + newTreeIter.reset(reader, git.getRepository.resolve("HEAD^{tree}")) + + import scala.collection.JavaConverters._ + val diffs = git.diff.setNewTree(newTreeIter).setOldTree(oldTreeIter).call.asScala.map { diff => + DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath, + getContent(git, diff.getOldId.toObjectId), + getContent(git, diff.getNewId.toObjectId)) + } + + html.commit(branch, + CommitInfo(rev.getName, rev.getCommitterIdent.getWhen, rev.getCommitterIdent.getName, rev.getFullMessage), + repositoryInfo, diffs) + } + + def getContent(git: Git, id: ObjectId): Option[String] = try { + Some(new String(git.getRepository.getObjectDatabase.open(id).getBytes())) + } catch { + case e: MissingObjectException => None + } + + /** * Returns the repository information. It contains branch names and tag names. * * @param owner the repository owner diff --git a/src/main/scala/view/helpers.scala b/src/main/scala/view/helpers.scala index 63a09fe..12db0e1 100644 --- a/src/main/scala/view/helpers.scala +++ b/src/main/scala/view/helpers.scala @@ -4,14 +4,23 @@ object helpers { - def datetime(date: Date): String = { - new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(date) - } + /** + * Format java.util.Date to "yyyy/MM/dd HH:mm:ss". + */ + def datetime(date: Date): String = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(date) - def date(date: Date): String = { - new SimpleDateFormat("yyyy/MM/dd").format(date) - } + /** + * Format java.util.Date to "yyyy/MM/dd". + */ + def date(date: Date): String = new SimpleDateFormat("yyyy/MM/dd").format(date) + // TODO escape html tags using HtmlEscapeUtils (Commons Lang) + def text(value: String): twirl.api.Html = twirl.api.Html( + value.replaceAll(" ", " ").replaceAll("\t", "    ").replaceAll("\n", "
")) + + /** + * Cut the given string by specified length. + */ def cut(message: String, length: Int): String = { if(message.length > length){ message.substring(0, length) + "..." diff --git a/src/main/twirl/commit.scala.html b/src/main/twirl/commit.scala.html new file mode 100644 index 0000000..68fec95 --- /dev/null +++ b/src/main/twirl/commit.scala.html @@ -0,0 +1,41 @@ +@(branch: String, commit: app.CommitInfo, repository: app.RepositoryInfo, diffs: Seq[app.DiffInfo])(implicit context: app.Context) +@import context._ +@import view.helpers._ +@main(cut(commit.message, 20)){ + @header(branch, repository) + @navtab(branch, repository, "commits") + + + + + + + +
+
@text(commit.message)
+
@branch
+
+ @commit.committer @datetime(commit.time) +
+ commit @commit.id +
+
+ + @diffs.map { diff => + + + + + + + +
+ @diff.newPath + +
+
@diff.newContent.getOrElse("")
+
+ } +} \ No newline at end of file diff --git a/src/main/twirl/commits.scala.html b/src/main/twirl/commits.scala.html index 64e4334..22cd0f2 100644 --- a/src/main/twirl/commits.scala.html +++ b/src/main/twirl/commits.scala.html @@ -23,8 +23,8 @@
- @commit.id.substring(0, 10)@**@
- Browse code@**@ + @commit.id.substring(0, 10)
+ Browse code
diff --git a/src/main/twirl/files.scala.html b/src/main/twirl/files.scala.html index a0d579d..f356fe1 100644 --- a/src/main/twirl/files.scala.html +++ b/src/main/twirl/files.scala.html @@ -17,7 +17,7 @@ @view.helpers.cut(latestCommit.message, 100)
@view.helpers.datetime(latestCommit.time) - @latestCommit.id.substring(0, 10) + @latestCommit.id.substring(0, 10)