mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-10 15:35:59 +01:00
(refs #1101)Support LFS files in the blob view
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package gitbucket.core.controller
|
||||
|
||||
import javax.servlet.http.{HttpServletResponse, HttpServletRequest}
|
||||
import java.io.FileInputStream
|
||||
import javax.servlet.http.{HttpServletRequest, HttpServletResponse}
|
||||
|
||||
import gitbucket.core.plugin.PluginRegistry
|
||||
import gitbucket.core.repo.html
|
||||
@@ -16,9 +17,8 @@ import gitbucket.core.model.{Account, WebHook}
|
||||
import gitbucket.core.service.WebHookService._
|
||||
import gitbucket.core.view
|
||||
import gitbucket.core.view.helpers
|
||||
|
||||
import io.github.gitbucket.scalatra.forms._
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.apache.commons.io.{FileUtils, IOUtils}
|
||||
import org.eclipse.jgit.api.{ArchiveCommand, Git}
|
||||
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
|
||||
import org.eclipse.jgit.dircache.DirCache
|
||||
@@ -255,13 +255,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
val (id, path) = repository.splitPath(multiParams("splat").head)
|
||||
using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
|
||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))
|
||||
getPathObjectId(git, path, revCommit).flatMap { objectId =>
|
||||
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
|
||||
contentType = FileUtil.getMimeType(path)
|
||||
response.setContentLength(loader.getSize.toInt)
|
||||
loader.copyTo(response.outputStream)
|
||||
()
|
||||
}
|
||||
|
||||
getPathObjectId(git, path, revCommit).map { objectId =>
|
||||
responseRawFile(git, objectId, path)
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
@@ -277,23 +273,61 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
||||
getPathObjectId(git, path, revCommit).map { objectId =>
|
||||
if(raw){
|
||||
// Download (This route is left for backword compatibility)
|
||||
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
|
||||
contentType = FileUtil.getMimeType(path)
|
||||
response.setContentLength(loader.getSize.toInt)
|
||||
loader.copyTo(response.outputStream)
|
||||
()
|
||||
} getOrElse NotFound()
|
||||
responseRawFile(git, objectId, path)
|
||||
} else {
|
||||
html.blob(id, repository, path.split("/").toList,
|
||||
JGitUtil.getContentInfo(git, path, objectId),
|
||||
new JGitUtil.CommitInfo(JGitUtil.getLastModifiedCommit(git, revCommit, path)),
|
||||
hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
|
||||
request.paths(2) == "blame")
|
||||
request.paths(2) == "blame",
|
||||
isLfsFile(git, objectId))
|
||||
}
|
||||
} getOrElse NotFound()
|
||||
}
|
||||
})
|
||||
|
||||
private def isLfsFile(git: Git, objectId: ObjectId): Boolean = {
|
||||
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
|
||||
if(loader.isLarge){
|
||||
false
|
||||
} else {
|
||||
new String(loader.getCachedBytes, "UTF-8").startsWith("version https://git-lfs.github.com/spec/v1")
|
||||
}
|
||||
}.getOrElse(false)
|
||||
}
|
||||
|
||||
private def responseRawFile(git: Git, objectId: ObjectId, path: String): Unit = {
|
||||
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
|
||||
contentType = FileUtil.getMimeType(path)
|
||||
|
||||
if(loader.isLarge || context.settings.lfs.serverUrl.isEmpty){
|
||||
response.setContentLength(loader.getSize.toInt)
|
||||
loader.copyTo(response.outputStream)
|
||||
} else {
|
||||
val bytes = loader.getCachedBytes
|
||||
val text = new String(bytes, "UTF-8")
|
||||
|
||||
if(text.startsWith("version https://git-lfs.github.com/spec/v1")){
|
||||
// LFS objects
|
||||
val attrs = text.split("\n").map { line =>
|
||||
val dim = line.split(" ")
|
||||
dim(0) -> dim(1)
|
||||
}.toMap
|
||||
|
||||
response.setContentLength(attrs("size").toInt)
|
||||
val hash = attrs("oid").split(":")(1)
|
||||
|
||||
using(new FileInputStream(Directory.LfsHome + "/" + hash.substring(0, 2) + "/" + hash.substring(2, 4) + "/" + hash)){ in =>
|
||||
IOUtils.copy(in, response.getOutputStream)
|
||||
}
|
||||
} else {
|
||||
response.setContentLength(loader.getSize.toInt)
|
||||
response.getOutputStream.write(bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get("/:owner/:repository/blame/*"){
|
||||
blobRoute.action()
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ object Directory {
|
||||
|
||||
val TemporaryHome = s"${GitBucketHome}/tmp"
|
||||
|
||||
val LfsHome = s"${GitBucketHome}/lfs"
|
||||
|
||||
/**
|
||||
* Substance directory of the repository.
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
content: gitbucket.core.util.JGitUtil.ContentInfo,
|
||||
latestCommit: gitbucket.core.util.JGitUtil.CommitInfo,
|
||||
hasWritePermission: Boolean,
|
||||
isBlame: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||
isBlame: Boolean,
|
||||
isLfsFile: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||
@import gitbucket.core.view.helpers
|
||||
@gitbucket.core.html.main(s"${(repository.name :: pathList).mkString("/")} at ${helpers.encodeRefName(branch)} - ${repository.owner}/${repository.name}", Some(repository)) {
|
||||
@gitbucket.core.html.menu("files", repository){
|
||||
@@ -45,6 +46,9 @@
|
||||
<a href="@helpers.url(repository)/tree/@helpers.encodeRefName(branch)/@pathList.take(i + 1).mkString("/")">@section</a> /
|
||||
}
|
||||
}
|
||||
@if(isLfsFile){
|
||||
<span class="label label-info">LFS</span>
|
||||
}
|
||||
</div>
|
||||
<div class="box-header">
|
||||
@helpers.avatar(latestCommit, 28)
|
||||
|
||||
Reference in New Issue
Block a user