diff --git a/scm-core/src/main/java/sonia/scm/repository/api/CatCommandBuilder.java b/scm-core/src/main/java/sonia/scm/repository/api/CatCommandBuilder.java
index f7b4d75fbd..8a08663f25 100644
--- a/scm-core/src/main/java/sonia/scm/repository/api/CatCommandBuilder.java
+++ b/scm-core/src/main/java/sonia/scm/repository/api/CatCommandBuilder.java
@@ -37,22 +37,21 @@ package sonia.scm.repository.api;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.spi.CatCommand;
import sonia.scm.repository.spi.CatCommandRequest;
import sonia.scm.util.IOUtil;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+//~--- JDK imports ------------------------------------------------------------
+
/**
* Shows the content of a file in the {@link Repository}.
*
@@ -106,23 +105,31 @@ public final class CatCommandBuilder
}
/**
- * Passes the content of the given file to the outputstream.
+ * Passes the content of the given file to the output stream.
*
- * @param outputStream outputstream for the content
+ * @param outputStream output stream for the content
* @param path file path
- *
- * @return {@code this}
- *
- * @throws IOException
- * @throws RepositoryException
*/
- public CatCommandBuilder retriveContent(OutputStream outputStream,
- String path)
- throws IOException, RepositoryException
- {
+ public void retriveContent(OutputStream outputStream, String path) throws IOException, RepositoryException {
getCatResult(outputStream, path);
+ }
- return this;
+ /**
+ * Returns an output stream with the file content.
+ *
+ * @param path file path
+ */
+ public InputStream getStream(String path) throws IOException, RepositoryException {
+ Preconditions.checkArgument(!Strings.isNullOrEmpty(path),
+ "path is required");
+
+ CatCommandRequest requestClone = request.clone();
+
+ requestClone.setPath(path);
+
+ logger.debug("create cat stream for {}", requestClone);
+
+ return catCommand.getCatResultStream(requestClone);
}
//~--- get methods ----------------------------------------------------------
diff --git a/scm-core/src/main/java/sonia/scm/repository/spi/CatCommand.java b/scm-core/src/main/java/sonia/scm/repository/spi/CatCommand.java
index b9a6f52ab0..cbf1866298 100644
--- a/scm-core/src/main/java/sonia/scm/repository/spi/CatCommand.java
+++ b/scm-core/src/main/java/sonia/scm/repository/spi/CatCommand.java
@@ -37,11 +37,12 @@ package sonia.scm.repository.spi;
import sonia.scm.repository.RepositoryException;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -50,16 +51,7 @@ import java.io.OutputStream;
public interface CatCommand
{
- /**
- * Method description
- *
- *
- * @param request
- * @param output
- *
- * @throws IOException
- * @throws RepositoryException
- */
- public void getCatResult(CatCommandRequest request, OutputStream output)
- throws IOException, RepositoryException;
+ void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, RepositoryException;
+
+ InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException;
}
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 4420b9a22a..fdf8042c57 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
@@ -34,29 +34,29 @@ package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
-import com.google.common.base.Strings;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import sonia.scm.repository.GitUtil;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import sonia.scm.util.Util;
-//~--- JDK imports ------------------------------------------------------------
-
+import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -110,22 +110,31 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
getContent(repo, revId, request.getPath(), output);
}
- /**
- * Method description
- *
- *
- *
- * @param repo
- * @param revId
- * @param path
- * @param output
- *
- *
- * @throws IOException
- * @throws RepositoryException
- */
+ @Override
+ public InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException {
+ logger.debug("try to read content for {}", request);
+
+ org.eclipse.jgit.lib.Repository repo = open();
+
+ ObjectId revId = getCommitOrDefault(repo, request.getRevision());
+ ClosableObjectLoaderContainer closableObjectLoaderContainer = getLoader(repo, revId, request.getPath());
+ return new InputStreamWrapper(closableObjectLoaderContainer);
+ }
+
void getContent(org.eclipse.jgit.lib.Repository repo, ObjectId revId,
- String path, OutputStream output)
+ String path, OutputStream output)
+ throws IOException, RepositoryException
+ {
+ ClosableObjectLoaderContainer closableObjectLoaderContainer = getLoader(repo, revId, path);
+ try {
+ closableObjectLoaderContainer.objectLoader.copyTo(output);
+ } finally {
+ closableObjectLoaderContainer.close();
+ }
+ }
+
+ private ClosableObjectLoaderContainer getLoader(Repository repo, ObjectId revId,
+ String path)
throws IOException, RepositoryException
{
TreeWalk treeWalk = null;
@@ -157,23 +166,12 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
treeWalk.setFilter(PathFilter.create(path));
- if (treeWalk.next())
+ if (treeWalk.next() && treeWalk.getFileMode(0).getObjectType() == Constants.OBJ_BLOB)
{
+ ObjectId blobId = treeWalk.getObjectId(0);
+ ObjectLoader loader = repo.open(blobId);
- // Path exists
- if (treeWalk.getFileMode(0).getObjectType() == Constants.OBJ_BLOB)
- {
- ObjectId blobId = treeWalk.getObjectId(0);
- ObjectLoader loader = repo.open(blobId);
-
- loader.copyTo(output);
- }
- else
- {
-
- // Not a blob, its something else (tree, gitlink)
- throw new PathNotFoundException(path);
- }
+ return new ClosableObjectLoaderContainer(loader, treeWalk, revWalk);
}
else
{
@@ -182,8 +180,52 @@ public class GitCatCommand extends AbstractGitCommand implements CatCommand
}
finally
{
+ }
+ }
+
+ private static class ClosableObjectLoaderContainer implements Closeable {
+ private final ObjectLoader objectLoader;
+ private final TreeWalk treeWalk;
+ private final RevWalk revWalk;
+
+ private ClosableObjectLoaderContainer(ObjectLoader objectLoader, TreeWalk treeWalk, RevWalk revWalk) {
+ this.objectLoader = objectLoader;
+ this.treeWalk = treeWalk;
+ this.revWalk = revWalk;
+ }
+
+ @Override
+ public void close() throws IOException {
GitUtil.release(revWalk);
GitUtil.release(treeWalk);
}
}
+
+ private static class InputStreamWrapper extends InputStream {
+
+ private final InputStream delegate;
+ private final TreeWalk treeWalk;
+ private final RevWalk revWalk;
+
+ private InputStreamWrapper(ClosableObjectLoaderContainer container) throws IOException {
+ this(container.objectLoader.openStream(), container.treeWalk, container.revWalk);
+ }
+
+ private InputStreamWrapper(InputStream delegate, TreeWalk treeWalk, RevWalk revWalk) {
+ this.delegate = delegate;
+ this.treeWalk = treeWalk;
+ this.revWalk = revWalk;
+ }
+
+ @Override
+ public int read () throws IOException {
+ return delegate.read();
+ }
+
+ @Override
+ public void close () throws IOException {
+ GitUtil.release(revWalk);
+ GitUtil.release(treeWalk);
+ }
+ }
}
diff --git a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCatCommand.java b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCatCommand.java
index 76438c1f1e..a8e585915e 100644
--- a/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCatCommand.java
+++ b/scm-plugins/scm-hg-plugin/src/main/java/sonia/scm/repository/spi/HgCatCommand.java
@@ -37,17 +37,16 @@ package sonia.scm.repository.spi;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
-
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.web.HgUtil;
-//~--- JDK imports ------------------------------------------------------------
-
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -83,16 +82,9 @@ public class HgCatCommand extends AbstractCommand implements CatCommand
public void getCatResult(CatCommandRequest request, OutputStream output)
throws IOException, RepositoryException
{
- com.aragost.javahg.commands.CatCommand cmd =
- com.aragost.javahg.commands.CatCommand.on(open());
-
- cmd.rev(HgUtil.getRevision(request.getRevision()));
-
- InputStream input = null;
-
+ InputStream input = getCatResultStream(request);
try
{
- input = cmd.execute(request.getPath());
ByteStreams.copy(input, output);
}
finally
@@ -100,4 +92,14 @@ public class HgCatCommand extends AbstractCommand implements CatCommand
Closeables.close(input, true);
}
}
+
+ @Override
+ public InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException {
+ com.aragost.javahg.commands.CatCommand cmd =
+ com.aragost.javahg.commands.CatCommand.on(open());
+
+ cmd.rev(HgUtil.getRevision(request.getRevision()));
+
+ return cmd.execute(request.getPath());
+ }
}
diff --git a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnCatCommand.java b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnCatCommand.java
index af08ea929e..5bd3c54b1b 100644
--- a/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnCatCommand.java
+++ b/scm-plugins/scm-svn-plugin/src/main/java/sonia/scm/repository/spi/SvnCatCommand.java
@@ -37,22 +37,23 @@ package sonia.scm.repository.spi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.admin.SVNLookClient;
-
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.SvnUtil;
-//~--- JDK imports ------------------------------------------------------------
-
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+//~--- JDK imports ------------------------------------------------------------
+
/**
*
* @author Sebastian Sdorra
@@ -120,6 +121,16 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
}
}
+ @Override
+ public InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException {
+ // There seems to be no method creating an input stream as a result, so
+ // we have no other possibility then to copy the content into a buffer and
+ // stream it from there.
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ getCatResult(request, output);
+ return new ByteArrayInputStream(output.toByteArray());
+ }
+
/**
* Method description
*