Making compiler exit codes type safe. Fixes the problem with wrong command-line argument usage being missed by the IDE

This commit is contained in:
Andrey Breslav
2012-03-16 20:19:27 +04:00
parent fda2bc25dc
commit 9c58e5b45c
4 changed files with 41 additions and 21 deletions
@@ -23,6 +23,8 @@ import org.jetbrains.jet.compiler.MessageRenderer;
import java.io.PrintStream; import java.io.PrintStream;
import static org.jetbrains.jet.cli.KotlinCompiler.ExitCode.*;
/** /**
* @author yole * @author yole
* @author alex.tkachman * @author alex.tkachman
@@ -30,6 +32,22 @@ import java.io.PrintStream;
@SuppressWarnings("UseOfSystemOutOrSystemErr") @SuppressWarnings("UseOfSystemOutOrSystemErr")
public class KotlinCompiler { public class KotlinCompiler {
public enum ExitCode {
OK(0),
COMPILATION_ERROR(1),
INTERNAL_ERROR(2);
private final int code;
private ExitCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
public static void main(String... args) { public static void main(String... args) {
doMain(new KotlinCompiler(), args); doMain(new KotlinCompiler(), args);
} }
@@ -39,25 +57,25 @@ public class KotlinCompiler {
*/ */
public static void doMain(KotlinCompiler compiler, String[] args) { public static void doMain(KotlinCompiler compiler, String[] args) {
try { try {
int rc = compiler.exec(args); ExitCode rc = compiler.exec(args);
if (rc != 0) { if (rc != OK) {
System.err.println("exec() finished with " + rc + " return code"); System.err.println("exec() finished with " + rc + " return code");
System.exit(rc); System.exit(rc.getCode());
} }
} catch (CompileEnvironmentException e) { } catch (CompileEnvironmentException e) {
System.err.println(e.getMessage()); System.err.println(e.getMessage());
System.exit(1); System.exit(INTERNAL_ERROR.getCode());
} }
} }
public int exec(String... args) { public ExitCode exec(String... args) {
return exec(System.out, args); return exec(System.out, args);
} }
public int exec(PrintStream errStream, String... args) { public ExitCode exec(PrintStream errStream, String... args) {
CompilerArguments arguments = createArguments(); CompilerArguments arguments = createArguments();
if (!parseArguments(errStream, arguments, args)) { if (!parseArguments(errStream, arguments, args)) {
return 1; return INTERNAL_ERROR;
} }
return exec(errStream, arguments); return exec(errStream, arguments);
} }
@@ -65,10 +83,10 @@ public class KotlinCompiler {
/** /**
* Executes the compiler on the parsed arguments * Executes the compiler on the parsed arguments
*/ */
public int exec(PrintStream errStream, CompilerArguments arguments) { public ExitCode exec(PrintStream errStream, CompilerArguments arguments) {
if (arguments.help) { if (arguments.help) {
usage(errStream); usage(errStream);
return 0; return OK;
} }
System.setProperty("java.awt.headless", "true"); System.setProperty("java.awt.headless", "true");
@@ -84,11 +102,11 @@ public class KotlinCompiler {
else { else {
noErrors = environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime); noErrors = environment.compileBunchOfSources(arguments.src, arguments.jar, arguments.outputDir, arguments.includeRuntime);
} }
return noErrors ? 0 : 1; return noErrors ? OK : COMPILATION_ERROR;
} }
catch (Throwable t) { catch (Throwable t) {
errStream.println(messageRenderer.renderException(t)); errStream.println(messageRenderer.renderException(t));
return 1; return INTERNAL_ERROR;
} }
finally { finally {
environment.dispose(); environment.dispose();
@@ -104,7 +122,7 @@ public class KotlinCompiler {
return true; return true;
} }
catch (IllegalArgumentException e) { catch (IllegalArgumentException e) {
usage(System.err); usage(errStream);
} }
catch (Throwable t) { catch (Throwable t) {
// Always use tags // Always use tags
@@ -55,10 +55,10 @@ public class CompileEnvironmentTest extends TestCase {
try { try {
File stdlib = ForTestCompileStdlib.stdlibJarForTests(); File stdlib = ForTestCompileStdlib.stdlibJarForTests();
File resultJar = new File(tempDir, "result.jar"); File resultJar = new File(tempDir, "result.jar");
int rv = new KotlinCompiler().exec("-module", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kts", KotlinCompiler.ExitCode rv = new KotlinCompiler().exec("-module", JetParsingTest.getTestDataDir() + "/compiler/smoke/Smoke.kts",
"-jar", resultJar.getAbsolutePath(), "-jar", resultJar.getAbsolutePath(),
"-stdlib", stdlib.getAbsolutePath()); "-stdlib", stdlib.getAbsolutePath());
Assert.assertEquals("compilation completed with non-zero code", 0, rv); Assert.assertEquals("compilation completed with non-zero code", KotlinCompiler.ExitCode.OK, rv);
FileInputStream fileInputStream = new FileInputStream(resultJar); FileInputStream fileInputStream = new FileInputStream(resultJar);
try { try {
JarInputStream is = new JarInputStream(fileInputStream); JarInputStream is = new JarInputStream(fileInputStream);
@@ -274,8 +274,10 @@ public class JetCompiler implements TranslatingCompiler {
context.addMessage(INFORMATION, "Invoking in-process compiler " + compilerClassName + " with arguments " + Arrays.asList(arguments), "", -1, -1); context.addMessage(INFORMATION, "Invoking in-process compiler " + compilerClassName + " with arguments " + Arrays.asList(arguments), "", -1, -1);
Object rc = exec.invoke(kompiler.newInstance(), out, arguments); Object rc = exec.invoke(kompiler.newInstance(), out, arguments);
if (rc instanceof Integer) { // exec() returns a KotlinCompiler.ExitCode object, that class is not accessible here,
return ((Integer) rc).intValue(); // so we take it's contents through reflection
if ("org.jetbrains.jet.cli.KotlinCompiler.ExitCode".equals(rc.getClass().getCanonicalName())) {
return (Integer) rc.getClass().getMethod("getCode").invoke(rc);
} }
else { else {
throw new IllegalStateException("Unexpected return: " + rc); throw new IllegalStateException("Unexpected return: " + rc);
@@ -150,8 +150,8 @@ public class LibrariesTest extends PlatformTestCase {
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
String libraryDir = FileUtil.getTempDirectory(); String libraryDir = FileUtil.getTempDirectory();
int compilerExec = new KotlinCompiler().exec("-src", TEST_DATA_PATH + "/library", "-output", libraryDir); KotlinCompiler.ExitCode compilerExec = new KotlinCompiler().exec("-src", TEST_DATA_PATH + "/library", "-output", libraryDir);
assertEquals(0, compilerExec); assertEquals(KotlinCompiler.ExitCode.OK, compilerExec);
myLibraryDir = LocalFileSystem.getInstance().findFileByPath(libraryDir); myLibraryDir = LocalFileSystem.getInstance().findFileByPath(libraryDir);
assertNotNull(myLibraryDir); assertNotNull(myLibraryDir);
@@ -168,4 +168,4 @@ public class LibrariesTest extends PlatformTestCase {
} }
}); });
} }
} }