Merge pull request #1401 from gitbucket/git-lfs-support
GitLFS support
commit 3c34689e7d7f242da17c0b9846f189dcad3992ab
2 parents 72049c5 + b95d912
@Naoki Takezoe Naoki Takezoe authored on 5 Jan 2017
GitHub committed on 5 Jan 2017
Showing 15 changed files
View
2
■■■
src/main/scala/gitbucket/core/controller/ControllerBase.scala
} else {
// Redirect to dashboard
httpResponse.sendRedirect(baseUrl + "/")
}
} else if(path.startsWith("/git/")){
} else if(path.startsWith("/git/") || path.startsWith("/git-lfs/")){
// Git repository
chain.doFilter(request, response)
} else {
if(path.startsWith("/api/v3/")){
View
80
src/main/scala/gitbucket/core/controller/RepositoryViewerController.scala
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
import gitbucket.core.helper
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
import org.eclipse.jgit.errors.MissingObjectException
get("/:owner/:repository/raw/*")(referrersOnly { repository =>
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, repository)
} getOrElse NotFound()
}
})
 
val revCommit = JGitUtil.getRevCommitFromId(git, git.getRepository.resolve(id))
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, repository)
} 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,
repository: RepositoryService.RepositoryInfo): Unit = {
JGitUtil.getObjectLoaderFromId(git, objectId){ loader =>
contentType = FileUtil.getMimeType(path)
 
if(loader.isLarge){
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 oid = attrs("oid").split(":")(1)
 
using(new FileInputStream(FileUtil.getLfsFilePath(repository.owner, repository.name, oid))){ in =>
IOUtils.copy(in, response.getOutputStream)
}
} else {
response.setContentLength(loader.getSize.toInt)
response.getOutputStream.write(bytes)
}
}
}
}
 
get("/:owner/:repository/blame/*"){
blobRoute.action()
}
View
src/main/scala/gitbucket/core/service/AccessTokenService.scala
View
src/main/scala/gitbucket/core/service/SystemSettingsService.scala
View
src/main/scala/gitbucket/core/servlet/GitLfsTransferServlet.scala 0 → 100644
View
src/main/scala/gitbucket/core/servlet/GitRepositoryServlet.scala
View
src/main/scala/gitbucket/core/servlet/TransactionFilter.scala
View
src/main/scala/gitbucket/core/util/ControlUtil.scala
View
src/main/scala/gitbucket/core/util/Directory.scala
View
src/main/scala/gitbucket/core/util/FileUtil.scala
View
src/main/scala/gitbucket/core/util/StringUtil.scala
View
src/main/twirl/gitbucket/core/admin/system.scala.html
View
src/main/twirl/gitbucket/core/repo/blob.scala.html
View
src/main/webapp/WEB-INF/web.xml
View
src/test/scala/gitbucket/core/view/AvatarImageProviderSpec.scala