tags:

views:

1610

answers:

5

When I run ant from the command-line, if I get a failure, I get a non-zero exit status ($? on UNIX, %ERRORLEVEL% on Windows). But we have a Java program which is running ant (through ProcessBuilder), and when ant fails, on Windows we cannot get the exit status.

I just verified this with this simple ant test file:

<project name="x" default="a">
  <target name="a">
    <fail/>
  </target>
</project>

On UNIX, running ant prints a failure message, and echoing $? afterward prints 1. On Windows, running ant or ant.bat prints a failure message, and echoing %ERRORLEVEL% afterward prints 1.

Now, using the test program below: On UNIX, java Run ant prints a failure message, and echoing $? afterward prints 1. On Windows, java Run ant can't find a program named ant to run, but java Run ant.bat prints a failure message, yet echoing %ERRORLEVEL% afterward prints 0. What gives?

We're relying on being able to check the exit status after running ant. We were, anyway. Why can't we rely on this, programmatically?

Test program:

import java.io.*;

public class Run {
  public static void main(String[] args) throws IOException, InterruptedException {
    ProcessBuilder pb = new ProcessBuilder(args);
    Process p = pb.start();
    ProcThread stdout = new ProcThread(p.getInputStream(), System.out);
    ProcThread stderr = new ProcThread(p.getErrorStream(), System.err);
    stdout.start();
    stderr.start();
    int errorLevel = p.waitFor();
    stdout.join();
    stderr.join();
    IOException outE = stdout.getException();
    if (outE != null)
      throw(outE);
    IOException errE = stdout.getException();
    if (errE != null)
      throw(errE);
    System.exit(errorLevel);
  }

  static class ProcThread extends Thread {
    BufferedReader input;
    PrintStream out;
    IOException ex;

    ProcThread(InputStream is, PrintStream out) {
      input = new BufferedReader(new InputStreamReader(is));
      this.out = out;
    }

    @Override
    public void run() {
      String line;
      try {
        while ((line = input.readLine()) != null)
          out.println(line);
      } catch (IOException e) {
        setException(e);
      }
    }

    private void setException(IOException e) {
      this.ex = e;
    }

    public IOException getException() {
      return ex;
    }
  }
}
+1  A: 

Do you need to run Ant via its .bat file? It's just a java program, you could just execute in inside the VM by directly instantiating and executing the Ant runtime. Have a look inside ant.bat, see what its Main class is, and execute it directly.

skaffman
ant.bat is complex and running the java program directly is correspondingly complex. I'm seeing the same problem executing ant.bat from within an ant script (no, don't ask). I cannot see the ant.bat errorlevel. I don't want to deliver ant2.bat to my builder's environment, but I will if I have to.Does anyone know *why* this works?PS: What is the formatting markup for this comment???
Steve Powell
A: 

This is a long-standing issue for older versions of Ant on Windows. I believe it has been fixed in version 1.7.0.

See this bug for details and this discussion for an approach to address it.

Rich Seller
I'm on ant 1.7.1. I just tried running with the full path to make sure I'm not running another version of ant. Same behavior: correct error level when run from a prompt; incorrect errorlevel when run from a program.
skiphoppy
+2  A: 

I solved this problem by creating two extra batch files (not very nice, but it works):

Content of file myant.bat:

call ant2.bat %*

Content of file ant2.bat:

call ant.bat %*
if errorlevel 1 (goto ERROR_EXIT)
exit /B 0
:ERROR_EXIT
exit /B 1

Now I can call myant.bat as a Process from java and I get the correct exit value.

Sorry, I cannot say why this works. It's simply the result of a many many tries.

tangens
A: 

I googled to this thread and find tangens' answer almost solved my problem: the exit coded are always 0 on Windows from ant.bat, even when I intentionally failed an ant build; I need to get the exit code from a TFS build script, and it showed that even the %ERRORLEVEL% can't be found in TFS build.

However, I have to remove the /B from exit lines, otherwise, it still always shows me exit code 0.

Sapience
A: 

I solved this problem by creating a single batch file (quite a bit nicer than the above but still mysterious):

Content of file myant.bat:

@echo off
rem RunAnt simply calls ant -- correctly returns errorlevel for callers
call ant.bat %*

crucially, without any code whatsoever after the call.

Steve Powell