package hudson.plugins.build_timeout;
import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Descriptor;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.plugins.build_timeout.operations.AbortOperation;
import hudson.tasks.BuildStep;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Builder;
import hudson.triggers.SafeTimerTask;
import hudson.triggers.Trigger;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.jenkinsci.plugins.tokenmacro.MacroEvaluationException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class BuildStepWithTimeout extends Builder implements BuildStep {
private final BuildTimeOutStrategy strategy;
private final BuildStep buildStep;
private final List<BuildTimeOutOperation> operationList;
@DataBoundConstructor
public BuildStepWithTimeout(BuildStep buildStep, BuildTimeOutStrategy strategy, List<BuildTimeOutOperation> operationList) {
this.strategy = strategy;
this.buildStep = buildStep;
if (operationList != null && !operationList.isEmpty()) {
this.operationList = operationList;
}
else {
this.operationList = Collections.emptyList();
}
}
public List<BuildTimeOutOperation> getOperationList() {
return operationList;
}
public BuildStep getBuildStep() {
return buildStep;
}
private long getTimeout(Run run, TaskListener listener) throws IOException, InterruptedException {
try {
return strategy.getTimeOut((AbstractBuild<?, ?>) run, (BuildListener) listener);
} catch (MacroEvaluationException e) {
e.printStackTrace(listener.getLogger());
listener.error("Can't evaluate timeout - timeout would be disabled");
return Long.MAX_VALUE;
}
}
@Override
public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
return perform((Build)build, launcher, listener);
}
@Override
public boolean perform(final Build<?,?> build, final Launcher launcher, final BuildListener listener) throws InterruptedException, IOException {
final Timer timer = Trigger.timer;
final long delay = getTimeout(build, listener);
final TimerTask task = new SafeTimerTask() {
@Override
public void doRun() {
if (operationList.isEmpty()) {
new AbortOperation().perform(build, listener, delay);
}
for (BuildTimeOutOperation op : operationList) {
op.perform(build, listener, delay);
}
}
};
try {
timer.schedule(task, delay);
return buildStep.perform(build, launcher, listener);
} finally {
task.cancel();
}
}
public BuildTimeOutStrategy getStrategy() {
return strategy;
}
@Override
public BuildStepMonitor getRequiredMonitorService() {
return buildStep.getRequiredMonitorService();
}
@Extension
public static class DescriptorImpl extends BuildStepDescriptor<Builder> {
@Override
public BuildStepWithTimeout newInstance(StaplerRequest req, JSONObject formData)
throws hudson.model.Descriptor.FormException {
BuildStep buildstep = BuildTimeOutUtility.bindJSONWithDescriptor(req, formData, "buildStep", BuildStep.class);
BuildTimeOutStrategy strategy = BuildTimeOutUtility.bindJSONWithDescriptor(req, formData, "strategy", BuildTimeOutStrategy.class);
List<BuildTimeOutOperation> operationList = newInstancesFromHeteroList(req, formData, "operationList", getOperations());
return new BuildStepWithTimeout(buildstep, strategy, operationList);
}
@Override
public String getDisplayName() {
return "Run with timeout";
}
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
public List<Descriptor<?>> getBuildStepWithTimeoutRunners() {
List<Descriptor<?>> buildsteps = new ArrayList<Descriptor<?>>(Builder.all());
buildsteps.remove(this);
return buildsteps;
}
public List<BuildTimeOutStrategyDescriptor> getStrategies() {
List<BuildTimeOutStrategyDescriptor> descriptors = Jenkins.getInstance().getDescriptorList(BuildTimeOutStrategy.class);
List<BuildTimeOutStrategyDescriptor> supportedStrategies = new ArrayList<BuildTimeOutStrategyDescriptor>(descriptors.size());
for(BuildTimeOutStrategyDescriptor descriptor : descriptors) {
if (descriptor.isApplicableAsBuildStep()) {
supportedStrategies.add(descriptor);
}
}
return supportedStrategies;
}
@SuppressWarnings("unchecked")
public List<BuildTimeOutOperationDescriptor> getOperations(AbstractProject<?,?> project) {
return BuildTimeOutOperationDescriptor.all((Class<? extends AbstractProject<?, ?>>)project.getClass());
}
public List<BuildTimeOutOperationDescriptor> getOperations() {
return BuildTimeOutOperationDescriptor.all();
}
}
}