提交 2d8aa916 编写于 作者: K kohsuke

modified to use maven-agent to launch M2 outside Hudson JVM.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@2294 71c3de6d-444a-0410-be80-ed276b4c234a
上级 5ae92ea0
......@@ -213,6 +213,11 @@
<artifactId>svnkit</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>${groupId}</groupId>
<artifactId>maven-agent</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>net.sf.retrotranslator</groupId>
<artifactId>retrotranslator-runtime</artifactId>
......
......@@ -2,8 +2,11 @@ package hudson;
import hudson.model.Hudson;
import hudson.model.TaskListener;
import hudson.model.Computer;
import hudson.remoting.VirtualChannel;
import hudson.remoting.Channel;
import hudson.Proc.LocalProc;
import hudson.util.StreamCopyThread;
import java.io.File;
import java.io.IOException;
......@@ -89,6 +92,15 @@ public abstract class Launcher {
*/
public abstract Proc launch(String[] cmd,String[] env,InputStream in,OutputStream out, FilePath workDir) throws IOException;
/**
* Launches a specified process and connects its input/output to a {@link Channel}, then
* return it.
*
* @param out
* The stderr from the launched process will be sent to this stream.
*/
public abstract Channel launchChannel(String[] cmd, String[] env, OutputStream out, FilePath workDir) throws IOException;
/**
* Returns true if this {@link Launcher} is going to launch on Unix.
*/
......@@ -127,7 +139,25 @@ public abstract class Launcher {
public Proc launch(String[] cmd,String[] env,InputStream in,OutputStream out, FilePath workDir) throws IOException {
printCommandLine(cmd, workDir);
return new LocalProc(cmd,Util.mapToEnv(inherit(env)),in,out, workDir==null ? null : new File(workDir.getRemote()));
return new LocalProc(cmd,Util.mapToEnv(inherit(env)),in,out, toFile(workDir));
}
private File toFile(FilePath f) {
return f==null ? null : new File(f.getRemote());
}
public Channel launchChannel(String[] cmd, String[] env, OutputStream out, FilePath workDir) throws IOException {
printCommandLine(cmd, workDir);
Process proc = Runtime.getRuntime().exec(cmd, env, toFile(workDir));
// TODO: don't we need the equivalent of 'Proc' here? to abort it
Thread t2 = new StreamCopyThread(cmd+": stderr copier", proc.getErrorStream(), out);
t2.start();
return new Channel("locally launched channel on "+cmd,
Computer.threadPoolForRemoting, proc.getInputStream(), proc.getOutputStream(), out);
}
/**
......
......@@ -2,8 +2,7 @@ package hudson.maven;
import hudson.FilePath;
import hudson.Util;
import hudson.FilePath.FileCallable;
import hudson.maven.PluginManagerInterceptor.AbortException;
import hudson.maven.agent.Main;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
......@@ -11,28 +10,23 @@ import hudson.model.DependencyGraph;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.model.Run;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
import hudson.remoting.Launcher;
import hudson.remoting.Which;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
import hudson.tasks.Maven.MavenInstallation;
import hudson.tasks.test.AbstractTestResultAction;
import hudson.util.ArgumentListBuilder;
import org.apache.maven.BuildFailureException;
import org.apache.maven.embedder.MavenEmbedderException;
import org.apache.maven.embedder.PlexusLoggerAdapter;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.monitor.event.DefaultEventMonitor;
import org.apache.maven.monitor.event.EventMonitor;
import org.apache.maven.plugin.PluginManager;
import org.apache.maven.project.DuplicateProjectException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.util.dag.CycleDetectedException;
import hudson.util.IOException2;
import org.codehaus.classworlds.NoSuchRealmException;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
......@@ -108,7 +102,7 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
*
* This code is executed on the remote machine.
*/
private static final class Builder implements FileCallable<Result> {
private static final class Builder implements Callable<Result,IOException> {
private final BuildListener listener;
private final MavenBuildProxy buildProxy;
private final MavenReporter[] reporters;
......@@ -121,73 +115,86 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
this.goals = goals;
}
public Result invoke(File moduleRoot, VirtualChannel channel) throws IOException {
MavenProject p=null;
public Result call() throws IOException {
try {
MavenEmbedder embedder = MavenUtil.createEmbedder(listener);
File pom = new File(moduleRoot,"pom.xml").getAbsoluteFile(); // MavenEmbedder only works if it's absolute
if(!pom.exists()) {
listener.error("No POM: "+pom);
return Result.FAILURE;
}
// event monitor is mostly useless. It only provides a few strings
EventMonitor eventMonitor = new DefaultEventMonitor( new PlexusLoggerAdapter( new EmbedderLoggerImpl(listener) ) );
p = embedder.readProject(pom);
PluginManagerInterceptor interceptor;
try {
interceptor = (PluginManagerInterceptor)embedder.getContainer().lookup(PluginManager.class.getName());
interceptor.setBuilder(buildProxy,reporters,listener);
} catch (ComponentLookupException e) {
throw new Error(e); // impossible
}
for (MavenReporter r : reporters)
r.preBuild(buildProxy,p,listener);
embedder.execute(p, goals, eventMonitor,
new TransferListenerImpl(listener),
null, // TODO: allow additional properties to be specified
pom.getParentFile());
interceptor.fireLeaveModule();
return null;
} catch (MavenEmbedderException e) {
buildProxy.setResult(Result.FAILURE);
e.printStackTrace(listener.error(e.getMessage()));
} catch (ProjectBuildingException e) {
buildProxy.setResult(Result.FAILURE);
e.printStackTrace(listener.error(e.getMessage()));
} catch (CycleDetectedException e) {
buildProxy.setResult(Result.FAILURE);
e.printStackTrace(listener.error(e.getMessage()));
} catch (LifecycleExecutionException e) {
buildProxy.setResult(Result.FAILURE);
e.printStackTrace(listener.error(e.getMessage()));
} catch (BuildFailureException e) {
buildProxy.setResult(Result.FAILURE);
e.printStackTrace(listener.error(e.getMessage()));
} catch (DuplicateProjectException e) {
buildProxy.setResult(Result.FAILURE);
e.printStackTrace(listener.error(e.getMessage()));
} catch (AbortException e) {
listener.error("build aborted");
} catch (InterruptedException e) {
listener.error("build aborted");
} finally {
// this should happen after a build is marked as a failure
try {
if(p!=null)
for (MavenReporter r : reporters)
r.postBuild(buildProxy,p,listener);
} catch (InterruptedException e) {
buildProxy.setResult(Result.FAILURE);
}
int r = Main.launch(goals.toArray(new String[goals.size()]));
return r==0 ? Result.SUCCESS : Result.FAILURE;
} catch (NoSuchMethodException e) {
throw new IOException2(e);
} catch (IllegalAccessException e) {
throw new IOException2(e);
} catch (NoSuchRealmException e) {
throw new IOException2(e);
} catch (InvocationTargetException e) {
throw new IOException2(e);
} catch (ClassNotFoundException e) {
throw new IOException2(e);
}
return Result.FAILURE;
//MavenProject p=null;
//try {
// MavenEmbedder embedder = MavenUtil.createEmbedder(listener);
// File pom = new File("pom.xml").getAbsoluteFile(); // MavenEmbedder only works if it's absolute
// if(!pom.exists()) {
// listener.error("No POM: "+pom);
// return Result.FAILURE;
// }
//
// // event monitor is mostly useless. It only provides a few strings
// EventMonitor eventMonitor = new DefaultEventMonitor( new PlexusLoggerAdapter( new EmbedderLoggerImpl(listener) ) );
//
// p = embedder.readProject(pom);
// PluginManagerInterceptor interceptor;
//
// try {
// interceptor = (PluginManagerInterceptor)embedder.getContainer().lookup(PluginManager.class.getName());
// interceptor.setBuilder(buildProxy,reporters,listener);
// } catch (ComponentLookupException e) {
// throw new Error(e); // impossible
// }
//
// for (MavenReporter r : reporters)
// r.preBuild(buildProxy,p,listener);
//
// embedder.execute(p, goals, eventMonitor,
// new TransferListenerImpl(listener),
// null, // TODO: allow additional properties to be specified
// pom.getParentFile());
//
// interceptor.fireLeaveModule();
//
// return null;
//} catch (MavenEmbedderException e) {
// buildProxy.setResult(Result.FAILURE);
// e.printStackTrace(listener.error(e.getMessage()));
//} catch (ProjectBuildingException e) {
// buildProxy.setResult(Result.FAILURE);
// e.printStackTrace(listener.error(e.getMessage()));
//} catch (CycleDetectedException e) {
// buildProxy.setResult(Result.FAILURE);
// e.printStackTrace(listener.error(e.getMessage()));
//} catch (LifecycleExecutionException e) {
// buildProxy.setResult(Result.FAILURE);
// e.printStackTrace(listener.error(e.getMessage()));
//} catch (BuildFailureException e) {
// buildProxy.setResult(Result.FAILURE);
// e.printStackTrace(listener.error(e.getMessage()));
//} catch (DuplicateProjectException e) {
// buildProxy.setResult(Result.FAILURE);
// e.printStackTrace(listener.error(e.getMessage()));
//} catch (AbortException e) {
// listener.error("build aborted");
//} catch (InterruptedException e) {
// listener.error("build aborted");
//} finally {
// // this should happen after a build is marked as a failure
// try {
// if(p!=null)
// for (MavenReporter r : reporters)
// r.postBuild(buildProxy,p,listener);
// } catch (InterruptedException e) {
// buildProxy.setResult(Result.FAILURE);
// }
//}
}
}
......@@ -224,6 +231,12 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
}
}
private static final class getJavaExe implements Callable<String,IOException> {
public String call() throws IOException {
return new File(new File(System.getProperty("java.home")),"bin/java").getPath();
}
}
private class RunnerImpl extends AbstractRunner {
protected Result doRun(BuildListener listener) throws Exception {
// pick up a list of reporters to run
......@@ -237,12 +250,57 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
reporters.add(auto);
}
ArgumentListBuilder args = new ArgumentListBuilder();
args.addTokenized(getProject().getGoals());
// start maven process
ArgumentListBuilder args = buildMavenCmdLine();
Channel channel = launcher.launchChannel(args.toCommandArray(), new String[0],
listener.getLogger(), getProject().getModuleRoot());
return getProject().getModuleRoot().act(new Builder(
listener,new ProxyImpl(),
reporters.toArray(new MavenReporter[0]), args.toList()));
// Maven started.
ArgumentListBuilder margs = new ArgumentListBuilder();
margs.add("-N");
margs.addTokenized(getProject().getGoals());
try {
return channel.call(new Builder(
listener,new ProxyImpl(),
reporters.toArray(new MavenReporter[0]), margs.toList()));
} finally {
channel.close();
}
}
private ArgumentListBuilder buildMavenCmdLine() throws IOException, InterruptedException {
MavenInstallation mvn = getParent().getParent().getMaven();
// find classworlds.jar
File bootDir = new File(mvn.getHomeDir(), "core/boot");
File[] classworlds = bootDir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("classworlds") && name.endsWith(".jar");
}
});
if(classworlds==null || classworlds.length==0)
throw new IOException("No classworlds*.jar found in "+bootDir);
ArgumentListBuilder args = new ArgumentListBuilder();
args.add(launcher.getChannel().call(new getJavaExe()));
args.add("-cp");
args.add(Which.jarFile(Main.class)+
(launcher.isUnix()?":":";")+
classworlds[0].getAbsolutePath()); // TODO locate Main.jar
args.add(Main.class.getName());
// M2_HOME
args.add(mvn.getMavenHome());
// remoting.jar
args.add(Which.jarFile(Launcher.class).getPath());
// interceptor.jar
args.add(Which.jarFile(hudson.maven.agent.PluginManagerInterceptor.class).getPath()); // TODO
return args;
}
public void post(BuildListener listener) {
......
......@@ -2,6 +2,8 @@ package hudson.maven;
import hudson.FilePath;
import hudson.Util;
import hudson.tasks.Maven;
import hudson.tasks.Maven.MavenInstallation;
import hudson.model.AbstractProject;
import hudson.model.DependencyGraph;
import hudson.model.Executor;
......@@ -59,6 +61,12 @@ public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenMo
*/
private String defaultGoals;
/**
* Identifies {@link MavenInstallation} to be used.
* Null to indicate 'default' maven.
*/
private String mavenName;
public MavenModuleSet(String name) {
super(Hudson.getInstance(),name);
}
......@@ -236,6 +244,18 @@ public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenMo
return goals;
}
/**
* Gets the Maven to invoke.
* If null, we pick any random Maven installation.
*/
public MavenInstallation getMaven() {
for( MavenInstallation i : DESCRIPTOR.getMavenDescriptor().getInstallations() ) {
if(mavenName==null || i.getName().equals(mavenName))
return i;
}
return null;
}
/**
* Gets the list of goals specified by the user,
* without taking inheritance and POM default goals
......@@ -271,6 +291,7 @@ public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenMo
if(rootPOM.equals("pom.xml")) rootPOM=null; // normalization
goals = Util.fixEmpty(req.getParameter("goals").trim());
mavenName = req.getParameter("maven_version");
super.doConfigSubmit(req,rsp);
......@@ -281,7 +302,7 @@ public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenMo
return DESCRIPTOR;
}
public static final TopLevelItemDescriptor DESCRIPTOR = new DescriptorImpl();
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends TopLevelItemDescriptor {
private DescriptorImpl() {
......@@ -295,6 +316,10 @@ public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenMo
public MavenModuleSet newInstance(String name) {
return new MavenModuleSet(name);
}
public Maven.DescriptorImpl getMavenDescriptor() {
return Maven.DESCRIPTOR;
}
}
private static final Logger LOGGER = Logger.getLogger(MavenModuleSet.class.getName());
......
......@@ -29,11 +29,6 @@ class MavenUtil {
ClassLoader cl = MavenUtil.class.getClassLoader();
maven.setClassLoader(new MaskingClassLoader(cl));
maven.setLogger( new EmbedderLoggerImpl(listener) );
// if we let Plexus find components, there's no guaranteed ordering,
// so Plexus may well find the DefaultPluginManager from maven.jar instead of
// our override. So use this mechanism to make sure ours are loaded first
// before Plexus goes service loader discovery.
maven.setOverridingComponentsXml(cl.getResource("META-INF/plexus/hudson-components.xml"));
maven.start();
......
package hudson.maven;
import org.apache.maven.plugin.DefaultPluginManager;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.PluginManagerException;
import org.apache.maven.plugin.PluginConfigurationException;
import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException;
import hudson.model.BuildListener;
import hudson.maven.agent.PluginManagerListener;
import hudson.maven.agent.AbortException;
/**
* Description in META-INF/plexus/components.xml makes it possible to use this instead of the default
......@@ -31,9 +17,7 @@ import hudson.model.BuildListener;
*
* @author Kohsuke Kawaguchi
*/
public class PluginManagerInterceptor extends DefaultPluginManager {
private final Method mergeMojoConfiguration;
public class PluginManagerInterceptor implements PluginManagerListener {
private MavenBuildProxy buildProxy;
private MavenReporter[] reporters;
......@@ -44,18 +28,6 @@ public class PluginManagerInterceptor extends DefaultPluginManager {
*/
private MavenProject lastModule;
public PluginManagerInterceptor() {
try {
this.mergeMojoConfiguration = DefaultPluginManager.class.getDeclaredMethod(
"mergeMojoConfiguration", XmlPlexusConfiguration.class,MojoDescriptor.class);
mergeMojoConfiguration.setAccessible(true);
} catch (NoSuchMethodException e) {
NoSuchMethodError x = new NoSuchMethodError("Unable to find DefaultPluginManager.mergeMojoConfiguration()");
x.initCause(e);
throw x;
}
}
/**
* Called by {@link MavenBuild} to connect this object to the rest of Hudson objects,
* namely {@link MavenBuild}.
......@@ -70,64 +42,27 @@ public class PluginManagerInterceptor extends DefaultPluginManager {
this.listener = listener;
}
public void executeMojo(MavenProject project, MojoExecution mojoExecution, MavenSession session) throws ArtifactResolutionException, MojoExecutionException, MojoFailureException, ArtifactNotFoundException, InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException {
Xpp3Dom dom = getConfigDom(mojoExecution, project);
XmlPlexusConfiguration pomConfiguration;
if ( dom == null )
{
pomConfiguration = new XmlPlexusConfiguration( "configuration" );
}
else
{
pomConfiguration = new XmlPlexusConfiguration( dom );
public void preExecute(MavenProject project, MojoExecution exec, PlexusConfiguration mergedConfig, ExpressionEvaluator eval) throws IOException, InterruptedException, AbortException {
if(lastModule!=project) {
// module change
fireLeaveModule();
fireEnterModule(project);
}
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PlexusConfiguration mergedConfiguration;
try {
mergedConfiguration = (PlexusConfiguration) mergeMojoConfiguration.invoke(this, pomConfiguration, mojoDescriptor );
} catch (IllegalAccessException e) {
IllegalAccessError x = new IllegalAccessError();
x.initCause(e);
throw x;
} catch (InvocationTargetException e) {
throw new MojoExecutionException("Failed to check configuration",e);
}
// this just seems like an error check
//PlexusConfiguration extractedMojoConfiguration =
// extractMojoConfiguration( mergedConfiguration, mojoDescriptor ); // what does this do?
ExpressionEvaluator eval = new PluginParameterExpressionEvaluator( session, mojoExecution,
pathTranslator, getLogger(),
project,
session.getExecutionProperties() );
try {
if(lastModule!=project) {
// module change
fireLeaveModule();
fireEnterModule(project);
}
MojoInfo info = new MojoInfo(exec, mergedConfig, eval);
for (MavenReporter r : reporters)
if(!r.preExecute(buildProxy,project,info,listener))
throw new AbortException(r+" failed");
}
MojoInfo info = new MojoInfo(mojoExecution, mergedConfiguration, eval);
for (MavenReporter r : reporters)
if(!r.preExecute(buildProxy,project,info,listener))
throw new AbortException(r+" failed");
public void postExecute(MavenProject project, MojoExecution exec, PlexusConfiguration mergedConfig, ExpressionEvaluator eval) throws IOException, InterruptedException, AbortException {
MojoInfo info = new MojoInfo(exec, mergedConfig, eval);
super.executeMojo(project, mojoExecution, session);
for (MavenReporter r : reporters)
if(!r.postExecute(buildProxy,project, info,listener))
throw new AbortException(r+" failed");
} catch (InterruptedException e) {
// orderly abort
throw new AbortException("Execution aborted",e);
} catch (IOException e) {
throw new PluginManagerException(e.getMessage(),e);
}
for (MavenReporter r : reporters)
if(!r.postExecute(buildProxy,project, info,listener))
throw new AbortException(r+" failed");
}
private void fireEnterModule(MavenProject project) throws InterruptedException, IOException, AbortException {
lastModule = project;
for (MavenReporter r : reporters)
......@@ -135,42 +70,11 @@ public class PluginManagerInterceptor extends DefaultPluginManager {
throw new AbortException(r+" failed");
}
/*package*/ void fireLeaveModule() throws InterruptedException, IOException, AbortException {
private void fireLeaveModule() throws InterruptedException, IOException, AbortException {
if(lastModule!=null) {
for (MavenReporter r : reporters)
if(!r.leaveModule(buildProxy,lastModule,listener))
throw new AbortException(r+" failed");
}
}
private Xpp3Dom getConfigDom(MojoExecution mojoExecution, MavenProject project) {
MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
String goalId = mojoDescriptor.getGoal();
String groupId = pluginDescriptor.getGroupId();
String artifactId = pluginDescriptor.getArtifactId();
String executionId = mojoExecution.getExecutionId();
Xpp3Dom dom = project.getGoalConfiguration( groupId, artifactId, executionId, goalId );
Xpp3Dom reportDom = project.getReportConfiguration( groupId, artifactId, executionId );
dom = Xpp3Dom.mergeXpp3Dom( dom, reportDom );
if ( mojoExecution.getConfiguration() != null )
{
dom = Xpp3Dom.mergeXpp3Dom( dom, mojoExecution.getConfiguration() );
}
return dom;
}
/**
* Thrown when {@link MavenReporter} returned false to orderly
* abort the execution. The caller shouldn't dump the stack trace for
* this exception.
*/
public final class AbortException extends PluginManagerException {
public AbortException(String message) {
super(message);
}
public AbortException(String message, Exception e) {
super(message, e);
}
}
}
......@@ -261,7 +261,7 @@ public abstract class Computer implements ModelObject {
}
protected static final ExecutorService threadPoolForRemoting = Executors.newCachedThreadPool(new DaemonThreadFactory());
public static final ExecutorService threadPoolForRemoting = Executors.newCachedThreadPool(new DaemonThreadFactory());
//
//
......
......@@ -14,6 +14,7 @@ import hudson.remoting.Channel.Listener;
import hudson.remoting.RemoteInputStream;
import hudson.remoting.RemoteOutputStream;
import hudson.remoting.VirtualChannel;
import hudson.remoting.Pipe;
import hudson.util.NullStream;
import hudson.util.StreamCopyThread;
import hudson.util.StreamTaskListener;
......@@ -398,6 +399,19 @@ public final class Slave implements Node, Serializable {
return new RemoteProc(getChannel().callAsync(new RemoteLaunchCallable(cmd, env, in, out, workDir)));
}
public Channel launchChannel(String[] cmd, String[] env, OutputStream err, FilePath _workDir) throws IOException {
printCommandLine(cmd, _workDir);
Pipe in = Pipe.createLocalToRemote();
Pipe out = Pipe.createRemoteToLocal();
final String workDir = _workDir==null ? null : _workDir.getRemote();
getChannel().callAsync(new RemoteChannelLaunchCallable(cmd, env, in, out, workDir));
return new Channel("remotely launched channel on "+getNodeName(),
Computer.threadPoolForRemoting, out.getIn(), in.getOut());
}
@Override
public boolean isUnix() {
// Windows can handle '/' as a path separator but Unix can't,
......@@ -482,4 +496,28 @@ public final class Slave implements Node, Serializable {
private static final long serialVersionUID = 1L;
}
private static class RemoteChannelLaunchCallable implements Callable<Integer,IOException> {
private final String[] cmd;
private final String[] env;
private final Pipe in;
private final Pipe out;
private final String workDir;
public RemoteChannelLaunchCallable(String[] cmd, String[] env, Pipe in, Pipe out, String workDir) {
this.cmd = cmd;
this.env = env;
this.in = in;
this.out = out;
this.workDir = workDir;
}
public Integer call() throws IOException {
Proc p = new LocalLauncher(TaskListener.NULL).launch(cmd, env, in.getIn(), out.getOut(),
workDir ==null ? null : new FilePath(new File(workDir)));
return p.join();
}
private static final long serialVersionUID = 1L;
}
}
......@@ -251,6 +251,10 @@ public class Maven extends Builder {
return mavenHome;
}
public File getHomeDir() {
return new File(mavenHome);
}
/**
* Human readable display name.
*/
......
<!--
This file is used by MavenBuild to replace Maven's default PluginManager with ours
that allow interception.
-->
<component-set>
<components>
<component>
<role>org.apache.maven.plugin.PluginManager</role>
<implementation>hudson.maven.PluginManagerInterceptor</implementation>
<requirements>
<requirement>
<role>org.apache.maven.project.path.PathTranslator</role>
</requirement>
<requirement>
<role>org.apache.maven.plugin.MavenPluginCollector</role>
</requirement>
<requirement>
<role>org.apache.maven.plugin.version.PluginVersionManager</role>
</requirement>
<requirement>
<role>org.apache.maven.artifact.factory.ArtifactFactory</role>
</requirement>
<requirement>
<role>org.apache.maven.artifact.resolver.ArtifactResolver</role>
</requirement>
<requirement>
<role>org.apache.maven.artifact.metadata.ArtifactMetadataSource</role>
</requirement>
<requirement>
<role>org.apache.maven.plugin.PluginMappingManager</role>
</requirement>
<requirement>
<role>org.apache.maven.execution.RuntimeInformation</role>
</requirement>
<requirement>
<role>org.apache.maven.project.MavenProjectBuilder</role>
</requirement>
</requirements>
</component>
</components>
</component-set>
......@@ -23,7 +23,15 @@
</f:triggerDescriptorList>
<f:section title="Build">
<f:entry title="root POM" help="/help/maven/root-pom.html">
<f:entry title="Maven Version">
<select class="setting-input" name="maven_version">
<option>(Default)</option>
<j:forEach var="inst" items="${it.descriptor.mavenDescriptor.mavenInstallations}">
<f:option selected="${inst.name==instance.maven.name}">${inst.name}</f:option>
</j:forEach>
</select>
</f:entry>
<f:entry title="Root POM" help="/help/maven/root-pom.html">
<f:textbox name="rootPOM" value="${it.rootPOM}"/>
</f:entry>
<f:entry title="Goals" help="/help/maven/goals.html">
......
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.jvnet.hudson.main</groupId>
<artifactId>pom</artifactId>
<version>1.83-SNAPSHOT</version>
<version>1.85-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -10,12 +10,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URI;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
......@@ -30,6 +24,8 @@ public class LaunchTest extends TestCase {
//args.add("-Xrunjdwp:transport=dt_socket,server=y,address=8000");
System.out.println(Channel.class);
args.add("-cp");
args.add(Which.jarFile(Main.class)+File.pathSeparator+Which.jarFile(ClassWorld.class));
args.add(Main.class.getName());
......
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.jvnet.hudson.main</groupId>
<artifactId>pom</artifactId>
<version>1.83-SNAPSHOT</version>
<version>1.85-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -19,6 +19,8 @@
<module>remoting</module>
<module>core</module>
<module>jnlp-agent</module>
<module>maven-agent</module>
<module>maven-interceptor</module>
<module>war</module>
</modules>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册