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); } } } }