/** * */ package de.saumya.mojo.ruby.gems; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.Collection; import java.util.List; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.plugin.descriptor.PluginDescriptor; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.FileUtils; import de.saumya.mojo.ruby.script.Script; import de.saumya.mojo.ruby.script.ScriptException; import de.saumya.mojo.ruby.script.ScriptFactory; public class GemsInstaller { private static final String OPENSSL_VERSION = "0.8.2"; private static final String OPENSSL = "jruby-openssl"; private static final FileFilter FILTER = new FileFilter() { public boolean accept(File f) { return f.getName().endsWith(".gemspec"); } }; public final GemsConfig config; public final ScriptFactory factory; public final GemManager manager; public GemsInstaller(final GemsConfig config, final ScriptFactory factory, final GemManager manager) { this.config = config; this.factory = factory; this.manager = manager; } public void installPom(final MavenProject pom) throws IOException, ScriptException, GemException { installGems(pom, null); } public void installPom(final MavenProject pom, final ArtifactRepository localRepository) throws IOException, ScriptException, GemException { installPom(pom, localRepository, null); } public void installPom(final MavenProject pom, final ArtifactRepository localRepository, String scope) throws IOException, ScriptException, GemException { installGems(pom, localRepository, scope); } public MavenProject installOpenSSLGem(final Object repositorySystemSession, final ArtifactRepository localRepository, List<ArtifactRepository> remotes) throws GemException, IOException, ScriptException { return installGem(OPENSSL, OPENSSL_VERSION, repositorySystemSession, localRepository, remotes); } public MavenProject installGem(final String name, final String version, final Object repositorySystemSession, final ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories) throws GemException, IOException, ScriptException { final Artifact artifact; if (version == null) { artifact = this.manager.createGemArtifactWithLatestVersion(name, localRepository, remoteRepositories); } else { artifact = this.manager.createGemArtifact(name, version); } final MavenProject pom = this.manager.buildPom(artifact, repositorySystemSession, localRepository, remoteRepositories); installPom(pom); return pom; } public void installGems(final MavenProject pom, final ArtifactRepository localRepository) throws IOException, ScriptException, GemException { installGems(pom, localRepository, null); } public void installGems(final MavenProject pom, final ArtifactRepository localRepository, String scope ) throws IOException, ScriptException, GemException { installGems(pom, (Collection<Artifact>)null, localRepository, scope); } public void installGems(final MavenProject pom, PluginDescriptor plugin, final ArtifactRepository localRepository) throws IOException, ScriptException, GemException { installGems(pom, plugin.getArtifacts(), localRepository, (String) null); } public void installGems(final MavenProject pom, final Collection<Artifact> artifacts, final ArtifactRepository localRepository, String scope) throws IOException, ScriptException, GemException { installGems(pom, artifacts, localRepository, pom.getRemoteArtifactRepositories(), scope); } public void installGems(final MavenProject pom, final Collection<Artifact> artifacts, final ArtifactRepository localRepository, List<ArtifactRepository> remoteRepos) throws IOException, ScriptException, GemException { installGems( pom, artifacts, localRepository, remoteRepos, null ); } public void installGems(final MavenProject pom, final Collection<Artifact> artifacts, final ArtifactRepository localRepository, List<ArtifactRepository> remoteRepos, String scope ) throws IOException, ScriptException, GemException { // start without script object. // script object will be created when first un-installed gem is found Script script = null; if (pom != null) { boolean hasAlreadyOpenSSL = false; for (final Artifact artifact : pom.getArtifacts()) { // assume pom.getBasedir() != null indicates the project pom if ( ( "compile".equals(artifact.getScope()) || "runtime".equals(artifact.getScope()) || pom.getBasedir() != null ) && ( scope == null || scope.equals(artifact.getScope()) ) ) { if (!artifact.getFile().exists()) { this.manager.resolve(artifact, localRepository, remoteRepos); } script = maybeAddArtifact(script, artifact); hasAlreadyOpenSSL = hasAlreadyOpenSSL || artifact.getArtifactId().equals(OPENSSL); } } if (artifacts != null) { for (final Artifact artifact : artifacts) { if (!artifact.getFile().exists()) { this.manager.resolve(artifact, localRepository, remoteRepos); } script = maybeAddArtifact(script, artifact); hasAlreadyOpenSSL = hasAlreadyOpenSSL || artifact.getArtifactId().equals(OPENSSL); } } if ( pom.getArtifact().getFile() != null // to filter out target/classes && pom.getArtifact().getFile().isFile() // have only gem files && pom.getArtifact().getFile().getName().endsWith(".gem") ) { script = maybeAddArtifact(script, pom.getArtifact()); } if (!this.config.skipJRubyOpenSSL() && !hasAlreadyOpenSSL && script != null) { // keep the version hard-coded to stay reproducible final Artifact openssl = this.manager.createGemArtifact(OPENSSL, OPENSSL_VERSION); if (pom.getFile() == null) { // we do not have a pom so we need the default gems repo this.manager.addDefaultGemRepositories(remoteRepos); } for(Artifact a : this.manager.resolve(openssl, localRepository, remoteRepos, true) ) { if (a.getFile() == null || !a.getFile().exists()) { this.manager.resolve(a, localRepository, remoteRepos); } script = maybeAddArtifact(script, a); } } } if (script != null) { script.addArg("--bindir", this.config.getBinDirectory()); if(this.config.getBinDirectory() != null && !this.config.getBinDirectory().exists()){ this.config.getBinDirectory().mkdirs(); } script.execute(); if (this.config.getGemHome() != null){ // workaround for unpatched: https://github.com/rubygems/rubygems/commit/21cccd55b823848c5e941093a615b0fdd6cd8bc7 for(File spec : new File(this.config.getGemHome(), "specifications").listFiles(FILTER)){ String content = FileUtils.fileRead(spec); FileUtils.fileWrite(spec.getAbsolutePath(), content.replaceFirst(" 00:00:00.000000000Z", "")); } } this.factory.newScript( "require 'jruby/commands'; JRuby::Commands.generate_dir_info '" + this.config.getGemHome() + "' if JRuby::Commands.respond_to? :generate_dir_info" ).execute(); } } private boolean exists(Artifact artifact) { // check if the specifications exists String basename = artifact.getArtifactId() + "-" + artifact.getVersion().replaceFirst("-SNAPSHOT$", ""); String universalJavaBasename = basename + "-universal-java.gemspec"; String javaBasename = basename + "-java.gemspec"; String rubyBasename = basename + ".gemspec"; for (File dir : this.config.getGemsDirectory()) { File specs = new File( dir.getParentFile(), "specifications" ); if (new File(specs, rubyBasename).exists() || new File(specs, javaBasename).exists() || new File(specs, universalJavaBasename).exists()) { return true; } } return false; } private Script maybeAddArtifact(Script script, final Artifact artifact) throws IOException, GemException { if (artifact.getType().contains("gem")) { if (!exists(artifact)) { if (script == null) { script = this.factory.newScriptFromJRubyJar("gem") .addArg("install") .addArg("--ignore-dependencies") .addArg(booleanArg(this.config.isAddRdoc(), "rdoc")) .addArg(booleanArg(this.config.isAddRI(), "ri")) .addArg(booleanArg(this.config.isUserInstall(), "user-install")) .addArg(booleanArg(this.config.isVerbose(), "verbose")); } if (artifact.getFile() != null) { script.addArg(artifact.getFile()); } } } return script; } private String booleanArg(final boolean flag, final String name) { return "--" + (flag ? "" : "no-") + name; } }