mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-02 19:45:57 +01:00
Displays image files and large files well in the repository viewer.
This commit is contained in:
@@ -12,6 +12,7 @@ import org.eclipse.jgit.treewalk._
|
|||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
||||||
import org.eclipse.jgit.errors.MissingObjectException
|
import org.eclipse.jgit.errors.MissingObjectException
|
||||||
|
import org.apache.commons.io.FilenameUtils
|
||||||
|
|
||||||
case class RepositoryInfo(owner: String, name: String, url: String, branchList: List[String], tags: List[String])
|
case class RepositoryInfo(owner: String, name: String, url: String, branchList: List[String], tags: List[String])
|
||||||
|
|
||||||
@@ -23,6 +24,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])
|
case class DiffInfo(changeType: ChangeType, oldPath: String, newPath: String, oldContent: Option[String], newContent: Option[String])
|
||||||
|
|
||||||
|
case class ContentInfo(viewType: String, content: Option[String])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The repository viewer.
|
* The repository viewer.
|
||||||
@@ -30,7 +33,7 @@ case class DiffInfo(changeType: ChangeType, oldPath: String, newPath: String, ol
|
|||||||
class RepositoryViewerServlet extends ServletBase {
|
class RepositoryViewerServlet extends ServletBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows user information.
|
* Displays user information.
|
||||||
*/
|
*/
|
||||||
get("/:owner") {
|
get("/:owner") {
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
@@ -38,7 +41,7 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the file list of the repository root and the default branch.
|
* Displays the file list of the repository root and the default branch.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository") {
|
get("/:owner/:repository") {
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
@@ -48,7 +51,7 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the file list of the repository root and the specified branch.
|
* Displays the file list of the repository root and the specified branch.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository/tree/:branch") {
|
get("/:owner/:repository/tree/:branch") {
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
@@ -58,7 +61,7 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the file list of the specified path and branch.
|
* Displays the file list of the specified path and branch.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository/tree/:branch/*") {
|
get("/:owner/:repository/tree/:branch/*") {
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
@@ -68,7 +71,7 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the commit list of the specified branch.
|
* Displays the commit list of the specified branch.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository/commits/:branch"){
|
get("/:owner/:repository/commits/:branch"){
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
@@ -93,24 +96,35 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the file content of the specified branch or commit.
|
* Displays the file content of the specified branch or commit.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository/blob/:id/*"){
|
get("/:owner/:repository/blob/:id/*"){
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
val repository = params("repository")
|
val repository = params("repository")
|
||||||
val id = params("id") // branch name or commit id
|
val id = params("id") // branch name or commit id
|
||||||
|
val raw = params.get("raw").getOrElse("false").toBoolean
|
||||||
val path = multiParams("splat").head.replaceFirst("^tree/.+?/", "")
|
val path = multiParams("splat").head.replaceFirst("^tree/.+?/", "")
|
||||||
val repositoryInfo = getRepositoryInfo(owner, repository)
|
val repositoryInfo = getRepositoryInfo(owner, repository)
|
||||||
|
|
||||||
if(repositoryInfo.branchList.contains(id)){
|
if(repositoryInfo.branchList.contains(id)){
|
||||||
// id is branch name
|
// id is branch name
|
||||||
val dir = getBranchDir(owner, repository, id)
|
val dir = getBranchDir(owner, repository, id)
|
||||||
val content = FileUtils.readFileToString(new File(dir, path), "UTF-8")
|
val git = Git.open(dir)
|
||||||
val git = Git.open(dir)
|
val rev = git.log.addPath(path).call.iterator.next
|
||||||
val rev = git.log.addPath(path).call.iterator.next
|
val file = new File(dir, path)
|
||||||
|
|
||||||
html.blob(id, repositoryInfo, path.split("/").toList, content, new CommitInfo(rev))
|
if(raw){
|
||||||
|
// Download
|
||||||
|
contentType = "application/octet-stream"
|
||||||
|
file
|
||||||
|
} else {
|
||||||
|
// Viewer
|
||||||
|
val viewer = if(isImage(file.getName)) "image" else if(isLarge(file.length)) "large" else "text"
|
||||||
|
val content = ContentInfo(
|
||||||
|
viewer, if(viewer == "text") Some(FileUtils.readFileToString(file, "UTF-8")) else None
|
||||||
|
)
|
||||||
|
html.blob(id, repositoryInfo, path.split("/").toList, content, new CommitInfo(rev))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// id is commit id
|
// id is commit id
|
||||||
val branch = getBranchNameFromCommitId(id, repositoryInfo)
|
val branch = getBranchNameFromCommitId(id, repositoryInfo)
|
||||||
@@ -119,24 +133,34 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
val rev = git.log.add(ObjectId.fromString(id)).call.iterator.next
|
val rev = git.log.add(ObjectId.fromString(id)).call.iterator.next
|
||||||
|
|
||||||
@scala.annotation.tailrec
|
@scala.annotation.tailrec
|
||||||
def getPathContent(path: String, walk: TreeWalk): Option[String] = {
|
def getPathObjectId(path: String, walk: TreeWalk): ObjectId = walk.next match {
|
||||||
walk.next match{
|
case true if(walk.getPathString == path) => walk.getObjectId(0)
|
||||||
case true if(walk.getPathString == path) => getContent(git, walk.getObjectId(0))
|
case true => getPathObjectId(path, walk)
|
||||||
case true => getPathContent(path, walk)
|
|
||||||
case false => None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val walk = new TreeWalk(git.getRepository)
|
val walk = new TreeWalk(git.getRepository)
|
||||||
walk.addTree(rev.getTree)
|
walk.addTree(rev.getTree)
|
||||||
val content = getPathContent(path, walk).get
|
walk.setRecursive(true)
|
||||||
|
val objectId = getPathObjectId(path, walk)
|
||||||
|
|
||||||
html.blob(branch, repositoryInfo, path.split("/").toList, content, new CommitInfo(rev))
|
if(raw){
|
||||||
|
// Download
|
||||||
|
contentType = "application/octet-stream"
|
||||||
|
getContent(git, objectId)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Viewer
|
||||||
|
val large = isLarge(git.getRepository.getObjectDatabase.open(objectId).getSize)
|
||||||
|
val viewer = if(isImage(path)) "image" else if(large) "large" else "text"
|
||||||
|
val content = ContentInfo(viewer, if(viewer == "text") getContent(git, objectId).map(new String(_, "UTF-8")) else None)
|
||||||
|
|
||||||
|
html.blob(branch, repositoryInfo, path.split("/").toList, content, new CommitInfo(rev))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows details of the specified commit.
|
* Displays details of the specified commit.
|
||||||
*/
|
*/
|
||||||
get("/:owner/:repository/commit/:id"){
|
get("/:owner/:repository/commit/:id"){
|
||||||
val owner = params("owner")
|
val owner = params("owner")
|
||||||
@@ -170,8 +194,8 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
import scala.collection.JavaConverters._
|
import scala.collection.JavaConverters._
|
||||||
git.diff.setNewTree(newTreeIter).setOldTree(oldTreeIter).call.asScala.map { diff =>
|
git.diff.setNewTree(newTreeIter).setOldTree(oldTreeIter).call.asScala.map { diff =>
|
||||||
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath,
|
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath,
|
||||||
getContent(git, diff.getOldId.toObjectId),
|
getContent(git, diff.getOldId.toObjectId).map(new String(_, "UTF-8")),
|
||||||
getContent(git, diff.getNewId.toObjectId))
|
getContent(git, diff.getNewId.toObjectId).map(new String(_, "UTF-8")))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// initial commit
|
// initial commit
|
||||||
@@ -179,7 +203,7 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
walk.addTree(rev.getTree)
|
walk.addTree(rev.getTree)
|
||||||
val buffer = new scala.collection.mutable.ListBuffer[DiffInfo]()
|
val buffer = new scala.collection.mutable.ListBuffer[DiffInfo]()
|
||||||
while(walk.next){
|
while(walk.next){
|
||||||
buffer.append(DiffInfo(ChangeType.ADD, null, walk.getPathString, None, getContent(git, walk.getObjectId(0))))
|
buffer.append(DiffInfo(ChangeType.ADD, null, walk.getPathString, None, getContent(git, walk.getObjectId(0)).map(new String(_, "UTF-8"))))
|
||||||
}
|
}
|
||||||
buffer.toList
|
buffer.toList
|
||||||
}
|
}
|
||||||
@@ -206,8 +230,8 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
* @param id the object id
|
* @param id the object id
|
||||||
* @return the object or None if object does not exist
|
* @return the object or None if object does not exist
|
||||||
*/
|
*/
|
||||||
def getContent(git: Git, id: ObjectId): Option[String] = try {
|
def getContent(git: Git, id: ObjectId): Option[Array[Byte]] = try {
|
||||||
Some(new String(git.getRepository.getObjectDatabase.open(id).getBytes, "UTF-8"))
|
Some(git.getRepository.getObjectDatabase.open(id).getBytes)
|
||||||
} catch {
|
} catch {
|
||||||
case e: MissingObjectException => None
|
case e: MissingObjectException => None
|
||||||
}
|
}
|
||||||
@@ -291,4 +315,11 @@ class RepositoryViewerServlet extends ServletBase {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def isImage(name: String): Boolean = FilenameUtils.getExtension(name).toLowerCase match {
|
||||||
|
case "jpg"|"jpeg"|"bmp"|"gif"|"png" => true
|
||||||
|
case _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
def isLarge(size: Long): Boolean = (size > 1024 * 1000)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@(branch: String, repository: app.RepositoryInfo, pathList: List[String], content: String, latestCommit: app.CommitInfo)(implicit context: app.Context)
|
@(branch: String, repository: app.RepositoryInfo, pathList: List[String], content: app.ContentInfo, latestCommit: app.CommitInfo)(implicit context: app.Context)
|
||||||
@import context._
|
@import context._
|
||||||
@import view.helpers
|
@import view.helpers
|
||||||
@main(repository.owner+"/"+repository.name) {
|
@main(repository.owner+"/"+repository.name) {
|
||||||
@@ -24,14 +24,27 @@
|
|||||||
@helpers.cut(latestCommit.message, 100)<br>
|
@helpers.cut(latestCommit.message, 100)<br>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group pull-right">
|
<div class="btn-group pull-right">
|
||||||
<button class="btn btn-mini">Edit</button>
|
<a class="btn btn-mini">Edit</a>
|
||||||
<button class="btn btn-mini">Raw</button>
|
<a class="btn btn-mini" href="?raw=true">Raw</a>
|
||||||
<button class="btn btn-mini">History</button>
|
<a class="btn btn-mini">History</a>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><pre class="prettyprint linenums">@content</pre></td>
|
<td>
|
||||||
|
@if(content.viewType == "text"){
|
||||||
|
<pre class="prettyprint linenums">@content.content.get</pre>
|
||||||
|
}
|
||||||
|
@if(content.viewType == "image"){
|
||||||
|
<img src="?raw=true"/>
|
||||||
|
}
|
||||||
|
@if(content.viewType == "large"){
|
||||||
|
<div style="text-align: center">
|
||||||
|
<a href="?raw=true">View Raw</a><br>
|
||||||
|
(Sorry about that, but we can't show files that are this big right now)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user