diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java index 7175d3b646..9bc40f409a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/GitUtil.java @@ -42,7 +42,10 @@ import com.google.common.collect.Multimap; import org.eclipse.jgit.api.FetchCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.attributes.Attribute; +import org.eclipse.jgit.attributes.Attributes; import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.lfs.LfsPointer; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -55,6 +58,7 @@ import org.eclipse.jgit.transport.FetchResult; import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.LfsFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.ContextEntry; @@ -65,10 +69,12 @@ import sonia.scm.web.GitUserAgentProvider; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; +import static java.util.Optional.empty; import static java.util.Optional.of; //~--- JDK imports ------------------------------------------------------------ @@ -731,6 +737,20 @@ public final class GitUtil } } + public static Optional getLfsPointer(org.eclipse.jgit.lib.Repository repo, String path, RevCommit commit, TreeWalk treeWalk) throws IOException { + Attributes attributes = LfsFactory.getAttributesForPath(repo, path, commit); + + Attribute filter = attributes.get("filter"); + if (filter != null && "lfs".equals(filter.getValue())) { + ObjectId blobId = treeWalk.getObjectId(0); + try (InputStream is = repo.open(blobId, Constants.OBJ_BLOB).openStream()) { + return of(LfsPointer.parseLfsPointer(is)); + } + } else { + return empty(); + } + } + //~--- methods -------------------------------------------------------------- /** diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java index 1bc59f8e1b..5ec69cccdd 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitBrowseCommand.java @@ -38,6 +38,7 @@ package sonia.scm.repository.spi; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import org.eclipse.jgit.lfs.LfsPointer; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; @@ -57,6 +58,8 @@ import sonia.scm.repository.GitSubModuleParser; import sonia.scm.repository.GitUtil; import sonia.scm.repository.Repository; import sonia.scm.repository.SubRepository; +import sonia.scm.store.Blob; +import sonia.scm.store.BlobStore; import sonia.scm.util.Util; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -65,6 +68,7 @@ import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import static sonia.scm.ContextEntry.ContextBuilder.entity; import static sonia.scm.NotFoundException.notFound; @@ -170,7 +174,7 @@ public class GitBrowseCommand extends AbstractGitCommand * @throws IOException */ private FileObject createFileObject(org.eclipse.jgit.lib.Repository repo, - BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) + BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException { FileObject file = new FileObject(); @@ -198,7 +202,6 @@ public class GitBrowseCommand extends AbstractGitCommand ObjectLoader loader = repo.open(treeWalk.getObjectId(0)); file.setDirectory(loader.getType() == Constants.OBJ_TREE); - file.setLength(loader.getSize()); // don't show message and date for directories to improve performance if (!file.isDirectory() &&!request.isDisableLastCommit()) @@ -206,6 +209,16 @@ public class GitBrowseCommand extends AbstractGitCommand logger.trace("fetch last commit for {} at {}", path, revId.getName()); RevCommit commit = getLatestCommit(repo, revId, path); + Optional lfsPointer = GitUtil.getLfsPointer(repo, path, commit, treeWalk); + + if (lfsPointer.isPresent()) { + BlobStore lfsBlobStore = lfsBlobStoreFactory.getLfsBlobStore(repository); + Blob blob = lfsBlobStore.get(lfsPointer.get().getOid().getName()); + file.setLength(blob.getSize()); + } else { + file.setLength(loader.getSize()); + } + if (commit != null) { file.setLastModified(GitUtil.getCommitTime(commit)); @@ -235,7 +248,7 @@ public class GitBrowseCommand extends AbstractGitCommand * @return */ private RevCommit getLatestCommit(org.eclipse.jgit.lib.Repository repo, - ObjectId revId, String path) + ObjectId revId, String path) { RevCommit result = null; RevWalk walk = null; @@ -342,7 +355,7 @@ public class GitBrowseCommand extends AbstractGitCommand } private FileObject findFirstMatch(org.eclipse.jgit.lib.Repository repo, - BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException { + BrowseCommandRequest request, ObjectId revId, TreeWalk treeWalk) throws IOException { String[] pathElements = request.getPath().split("/"); int currentDepth = 0; int limit = pathElements.length; @@ -367,7 +380,7 @@ public class GitBrowseCommand extends AbstractGitCommand @SuppressWarnings("unchecked") private Map getSubRepositories(org.eclipse.jgit.lib.Repository repo, - ObjectId revision) + ObjectId revision) throws IOException { if (logger.isDebugEnabled()) { @@ -392,7 +405,7 @@ public class GitBrowseCommand extends AbstractGitCommand } private SubRepository getSubRepository(org.eclipse.jgit.lib.Repository repo, - ObjectId revId, String path) + ObjectId revId, String path) throws IOException { Map subRepositories = subrepositoryCache.get(revId); @@ -413,7 +426,7 @@ public class GitBrowseCommand extends AbstractGitCommand } //~--- fields --------------------------------------------------------------- - + /** sub repository cache */ private final Map> subrepositoryCache = Maps.newHashMap(); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java index 21f4b942df..c9f33d84f4 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitCatCommand.java @@ -50,6 +50,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.GitUtil; import sonia.scm.store.Blob; +import sonia.scm.store.BlobStore; import sonia.scm.util.IOUtil; import sonia.scm.util.Util; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -59,6 +60,7 @@ import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Optional; import static sonia.scm.ContextEntry.ContextBuilder.entity; import static sonia.scm.NotFoundException.notFound; @@ -126,29 +128,27 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand { treeWalk.setFilter(PathFilter.create(path)); if (treeWalk.next() && treeWalk.getFileMode(0).getObjectType() == Constants.OBJ_BLOB) { - Attributes attributes = LfsFactory.getAttributesForPath(repo, path, entry); - - Attribute filter = attributes.get("filter"); - if (filter != null && "lfs".equals(filter.getValue())) { - return loadFromLfsStore(repo, treeWalk, revWalk); + Optional lfsPointer = GitUtil.getLfsPointer(repo, path, entry, treeWalk); + if (lfsPointer.isPresent()) { + return loadFromLfsStore(treeWalk, revWalk, lfsPointer.get()); + } else { + return loadFromGit(repo, treeWalk, revWalk); } - - ObjectId blobId = treeWalk.getObjectId(0); - ObjectLoader loader = repo.open(blobId); - - return new GitObjectLoaderWrapper(loader, treeWalk, revWalk); } else { throw notFound(entity("Path", path).in("Revision", revId.getName()).in(repository)); } } - private Loader loadFromLfsStore(Repository repo, TreeWalk treeWalk, RevWalk revWalk) throws IOException { + private Loader loadFromGit(Repository repo, TreeWalk treeWalk, RevWalk revWalk) throws IOException { ObjectId blobId = treeWalk.getObjectId(0); - LfsPointer lfsPointer; - try (InputStream is = repo.open(blobId, Constants.OBJ_BLOB).openStream()) { - lfsPointer = LfsPointer.parseLfsPointer(is); - } - Blob blob = lfsBlobStoreFactory.getLfsBlobStore(repository).get(lfsPointer.getOid().getName()); + ObjectLoader loader = repo.open(blobId); + + return new GitObjectLoaderWrapper(loader, treeWalk, revWalk); + } + + private Loader loadFromLfsStore(TreeWalk treeWalk, RevWalk revWalk, LfsPointer lfsPointer) throws IOException { + BlobStore lfsBlobStore = lfsBlobStoreFactory.getLfsBlobStore(repository); + Blob blob = lfsBlobStore.get(lfsPointer.getOid().getName()); GitUtil.release(revWalk); GitUtil.release(treeWalk); return new BlobLoader(blob);