diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java index bcf272852..cb2a7258a 100644 --- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java +++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java @@ -102,6 +102,13 @@ public class ArchiveTest extends CLIRepositoryTestCase { assertArrayEquals(new String[0], listTarEntries(result)); } + @Test + public void testUnrecognizedFormat() throws Exception { + final String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" }; + final String[] actual = execute("git archive --format=nonsense " + emptyTree); + assertArrayEquals(expect, actual); + } + @Test public void testArchiveWithFiles() throws Exception { writeTrashFile("a", "a file with content!"); diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties index cdf712395..3fa167e95 100644 --- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties +++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties @@ -173,6 +173,7 @@ tooManyRefsGiven=Too many refs given unknownIoErrorStdout=An unknown I/O error occurred on standard output unknownMergeStrategy=unknown merge strategy {0} specified unmergedPaths=Unmerged paths: +unsupportedArchiveFormat=Unknown archive format ''{0}'' unsupportedOperation=Unsupported operation: {0} untrackedFiles=Untracked files: updating=Updating {0}..{1} 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 815c96bfe..6d4f5aa51 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,6 +43,7 @@ package org.eclipse.jgit.pgm; +import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.pgm.TextBuiltin; import org.eclipse.jgit.pgm.archive.ArchiveCommand; @@ -56,7 +57,7 @@ class Archive extends TextBuiltin { private ObjectId tree; @Option(name = "--format", metaVar = "metaVar_archiveFormat", usage = "usage_archiveFormat") - private ArchiveCommand.Format format = ArchiveCommand.Format.ZIP; + private String format = "zip"; @Override protected void run() throws Exception { @@ -68,6 +69,8 @@ class Archive extends TextBuiltin { cmd.setTree(tree) .setFormat(format) .setOutputStream(outs).call(); + } catch (GitAPIException e) { + throw die(e.getMessage()); } finally { cmd.release(); } 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 index 1235d0ae0..ff5b0d0cd 100644 --- 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 @@ -44,15 +44,11 @@ package org.eclipse.jgit.pgm.archive; import java.io.IOException; import java.io.OutputStream; -import java.util.EnumMap; -import java.util.Map; +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; 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.Git; import org.eclipse.jgit.api.GitCommand; import org.eclipse.jgit.api.errors.GitAPIException; @@ -89,7 +85,7 @@ import org.eclipse.jgit.treewalk.TreeWalk; *
* try { * cmd.setTree(db.resolve("master")) - * .setFormat(ArchiveCommand.Format.ZIP) + * .setFormat("zip") * .setOutputStream(out).call(); * } finally { * cmd.release(); @@ -103,91 +99,69 @@ import org.eclipse.jgit.treewalk.TreeWalk; */ public class ArchiveCommand extends GitCommand{ /** - * Available archival formats (corresponding to values for - * the --format= option) + * Archival format. + * + * Usage: + * Repository repo = git.getRepository(); + * ArchiveOutputStream out = format.createArchiveOutputStream(System.out); + * try { + * for (...) { + * format.putEntry(path, mode, repo.open(objectId), out); + * } + * } finally { + * out.close(); + * } */ - public static enum Format { - /** Zip format */ - ZIP, - - /** Posix TAR-format */ - TAR - } - - private static interface Archiver { + public static interface Format { ArchiveOutputStream createArchiveOutputStream(OutputStream s); void putEntry(String path, FileMode mode, // ObjectLoader loader, ArchiveOutputStream out) // throws IOException; } - private static final Map formats; + /** + * Signals an attempt to use an archival format that ArchiveCommand + * doesn't know about (for example due to a typo). + */ + public static class UnsupportedFormatException extends GitAPIException { + private static final long serialVersionUID = 1L; - static { - Map fmts = new EnumMap (Format.class); - fmts.put(Format.ZIP, new Archiver() { - public ArchiveOutputStream createArchiveOutputStream(OutputStream s) { - return new ZipArchiveOutputStream(s); - } + private final String format; - public void putEntry(String path, FileMode mode, // - ObjectLoader loader, ArchiveOutputStream out) // - throws IOException { - final ZipArchiveEntry entry = new ZipArchiveEntry(path); + /** + * @param format the problematic format name + */ + public UnsupportedFormatException(String format) { + super(MessageFormat.format(CLIText.get().unsupportedArchiveFormat, format)); + this.format = format; + } - if (mode == FileMode.REGULAR_FILE) { - // ok - } else if (mode == FileMode.EXECUTABLE_FILE - || mode == FileMode.SYMLINK) { - entry.setUnixMode(mode.getBits()); - } else { - // TODO(jrn): Let the caller know the tree contained - // an entry with unsupported mode (e.g., a submodule). - } - 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); - } + /** + * @return the problematic format name + */ + public String getFormat() { + return format; + } + } - 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; - } + private static final ConcurrentMap formats = + new ConcurrentHashMap (); - final TarArchiveEntry entry = new TarArchiveEntry(path); - if (mode == FileMode.REGULAR_FILE || - mode == FileMode.EXECUTABLE_FILE) { - entry.setMode(mode.getBits()); - } else { - // TODO(jrn): Let the caller know the tree contained - // an entry with unsupported mode (e.g., a submodule). - } - entry.setSize(loader.getSize()); - out.putArchiveEntry(entry); - loader.copyTo(out); - out.closeArchiveEntry(); - } - }); - formats = fmts; + static { + formats.put("zip", new ZipFormat()); + formats.put("tar", new TarFormat()); + } + + private static Format lookupFormat(String formatName) throws UnsupportedFormatException { + Format fmt = formats.get(formatName); + if (fmt == null) + throw new UnsupportedFormatException(formatName); + return fmt; } private OutputStream out; private TreeWalk walk; - private Format format = Format.TAR; + private String format = "tar"; /** * @param repo @@ -213,7 +187,7 @@ public class ArchiveCommand extends GitCommand { @Override public OutputStream call() throws GitAPIException { final MutableObjectId idBuf = new MutableObjectId(); - final Archiver fmt = formats.get(format); + final Format fmt = lookupFormat(format); final ArchiveOutputStream outa = fmt.createArchiveOutputStream(out); final ObjectReader reader = walk.getObjectReader(); @@ -268,10 +242,10 @@ public class ArchiveCommand extends GitCommand { /** * @param fmt - * archive format (e.g., Format.TAR) + * archive format (e.g., "tar" or "zip") * @return this */ - public ArchiveCommand setFormat(Format fmt) { + public ArchiveCommand setFormat(String fmt) { this.format = fmt; return this; } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/TarFormat.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/TarFormat.java new file mode 100644 index 000000000..c27fb350b --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/TarFormat.java @@ -0,0 +1,85 @@ +/* + * 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.io.IOException; +import java.io.OutputStream; + +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.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectLoader; + +class TarFormat implements ArchiveCommand.Format { + 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 { + // TODO(jrn): Let the caller know the tree contained + // an entry with unsupported mode (e.g., a submodule). + } + entry.setSize(loader.getSize()); + out.putArchiveEntry(entry); + loader.copyTo(out); + out.closeArchiveEntry(); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ZipFormat.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ZipFormat.java new file mode 100644 index 000000000..d08428f54 --- /dev/null +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/archive/ZipFormat.java @@ -0,0 +1,77 @@ +/* + * 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.io.IOException; +import java.io.OutputStream; + +import org.apache.commons.compress.archivers.ArchiveOutputStream; +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.ObjectLoader; + +class ZipFormat implements ArchiveCommand.Format { + 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 { + // TODO(jrn): Let the caller know the tree contained + // an entry with unsupported mode (e.g., a submodule). + } + entry.setSize(loader.getSize()); + out.putArchiveEntry(entry); + loader.copyTo(out); + out.closeArchiveEntry(); + } +} diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java index 62865d51c..937707bd3 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/internal/CLIText.java @@ -236,6 +236,7 @@ public class CLIText extends TranslationBundle { /***/ public char[] unknownIoErrorStdout; /***/ public String unknownMergeStrategy; /***/ public String unmergedPaths; + /***/ public String unsupportedArchiveFormat; /***/ public String unsupportedOperation; /***/ public String untrackedFiles; /***/ public String updating; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java index ba38529ab..92599ca7d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/GitAPIException.java @@ -45,11 +45,19 @@ package org.eclipse.jgit.api.errors; public abstract class GitAPIException extends Exception { private static final long serialVersionUID = 1L; - GitAPIException(String message, Throwable cause) { + /** + * Constructs a new exception with the specified detail + * message and cause. + */ + protected GitAPIException(String message, Throwable cause) { super(message, cause); } - GitAPIException(String message) { + /** + * Constructs a new exception with the specified detail + * message and no cause. + */ + protected GitAPIException(String message) { super(message); } }