archive: Prepend a specified prefix to all entry filenames
Common practice when distributing tarballs is to prefix all entries with a single directory name so when the tarball is extracted it all falls neatly into a single directory. Add a setPrefix() method to ArchiveCommand to support this. Change-Id: I16b2832ef98c30977f6b77b646728b83d93c196f Signed-off-by: Jonathan Nieder <jrn@google.com>
This commit is contained in:
parent
aad7dee3ef
commit
f2abbd0ea9
|
@ -338,6 +338,99 @@ public void testTarWithSubdir() throws Exception {
|
|||
assertArrayEquals(expect, actual);
|
||||
}
|
||||
|
||||
private void commitBazAndFooSlashBar() throws Exception {
|
||||
writeTrashFile("baz", "a file");
|
||||
writeTrashFile("foo/bar", "another file");
|
||||
git.add().addFilepattern("baz").call();
|
||||
git.add().addFilepattern("foo").call();
|
||||
git.commit().setMessage("sample commit").call();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArchivePrefixOption() throws Exception {
|
||||
commitBazAndFooSlashBar();
|
||||
byte[] result = CLIGitCommand.rawExecute(
|
||||
"git archive --prefix=x/ --format=zip master", db);
|
||||
String[] expect = { "x/baz", "x/foo/bar" };
|
||||
String[] actual = listZipEntries(result);
|
||||
|
||||
Arrays.sort(expect);
|
||||
Arrays.sort(actual);
|
||||
assertArrayEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTarPrefixOption() throws Exception {
|
||||
commitBazAndFooSlashBar();
|
||||
byte[] result = CLIGitCommand.rawExecute(
|
||||
"git archive --prefix=x/ --format=tar master", db);
|
||||
String[] expect = { "x/baz", "x/foo/bar" };
|
||||
String[] actual = listTarEntries(result);
|
||||
|
||||
Arrays.sort(expect);
|
||||
Arrays.sort(actual);
|
||||
assertArrayEquals(expect, actual);
|
||||
}
|
||||
|
||||
private void commitFoo() throws Exception {
|
||||
writeTrashFile("foo", "a file");
|
||||
git.add().addFilepattern("foo").call();
|
||||
git.commit().setMessage("boring commit").call();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception {
|
||||
commitFoo();
|
||||
byte[] result = CLIGitCommand.rawExecute(
|
||||
"git archive --prefix=x// --format=zip master", db);
|
||||
String[] expect = { "x//foo" };
|
||||
assertArrayEquals(expect, listZipEntries(result));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception {
|
||||
commitFoo();
|
||||
final byte[] result = CLIGitCommand.rawExecute( //
|
||||
"git archive --prefix=x// --format=tar master", db);
|
||||
String[] expect = { "x//foo" };
|
||||
assertArrayEquals(expect, listTarEntries(result));
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix passed to "git archive" need not end with '/'.
|
||||
* In practice it is not very common to have a nonempty prefix
|
||||
* that does not name a directory (and hence end with /), but
|
||||
* since git has historically supported other prefixes, we do,
|
||||
* too.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testPrefixWithoutTrailingSlash() throws Exception {
|
||||
commitBazAndFooSlashBar();
|
||||
byte[] result = CLIGitCommand.rawExecute(
|
||||
"git archive --prefix=my- --format=zip master", db);
|
||||
String[] expect = { "my-baz", "my-foo/bar" };
|
||||
String[] actual = listZipEntries(result);
|
||||
|
||||
Arrays.sort(expect);
|
||||
Arrays.sort(actual);
|
||||
assertArrayEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTarPrefixWithoutTrailingSlash() throws Exception {
|
||||
commitBazAndFooSlashBar();
|
||||
final byte[] result = CLIGitCommand.rawExecute( //
|
||||
"git archive --prefix=my- --format=tar master", db);
|
||||
String[] expect = { "my-baz", "my-foo/bar" };
|
||||
String[] actual = listTarEntries(result);
|
||||
|
||||
Arrays.sort(expect);
|
||||
Arrays.sort(actual);
|
||||
assertArrayEquals(expect, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArchivePreservesMode() throws Exception {
|
||||
writeTrashFile("plain", "a file with content");
|
||||
|
|
|
@ -74,6 +74,7 @@ mergeWentWellStoppedBeforeCommitting=Automatic merge went well; stopped before c
|
|||
metaVar_DAG=DAG
|
||||
metaVar_KEY=KEY
|
||||
metaVar_archiveFormat=format
|
||||
metaVar_archivePrefix=prefix/
|
||||
metaVar_arg=ARG
|
||||
metaVar_author=AUTHOR
|
||||
metaVar_base=base
|
||||
|
@ -229,6 +230,7 @@ usage_approveDestructionOfRepository=approve destruction of repository
|
|||
usage_archive=zip up files from the named tree
|
||||
usage_archiveFormat=archive format. Currently supported formats: 'tar', 'zip', 'tgz', 'tbz2', 'txz'
|
||||
usage_archiveOutput=output file to write the archive to
|
||||
usage_archivePrefix=string to prepend to each pathname in the archive
|
||||
usage_blameLongRevision=show long revision
|
||||
usage_blameRange=annotate only the given range
|
||||
usage_blameRawTimestamp=show raw timestamp
|
||||
|
|
|
@ -69,6 +69,9 @@ class Archive extends TextBuiltin {
|
|||
@Option(name = "--format", metaVar = "metaVar_archiveFormat", usage = "usage_archiveFormat")
|
||||
private String format;
|
||||
|
||||
@Option(name = "--prefix", metaVar = "metaVar_archivePrefix", usage = "usage_archivePrefix")
|
||||
private String prefix;
|
||||
|
||||
@Option(name = "--output", aliases = { "-o" }, metaVar = "metaVar_file", usage = "usage_archiveOutput")
|
||||
private String output;
|
||||
|
||||
|
@ -88,6 +91,7 @@ protected void run() throws Exception {
|
|||
ArchiveCommand cmd = new Git(db).archive()
|
||||
.setTree(tree)
|
||||
.setFormat(format)
|
||||
.setPrefix(prefix)
|
||||
.setOutputStream(stream);
|
||||
if (output != null)
|
||||
cmd.setFilename(output);
|
||||
|
|
|
@ -143,6 +143,7 @@ public static String formatLine(String line) {
|
|||
/***/ public String mergeWentWellStoppedBeforeCommitting;
|
||||
/***/ public String metaVar_KEY;
|
||||
/***/ public String metaVar_archiveFormat;
|
||||
/***/ public String metaVar_archivePrefix;
|
||||
/***/ public String metaVar_arg;
|
||||
/***/ public String metaVar_author;
|
||||
/***/ public String metaVar_bucket;
|
||||
|
|
|
@ -250,6 +250,7 @@ private static Format<?> lookupFormat(String formatName) throws UnsupportedForma
|
|||
|
||||
private OutputStream out;
|
||||
private ObjectId tree;
|
||||
private String prefix;
|
||||
private String format;
|
||||
|
||||
/** Filename suffix, for automatically choosing a format. */
|
||||
|
@ -264,6 +265,7 @@ public ArchiveCommand(Repository repo) {
|
|||
}
|
||||
|
||||
private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
|
||||
final String pfx = prefix == null ? "" : prefix;
|
||||
final TreeWalk walk = new TreeWalk(repo);
|
||||
try {
|
||||
final T outa = fmt.createArchiveOutputStream(out);
|
||||
|
@ -275,7 +277,7 @@ private <T extends Closeable> OutputStream writeArchive(Format<T> fmt) {
|
|||
walk.reset(rw.parseTree(tree));
|
||||
walk.setRecursive(true);
|
||||
while (walk.next()) {
|
||||
final String name = walk.getPathString();
|
||||
final String name = pfx + walk.getPathString();
|
||||
final FileMode mode = walk.getFileMode(0);
|
||||
|
||||
if (mode == FileMode.TREE)
|
||||
|
@ -329,6 +331,18 @@ public ArchiveCommand setTree(ObjectId tree) {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param prefix
|
||||
* string prefixed to filenames in archive (e.g., "master/").
|
||||
* null means to not use any leading prefix.
|
||||
* @return this
|
||||
* @since 3.3
|
||||
*/
|
||||
public ArchiveCommand setPrefix(String prefix) {
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the intended filename for the produced archive. Currently the only
|
||||
* effect is to determine the default archive format when none is specified
|
||||
|
|
Loading…
Reference in New Issue