# 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
- 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
\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
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
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
* @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
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
\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
--- /dev/null
+/*\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
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
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
}\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
<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
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
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
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
\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
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
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
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
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
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
--- /dev/null
+<!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
--- /dev/null
+/*\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
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
\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