diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java index a3436a017..a6af077aa 100644 --- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java +++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java @@ -54,7 +54,8 @@ import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.pgm.CLIGitCommand; -import org.eclipse.jgit.pgm.Die; +import org.eclipse.jgit.pgm.CLIGitCommand.Result; +import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException; import org.junit.Before; public class CLIRepositoryTestCase extends LocalDiskRepositoryTestCase { @@ -84,7 +85,7 @@ public void setUp() throws Exception { protected String[] executeUnchecked(String... cmds) throws Exception { List result = new ArrayList(cmds.length); for (String cmd : cmds) { - result.addAll(CLIGitCommand.execute(cmd, db)); + result.addAll(CLIGitCommand.executeUnchecked(cmd, db)); } return result.toArray(new String[0]); } @@ -102,11 +103,13 @@ protected String[] executeUnchecked(String... cmds) throws Exception { protected String[] execute(String... cmds) throws Exception { List result = new ArrayList(cmds.length); for (String cmd : cmds) { - List out = CLIGitCommand.execute(cmd, db); - if (contains(out, "fatal: ")) { - throw new Die(toString(out)); + Result r = CLIGitCommand.executeRaw(cmd, db); + if (r.ex instanceof TerminatedByHelpException) { + result.addAll(r.errLines()); + } else if (r.ex != null) { + throw r.ex; } - result.addAll(out); + result.addAll(r.outLines()); } return result.toArray(new String[0]); } diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java index 6a12019d7..3f396563c 100644 --- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java +++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/pgm/CLIGitCommand.java @@ -42,33 +42,31 @@ */ package org.eclipse.jgit.pgm; +import static org.junit.Assert.assertNull; + import java.io.ByteArrayOutputStream; import java.io.File; + +import java.io.IOException; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.pgm.TextBuiltin.TerminatedByHelpException; -import org.eclipse.jgit.pgm.internal.CLIText; -import org.eclipse.jgit.pgm.opt.CmdLineParser; -import org.eclipse.jgit.pgm.opt.SubcommandHandler; import org.eclipse.jgit.util.IO; -import org.kohsuke.args4j.Argument; -public class CLIGitCommand { - @Argument(index = 0, metaVar = "metaVar_command", required = true, handler = SubcommandHandler.class) - private TextBuiltin subcommand; +public class CLIGitCommand extends Main { - @Argument(index = 1, metaVar = "metaVar_arg") - private List arguments = new ArrayList(); + private final Result result; - public TextBuiltin getSubcommand() { - return subcommand; - } + private final Repository db; - public List getArguments() { - return arguments; + public CLIGitCommand(Repository db) { + super(); + this.db = db; + result = new Result(); } /** @@ -102,57 +100,82 @@ public static void main(String[] args) throws Exception { public static List execute(String str, Repository db) throws Exception { + Result result = executeRaw(str, db); + return getOutput(result); + } + + public static Result executeRaw(String str, Repository db) + throws Exception { + CLIGitCommand cmd = new CLIGitCommand(db); + cmd.run(str); + return cmd.result; + } + + public static List executeUnchecked(String str, Repository db) + throws Exception { + CLIGitCommand cmd = new CLIGitCommand(db); try { - return IO.readLines(new String(rawExecute(str, db))); - } catch (Die e) { - return IO.readLines(CLIText.fatalError(e.getMessage())); + cmd.run(str); + return getOutput(cmd.result); + } catch (Throwable e) { + return cmd.result.errLines(); } } - public static byte[] rawExecute(String str, Repository db) + private static List getOutput(Result result) { + if (result.ex instanceof TerminatedByHelpException) { + return result.errLines(); + } + return result.outLines(); + } + + private void run(String commandLine) throws Exception { + String[] argv = convertToMainArgs(commandLine); + try { + super.run(argv); + } catch (TerminatedByHelpException e) { + // this is not a failure, super called exit() on help + } finally { + writer.flush(); + } + } + + private static String[] convertToMainArgs(String str) throws Exception { String[] args = split(str); - if (!args[0].equalsIgnoreCase("git") || args.length < 2) + if (!args[0].equalsIgnoreCase("git") || args.length < 2) { throw new IllegalArgumentException( "Expected 'git []', was:" + str); + } String[] argv = new String[args.length - 1]; System.arraycopy(args, 1, argv, 0, args.length - 1); + return argv; + } - CLIGitCommand bean = new CLIGitCommand(); - final CmdLineParser clp = new TestCmdLineParser(bean); - clp.parseArgument(argv); + @Override + PrintWriter createErrorWriter() { + return new PrintWriter(result.err); + } - final TextBuiltin cmd = bean.getSubcommand(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - cmd.outs = baos; - ByteArrayOutputStream errs = new ByteArrayOutputStream(); - cmd.errs = errs; - boolean seenHelp = TextBuiltin.containsHelp(argv); - if (cmd.requiresRepository()) - cmd.init(db, null); - else - cmd.init(null, null); - try { - cmd.execute(bean.getArguments().toArray( - new String[bean.getArguments().size()])); - } catch (TerminatedByHelpException e) { - seenHelp = true; - // this is not a failure, command execution should just not happen - } finally { - if (cmd.outw != null) { - cmd.outw.flush(); - } - if (cmd.errw != null) { - cmd.errw.flush(); - } - if (seenHelp) { - return errs.toByteArray(); - } else if (errs.size() > 0) { - // forward the errors to the standard err - System.err.print(errs.toString()); - } + void init(final TextBuiltin cmd) throws IOException { + cmd.outs = result.out; + cmd.errs = result.err; + super.init(cmd); + } + + @Override + protected Repository openGitDir(String aGitdir) throws IOException { + assertNull(aGitdir); + return db; + } + + @Override + void exit(int status, Exception t) throws Exception { + if (t == null) { + t = new IllegalStateException(Integer.toString(status)); } - return baos.toByteArray(); + result.ex = t; + throw t; } /** @@ -210,14 +233,36 @@ else if (r.length() > 0) { return list.toArray(new String[list.size()]); } - static class TestCmdLineParser extends CmdLineParser { - public TestCmdLineParser(Object bean) { - super(bean); + public static class Result { + public final ByteArrayOutputStream out = new ByteArrayOutputStream(); + + public final ByteArrayOutputStream err = new ByteArrayOutputStream(); + + public Exception ex; + + public byte[] outBytes() { + return out.toByteArray(); } - @Override - protected boolean containsHelp(String... args) { - return false; + public byte[] errBytes() { + return err.toByteArray(); + } + + public String outString() { + return out.toString(); + } + + public List outLines() { + return IO.readLines(out.toString()); + } + + public String errString() { + return err.toString(); + } + + public List errLines() { + return IO.readLines(err.toString()); } } + } 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 2e02c762b..a503ffdad 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 @@ -87,21 +87,22 @@ public void setUp() throws Exception { @Test public void testEmptyArchive() throws Exception { - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=zip " + emptyTree, db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=zip " + emptyTree, db).outBytes(); assertArrayEquals(new String[0], listZipEntries(result)); } @Test public void testEmptyTar() throws Exception { - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=tar " + emptyTree, db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=tar " + emptyTree, db).outBytes(); assertArrayEquals(new String[0], listTarEntries(result)); } @Test public void testUnrecognizedFormat() throws Exception { - String[] expect = new String[] { "fatal: Unknown archive format 'nonsense'" }; + String[] expect = new String[] { + "fatal: Unknown archive format 'nonsense'", "" }; String[] actual = executeUnchecked( "git archive --format=nonsense " + emptyTree); assertArrayEquals(expect, actual); @@ -116,8 +117,8 @@ public void testArchiveWithFiles() throws Exception { git.add().addFilepattern("c").call(); git.commit().setMessage("populate toplevel").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=zip HEAD", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=zip HEAD", db).outBytes(); assertArrayEquals(new String[] { "a", "c" }, listZipEntries(result)); } @@ -131,8 +132,8 @@ private void commitGreeting() throws Exception { @Test public void testDefaultFormatIsTar() throws Exception { commitGreeting(); - byte[] result = CLIGitCommand.rawExecute( - "git archive HEAD", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive HEAD", db).outBytes(); assertArrayEquals(new String[] { "greeting" }, listTarEntries(result)); } @@ -298,8 +299,8 @@ public void testArchiveWithSubdir() throws Exception { git.add().addFilepattern("b").call(); git.commit().setMessage("add subdir").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=zip master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=zip master", db).outBytes(); String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; String[] actual = listZipEntries(result); @@ -324,8 +325,8 @@ public void testTarWithSubdir() throws Exception { git.add().addFilepattern("b").call(); git.commit().setMessage("add subdir").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=tar master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=tar master", db).outBytes(); String[] expect = { "a", "b.c", "b0c", "b/", "b/a", "b/b", "c" }; String[] actual = listTarEntries(result); @@ -345,8 +346,8 @@ private void commitBazAndFooSlashBar() throws Exception { @Test public void testArchivePrefixOption() throws Exception { commitBazAndFooSlashBar(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --prefix=x/ --format=zip master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --prefix=x/ --format=zip master", db).outBytes(); String[] expect = { "x/baz", "x/foo/", "x/foo/bar" }; String[] actual = listZipEntries(result); @@ -358,8 +359,8 @@ public void testArchivePrefixOption() throws Exception { @Test public void testTarPrefixOption() throws Exception { commitBazAndFooSlashBar(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --prefix=x/ --format=tar master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --prefix=x/ --format=tar master", db).outBytes(); String[] expect = { "x/baz", "x/foo/", "x/foo/bar" }; String[] actual = listTarEntries(result); @@ -377,8 +378,8 @@ private void commitFoo() throws Exception { @Test public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception { commitFoo(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --prefix=x// --format=zip master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --prefix=x// --format=zip master", db).outBytes(); String[] expect = { "x//foo" }; assertArrayEquals(expect, listZipEntries(result)); } @@ -386,8 +387,8 @@ public void testPrefixDoesNotNormalizeDoubleSlash() throws Exception { @Test public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception { commitFoo(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --prefix=x// --format=tar master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --prefix=x// --format=tar master", db).outBytes(); String[] expect = { "x//foo" }; assertArrayEquals(expect, listTarEntries(result)); } @@ -404,8 +405,8 @@ public void testPrefixDoesNotNormalizeDoubleSlashInTar() throws Exception { @Test public void testPrefixWithoutTrailingSlash() throws Exception { commitBazAndFooSlashBar(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --prefix=my- --format=zip master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --prefix=my- --format=zip master", db).outBytes(); String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; String[] actual = listZipEntries(result); @@ -417,8 +418,8 @@ public void testPrefixWithoutTrailingSlash() throws Exception { @Test public void testTarPrefixWithoutTrailingSlash() throws Exception { commitBazAndFooSlashBar(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --prefix=my- --format=tar master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --prefix=my- --format=tar master", db).outBytes(); String[] expect = { "my-baz", "my-foo/", "my-foo/bar" }; String[] actual = listTarEntries(result); @@ -437,8 +438,8 @@ public void testArchiveIncludesSubmoduleDirectory() throws Exception { git.submoduleAdd().setURI("./.").setPath("b").call().close(); git.commit().setMessage("add submodule").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=zip master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=zip master", db).outBytes(); String[] expect = { ".gitmodules", "a", "b/", "c" }; String[] actual = listZipEntries(result); @@ -457,8 +458,8 @@ public void testTarIncludesSubmoduleDirectory() throws Exception { git.submoduleAdd().setURI("./.").setPath("b").call().close(); git.commit().setMessage("add submodule").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=tar master", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=tar master", db).outBytes(); String[] expect = { ".gitmodules", "a", "b/", "c" }; String[] actual = listTarEntries(result); @@ -487,8 +488,8 @@ public void testArchivePreservesMode() throws Exception { git.commit().setMessage("three files with different modes").call(); - byte[] zipData = CLIGitCommand.rawExecute( - "git archive --format=zip master", db); + byte[] zipData = CLIGitCommand.executeRaw( + "git archive --format=zip master", db).outBytes(); writeRaw("zip-with-modes.zip", zipData); assertContainsEntryWithMode("zip-with-modes.zip", "-rw-", "plain"); assertContainsEntryWithMode("zip-with-modes.zip", "-rwx", "executable"); @@ -516,8 +517,8 @@ public void testTarPreservesMode() throws Exception { git.commit().setMessage("three files with different modes").call(); - byte[] archive = CLIGitCommand.rawExecute( - "git archive --format=tar master", db); + byte[] archive = CLIGitCommand.executeRaw( + "git archive --format=tar master", db).outBytes(); writeRaw("with-modes.tar", archive); assertTarContainsEntry("with-modes.tar", "-rw-r--r--", "plain"); assertTarContainsEntry("with-modes.tar", "-rwxr-xr-x", "executable"); @@ -539,8 +540,8 @@ public void testArchiveWithLongFilename() throws Exception { git.add().addFilepattern("1234567890").call(); git.commit().setMessage("file with long name").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=zip HEAD", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=zip HEAD", db).outBytes(); assertArrayEquals(l.toArray(new String[l.size()]), listZipEntries(result)); } @@ -559,8 +560,8 @@ public void testTarWithLongFilename() throws Exception { git.add().addFilepattern("1234567890").call(); git.commit().setMessage("file with long name").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=tar HEAD", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=tar HEAD", db).outBytes(); assertArrayEquals(l.toArray(new String[l.size()]), listTarEntries(result)); } @@ -572,8 +573,8 @@ public void testArchivePreservesContent() throws Exception { git.add().addFilepattern("xyzzy").call(); git.commit().setMessage("add file with content").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=zip HEAD", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=zip HEAD", db).outBytes(); assertArrayEquals(new String[] { payload }, zipEntryContent(result, "xyzzy")); } @@ -585,8 +586,8 @@ public void testTarPreservesContent() throws Exception { git.add().addFilepattern("xyzzy").call(); git.commit().setMessage("add file with content").call(); - byte[] result = CLIGitCommand.rawExecute( - "git archive --format=tar HEAD", db); + byte[] result = CLIGitCommand.executeRaw( + "git archive --format=tar HEAD", db).outBytes(); assertArrayEquals(new String[] { payload }, tarEntryContent(result, "xyzzy")); } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java index e31306b21..d701f22c3 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Main.java @@ -90,14 +90,23 @@ public class Main { @Argument(index = 1, metaVar = "metaVar_arg") private List arguments = new ArrayList(); + PrintWriter writer; + + /** + * + */ + public Main() { + HttpTransport.setConnectionFactory(new HttpClientConnectionFactory()); + } + /** * Execute the command line. * * @param argv * arguments. + * @throws Exception */ - public static void main(final String[] argv) { - HttpTransport.setConnectionFactory(new HttpClientConnectionFactory()); + public static void main(final String[] argv) throws Exception { new Main().run(argv); } @@ -116,8 +125,10 @@ public static void main(final String[] argv) { * * @param argv * arguments. + * @throws Exception */ - protected void run(final String[] argv) { + protected void run(final String[] argv) throws Exception { + writer = createErrorWriter(); try { if (!installConsole()) { AwtAuthenticator.install(); @@ -126,12 +137,14 @@ protected void run(final String[] argv) { configureHttpProxy(); execute(argv); } catch (Die err) { - if (err.isAborted()) - System.exit(1); - System.err.println(CLIText.fatalError(err.getMessage())); - if (showStackTrace) - err.printStackTrace(); - System.exit(128); + if (err.isAborted()) { + exit(1, err); + } + writer.println(CLIText.fatalError(err.getMessage())); + if (showStackTrace) { + err.printStackTrace(writer); + } + exit(128, err); } catch (Exception err) { // Try to detect errno == EPIPE and exit normally if that happens // There may be issues with operating system versions and locale, @@ -139,46 +152,54 @@ protected void run(final String[] argv) { // under other circumstances. if (err.getClass() == IOException.class) { // Linux, OS X - if (err.getMessage().equals("Broken pipe")) //$NON-NLS-1$ - System.exit(0); + if (err.getMessage().equals("Broken pipe")) { //$NON-NLS-1$ + exit(0, err); + } // Windows - if (err.getMessage().equals("The pipe is being closed")) //$NON-NLS-1$ - System.exit(0); + if (err.getMessage().equals("The pipe is being closed")) { //$NON-NLS-1$ + exit(0, err); + } } if (!showStackTrace && err.getCause() != null - && err instanceof TransportException) - System.err.println(CLIText.fatalError(err.getCause().getMessage())); + && err instanceof TransportException) { + writer.println(CLIText.fatalError(err.getCause().getMessage())); + } if (err.getClass().getName().startsWith("org.eclipse.jgit.errors.")) { //$NON-NLS-1$ - System.err.println(CLIText.fatalError(err.getMessage())); - if (showStackTrace) + writer.println(CLIText.fatalError(err.getMessage())); + if (showStackTrace) { err.printStackTrace(); - System.exit(128); + } + exit(128, err); } err.printStackTrace(); - System.exit(1); + exit(1, err); } if (System.out.checkError()) { - System.err.println(CLIText.get().unknownIoErrorStdout); - System.exit(1); + writer.println(CLIText.get().unknownIoErrorStdout); + exit(1, null); } - if (System.err.checkError()) { + if (writer.checkError()) { // No idea how to present an error here, most likely disk full or // broken pipe - System.exit(1); + exit(1, null); } } + PrintWriter createErrorWriter() { + return new PrintWriter(System.err); + } + private void execute(final String[] argv) throws Exception { final CmdLineParser clp = new SubcommandLineParser(this); - PrintWriter writer = new PrintWriter(System.err); + try { clp.parseArgument(argv); } catch (CmdLineException err) { if (argv.length > 0 && !help && !version) { writer.println(CLIText.fatalError(err.getMessage())); writer.flush(); - System.exit(1); + exit(1, err); } } @@ -194,22 +215,24 @@ private void execute(final String[] argv) throws Exception { writer.println(CLIText.get().mostCommonlyUsedCommandsAre); final CommandRef[] common = CommandCatalog.common(); int width = 0; - for (final CommandRef c : common) + for (final CommandRef c : common) { width = Math.max(width, c.getName().length()); + } width += 2; for (final CommandRef c : common) { writer.print(' '); writer.print(c.getName()); - for (int i = c.getName().length(); i < width; i++) + for (int i = c.getName().length(); i < width; i++) { writer.print(' '); + } writer.print(CLIText.get().resourceBundle().getString(c.getUsage())); writer.println(); } writer.println(); } writer.flush(); - System.exit(1); + exit(1, null); } if (version) { @@ -218,20 +241,38 @@ private void execute(final String[] argv) throws Exception { } final TextBuiltin cmd = subcommand; - if (cmd.requiresRepository()) - cmd.init(openGitDir(gitdir), null); - else - cmd.init(null, gitdir); + init(cmd); try { cmd.execute(arguments.toArray(new String[arguments.size()])); } finally { - if (cmd.outw != null) + if (cmd.outw != null) { cmd.outw.flush(); - if (cmd.errw != null) + } + if (cmd.errw != null) { cmd.errw.flush(); + } } } + void init(final TextBuiltin cmd) throws IOException { + if (cmd.requiresRepository()) { + cmd.init(openGitDir(gitdir), null); + } else { + cmd.init(null, gitdir); + } + } + + /** + * @param status + * @param t + * can be {@code null} + * @throws Exception + */ + void exit(int status, Exception t) throws Exception { + writer.flush(); + System.exit(status); + } + /** * Evaluate the {@code --git-dir} option and open the repository. * @@ -281,7 +322,7 @@ private static void install(final String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { try { - Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$ + Class.forName(name).getMethod("install").invoke(null); //$NON-NLS-1$ } catch (InvocationTargetException e) { if (e.getCause() instanceof RuntimeException) throw (RuntimeException) e.getCause();