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