mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-11 16:05:49 +01:00
(refs #1101)Support LFS files in the blob view
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package gitbucket.core.controller
|
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.plugin.PluginRegistry
|
||||||
import gitbucket.core.repo.html
|
import gitbucket.core.repo.html
|
||||||
@@ -16,9 +17,8 @@ import gitbucket.core.model.{Account, WebHook}
|
|||||||
import gitbucket.core.service.WebHookService._
|
import gitbucket.core.service.WebHookService._
|
||||||
import gitbucket.core.view
|
import gitbucket.core.view
|
||||||
import gitbucket.core.view.helpers
|
import gitbucket.core.view.helpers
|
||||||
|
|
||||||
import io.github.gitbucket.scalatra.forms._
|
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.api.{ArchiveCommand, Git}
|
||||||
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
|
import org.eclipse.jgit.archive.{TgzFormat, ZipFormat}
|
||||||
import org.eclipse.jgit.dircache.DirCache
|
import org.eclipse.jgit.dircache.DirCache
|
||||||
@@ -255,13 +255,9 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
val (id, path) = repository.splitPath(multiParams("splat").head)
|
val (id, path) = repository.splitPath(multiParams("splat").head)
|
||||||
using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
|
using(Git.open(getRepositoryDir(repository.owner, repository.name))){ git =>
|
||||||
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))
|
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))
|
||||||
getPathObjectId(git, path, revCommit).flatMap { objectId =>
|
|
||||||
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
|
getPathObjectId(git, path, revCommit).map { objectId =>
|
||||||
contentType = FileUtil.getMimeType(path)
|
responseRawFile(git, objectId, path)
|
||||||
response.setContentLength(loader.getSize.toInt)
|
|
||||||
loader.copyTo(response.outputStream)
|
|
||||||
()
|
|
||||||
}
|
|
||||||
} getOrElse NotFound()
|
} getOrElse NotFound()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -277,23 +273,61 @@ trait RepositoryViewerControllerBase extends ControllerBase {
|
|||||||
getPathObjectId(git, path, revCommit).map { objectId =>
|
getPathObjectId(git, path, revCommit).map { objectId =>
|
||||||
if(raw){
|
if(raw){
|
||||||
// Download (This route is left for backword compatibility)
|
// Download (This route is left for backword compatibility)
|
||||||
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
|
responseRawFile(git, objectId, path)
|
||||||
contentType = FileUtil.getMimeType(path)
|
|
||||||
response.setContentLength(loader.getSize.toInt)
|
|
||||||
loader.copyTo(response.outputStream)
|
|
||||||
()
|
|
||||||
} getOrElse NotFound()
|
|
||||||
} else {
|
} else {
|
||||||
html.blob(id, repository, path.split("/").toList,
|
html.blob(id, repository, path.split("/").toList,
|
||||||
JGitUtil.getContentInfo(git, path, objectId),
|
JGitUtil.getContentInfo(git, path, objectId),
|
||||||
new JGitUtil.CommitInfo(JGitUtil.getLastModifiedCommit(git, revCommit, path)),
|
new JGitUtil.CommitInfo(JGitUtil.getLastModifiedCommit(git, revCommit, path)),
|
||||||
hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
|
hasDeveloperRole(repository.owner, repository.name, context.loginAccount),
|
||||||
request.paths(2) == "blame")
|
request.paths(2) == "blame",
|
||||||
|
isLfsFile(git, objectId))
|
||||||
}
|
}
|
||||||
} getOrElse NotFound()
|
} 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/*"){
|
get("/:owner/:repository/blame/*"){
|
||||||
blobRoute.action()
|
blobRoute.action()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ object Directory {
|
|||||||
|
|
||||||
val TemporaryHome = s"${GitBucketHome}/tmp"
|
val TemporaryHome = s"${GitBucketHome}/tmp"
|
||||||
|
|
||||||
|
val LfsHome = s"${GitBucketHome}/lfs"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Substance directory of the repository.
|
* Substance directory of the repository.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
content: gitbucket.core.util.JGitUtil.ContentInfo,
|
content: gitbucket.core.util.JGitUtil.ContentInfo,
|
||||||
latestCommit: gitbucket.core.util.JGitUtil.CommitInfo,
|
latestCommit: gitbucket.core.util.JGitUtil.CommitInfo,
|
||||||
hasWritePermission: Boolean,
|
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
|
@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.main(s"${(repository.name :: pathList).mkString("/")} at ${helpers.encodeRefName(branch)} - ${repository.owner}/${repository.name}", Some(repository)) {
|
||||||
@gitbucket.core.html.menu("files", 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> /
|
<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>
|
||||||
<div class="box-header">
|
<div class="box-header">
|
||||||
@helpers.avatar(latestCommit, 28)
|
@helpers.avatar(latestCommit, 28)
|
||||||
|
|||||||
Reference in New Issue
Block a user