Add internal porcelain-style API for ArchiveCommand
One step closer to exposing archive creation functionality in a org.eclipse.jgit.archive bundle. Change-Id: If0ebb2417a941d9d3fc0d3f444316d0d1c494ff3
This commit is contained in:
parent
543b8560ac
commit
b525e696d5
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ public static String formatLine(String line) {
|
|||
/***/ public String doesNotExist;
|
||||
/***/ public String dontOverwriteLocalChanges;
|
||||
/***/ public String everythingUpToDate;
|
||||
/***/ public String exceptionCaughtDuringExecutionOfArchiveCommand;
|
||||
/***/ public String expectedNumberOfbytes;
|
||||
/***/ public String exporting;
|
||||
/***/ public String failedToCommitIndex;
|
||||
|
|
|
@ -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("HEAD"))
|
||||
* .setOutputStream(out).call();
|
||||
* } finally {
|
||||
* cmd.release();
|
||||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* Create a ZIP file from master:
|
||||
*
|
||||
* <pre>
|
||||
* try {
|
||||
* cmd.setTree(db.resolve("master"))
|
||||
* .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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue