提交 9e3b4951 编写于 作者: K Kohsuke Kawaguchi

added ability to wait for the start of a build in a future, not just the end of it.

上级 2776eea6
......@@ -27,6 +27,7 @@
*/
package hudson.model;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import hudson.Functions;
import antlr.ANTLRException;
import hudson.AbortException;
......@@ -46,6 +47,7 @@ import hudson.model.Fingerprint.RangeSet;
import hudson.model.Queue.Executable;
import hudson.model.Queue.Task;
import hudson.model.listeners.SCMListener;
import hudson.model.queue.QueueTaskFuture;
import hudson.model.queue.SubTask;
import hudson.model.Queue.WaitingItem;
import hudson.model.RunMap.Constructor;
......@@ -814,7 +816,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
* @param actions
* For the convenience of the caller, this array can contain null, and those will be silently ignored.
*/
public Future<R> scheduleBuild2(int quietPeriod, Cause c, Action... actions) {
@WithBridgeMethods(Future.class)
public QueueTaskFuture<R> scheduleBuild2(int quietPeriod, Cause c, Action... actions) {
return scheduleBuild2(quietPeriod,c,Arrays.asList(actions));
}
......@@ -827,7 +830,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
* @since 1.383
*/
@SuppressWarnings("unchecked")
public Future<R> scheduleBuild2(int quietPeriod, Cause c, Collection<? extends Action> actions) {
@WithBridgeMethods(Future.class)
public QueueTaskFuture<R> scheduleBuild2(int quietPeriod, Cause c, Collection<? extends Action> actions) {
if (!isBuildable())
return null;
......@@ -842,7 +846,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
WaitingItem i = Jenkins.getInstance().getQueue().schedule(this, quietPeriod, queueActions);
if(i!=null)
return (Future)i.getFuture();
return (QueueTaskFuture)i.getFuture();
return null;
}
......@@ -877,7 +881,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
* as deprecated.
*/
@SuppressWarnings("deprecation")
public Future<R> scheduleBuild2(int quietPeriod) {
@WithBridgeMethods(Future.class)
public QueueTaskFuture<R> scheduleBuild2(int quietPeriod) {
return scheduleBuild2(quietPeriod, new LegacyCodeCause());
}
......@@ -885,7 +890,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
* Schedules a build of this project, and returns a {@link Future} object
* to wait for the completion of the build.
*/
public Future<R> scheduleBuild2(int quietPeriod, Cause c) {
@WithBridgeMethods(Future.class)
public QueueTaskFuture<R> scheduleBuild2(int quietPeriod, Cause c) {
return scheduleBuild2(quietPeriod, c, new Action[0]);
}
......
......@@ -32,13 +32,15 @@ import hudson.remoting.AsyncFutureImpl;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* Created when {@link Queue.Item} is created so that the caller can track the progress of the task.
*
* @author Kohsuke Kawaguchi
*/
public final class FutureImpl extends AsyncFutureImpl<Executable> {
public final class FutureImpl extends AsyncFutureImpl<Executable> implements QueueTaskFuture<Executable> {
private final Task task;
/**
......@@ -46,10 +48,25 @@ public final class FutureImpl extends AsyncFutureImpl<Executable> {
*/
private final Set<Executor> executors = new HashSet<Executor>();
/**
* {@link Future} that completes when the task started running.
*
* In contrast, {@link FutureImpl} will complete when the task finishes.
*/
/*package*/ final AsyncFutureImpl<Executable> start = new AsyncFutureImpl<Executable>();
public FutureImpl(Task task) {
this.task = task;
}
public Future<Executable> getStartCondition() {
return start;
}
public final Executable waitForStart() throws InterruptedException, ExecutionException {
return getStartCondition().get();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
Queue q = Jenkins.getInstance().getQueue();
......
package hudson.model.queue;
import hudson.model.Queue.Executable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* {@link Future} that can be used to wait for the start and the end of the task execution
* (such as a build.)
*
* <p>
* For a historical reason, this object itself extends from {@link Future} to signal the
* end of the task execution, and {@link #getStartCondition()} returns a separate
* {@link Future} object that waits for the start of the task.
*
* @author Kohsuke Kawaguchi
* @since 1.469
*/
public interface QueueTaskFuture<R extends Executable> extends Future<R> {
/**
* Returns a {@link Future} object that can be used to wait for the start of the task execution.
*
* @return
* never return null.
*/
Future<R> getStartCondition();
/**
* Short for {@code getStartCondition().get()}
*/
R waitForStart() throws InterruptedException, ExecutionException;
}
......@@ -45,7 +45,7 @@ public final class WorkUnitContext {
public final Task task;
/**
* Once the execution is complete, update this future object with the outcome.
* Once the execution starts and completes, update this future object with the outcome.
*/
public final FutureImpl future;
......@@ -110,6 +110,12 @@ public final class WorkUnitContext {
*/
public void synchronizeStart() throws InterruptedException {
startLatch.synchronize();
// the main thread will send a notification
Executor e = Executor.currentExecutor();
WorkUnit wu = e.getCurrentWorkUnit();
if (wu.isMainWork()) {
future.start.set(e.getCurrentExecutable());
}
}
/**
......
......@@ -32,6 +32,7 @@ import hudson.matrix.MatrixProject;
import hudson.matrix.TextAxis;
import hudson.model.Cause.*;
import hudson.model.Queue.*;
import hudson.model.queue.QueueTaskFuture;
import hudson.tasks.Shell;
import hudson.triggers.SCMTrigger.SCMTriggerCause;
import hudson.triggers.TimerTrigger.TimerTriggerCause;
......@@ -287,4 +288,26 @@ public class QueueTest extends HudsonTestCase {
for (Future<MatrixBuild> f : r)
assertBuildStatusSuccess(f);
}
public void testWaitForStart() throws Exception {
final OneShotEvent ev = new OneShotEvent();
FreeStyleProject p = createFreeStyleProject();
p.getBuildersList().add(new TestBuilder() {
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
ev.block();
return true;
}
});
QueueTaskFuture<FreeStyleBuild> v = p.scheduleBuild2(0);
FreeStyleBuild b = v.waitForStart();
assertEquals(1,b.getNumber());
assertTrue(b.isBuilding());
assertSame(p,b.getProject());
ev.signal(); // let the build complete
FreeStyleBuild b2 = assertBuildStatusSuccess(v);
assertSame(b,b2);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册