(refs #13)Commit from AceEditor is available.

This commit is contained in:
Naoki Takezoe
2014-04-24 21:49:30 +09:00
parent 3721b328a6
commit ad244adbfa
5 changed files with 79 additions and 38 deletions

View File

@@ -1,8 +1,9 @@
package app package app
import _root_.util.JGitUtil.CommitInfo
import util.Directory._ import util.Directory._
import util.Implicits._ import util.Implicits._
import util.ControlUtil._ import _root_.util.ControlUtil._
import _root_.util._ import _root_.util._
import service._ import service._
import org.scalatra._ import org.scalatra._
@@ -14,6 +15,7 @@ import org.eclipse.jgit.treewalk._
import java.util.zip.{ZipEntry, ZipOutputStream} import java.util.zip.{ZipEntry, ZipOutputStream}
import jp.sf.amateras.scalatra.forms._ import jp.sf.amateras.scalatra.forms._
import org.eclipse.jgit.dircache.DirCache import org.eclipse.jgit.dircache.DirCache
import org.eclipse.jgit.revwalk.RevWalk
class RepositoryViewerController extends RepositoryViewerControllerBase class RepositoryViewerController extends RepositoryViewerControllerBase
with RepositoryService with AccountService with ActivityService with ReferrerAuthenticator with CollaboratorsAuthenticator with RepositoryService with AccountService with ActivityService with ReferrerAuthenticator with CollaboratorsAuthenticator
@@ -24,11 +26,12 @@ class RepositoryViewerController extends RepositoryViewerControllerBase
trait RepositoryViewerControllerBase extends ControllerBase { trait RepositoryViewerControllerBase extends ControllerBase {
self: RepositoryService with AccountService with ActivityService with ReferrerAuthenticator with CollaboratorsAuthenticator => self: RepositoryService with AccountService with ActivityService with ReferrerAuthenticator with CollaboratorsAuthenticator =>
case class EditorForm(content: String, message: Option[String]) case class EditorForm(content: String, message: Option[String], charset: String)
val editorForm = mapping( val editorForm = mapping(
"content" -> trim(label("Content", text())), "content" -> trim(label("Content", text())),
"message" -> trim(label("Messgae", optional(text()))) "message" -> trim(label("Messgae", optional(text()))),
"charset" -> trim(label("Charset", text()))
)(EditorForm.apply) )(EditorForm.apply)
/** /**
@@ -108,14 +111,14 @@ trait RepositoryViewerControllerBase extends ControllerBase {
val content = if(viewer == "other"){ val content = if(viewer == "other"){
if(bytes.isDefined && FileUtil.isText(bytes.get)){ if(bytes.isDefined && FileUtil.isText(bytes.get)){
// text // text
JGitUtil.ContentInfo("text", bytes.map(StringUtil.convertFromByteArray)) JGitUtil.ContentInfo("text", Some(StringUtil.convertFromByteArray(bytes.get)), Some(StringUtil.detectEncoding(bytes.get)))
} else { } else {
// binary // binary
JGitUtil.ContentInfo("binary", None) JGitUtil.ContentInfo("binary", None, None)
} }
} else { } else {
// image or large // image or large
JGitUtil.ContentInfo(viewer, None) JGitUtil.ContentInfo(viewer, None, None)
} }
repo.html.editor(id, repository, path.split("/").toList, content, new JGitUtil.CommitInfo(revCommit)) repo.html.editor(id, repository, path.split("/").toList, content, new JGitUtil.CommitInfo(revCommit))
@@ -123,22 +126,63 @@ trait RepositoryViewerControllerBase extends ControllerBase {
} }
}) })
// TODO Share this method with WikiService
private def processTree(git: Git, id: ObjectId)(f: (String, CanonicalTreeParser) => Unit) = {
using(new RevWalk(git.getRepository)){ revWalk =>
using(new TreeWalk(git.getRepository)){ treeWalk =>
val index = treeWalk.addTree(revWalk.parseTree(id))
treeWalk.setRecursive(true)
while(treeWalk.next){
f(treeWalk.getPathString, treeWalk.getTree(index, classOf[CanonicalTreeParser]))
}
}
}
}
post("/:owner/:repository/edit/*", editorForm)(collaboratorsOnly { (form, repository) => post("/:owner/:repository/edit/*", editorForm)(collaboratorsOnly { (form, repository) =>
// val (id, path) = splitPath(repository, multiParams("splat").head) val (id, path) = splitPath(repository, multiParams("splat").head)
// val loginAccount = context.loginAccount.get
// LockUtil.lock(s"${repository.owner}/${repository.name}"){
// using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git => using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
// val builder = DirCache.newInCore.builder() val loginAccount = context.loginAccount.get
// val inserter = git.getRepository.newObjectInserter() val builder = DirCache.newInCore.builder()
// val headId = git.getRepository.resolve(Constants.HEAD + "^{commit}") val inserter = git.getRepository.newObjectInserter()
// val headName = s"refs/heads/${id}"
// builder.add(JGitUtil.createDirCacheEntry(path, FileMode.REGULAR_FILE, val headTip = git.getRepository.resolve(s"refs/heads/${id}")
// inserter.insert(Constants.OBJ_BLOB, form.content.getBytes("UTF-8")))) // TODO charset auto detection
// builder.finish() processTree(git, headTip){ (treePath, tree) =>
// if(treePath != path){
// JGitUtil.createNewCommit(git, inserter, headId, builder.getDirCache.writeTree(inserter), builder.add(JGitUtil.createDirCacheEntry(treePath, tree.getEntryFileMode, tree.getEntryObjectId))
// loginAccount.fullName, loginAccount.mailAddress, form.message.getOrElse(s"Update ${path.split("/").last}")) }
// } }
builder.add(JGitUtil.createDirCacheEntry(path, FileMode.REGULAR_FILE,
inserter.insert(Constants.OBJ_BLOB, form.content.getBytes(form.charset))))
builder.finish()
val commitId = JGitUtil.createNewCommit(git, inserter, headTip, builder.getDirCache.writeTree(inserter),
loginAccount.fullName, loginAccount.mailAddress, form.message.getOrElse(s"Update ${path.split("/").last}"))
inserter.flush()
inserter.release()
// update refs
val refUpdate = git.getRepository.updateRef(headName)
refUpdate.setNewObjectId(commitId)
refUpdate.setForceUpdate(false)
refUpdate.setRefLogIdent(new PersonIdent(loginAccount.fullName, loginAccount.mailAddress))
//refUpdate.setRefLogMessage("merged", true)
refUpdate.update()
// record activity
recordPushActivity(repository.owner, repository.name, loginAccount.userName, id,
List(new CommitInfo(JGitUtil.getRevCommitFromId(git, commitId))))
// TODO invoke hook
redirect(s"/${repository.owner}/${repository.name}/blob/${id}/${path}")
}
}
}) })
/** /**
@@ -178,14 +222,14 @@ trait RepositoryViewerControllerBase extends ControllerBase {
val content = if(viewer == "other"){ val content = if(viewer == "other"){
if(bytes.isDefined && FileUtil.isText(bytes.get)){ if(bytes.isDefined && FileUtil.isText(bytes.get)){
// text // text
JGitUtil.ContentInfo("text", bytes.map(StringUtil.convertFromByteArray)) JGitUtil.ContentInfo("text", Some(StringUtil.convertFromByteArray(bytes.get)), Some(StringUtil.detectEncoding(bytes.get)))
} else { } else {
// binary // binary
JGitUtil.ContentInfo("binary", None) JGitUtil.ContentInfo("binary", None, None)
} }
} else { } else {
// image or large // image or large
JGitUtil.ContentInfo(viewer, None) JGitUtil.ContentInfo(viewer, None, None)
} }
repo.html.blob(id, repository, path.split("/").toList, content, new JGitUtil.CommitInfo(revCommit), repo.html.blob(id, repository, path.split("/").toList, content, new JGitUtil.CommitInfo(revCommit),

View File

@@ -262,7 +262,7 @@ trait WikiService {
message message
}) })
Some(newHeadId) Some(newHeadId.getName)
} else None } else None
} }
} }

View File

@@ -92,8 +92,9 @@ object JGitUtil {
* *
* @param viewType "image", "large" or "other" * @param viewType "image", "large" or "other"
* @param content the string content * @param content the string content
* @param charset the character encoding
*/ */
case class ContentInfo(viewType: String, content: Option[String]) case class ContentInfo(viewType: String, content: Option[String], charset: Option[String])
/** /**
* The tag data. * The tag data.
@@ -480,7 +481,7 @@ object JGitUtil {
} }
def createNewCommit(git: Git, inserter: ObjectInserter, headId: AnyObjectId, treeId: AnyObjectId, def createNewCommit(git: Git, inserter: ObjectInserter, headId: AnyObjectId, treeId: AnyObjectId,
fullName: String, mailAddress: String, message: String): String = { fullName: String, mailAddress: String, message: String): ObjectId = {
val newCommit = new CommitBuilder() val newCommit = new CommitBuilder()
newCommit.setCommitter(new PersonIdent(fullName, mailAddress)) newCommit.setCommitter(new PersonIdent(fullName, mailAddress))
newCommit.setAuthor(new PersonIdent(fullName, mailAddress)) newCommit.setAuthor(new PersonIdent(fullName, mailAddress))
@@ -498,7 +499,7 @@ object JGitUtil {
refUpdate.setNewObjectId(newHeadId) refUpdate.setNewObjectId(newHeadId)
refUpdate.update() refUpdate.update()
newHeadId.getName newHeadId
} }
/** /**

View File

@@ -29,11 +29,6 @@
<span class="muted">@datetime(latestCommit.time)</span> <span class="muted">@datetime(latestCommit.time)</span>
<a href="@url(repository)/commit/@latestCommit.id" class="commit-message">@link(latestCommit.summary, repository)</a> <a href="@url(repository)/commit/@latestCommit.id" class="commit-message">@link(latestCommit.summary, repository)</a>
</div> </div>
@if(hasWritePermission){
<div class="btn-group pull-right">
<a class="btn btn-mini btn-danger" href="@url(repository)/delete/@encodeRefName(branch)/@pathList.mkString("/")">Delete</a>
</div>
}
<div class="btn-group pull-right"> <div class="btn-group pull-right">
@if(hasWritePermission){ @if(hasWritePermission){
<a class="btn btn-mini" href="@url(repository)/edit/@encodeRefName(branch)/@pathList.mkString("/")">Edit</a> <a class="btn btn-mini" href="@url(repository)/edit/@encodeRefName(branch)/@pathList.mkString("/")">Edit</a>

View File

@@ -60,6 +60,7 @@
<div style="text-align: right;"> <div style="text-align: right;">
<a href="@url(repository)/blob/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-danger">Cancel</a> <a href="@url(repository)/blob/@encodeRefName(branch)/@pathList.mkString("/")" class="btn btn-danger">Cancel</a>
<input type="submit" id="commit" class="btn btn-success" value="Commit changes"/> <input type="submit" id="commit" class="btn btn-success" value="Commit changes"/>
<input type="hidden" id="charset" name="charset" value="@content.charset"/>
<input type="hidden" id="content" name="content" value=""/> <input type="hidden" id="content" name="content" value=""/>
</div> </div>
</div> </div>