Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ant.bat not return an error status when run programmatically?

Tags:

java

fork

exec

ant

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;
    }
  }
}
like image 667
skiphoppy Avatar asked Sep 21 '09 21:09

skiphoppy


3 Answers

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.

like image 168
Steve Powell Avatar answered Nov 07 '22 20:11

Steve Powell


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.

like image 39
tangens Avatar answered Nov 07 '22 20:11

tangens


A quick patch is adding the following at the end of ANT.BAT file:

exit /b %ANT_ERROR%

This problem has long existed and fixed recently. Refer to Bug 41039.

It should be ready in ANT release 1.8.2 or later.

like image 40
Chau Chee Yang Avatar answered Nov 07 '22 18:11

Chau Chee Yang