提交 7a5b3ab6 编写于 作者: K kohsuke

added more Maven related code (all experimental)


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@1707 71c3de6d-444a-0410-be80-ed276b4c234a
上级 f7451c73
......@@ -49,6 +49,8 @@ public class MavenBuild extends AbstractBuild<MavenJob,MavenBuild> {
/**
* Runs Maven and builds the project.
*
* This code is executed on the remote machine.
*/
private static final class Builder implements FileCallable<Result> {
private final BuildListener listener;
......@@ -125,7 +127,7 @@ public class MavenBuild extends AbstractBuild<MavenJob,MavenBuild> {
//private boolean preBuild(BuildListener listener,Map<?,? extends BuildStep> steps) {
// for( BuildStep bs : steps.values() )
// if(!bs.prebuild(Build.this,listener))
// if(!bs.preBuild(Build.this,listener))
// return false;
// return true;
//}
......
package hudson.maven;
import hudson.FilePath;
import java.io.Serializable;
import java.io.IOException;
/**
* Remoting proxy interface for {@link MavenReporter}s to talk to {@link MavenBuild}
* during the build.
*
* @author Kohsuke Kawaguchi
*/
public interface MavenBuildProxy {
/**
* Executes the given {@link BuildCallable} on the master, where one
* has access to {@link MavenBuild} and all the other Hudson objects.
*
* <p>
* The parameter, return value, and exception are all transfered by using
* Java serialization.
*
* @return
* the value that {@link BuildCallable} returned.
* @throws T
* if {@link BuildCallable} throws this exception.
* @throws IOException
* if the remoting failed.
* @throws InterruptedException
* if the remote execution is aborted.
*/
<V,T extends Throwable> V execute( BuildCallable<V,T> program ) throws T, IOException, InterruptedException;
/**
* Root directory of the build.
*
* @see MavenBuild#getRootDir()
*/
FilePath getRootDir();
/**
* @see MavenBuild#getArtifactsDir()
*/
FilePath getArtifactsDir();
public interface BuildCallable<V,T extends Throwable> extends Serializable {
/**
* Performs computation and returns the result,
* or throws some exception.
*/
V call(MavenBuild build) throws T;
}
}
package hudson.maven;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Job;
import hudson.model.JobDescriptor;
import hudson.model.Descriptor.FormException;
import hudson.util.DescribableList;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -16,11 +19,22 @@ import java.io.IOException;
*
* @author Kohsuke Kawaguchi
*/
public final class MavenJob extends AbstractProject<MavenJob,MavenBuild> {
public final class MavenJob extends AbstractProject<MavenJob,MavenBuild> implements DescribableList.Owner {
private DescribableList<MavenReporter,Descriptor<MavenReporter>> reporters =
new DescribableList<MavenReporter,Descriptor<MavenReporter>>(this);
public MavenJob(Hudson parent, String name) {
super(parent, name);
}
@Override
protected void onLoad(Hudson root, String name) throws IOException {
super.onLoad(root, name);
if(reporters==null)
reporters = new DescribableList<MavenReporter, Descriptor<MavenReporter>>(this);
reporters.setOwner(this);
}
@Override
public MavenBuild newBuild() throws IOException {
MavenBuild lastBuild = new MavenBuild(this);
......@@ -33,11 +47,21 @@ public final class MavenJob extends AbstractProject<MavenJob,MavenBuild> {
return new MavenBuild(this,dir);
}
/**
* List of active {@link MavenReporter}s configured for this project.
*/
public DescribableList<MavenReporter, Descriptor<MavenReporter>> getReporters() {
return reporters;
}
public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
super.doConfigSubmit(req, rsp);
// TODO
try {
reporters.rebuild(req,MavenReporters.LIST,"reporter");
} catch (FormException e) {
sendError(e,req,rsp);
}
save();
}
......
......@@ -9,26 +9,36 @@ import hudson.tasks.BuildStep;
import java.io.IOException;
import org.apache.maven.project.MavenProject;
/**
* Listens to the build execution of {@link MavenBuild},
* and normally records some information and exposes thoses
* in {@link MavenBuild} later.
*
* <p>
* TODO: talk about two nodes involved
* Because builds may happen on a remote slave node, {@link MavenReporter}
* implementation needs ...
*
* <p>
* This is the {@link MavenBuild} equivalent of {@link BuildStep}.
*
* @author Kohsuke Kawaguchi
* @see MavenReporters
*/
public abstract class MavenListener implements Describable<MavenListener>, ExtensionPoint {
public abstract class MavenReporter implements Describable<MavenReporter>, ExtensionPoint {
/**
* Called before the actual maven2 execution begins.
*
* @param pom
* Represents the POM to be executed.
* @return
* true if the build can continue, false if there was an error
* and the build needs to be aborted.
* @throws InterruptedException
* If the build is interrupted by the user (in an attempt to abort the build.)
* Normally the {@link MavenListener} implementations may simply forward the exception
* Normally the {@link MavenReporter} implementations may simply forward the exception
* it got from its lower-level functions.
* @throws IOException
* If the implementation wants to abort the processing when an {@link IOException}
......@@ -38,27 +48,35 @@ public abstract class MavenListener implements Describable<MavenListener>, Exten
* provide a better error message, if it can do so, so that users have better
* understanding on why it failed.
*/
public boolean prebuild(MavenBuild build, BuildListener listener) throws InterruptedException, IOException {
public boolean preBuild(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
return true;
}
public void preExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException {
}
public void postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException {
}
/**
* Called after the actual maven2 execution completed.
*
* @return
* See {@link #prebuild(MavenBuild, BuildListener)}
* See {@link #preBuild}
* @throws InterruptedException
* See {@link #prebuild(MavenBuild, BuildListener)}
* See {@link # preBuild}
* @throws IOException
* See {@link #prebuild(MavenBuild, BuildListener)}
* See {@link # preBuild}
*/
public boolean postbuild(MavenBuild build, BuildListener listener) throws InterruptedException, IOException {
public boolean postBuild(MavenBuildProxy build, MavenProject pom, BuildListener listener) throws InterruptedException, IOException {
return true;
}
/**
* Equivalent of {@link BuildStep#getProjectAction(Project)}
* for {@link MavenListener}.
* for {@link MavenReporter}.
*/
public Action getProjectAction(MavenJob project) {
return null;
......
package hudson.maven;
import hudson.model.Descriptor;
import hudson.maven.reporters.MavenArtifactArchiver;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
* @see MavenReporter
*/
public final class MavenReporters {
/**
* List of all installed {@link MavenReporter}s.
*/
public static final List<Descriptor<MavenReporter>> LIST = Descriptor.<Descriptor<MavenReporter>>toList(
MavenArtifactArchiver.DescriptorImpl.DESCRIPTOR
);
}
package hudson.maven;
import org.apache.maven.plugin.MojoExecution;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
import org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup;
import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
/**
* Information about Mojo to be executed. This object provides
* convenient access to various mojo information, so that {@link MavenReporter}
* implementations are shielded to some extent from Maven internals.
*
* <p>
* For each mojo to be executed, this object is created and passed to
* {@link MavenReporter}.
*
* @author Kohsuke Kawaguchi
* @see MavenReporter
*/
public final class MojoInfo {
/**
* Object from Maven that describes the Mojo to be executed.
*/
public final MojoExecution mojoExecution;
/**
* Name of the plugin that contains this mojo.
*/
public final Name pluginName;
/**
* Configuration of the mojo for the current execution.
* This reflects the default values, as well as values configured from POM,
* including inherited values.
*/
public final PlexusConfiguration configuration;
/**
* Object that Maven uses to resolve variables like "${project}" to its
* corresponding object.
*/
public final ExpressionEvaluator expressionEvaluator;
/**
* Used to obtain a value from {@link PlexusConfiguration} as a typed object,
* instead of String.
*/
private final ConverterLookup converterLookup = new DefaultConverterLookup();
public MojoInfo(MojoExecution mojoExecution, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator) {
this.mojoExecution = mojoExecution;
this.configuration = configuration;
this.expressionEvaluator = expressionEvaluator;
this.pluginName = new Name(mojoExecution.getMojoDescriptor().getPluginDescriptor());
}
/**
* Gets the goal name of the mojo to be executed,
* such as "javadoc". This is local to the plugin name.
*/
public String getGoal() {
return mojoExecution.getMojoDescriptor().getGoal();
}
public <T> T getConfigurationValue(String configName, Class<T> type) throws ComponentConfigurationException {
PlexusConfiguration child = configuration.getChild(configName);
if(child==null) return null; // no such config
ConfigurationConverter converter = converterLookup.lookupConverterForType(type);
return type.cast(converter.fromConfiguration(converterLookup,child,type,
// the implementation seems to expect the type of the bean for which the configuration is done
// in this parameter, but we have no such type. So passing in a dummy
Object.class,
mojoExecution.getMojoDescriptor().getPluginDescriptor().getClassRealm().getClassLoader(),
expressionEvaluator));
}
}
package hudson.maven;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
/**
* Identifier of an artifact (like jar) in Maven,
* that consists of groupId, artifactId, and version.
*
*
* @author Kohsuke Kawaguchi
*/
public final class Name {
public final String groupId;
public final String artifactId;
public final String version;
public Name(String groupId, String artifactId, String version) {
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
}
public Name(PluginDescriptor pd) {
this(pd.getGroupId(), pd.getArtifactId(), pd.getVersion());
}
/**
* Returns the "groupId:artifactId:version" form.
*/
public String toString() {
return groupId+':'+artifactId+':'+version;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Name that = (Name) o;
return artifactId.equals(that.artifactId)
&& groupId.equals(that.groupId)
&& version.equals(that.version);
}
public int hashCode() {
int result;
result = groupId.hashCode();
result = 31 * result + artifactId.hashCode();
result = 31 * result + version.hashCode();
return result;
}
}
......@@ -16,6 +16,11 @@ 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;
/**
* Description in META-INF/plexus/components.xml makes it possible to use this instead of the default
......@@ -25,14 +30,57 @@ import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator
*/
public class PluginManagetInterceptor extends DefaultPluginManager {
private final Method mergeMojoConfiguration;
public PluginManagetInterceptor() {
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;
}
}
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 );
}
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() );
// the proper step is first check the value, then check the default-value attribute.
System.out.println("EXECUTING "+mojoExecution.getExecutionId());
super.executeMojo(project, mojoExecution, session);
}
......
package hudson.maven.reporters;
import hudson.model.Descriptor;
import hudson.model.BuildListener;
import hudson.FilePath;
import hudson.maven.MavenReporter;
import hudson.maven.MavenBuildProxy;
import hudson.maven.MojoInfo;
import org.kohsuke.stapler.StaplerRequest;
import org.apache.maven.project.MavenProject;
import org.apache.maven.artifact.Artifact;
import java.io.IOException;
/**
* Archives artifacts of the build.
*
* @author Kohsuke Kawaguchi
*/
public class MavenArtifactArchiver extends MavenReporter {
public void postExecute(MavenBuildProxy build, MavenProject pom, MojoInfo mojo, BuildListener listener) throws InterruptedException, IOException {
record(build,pom.getArtifact());
for( Object a : pom.getAttachedArtifacts() )
record(build,(Artifact)a);
}
/**
* Archives the given {@link Artifact}.
*/
private void record(MavenBuildProxy build, Artifact a) throws IOException, InterruptedException {
if(a.getFile()==null)
return; // perhaps build failed and didn't leave an artifact
new FilePath(a.getFile()).copyTo(
build.getArtifactsDir()
.child(a.getGroupId())
.child(a.getArtifactId())
.child(a.getVersion())
.child(a.getArtifactId()+'-'+a.getVersion()+(a.getClassifier()!=null?'-'+a.getClassifier():"")+'.'+a.getType()));
}
public DescriptorImpl getDescriptor() {
return DescriptorImpl.DESCRIPTOR;
}
public static final class DescriptorImpl extends Descriptor<MavenReporter> {
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
private DescriptorImpl() {
super(MavenArtifactArchiver.class);
}
public String getDisplayName() {
return "Archive the artifacts";
}
public MavenArtifactArchiver newInstance(StaplerRequest req) throws FormException {
return new MavenArtifactArchiver();
}
}
}
<!-- nothing to configure -->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" />
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册