提交 14dee6e5 编写于 作者: C Christoph Kutzinski

Merge pull request #274 from kutzi/processfactory-refactor

Remove code duplication between Maven2 and Maven3 builders
......@@ -26,9 +26,12 @@ package hudson.maven;
import hudson.model.BuildListener;
import jenkins.model.Jenkins;
import hudson.model.Result;
import hudson.remoting.Channel;
import hudson.remoting.DelegatingCallable;
import hudson.remoting.Future;
import java.io.IOException;
import java.io.Serializable;
import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
......@@ -39,6 +42,7 @@ import java.util.Map;
*/
public abstract class AbstractMavenBuilder implements DelegatingCallable<Result,IOException> {
private static final long serialVersionUID = -2687215937784908860L;
/**
* Goals to be executed in this Maven execution.
*/
......@@ -53,6 +57,12 @@ public abstract class AbstractMavenBuilder implements DelegatingCallable<Result,
*/
protected final BuildListener listener;
/**
* Record all asynchronous executions as they are scheduled,
* to make sure they are all completed before we finish.
*/
protected transient /*final*/ List<Future<?>> futures;
protected AbstractMavenBuilder(BuildListener listener, List<String> goals, Map<String, String> systemProps) {
this.listener = listener;
this.goals = goals;
......@@ -99,4 +109,29 @@ public abstract class AbstractMavenBuilder implements DelegatingCallable<Result,
return Jenkins.getInstance().getPluginManager().uberClassLoader;
}
protected class FilterImpl extends MavenBuildProxy2.Filter<MavenBuildProxy2> implements Serializable {
private MavenBuildInformation mavenBuildInformation;
private Channel channel;
public FilterImpl(MavenBuildProxy2 core, MavenBuildInformation mavenBuildInformation, Channel channel) {
super(core);
this.mavenBuildInformation = mavenBuildInformation;
this.channel = channel;
}
@Override
public void executeAsync(final BuildCallable<?,?> program) throws IOException {
futures.add(channel.callAsync(new AsyncInvoker(core,program)));
}
private static final long serialVersionUID = 1L;
public MavenBuildInformation getMavenBuildInformation()
{
return mavenBuildInformation;
}
}
}
......@@ -15,6 +15,7 @@ import hudson.model.Executor;
import hudson.model.JDK;
import hudson.model.Node;
import hudson.model.TaskListener;
import hudson.model.Run.RunnerAbortedException;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.RemoteInputStream;
......@@ -38,6 +39,9 @@ import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Arrays;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.framework.io.IOException2;
/*
......@@ -248,10 +252,76 @@ public abstract class AbstractMavenProcessFactory
/**
* Builds the command line argument list to launch the maven process.
*
*/
protected abstract ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener,int tcpPort)
throws IOException, InterruptedException;
protected ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener,int tcpPort) throws IOException, InterruptedException {
MavenInstallation mvn = getMavenInstallation(listener);
if(mvn==null) {
listener.error("Maven version is not configured for this project. Can't determine which Maven to run");
throw new RunnerAbortedException();
}
if(mvn.getHome()==null) {
listener.error("Maven '%s' doesn't have its home set",mvn.getName());
throw new RunnerAbortedException();
}
boolean isMaster = getCurrentNode()== Jenkins.getInstance();
FilePath slaveRoot=null;
if(!isMaster)
slaveRoot = getCurrentNode().getRootPath();
ArgumentListBuilder args = new ArgumentListBuilder();
JDK jdk = getJava(listener);
if(jdk==null) {
args.add("java");
} else {
args.add(jdk.getHome()+"/bin/java"); // use JDK.getExecutable() here ?
}
if(debugPort!=0)
args.add("-Xrunjdwp:transport=dt_socket,server=y,address="+debugPort);
if(yjp)
args.add("-agentlib:yjpagent=tracing");
args.addTokenized(getMavenOpts());
args.add( "-cp" );
args.add(getMavenAgentClassPath(mvn,isMaster,slaveRoot,listener));
args.add(getMainClassName());
// M2_HOME
args.add(mvn.getHome());
// remoting.jar
String remotingJar = getLauncher().getChannel().call(new GetRemotingJar());
if(remotingJar==null) {// this shouldn't be possible, but there are still reports indicating this, so adding a probe here.
listener.error("Failed to determine the location of slave.jar");
throw new RunnerAbortedException();
}
args.add(remotingJar);
// interceptor.jar
args.add(getMavenInterceptorClassPath(mvn,isMaster,slaveRoot));
// TCP/IP port to establish the remoting infrastructure
args.add(tcpPort);
return args;
}
/**
* Returns the classpath string for the maven-agent jar including classworlds
*/
protected abstract String getMavenAgentClassPath(MavenInstallation mvn,boolean isMaster,FilePath slaveRoot,BuildListener listener) throws IOException, InterruptedException ;
/**
* Returns the classpath string for the maven-interceptor jar
*/
protected abstract String getMavenInterceptorClassPath(MavenInstallation mvn,boolean isMaster,FilePath slaveRoot) throws IOException, InterruptedException ;
/**
* Returns the name of the Maven main class.
*/
protected abstract String getMainClassName();
public String getMavenOpts() {
if( this.mavenOpts != null )
......@@ -349,5 +419,19 @@ public abstract class AbstractMavenProcessFactory
public static final String MAVEN_REMOTE_USEINET_ENV_VAR_NAME = "MAVEN_REMOTE_USEINET";
/**
* If true, launch Maven with YJP offline profiler agent.
*/
public static boolean yjp = Boolean.getBoolean("hudson.maven.yjp");
/**
* If not 0, launch Maven with a debugger port.
*/
public static int debugPort;
static {
String port = System.getProperty("hudson.maven.debugPort");
if(port!=null)
debugPort = Integer.parseInt(port);
}
}
/*
* The MIT License
*
* Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi,
* Red Hat, Inc., Victor Glushenkov, Alan Harder, Olivier Lamy, Christoph Kutzinski
*
* 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.Launcher;
import hudson.maven.MavenBuild.ProxyImpl2;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.remoting.Channel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.apache.maven.BuildFailureException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.monitor.event.EventDispatcher;
import org.apache.maven.project.MavenProject;
/**
* Runs Maven and builds the project.
*
* This is only used for
* {@link MavenModuleSet#isAggregatorStyleBuild() the aggregator style build}.
*/
final class Maven2Builder extends MavenBuilder {
private final Map<ModuleName,MavenBuildProxy2> proxies;
private final Map<ModuleName,List<MavenReporter>> reporters = new HashMap<ModuleName,List<MavenReporter>>();
private final Map<ModuleName,List<ExecutedMojo>> executedMojos = new HashMap<ModuleName,List<ExecutedMojo>>();
private long mojoStartTime;
private MavenBuildProxy2 lastProxy;
/**
* Kept so that we can finalize them in the end method.
*/
private final transient Map<ModuleName,ProxyImpl2> sourceProxies;
public Maven2Builder(BuildListener listener,Map<ModuleName,ProxyImpl2> proxies, Collection<MavenModule> modules, List<String> goals, Map<String,String> systemProps, MavenBuildInformation mavenBuildInformation) {
super(listener,goals,systemProps);
this.sourceProxies = proxies;
this.proxies = new HashMap<ModuleName, MavenBuildProxy2>(proxies);
for (Entry<ModuleName,MavenBuildProxy2> e : this.proxies.entrySet())
e.setValue(new FilterImpl(e.getValue(), mavenBuildInformation, Channel.current()));
for (MavenModule m : modules)
reporters.put(m.getModuleName(),m.createReporters());
}
/**
* Invoked after the maven has finished running, and in the master, not in the maven process.
*/
void end(Launcher launcher) throws IOException, InterruptedException {
for (Map.Entry<ModuleName,ProxyImpl2> e : sourceProxies.entrySet()) {
ProxyImpl2 p = e.getValue();
for (MavenReporter r : reporters.get(e.getKey())) {
// we'd love to do this when the module build ends, but doing so requires
// we know how many task segments are in the current build.
r.end(p.owner(),launcher,listener);
p.appendLastLog();
}
p.close();
}
}
@Override
public Result call() throws IOException {
try {
if (MavenModuleSetBuild.debug) {
listener.getLogger().println("Builder extends MavenBuilder in call " + Thread.currentThread().getContextClassLoader());
}
return super.call();
} finally {
if(lastProxy!=null)
lastProxy.appendLastLog();
}
}
@Override
void preBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException {
// set all modules which are not actually being build (in incremental builds) to NOT_BUILD
List<MavenProject> projects = rm.getSortedProjects();
Set<ModuleName> buildingProjects = new HashSet<ModuleName>();
for (MavenProject p : projects) {
buildingProjects.add(new ModuleName(p));
}
for (Entry<ModuleName,MavenBuildProxy2> e : this.proxies.entrySet()) {
if (! buildingProjects.contains(e.getKey())) {
MavenBuildProxy2 proxy = e.getValue();
proxy.start();
proxy.setResult(Result.NOT_BUILT);
proxy.end();
}
}
}
void postBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException {
// TODO
}
void preModule(MavenProject project) throws InterruptedException, IOException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy2 proxy = proxies.get(name);
listener.getLogger().flush(); // make sure the data until here are all written
proxy.start();
for (MavenReporter r : reporters.get(name))
if(!r.preBuild(proxy,project,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
}
void postModule(MavenProject project) throws InterruptedException, IOException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy2 proxy = proxies.get(name);
List<MavenReporter> rs = reporters.get(name);
if(rs==null) { // probe for issue #906
throw new AssertionError("reporters.get("+name+")==null. reporters="+reporters+" proxies="+proxies);
}
for (MavenReporter r : rs)
if(!r.postBuild(proxy,project,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
proxy.setExecutedMojos(executedMojos.get(name));
listener.getLogger().flush(); // make sure the data until here are all written
proxy.end();
lastProxy = proxy;
}
void preExecute(MavenProject project, MojoInfo mojoInfo) throws IOException, InterruptedException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy proxy = proxies.get(name);
for (MavenReporter r : reporters.get(name))
if(!r.preExecute(proxy,project,mojoInfo,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
mojoStartTime = System.currentTimeMillis();
}
void postExecute(MavenProject project, MojoInfo mojoInfo, Exception exception) throws IOException, InterruptedException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
List<ExecutedMojo> mojoList = executedMojos.get(name);
if(mojoList==null)
executedMojos.put(name,mojoList=new ArrayList<ExecutedMojo>());
mojoList.add(new ExecutedMojo(mojoInfo,System.currentTimeMillis()-mojoStartTime));
MavenBuildProxy2 proxy = proxies.get(name);
for (MavenReporter r : reporters.get(name))
if(!r.postExecute(proxy,project,mojoInfo,listener,exception))
throw new hudson.maven.agent.AbortException(r+" failed");
if(exception!=null)
proxy.setResult(Result.FAILURE);
}
void onReportGenerated(MavenProject project, MavenReportInfo report) throws IOException, InterruptedException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy proxy = proxies.get(name);
for (MavenReporter r : reporters.get(name))
if(!r.reportGenerated(proxy,project,report,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
}
private static final long serialVersionUID = 1L;
}
\ No newline at end of file
......@@ -28,7 +28,6 @@ import hudson.maven.MavenBuild.ProxyImpl2;
import hudson.maven.util.ExecutionEventLogger;
import hudson.model.BuildListener;
import hudson.model.Executor;
import jenkins.model.Jenkins;
import hudson.model.Result;
import hudson.remoting.Channel;
import hudson.remoting.DelegatingCallable;
......@@ -79,12 +78,6 @@ public class Maven3Builder extends AbstractMavenBuilder implements DelegatingCal
*/
private final boolean profile = MavenProcessFactory.profile;
/**
* Record all asynchronous executions as they are scheduled,
* to make sure they are all completed before we finish.
*/
protected transient /*final*/ List<Future<?>> futures;
HudsonMavenExecutionResult mavenExecutionResult;
private final Map<ModuleName,MavenBuildProxy2> proxies;
......@@ -190,12 +183,6 @@ public class Maven3Builder extends AbstractMavenBuilder implements DelegatingCal
}
}
// since reporters might be from plugins, use the uberjar to resolve them.
public ClassLoader getClassLoader() {
return Jenkins.getInstance().getPluginManager().uberClassLoader;
}
/**
* Invoked after the maven has finished running, and in the master, not in the maven process.
*/
......@@ -212,34 +199,10 @@ public class Maven3Builder extends AbstractMavenBuilder implements DelegatingCal
}
}
private class FilterImpl extends MavenBuildProxy2.Filter<MavenBuildProxy2> implements Serializable {
private MavenBuildInformation mavenBuildInformation;
private Channel channel;
public FilterImpl(MavenBuildProxy2 core, MavenBuildInformation mavenBuildInformation, Channel channel) {
super(core);
this.mavenBuildInformation = mavenBuildInformation;
this.channel = channel;
}
@Override
public void executeAsync(final BuildCallable<?,?> program) throws IOException {
futures.add(channel.callAsync(new AsyncInvoker(core,program)));
}
private static final long serialVersionUID = 1L;
public MavenBuildInformation getMavenBuildInformation()
{
return mavenBuildInformation;
}
}
private static final class MavenExecutionListener extends AbstractExecutionListener implements Serializable, ExecutionListener {
private static final long serialVersionUID = 4942789836756366116L;
private final Maven3Builder maven3Builder;
/**
......
......@@ -27,14 +27,11 @@ import hudson.EnvVars;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.BuildListener;
import jenkins.model.Jenkins;
import hudson.model.JDK;
import hudson.model.Run.RunnerAbortedException;
import hudson.model.TaskListener;
import hudson.remoting.Callable;
import hudson.remoting.Which;
import hudson.tasks.Maven.MavenInstallation;
import hudson.util.ArgumentListBuilder;
import java.io.File;
import java.io.FilenameFilter;
......@@ -53,75 +50,32 @@ public class Maven3ProcessFactory extends AbstractMavenProcessFactory implements
Maven3ProcessFactory(MavenModuleSet mms, Launcher launcher, EnvVars envVars, String mavenOpts, FilePath workDir) {
super( mms, launcher, envVars, mavenOpts, workDir );
}
/**
* Builds the command line argument list to launch the maven process.
*
*/
protected ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener,int tcpPort) throws IOException, InterruptedException {
MavenInstallation mvn = getMavenInstallation(listener);
if(mvn==null) {
listener.error("Maven version is not configured for this project. Can't determine which Maven to run");
throw new RunnerAbortedException();
}
if(mvn.getHome()==null) {
listener.error("Maven '%s' doesn't have its home set",mvn.getName());
throw new RunnerAbortedException();
}
// find classworlds.jar
@Override
protected String getMavenAgentClassPath(MavenInstallation mvn,boolean isMaster,FilePath slaveRoot,BuildListener listener) throws IOException, InterruptedException {
String classWorldsJar = getLauncher().getChannel().call(new GetClassWorldsJar(mvn.getHome(),listener));
boolean isMaster = getCurrentNode()== Jenkins.getInstance();
FilePath slaveRoot=null;
if(!isMaster)
slaveRoot = getCurrentNode().getRootPath();
ArgumentListBuilder args = new ArgumentListBuilder();
JDK jdk = getJava(listener);
if(jdk==null) {
args.add("java");
} else {
args.add(jdk.getHome()+"/bin/java"); // use JDK.getExecutable() here ?
}
if(MavenProcessFactory.debugPort!=0)
args.add("-Xrunjdwp:transport=dt_socket,server=y,address="+MavenProcessFactory.debugPort);
if(MavenProcessFactory.yjp)
args.add("-agentlib:yjpagent=tracing");
args.addTokenized(getMavenOpts());
args.add("-cp");
args.add(
(isMaster? Which.jarFile(Maven3Main.class).getAbsolutePath():slaveRoot.child("maven3-agent.jar").getRemote())+
(getLauncher().isUnix()?":":";")+classWorldsJar);
args.add(Maven3Main.class.getName());
// M2_HOME
args.add(mvn.getHome());
// remoting.jar
String remotingJar = getLauncher().getChannel().call(new GetRemotingJar());
if(remotingJar==null) {// this shouldn't be possible, but there are still reports indicating this, so adding a probe here.
listener.error("Failed to determine the location of slave.jar");
throw new RunnerAbortedException();
}
args.add(remotingJar);
args.add(isMaster?
Which.jarFile(Maven3Launcher.class).getAbsolutePath():
slaveRoot.child("maven3-interceptor.jar").getRemote());
// TCP/IP port to establish the remoting infrastructure
args.add(tcpPort);
return args;
return (isMaster? Which.jarFile(Maven3Main.class).getAbsolutePath():slaveRoot.child("maven3-agent.jar").getRemote())+
(getLauncher().isUnix()?":":";")+classWorldsJar;
}
@Override
protected String getMainClassName() {
return Maven3Main.class.getName();
}
@Override
protected String getMavenInterceptorClassPath(MavenInstallation mvn,boolean isMaster,FilePath slaveRoot) throws IOException, InterruptedException {
return isMaster?
Which.jarFile(Maven3Launcher.class).getAbsolutePath():
slaveRoot.child("maven3-interceptor.jar").getRemote();
}
/**
* Finds classworlds.jar
*/
private static final class GetClassWorldsJar implements Callable<String,IOException> {
private static final long serialVersionUID = -2599434124883557137L;
private final String mvnHome;
private final TaskListener listener;
......@@ -137,15 +91,8 @@ public class Maven3ProcessFactory extends AbstractMavenProcessFactory implements
File bootDir = new File(home, "boot");
File[] classworlds = bootDir.listFiles(CLASSWORLDS_FILTER);
if(classworlds==null || classworlds.length==0) {
// Maven 2.0.6 puts it to a different place
bootDir = new File(home, "boot");
classworlds = bootDir.listFiles(CLASSWORLDS_FILTER);
if(classworlds==null || classworlds.length==0) {
// FIXME use messages
//listener.error(Messages.MavenProcessFactory_ClassWorldsNotFound(home));
listener.error("classworld not found");
throw new RunnerAbortedException();
}
listener.error(Messages.MavenProcessFactory_ClassWorldsNotFound(home));
throw new RunnerAbortedException();
}
return classworlds[0].getAbsolutePath();
}
......
......@@ -83,12 +83,6 @@ public abstract class MavenBuilder extends AbstractMavenBuilder implements Deleg
*/
private final boolean profile = MavenProcessFactory.profile;
/**
* Record all asynchronous executions as they are scheduled,
* to make sure they are all completed before we finish.
*/
protected transient /*final*/ List<Future<?>> futures;
protected MavenBuilder(BuildListener listener, List<String> goals, Map<String, String> systemProps) {
super( listener, goals, systemProps );
}
......
......@@ -29,7 +29,6 @@ import hudson.AbortException;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.FilePath.FileCallable;
import hudson.Launcher;
import hudson.Util;
import hudson.maven.MavenBuild.ProxyImpl2;
import hudson.maven.reporters.MavenAggregatedArtifactRecord;
......@@ -54,7 +53,6 @@ import hudson.model.Result;
import hudson.model.Run;
import hudson.model.StringParameterDefinition;
import hudson.model.TaskListener;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
import hudson.scm.ChangeLogSet;
import hudson.tasks.BuildStep;
......@@ -63,14 +61,12 @@ import hudson.tasks.MailSender;
import hudson.tasks.Maven.MavenInstallation;
import hudson.util.ArgumentListBuilder;
import hudson.util.IOUtils;
import hudson.util.MaskingClassLoader;
import hudson.util.StreamTaskListener;
import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.PrintStream;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
......@@ -90,13 +86,8 @@ import jenkins.model.Jenkins;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.BuildFailureException;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.execution.ReactorManager;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.monitor.event.EventDispatcher;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.codehaus.plexus.util.PathTool;
......@@ -775,8 +766,8 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
} else {
Builder builder =
new Builder(slistener, proxies, project.sortedActiveModules, margs.toList(), envVars, mavenBuildInformation);
Maven2Builder builder =
new Maven2Builder(slistener, proxies, project.sortedActiveModules, margs.toList(), envVars, mavenBuildInformation);
MavenProbeAction mpa=null;
try {
mpa = new MavenProbeAction(project,process.channel);
......@@ -1015,184 +1006,6 @@ public class MavenModuleSetBuild extends AbstractMavenBuild<MavenModuleSet,Maven
}
/**
* Runs Maven and builds the project.
*
* This is only used for
* {@link MavenModuleSet#isAggregatorStyleBuild() the aggregator style build}.
*/
private static final class Builder extends MavenBuilder {
private final Map<ModuleName,MavenBuildProxy2> proxies;
private final Map<ModuleName,List<MavenReporter>> reporters = new HashMap<ModuleName,List<MavenReporter>>();
private final Map<ModuleName,List<ExecutedMojo>> executedMojos = new HashMap<ModuleName,List<ExecutedMojo>>();
private long mojoStartTime;
private MavenBuildProxy2 lastProxy;
/**
* Kept so that we can finalize them in the end method.
*/
private final transient Map<ModuleName,ProxyImpl2> sourceProxies;
public Builder(BuildListener listener,Map<ModuleName,ProxyImpl2> proxies, Collection<MavenModule> modules, List<String> goals, Map<String,String> systemProps, MavenBuildInformation mavenBuildInformation) {
super(listener,goals,systemProps);
this.sourceProxies = proxies;
this.proxies = new HashMap<ModuleName, MavenBuildProxy2>(proxies);
for (Entry<ModuleName,MavenBuildProxy2> e : this.proxies.entrySet())
e.setValue(new FilterImpl(e.getValue(), mavenBuildInformation));
for (MavenModule m : modules)
reporters.put(m.getModuleName(),m.createReporters());
}
private class FilterImpl extends MavenBuildProxy2.Filter<MavenBuildProxy2> implements Serializable {
private MavenBuildInformation mavenBuildInformation;
public FilterImpl(MavenBuildProxy2 core, MavenBuildInformation mavenBuildInformation) {
super(core);
this.mavenBuildInformation = mavenBuildInformation;
}
@Override
public void executeAsync(final BuildCallable<?,?> program) throws IOException {
futures.add(Channel.current().callAsync(new AsyncInvoker(core,program)));
}
public MavenBuildInformation getMavenBuildInformation() {
return mavenBuildInformation;
}
private static final long serialVersionUID = 1L;
}
/**
* Invoked after the maven has finished running, and in the master, not in the maven process.
*/
void end(Launcher launcher) throws IOException, InterruptedException {
for (Map.Entry<ModuleName,ProxyImpl2> e : sourceProxies.entrySet()) {
ProxyImpl2 p = e.getValue();
for (MavenReporter r : reporters.get(e.getKey())) {
// we'd love to do this when the module build ends, but doing so requires
// we know how many task segments are in the current build.
r.end(p.owner(),launcher,listener);
p.appendLastLog();
}
p.close();
}
}
@Override
public Result call() throws IOException {
try {
if (debug) {
listener.getLogger().println("Builder extends MavenBuilder in call " + Thread.currentThread().getContextClassLoader());
}
return super.call();
} finally {
if(lastProxy!=null)
lastProxy.appendLastLog();
}
}
@Override
void preBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException {
// set all modules which are not actually being build (in incremental builds) to NOT_BUILD
List<MavenProject> projects = rm.getSortedProjects();
Set<ModuleName> buildingProjects = new HashSet<ModuleName>();
for (MavenProject p : projects) {
buildingProjects.add(new ModuleName(p));
}
for (Entry<ModuleName,MavenBuildProxy2> e : this.proxies.entrySet()) {
if (! buildingProjects.contains(e.getKey())) {
MavenBuildProxy2 proxy = e.getValue();
proxy.start();
proxy.setResult(Result.NOT_BUILT);
proxy.end();
}
}
}
void postBuild(MavenSession session, ReactorManager rm, EventDispatcher dispatcher) throws BuildFailureException, LifecycleExecutionException, IOException, InterruptedException {
// TODO
}
void preModule(MavenProject project) throws InterruptedException, IOException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy2 proxy = proxies.get(name);
listener.getLogger().flush(); // make sure the data until here are all written
proxy.start();
for (MavenReporter r : reporters.get(name))
if(!r.preBuild(proxy,project,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
}
void postModule(MavenProject project) throws InterruptedException, IOException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy2 proxy = proxies.get(name);
List<MavenReporter> rs = reporters.get(name);
if(rs==null) { // probe for issue #906
throw new AssertionError("reporters.get("+name+")==null. reporters="+reporters+" proxies="+proxies);
}
for (MavenReporter r : rs)
if(!r.postBuild(proxy,project,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
proxy.setExecutedMojos(executedMojos.get(name));
listener.getLogger().flush(); // make sure the data until here are all written
proxy.end();
lastProxy = proxy;
}
void preExecute(MavenProject project, MojoInfo mojoInfo) throws IOException, InterruptedException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy proxy = proxies.get(name);
for (MavenReporter r : reporters.get(name))
if(!r.preExecute(proxy,project,mojoInfo,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
mojoStartTime = System.currentTimeMillis();
}
void postExecute(MavenProject project, MojoInfo mojoInfo, Exception exception) throws IOException, InterruptedException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
List<ExecutedMojo> mojoList = executedMojos.get(name);
if(mojoList==null)
executedMojos.put(name,mojoList=new ArrayList<ExecutedMojo>());
mojoList.add(new ExecutedMojo(mojoInfo,System.currentTimeMillis()-mojoStartTime));
MavenBuildProxy2 proxy = proxies.get(name);
for (MavenReporter r : reporters.get(name))
if(!r.postExecute(proxy,project,mojoInfo,listener,exception))
throw new hudson.maven.agent.AbortException(r+" failed");
if(exception!=null)
proxy.setResult(Result.FAILURE);
}
void onReportGenerated(MavenProject project, MavenReportInfo report) throws IOException, InterruptedException, hudson.maven.agent.AbortException {
ModuleName name = new ModuleName(project);
MavenBuildProxy proxy = proxies.get(name);
for (MavenReporter r : reporters.get(name))
if(!r.reportGenerated(proxy,project,report,listener))
throw new hudson.maven.agent.AbortException(r+" failed");
}
private static final long serialVersionUID = 1L;
@Override
public ClassLoader getClassLoader()
{
return new MaskingClassLoader( super.getClassLoader() );
}
}
/**
* Used to tunnel exception from Maven through remoting.
*/
......
......@@ -29,14 +29,11 @@ import hudson.EnvVars;
import hudson.maven.agent.Main;
import hudson.maven.agent.Maven21Interceptor;
import hudson.model.BuildListener;
import jenkins.model.Jenkins;
import hudson.model.JDK;
import hudson.model.Run.RunnerAbortedException;
import hudson.model.TaskListener;
import hudson.remoting.Callable;
import hudson.remoting.Which;
import hudson.tasks.Maven.MavenInstallation;
import hudson.util.ArgumentListBuilder;
import java.io.File;
import java.io.FilenameFilter;
......@@ -55,88 +52,39 @@ final class MavenProcessFactory extends AbstractMavenProcessFactory implements P
super( mms, launcher, envVars, mavenOpts, workDir );
}
/**
* Builds the command line argument list to launch the maven process.
*
* UGLY.
*/
protected ArgumentListBuilder buildMavenAgentCmdLine(BuildListener listener,int tcpPort) throws IOException, InterruptedException {
MavenInstallation mvn = getMavenInstallation(listener);
if(mvn==null) {
listener.error("Maven version is not configured for this project. Can't determine which Maven to run");
throw new RunnerAbortedException();
}
if(mvn.getHome()==null) {
listener.error("Maven '%s' doesn't have its home set",mvn.getName());
throw new RunnerAbortedException();
}
// find classworlds.jar
@Override
protected String getMavenAgentClassPath(MavenInstallation mvn,boolean isMaster,FilePath slaveRoot,BuildListener listener) throws IOException, InterruptedException {
String classWorldsJar = getLauncher().getChannel().call(new GetClassWorldsJar(mvn.getHome(),listener));
boolean isMaster = getCurrentNode()== Jenkins.getInstance();
FilePath slaveRoot=null;
if(!isMaster)
slaveRoot = getCurrentNode().getRootPath();
ArgumentListBuilder args = new ArgumentListBuilder();
JDK jdk = getJava(listener);
if(jdk==null) {
args.add("java");
} else {
args.add(jdk.getHome()+"/bin/java"); // use JDK.getExecutable() here ?
}
if(debugPort!=0)
args.add("-Xrunjdwp:transport=dt_socket,server=y,address="+debugPort);
if(yjp)
args.add("-agentlib:yjpagent=tracing");
args.addTokenized(getMavenOpts());
args.add( "-cp" );
String classPath =
( isMaster ? Which.jarFile( Main.class ).getAbsolutePath()
: slaveRoot.child( "maven-agent.jar" ).getRemote() )
+ ( getLauncher().isUnix() ? ":" : ";" )
+ ( isMaster ? classWorldsJar : slaveRoot.child( "classworlds.jar" ).getRemote() );
args.add( classPath );
//+classWorldsJar);
args.add(Main.class.getName());
// M2_HOME
args.add(mvn.getHome());
// remoting.jar
String remotingJar = getLauncher().getChannel().call(new GetRemotingJar());
if(remotingJar==null) {// this shouldn't be possible, but there are still reports indicating this, so adding a probe here.
listener.error("Failed to determine the location of slave.jar");
throw new RunnerAbortedException();
}
args.add(remotingJar);
// interceptor.jar
args.add(isMaster?
Which.jarFile(hudson.maven.agent.AbortException.class).getAbsolutePath():
slaveRoot.child("maven-interceptor.jar").getRemote());
// TCP/IP port to establish the remoting infrastructure
args.add(tcpPort);
return classPath;
}
protected String getMainClassName() {
return Main.class.getName();
}
// if this is Maven 2.1, interceptor override
@Override
protected String getMavenInterceptorClassPath(MavenInstallation mvn,boolean isMaster,FilePath slaveRoot) throws IOException, InterruptedException {
if(mvn.isMaven2_1(getLauncher())) {
args.add(isMaster?
return isMaster?
Which.jarFile(Maven21Interceptor.class).getAbsolutePath():
slaveRoot.child("maven2.1-interceptor.jar").getRemote());
slaveRoot.child("maven2.1-interceptor.jar").getRemote();
} else {
return isMaster?
Which.jarFile(hudson.maven.agent.AbortException.class).getAbsolutePath():
slaveRoot.child("maven-interceptor.jar").getRemote();
}
return args;
}
/**
* Finds classworlds.jar
*/
private static final class GetClassWorldsJar implements Callable<String,IOException> {
private static final long serialVersionUID = 5812919424079344101L;
private final String mvnHome;
private final TaskListener listener;
......@@ -193,23 +141,7 @@ final class MavenProcessFactory extends AbstractMavenProcessFactory implements P
*/
public static boolean debug = false;
/**
* If not 0, launch Maven with a debugger port.
*/
public static int debugPort;
public static boolean profile = Boolean.getBoolean("hudson.maven.profile");
/**
* If true, launch Maven with YJP offline profiler agent.
*/
public static boolean yjp = Boolean.getBoolean("hudson.maven.yjp");
static {
String port = System.getProperty("hudson.maven.debugPort");
if(port!=null)
debugPort = Integer.parseInt(port);
}
public static int socketTimeOut = Integer.parseInt( System.getProperty( "hudson.maven.socketTimeOut", Integer.toString( 30*1000 ) ) );
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册