]> source.dussan.org Git - gitblit.git/commitdiff
Support alternate compressed download formats (issue-174)
authorJames Moger <james.moger@gitblit.com>
Fri, 30 Nov 2012 23:05:35 +0000 (18:05 -0500)
committerJames Moger <james.moger@gitblit.com>
Fri, 30 Nov 2012 23:05:35 +0000 (18:05 -0500)
12 files changed:
distrib/gitblit.properties
docs/04_releases.mkd
src/com/gitblit/DownloadZipServlet.java
src/com/gitblit/utils/CompressionUtils.java [new file with mode: 0644]
src/com/gitblit/utils/JGitUtils.java
src/com/gitblit/wicket/pages/CommitPage.html
src/com/gitblit/wicket/pages/CommitPage.java
src/com/gitblit/wicket/pages/TreePage.html
src/com/gitblit/wicket/pages/TreePage.java
src/com/gitblit/wicket/panels/CompressedDownloadsPanel.html [new file with mode: 0644]
src/com/gitblit/wicket/panels/CompressedDownloadsPanel.java [new file with mode: 0644]
tests/com/gitblit/tests/JGitUtilsTest.java

index ee050a486380af562178152328b844dc72b0b5f6..233fdfad04f8a2b7ffd5dececf5d65cdf860f281 100644 (file)
@@ -482,6 +482,19 @@ web.allowGravatar = true
 # SINCE 0.5.0   \r
 web.allowZipDownloads = true\r
 \r
+# If *web.allowZipDownloads=true* the following formats will be displayed for\r
+# download compressed archive links:\r
+#\r
+# zip   = standard .zip\r
+# tar   = standard tar format (preserves *nix permissions and symlinks)\r
+# gz    = gz-compressed tar\r
+# xz    = xz-compressed tar\r
+# bzip2 = bzip2-compressed tar\r
+#\r
+# SPACE-DELIMITED\r
+# SINCE 1.2.0\r
+web.compressedDownloads = zip gz\r
+\r
 # Allow optional Lucene integration. Lucene indexing is an opt-in feature.\r
 # A repository may specify branches to index with Lucene instead of using Git\r
 # commit traversal. There are scenarios where you may want to completely disable\r
index 70a853fcf91b851cef4f543a975052d2380758a3..3f03160a1e0141896106895d38dc217d729ac3fa 100644 (file)
@@ -60,6 +60,8 @@ This is extreme and should be considered carefully since it affects every https
 - Added Gitblit Certificate Authority, an X509 certificate generation tool for Gitblit GO to encourage use of client certificate authentication.\r
 - Added setting to control length of shortened commit ids  \r
     **New:** *web.shortCommitIdLength=8*  \r
+- Added alternate compressed download formats: tar.gz, tar.xz, tar.bzip2 (issue 174)  \r
+    **New:** *web.compressedDownloads = zip gz*\r
 - Added simple project pages.  A project is a subfolder off the *git.repositoriesFolder*.\r
 - Added support for X-Forwarded-Context for Apache subdomain proxy configurations (issue 135)\r
 - Delete branch feature (issue 121, Github/ajermakovics)\r
@@ -70,6 +72,7 @@ This is extreme and should be considered carefully since it affects every https
 \r
 #### changes\r
 \r
+- Access restricted servlets (e.g. DownloadZip, RSS, etc) will try to authenticate any Gitblit cookie found in the request before resorting to BASIC authentication.\r
 - Added *groovy* and *scala* to *web.prettyPrintExtensions*\r
 - Added short commit id column to log and history tables (issue 168)\r
 - Teams can now specify the *admin*, *create*, and *fork* roles to simplify user administration\r
index 26559344ce804972cbcf09692cc76da19303f186..0feee8795c1d97b0adf566de68a48ad64dfe7db3 100644 (file)
@@ -29,6 +29,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
 import org.slf4j.Logger;\r
 import org.slf4j.LoggerFactory;\r
 \r
+import com.gitblit.utils.CompressionUtils;\r
 import com.gitblit.utils.JGitUtils;\r
 import com.gitblit.utils.MarkdownUtils;\r
 import com.gitblit.utils.StringUtils;\r
@@ -45,6 +46,25 @@ public class DownloadZipServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;\r
 \r
        private transient Logger logger = LoggerFactory.getLogger(DownloadZipServlet.class);\r
+       \r
+       public static enum Format {\r
+               zip(".zip"), tar(".tar"), gz(".tar.gz"), xz(".tar.xz"), bzip2(".tar.bzip2");\r
+               \r
+               public final String extension;\r
+               \r
+               Format(String ext) {\r
+                       this.extension = ext;\r
+               }\r
+               \r
+               public static Format fromName(String name) {\r
+                       for (Format format : values()) {\r
+                               if (format.name().equalsIgnoreCase(name)) {\r
+                                       return format;\r
+                               }\r
+                       }\r
+                       return zip;\r
+               }\r
+       }\r
 \r
        public DownloadZipServlet() {\r
                super();\r
@@ -57,15 +77,17 @@ public class DownloadZipServlet extends HttpServlet {
         * @param repository\r
         * @param objectId\r
         * @param path\r
+        * @param format\r
         * @return an url\r
         */\r
-       public static String asLink(String baseURL, String repository, String objectId, String path) {\r
+       public static String asLink(String baseURL, String repository, String objectId, String path, Format format) {\r
                if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {\r
                        baseURL = baseURL.substring(0, baseURL.length() - 1);\r
                }\r
                return baseURL + Constants.ZIP_PATH + "?r=" + repository\r
                                + (path == null ? "" : ("&p=" + path))\r
-                               + (objectId == null ? "" : ("&h=" + objectId));\r
+                               + (objectId == null ? "" : ("&h=" + objectId))\r
+                               + (format == null ? "" : ("&format=" + format.name()));\r
        }\r
 \r
        /**\r
@@ -84,16 +106,22 @@ public class DownloadZipServlet extends HttpServlet {
                        response.sendError(HttpServletResponse.SC_FORBIDDEN);\r
                        return;\r
                }\r
-\r
+               \r
+               Format format = Format.zip;\r
                String repository = request.getParameter("r");\r
                String basePath = request.getParameter("p");\r
                String objectId = request.getParameter("h");\r
-\r
+               String f = request.getParameter("format");\r
+               if (!StringUtils.isEmpty(f)) {\r
+                       format = Format.fromName(f);\r
+               }\r
+               \r
                try {\r
                        String name = repository;\r
                        if (name.indexOf('/') > -1) {\r
                                name = name.substring(name.lastIndexOf('/') + 1);\r
                        }\r
+                       name = StringUtils.stripDotGit(name);\r
 \r
                        if (!StringUtils.isEmpty(basePath)) {\r
                                name += "-" + basePath.replace('/', '_');\r
@@ -122,15 +150,31 @@ public class DownloadZipServlet extends HttpServlet {
 \r
                        String contentType = "application/octet-stream";\r
                        response.setContentType(contentType + "; charset=" + response.getCharacterEncoding());\r
-                       response.setHeader("Content-Disposition", "attachment; filename=\"" + name + ".zip"\r
-                                       + "\"");\r
+                       response.setHeader("Content-Disposition", "attachment; filename=\"" + name + format.extension + "\"");\r
                        response.setDateHeader("Last-Modified", date.getTime());\r
                        response.setHeader("Cache-Control", "no-cache");\r
                        response.setHeader("Pragma", "no-cache");\r
                        response.setDateHeader("Expires", 0);\r
 \r
                        try {\r
-                               JGitUtils.zip(r, basePath, objectId, response.getOutputStream());\r
+                               switch (format) {\r
+                               case zip:\r
+                                       CompressionUtils.zip(r, basePath, objectId, response.getOutputStream());\r
+                                       break;\r
+                               case tar:\r
+                                       CompressionUtils.tar(r, basePath, objectId, response.getOutputStream());\r
+                                       break;\r
+                               case gz:\r
+                                       CompressionUtils.gz(r, basePath, objectId, response.getOutputStream());\r
+                                       break;\r
+                               case xz:\r
+                                       CompressionUtils.xz(r, basePath, objectId, response.getOutputStream());\r
+                                       break;\r
+                               case bzip2:\r
+                                       CompressionUtils.bzip2(r, basePath, objectId, response.getOutputStream());\r
+                                       break;\r
+                               }\r
+                               \r
                                response.flushBuffer();\r
                        } catch (Throwable t) {\r
                                logger.error("Failed to write attachment to client", t);\r
diff --git a/src/com/gitblit/utils/CompressionUtils.java b/src/com/gitblit/utils/CompressionUtils.java
new file mode 100644 (file)
index 0000000..7b0d047
--- /dev/null
@@ -0,0 +1,315 @@
+/*\r
+ * Copyright 2012 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit.utils;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.text.MessageFormat;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.zip.ZipEntry;\r
+import java.util.zip.ZipOutputStream;\r
+\r
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;\r
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\r
+import org.apache.commons.compress.compressors.CompressorException;\r
+import org.apache.commons.compress.compressors.CompressorStreamFactory;\r
+import org.apache.commons.compress.utils.IOUtils;\r
+import org.eclipse.jgit.lib.Constants;\r
+import org.eclipse.jgit.lib.FileMode;\r
+import org.eclipse.jgit.lib.ObjectId;\r
+import org.eclipse.jgit.lib.ObjectLoader;\r
+import org.eclipse.jgit.lib.Repository;\r
+import org.eclipse.jgit.revwalk.RevBlob;\r
+import org.eclipse.jgit.revwalk.RevCommit;\r
+import org.eclipse.jgit.revwalk.RevWalk;\r
+import org.eclipse.jgit.treewalk.TreeWalk;\r
+import org.eclipse.jgit.treewalk.filter.PathFilter;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+/**\r
+ * Collection of static methods for retrieving information from a repository.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
+public class CompressionUtils {\r
+\r
+       static final Logger LOGGER = LoggerFactory.getLogger(CompressionUtils.class);\r
+\r
+       /**\r
+        * Log an error message and exception.\r
+        * \r
+        * @param t\r
+        * @param repository\r
+        *            if repository is not null it MUST be the {0} parameter in the\r
+        *            pattern.\r
+        * @param pattern\r
+        * @param objects\r
+        */\r
+       private static void error(Throwable t, Repository repository, String pattern, Object... objects) {\r
+               List<Object> parameters = new ArrayList<Object>();\r
+               if (objects != null && objects.length > 0) {\r
+                       for (Object o : objects) {\r
+                               parameters.add(o);\r
+                       }\r
+               }\r
+               if (repository != null) {\r
+                       parameters.add(0, repository.getDirectory().getAbsolutePath());\r
+               }\r
+               LOGGER.error(MessageFormat.format(pattern, parameters.toArray()), t);\r
+       }\r
+\r
+       /**\r
+        * Zips the contents of the tree at the (optionally) specified revision and\r
+        * the (optionally) specified basepath to the supplied outputstream.\r
+        * \r
+        * @param repository\r
+        * @param basePath\r
+        *            if unspecified, entire repository is assumed.\r
+        * @param objectId\r
+        *            if unspecified, HEAD is assumed.\r
+        * @param os\r
+        * @return true if repository was successfully zipped to supplied output\r
+        *         stream\r
+        */\r
+       public static boolean zip(Repository repository, String basePath, String objectId,\r
+                       OutputStream os) {\r
+               RevCommit commit = JGitUtils.getCommit(repository, objectId);\r
+               if (commit == null) {\r
+                       return false;\r
+               }\r
+               boolean success = false;\r
+               RevWalk rw = new RevWalk(repository);\r
+               TreeWalk tw = new TreeWalk(repository);\r
+               try {\r
+                       tw.addTree(commit.getTree());\r
+                       ZipOutputStream zos = new ZipOutputStream(os);\r
+                       zos.setComment("Generated by Gitblit");\r
+                       if (!StringUtils.isEmpty(basePath)) {\r
+                               PathFilter f = PathFilter.create(basePath);\r
+                               tw.setFilter(f);\r
+                       }\r
+                       tw.setRecursive(true);\r
+                       while (tw.next()) {\r
+                               if (tw.getFileMode(0) == FileMode.GITLINK) {\r
+                                       continue;\r
+                               }\r
+                               ZipEntry entry = new ZipEntry(tw.getPathString());\r
+                               entry.setSize(tw.getObjectReader().getObjectSize(tw.getObjectId(0),\r
+                                               Constants.OBJ_BLOB));\r
+                               entry.setComment(commit.getName());\r
+                               zos.putNextEntry(entry);\r
+\r
+                               ObjectId entid = tw.getObjectId(0);\r
+                               FileMode entmode = tw.getFileMode(0);\r
+                               RevBlob blob = (RevBlob) rw.lookupAny(entid, entmode.getObjectType());\r
+                               rw.parseBody(blob);\r
+\r
+                               ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);\r
+                               byte[] tmp = new byte[4096];\r
+                               InputStream in = ldr.openStream();\r
+                               int n;\r
+                               while ((n = in.read(tmp)) > 0) {\r
+                                       zos.write(tmp, 0, n);\r
+                               }\r
+                               in.close();\r
+                       }\r
+                       zos.finish();\r
+                       success = true;\r
+               } catch (IOException e) {\r
+                       error(e, repository, "{0} failed to zip files from commit {1}", commit.getName());\r
+               } finally {\r
+                       tw.release();\r
+                       rw.dispose();\r
+               }\r
+               return success;\r
+       }\r
+       \r
+       /**\r
+        * tar the contents of the tree at the (optionally) specified revision and\r
+        * the (optionally) specified basepath to the supplied outputstream.\r
+        * \r
+        * @param repository\r
+        * @param basePath\r
+        *            if unspecified, entire repository is assumed.\r
+        * @param objectId\r
+        *            if unspecified, HEAD is assumed.\r
+        * @param os\r
+        * @return true if repository was successfully zipped to supplied output\r
+        *         stream\r
+        */\r
+       public static boolean tar(Repository repository, String basePath, String objectId,\r
+                       OutputStream os) {\r
+               return tar(null, repository, basePath, objectId, os);\r
+       }\r
+       \r
+       /**\r
+        * tar.gz the contents of the tree at the (optionally) specified revision and\r
+        * the (optionally) specified basepath to the supplied outputstream.\r
+        * \r
+        * @param repository\r
+        * @param basePath\r
+        *            if unspecified, entire repository is assumed.\r
+        * @param objectId\r
+        *            if unspecified, HEAD is assumed.\r
+        * @param os\r
+        * @return true if repository was successfully zipped to supplied output\r
+        *         stream\r
+        */\r
+       public static boolean gz(Repository repository, String basePath, String objectId,\r
+                       OutputStream os) {\r
+               return tar(CompressorStreamFactory.GZIP, repository, basePath, objectId, os);\r
+       }\r
+       \r
+       /**\r
+        * tar.xz the contents of the tree at the (optionally) specified revision and\r
+        * the (optionally) specified basepath to the supplied outputstream.\r
+        * \r
+        * @param repository\r
+        * @param basePath\r
+        *            if unspecified, entire repository is assumed.\r
+        * @param objectId\r
+        *            if unspecified, HEAD is assumed.\r
+        * @param os\r
+        * @return true if repository was successfully zipped to supplied output\r
+        *         stream\r
+        */\r
+       public static boolean xz(Repository repository, String basePath, String objectId,\r
+                       OutputStream os) {\r
+               return tar(CompressorStreamFactory.XZ, repository, basePath, objectId, os);\r
+       }\r
+       \r
+       /**\r
+        * tar.bzip2 the contents of the tree at the (optionally) specified revision and\r
+        * the (optionally) specified basepath to the supplied outputstream.\r
+        * \r
+        * @param repository\r
+        * @param basePath\r
+        *            if unspecified, entire repository is assumed.\r
+        * @param objectId\r
+        *            if unspecified, HEAD is assumed.\r
+        * @param os\r
+        * @return true if repository was successfully zipped to supplied output\r
+        *         stream\r
+        */\r
+       public static boolean bzip2(Repository repository, String basePath, String objectId,\r
+                       OutputStream os) {\r
+               \r
+               return tar(CompressorStreamFactory.BZIP2, repository, basePath, objectId, os);\r
+       }\r
+       \r
+       /**\r
+        * Compresses/archives the contents of the tree at the (optionally)\r
+        * specified revision and the (optionally) specified basepath to the\r
+        * supplied outputstream.\r
+        * \r
+        * @param algorithm\r
+        *            compression algorithm for tar (optional)\r
+        * @param repository\r
+        * @param basePath\r
+        *            if unspecified, entire repository is assumed.\r
+        * @param objectId\r
+        *            if unspecified, HEAD is assumed.\r
+        * @param os\r
+        * @return true if repository was successfully zipped to supplied output\r
+        *         stream\r
+        */\r
+       private static boolean tar(String algorithm, Repository repository, String basePath, String objectId,\r
+                       OutputStream os) {\r
+               RevCommit commit = JGitUtils.getCommit(repository, objectId);\r
+               if (commit == null) {\r
+                       return false;\r
+               }\r
+               \r
+               OutputStream cos = os;\r
+               if (!StringUtils.isEmpty(algorithm)) {\r
+                       try {\r
+                               cos = new CompressorStreamFactory().createCompressorOutputStream(algorithm, os);\r
+                       } catch (CompressorException e1) {\r
+                               error(e1, repository, "{0} failed to open {1} stream", algorithm);\r
+                       }\r
+               }\r
+               boolean success = false;\r
+               RevWalk rw = new RevWalk(repository);\r
+               TreeWalk tw = new TreeWalk(repository);\r
+               try {\r
+                       tw.addTree(commit.getTree());\r
+                       TarArchiveOutputStream tos = new TarArchiveOutputStream(cos);\r
+                       tos.setAddPaxHeadersForNonAsciiNames(true);\r
+                       tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\r
+                       if (!StringUtils.isEmpty(basePath)) {\r
+                               PathFilter f = PathFilter.create(basePath);\r
+                               tw.setFilter(f);\r
+                       }\r
+                       tw.setRecursive(true);\r
+                       while (tw.next()) {\r
+                               FileMode mode = tw.getFileMode(0);\r
+                               if (mode == FileMode.GITLINK) {\r
+                                       continue;\r
+                               }\r
+                               ObjectId id = tw.getObjectId(0);\r
+                               \r
+                               // new entry\r
+                               TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());\r
+                               entry.setSize(tw.getObjectReader().getObjectSize(id, Constants.OBJ_BLOB));\r
+                               \r
+                               if (FileMode.SYMLINK.equals(mode)) {\r
+                                       // symlink\r
+                                       entry.setMode(mode.getBits());\r
+                                       \r
+                                       // read the symlink target\r
+                                       ByteArrayOutputStream bs = new ByteArrayOutputStream();\r
+                                       RevBlob blob = (RevBlob) rw.lookupAny(id, mode.getObjectType());\r
+                                       rw.parseBody(blob);                             \r
+                                       ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);\r
+                                       IOUtils.copy(ldr.openStream(), bs);\r
+                                       entry.setLinkName(bs.toString("UTF-8"));\r
+                               } else {\r
+                                       // regular file or executable file\r
+                                       entry.setMode(mode.getBits());\r
+                               }                               \r
+                               entry.setModTime(commit.getAuthorIdent().getWhen());\r
+\r
+                               tos.putArchiveEntry(entry);\r
+                               \r
+                               if (!FileMode.SYMLINK.equals(mode)) {\r
+                                       // write the blob\r
+                                       RevBlob blob = (RevBlob) rw.lookupAny(id, mode.getObjectType());\r
+                                       rw.parseBody(blob);                             \r
+                                       ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);\r
+                                       IOUtils.copy(ldr.openStream(), tos);\r
+                               }\r
+                               \r
+                               // close entry\r
+                               tos.closeArchiveEntry();\r
+                       }\r
+                       tos.finish();\r
+                       tos.close();\r
+                       cos.close();\r
+                       success = true;\r
+               } catch (IOException e) {\r
+                       error(e, repository, "{0} failed to {1} stream files from commit {2}", algorithm, commit.getName());\r
+               } finally {\r
+                       tw.release();\r
+                       rw.dispose();\r
+               }\r
+               return success;\r
+       }\r
+}\r
index bc44f00f30c7337a387b0f0dba266278c05098ed..9cfb37fd21d3f491fe4123b07589501baf3a680a 100644 (file)
@@ -19,7 +19,6 @@ import java.io.ByteArrayOutputStream;
 import java.io.File;\r
 import java.io.IOException;\r
 import java.io.InputStream;\r
-import java.io.OutputStream;\r
 import java.text.MessageFormat;\r
 import java.util.ArrayList;\r
 import java.util.Arrays;\r
@@ -30,8 +29,6 @@ import java.util.List;
 import java.util.Map;\r
 import java.util.Map.Entry;\r
 import java.util.regex.Pattern;\r
-import java.util.zip.ZipEntry;\r
-import java.util.zip.ZipOutputStream;\r
 \r
 import org.eclipse.jgit.api.CloneCommand;\r
 import org.eclipse.jgit.api.FetchCommand;\r
@@ -1723,70 +1720,4 @@ public class JGitUtils {
                }\r
                return success;\r
        }\r
-\r
-       /**\r
-        * Zips the contents of the tree at the (optionally) specified revision and\r
-        * the (optionally) specified basepath to the supplied outputstream.\r
-        * \r
-        * @param repository\r
-        * @param basePath\r
-        *            if unspecified, entire repository is assumed.\r
-        * @param objectId\r
-        *            if unspecified, HEAD is assumed.\r
-        * @param os\r
-        * @return true if repository was successfully zipped to supplied output\r
-        *         stream\r
-        */\r
-       public static boolean zip(Repository repository, String basePath, String objectId,\r
-                       OutputStream os) {\r
-               RevCommit commit = getCommit(repository, objectId);\r
-               if (commit == null) {\r
-                       return false;\r
-               }\r
-               boolean success = false;\r
-               RevWalk rw = new RevWalk(repository);\r
-               TreeWalk tw = new TreeWalk(repository);\r
-               try {\r
-                       tw.addTree(commit.getTree());\r
-                       ZipOutputStream zos = new ZipOutputStream(os);\r
-                       zos.setComment("Generated by Gitblit");\r
-                       if (!StringUtils.isEmpty(basePath)) {\r
-                               PathFilter f = PathFilter.create(basePath);\r
-                               tw.setFilter(f);\r
-                       }\r
-                       tw.setRecursive(true);\r
-                       while (tw.next()) {\r
-                               if (tw.getFileMode(0) == FileMode.GITLINK) {\r
-                                       continue;\r
-                               }\r
-                               ZipEntry entry = new ZipEntry(tw.getPathString());\r
-                               entry.setSize(tw.getObjectReader().getObjectSize(tw.getObjectId(0),\r
-                                               Constants.OBJ_BLOB));\r
-                               entry.setComment(commit.getName());\r
-                               zos.putNextEntry(entry);\r
-\r
-                               ObjectId entid = tw.getObjectId(0);\r
-                               FileMode entmode = tw.getFileMode(0);\r
-                               RevBlob blob = (RevBlob) rw.lookupAny(entid, entmode.getObjectType());\r
-                               rw.parseBody(blob);\r
-\r
-                               ObjectLoader ldr = repository.open(blob.getId(), Constants.OBJ_BLOB);\r
-                               byte[] tmp = new byte[4096];\r
-                               InputStream in = ldr.openStream();\r
-                               int n;\r
-                               while ((n = in.read(tmp)) > 0) {\r
-                                       zos.write(tmp, 0, n);\r
-                               }\r
-                               in.close();\r
-                       }\r
-                       zos.finish();\r
-                       success = true;\r
-               } catch (IOException e) {\r
-                       error(e, repository, "{0} failed to zip files from commit {1}", commit.getName());\r
-               } finally {\r
-                       tw.release();\r
-                       rw.dispose();\r
-               }\r
-               return success;\r
-       }\r
 }\r
index 20e6b60793c17dc605668c7be98ed55c19db1ea9..79a038c9d4343a1713af164afa7837083419e642 100644 (file)
@@ -30,7 +30,7 @@
                <tr class="hidden-phone"><th><wicket:message key="gb.tree">tree</wicket:message></th>\r
                        <td><span class="sha1" wicket:id="commitTree">[commit tree]</span>\r
                                <span class="link">\r
-                                       <a wicket:id="treeLink"><wicket:message key="gb.tree"></wicket:message></a> | <a wicket:id="zipLink"><wicket:message key="gb.zip"></wicket:message></a>\r
+                                       <a wicket:id="treeLink"><wicket:message key="gb.tree"></wicket:message></a> | <span wicket:id="compressedLinks"></span>\r
                                </span>\r
                        </td></tr>\r
                <tr class="hidden-phone"><th valign="top"><wicket:message key="gb.parent">parent</wicket:message></th>\r
index 7bc6b41d7c19b30a109e9fb7dbf4074831a4c24a..b2a8112ba8c3e33d0162758c4199bed20a70854f 100644 (file)
@@ -22,7 +22,6 @@ import java.util.List;
 import org.apache.wicket.PageParameters;\r
 import org.apache.wicket.markup.html.basic.Label;\r
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
-import org.apache.wicket.markup.html.link.ExternalLink;\r
 import org.apache.wicket.markup.repeater.Item;\r
 import org.apache.wicket.markup.repeater.data.DataView;\r
 import org.apache.wicket.markup.repeater.data.ListDataProvider;\r
@@ -32,16 +31,15 @@ import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;\r
 \r
 import com.gitblit.Constants;\r
-import com.gitblit.DownloadZipServlet;\r
 import com.gitblit.GitBlit;\r
-import com.gitblit.Keys;\r
 import com.gitblit.models.GitNote;\r
-import com.gitblit.models.SubmoduleModel;\r
 import com.gitblit.models.PathModel.PathChangeModel;\r
+import com.gitblit.models.SubmoduleModel;\r
 import com.gitblit.utils.JGitUtils;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.panels.CommitHeaderPanel;\r
 import com.gitblit.wicket.panels.CommitLegendPanel;\r
+import com.gitblit.wicket.panels.CompressedDownloadsPanel;\r
 import com.gitblit.wicket.panels.GravatarImage;\r
 import com.gitblit.wicket.panels.LinkPanel;\r
 import com.gitblit.wicket.panels.RefsPanel;\r
@@ -95,8 +93,8 @@ public class CommitPage extends RepositoryPage {
                                newCommitParameter()));\r
                add(new BookmarkablePageLink<Void>("treeLink", TreePage.class, newCommitParameter()));\r
                final String baseUrl = WicketUtils.getGitblitURL(getRequest());\r
-               add(new ExternalLink("zipLink", DownloadZipServlet.asLink(baseUrl, repositoryName,\r
-                               objectId, null)).setVisible(GitBlit.getBoolean(Keys.web.allowZipDownloads, true)));\r
+               \r
+               add(new CompressedDownloadsPanel("compressedLinks", baseUrl, repositoryName, objectId, null));\r
 \r
                // Parent Commits\r
                ListDataProvider<String> parentsDp = new ListDataProvider<String>(parents);\r
index 0047ff0d162b3c0fc190adb5e36774076c678c5d..b7e55ed6d5599a839ba490ecde563cb6b3ec7552 100644 (file)
@@ -9,7 +9,7 @@
 \r
        <!-- blob nav links --> \r
        <div class="page_nav2">\r
-               <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a> | <a wicket:id="zipLink"><wicket:message key="gb.zip"></wicket:message></a>\r
+               <a wicket:id="historyLink"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="headLink"><wicket:message key="gb.head"></wicket:message></a> | <span wicket:id="compressedLinks"></span>\r
        </div>  \r
        \r
        <!-- commit header -->\r
        <!--  submodule links -->\r
        <wicket:fragment wicket:id="submoduleLinks">\r
                <span class="link">\r
-                       <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <span class="hidden-phone"><a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | </span><a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="zip"><wicket:message key="gb.zip"></wicket:message></a>\r
+                       <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <span class="hidden-phone"><a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | </span><a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <span wicket:id="compressedLinks"></span>\r
                </span>\r
        </wicket:fragment>\r
 \r
        <!--  tree links -->\r
        <wicket:fragment wicket:id="treeLinks">\r
                <span class="link">\r
-                       <span class="hidden-phone"><a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | </span><a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <a wicket:id="zip"><wicket:message key="gb.zip"></wicket:message></a>\r
+                       <span class="hidden-phone"><a wicket:id="tree"><wicket:message key="gb.tree"></wicket:message></a> | </span><a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a> | <span wicket:id="compressedLinks"></span>\r
                </span>\r
        </wicket:fragment>\r
        \r
index 973634b7ad460042515a7fc6217741eea7b286a4..345814f4af903dfb2f28baf4bd426b63a67ab8f5 100644 (file)
@@ -20,7 +20,6 @@ import java.util.List;
 import org.apache.wicket.PageParameters;\r
 import org.apache.wicket.markup.html.basic.Label;\r
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;\r
-import org.apache.wicket.markup.html.link.ExternalLink;\r
 import org.apache.wicket.markup.html.panel.Fragment;\r
 import org.apache.wicket.markup.repeater.Item;\r
 import org.apache.wicket.markup.repeater.data.DataView;\r
@@ -30,15 +29,13 @@ import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.Repository;\r
 import org.eclipse.jgit.revwalk.RevCommit;\r
 \r
-import com.gitblit.DownloadZipServlet;\r
-import com.gitblit.GitBlit;\r
-import com.gitblit.Keys;\r
 import com.gitblit.models.PathModel;\r
 import com.gitblit.models.SubmoduleModel;\r
 import com.gitblit.utils.ByteFormat;\r
 import com.gitblit.utils.JGitUtils;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.panels.CommitHeaderPanel;\r
+import com.gitblit.wicket.panels.CompressedDownloadsPanel;\r
 import com.gitblit.wicket.panels.LinkPanel;\r
 import com.gitblit.wicket.panels.PathBreadcrumbsPanel;\r
 \r
@@ -58,9 +55,8 @@ public class TreePage extends RepositoryPage {
                                WicketUtils.newPathParameter(repositoryName, objectId, path)));\r
                add(new BookmarkablePageLink<Void>("headLink", TreePage.class,\r
                                WicketUtils.newPathParameter(repositoryName, Constants.HEAD, path)));\r
-               add(new ExternalLink("zipLink", DownloadZipServlet.asLink(getRequest()\r
-                               .getRelativePathPrefixToContextRoot(), repositoryName, objectId, path))\r
-                               .setVisible(GitBlit.getBoolean(Keys.web.allowZipDownloads, true)));\r
+               add(new CompressedDownloadsPanel("compressedLinks", getRequest()\r
+                               .getRelativePathPrefixToContextRoot(), repositoryName, objectId, path));\r
 \r
                add(new CommitHeaderPanel("commitHeader", repositoryName, commit));\r
 \r
@@ -114,10 +110,10 @@ public class TreePage extends RepositoryPage {
                                                                                entry.path)));\r
                                                links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,\r
                                                                WicketUtils.newPathParameter(repositoryName, entry.commitId,\r
-                                                                               entry.path)));\r
-                                               links.add(new ExternalLink("zip", DownloadZipServlet.asLink(baseUrl,\r
-                                                               repositoryName, objectId, entry.path)).setVisible(GitBlit\r
-                                                               .getBoolean(Keys.web.allowZipDownloads, true)));\r
+                                                                               entry.path)));                                          \r
+                                               links.add(new CompressedDownloadsPanel("compressedLinks", baseUrl,\r
+                                                               repositoryName, objectId, entry.path));\r
+\r
                                                item.add(links);\r
                                        } else if (entry.isSubmodule()) {\r
                                                // submodule\r
@@ -143,9 +139,8 @@ public class TreePage extends RepositoryPage {
                                                links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class,\r
                                                                WicketUtils.newPathParameter(submodulePath, submoduleId,\r
                                                                                "")).setEnabled(hasSubmodule));\r
-                                               links.add(new ExternalLink("zip", DownloadZipServlet.asLink(baseUrl,\r
-                                                               submodulePath, submoduleId, "")).setVisible(GitBlit\r
-                                                               .getBoolean(Keys.web.allowZipDownloads, true)).setEnabled(hasSubmodule));\r
+                                               links.add(new CompressedDownloadsPanel("compressedLinks", baseUrl,\r
+                                                               submodulePath, submoduleId, "").setEnabled(hasSubmodule));\r
                                                item.add(links);                                                \r
                                        } else {\r
                                                // blob link\r
diff --git a/src/com/gitblit/wicket/panels/CompressedDownloadsPanel.html b/src/com/gitblit/wicket/panels/CompressedDownloadsPanel.html
new file mode 100644 (file)
index 0000000..7123d0a
--- /dev/null
@@ -0,0 +1,12 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml"  \r
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"  \r
+      xml:lang="en"  \r
+      lang="en"> \r
+\r
+<wicket:panel>\r
+       <span wicket:id="compressedLinks">\r
+               <span wicket:id="linkSep">|</span><span wicket:id="compressedLink">ref</span>\r
+       </span> \r
+</wicket:panel>\r
+</html>
\ No newline at end of file
diff --git a/src/com/gitblit/wicket/panels/CompressedDownloadsPanel.java b/src/com/gitblit/wicket/panels/CompressedDownloadsPanel.java
new file mode 100644 (file)
index 0000000..b22c758
--- /dev/null
@@ -0,0 +1,77 @@
+/*\r
+ * Copyright 2012 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit.wicket.panels;\r
+\r
+import java.util.List;\r
+\r
+import org.apache.wicket.Component;\r
+import org.apache.wicket.markup.html.basic.Label;\r
+import org.apache.wicket.markup.html.panel.Panel;\r
+import org.apache.wicket.markup.repeater.Item;\r
+import org.apache.wicket.markup.repeater.data.DataView;\r
+import org.apache.wicket.markup.repeater.data.ListDataProvider;\r
+\r
+import com.gitblit.DownloadZipServlet;\r
+import com.gitblit.DownloadZipServlet.Format;\r
+import com.gitblit.GitBlit;\r
+import com.gitblit.Keys;\r
+\r
+public class CompressedDownloadsPanel extends Panel {\r
+\r
+       private static final long serialVersionUID = 1L;\r
+\r
+       public CompressedDownloadsPanel(String id, final String baseUrl, final String repositoryName, final String objectId, final String path) {\r
+               super(id);\r
+               \r
+               List<String> types = GitBlit.getStrings(Keys.web.compressedDownloads);\r
+               if (types.isEmpty()) {\r
+                       types.add(Format.zip.name());\r
+                       types.add(Format.gz.name());\r
+               }\r
+               \r
+               ListDataProvider<String> refsDp = new ListDataProvider<String>(types);\r
+               DataView<String> refsView = new DataView<String>("compressedLinks", refsDp) {\r
+                       private static final long serialVersionUID = 1L;\r
+                       int counter;\r
+\r
+                       @Override\r
+                       protected void onBeforeRender() {\r
+                               super.onBeforeRender();\r
+                               counter = 0;\r
+                       }\r
+                       \r
+                       @Override\r
+                       public void populateItem(final Item<String> item) {\r
+                               String compressionType = item.getModelObject();\r
+                               Format format = Format.fromName(compressionType);\r
+                               \r
+                               String href = DownloadZipServlet.asLink(baseUrl, repositoryName,\r
+                                               objectId, path, format);\r
+                               Component c = new LinkPanel("compressedLink", null, format.name(), href);\r
+                               item.add(c);\r
+                               Label lb = new Label("linkSep", "|");\r
+                               lb.setVisible(counter > 0);\r
+                               lb.setRenderBodyOnly(true);\r
+                               item.add(lb.setEscapeModelStrings(false));\r
+                               item.setRenderBodyOnly(true);\r
+                               counter++;\r
+                       }\r
+               };\r
+               add(refsView);\r
+               \r
+               setVisible(GitBlit.getBoolean(Keys.web.allowZipDownloads, true));\r
+       }\r
+}
\ No newline at end of file
index 7e4d630901517695663f187f6dff5c3ace30656c..ce72a46f94b6482ee2c22d6f35a723ab1e1d4acf 100644 (file)
@@ -50,6 +50,7 @@ import com.gitblit.models.GitNote;
 import com.gitblit.models.PathModel;\r
 import com.gitblit.models.PathModel.PathChangeModel;\r
 import com.gitblit.models.RefModel;\r
+import com.gitblit.utils.CompressionUtils;\r
 import com.gitblit.utils.JGitUtils;\r
 import com.gitblit.utils.StringUtils;\r
 \r
@@ -446,16 +447,16 @@ public class JGitUtilsTest {
 \r
        @Test\r
        public void testZip() throws Exception {\r
-               assertFalse(JGitUtils.zip(null, null, null, null));\r
+               assertFalse(CompressionUtils.zip(null, null, null, null));\r
                Repository repository = GitBlitSuite.getHelloworldRepository();\r
                File zipFileA = new File(GitBlitSuite.REPOSITORIES, "helloworld.zip");\r
                FileOutputStream fosA = new FileOutputStream(zipFileA);\r
-               boolean successA = JGitUtils.zip(repository, null, Constants.HEAD, fosA);\r
+               boolean successA = CompressionUtils.zip(repository, null, Constants.HEAD, fosA);\r
                fosA.close();\r
 \r
                File zipFileB = new File(GitBlitSuite.REPOSITORIES, "helloworld-java.zip");\r
                FileOutputStream fosB = new FileOutputStream(zipFileB);\r
-               boolean successB = JGitUtils.zip(repository, "java.java", Constants.HEAD, fosB);\r
+               boolean successB = CompressionUtils.zip(repository, "java.java", Constants.HEAD, fosB);\r
                fosB.close();\r
 \r
                repository.close();\r