de.saumya.mojo.jruby.AbstractJRubyMojo Maven / Gradle / Ivy
package de.saumya.mojo.jruby;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.classworlds.ClassRealm;
import org.codehaus.classworlds.NoSuchRealmException;
import org.sonatype.plexus.build.incremental.BuildContext;
import de.saumya.mojo.ruby.Logger;
import de.saumya.mojo.ruby.script.ScriptException;
import de.saumya.mojo.ruby.script.ScriptFactory;
/**
* Base for all JRuby mojos.
*/
//@Mojo( requiresProject = true )
public abstract class AbstractJRubyMojo extends AbstractMojo {
protected static final String JRUBY_COMPLETE = "jruby-complete";
protected static final String JRUBY_CORE = "jruby-core";
protected static final String JRUBY_STDLIB = "jruby-stdlib";
protected static final String DEFAULT_JRUBY_VERSION = "1.7.22";
/**
* common arguments
*/
@Parameter( property = "args")
protected String args;
/**
* jvm arguments for the java command executing jruby
*/
@Parameter( property = "jruby.jvmargs")
protected String jrubyJvmArgs;
/**
* switches for the jruby command, like '--1.9'
*/
@Parameter( property = "jruby.switches")
protected String jrubySwitches;
/**
* environment values passed on to the jruby process. needs jrubyFork true.
*/
@Parameter( property = "jruby.env")
protected Map env;
/**
* if the pom.xml has no runtime dependency to a jruby-complete.jar then
* this version is used to resolve the jruby-complete dependency from the
* local/remote maven repository. it overwrites the jruby version from
* the dependencies if any. i.e. you can easily switch jruby version from the commandline !
*
* default see {@code DEFAULT_JRUBY_VERSION}
*/
// no defaultVersion here since we treat null as default later on
@Parameter( property = "jruby.version" )
private String jrubyVersion;
/**
* fork the JRuby execution.
*/
@Parameter( property = "jruby.fork", defaultValue = "true")
protected boolean jrubyFork;
/**
* verbose jruby related output
*/
@Parameter( property = "jruby.verbose", defaultValue = "false")
protected boolean jrubyVerbose;
/**
* directory with ruby sources - added to java classpath and ruby loadpath
*/
@Parameter( property = "jruby.sourceDirectory", defaultValue = "src/main/ruby")
protected File rubySourceDirectory;
/**
* directory with ruby sources - added to ruby loadpath only
*/
@Parameter( property = "jruby.lib", defaultValue = "lib")
protected File libDirectory;
/**
* the launch directory for the JRuby execution.
*/
@Parameter( property = "jruby.launchDirectory", defaultValue = "${project.basedir}")
private File launchDirectory;
/**
* reference to maven project for internal use.
*/
@Parameter( defaultValue = "${project}", readonly = true )
protected MavenProject project;
/**
* add project class path to JVM classpath on executing jruby.
*/
@Parameter( defaultValue = "true", property = "jruby.addProjectClasspath" )
protected boolean addProjectClasspath;
/**
* local repository for internal use.
*/
@Parameter( readonly = true, defaultValue="${localRepository}" )
protected ArtifactRepository localRepository;
/**
* classrealm for internal use.
*/
@Parameter( readonly = true, defaultValue="${dummy}" )
protected ClassRealm classRealm;
@Component
protected RepositorySystem repositorySystem;
protected Logger logger;
protected ScriptFactory factory;
private JRubyVersion jRubyVersion;
@Component
private BuildContext buildContext;
@Parameter( property="m2e.jruby.watch" )
protected List eclipseWatches = new ArrayList();
@Parameter( property="m2e.jruby.refresh" )
protected List eclipseRefresh = new ArrayList();
protected String getDefaultJRubyVersion() {
return DEFAULT_JRUBY_VERSION;
}
protected JRubyVersion getJrubyVersion()
{
if (jRubyVersion == null )
{
this.jRubyVersion = new JRubyVersion( jrubyVersion == null ? getDefaultJRubyVersion() : jrubyVersion );
}
return jRubyVersion;
}
private ScriptFactory newScriptFactory() throws MojoExecutionException {
ScriptFactory factory = createScriptFactory();
if( env != null ){
for( Map.Entry entry: env.entrySet() ){
factory.addEnv( entry.getKey(), entry.getValue() );
}
}
return factory;
}
private ScriptFactory createScriptFactory() throws MojoExecutionException {
try
{
classRealm.getWorld().disposeRealm("jruby-all");
}
catch( NoSuchRealmException ignore )
{
// ignore
}
try {
ClassRealm realm = classRealm.getWorld().newRealm("jruby-all");
for (String path : getProjectClasspath()) {
realm.addConstituent(new File(path).toURI().toURL());
}
if (this.jrubyVersion != null) {
// preference to command line or property version
return newScriptFactory( resolveJRubyCompleteArtifact(this.jrubyVersion) );
}
// check if there is jruby present
Class> clazz = realm.loadClass("org.jruby.runtime.Constants");
if ( jrubyVerbose ){
String version = clazz.getField( "VERSION" ).get(clazz).toString();
getLog().info("found jruby on classpath");
getLog().info("jruby version : " + version);
}
this.classRealm = realm;
return newScriptFactory( null );
} catch (final Exception e) {
//TODO debug
//e.printStackTrace();
try {
return newScriptFactory(resolveJRubyArtifact());
} catch (final DependencyResolutionRequiredException ee) {
throw new MojoExecutionException("could not resolve jruby", e);
}
}
}
protected ScriptFactory newScriptFactory(Artifact artifact) throws MojoExecutionException {
try {
final ScriptFactory factory =
artifact == null ?
new ScriptFactory(this.logger,
this.classRealm,
null,
getProjectClasspath(),
this.jrubyFork):
(JRUBY_CORE.equals(artifact.getArtifactId()) ?
new ScriptFactory(this.logger,
this.classRealm,
artifact.getFile(),
resolveJRubyStdlibArtifact(artifact).getFile(),
getProjectClasspath(),
this.jrubyFork) :
new ScriptFactory(this.logger,
this.classRealm,
artifact.getFile(),
getProjectClasspath(),
this.jrubyFork) );
if(libDirectory != null && libDirectory.exists()){
if(jrubyVerbose){
getLog().info("add to ruby loadpath: " + libDirectory.getAbsolutePath());
}
// add it to the load path for all scripts using that factory
factory.addSwitch("-I", libDirectory.getAbsolutePath());
}
if(rubySourceDirectory != null && rubySourceDirectory.exists()){
if(jrubyVerbose){
getLog().info("add to ruby loadpath: " + rubySourceDirectory.getAbsolutePath());
}
// add it to the load path for all scripts using that factory
factory.addSwitch("-I", rubySourceDirectory.getAbsolutePath());
}
return factory;
} catch (final DependencyResolutionRequiredException e) {
throw new MojoExecutionException("could not resolve jruby", e);
} catch (final ScriptException e) {
throw new MojoExecutionException(
"could not initialize script factory", e);
} catch (final IOException e) {
throw new MojoExecutionException(
"could not initialize script factory", e);
}
}
public void execute() throws MojoExecutionException, MojoFailureException {
boolean shouldCheckChanges = buildContext.isIncremental() && !eclipseWatches.isEmpty();
if (shouldCheckChanges && !buildContext.hasDelta(eclipseWatches)) {
return;
}
System.setProperty("jbundle.skip", "true");
this.logger = new MojoLogger(this.jrubyVerbose, getLog());
this.factory = newScriptFactory();
// skip installing jars via jbundler
this.factory.addEnv("JBUNDLE_SKIP", "true");
// skip installing jars via jar-dependencies
this.factory.addEnv("JARS_SKIP", "true");
this.factory.addJvmArgs(this.jrubyJvmArgs);
this.factory.addSwitches(this.jrubySwitches);
if(rubySourceDirectory != null && rubySourceDirectory.exists()){
if(jrubyVerbose){
getLog().info("add to java classpath: " + rubySourceDirectory.getAbsolutePath());
}
// add it to the classpath so java classes can find the ruby files
Resource resource = new Resource();
resource.setDirectory(rubySourceDirectory.getAbsolutePath());
project.getBuild().getResources().add(resource);
}
try {
executeJRuby();
} catch (final IOException e) {
throw new MojoExecutionException("error in executing jruby", e);
} catch (final ScriptException e) {
throw new MojoExecutionException("error in executing jruby", e);
} finally {
// ensure that eclipse update any changes, include errors reports
if (!eclipseRefresh.isEmpty()) {
for (String fileName : eclipseRefresh) {
File file = new File(fileName);
buildContext.refresh(file);;
}
}
}
}
abstract protected void executeJRuby() throws MojoExecutionException,
MojoFailureException, IOException, ScriptException;
protected File launchDirectory() {
if (this.launchDirectory == null) {
this.launchDirectory = this.project.getBasedir();
if (this.launchDirectory == null || !this.launchDirectory.exists()) {
this.launchDirectory = new File(System.getProperty("user.dir"));
}
}
return this.launchDirectory;
}
protected Artifact resolveJRubyCompleteArtifact(final String version)
throws DependencyResolutionRequiredException {
getLog().debug("resolve jruby for version " + version);
final Artifact artifact = this.repositorySystem.createArtifact(
"org.jruby", JRUBY_COMPLETE, version, "jar");
return resolveJRubyArtifact(artifact);
}
private Artifact resolveJRubyArtifact(final Artifact artifact)
throws DependencyResolutionRequiredException {
final ArtifactResolutionRequest request = new ArtifactResolutionRequest();
request.setArtifact(artifact);
request.setLocalRepository(this.localRepository);
request.setRemoteRepositories(this.project.getRemoteArtifactRepositories());
this.repositorySystem.resolve(request);
if (this.jrubyVerbose) {
getLog().info("jruby version : " + artifact.getVersion());
}
// set it so other plugins can retrieve the version in use
this.jrubyVersion = artifact.getVersion();
return artifact;
}
protected Artifact resolveJRubyArtifact() throws DependencyResolutionRequiredException,
MojoExecutionException {
if (this.jrubyVersion != null) {
// preference to command line or property version
return resolveJRubyCompleteArtifact(this.jrubyVersion);
}
else {
// then take jruby from the dependencies either jruby-complete or jruby-core
for (final Dependency artifact : this.project.getDependencies()) {
if ((artifact.getArtifactId().equals(JRUBY_COMPLETE)
|| artifact.getArtifactId().equals(JRUBY_CORE))
// TODO this condition is not needed ?
&& !artifact.getScope().equals(Artifact.SCOPE_PROVIDED)
&& !artifact.getScope().equals(Artifact.SCOPE_SYSTEM)) {
return resolveJRubyArtifact(this.repositorySystem
.createArtifact(artifact.getGroupId(), artifact
.getArtifactId(), artifact.getVersion(),
artifact.getType()));
}
}
}
// finally fall back on the default version of jruby
return resolveJRubyCompleteArtifact(getDefaultJRubyVersion());
}
protected Artifact resolveJRubyStdlibArtifact(Artifact jruby) throws DependencyResolutionRequiredException,
MojoExecutionException {
final ArtifactResolutionRequest request = new ArtifactResolutionRequest();
for (final Dependency artifact : this.project.getDependencies()) {
if (artifact.getArtifactId().equals(JRUBY_STDLIB)
// TODO this condition is not needed ?
&& !artifact.getScope().equals(Artifact.SCOPE_PROVIDED)
&& !artifact.getScope().equals(Artifact.SCOPE_SYSTEM)) {
request.setArtifact(this.repositorySystem
.createArtifact(artifact.getGroupId(), artifact
.getArtifactId(), artifact.getVersion(),
artifact.getType()));
break;
}
}
if (request.getArtifact() == null){
request.setResolveTransitively(true);
request.setArtifact(jruby);
}
request.setLocalRepository(this.localRepository);
request.setRemoteRepositories(this.project.getRemoteArtifactRepositories());
Set set = this.repositorySystem.resolve(request).getArtifacts();
for (Artifact a: set){
if (JRUBY_STDLIB.equals(a.getArtifactId())) {
return a;
}
}
throw new MojoExecutionException("failed to resolve jruby stdlib artifact");
}
protected List getProjectClasspath() throws DependencyResolutionRequiredException {
if (addProjectClasspath) {
return project.getTestClasspathElements();
} else {
return new ArrayList();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy