
hudson.matrix.MatrixBuild Maven / Gradle / Ivy
package hudson.matrix;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Executor;
import hudson.model.Fingerprint;
import hudson.model.Hudson;
import hudson.model.JobProperty;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.tasks.Publisher;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
/**
* Build of {@link MatrixProject}.
*
* @author Kohsuke Kawaguchi
*/
public class MatrixBuild extends AbstractBuild {
public MatrixBuild(MatrixProject job) throws IOException {
super(job);
}
public MatrixBuild(MatrixProject job, Calendar timestamp) {
super(job, timestamp);
}
public MatrixBuild(MatrixProject project, File buildDir) throws IOException {
super(project, buildDir);
}
/**
* Used by view to render a ball for {@link MatrixRun}.
*/
public final class RunPtr {
public final Combination combination;
private RunPtr(Combination c) { this.combination=c; }
public MatrixRun getRun() { return MatrixBuild.this.getRun(combination); }
public String getTooltip() {
MatrixRun r = getRun();
if(r!=null) return r.getIconColor().getDescription();
Queue.Item item = Hudson.getInstance().getQueue().getItem(getParent().getItem(combination));
if(item!=null)
return item.getWhy();
return null; // fall back
}
}
public Layouter getLayouter() {
return new Layouter(getParent().getAxes()) {
protected RunPtr getT(Combination c) {
return new RunPtr(c);
}
};
}
/**
* Gets the {@link MatrixRun} in this build that corresponds
* to the given combination.
*/
public MatrixRun getRun(Combination c) {
MatrixConfiguration config = getParent().getItem(c);
if(config==null) return null;
return config.getBuildByNumber(getNumber());
}
/**
* Returns all {@link MatrixRun}s for this {@link MatrixBuild}.
*/
public List getRuns() {
List r = new ArrayList();
for(MatrixConfiguration c : getParent().getItems())
r.add(c.getBuildByNumber(getNumber()));
return r;
}
public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
try {
MatrixRun item = getRun(Combination.fromString(token));
if(item!=null)
return item;
} catch (IllegalArgumentException _) {
// failed to parse the token as Combination. Must be something else
}
return super.getDynamic(token,req,rsp);
}
@Override
public void run() {
run(new RunnerImpl());
}
@Override
public Fingerprint.RangeSet getDownstreamRelationship(AbstractProject that) {
Fingerprint.RangeSet rs = super.getDownstreamRelationship(that);
for(MatrixRun run : getRuns())
rs.add(run.getDownstreamRelationship(that));
return rs;
}
private class RunnerImpl extends AbstractRunner {
private final List aggregators = new ArrayList();
protected Result doRun(BuildListener listener) throws Exception {
MatrixProject p = getProject();
PrintStream logger = listener.getLogger();
// list up aggregators
for (Publisher pub : p.getPublishers().values()) {
if (pub instanceof MatrixAggregatable) {
MatrixAggregatable ma = (MatrixAggregatable) pub;
MatrixAggregator a = ma.createAggregator(MatrixBuild.this, launcher, listener);
if(a!=null)
aggregators.add(a);
}
}
//let properties do their job
for (JobProperty prop : p.getProperties().values()) {
if (prop instanceof MatrixAggregatable) {
MatrixAggregatable ma = (MatrixAggregatable) prop;
MatrixAggregator a = ma.createAggregator(MatrixBuild.this, launcher, listener);
if(a!=null)
aggregators.add(a);
}
}
Collection activeConfigurations = p.getActiveConfigurations();
int n = getNumber();
for (MatrixAggregator a : aggregators)
if(!a.startBuild())
return Result.FAILURE;
try {
for(MatrixConfiguration c : activeConfigurations) {
logger.println(Messages.MatrixBuild_Triggering(c.getDisplayName()));
c.scheduleBuild();
}
// this occupies an executor unnecessarily.
// it would be nice if this can be placed in a temproary executor.
Result r = Result.SUCCESS;
for (MatrixConfiguration c : activeConfigurations) {
String whyInQueue = "";
long startTime = System.currentTimeMillis();
// wait for the completion
while(true) {
MatrixRun b = c.getBuildByNumber(n);
// two ways to get beyond this. one is that the build starts and gets done,
// or the build gets cancelled before it even started.
Result buildResult = null;
if(b!=null && !b.isBuilding())
buildResult = b.getResult();
Queue.Item qi = c.getQueueItem();
if(b==null && qi==null) {
// there's conceivably a race condition here, since b is set early on,
// and we are checking c.isInQueue() later. A build might have started
// after we computed b but before we checked c.isInQueue(). So
// double-check 'b' to see if it's really not there. Possibly related to
// http://www.nabble.com/Master-slave-problem-tt14710987.html
b = c.getBuildByNumber(n);
if(b==null) {
logger.println(Messages.MatrixBuild_AppearsCancelled(c.getDisplayName()));
buildResult = Result.ABORTED;
}
}
if(buildResult!=null) {
r = r.combine(buildResult);
if(b!=null)
for (MatrixAggregator a : aggregators)
if(!a.endRun(b))
return Result.FAILURE;
break;
} else {
if(qi!=null) {
// if the build seems to be stuck in the queue, display why
String why = qi.getWhy();
if(!why.equals(whyInQueue) && System.currentTimeMillis()-startTime>5000) {
logger.println(c.getDisplayName()+" is still in the queue: "+why);
whyInQueue = why;
}
}
}
Thread.sleep(1000);
}
}
return r;
} catch( InterruptedException e ) {
logger.println("Aborted");
return Result.ABORTED;
} finally {
// if the build was aborted in the middle. Cancel all the configuration builds.
Queue q = Hudson.getInstance().getQueue();
synchronized(q) {// avoid micro-locking in q.cancel.
for (MatrixConfiguration c : activeConfigurations) {
if(q.cancel(c))
logger.println(Messages.MatrixBuild_Cancelled(c.getDisplayName()));
MatrixRun b = c.getBuildByNumber(n);
if(b!=null) {
Executor exe = b.getExecutor();
if(exe!=null) {
logger.println(Messages.MatrixBuild_Interrupting(b.getDisplayName()));
exe.interrupt();
}
}
}
}
}
}
public void post2(BuildListener listener) throws Exception {
for (MatrixAggregator a : aggregators)
a.endBuild();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy