(refs #180)Reverting from history without working repository is completed.

This commit is contained in:
takezoe
2013-10-30 11:13:10 +09:00
parent 68b25ddbb5
commit ef3e7d9286

View File

@@ -8,9 +8,7 @@ import _root_.util.ControlUtil._
import org.eclipse.jgit.treewalk.{TreeWalk, CanonicalTreeParser} import org.eclipse.jgit.treewalk.{TreeWalk, CanonicalTreeParser}
import org.eclipse.jgit.lib._ import org.eclipse.jgit.lib._
import org.eclipse.jgit.dircache.{DirCache, DirCacheEntry} import org.eclipse.jgit.dircache.{DirCache, DirCacheEntry}
import org.eclipse.jgit.merge.{ResolveMerger, MergeStrategy}
import org.eclipse.jgit.revwalk.RevWalk import org.eclipse.jgit.revwalk.RevWalk
import scala.collection.JavaConverters._
import org.eclipse.jgit.diff.{DiffEntry, DiffFormatter} import org.eclipse.jgit.diff.{DiffEntry, DiffFormatter}
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import org.eclipse.jgit.patch._ import org.eclipse.jgit.patch._
@@ -108,8 +106,12 @@ 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 = {
case class RevertInfo(operation: String, filePath: String, source: String)
try {
LockUtil.lock(s"${owner}/${repository}/wiki"){ LockUtil.lock(s"${owner}/${repository}/wiki"){
using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git => using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ 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}"))
@@ -117,7 +119,6 @@ trait WikiService {
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._
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"
@@ -140,115 +141,90 @@ trait WikiService {
val revertInfo = (p.getFiles.asScala.map { fh => val revertInfo = (p.getFiles.asScala.map { fh =>
fh.getChangeType match { fh.getChangeType match {
case DiffEntry.ChangeType.MODIFY => { case DiffEntry.ChangeType.MODIFY => {
val page = getWikiPage(owner, repository, fh.getNewPath.replaceFirst("\\.md$", "")).get val source = getWikiPage(owner, repository, fh.getNewPath.replaceFirst("\\.md$", "")).map(_.content).getOrElse("")
Seq(RevertInfo("ADD", fh.getNewPath, PatchUtil.apply(page.content, fh))) val applied = PatchUtil.apply(source, fh)
if(applied != null){
Seq(RevertInfo("ADD", fh.getNewPath, applied))
} else Nil
} }
case DiffEntry.ChangeType.ADD => { case DiffEntry.ChangeType.ADD => {
Seq(RevertInfo("ADD", fh.getNewPath, PatchUtil.apply("", fh))) val applied = PatchUtil.apply("", fh)
if(applied != null){
Seq(RevertInfo("ADD", fh.getNewPath, applied))
} else Nil
} }
case DiffEntry.ChangeType.DELETE => { case DiffEntry.ChangeType.DELETE => {
Seq(RevertInfo("DELETE", fh.getNewPath, "")) Seq(RevertInfo("DELETE", fh.getNewPath, ""))
} }
case DiffEntry.ChangeType.RENAME => { case DiffEntry.ChangeType.RENAME => {
Seq( val applied = PatchUtil.apply("", fh)
RevertInfo("DELETE", fh.getOldPath, ""), if(applied != null){
RevertInfo("ADD", fh.getNewPath, PatchUtil.apply("", fh)) Seq(RevertInfo("DELETE", fh.getOldPath, ""), RevertInfo("ADD", fh.getNewPath, applied))
) } else {
Seq(RevertInfo("DELETE", fh.getOldPath, ""))
}
} }
case _ => Nil case _ => Nil
} }
}).flatten }).flatten
revertInfo.foreach { revert => if(revertInfo.nonEmpty){
println(revert) val builder = DirCache.newInCore.builder()
val inserter = git.getRepository.newObjectInserter()
val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
using(new RevWalk(git.getRepository)){ revWalk =>
using(new TreeWalk(git.getRepository)){ treeWalk =>
val index = treeWalk.addTree(revWalk.parseTree(headId))
treeWalk.setRecursive(true)
while(treeWalk.next){
val path = treeWalk.getPathString
val tree = treeWalk.getTree(index, classOf[CanonicalTreeParser])
if(revertInfo.find(x => x.filePath == path).isEmpty){
builder.add(createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
}
} }
// val source = getWikiPage(owner, repository, pageName.get)
// PatchUtil.applyToFile(PatchUtil.createPatch(patch), source.get.content, pageName + ".md")
// try {
// git.apply.setPatch(new java.io.ByteArrayInputStream(patch.getBytes("UTF-8"))).call
// git.add.addFilepattern(".").call
// git.commit.setCommitter(committer.fullName, committer.mailAddress).setMessage(pageName match {
// case Some(x) => s"Revert ${from} ... ${to} on ${x}"
// case None => s"Revert ${from} ... ${to}"
// }).call
// git.push.call
// true
// } catch {
// case ex: PatchApplyException => false
// }
} }
} }
revertInfo.filter(_.operation == "ADD").foreach { x =>
builder.add(createDirCacheEntry(x.filePath, FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, x.source.getBytes("UTF-8"))))
}
builder.finish()
createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter), committer.fullName, committer.mailAddress,
// LockUtil.lock(s"${owner}/${repository}/wiki"){ pageName match {
// defining(Directory.getWikiWorkDir(owner, repository)){ workDir => case Some(x) => s"Revert ${from} ... ${to} on ${x}"
// // clone working copy case None => s"Revert ${from} ... ${to}"
// cloneOrPullWorkingCopy(workDir, owner, repository) })
// }
// using(Git.open(workDir)){ git => }
// val reader = git.getRepository.newObjectReader }
// val oldTreeIter = new CanonicalTreeParser
// oldTreeIter.reset(reader, git.getRepository.resolve(from + "^{tree}"))
//
// val newTreeIter = new CanonicalTreeParser
// newTreeIter.reset(reader, git.getRepository.resolve(to + "^{tree}"))
//
// import scala.collection.JavaConverters._
// val diffs = git.diff.setNewTree(oldTreeIter).setOldTree(newTreeIter).call.asScala.filter { diff =>
// pageName match {
// case Some(x) => diff.getNewPath == x + ".md"
// case None => true
// }
// }
//
// val patch = using(new java.io.ByteArrayOutputStream()){ out =>
// val formatter = new DiffFormatter(out)
// formatter.setRepository(git.getRepository)
// formatter.format(diffs.asJava)
// new String(out.toByteArray, "UTF-8")
// }
//
// try {
// git.apply.setPatch(new java.io.ByteArrayInputStream(patch.getBytes("UTF-8"))).call
// git.add.addFilepattern(".").call
// git.commit.setCommitter(committer.fullName, committer.mailAddress).setMessage(pageName match {
// case Some(x) => s"Revert ${from} ... ${to} on ${x}"
// case None => s"Revert ${from} ... ${to}"
// }).call
// git.push.call
// true
// } catch {
// case ex: PatchApplyException => false
// }
// }
// }
// }
true true
} catch {
case e: Exception => {
e.printStackTrace()
false
}
}
} }
/** /**
* Save the wiki page. * Save the wiki page.
*/ */
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] = {
LockUtil.lock(s"${owner}/${repository}/wiki"){ LockUtil.lock(s"${owner}/${repository}/wiki"){
using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git => using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
val repo = git.getRepository() val builder = DirCache.newInCore.builder()
val dirCache = DirCache.newInCore() val inserter = git.getRepository.newObjectInserter()
val builder = dirCache.builder() val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
val inserter = repo.newObjectInserter()
val headId = repo.resolve(Constants.HEAD + "^{commit}")
var created = true var created = true
var updated = false var updated = false
var removed = false var removed = false
using(new RevWalk(git.getRepository)){ revWalk => using(new RevWalk(git.getRepository)){ revWalk =>
val treeWalk = new TreeWalk(repo) using(new TreeWalk(git.getRepository)){ treeWalk =>
val index = treeWalk.addTree(revWalk.parseTree(headId)) val index = treeWalk.addTree(revWalk.parseTree(headId))
treeWalk.setRecursive(true) treeWalk.setRecursive(true)
while(treeWalk.next){ while(treeWalk.next){
@@ -257,31 +233,20 @@ trait WikiService {
if(path == currentPageName + ".md" && currentPageName != newPageName){ if(path == currentPageName + ".md" && currentPageName != newPageName){
removed = true removed = true
} else if(path != newPageName + ".md"){ } else if(path != newPageName + ".md"){
val entry = new DirCacheEntry(path) builder.add(createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
entry.setObjectId(tree.getEntryObjectId())
entry.setFileMode(tree.getEntryFileMode())
builder.add(entry)
} else { } else {
created = false created = false
updated = JGitUtil.getContent(git, tree.getEntryObjectId, true).map(new String(_, "UTF-8") != content).getOrElse(false) updated = JGitUtil.getContent(git, tree.getEntryObjectId, true).map(new String(_, "UTF-8") != content).getOrElse(false)
} }
} }
treeWalk.release() }
} }
optionIf(created || updated || removed){ optionIf(created || updated || removed){
val entry = new DirCacheEntry(newPageName + ".md") builder.add(createDirCacheEntry(newPageName + ".md", FileMode.REGULAR_FILE, inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8"))))
entry.setFileMode(FileMode.REGULAR_FILE)
entry.setObjectId(inserter.insert(Constants.OBJ_BLOB, content.getBytes("UTF-8")))
builder.add(entry)
builder.finish() builder.finish()
val treeId = dirCache.writeTree(inserter) val newHeadId = createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter), committer.fullName, committer.mailAddress,
if(message.trim.length == 0) {
val newCommit = new CommitBuilder()
newCommit.setCommitter(new PersonIdent(committer.fullName, committer.mailAddress))
newCommit.setAuthor(new PersonIdent(committer.fullName, committer.mailAddress))
newCommit.setMessage(if(message.trim.length == 0) {
if(removed){ if(removed){
s"Rename ${currentPageName} to ${newPageName}" s"Rename ${currentPageName} to ${newPageName}"
} else if(created){ } else if(created){
@@ -292,17 +257,8 @@ trait WikiService {
} else { } else {
message message
}) })
newCommit.setParentIds(List(headId).asJava)
newCommit.setTreeId(treeId)
val newHeadId = inserter.insert(newCommit) Some(newHeadId)
inserter.flush()
val refUpdate = repo.updateRef(Constants.HEAD)
refUpdate.setNewObjectId(newHeadId)
refUpdate.update()
Some(newHeadId.getName)
} }
} }
} }
@@ -315,39 +271,49 @@ trait WikiService {
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"){
using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git => using(Git.open(Directory.getWikiRepositoryDir(owner, repository))){ git =>
val repo = git.getRepository() val builder = DirCache.newInCore.builder()
val dirCache = DirCache.newInCore() val inserter = git.getRepository.newObjectInserter()
val builder = dirCache.builder() val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}")
val inserter = repo.newObjectInserter()
val headId = repo.resolve(Constants.HEAD + "^{commit}")
var removed = false var removed = false
using(new RevWalk(git.getRepository)){ revWalk => using(new RevWalk(git.getRepository)){ revWalk =>
val treeWalk = new TreeWalk(repo) using(new TreeWalk(git.getRepository)){ treeWalk =>
val index = treeWalk.addTree(revWalk.parseTree(headId)) val index = treeWalk.addTree(revWalk.parseTree(headId))
treeWalk.setRecursive(true) treeWalk.setRecursive(true)
while(treeWalk.next){ while(treeWalk.next){
val path = treeWalk.getPathString val path = treeWalk.getPathString
val tree = treeWalk.getTree(index, classOf[CanonicalTreeParser]) val tree = treeWalk.getTree(index, classOf[CanonicalTreeParser])
if(path != pageName + ".md"){ if(path != pageName + ".md"){
val entry = new DirCacheEntry(path) builder.add(createDirCacheEntry(path, tree.getEntryFileMode, tree.getEntryObjectId))
entry.setObjectId(tree.getEntryObjectId())
entry.setFileMode(tree.getEntryFileMode())
builder.add(entry)
} else { } else {
removed = true removed = true
} }
} }
treeWalk.release()
} }
if(removed){ if(removed){
builder.finish() builder.finish()
val treeId = dirCache.writeTree(inserter) createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter), committer, mailAddress, message)
}
}
}
}
}
// This method should be moved to JGitUtil?
private def createDirCacheEntry(path: String, mode: FileMode, objectId: ObjectId): DirCacheEntry = {
val entry = new DirCacheEntry(path)
entry.setFileMode(mode)
entry.setObjectId(objectId)
entry
}
// This method should be moved to JGitUtil?
private def createNewCommit(git: Git, inserter: ObjectInserter, headId: AnyObjectId, treeId: AnyObjectId,
fullName: String, mailAddress: String, message: String): String = {
val newCommit = new CommitBuilder() val newCommit = new CommitBuilder()
newCommit.setCommitter(new PersonIdent(committer, mailAddress)) newCommit.setCommitter(new PersonIdent(fullName, mailAddress))
newCommit.setAuthor(new PersonIdent(committer, mailAddress)) newCommit.setAuthor(new PersonIdent(fullName, mailAddress))
newCommit.setMessage(message) newCommit.setMessage(message)
newCommit.setParentIds(List(headId).asJava) newCommit.setParentIds(List(headId).asJava)
newCommit.setTreeId(treeId) newCommit.setTreeId(treeId)
@@ -355,28 +321,11 @@ trait WikiService {
val newHeadId = inserter.insert(newCommit) val newHeadId = inserter.insert(newCommit)
inserter.flush() inserter.flush()
val refUpdate = repo.updateRef(Constants.HEAD) val refUpdate = git.getRepository.updateRef(Constants.HEAD)
refUpdate.setNewObjectId(newHeadId) refUpdate.setNewObjectId(newHeadId)
refUpdate.update() refUpdate.update()
} newHeadId.getName
}
}
} }
case class RevertInfo(operation: String, filePath: String, source: String)
// private def cloneOrPullWorkingCopy(workDir: File, owner: String, repository: String): Unit = {
// if(!workDir.exists){
// Git.cloneRepository
// .setURI(Directory.getWikiRepositoryDir(owner, repository).toURI.toString)
// .setDirectory(workDir)
// .call
// .getRepository
// .close
// } else using(Git.open(workDir)){ git =>
// git.pull.call
// }
// }
} }