package de.saumya.mojo.gem;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.ModelReader;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import de.saumya.mojo.ruby.gems.GemException;
import de.saumya.mojo.ruby.script.ScriptException;
/**
* installs a set of given gems without resolving any transitive dependencies
*/
@Mojo( name = "sets", defaultPhase = LifecyclePhase.INITIALIZE,
requiresDependencyResolution = ResolutionScope.TEST )
public class SetsMojo extends AbstractGemMojo {
/**
* the scope under which the gems get installed
*/
@Parameter( defaultValue = "compile" )
protected String scope;
/**
* map of gemname to version, i.e. it is a "list" of gems with fixed version
*/
@Parameter
protected Map<String, String> gems = Collections.emptyMap();
@Component
protected ModelReader reader;
protected void executeWithGems() throws MojoExecutionException,
ScriptException, IOException, GemException {
Set<Artifact> gems = new TreeSet<Artifact>();
Set<Artifact> jars = new TreeSet<Artifact>();
for( Map.Entry<String, String> gem : this.gems.entrySet() ) {
Set<Artifact> set = manager.resolve( manager.createGemArtifact( gem.getKey(),
gem.getValue() ),
localRepository,
project.getRemoteArtifactRepositories() );
if ( set.size() == 1 )
{
Artifact artifact = set.iterator().next();
artifact.setScope(scope);
gems.add(artifact);
collectJarDependencies(jars, artifact);
}
else if ( set.size() > 1 )
{
getLog().error( "found more then one artifact for given version: " + gem.getKey() + " " + gem.getValue() );
}
}
resolveJarDepedencies(jars);
installGems(gems);
Set<Artifact> resolved = (Set<Artifact>) project.getContextValue("jruby.resolved.artifacts");
if (resolved == null) {
resolved = project.getArtifacts();
// TODO this might mix the java and ruby application jars
// use resolved artifacts as project ones
project.setResolvedArtifacts(resolved);
project.setContextValue("jruby.resolved.artifacts", resolved);
}
resolved.addAll(jars);
resolved.addAll(gems);
}
private void installGems(Set<Artifact> gems) throws IOException, ScriptException, GemException {
File home = gemsConfig.getGemHome();
// use gemHome as base for other gems installation directories
String base = this.gemsConfig.getGemHome() != null ?
this.gemsConfig.getGemHome().getAbsolutePath() :
(project.getBuild().getDirectory() + "/rubygems");
try
{
final File gemHome;
if ( "test".equals( scope ) || "provided".equals( scope ) )
{
gemHome = gemHome( base, scope);
}
else
{
gemHome = new File( base );
}
this.gemsConfig.setGemHome(gemHome);
this.gemsConfig.addGemPath(gemHome);
getLog().info("installing gem sets for " + scope + " scope into " +
gemHome.getAbsolutePath().replace(project.getBasedir().getAbsolutePath() + File.separatorChar, ""));
gemsInstaller.installGems(project, gems, null, (List<ArtifactRepository>) null);
}
finally
{
// reset old gem home again
this.gemsConfig.setGemHome(home);
}
}
private void collectJarDependencies(Set<Artifact> jars, Artifact artifact) throws GemException, IOException {
Set<Artifact> set = manager.resolve(manager.createArtifact(artifact.getGroupId(),
artifact.getArtifactId(), artifact.getVersion(), "pom"),
localRepository,
project.getRemoteArtifactRepositories());
Model pom = reader.read(set.iterator().next().getFile(), null);
for( Dependency dependency : pom.getDependencies() ){
if (!dependency.getType().equals("gem")) {
if (dependency.getScope() == null || dependency.getScope().equals("compile") ||
dependency.getScope().equals("runtime")) {
Artifact a = manager.createArtifact(dependency.getGroupId(), dependency.getArtifactId(),
dependency.getVersion(), dependency.getClassifier(), dependency.getType());
a.setScope(dependency.getScope());
jars.add(a);
}
}
}
}
private void resolveJarDepedencies(Set<Artifact> jars) {
ArtifactResolutionRequest req = new ArtifactResolutionRequest()
.setArtifact(project.getArtifact())
.setResolveRoot(false)
.setArtifactDependencies(jars)
.setResolveTransitively(true)
.setLocalRepository(localRepository)
.setRemoteRepositories(project.getRemoteArtifactRepositories())
.setCollectionFilter(new ArtifactFilter() {
// we want to skip all those jruby artifacts to be on the safe side
public boolean include(Artifact artifact) {
return !(artifact.getGroupId().equals("org.jruby") &&
(artifact.getArtifactId().equals("jruby") ||
artifact.getArtifactId().equals("jruby-complete") ||
artifact.getArtifactId().equals("jruby-core") ||
artifact.getArtifactId().equals("jruby-stdlib")));
}
});
ArtifactResolutionResult result = this.repositorySystem.resolve(req);
Set<Artifact> resolvedArtifacts = result.getArtifacts();
for( Artifact artifact : resolvedArtifacts ){
// * compile scope we leave things as they are
// * other scopes we only take runtime, compile time artifacts and set the scope to outer scope
if ("compile".equals(scope)) {
if (artifact.getScope() == null) artifact.setScope(scope);
jars.add(artifact);
}
else if (!"test".equals(artifact.getScope()) && !"provided".equals(artifact.getScope())) {
artifact.setScope(scope);
jars.add(artifact);
}
}
}
}