From 495d97dd5f8ee1066bc3c9b1f87a4688a8b12c71 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 25 Jun 2013 15:07:07 -0700 Subject: [PATCH] Based on further conversation with the Artifactory plugin developers, revisiting this extension point. This is a breaking change, but this extension point was added very recently, and it's based on the input from Artifactory plugin, so there's not much point in keeping one that doesn't serve the intended use case. --- changelog.html | 2 + .../maven/AbstractMavenProcessFactory.java | 16 +++-- .../hudson/maven/Maven3ProcessFactory.java | 18 +++-- .../main/java/hudson/maven/MavenBuild.java | 4 +- .../hudson/maven/MavenModuleSetBuild.java | 19 +++--- .../hudson/maven/MavenProcessFactory.java | 15 ++-- .../hudson/maven/PlexusModuleContributor.java | 66 ++++++++++++------ .../maven/PlexusModuleContributorFactory.java | 68 +++++++++++++++++++ .../maven/PlexusModuleContributorTest.java | 39 +++++++---- 9 files changed, 185 insertions(+), 62 deletions(-) create mode 100644 maven-plugin/src/main/java/hudson/maven/PlexusModuleContributorFactory.java diff --git a/changelog.html b/changelog.html index be11aa1569..7ac87b6e2c 100644 --- a/changelog.html +++ b/changelog.html @@ -78,6 +78,8 @@ Upcoming changes
  • Edited description wasn't reflected when pressing the "Apply" button. (issue 18436) +
  • + Revisited the extension point added in 1.519 that adds custom plexus components. diff --git a/maven-plugin/src/main/java/hudson/maven/AbstractMavenProcessFactory.java b/maven-plugin/src/main/java/hudson/maven/AbstractMavenProcessFactory.java index 8e7e9d9094..4c5bcb4f6e 100644 --- a/maven-plugin/src/main/java/hudson/maven/AbstractMavenProcessFactory.java +++ b/maven-plugin/src/main/java/hudson/maven/AbstractMavenProcessFactory.java @@ -80,6 +80,7 @@ public abstract class AbstractMavenProcessFactory { private final MavenModuleSet mms; + private final AbstractMavenBuild build; private final Launcher launcher; /** * Environment variables to be set to the maven process. @@ -99,7 +100,8 @@ public abstract class AbstractMavenProcessFactory private final String mavenOpts; - AbstractMavenProcessFactory(MavenModuleSet mms, Launcher launcher, EnvVars envVars, String mavenOpts, FilePath workDir) { + AbstractMavenProcessFactory(MavenModuleSet mms, AbstractMavenBuild build, Launcher launcher, EnvVars envVars, String mavenOpts, FilePath workDir) { + this.build = build; this.mms = mms; this.launcher = launcher; this.envVars = envVars; @@ -243,8 +245,8 @@ public abstract class AbstractMavenProcessFactory Computer.threadPoolForRemoting, new BufferedInputStream(con.in), new BufferedOutputStream(con.out), listener.getLogger(), proc); - if (!PlexusModuleContributor.all().isEmpty()) - applyPlexusModuleContributor(ch); + if (!PlexusModuleContributorFactory.all().isEmpty()) + applyPlexusModuleContributor(ch,build); return new NewProcess(ch,proc); } catch (IOException e) { @@ -260,9 +262,15 @@ public abstract class AbstractMavenProcessFactory /** * Apply extension plexus modules to the newly launched Maven process. + * + * + * @param channel + * Channel to the Maven process. + * @param context + * Context that {@link PlexusModuleContributor} needs to figure out what it needs to do. * @since 1.519 */ - protected abstract void applyPlexusModuleContributor(Channel channel) throws InterruptedException, IOException; + protected abstract void applyPlexusModuleContributor(Channel channel, AbstractMavenBuild context) throws InterruptedException, IOException; /** * Builds the command line argument list to launch the maven process. diff --git a/maven-plugin/src/main/java/hudson/maven/Maven3ProcessFactory.java b/maven-plugin/src/main/java/hudson/maven/Maven3ProcessFactory.java index 0d6fc6c7cb..ecadce647a 100644 --- a/maven-plugin/src/main/java/hudson/maven/Maven3ProcessFactory.java +++ b/maven-plugin/src/main/java/hudson/maven/Maven3ProcessFactory.java @@ -26,7 +26,6 @@ package hudson.maven; import hudson.EnvVars; import hudson.FilePath; import hudson.Launcher; -import hudson.maven.agent.Main; import hudson.model.BuildListener; import hudson.model.Run.RunnerAbortedException; import hudson.model.TaskListener; @@ -44,14 +43,15 @@ import org.jvnet.hudson.maven3.agent.Maven3Main; import org.jvnet.hudson.maven3.launcher.Maven3Launcher; /** - * @author Olivier Lamy + * {@link AbstractMavenProcessFactory} for Maven 3. * + * @author Olivier Lam */ public class Maven3ProcessFactory extends AbstractMavenProcessFactory implements ProcessCache.Factory { - Maven3ProcessFactory(MavenModuleSet mms, Launcher launcher, EnvVars envVars, String mavenOpts, FilePath workDir) { - super( mms, launcher, envVars, mavenOpts, workDir ); + Maven3ProcessFactory(MavenModuleSet mms, AbstractMavenBuild build, Launcher launcher, EnvVars envVars, String mavenOpts, FilePath workDir) { + super( mms, build, launcher, envVars, mavenOpts, workDir ); } @Override @@ -82,12 +82,16 @@ public class Maven3ProcessFactory extends AbstractMavenProcessFactory implements } @Override - protected void applyPlexusModuleContributor(Channel channel) throws InterruptedException, IOException { - channel.call(new InstallPlexusModulesTask()); + protected void applyPlexusModuleContributor(Channel channel, AbstractMavenBuild context) throws InterruptedException, IOException { + channel.call(new InstallPlexusModulesTask(context)); } private static final class InstallPlexusModulesTask implements Callable { - PlexusModuleContributor c = PlexusModuleContributor.aggregate(); + PlexusModuleContributor c; + + public InstallPlexusModulesTask(AbstractMavenBuild context) throws IOException, InterruptedException { + c = PlexusModuleContributorFactory.aggregate(context); + } public Void call() throws IOException { Maven3Main.addPlexusComponents(c.getPlexusComponentJars().toArray(new URL[0])); diff --git a/maven-plugin/src/main/java/hudson/maven/MavenBuild.java b/maven-plugin/src/main/java/hudson/maven/MavenBuild.java index 23d4b7a625..43218130c5 100644 --- a/maven-plugin/src/main/java/hudson/maven/MavenBuild.java +++ b/maven-plugin/src/main/java/hudson/maven/MavenBuild.java @@ -707,9 +707,9 @@ public class MavenBuild extends AbstractMavenBuild { ProcessCache.MavenProcess process = MavenBuild.mavenProcessCache.get( launcher.getChannel(), listener, maven3orLater ? new Maven3ProcessFactory( - getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null ) + getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null ) : new MavenProcessFactory( - getParent().getParent(), launcher, envVars, getMavenOpts(listener, envVars), null )); + getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null )); ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B"); FilePath localRepo = mms.getLocalRepository().locate(MavenBuild.this); diff --git a/maven-plugin/src/main/java/hudson/maven/MavenModuleSetBuild.java b/maven-plugin/src/main/java/hudson/maven/MavenModuleSetBuild.java index b3712049e1..dab68b559d 100644 --- a/maven-plugin/src/main/java/hudson/maven/MavenModuleSetBuild.java +++ b/maven-plugin/src/main/java/hudson/maven/MavenModuleSetBuild.java @@ -683,18 +683,16 @@ public class MavenModuleSetBuild extends AbstractMavenBuild build, Launcher launcher, EnvVars envVars, String mavenOpts, FilePath workDir) { + super( mms, build, launcher, envVars, mavenOpts, workDir ); } @Override @@ -88,12 +89,16 @@ final class MavenProcessFactory extends AbstractMavenProcessFactory implements P } @Override - protected void applyPlexusModuleContributor(Channel channel) throws InterruptedException, IOException { - channel.call(new InstallPlexusModulesTask()); + protected void applyPlexusModuleContributor(Channel channel, AbstractMavenBuild context) throws InterruptedException, IOException { + channel.call(new InstallPlexusModulesTask(context)); } private static final class InstallPlexusModulesTask implements Callable { - PlexusModuleContributor c = PlexusModuleContributor.aggregate(); + PlexusModuleContributor c; + + public InstallPlexusModulesTask(AbstractMavenBuild context) throws IOException, InterruptedException { + c = PlexusModuleContributorFactory.aggregate(context); + } public Void call() throws IOException { Main.addPlexusComponents(c.getPlexusComponentJars().toArray(new URL[0])); diff --git a/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributor.java b/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributor.java index 4bdac6ac33..7a6e79806a 100644 --- a/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributor.java +++ b/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributor.java @@ -1,53 +1,81 @@ package hudson.maven; -import hudson.ExtensionList; -import hudson.ExtensionPoint; -import jenkins.model.Jenkins; +import hudson.FilePath; +import hudson.remoting.Channel; import org.apache.maven.AbstractMavenLifecycleParticipant; +import sun.tools.jar.resources.jar; +import java.io.File; import java.io.Serializable; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import static java.util.Arrays.asList; + /** * Contributes additional code into Plexus container when we run Maven. * *

    - * Injecting custom plexus components, such as {@link AbstractMavenLifecycleParticipant}, allows plugins to - * participate into the Maven internals more deeply. + * This object gets serialized and is sent to Maven JVM to run. * * @author Kohsuke Kawaguchi - * @since 1.519 + * @since 1.521 + * @see PlexusModuleContributorFactory */ -public abstract class PlexusModuleContributor implements ExtensionPoint, Serializable { +public abstract class PlexusModuleContributor implements Serializable { + /** + * Designates the list of URLs to be added to the classpath of the core plexus components + * that constitute Maven. + */ public abstract List getPlexusComponentJars(); /** - * Returns all the registered {@link PlexusModuleContributor}s. + * When {@link #getPlexusComponentJars()} is called, this field is set + * to the channel that represents the connection to the master. */ - public static ExtensionList all() { - return Jenkins.getInstance().getExtensionList(PlexusModuleContributor.class); + protected transient Channel channel; + + protected Object readResolve() { + channel = Channel.current(); + return this; } private static final long serialVersionUID = 1L; + public static PlexusModuleContributor of(FilePath... jars) { + return of(asList(jars)); + } + /** - * Returns a single {@link PlexusModuleContributor} that aggregates all the registered - * {@link PlexusModuleContributor}s in the system. The instance is remoting portable. + * Convenience method that creates a {@link PlexusModuleContributor} object + * that adds the given files as classpaths. + * + * These jar files must represent the files on the computer on which Maven process is running. */ - public static PlexusModuleContributor aggregate() { - // capture in a serializable form - final List all = new ArrayList(all()); + public static PlexusModuleContributor of(List jars) { + final List files = new ArrayList(jars.size()); + for (FilePath jar : jars) { + files.add(jar.getRemote()); + } + return new PlexusModuleContributor() { @Override public List getPlexusComponentJars() { - List urls = new ArrayList(); - for (PlexusModuleContributor pc : all) { - urls.addAll(pc.getPlexusComponentJars()); + try { + List r = new ArrayList(files.size()); + for (String file : files) { + r.add(new File(file).toURI().toURL()); + } + return r; + } catch (MalformedURLException e) { + throw new IllegalStateException(e); } - return urls; } + + private static final long serialVersionUID = 1L; }; } } diff --git a/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributorFactory.java b/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributorFactory.java new file mode 100644 index 0000000000..abf893cf3b --- /dev/null +++ b/maven-plugin/src/main/java/hudson/maven/PlexusModuleContributorFactory.java @@ -0,0 +1,68 @@ +package hudson.maven; + +import hudson.ExtensionList; +import hudson.ExtensionPoint; +import hudson.model.AbstractBuild; +import jenkins.model.Jenkins; +import org.apache.maven.AbstractMavenLifecycleParticipant; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +/** + * Contributes additional code into Plexus container when we run Maven. + * + *

    + * Injecting custom plexus components, such as {@link AbstractMavenLifecycleParticipant}, allows plugins to + * participate into the Maven internals more deeply. + * + *

    Lifecycle

    + *

    + * {@link PlexusModuleContributorFactory}s are instantiated as singletons on the master, and whenever a new Maven + * process starts, its {@link #createFor(AbstractBuild)} method is called to instantiate {@link PlexusModuleContributor}, + * which gets serialized on the master, then deserialized inside the Maven process, and then its + * {@link PlexusModuleContributor#getPlexusComponentJars()} will be invoked to determine the additional classpaths. + * and then run. + * + * @author Kohsuke Kawaguchi + * @since 1.521 + * @see PlexusModuleContributor + */ +public abstract class PlexusModuleContributorFactory implements ExtensionPoint { + + public abstract PlexusModuleContributor createFor(AbstractBuild context) throws IOException, InterruptedException; + + /** + * Returns all the registered {@link PlexusModuleContributor}s. + */ + public static ExtensionList all() { + return Jenkins.getInstance().getExtensionList(PlexusModuleContributorFactory.class); + } + + /** + * Returns a single {@link PlexusModuleContributor} that aggregates all the registered + * {@link PlexusModuleContributor}s in the system. The instance is remoting portable. + */ + public static PlexusModuleContributor aggregate(AbstractBuild context) throws IOException, InterruptedException { + // capture in a serializable form + final List all = new ArrayList(); + for (PlexusModuleContributorFactory pmcf : all()) { + PlexusModuleContributor pmc = pmcf.createFor(context); + if (pmc!=null) + all.add(pmc); + } + + return new PlexusModuleContributor() { + @Override + public List getPlexusComponentJars() { + List urls = new ArrayList(); + for (PlexusModuleContributor pc : all) { + urls.addAll(pc.getPlexusComponentJars()); + } + return urls; + } + }; + } +} diff --git a/test/src/test/java/hudson/maven/PlexusModuleContributorTest.java b/test/src/test/java/hudson/maven/PlexusModuleContributorTest.java index 638dc03842..9c893fe446 100644 --- a/test/src/test/java/hudson/maven/PlexusModuleContributorTest.java +++ b/test/src/test/java/hudson/maven/PlexusModuleContributorTest.java @@ -1,6 +1,9 @@ package hudson.maven; +import hudson.FilePath; +import hudson.model.AbstractBuild; import hudson.remoting.Which; +import hudson.slaves.DumbSlave; import hudson.tasks.Maven.MavenInstallation; import org.junit.Rule; import org.junit.Test; @@ -9,10 +12,8 @@ import org.jvnet.hudson.test.SingleFileSCM; import org.jvnet.hudson.test.TestExtension; import test.BogusPlexusComponent; +import java.io.File; import java.io.IOException; -import java.net.URL; -import java.util.Collections; -import java.util.List; /** * @author Kohsuke Kawaguchi @@ -44,21 +45,29 @@ public class PlexusModuleContributorTest { j.assertBuildStatusSuccess(p.scheduleBuild2(0)); } - @TestExtension - public static class PlexusLoader extends PlexusModuleContributor { - private URL bogusPlexusJar; + @Test + public void testCustomPlexusComponent_Maven3_slave() throws Exception { + j.configureDefaultMaven("apache-maven-3.0.1", MavenInstallation.MAVEN_30); + DumbSlave s = j.createSlave(); + s.toComputer().connect(false).get(); - public PlexusLoader() { - try { - this.bogusPlexusJar = Which.jarFile(BogusPlexusComponent.class).toURL(); - } catch (IOException e) { - throw new AssertionError(e); - } - } + MavenModuleSet p = j.createMavenProject(); + p.setAssignedLabel(s.getSelfLabel()); + + p.setScm(new SingleFileSCM("pom.xml",getClass().getResource("custom-plexus-component.pom"))); + p.setGoals("clean"); + j.assertBuildStatusSuccess(p.scheduleBuild2(0)); + } + @TestExtension + public static class PlexusLoader extends PlexusModuleContributorFactory { @Override - public List getPlexusComponentJars() { - return Collections.singletonList(bogusPlexusJar); + public PlexusModuleContributor createFor(AbstractBuild context) throws IOException, InterruptedException { + File bogusPlexusJar = Which.jarFile(BogusPlexusComponent.class); + final FilePath localJar = context.getBuiltOn().getRootPath().child("cache/bogusPlexus.jar"); + localJar.copyFrom(new FilePath(bogusPlexusJar)); + + return PlexusModuleContributor.of(localJar); } } } -- GitLab