Improve DiffEntry searching and add download patch endpoint

This commit is contained in:
Naoki Takezoe
2017-12-05 03:31:23 +09:00
parent 2862ceb5ad
commit 8e91b9f0b5
7 changed files with 66 additions and 99 deletions

View File

@@ -35,18 +35,18 @@ case class ApiCommit(
object ApiCommit{
def apply(git: Git, repositoryName: RepositoryName, commit: CommitInfo, urlIsHtmlUrl: Boolean = false): ApiCommit = {
val diffs = JGitUtil.getDiffs(git, commit.id, false)
val diffs = JGitUtil.getDiffs(git, None, commit.id, false, false)
ApiCommit(
id = commit.id,
message = commit.fullMessage,
timestamp = commit.commitTime,
added = diffs._1.collect {
added = diffs.collect {
case x if x.changeType == DiffEntry.ChangeType.ADD => x.newPath
},
removed = diffs._1.collect {
removed = diffs.collect {
case x if x.changeType == DiffEntry.ChangeType.DELETE => x.oldPath
},
modified = diffs._1.collect {
modified = diffs.collect {
case x if x.changeType != DiffEntry.ChangeType.ADD && x.changeType != DiffEntry.ChangeType.DELETE => x.newPath
},
author = ApiPersonIdent.author(commit),

View File

@@ -655,7 +655,7 @@ trait ApiControllerBase extends ControllerBase {
JsonFormat(ApiCommits(
repositoryName = RepositoryName(repository),
commitInfo = commitInfo,
diffs = JGitUtil.getDiffs(git, commitInfo.parents.head, commitInfo.id, false, true),
diffs = JGitUtil.getDiffs(git, Some(commitInfo.parents.head), commitInfo.id, false, true),
author = getAccount(commitInfo.authorName, commitInfo.authorEmailAddress),
committer = getAccount(commitInfo.committerName, commitInfo.committerEmailAddress),
commentCount = getCommitComment(repository.owner, repository.name, sha).size

View File

@@ -451,14 +451,14 @@ trait RepositoryViewerControllerBase extends ControllerBase {
try {
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
defining(JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))) { revCommit =>
JGitUtil.getDiffs(git, id, true) match {
case (diffs, oldCommitId) =>
html.commit(id, new JGitUtil.CommitInfo(revCommit),
JGitUtil.getBranchesOfCommit(git, revCommit.getName),
JGitUtil.getTagsOfCommit(git, revCommit.getName),
getCommitComments(repository.owner, repository.name, id, true),
repository, diffs, oldCommitId, hasDeveloperRole(repository.owner, repository.name, context.loginAccount))
}
val diffs = JGitUtil.getDiffs(git, None, id, true, false)
val oldCommitId = JGitUtil.getParentCommitId(git, id)
html.commit(id, new JGitUtil.CommitInfo(revCommit),
JGitUtil.getBranchesOfCommit(git, revCommit.getName),
JGitUtil.getTagsOfCommit(git, revCommit.getName),
getCommitComments(repository.owner, repository.name, id, true),
repository, diffs, oldCommitId, hasDeveloperRole(repository.owner, repository.name, context.loginAccount))
}
}
} catch {
@@ -466,6 +466,18 @@ trait RepositoryViewerControllerBase extends ControllerBase {
}
})
get("/:owner/:repository/commit/:id/patch")(referrersOnly { repository =>
try {
using(Git.open(getRepositoryDir(repository.owner, repository.name))) { git =>
val diff = JGitUtil.getPatch(git, params("id"))
contentType = formats("txt")
diff
}
} catch {
case e:MissingObjectException => NotFound()
}
})
post("/:owner/:repository/commit/:id/comment/new", commentForm)(readableUsersOnly { (form, repository) =>
val id = params("id")
createCommitComment(repository.owner, repository.name, id, context.loginAccount.get.userName, form.content,

View File

@@ -76,7 +76,7 @@ trait WikiControllerBase extends ControllerBase {
val Array(from, to) = params("commitId").split("\\.\\.\\.")
using(Git.open(getWikiRepositoryDir(repository.owner, repository.name))){ git =>
html.compare(Some(pageName), from, to, JGitUtil.getDiffs(git, from, to, true, false).filter(_.newPath == pageName + ".md"), repository,
html.compare(Some(pageName), from, to, JGitUtil.getDiffs(git, Some(from), to, true, false).filter(_.newPath == pageName + ".md"), repository,
isEditable(repository), flash.get("info"))
}
})
@@ -85,7 +85,7 @@ trait WikiControllerBase extends ControllerBase {
val Array(from, to) = params("commitId").split("\\.\\.\\.")
using(Git.open(getWikiRepositoryDir(repository.owner, repository.name))){ git =>
html.compare(None, from, to, JGitUtil.getDiffs(git, from, to, true, false), repository,
html.compare(None, from, to, JGitUtil.getDiffs(git, Some(from), to, true, false), repository,
isEditable(repository), flash.get("info"))
}
})

View File

@@ -230,7 +230,7 @@ trait PullRequestService { self: IssuesService with CommitsService =>
helpers.date(commit1.commitTime) == view.helpers.date(commit2.commitTime)
}
val diffs = JGitUtil.getDiffs(newGit, oldId.getName, newId.getName, true, false)
val diffs = JGitUtil.getDiffs(newGit, Some(oldId.getName), newId.getName, true, false)
(commits, diffs)
}

View File

@@ -347,8 +347,8 @@ class WikiCommitHook(owner: String, repository: String, pusher: String, baseUrl:
commitIds.map { case (oldCommitId, newCommitId) =>
val commits = using(Git.open(Directory.getWikiRepositoryDir(owner, repository))) { git =>
JGitUtil.getCommitLog(git, oldCommitId, newCommitId).flatMap { commit =>
val diffs = JGitUtil.getDiffs(git, commit.id, false)
diffs._1.collect { case diff if diff.newPath.toLowerCase.endsWith(".md") =>
val diffs = JGitUtil.getDiffs(git, None, commit.id, false, false)
diffs.collect { case diff if diff.newPath.toLowerCase.endsWith(".md") =>
val action = if(diff.changeType == ChangeType.ADD) "created" else "edited"
val fileName = diff.newPath
(action, fileName, commit.id)

View File

@@ -24,8 +24,9 @@ import java.util.function.Consumer
import org.cache2k.{Cache2kBuilder, CacheEntry}
import org.eclipse.jgit.api.errors.{InvalidRefNameException, JGitInternalException, NoHeadException, RefAlreadyExistsException}
import org.eclipse.jgit.diff.{DiffEntry, DiffFormatter}
import org.eclipse.jgit.diff.{DiffEntry, DiffFormatter, RawTextComparator}
import org.eclipse.jgit.dircache.DirCacheEntry
import org.eclipse.jgit.util.io.{DisabledOutputStream, NullOutputStream}
import org.slf4j.LoggerFactory
/**
@@ -518,93 +519,47 @@ object JGitUtil {
}.toMap
}
/**
* Returns the tuple of diff of the given commit and parent commit ids.
* DiffInfos returned from this method don't include the patch property.
*/
def getDiffs(git: Git, id: String, fetchContent: Boolean): (List[DiffInfo], Option[String]) = {
@scala.annotation.tailrec
def getCommitLog(i: java.util.Iterator[RevCommit], logs: List[RevCommit]): List[RevCommit] =
i.hasNext match {
case true if(logs.size < 2) => getCommitLog(i, logs :+ i.next)
case _ => logs
}
def getPatch(git: Git, id: String): String = {
val out = new ByteArrayOutputStream()
val df = new DiffFormatter(out)
df.setRepository(git.getRepository)
df.setDiffComparator(RawTextComparator.DEFAULT)
df.setDetectRenames(true)
df.format(getDiffEntries(git, None, id, df).head)
new String(out.toByteArray, "UTF-8")
}
private def getDiffEntries(git: Git, from: Option[String], to: String, df: DiffFormatter): Seq[DiffEntry] = {
using(new RevWalk(git.getRepository)){ revWalk =>
revWalk.markStart(revWalk.parseCommit(git.getRepository.resolve(id)))
val commits = getCommitLog(revWalk.iterator, Nil)
val revCommit = commits(0)
if(commits.length >= 2){
// not initial commit
val oldCommit = if(revCommit.getParentCount >= 2) {
// merge commit
revCommit.getParents.head
} else {
commits(1)
}
(getDiffs(git, oldCommit.getName, id, fetchContent, false), Some(oldCommit.getName))
} else {
// initial commit
using(new TreeWalk(git.getRepository)){ treeWalk =>
treeWalk.setRecursive(true)
treeWalk.addTree(revCommit.getTree)
val buffer = new scala.collection.mutable.ListBuffer[DiffInfo]()
while(treeWalk.next){
val newIsImage = FileUtil.isImage(treeWalk.getPathString)
buffer.append((if(!fetchContent){
DiffInfo(
changeType = ChangeType.ADD,
oldPath = "",
newPath = treeWalk.getPathString,
oldContent = None,
newContent = None,
oldIsImage = false,
newIsImage = newIsImage,
oldObjectId = None,
newObjectId = Option(treeWalk.getObjectId(0)).map(_.name),
oldMode = treeWalk.getFileMode(0).toString,
newMode = treeWalk.getFileMode(0).toString,
tooLarge = false,
patch = None
)
} else {
DiffInfo(
changeType = ChangeType.ADD,
oldPath = "",
newPath = treeWalk.getPathString,
oldContent = None,
newContent = JGitUtil.getContentFromId(git, treeWalk.getObjectId(0), false).filter(FileUtil.isText).map(convertFromByteArray),
oldIsImage = false,
newIsImage = newIsImage,
oldObjectId = None,
newObjectId = Option(treeWalk.getObjectId(0)).map(_.name),
oldMode = treeWalk.getFileMode(0).toString,
newMode = treeWalk.getFileMode(0).toString,
tooLarge = false,
patch = None
)
}))
val toCommit = revWalk.parseCommit(git.getRepository.resolve(to))
from match {
case None => {
toCommit.getParentCount match {
case 0 => df.scan(new EmptyTreeIterator(), new CanonicalTreeParser(null, git.getRepository.newObjectReader(), toCommit.getTree)).asScala
case _ => df.scan(toCommit.getParent(0), toCommit.getTree).asScala
}
(buffer.toList, None)
}
case Some(from) => {
val fromCommit = revWalk.parseCommit(git.getRepository.resolve(from))
df.scan(fromCommit.getTree, toCommit.getTree).asScala
}
}
}
}
def getDiffs(git: Git, from: String, to: String, fetchContent: Boolean, makePatch: Boolean): List[DiffInfo] = {
val reader = git.getRepository.newObjectReader
val oldTreeIter = new CanonicalTreeParser
oldTreeIter.reset(reader, git.getRepository.resolve(from + "^{tree}"))
def getParentCommitId(git: Git, id: String): Option[String] = {
using(new RevWalk(git.getRepository)){ revWalk =>
val commit = revWalk.parseCommit(git.getRepository.resolve(id))
commit.getParentCount match {
case 0 => None
case _ => Some(commit.getParent(0).getName)
}
}
}
val newTreeIter = new CanonicalTreeParser
newTreeIter.reset(reader, git.getRepository.resolve(to + "^{tree}"))
import scala.collection.JavaConverters._
git.getRepository.getConfig.setString("diff", null, "renames", "copies")
val diffs = git.diff.setNewTree(newTreeIter).setOldTree(oldTreeIter).call.asScala
def getDiffs(git: Git, from: Option[String], to: String, fetchContent: Boolean, makePatch: Boolean): List[DiffInfo] = {
val df = new DiffFormatter(System.out)
val diffs = getDiffEntries(git, from, to, df)
diffs.map { diff =>
if(diffs.size > 100){
DiffInfo(
@@ -639,7 +594,7 @@ object JGitUtil {
oldMode = diff.getOldMode.toString,
newMode = diff.getNewMode.toString,
tooLarge = false,
patch = (if(makePatch) Some(makePatchFromDiffEntry(git, diff)) else None)
patch = (if(makePatch) Some(makePatchFromDiffEntry(git, diff)) else None) // TODO use DiffFormatter
)
} else {
DiffInfo(
@@ -655,7 +610,7 @@ object JGitUtil {
oldMode = diff.getOldMode.toString,
newMode = diff.getNewMode.toString,
tooLarge = false,
patch = (if(makePatch) Some(makePatchFromDiffEntry(git, diff)) else None)
patch = (if(makePatch) Some(makePatchFromDiffEntry(git, diff)) else None) // TODO use DiffFormatter
)
}
}