aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Nieder2013-04-26 16:43:23 (EDT)
committerJonathan Nieder2013-04-26 17:12:42 (EDT)
commitb525e696d558bee033652d847b18514e5656fbda (patch)
treec85417fb9fe1101d0f42a17994ed3d87a812b9b5
parent543b8560ac41a32f1ef0e5dbc8d0fca51c3c34e9 (diff)
downloadjgit-b525e696d558bee033652d847b18514e5656fbda.zip
jgit-b525e696d558bee033652d847b18514e5656fbda.tar.gz
jgit-b525e696d558bee033652d847b18514e5656fbda.tar.bz2
Add internal porcelain-style API for ArchiveCommandrefs/changes/56/11556/10
One step closer to exposing archive creation functionality in a org.eclipse.jgit.archive bundle. Change-Id: If0ebb2417a941d9d3fc0d3f444316d0d1c494ff3
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties1
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java133
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java1
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java277
4 files changed, 288 insertions, 124 deletions
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
index 39c1268..4808df9 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/CLIText.properties
@@ -48,6 +48,7 @@ deletedRemoteBranch=Deleted remote branch {0}
doesNotExist={0} does not exist
dontOverwriteLocalChanges=error: Your local changes to the following file would be overwritten by merge:
everythingUpToDate=Everything up-to-date
+exceptionCaughtDuringExecutionOfArchiveCommand=Exception caught during execution of archive command
expectedNumberOfbytes=Expected {0} bytes.
exporting=Exporting {0}
failedToCommitIndex=failed to commit index
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
index 9075cf0..5685aa4 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Archive.java
@@ -43,148 +43,33 @@
package org.eclipse.jgit.pgm;
-import java.lang.String;
-import java.lang.System;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.EnumMap;
-import java.util.Map;
-import java.text.MessageFormat;
-
-import org.apache.commons.compress.archivers.ArchiveOutputStream;
-import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
-import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
-import org.apache.commons.compress.archivers.tar.TarConstants;
-import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
-import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
-import org.eclipse.jgit.lib.FileMode;
-import org.eclipse.jgit.lib.MutableObjectId;
-import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.pgm.CLIText;
import org.eclipse.jgit.pgm.TextBuiltin;
-import org.eclipse.jgit.treewalk.AbstractTreeIterator;
-import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.pgm.archive.ArchiveCommand;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@Command(common = true, usage = "usage_archive")
class Archive extends TextBuiltin {
@Argument(index = 0, metaVar = "metaVar_treeish")
- private AbstractTreeIterator tree;
+ private ObjectId tree;
@Option(name = "--format", metaVar = "metaVar_archiveFormat", usage = "usage_archiveFormat")
- private Format format = Format.ZIP;
+ private ArchiveCommand.Format format = ArchiveCommand.Format.ZIP;
@Override
protected void run() throws Exception {
- final MutableObjectId idBuf = new MutableObjectId();
- final Archiver fmt = formats.get(format);
-
if (tree == null)
throw die(CLIText.get().treeIsRequired);
- final ArchiveOutputStream outa = fmt.createArchiveOutputStream(outs);
- final TreeWalk walk = new TreeWalk(db);
- final ObjectReader reader = walk.getObjectReader();
-
+ final ArchiveCommand cmd = new ArchiveCommand(db);
try {
- walk.reset();
- walk.addTree(tree);
- walk.setRecursive(true);
- while (walk.next()) {
- final String name = walk.getPathString();
- final FileMode mode = walk.getFileMode(0);
-
- if (mode == FileMode.TREE)
- // ZIP entries for directories are optional.
- // Leave them out, mimicking "git archive".
- continue;
-
- walk.getObjectId(idBuf, 0);
- fmt.putEntry(name, mode, reader.open(idBuf), outa);
- }
+ cmd.setTree(tree)
+ .setFormat(format)
+ .setOutputStream(outs).call();
} finally {
- reader.release();
- outa.close();
+ cmd.release();
}
}
-
- static private void warnArchiveEntryModeIgnored(String name) {
- System.err.println(MessageFormat.format( //
- CLIText.get().archiveEntryModeIgnored, //
- name));
- }
-
- public enum Format {
- ZIP,
- TAR
- }
-
- private static interface Archiver {
- ArchiveOutputStream createArchiveOutputStream(OutputStream s);
- void putEntry(String path, FileMode mode, //
- ObjectLoader loader, ArchiveOutputStream out) //
- throws IOException;
- }
-
- private static final Map<Format, Archiver> formats;
- static {
- Map<Format, Archiver> fmts = new EnumMap<Format, Archiver>(Format.class);
- fmts.put(Format.ZIP, new Archiver() {
- public ArchiveOutputStream createArchiveOutputStream(OutputStream s) {
- return new ZipArchiveOutputStream(s);
- }
-
- public void putEntry(String path, FileMode mode, //
- ObjectLoader loader, ArchiveOutputStream out) //
- throws IOException {
- final ZipArchiveEntry entry = new ZipArchiveEntry(path);
-
- if (mode == FileMode.REGULAR_FILE) {
- // ok
- } else if (mode == FileMode.EXECUTABLE_FILE
- || mode == FileMode.SYMLINK) {
- entry.setUnixMode(mode.getBits());
- } else {
- warnArchiveEntryModeIgnored(path);
- }
- entry.setSize(loader.getSize());
- out.putArchiveEntry(entry);
- loader.copyTo(out);
- out.closeArchiveEntry();
- }
- });
- fmts.put(Format.TAR, new Archiver() {
- public ArchiveOutputStream createArchiveOutputStream(OutputStream s) {
- return new TarArchiveOutputStream(s);
- }
-
- public void putEntry(String path, FileMode mode, //
- ObjectLoader loader, ArchiveOutputStream out) //
- throws IOException {
- if (mode == FileMode.SYMLINK) {
- final TarArchiveEntry entry = new TarArchiveEntry( //
- path, TarConstants.LF_SYMLINK);
- entry.setLinkName(new String( //
- loader.getCachedBytes(100), "UTF-8")); //$NON-NLS-1$
- out.putArchiveEntry(entry);
- out.closeArchiveEntry();
- return;
- }
-
- final TarArchiveEntry entry = new TarArchiveEntry(path);
- if (mode == FileMode.REGULAR_FILE ||
- mode == FileMode.EXECUTABLE_FILE)
- entry.setMode(mode.getBits());
- else
- warnArchiveEntryModeIgnored(path);
- entry.setSize(loader.getSize());
- out.putArchiveEntry(entry);
- loader.copyTo(out);
- out.closeArchiveEntry();
- }
- });
- formats = fmts;
- }
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
index fe1c87b..727317b 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/CLIText.java
@@ -117,6 +117,7 @@ public class CLIText extends TranslationBundle {
/***/ public String doesNotExist;
/***/ public String dontOverwriteLocalChanges;
/***/ public String everythingUpToDate;
+ /***/ public String exceptionCaughtDuringExecutionOfArchiveCommand;
/***/ public String expectedNumberOfbytes;
/***/ public String exporting;
/***/ public String failedToCommitIndex;
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java
new file mode 100644
index 0000000..eaa80ae
--- /dev/null
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ArchiveCommand.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.pgm.archive;
+
+import java.lang.String;
+import java.lang.System;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.EnumMap;
+import java.util.Map;
+import java.text.MessageFormat;
+
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
+import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
+import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
+import org.apache.commons.compress.archivers.tar.TarConstants;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
+import org.eclipse.jgit.api.GitCommand;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.pgm.CLIText;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+/**
+ * Create an archive of files from a named tree.
+ * <p>
+ * Examples (<code>git</code> is a {@link Git} instance):
+ * <p>
+ * Create a tarball from HEAD:
+ *
+ * <pre>
+ * cmd = new ArchiveCommand(git.getRepository());
+ * try {
+ * cmd.setTree(db.resolve(&quot;HEAD&quot;))
+ * .setOutputStream(out).call();
+ * } finally {
+ * cmd.release();
+ * }
+ * </pre>
+ * <p>
+ * Create a ZIP file from master:
+ *
+ * <pre>
+ * try {
+ * cmd.setTree(db.resolve(&quot;master&quot;))
+ * .setFormat(ArchiveCommand.Format.ZIP)
+ * .setOutputStream(out).call();
+ * } finally {
+ * cmd.release();
+ * }
+ * </pre>
+ *
+ * @see <a href="http://git-htmldocs.googlecode.com/git/git-archive.html"
+ * >Git documentation about archive</a>
+ */
+public class ArchiveCommand extends GitCommand<OutputStream> {
+ /**
+ * Available archival formats (corresponding to values for
+ * the --format= option)
+ */
+ public static enum Format {
+ ZIP,
+ TAR
+ }
+
+ private static interface Archiver {
+ ArchiveOutputStream createArchiveOutputStream(OutputStream s);
+ void putEntry(String path, FileMode mode, //
+ ObjectLoader loader, ArchiveOutputStream out) //
+ throws IOException;
+ }
+
+ private static void warnArchiveEntryModeIgnored(String name) {
+ System.err.println(MessageFormat.format( //
+ CLIText.get().archiveEntryModeIgnored, //
+ name));
+ }
+
+ private static final Map<Format, Archiver> formats;
+
+ static {
+ Map<Format, Archiver> fmts = new EnumMap<Format, Archiver>(Format.class);
+ fmts.put(Format.ZIP, new Archiver() {
+ public ArchiveOutputStream createArchiveOutputStream(OutputStream s) {
+ return new ZipArchiveOutputStream(s);
+ }
+
+ public void putEntry(String path, FileMode mode, //
+ ObjectLoader loader, ArchiveOutputStream out) //
+ throws IOException {
+ final ZipArchiveEntry entry = new ZipArchiveEntry(path);
+
+ if (mode == FileMode.REGULAR_FILE) {
+ // ok
+ } else if (mode == FileMode.EXECUTABLE_FILE
+ || mode == FileMode.SYMLINK) {
+ entry.setUnixMode(mode.getBits());
+ } else {
+ warnArchiveEntryModeIgnored(path);
+ }
+ entry.setSize(loader.getSize());
+ out.putArchiveEntry(entry);
+ loader.copyTo(out);
+ out.closeArchiveEntry();
+ }
+ });
+ fmts.put(Format.TAR, new Archiver() {
+ public ArchiveOutputStream createArchiveOutputStream(OutputStream s) {
+ return new TarArchiveOutputStream(s);
+ }
+
+ public void putEntry(String path, FileMode mode, //
+ ObjectLoader loader, ArchiveOutputStream out) //
+ throws IOException {
+ if (mode == FileMode.SYMLINK) {
+ final TarArchiveEntry entry = new TarArchiveEntry( //
+ path, TarConstants.LF_SYMLINK);
+ entry.setLinkName(new String( //
+ loader.getCachedBytes(100), "UTF-8")); //$NON-NLS-1$
+ out.putArchiveEntry(entry);
+ out.closeArchiveEntry();
+ return;
+ }
+
+ final TarArchiveEntry entry = new TarArchiveEntry(path);
+ if (mode == FileMode.REGULAR_FILE ||
+ mode == FileMode.EXECUTABLE_FILE)
+ entry.setMode(mode.getBits());
+ else
+ warnArchiveEntryModeIgnored(path);
+ entry.setSize(loader.getSize());
+ out.putArchiveEntry(entry);
+ loader.copyTo(out);
+ out.closeArchiveEntry();
+ }
+ });
+ formats = fmts;
+ }
+
+ private OutputStream out;
+ private TreeWalk walk;
+ private Format format = Format.TAR;
+
+ /**
+ * @param repo
+ */
+ public ArchiveCommand(Repository repo) {
+ super(repo);
+ walk = new TreeWalk(repo);
+ }
+
+ /**
+ * Release any resources used by the internal ObjectReader.
+ * <p>
+ * This does not close the output stream set with setOutputStream, which
+ * belongs to the caller.
+ */
+ public void release() {
+ walk.release();
+ }
+
+ /**
+ * @return the stream to which the archive has been written
+ */
+ @Override
+ public OutputStream call() throws GitAPIException {
+ final MutableObjectId idBuf = new MutableObjectId();
+ final Archiver fmt = formats.get(format);
+ final ArchiveOutputStream outa = fmt.createArchiveOutputStream(out);
+ final ObjectReader reader = walk.getObjectReader();
+
+ try {
+ try {
+ walk.setRecursive(true);
+ while (walk.next()) {
+ final String name = walk.getPathString();
+ final FileMode mode = walk.getFileMode(0);
+
+ if (mode == FileMode.TREE)
+ // ZIP entries for directories are optional.
+ // Leave them out, mimicking "git archive".
+ continue;
+
+ walk.getObjectId(idBuf, 0);
+ fmt.putEntry(name, mode, reader.open(idBuf), outa);
+ }
+ } finally {
+ outa.close();
+ }
+ } catch (IOException e) {
+ // TODO(jrn): Throw finer-grained errors.
+ throw new JGitInternalException(
+ CLIText.get().exceptionCaughtDuringExecutionOfArchiveCommand, e);
+ }
+
+ return out;
+ }
+
+ /**
+ * @param tree
+ * the tag, commit, or tree object to produce an archive for
+ * @return this
+ */
+ public ArchiveCommand setTree(ObjectId tree) throws IOException {
+ final RevWalk rw = new RevWalk(walk.getObjectReader());
+ walk.reset(rw.parseTree(tree));
+ return this;
+ }
+
+ /**
+ * @param out
+ * the stream to which to write the archive
+ * @return this
+ */
+ public ArchiveCommand setOutputStream(OutputStream out) {
+ this.out = out;
+ return this;
+ }
+
+ /**
+ * @param fmt
+ * archive format (e.g., Format.TAR)
+ * @return this
+ */
+ public ArchiveCommand setFormat(Format fmt) {
+ this.format = fmt;
+ return this;
+ }
+}