diff --git a/core/src/main/java/hudson/cli/BuildCommand.java b/core/src/main/java/hudson/cli/BuildCommand.java index c14f81a521afec04a7b63b0260f7c2229e1d6031..8ca424145183986794d10a02ac2f6224fb3ab1dd 100644 --- a/core/src/main/java/hudson/cli/BuildCommand.java +++ b/core/src/main/java/hudson/cli/BuildCommand.java @@ -48,6 +48,7 @@ import java.util.HashMap; import java.util.List; import java.util.ArrayList; import java.util.Map.Entry; +import java.io.FileNotFoundException; import java.io.PrintStream; import jenkins.model.Jenkins; @@ -82,6 +83,12 @@ public class BuildCommand extends CLICommand { @Option(name="-v",usage="Prints out the console output of the build. Use with -s") public boolean consoleOutput = false; + @Option(name="-r", usage="Number of times to retry reading of the output log if it does not exists on first attempt. Defaults to 0. Use with -v.") + public String retryCntStr = "0"; + + // hold parsed retryCnt; + private int retryCnt = 0; + protected int run() throws Exception { job.checkPermission(Item.BUILD); @@ -114,6 +121,8 @@ public class BuildCommand extends CLICommand { a = new ParametersAction(values); } + retryCnt = Integer.parseInt(retryCntStr); + if (checkSCM) { if (job.poll(new StreamTaskListener(stdout, getClientCharset())).change == Change.NONE) { return 0; @@ -128,7 +137,24 @@ public class BuildCommand extends CLICommand { if (sync) { if (consoleOutput) { - b.writeWholeLogTo(stdout); + // read output in a retry loop, by default try only once + // writeWholeLogTo may fail with FileNotFound + // exception on a slow/busy machine, if it takes + // longish to create the log file + int retryInterval = 100; + for (int i=0;i<=retryCnt;) { + try { + b.writeWholeLogTo(stdout); + break; + } + catch (FileNotFoundException e) { + if ( i == retryCnt ) { + throw e; + } + i++; + Thread.sleep(retryInterval); + } + } } // TODO: should we abort the build if the CLI is cancelled? f.get(); // wait for the completion diff --git a/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy b/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy index ed928e1a71ce7af7ac45c6ba49c119122ea274cf..00e6182c14edebe569dab0d8a2997aa5eec7c464 100644 --- a/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy +++ b/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy @@ -84,6 +84,22 @@ public class BuildCommandTest extends HudsonTestCase { } + /** + * Tests synchronous execution with retried verbose output + */ + void testSyncWOutputStreaming() { + def p = createFreeStyleProject(); + p.buildersList.add(new Shell("sleep 3")); + + def cli =new CLI(getURL()) + try { + cli.execute(["build","-s","-v","-r","5",p.name]) + assertFalse(p.getBuildByNumber(1).isBuilding()) + } finally { + cli.close(); + } + } + void testParameters() { def p = createFreeStyleProject(); p.addProperty(new ParametersDefinitionProperty([new StringParameterDefinition("key",null)]));