提交 28e3adf4 编写于 作者: A abayer

[HUDSON-2736] Application of patch submitted by riksmith.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@19614 71c3de6d-444a-0410-be80-ed276b4c234a
上级 f0ce8118
/*
* The MIT License
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Red Hat, Inc., Victor Glushenkov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.maven;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.DependencyGraph;
import hudson.model.Hudson;
import hudson.model.Project;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.Cause.UpstreamCause;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.Set;
public abstract class AbstractMavenBuild<P extends AbstractMavenProject<P,B>,B extends AbstractMavenBuild<P,B>> extends AbstractBuild<P, B> {
/**
* Extra versbose debug switch.
*/
public static boolean debug = false;
protected AbstractMavenBuild(P job) throws IOException {
super(job);
}
public AbstractMavenBuild(P job, Calendar timestamp) {
super(job, timestamp);
}
public AbstractMavenBuild(P project, File buildDir) throws IOException {
super(project, buildDir);
}
/**
* Schedules all the downstream builds.
*
* @param downstreams
* List of downstream jobs that are already scheduled.
* The method will add jobs that it triggered here,
* and won't try to trigger jobs that are already in this list.
* @param listener
* Where the progress reports go.
*/
protected final void scheduleDownstreamBuilds(BuildListener listener) {
// trigger dependency builds
DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
for( AbstractProject<?,?> down : getParent().getDownstreamProjects()) {
if(debug)
listener.getLogger().println("Considering whether to trigger "+down+" or not");
// if the downstream module depends on multiple modules,
// only trigger them when all the upstream dependencies are updated.
boolean trigger = true;
if (down.isInQueue()) {
if(debug)
listener.getLogger().println(" -> No, because dependency is already in queue");
trigger = false;
} else {
AbstractBuild<?,?> dlb = down.getLastBuild(); // can be null.
for (AbstractMavenProject up : Util.filter(down.getUpstreamProjects(),AbstractMavenProject.class)) {
Run ulb;
if(up==getParent()) {
// the current build itself is not registered as lastSuccessfulBuild
// at this point, so we have to take that into account. ugly.
if(getResult()==null || !getResult().isWorseThan(Result.UNSTABLE))
ulb = this;
else
ulb = up.getLastSuccessfulBuild();
} else
ulb = up.getLastSuccessfulBuild();
if(ulb==null) {
// if no usable build is available from the upstream,
// then we have to wait at least until this build is ready
if(debug)
listener.getLogger().println(" -> No, because another upstream "+up+" for "+down+" has no successful build");
trigger = false;
break;
}
// if no record of the relationship in the last build
// is available, we'll just have to assume that the condition
// for the new build is met, or else no build will be fired forever.
if(dlb==null) continue;
int n = dlb.getUpstreamRelationship(up);
if(n==-1) continue;
assert ulb.getNumber()>=n;
}
}
if(trigger) {
listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
down.scheduleBuild(new UpstreamCause(this));
}
}
}
/**
* Returns the project if any of the upstream project (or itself) is either
* building or is in the queue.
* <p>
* This means eventually there will be an automatic triggering of
* the given project (provided that all builds went smoothly.)
*/
private AbstractProject getBuildingUpstream(DependencyGraph graph, AbstractProject project) {
Set<AbstractProject> tups = graph.getTransitiveUpstream(project);
tups.add(project);
for (AbstractProject tup : tups) {
if(tup!=getProject() && (tup.isBuilding() || tup.isInQueue()))
return tup;
}
return null;
}
}
......@@ -23,22 +23,38 @@
*/
package hudson.maven;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.DependencyGraph;
import hudson.model.Hudson;
import hudson.model.ItemGroup;
import hudson.model.Descriptor.FormException;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildWrappers;
import hudson.tasks.Publisher;
import hudson.tasks.Maven.ProjectWithMaven;
import hudson.triggers.Trigger;
import hudson.tasks.Maven.ProjectWithMaven;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletException;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* Common part between {@link MavenModule} and {@link MavenModuleSet}.
*
* @author Kohsuke Kawaguchi
*/
public abstract class AbstractMavenProject<P extends AbstractMavenProject<P,R>,R extends AbstractBuild<P,R>> extends AbstractProject<P,R>
public abstract class AbstractMavenProject<P extends AbstractProject<P,R>,R extends AbstractBuild<P,R>> extends AbstractProject<P,R>
implements ProjectWithMaven {
protected AbstractMavenProject(ItemGroup parent, String name) {
super(parent, name);
......@@ -63,6 +79,61 @@ public abstract class AbstractMavenProject<P extends AbstractMavenProject<P,R>,R
}
}
}
private boolean blockBuildWhenUpstreamBuilding = true;
protected abstract void addTransientActionsFromBuild(R lastBuild, Set<Class> added);
@Override
public boolean isBuildBlocked() {
boolean blocked = super.isBuildBlocked();
if (!blocked && blockBuildWhenUpstreamBuilding) {
DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
AbstractProject bup = getBuildingUpstream();
if(bup!=null) {
return true;
}
}
return blocked;
}
public String getWhyBlocked() {
if (super.isBuildBlocked()) {
return super.getWhyBlocked();
} else {
AbstractProject bup = getBuildingUpstream();
String projectName = "";
if(bup!=null) {
projectName = bup.getName();
}
return "Upstream project is building: " + projectName;
}
}
/**
* Returns the project if any of the upstream project (or itself) is either
* building or is in the queue.
* <p>
* This means eventually there will be an automatic triggering of
* the given project (provided that all builds went smoothly.)
*/
private AbstractProject getBuildingUpstream() {
DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
Set<AbstractProject> tups = graph.getTransitiveUpstream(this);
tups.add(this);
for (AbstractProject tup : tups) {
if(tup!=this && (tup.isBuilding() || tup.isInQueue()))
return tup;
}
return null;
}
public boolean blockBuildWhenUpstreamBuilding() {
return blockBuildWhenUpstreamBuilding;
}
protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
super.submit(req,rsp);
blockBuildWhenUpstreamBuilding = req.hasParameter("maven.blockBuildWhenUpstreamBuilding");
}
}
......@@ -72,7 +72,7 @@ import java.util.Set;
*
* @author Kohsuke Kawaguchi
*/
public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
public class MavenBuild extends AbstractMavenBuild<MavenModule,MavenBuild> {
/**
* {@link MavenReporter}s that will contribute project actions.
* Can be null if there's none.
......@@ -537,113 +537,10 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
public void cleanUp(BuildListener listener) throws Exception {
if(getResult().isBetterOrEqualTo(Result.SUCCESS))
scheduleDownstreamBuilds(listener,new HashSet<AbstractProject>());
scheduleDownstreamBuilds(listener);
}
}
/**
* Schedules all the downstream builds.
*
* @param downstreams
* List of downstream jobs that are already scheduled.
* The method will add jobs that it triggered here,
* and won't try to trigger jobs that are already in this list.
* @param listener
* Where the progress reports go.
*/
/*package*/ final void scheduleDownstreamBuilds(BuildListener listener, Set<AbstractProject> downstreams) {
// trigger dependency builds
DependencyGraph graph = Hudson.getInstance().getDependencyGraph();
for( AbstractProject<?,?> down : getParent().getDownstreamProjects()) {
if(downstreams.contains(down))
continue; // already triggered
if(debug)
listener.getLogger().println("Considering whether to trigger "+down+" or not");
if(graph.hasIndirectDependencies(getProject(),down)) {
// if there's a longer dependency path to this project,
// then scheduling the build now is going to be a waste,
// so don't do that.
// let the longer path eventually trigger this build
if(debug)
listener.getLogger().println(" -> No, because there's a longer dependency path");
continue;
}
// if the downstream module depends on multiple modules,
// only trigger them when all the upstream dependencies are updated.
boolean trigger = true;
AbstractBuild<?,?> dlb = down.getLastBuild(); // can be null.
for (MavenModule up : Util.filter(down.getUpstreamProjects(),MavenModule.class)) {
MavenBuild ulb;
if(up==getProject()) {
// the current build itself is not registered as lastSuccessfulBuild
// at this point, so we have to take that into account. ugly.
if(getResult()==null || !getResult().isWorseThan(Result.UNSTABLE))
ulb = MavenBuild.this;
else
ulb = up.getLastSuccessfulBuild();
} else
ulb = up.getLastSuccessfulBuild();
if(ulb==null) {
// if no usable build is available from the upstream,
// then we have to wait at least until this build is ready
if(debug)
listener.getLogger().println(" -> No, because another upstream "+up+" for "+down+" has no successful build");
trigger = false;
break;
}
// if no record of the relationship in the last build
// is available, we'll just have to assume that the condition
// for the new build is met, or else no build will be fired forever.
if(dlb==null) continue;
int n = dlb.getUpstreamRelationship(up);
if(n==-1) continue;
assert ulb.getNumber()>=n;
if(ulb.getNumber()==n) {
// there's no new build of this upstream since the last build
// of the downstream, and the upstream build is in progress.
// The new downstream build should wait until this build is started
AbstractProject bup = getBuildingUpstream(graph, up);
if(bup!=null) {
if(debug)
listener.getLogger().println(" -> No, because another upstream "+bup+" for "+down+" is building");
trigger = false;
break;
}
}
}
if(trigger) {
listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
downstreams.add(down);
down.scheduleBuild(new UpstreamCause(this));
}
}
}
/**
* Returns the project if any of the upstream project (or itself) is either
* building or is in the queue.
* <p>
* This means eventually there will be an automatic triggering of
* the given project (provided that all builds went smoothly.)
*/
private AbstractProject getBuildingUpstream(DependencyGraph graph, AbstractProject project) {
Set<AbstractProject> tups = graph.getTransitiveUpstream(project);
tups.add(project);
for (AbstractProject tup : tups) {
if(tup!=getProject() && (tup.isBuilding() || tup.isInQueue()))
return tup;
}
return null;
}
private static final int MAX_PROCESS_CACHE = 5;
protected static final ProcessCache mavenProcessCache = new ProcessCache(MAX_PROCESS_CACHE);
......@@ -652,4 +549,9 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
* Set true to produce debug output.
*/
public static boolean debug = false;
@Override
public MavenModule getParent() {// don't know why, but javac wants this
return super.getParent();
}
}
......@@ -442,6 +442,10 @@ public final class MavenModuleSet extends AbstractMavenProject<MavenModuleSet,Ma
}
protected void buildDependencyGraph(DependencyGraph graph) {
Collection<MavenModule> modules = getModules();
for (MavenModule m : modules) {
m.buildDependencyGraph(graph);
}
publishers.buildDependencyGraph(this,graph);
buildWrappers.buildDependencyGraph(this,graph);
}
......
......@@ -29,6 +29,7 @@ import hudson.Launcher;
import hudson.Util;
import hudson.EnvVars;
import hudson.FilePath.FileCallable;
import hudson.matrix.MatrixConfiguration;
import hudson.maven.MavenBuild.ProxyImpl2;
import hudson.maven.reporters.MavenFingerprinter;
import hudson.model.AbstractBuild;
......@@ -97,7 +98,7 @@ import org.kohsuke.stapler.StaplerResponse;
*
* @author Kohsuke Kawaguchi
*/
public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,MavenModuleSetBuild> {
public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,MavenModuleSetBuild> {
/**
* {@link MavenReporter}s that will contribute project actions.
* Can be null if there's none.
......@@ -526,10 +527,7 @@ public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,Mave
// schedule downstream builds. for non aggregator style builds,
// this is done by each module
if(getResult().isBetterOrEqualTo(Result.SUCCESS)) {
for(AbstractProject down : getProject().getDownstreamProjects()) {
listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
down.scheduleBuild(new UpstreamCause(MavenModuleSetBuild.this));
}
scheduleDownstreamBuilds(listener);
}
}
......@@ -789,4 +787,9 @@ public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,Mave
* Extra versbose debug switch.
*/
public static boolean debug = false;
@Override
public MavenModuleSet getParent() {// don't know why, but javac wants this
return super.getParent();
}
}
......@@ -119,8 +119,8 @@ public class MavenArtifactRecord extends MavenAbstractArtifactRecord<MavenBuild>
deployer.deploy(main.getFile(),main,deploymentRepository,embedder.getLocalRepository());
for (MavenArtifact aa : attachedArtifacts) {
logger.println(Messages.MavenArtifact_DeployingAttachedArtifact(main.getFile().getName()));
Artifact a = aa.toArtifact(handlerManager,factory, parent);
logger.println(Messages.MavenArtifact_DeployingAttachedArtifact(a.getFile().getName()));
deployer.deploy(a.getFile(),a,deploymentRepository,embedder.getLocalRepository());
}
}
......
......@@ -73,6 +73,8 @@ THE SOFTWARE.
checked="${!it.aggregatorStyleBuild}" />
<f:optionalBlock name="maven.usePrivateRepository" title="${%Use private Maven repository}" help="/help/maven/private-repository.html"
checked="${it.usesPrivateRepository()}" />
<f:optionalBlock name="maven.blockBuildWhenUpstreamBuilding" title="${%Block build when dependency building}" help="/help/maven/block-upstream-building.html"
checked="${it.blockBuildWhenUpstreamBuilding()}" />
</f:advanced>
</f:section>
......
<div>
When this option is checked, Hudson will prevent the project from building when a dependency of this project is in the queue, or building. The dependencies include the direct as well as the transitive dependencies.
</div>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册