2009-09-21 10 views
9

Quando eseguo form dalla riga di comando, se ottengo un errore, ottengo uno stato di uscita diverso da zero ($? Su UNIX,% ERRORLEVEL% su Windows). Ma abbiamo un programma Java che sta eseguendo ant (tramite ProcessBuilder), e quando la formica fallisce, su Windows non possiamo ottenere lo stato di uscita.Perché ant.bat non restituisce uno stato di errore quando viene eseguito a livello di codice?

Ho appena verificato questo con questo semplice file di test ant:

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

Su UNIX, in esecuzione stampe formica un messaggio di errore, e facendo eco $? stampa dopo 1. In Windows, in esecuzione formica o ant.bat stampa un messaggio di errore, e facendo eco% ERRORLEVEL% dopo stampe 1.

Ora, utilizzando il programma di prova di seguito: Su UNIX, Java Run stampe formica un fallimento messaggio e echo $? stampe successive 1. Su Windows, java Run ant non è in grado di trovare un programma chiamato formica da eseguire, ma java Run ant.bat stampa un messaggio di errore, tuttavia echoing% ERRORLEVEL% dopo stampa . Cosa dà?

Stiamo facendo affidamento sulla possibilità di controllare lo stato di uscita dopo aver eseguito ant. Eravamo, comunque. Perché non possiamo fare affidamento su questo, a livello di codice?

programma di test:

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

risposta

1

Avete bisogno di eseguire Ant tramite il suo file .bat? È solo un programma java, è possibile eseguire semplicemente all'interno della VM creando direttamente ed eseguendo il runtime Ant. Dai un'occhiata all'interno di ant.bat, vedi qual è la sua classe Main ed eseguila direttamente.

+0

ant.bat è complesso e l'esecuzione del programma java direttamente è corrispondentemente complessa. Sto vedendo lo stesso problema eseguire ant.bat da uno script ant (no, non chiedere). Non riesco a vedere l'errore ant.bat. Non voglio consegnare ant2.bat all'ambiente del mio costruttore, ma lo farò se dovessi farlo. Qualcuno sa * perché * questo funziona? PS: Qual è il codice di formattazione per questo commento ??? –

0

Questo è un problema di vecchia data per le versioni precedenti di Ant su Windows. Credo che sia stato corretto nella versione 1.7.0.

Vedere this bug per dettagli e this discussion per un approccio per affrontarlo.

+1

Sono su form 1.7.1. Ho appena provato a correre con il percorso completo per assicurarmi che non stia eseguendo un'altra versione di formica. Stesso comportamento: correggere il livello di errore quando si esegue da un prompt; errore errorlevel quando eseguito da un programma. – skiphoppy

2

Ho risolto questo problema con la creazione di due file batch in più (non molto bello, ma funziona):

il contenuto del file myant.bat:

call ant2.bat %* 

il contenuto del file ant2.bat:

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

Ora posso chiamare myant.bat come Process da java e ottengo il valore di uscita corretto.

Spiacente, non posso dire perché questo funziona. È semplicemente il risultato di molti tentativi.

0

Ho cercato su Google questo thread e ho trovato la risposta di tangens quasi risolto il mio problema: l'uscita codificata è sempre 0 su Windows da ant.bat, anche quando ho intenzionalmente fallito una generazione di formiche; Ho bisogno di ottenere il codice di uscita da uno script di compilazione TFS, e ha dimostrato che anche il %ERRORLEVEL% non può essere trovato in build TFS.

Tuttavia, devo rimuovere il /B da exit righe, altrimenti, mi mostra sempre il codice di uscita 0.

6

Ho risolto questo problema con la creazione di un unico file batch (un po 'più bello di quanto sopra, ma ancora misterioso):

il contenuto del file myant.bat:

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

soprattutto, senza alcun codice qualunque sia dopo lo call.

+0

+1 Ho avuto lo stesso problema nel cercare di chiamare la formica da psake. Questo ha risolto il mio problema. –

2

Una patch rapido è l'aggiunta di quanto segue alla fine del file ANT.BAT:

exit /b %ANT_ERROR% 

Questo problema esiste da lungo tempo e fissato di recente. Fare riferimento a Bug 41039.

Dovrebbe essere pronto in ANT 1.8.2 o versione successiva.

2

Un altro problema: se si chiama ANT all'interno di un file BAT e si è interessati a salvare il valore errorlevel, è necessario mantenere la chiamata da un blocco if/else.

Ad esempio, questo non funzionerà (... nel bel mezzo di alcuni di routine):

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

È necessario rompere la chiamata come segue (... collocato al di fuori che di routine):

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

(... nel mezzo di alcuni di routine)

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

ho risolto sostituendo IF ERRORLEVEL 1 con IF %ERRORLEVEL% NEQ 0:

call ant 

IF %ERRORLEVEL% NEQ 0 GOTO :build_error 
Problemi correlati