(refs #180)Eliminating the working repository cloning in Wiki.

This commit is contained in:
takezoe
2013-10-29 09:22:37 +09:00
parent f38fa0132c
commit 2642da3be3

View File

@@ -5,10 +5,17 @@ import java.util.Date
import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.Git
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
import util.{StringUtil, Directory, JGitUtil, LockUtil} import util.{StringUtil, Directory, JGitUtil, LockUtil}
import util.ControlUtil._ import _root_.util.ControlUtil._
import org.eclipse.jgit.treewalk.CanonicalTreeParser import org.eclipse.jgit.treewalk.{TreeWalk, CanonicalTreeParser}
import org.eclipse.jgit.diff.DiffFormatter import org.eclipse.jgit.diff.DiffFormatter
import org.eclipse.jgit.api.errors.PatchApplyException import org.eclipse.jgit.api.errors.PatchApplyException
import java.util
import org.eclipse.jgit.lib._
import org.eclipse.jgit.dircache.{DirCache, DirCacheEntry}
import org.eclipse.jgit.merge.{ResolveMerger, MergeStrategy}
import scala.Some
import org.eclipse.jgit.revwalk.RevWalk
import org.eclipse.jgit.api.CheckoutCommand.Stage
object WikiService { object WikiService {
@@ -99,49 +106,50 @@ trait WikiService {
*/ */
def revertWikiPage(owner: String, repository: String, from: String, to: String, def revertWikiPage(owner: String, repository: String, from: String, to: String,
committer: model.Account, pageName: Option[String]): Boolean = { committer: model.Account, pageName: Option[String]): Boolean = {
LockUtil.lock(s"${owner}/${repository}/wiki"){ // LockUtil.lock(s"${owner}/${repository}/wiki"){
defining(Directory.getWikiWorkDir(owner, repository)){ workDir => // defining(Directory.getWikiWorkDir(owner, repository)){ workDir =>
// clone working copy // // clone working copy
cloneOrPullWorkingCopy(workDir, owner, repository) // cloneOrPullWorkingCopy(workDir, owner, repository)
//
using(Git.open(workDir)){ git => // using(Git.open(workDir)){ git =>
val reader = git.getRepository.newObjectReader // val reader = git.getRepository.newObjectReader
val oldTreeIter = new CanonicalTreeParser // val oldTreeIter = new CanonicalTreeParser
oldTreeIter.reset(reader, git.getRepository.resolve(from + "^{tree}")) // oldTreeIter.reset(reader, git.getRepository.resolve(from + "^{tree}"))
//
val newTreeIter = new CanonicalTreeParser // val newTreeIter = new CanonicalTreeParser
newTreeIter.reset(reader, git.getRepository.resolve(to + "^{tree}")) // newTreeIter.reset(reader, git.getRepository.resolve(to + "^{tree}"))
//
import scala.collection.JavaConverters._ // import scala.collection.JavaConverters._
val diffs = git.diff.setNewTree(oldTreeIter).setOldTree(newTreeIter).call.asScala.filter { diff => // val diffs = git.diff.setNewTree(oldTreeIter).setOldTree(newTreeIter).call.asScala.filter { diff =>
pageName match { // pageName match {
case Some(x) => diff.getNewPath == x + ".md" // case Some(x) => diff.getNewPath == x + ".md"
case None => true // case None => true
} // }
} // }
//
val patch = using(new java.io.ByteArrayOutputStream()){ out => // val patch = using(new java.io.ByteArrayOutputStream()){ out =>
val formatter = new DiffFormatter(out) // val formatter = new DiffFormatter(out)
formatter.setRepository(git.getRepository) // formatter.setRepository(git.getRepository)
formatter.format(diffs.asJava) // formatter.format(diffs.asJava)
new String(out.toByteArray, "UTF-8") // new String(out.toByteArray, "UTF-8")
} // }
//
try { // try {
git.apply.setPatch(new java.io.ByteArrayInputStream(patch.getBytes("UTF-8"))).call // git.apply.setPatch(new java.io.ByteArrayInputStream(patch.getBytes("UTF-8"))).call
git.add.addFilepattern(".").call // git.add.addFilepattern(".").call
git.commit.setCommitter(committer.fullName, committer.mailAddress).setMessage(pageName match { // git.commit.setCommitter(committer.fullName, committer.mailAddress).setMessage(pageName match {
case Some(x) => s"Revert ${from} ... ${to} on ${x}" // case Some(x) => s"Revert ${from} ... ${to} on ${x}"
case None => s"Revert ${from} ... ${to}" // case None => s"Revert ${from} ... ${to}"
}).call // }).call
git.push.call // git.push.call
// true
// } catch {
// case ex: PatchApplyException => false
// }
// }
// }
// }
true true
} catch {
case ex: PatchApplyException => false
}
}
}
}
} }
@@ -151,50 +159,114 @@ trait WikiService {
def saveWikiPage(owner: String, repository: String, currentPageName: String, newPageName: String, def saveWikiPage(owner: String, repository: String, currentPageName: String, newPageName: String,
content: String, committer: model.Account, message: String, currentId: Option[String]): Option[String] = { content: String, committer: model.Account, message: String, currentId: Option[String]): Option[String] = {
import scala.collection.JavaConverters._
// TODO conflict detection and rename page
LockUtil.lock(s"${owner}/${repository}/wiki"){ LockUtil.lock(s"${owner}/${repository}/wiki"){
defining(Directory.getWikiWorkDir(owner, repository)){ workDir => using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
// clone working copy val repo = git.getRepository()
cloneOrPullWorkingCopy(workDir, owner, repository) val dirCache = DirCache.newInCore()
val builder = dirCache.builder()
val inserter = repo.newObjectInserter()
val headId = repo.resolve(Constants.HEAD + "^{commit}")
var created = true
// write as file using(new RevWalk(git.getRepository)){ revWalk =>
using(Git.open(workDir)){ git => val treeWalk = new TreeWalk(repo)
defining(new File(workDir, newPageName + ".md")){ file => val hIdx = treeWalk.addTree(revWalk.parseTree(headId))
// new page treeWalk.setRecursive(true)
val created = !file.exists while(treeWalk.next){
val path = treeWalk.getPathString
// created or updated if(path != newPageName + ".md"){
val added = executeIf(!file.exists || FileUtils.readFileToString(file, "UTF-8") != content){ val hTree = treeWalk.getTree(hIdx, classOf[CanonicalTreeParser])
FileUtils.writeStringToFile(file, content, "UTF-8") val entry = new DirCacheEntry(path)
git.add.addFilepattern(file.getName).call entry.setObjectId(hTree.getEntryObjectId())
entry.setFileMode(hTree.getEntryFileMode())
builder.add(entry)
} else {
created = false
}
}
treeWalk.release()
} }
// delete file val entry = new DirCacheEntry(newPageName + ".md")
val deleted = executeIf(currentPageName != "" && currentPageName != newPageName){ entry.setFileMode(FileMode.REGULAR_FILE)
git.rm.addFilepattern(currentPageName + ".md").call entry.setObjectId(inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8")))
} builder.add(entry)
// commit and push builder.finish()
optionIf(added || deleted){ val treeId = dirCache.writeTree(inserter)
defining(git.commit.setCommitter(committer.fullName, committer.mailAddress)
.setMessage(if(message.trim.length == 0){ val newCommit = new CommitBuilder()
if(deleted){ newCommit.setCommitter(new PersonIdent(committer.fullName, committer.mailAddress))
s"Rename ${currentPageName} to ${newPageName}" newCommit.setAuthor(new PersonIdent(committer.fullName, committer.mailAddress))
} else if(created){ newCommit.setMessage(if(message.trim.length == 0) {
if(created){
s"Created ${newPageName}" s"Created ${newPageName}"
} else { } else {
s"Updated ${newPageName}" s"Updated ${newPageName}"
} }
} else { } else {
message message
}).call){ commit => })
git.push.call newCommit.setParentIds(List(headId).asJava)
Some(commit.getName) newCommit.setTreeId(treeId)
}
} val newHeadId = inserter.insert(newCommit)
} inserter.flush()
}
val ru = repo.updateRef(Constants.HEAD)
ru.setNewObjectId(newHeadId)
ru.update()
Some(newHeadId.getName)
} }
} }
// defining(Directory.getWikiWorkDir(owner, repository)){ workDir =>
// // clone working copy
// cloneOrPullWorkingCopy(workDir, owner, repository)
//
// // write as file
// using(Git.open(workDir)){ git =>
// defining(new File(workDir, newPageName + ".md")){ file =>
// // new page
// val created = !file.exists
//
// // created or updated
// val added = executeIf(!file.exists || FileUtils.readFileToString(file, "UTF-8") != content){
// FileUtils.writeStringToFile(file, content, "UTF-8")
// git.add.addFilepattern(file.getName).call
// }
//
// // delete file
// val deleted = executeIf(currentPageName != "" && currentPageName != newPageName){
// git.rm.addFilepattern(currentPageName + ".md").call
// }
//
// // commit and push
// optionIf(added || deleted){
// defining(git.commit.setCommitter(committer.fullName, committer.mailAddress)
// .setMessage(if(message.trim.length == 0){
// if(deleted){
// s"Rename ${currentPageName} to ${newPageName}"
// } else if(created){
// s"Created ${newPageName}"
// } else {
// s"Updated ${newPageName}"
// }
// } else {
// message
// }).call){ commit =>
// git.push.call
// Some(commit.getName)
// }
// }
// }
// }
// }
// }
} }
/** /**
@@ -202,36 +274,36 @@ trait WikiService {
*/ */
def deleteWikiPage(owner: String, repository: String, pageName: String, def deleteWikiPage(owner: String, repository: String, pageName: String,
committer: String, mailAddress: String, message: String): Unit = { committer: String, mailAddress: String, message: String): Unit = {
LockUtil.lock(s"${owner}/${repository}/wiki"){ // LockUtil.lock(s"${owner}/${repository}/wiki"){
defining(Directory.getWikiWorkDir(owner, repository)){ workDir => // defining(Directory.getWikiWorkDir(owner, repository)){ workDir =>
// clone working copy // // clone working copy
cloneOrPullWorkingCopy(workDir, owner, repository) // cloneOrPullWorkingCopy(workDir, owner, repository)
//
// delete file // // delete file
new File(workDir, pageName + ".md").delete // new File(workDir, pageName + ".md").delete
//
using(Git.open(workDir)){ git => // using(Git.open(workDir)){ git =>
git.rm.addFilepattern(pageName + ".md").call // git.rm.addFilepattern(pageName + ".md").call
//
// commit and push // // commit and push
git.commit.setCommitter(committer, mailAddress).setMessage(message).call // git.commit.setCommitter(committer, mailAddress).setMessage(message).call
git.push.call // git.push.call
} // }
} // }
} // }
} }
private def cloneOrPullWorkingCopy(workDir: File, owner: String, repository: String): Unit = { // private def cloneOrPullWorkingCopy(workDir: File, owner: String, repository: String): Unit = {
if(!workDir.exists){ // if(!workDir.exists){
Git.cloneRepository // Git.cloneRepository
.setURI(Directory.getWikiRepositoryDir(owner, repository).toURI.toString) // .setURI(Directory.getWikiRepositoryDir(owner, repository).toURI.toString)
.setDirectory(workDir) // .setDirectory(workDir)
.call // .call
.getRepository // .getRepository
.close // .close
} else using(Git.open(workDir)){ git => // } else using(Git.open(workDir)){ git =>
git.pull.call // git.pull.call
} // }
} // }
} }