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

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

我刚用这个简单的ant测试文件validation了这个:

     

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

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

文件myant.bat内容:

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

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

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

文件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 ,我得到正确的退出值。

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

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

 exit /b %ANT_ERROR% 

最近这个问题早已存在并得到解决。 请参阅错误41039 。

它应该在ANT版本1.8.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 ) 

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

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

有关详细信息和此讨论 ,请参阅此错误以获取解决此问题的方法。

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

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

我用IF %ERRORLEVEL% NEQ 0解决了IF ERRORLEVEL 1问题:

 call ant IF %ERRORLEVEL% NEQ 0 GOTO :build_error