require 'uri' require 'tempfile' require 'fileutils' require 'rubygems' require 'rubygems/builder' require 'rubygems/installer' require 'set' # A modified maven_gemify module Gem class Maven3NotFound < StandardError; end #This is some of the worst stuff. I had to this because bundler will search #the index of specifications based on the name given in the GemFile which #includes the "mvn::" syntax. The rest of the ruby gem world #doesn't work on this name so I have to constantly convert to the maven name when #necessary for certain methods class MavenSpec < Gem::Specification alias_method :old_full_name, :full_name alias_method :old_full_gem_path, :full_gem_path alias_method :old_ruby, :to_ruby def to_ruby old_name=self.name self.name=Maven::Gemify2.mname(old_name) return_results = old_ruby self.name=old_name return_results end def full_name if @full_name.nil? #Needs to use the maven_name here not the gemname which has the "mvn:" stuff old_name=self.name self.name=Maven::Gemify2.mname(old_name) return_path = old_full_name self.name=old_name @full_name=return_path end @full_name end def full_gem_path if @full_gem_path.nil? #Needs to use the maven_name here not the gemname which has the "mvn:" stuff old_name=self.name self.name=Maven::Gemify2.mname(old_name) return_path = old_full_gem_path self.name=old_name @full_gem_path=return_path end @full_gem_path end end module Maven class Gemify2 attr_reader :repositories #repositories should be an array of urls def initialize(*repositories) maven # ensure maven initialized @repositories = Set.new if repositories.length > 0 @repositories.merge([repositories].flatten) end end def add_repository(repository_url) @repositories << repository_url end @@verbose = false def self.verbose? @@verbose || $DEBUG end def verbose? self.class.verbose? end def self.verbose=(v) @@verbose = v end private def self.maven_config @maven_config ||= Gem.configuration["maven"] || {} end def maven_config; self.class.maven_config; end def self.java_imports %w( org.codehaus.plexus.classworlds.ClassWorld org.codehaus.plexus.DefaultContainerConfiguration org.codehaus.plexus.DefaultPlexusContainer org.apache.maven.Maven org.apache.maven.repository.RepositorySystem org.apache.maven.execution.DefaultMavenExecutionRequest org.apache.maven.artifact.repository.MavenArtifactRepository org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout org.apache.maven.artifact.repository.ArtifactRepositoryPolicy javax.xml.stream.XMLStreamWriter javax.xml.stream.XMLOutputFactory javax.xml.stream.XMLStreamException ).each {|i| java_import i } end def self.create_maven require 'java' # done lazily, so we're not loading it all the time bin = nil if ENV['M2_HOME'] # use M2_HOME if set bin = File.join(ENV['M2_HOME'], "bin") else ENV['PATH'].split(File::PATH_SEPARATOR).detect do |path| mvn = File.join(path, "mvn") if File.exists?(mvn) if File.symlink?(mvn) link = File.readlink(mvn) if link =~ /^\// # is absolute path bin = File.dirname(File.expand_path(link)) else # is relative path so join with dir of the maven command bin = File.dirname(File.expand_path(File.join(File.dirname(mvn), link))) end else # is no link so just expand it bin = File.expand_path(path) end else nil end end end bin = "/usr/share/maven2/bin" if bin.nil? # OK let's try debian default if File.exists?(bin) @mvn = File.join(bin, "mvn") if Dir.glob(File.join(bin, "..", "lib", "maven-core-3.*jar")).size == 0 begin gem 'ruby-maven', ">=0" bin = File.dirname(Gem.bin_path('ruby-maven', "rmvn")) @mvn = File.join(bin, "rmvn") rescue LoadError bin = nil end end else bin = nil end raise Gem::Maven3NotFound.new("can not find maven3 installation. install ruby-maven with\n\n\tjruby -S gem install ruby-maven\n\n") if bin.nil? warn "Using Maven install at #{bin}" if verbose? boot = File.join(bin, "..", "boot") lib = File.join(bin, "..", "lib") ext = File.join(bin, "..", "ext") (Dir.glob(lib + "/*jar") + Dir.glob(boot + "/*jar")).each {|path| require path } java.lang.System.setProperty("classworlds.conf", File.join(bin, "m2.conf")) java.lang.System.setProperty("maven.home", File.join(bin, "..")) java_imports class_world = ClassWorld.new("plexus.core", java.lang.Thread.currentThread().getContextClassLoader()); config = DefaultContainerConfiguration.new config.set_class_world class_world config.set_name "ruby-tools" container = DefaultPlexusContainer.new(config); @@execution_request_populator = container.lookup(org.apache.maven.execution.MavenExecutionRequestPopulator.java_class) @@settings_builder = container.lookup(org.apache.maven.settings.building.SettingsBuilder.java_class ) container.lookup(Maven.java_class) end def self.maven @maven ||= create_maven end def maven; self.class.maven; end def self.temp_dir @temp_dir ||= begin d=Dir.mktmpdir at_exit {FileUtils.rm_rf(d.dup)} d end end def temp_dir self.class.temp_dir end def execute(goals, pomFile,props = {}) request = DefaultMavenExecutionRequest.new request.set_show_errors(true) props.each do |k,v| request.user_properties.put(k.to_s, v.to_s) end request.set_goals(goals) request.set_logging_level 0 request.setPom(java.io.File.new(pomFile)) if verbose? active_profiles = request.getActiveProfiles.collect{ |p| p.to_s } puts "active profiles:\n\t[#{active_profiles.join(', ')}]" puts "maven goals:" request.goals.each { |g| puts "\t#{g}" } puts "system properties:" request.getUserProperties.map.each { |k,v| puts "\t#{k} => #{v}" } puts end out = java.lang.System.out string_io = java.io.ByteArrayOutputStream.new java.lang.System.setOut(java.io.PrintStream.new(string_io)) result = maven.execute request java.lang.System.out = out has_exceptions = false result.exceptions.each do |e| has_exceptions = true e.print_stack_trace string_io.write(e.get_message.to_java_string.get_bytes) end raise string_io.to_s if has_exceptions string_io.to_s end def writeElement(xmlWriter,element_name, text) xmlWriter.writeStartElement(element_name.to_java) xmlWriter.writeCharacters(text.to_java) xmlWriter.writeEndElement end public def maven_name(gemname) self.class.mname(gemname) end #gemname==mvn:group_id:artifact_id def self.mname(gemname) gemname.gsub("mvn:","").gsub("-","_").gsub(".","_").gsub(":","_") end def get_versions(gemname) [] end def generate_spec(gemname, version) mname = maven_name(gemname) MavenSpec.new do |s| s.name = gemname s.date = '2010-04-28' s.summary = "Hola!" s.description = "A simple hello world gem" s.authors = ["Nick Quaranto"] s.email = 'nick@quaran.to' s.homepage = 'http://rubygems.org/gems/hola' s.version = version s.files = "lib/#{mname}.rb" end end def generate_gem(gemname, version) mname = maven_name(gemname) spec_file=generate_spec(gemname,version) # spec_file.name=mname #So that the gem's name is correct gemname=gemname.gsub("mvn:","") maven_parts = gemname.split(":") group_id = maven_parts[0] artifact_id = maven_parts[1] FileUtils.mkdir_p(File.join(temp_dir,"lib")) #Generate a dummy POM file that we'll use to run maven against #to resolve deps and generate a classpath pomfile=File.join(temp_dir,"pom.xml") puts "pomfile=#{pomfile}" out = java.io.BufferedOutputStream.new(java.io.FileOutputStream.new(pomfile.to_java)) outputFactory = XMLOutputFactory.newFactory() xmlStreamWriter = outputFactory.createXMLStreamWriter(out) xmlStreamWriter.writeStartDocument xmlStreamWriter.writeStartElement("project".to_java) writeElement(xmlStreamWriter,"groupId","org.hokiesuns.mavengemify") writeElement(xmlStreamWriter,"artifactId","mavengemify") writeElement(xmlStreamWriter,"modelVersion","4.0.0") writeElement(xmlStreamWriter,"version","1.0-SNAPSHOT") #Repositories if @repositories.length > 0 xmlStreamWriter.writeStartElement("repositories".to_java) @repositories.each_with_index {|repo,i| xmlStreamWriter.writeStartElement("repository".to_java) writeElement(xmlStreamWriter,"id","repository_#{i}") writeElement(xmlStreamWriter,"url",repo) xmlStreamWriter.writeEndElement #repository } xmlStreamWriter.writeEndElement #repositories end xmlStreamWriter.writeStartElement("dependencies".to_java) xmlStreamWriter.writeStartElement("dependency".to_java) writeElement(xmlStreamWriter,"groupId",group_id) writeElement(xmlStreamWriter,"artifactId",artifact_id) writeElement(xmlStreamWriter,"version",version.to_s) xmlStreamWriter.writeEndElement #dependency xmlStreamWriter.writeEndElement #dependencies xmlStreamWriter.writeEndElement #project xmlStreamWriter.writeEndDocument xmlStreamWriter.close out.close execute(["dependency:resolve","dependency:build-classpath"],pomfile,{"mdep.outputFile" => "cp.txt","mdep.fileSeparator"=>"/"}) ruby_file = File.new(File.join(temp_dir,"lib/#{mname}.rb"),"w") cp_file = File.new(File.join(temp_dir,"cp.txt"),"r") cp_line = cp_file.gets cp_file.close cp_entries = cp_line.split(";") cp_entries.each{ |entry| ruby_file.puts "require \"#{entry}\"" } ruby_file.close old_pwd = Dir.pwd Dir.chdir(temp_dir) gembuilder = Gem::Builder.new(spec_file) gemfile=gembuilder.build geminstaller = Gem::Installer.new(gemfile) geminstaller.install Dir.chdir(old_pwd) end end end end