Download commands: Add JGit archive

Since JGit 3.1 archive command was implemented. Add it to download
drop down as new line.

The following libraries are introduced in this change:

* jgit-archive (Apache 2)
* commons-compress (Apache 2)
* tukaani-xz (Public domain)

Change-Id: I5f61aac8c434414c73585a9320e84f4430dd111d
This commit is contained in:
David Ostrovsky 2014-02-18 00:16:37 +01:00 committed by David Ostrovsky
parent b6af30e13c
commit fbf6b7dabd
9 changed files with 270 additions and 0 deletions

View File

@ -40,9 +40,13 @@ import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwtexpui.clippy.client.CopyableLabel;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
class DownloadBox extends VerticalPanel {
private final static String ARCHIVE[] = {"tar", "tbz2", "tgz", "txz"};
private final ChangeInfo change;
private final String revision;
private final PatchSet.Id psId;
@ -109,6 +113,7 @@ class DownloadBox extends VerticalPanel {
}
}
insertPatch();
insertArchive();
insertCommand(null, scheme);
}
@ -141,6 +146,34 @@ class DownloadBox extends VerticalPanel {
insertCommand("Patch-File", p);
}
private void insertArchive() {
List<Anchor> formats = new ArrayList<>(ARCHIVE.length);
for (String f : ARCHIVE) {
Anchor archive = new Anchor(f);
archive.setHref(new RestApi("/changes/")
.id(psId.getParentKey().get())
.view("revisions")
.id(revision)
.view("archive")
.addParameter("format", f)
.url());
formats.add(archive);
}
HorizontalPanel p = new HorizontalPanel();
Iterator<Anchor> it = formats.iterator();
while (it.hasNext()) {
Anchor a = it.next();
p.add(a);
if (it.hasNext()) {
InlineLabel spacer = new InlineLabel("|");
spacer.setStyleName(Gerrit.RESOURCES.css().downloadBoxSpacer());
p.add(spacer);
}
}
insertCommand("Archive", p);
}
private void insertCommand(String commandName, Widget w) {
int row = commandTable.getRowCount();
commandTable.insertRow(row);

View File

@ -57,6 +57,7 @@ java_library2(
'//lib/guice:guice-assistedinject',
'//lib/guice:guice-servlet',
'//lib/jgit:jgit',
'//lib/jgit:jgit-archive',
'//lib/joda:joda-time',
'//lib/log:api',
'//lib/prolog:prolog-cafe',

View File

@ -0,0 +1,84 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// 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.google.gerrit.server.change;
import com.google.common.collect.Maps;
import org.eclipse.jgit.api.ArchiveCommand;
import org.eclipse.jgit.archive.TarFormat;
import org.eclipse.jgit.archive.Tbz2Format;
import org.eclipse.jgit.archive.TgzFormat;
import org.eclipse.jgit.archive.TxzFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.Map;
enum ArchiveFormat {
TGZ("application/x-gzip", new TgzFormat()),
TAR("application/x-tar", new TarFormat()),
TBZ2("application/x-bzip2", new Tbz2Format()),
TXZ("application/x-xz", new TxzFormat());
// Zip is not supported because it may be interpreted by a Java plugin as a
// valid JAR file, whose code would have access to cookies on the domain.
static final Logger log = LoggerFactory.getLogger(ArchiveFormat.class);
private final ArchiveCommand.Format<?> format;
private final String mimeType;
private ArchiveFormat(String mimeType, ArchiveCommand.Format<?> format) {
this.format = format;
this.mimeType = mimeType;
ArchiveCommand.registerFormat(name(), format);
}
String getShortName() {
return name().toLowerCase();
}
String getMimeType() {
return mimeType;
}
String getDefaultSuffix() {
return getSuffixes().iterator().next();
}
Iterable<String> getSuffixes() {
return format.suffixes();
}
static Map<String, ArchiveFormat> init() {
String[] formats = new String[values().length];
for (int i = 0; i < values().length; i++) {
formats[i] = values()[i].name();
}
Map<String, ArchiveFormat> exts = Maps.newLinkedHashMap();
for (String name : formats) {
try {
ArchiveFormat format = valueOf(name.toUpperCase());
for (String ext : format.getSuffixes()) {
exts.put(ext, format);
}
} catch (IllegalArgumentException e) {
log.warn("Invalid archive.format {}", name);
}
}
return Collections.unmodifiableMap(exts);
}
}

View File

@ -0,0 +1,111 @@
// Copyright (C) 2014 The Android Open Source Project
//
// 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.google.gerrit.server.change;
import com.google.common.base.Strings;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import org.eclipse.jgit.api.ArchiveCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
class GetArchive implements RestReadView<RevisionResource> {
private static final Map<String, ArchiveFormat> formats = ArchiveFormat.init();
private final GitRepositoryManager repoManager;
@Option(name = "--format")
private String format;
@Inject
GetArchive(GitRepositoryManager repoManager) {
this.repoManager = repoManager;
}
@Override
public BinaryResult apply(RevisionResource rsrc)
throws BadRequestException, IOException {
if (Strings.isNullOrEmpty(format)) {
throw new BadRequestException("format is not specified");
}
final ArchiveFormat f = formats.get("." + format);
if (f == null) {
throw new BadRequestException("unknown archive format");
}
boolean close = true;
final Repository repo = repoManager
.openRepository(rsrc.getControl().getProject().getNameKey());
try {
final RevWalk rw = new RevWalk(repo);
try {
final RevCommit commit =
rw.parseCommit(ObjectId.fromString(rsrc.getPatchSet()
.getRevision().get()));
BinaryResult bin = new BinaryResult() {
@Override
public void writeTo(OutputStream out) throws IOException {
try {
new ArchiveCommand(repo)
.setFormat(f.name())
.setTree(commit.getTree())
.setOutputStream(out).call();
} catch (GitAPIException e) {
throw new IOException(e);
}
}
@Override
public void close() throws IOException {
rw.release();
repo.close();
}
};
bin.disableGzip()
.setContentType(f.getMimeType())
.setAttachmentName(name(f, rw, commit));
close = false;
return bin;
} finally {
if (close) {
rw.release();
}
}
} finally {
if (close) {
repo.close();
}
}
}
private static String name(ArchiveFormat format, RevWalk rw, RevCommit commit)
throws IOException {
return String.format("%s%s",
rw.getObjectReader().abbreviate(commit,7).name(),
format.getDefaultSuffix());
}
}

View File

@ -82,6 +82,7 @@ public class Module extends RestApiModule {
get(REVISION_KIND, "submit_type").to(TestSubmitType.Get.class);
post(REVISION_KIND, "test.submit_rule").to(TestSubmitRule.class);
post(REVISION_KIND, "test.submit_type").to(TestSubmitType.class);
get(REVISION_KIND, "archive").to(GetArchive.class);
child(REVISION_KIND, "drafts").to(Drafts.class);
put(REVISION_KIND, "drafts").to(CreateDraft.class);

View File

@ -20,6 +20,7 @@ define_license(name = 'postgresql')
define_license(name = 'prologcafe')
define_license(name = 'protobuf')
define_license(name = 'slf4j')
define_license(name = 'xz')
define_license(name = 'DO_NOT_DISTRIBUTE')
maven_jar(
@ -248,3 +249,12 @@ maven_jar(
visibility = ['//lib:easymock'],
attach_source = False,
)
maven_jar(
name = 'tukaani-xz',
id = 'org.tukaani:xz:1.4',
sha1 = '18a9a2ce6abf32ea1b5fd31dae5210ad93f4e5e3',
license = 'xz',
attach_source = False,
visibility = ['//lib/jgit:jgit-archive'],
)

4
lib/LICENSE-xz Normal file
View File

@ -0,0 +1,4 @@
All the files in this package have been written by Lasse Collin
and/or Igor Pavlov. All these files have been put into the
public domain. You can do whatever you want with these files.
This software is provided "as is", without any warranty.

View File

@ -21,6 +21,15 @@ maven_jar(
],
)
maven_jar(
name = 'compress',
id = 'org.apache.commons:commons-compress:1.7',
sha1 = 'ab365c96ee9bc88adcc6fa40d185c8e15a31410d',
license = 'Apache2.0',
exclude = ['META-INF/LICENSE.txt', 'META-INF/NOTICE.txt'],
visibility = ['//lib/jgit:jgit-archive'],
)
maven_jar(
name = 'dbcp',
id = 'commons-dbcp:commons-dbcp:1.4',

View File

@ -33,6 +33,23 @@ maven_jar(
],
)
maven_jar(
name = 'jgit-archive',
id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
sha1 = 'c645b284344ec9791404f6fd0e04f6dbedb58b7d',
license = 'jgit',
repository = REPO,
deps = [':jgit',
'//lib/commons:compress',
'//lib:tukaani-xz',
],
unsign = True,
exclude = [
'about.html',
'plugin.properties',
],
)
maven_jar(
name = 'junit',
id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,