hudson.plugins.helpers.BuildProxy Maven / Gradle / Ivy
The newest version!
package hudson.plugins.helpers;
import hudson.FilePath;
import hudson.maven.MavenBuildProxy;
import hudson.util.IOException2;
import hudson.model.Action;
import hudson.model.Result;
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import java.util.Calendar;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
import java.io.Serializable;
import org.apache.maven.project.MavenProject;
/**
* Proxy for the key build information.
*
* @author Stephen Connolly
* @since 12-Jan-2008 12:08:32
*/
public final class BuildProxy implements Serializable {
// ------------------------------ FIELDS ------------------------------
private final FilePath artifactsDir;
private final FilePath projectRootDir;
private final FilePath buildRootDir;
private final FilePath executionRootDir;
private final Calendar timestamp;
private final List>> actions =
new ArrayList>>();
private Result result = null;
private boolean continueBuild = true;
// -------------------------- STATIC METHODS --------------------------
/**
* (Call from master) Invokes the ghostwriter on the master and slave nodes for this build.
*
* @param ghostwriter The ghostwriter that will be doing the work for the publisher.
* @param build The build.
* @param listener The build listener.
* @return true
if the build can continue.
* @throws IOException on IOException.
* @throws InterruptedException on InterruptedException.
*/
public static boolean doPerform(Ghostwriter ghostwriter,
AbstractBuild, ?> build,
BuildListener listener)
throws IOException, InterruptedException {
// first, do we need to do anything on the slave
if (ghostwriter instanceof Ghostwriter.SlaveGhostwriter) {
// construct the BuildProxy instance that we will use
BuildProxy buildProxy = new BuildProxy(
new FilePath(build.getArtifactsDir()),
new FilePath(build.getProject().getRootDir()),
new FilePath(build.getRootDir()),
build.getModuleRoot(),
build.getTimestamp());
BuildProxyCallableHelper callableHelper = new BuildProxyCallableHelper(buildProxy, ghostwriter, listener);
try {
buildProxy = buildProxy.getExecutionRootDir().act(callableHelper);
buildProxy.updateBuild(build);
// terminate the build if necessary
if (!buildProxy.isContinueBuild()) {
return false;
}
} catch (Exception e) {
throw unwrapException(e, listener);
}
}
// finally, on to the master
final Ghostwriter.MasterGhostwriter masterGhostwriter = Ghostwriter.MasterGhostwriter.class.cast(ghostwriter);
return masterGhostwriter == null
|| masterGhostwriter.performFromMaster(build, build.getModuleRoot(), listener);
}
/**
* Takes a remote exception that has been wrapped up in the remoting layer, and rethrows it as IOException,
* InterruptedException or if all else fails, a RuntimeException.
*
* @param e The wrapped exception.
* @param listener The listener for the build.
* @return never.
* @throws IOException if the wrapped exception is an IOException.
* @throws InterruptedException if the wrapped exception is an InterruptedException.
* @throws RuntimeException if the wrapped exception is neither an IOException nor an InterruptedException.
*/
private static RuntimeException unwrapException(Exception e,
BuildListener listener)
throws IOException, InterruptedException {
if (e.getCause() instanceof IOException) {
throw new IOException2(e.getCause().getMessage(), e);
}
if (e.getCause() instanceof InterruptedException) {
e.getCause().printStackTrace(listener.getLogger());
throw new InterruptedException(e.getCause().getMessage());
}
if (e.getCause() instanceof RuntimeException) {
throw new RuntimeException(e.getCause());
}
// How on earth do we get this far down the branch
e.printStackTrace(listener.getLogger());
throw new RuntimeException("Unexpected exception", e);
}
/**
* (Designed for execution from the master) Updates the build with the results that were reported to this proxy.
*
* @param build The build to update.
*/
public void updateBuild(AbstractBuild, ?> build) {
// update the actions
for (AbstractBuildAction> action : actions) {
if (!build.getActions().contains(action)) {
action.setBuild(build);
build.getActions().add(action);
}
}
// update the result
if (result != null && result.isWorseThan(build.getResult())) {
build.setResult(result);
}
}
/**
* (Call from slave) Invokes the ghostwriter on the master and slave nodes for this build.
*
* @param ghostwriter The ghostwriter that will be doing the work for the publisher.
* @param mavenBuildProxy The build (proxy).
* @param pom The maven pom.
* @param listener The build listener.
* @return true
if the build can continue.
* @throws IOException on IOException.
* @throws InterruptedException on InterruptedException.
*/
public static boolean doPerform(Ghostwriter ghostwriter,
MavenBuildProxy mavenBuildProxy,
MavenProject pom,
final BuildListener listener)
throws InterruptedException, IOException {
// first, construct the BuildProxy instance that we will use
BuildProxy buildProxy = new BuildProxy(
mavenBuildProxy.getArtifactsDir(),
mavenBuildProxy.getProjectRootDir(),
mavenBuildProxy.getRootDir(),
new FilePath(pom.getBasedir()),
mavenBuildProxy.getTimestamp());
// do we need to do anything on the slave
if (ghostwriter instanceof Ghostwriter.SlaveGhostwriter) {
final Ghostwriter.SlaveGhostwriter slaveGhostwriter = (Ghostwriter.SlaveGhostwriter) ghostwriter;
// terminate the build if necessary
if (!slaveGhostwriter.performFromSlave(buildProxy, listener)) {
return false;
}
}
// finally, on to the master
try {
return mavenBuildProxy.execute(new BuildProxyCallableHelper(buildProxy, ghostwriter, listener));
} catch (Exception e) {
throw unwrapException(e, listener);
}
}
// --------------------------- CONSTRUCTORS ---------------------------
/**
* Constructs a new build proxy that encapsulates all the information that a build step should need from the
* slave.
*
* @param artifactsDir The artifacts directory on the master.
* @param projectRootDir The project directory on the master (i.e. the .../hudson/jobs/ProjectName/). Note for
* multi-module projects it will be .../hudson/jobs/ProjectName/modules/ModuleName/.
* @param buildRootDir The build results directory on the master.
* @param executionRootDir The build base directory on the slave.
* @param timestamp The time when the build started executing.
*/
private BuildProxy(FilePath artifactsDir,
FilePath projectRootDir,
FilePath buildRootDir,
FilePath executionRootDir,
Calendar timestamp) {
this.artifactsDir = artifactsDir;
this.projectRootDir = projectRootDir;
this.buildRootDir = buildRootDir;
this.executionRootDir = executionRootDir;
this.timestamp = timestamp;
}
// --------------------- GETTER / SETTER METHODS ---------------------
/**
* Getter for property 'actions'.
*
* @return Value for property 'actions'.
*/
public List>> getActions() {
return actions;
}
/**
* Gets the directory (on the master) where the artifacts are archived.
*
* @return the directory (on the master) where the artifacts are archived.
*/
public FilePath getArtifactsDir() {
return artifactsDir;
}
/**
* Root directory of the {@link hudson.model.AbstractBuild} on the master.
*
* Files related to the {@link hudson.model.AbstractBuild} should be stored below this directory.
*
* @return Root directory of the {@link hudson.model.AbstractBuild} on the master.
*/
public FilePath getBuildRootDir() {
return buildRootDir;
}
/**
* Returns the root directory of the checked-out module on the machine where the build executes.
*
* This is usually where pom.xml, build.xml
* and so on exists.
*
* @return Returns the root directory of the checked-out module on the machine where the build executes.
*/
public FilePath getExecutionRootDir() {
return executionRootDir;
}
/**
* Root directory of the {@link hudson.model.AbstractProject} on the master.
*
* Files related to the {@link hudson.model.AbstractProject} should be stored below this directory.
*
* @return Root directory of the {@link hudson.model.AbstractProject} on the master.
*/
public FilePath getProjectRootDir() {
return projectRootDir;
}
/**
* Getter for property 'result'.
*
* @return Value for property 'result'.
*/
public Result getResult() {
return result;
}
/**
* Setter for property 'result'.
*
* @param result Value to set for property 'result'.
*/
public void setResult(Result result) {
this.result = result;
}
/**
* When the build is scheduled.
*
* @return The time when the build started executing.
*/
public Calendar getTimestamp() {
return timestamp;
}
/**
* Getter for property 'continueBuild'.
*
* @return Value for property 'continueBuild'.
*/
public boolean isContinueBuild() {
return continueBuild;
}
/**
* Setter for property 'continueBuild'.
*
* @param continueBuild Value to set for property 'continueBuild'.
*/
public void setContinueBuild(boolean continueBuild) {
this.continueBuild = continueBuild;
}
}