From eecaad8b8e2c447429c31a01d49260ddd6b4ee03 Mon Sep 17 00:00:00 2001 From: Paul Martin <paul@paulsputer.com> Date: Sat, 16 Apr 2016 17:35:32 -0400 Subject: [PATCH] Proof of concept #1026 --- src/main/java/com/gitblit/utils/CompressionUtils.java | 134 ++++++++++++++++++++++++++++++++------------ 1 files changed, 97 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/gitblit/utils/CompressionUtils.java b/src/main/java/com/gitblit/utils/CompressionUtils.java index a8dcdd8..1b8e6fc 100644 --- a/src/main/java/com/gitblit/utils/CompressionUtils.java +++ b/src/main/java/com/gitblit/utils/CompressionUtils.java @@ -15,6 +15,10 @@ */ package com.gitblit.utils; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.text.MessageFormat; @@ -27,10 +31,11 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.compress.compressors.CompressorException; import org.apache.commons.compress.compressors.CompressorStreamFactory; -import org.apache.wicket.util.io.ByteArrayOutputStream; +import org.apache.commons.io.IOUtils; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; @@ -41,11 +46,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.GitBlit; +import com.gitblit.manager.IFilestoreManager; +import com.gitblit.models.FilestoreModel; +import com.gitblit.models.FilestoreModel.Status; + /** * Collection of static methods for retrieving information from a repository. - * + * * @author James Moger - * + * */ public class CompressionUtils { @@ -53,7 +63,7 @@ /** * Log an error message and exception. - * + * * @param t * @param repository * if repository is not null it MUST be the {0} parameter in the @@ -77,7 +87,7 @@ /** * Zips the contents of the tree at the (optionally) specified revision and * the (optionally) specified basepath to the supplied outputstream. - * + * * @param repository * @param basePath * if unspecified, entire repository is assumed. @@ -87,7 +97,7 @@ * @return true if repository was successfully zipped to supplied output * stream */ - public static boolean zip(Repository repository, String basePath, String objectId, + public static boolean zip(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId, OutputStream os) { RevCommit commit = JGitUtils.getCommit(repository, objectId); if (commit == null) { @@ -115,16 +125,40 @@ continue; } tw.getObjectId(id, 0); - + + ObjectLoader loader = repository.open(id); + ZipArchiveEntry entry = new ZipArchiveEntry(tw.getPathString()); - entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB)); + + FilestoreModel filestoreItem = null; + + if (JGitUtils.isPossibleFilestoreItem(loader.getSize())) { + filestoreItem = JGitUtils.getFilestoreItem(tw.getObjectReader().open(id)); + } + + final long size = (filestoreItem == null) ? loader.getSize() : filestoreItem.getSize(); + + entry.setSize(size); entry.setComment(commit.getName()); entry.setUnixMode(mode.getBits()); entry.setTime(modified); zos.putArchiveEntry(entry); + + if (filestoreItem == null) { + //Copy repository stored file + loader.copyTo(zos); + } else { + //Copy filestore file + try (FileInputStream streamIn = new FileInputStream(filestoreManager.getStoragePath(filestoreItem.oid))) { + IOUtils.copyLarge(streamIn, zos); + } catch (Throwable e) { + LOGGER.error(MessageFormat.format("Failed to archive filestore item {0}", filestoreItem.oid), e); - ObjectLoader ldr = repository.open(id); - ldr.copyTo(zos); + //Handle as per other errors + throw e; + } + } + zos.closeArchiveEntry(); } zos.finish(); @@ -132,16 +166,16 @@ } catch (IOException e) { error(e, repository, "{0} failed to zip files from commit {1}", commit.getName()); } finally { - tw.release(); + tw.close(); rw.dispose(); } return success; } - + /** * tar the contents of the tree at the (optionally) specified revision and * the (optionally) specified basepath to the supplied outputstream. - * + * * @param repository * @param basePath * if unspecified, entire repository is assumed. @@ -151,15 +185,15 @@ * @return true if repository was successfully zipped to supplied output * stream */ - public static boolean tar(Repository repository, String basePath, String objectId, + public static boolean tar(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId, OutputStream os) { - return tar(null, repository, basePath, objectId, os); + return tar(null, repository, filestoreManager, basePath, objectId, os); } - + /** * tar.gz the contents of the tree at the (optionally) specified revision and * the (optionally) specified basepath to the supplied outputstream. - * + * * @param repository * @param basePath * if unspecified, entire repository is assumed. @@ -169,15 +203,15 @@ * @return true if repository was successfully zipped to supplied output * stream */ - public static boolean gz(Repository repository, String basePath, String objectId, + public static boolean gz(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId, OutputStream os) { - return tar(CompressorStreamFactory.GZIP, repository, basePath, objectId, os); + return tar(CompressorStreamFactory.GZIP, repository, filestoreManager, basePath, objectId, os); } - + /** * tar.xz the contents of the tree at the (optionally) specified revision and * the (optionally) specified basepath to the supplied outputstream. - * + * * @param repository * @param basePath * if unspecified, entire repository is assumed. @@ -187,15 +221,15 @@ * @return true if repository was successfully zipped to supplied output * stream */ - public static boolean xz(Repository repository, String basePath, String objectId, + public static boolean xz(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId, OutputStream os) { - return tar(CompressorStreamFactory.XZ, repository, basePath, objectId, os); + return tar(CompressorStreamFactory.XZ, repository, filestoreManager, basePath, objectId, os); } - + /** * tar.bzip2 the contents of the tree at the (optionally) specified revision and * the (optionally) specified basepath to the supplied outputstream. - * + * * @param repository * @param basePath * if unspecified, entire repository is assumed. @@ -205,17 +239,17 @@ * @return true if repository was successfully zipped to supplied output * stream */ - public static boolean bzip2(Repository repository, String basePath, String objectId, + public static boolean bzip2(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId, OutputStream os) { - - return tar(CompressorStreamFactory.BZIP2, repository, basePath, objectId, os); + + return tar(CompressorStreamFactory.BZIP2, repository, filestoreManager, basePath, objectId, os); } - + /** * Compresses/archives the contents of the tree at the (optionally) * specified revision and the (optionally) specified basepath to the * supplied outputstream. - * + * * @param algorithm * compression algorithm for tar (optional) * @param repository @@ -227,13 +261,13 @@ * @return true if repository was successfully zipped to supplied output * stream */ - private static boolean tar(String algorithm, Repository repository, String basePath, String objectId, + private static boolean tar(String algorithm, Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId, OutputStream os) { RevCommit commit = JGitUtils.getCommit(repository, objectId); if (commit == null) { return false; } - + OutputStream cos = os; if (!StringUtils.isEmpty(algorithm)) { try { @@ -263,8 +297,9 @@ if (mode == FileMode.GITLINK || mode == FileMode.TREE) { continue; } - tw.getObjectId(id, 0); + tw.getObjectId(id, 0); + ObjectLoader loader = repository.open(id); if (FileMode.SYMLINK == mode) { TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString(),TarArchiveEntry.LF_SYMLINK); @@ -278,9 +313,34 @@ TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString()); entry.setMode(mode.getBits()); entry.setModTime(modified); - entry.setSize(loader.getSize()); - tos.putArchiveEntry(entry); - loader.copyTo(tos); + + FilestoreModel filestoreItem = null; + + if (JGitUtils.isPossibleFilestoreItem(loader.getSize())) { + filestoreItem = JGitUtils.getFilestoreItem(tw.getObjectReader().open(id)); + } + + final long size = (filestoreItem == null) ? loader.getSize() : filestoreItem.getSize(); + + entry.setSize(size); + tos.putArchiveEntry(entry); + + if (filestoreItem == null) { + //Copy repository stored file + loader.copyTo(tos); + } else { + //Copy filestore file + try (FileInputStream streamIn = new FileInputStream(filestoreManager.getStoragePath(filestoreItem.oid))) { + + IOUtils.copyLarge(streamIn, tos); + } catch (Throwable e) { + LOGGER.error(MessageFormat.format("Failed to archive filestore item {0}", filestoreItem.oid), e); + + //Handle as per other errors + throw e; + } + } + tos.closeArchiveEntry(); } } @@ -291,7 +351,7 @@ } catch (IOException e) { error(e, repository, "{0} failed to {1} stream files from commit {2}", algorithm, commit.getName()); } finally { - tw.release(); + tw.close(); rw.dispose(); } return success; -- Gitblit v1.9.1