为什么ant.bat在以编程方式运行时不会返回错误状态?

时间:2009-09-21 21:28:01

标签: java ant exec fork

当我从命令行运行ant时,如果出现故障,我会得到一个非零退出状态(UNIX上为$?,Windows上为%ERRORLEVEL%)。但是我们有一个运行ant的Java程序(通过ProcessBuilder),当ant失败时,在Windows上我们无法获得退出状态。

我刚用这个简单的ant测试文件验证了这一点:

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

在UNIX上,运行ant会打印失败消息,并回显$?之后打印1。 在Windows上,运行ant或ant.bat会打印失败消息,然后回显%ERRORLEVEL%会打印1。

现在,使用下面的测试程序: 在UNIX上,java Run ant打印失败消息,并回显$?之后打印1。 在Windows上,java Run ant无法找到名为ant的程序来运行,但是java Run ant.bat打印出一条失败消息,然后回显%ERRORLEVEL%后打印 0 。是什么给了什么?

我们依靠能够在运行ant之后检查退出状态。无论如何,我们是。为什么我们不能以编程方式依赖于此?

测试程序:

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;
    }
  }
}

8 个答案:

答案 0 :(得分:6)

我通过创建一个单个批处理文件解决了这个问题(比上面的更好但仍然很神秘):

文件内容myant.bat

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

至关重要的是,在call之后没有任何代码。

答案 1 :(得分:2)

我通过创建两个额外的批处理文件解决了这个问题(不是很好,但它有效):

文件内容myant.bat

call ant2.bat %*

文件内容ant2.bat

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

现在我可以从java调用myant.bat作为Process并获得正确的退出值。

对不起,我不能说为什么这个有效。这只是许多尝试的结果。

答案 2 :(得分:2)

快速补丁在ANT.BAT文件末尾添加以下内容:

exit /b %ANT_ERROR%

这个问题最近已经存在并且已经解决。请参阅Bug 41039

应该在ANT 1.8.2或更高版本中准备好。

答案 3 :(得分:2)

另一个问题 - 如果您在BAT文件中调用ANT并且您有兴趣保存errorlevel值,则必须将调用保留在if / else块之外。

例如,这不起作用(......在某些例行程序中):

if "%DUMP_ARGS%"=="no" (
   call ant %ANT_TARGETS%
   set ANT_RETURN=%errorlevel%
)

您必须按照以下方式中断呼叫(...放在该例程之外):

:call_ant
call ant %ANT_TARGETS%
set ANT_RETURN=%errorlevel%
goto :eof

(...在一些例行程序中间)

if "%DUMP_ARGS%"=="no" (
    call :call_ant
)

答案 4 :(得分:1)

您是否需要通过其.bat文件运行Ant?它只是一个java程序,您可以通过直接实例化和执行Ant运行时在VM内部执行。看看ant.bat,看看它的Main类是什么,然后直接执行它。

答案 5 :(得分:0)

对于Windows上的旧版Ant,这是一个长期存在的问题。我相信它已在1.7.0版本中得到修复。

有关详细信息,请参阅this bug;有关解决问题的方法,请参见this discussion

答案 6 :(得分:0)

我搜索了这个帖子,发现tangens的答案几乎解决了我的问题:在ant.bat的Windows上,退出编码总是为0,即使我故意使ant构建失败;我需要从TFS构建脚本中获取退出代码,它表明即使在TFS构建中也找不到%ERRORLEVEL%

但是,我必须从/B行中移除exit,否则,它仍然会显示退出代码0。

答案 7 :(得分:0)

我解决了用IF ERRORLEVEL 1替换IF %ERRORLEVEL% NEQ 0

call ant

IF %ERRORLEVEL% NEQ 0 GOTO :build_error