2012-01-20 4 views
18

estoy trabajando en una joya que tiene necesidades para establecer dependencias condicionalmente cuando se instala la gema. He hecho algo de investigación en tornoconstruir una gema de rubíes y de forma condicionada especificar dependencias

y parece que no estoy solo en esta necesidad.

Rubygems: How do I add platform-specific dependency?

este es un hilo largo

http://www.ruby-forum.com/topic/957999

La única manera que puedo ver a agregar dependencias a una joya es utilizar add_dependency método dentro de un bloque de la gema :: Specifiction en una. tha archivo gemspec

Gem::Specification.new do |s| 

    # ... standard setup stuff 

    # conditionally set dependencies 
    s.add_dependency "rb-inotify", "~> 0.8.8" if RUBY_PLATFORM =~ /linux/i 
    s.add_dependency "rb-fsevent", "~> 0.4.3.1" if RUBY_PLATFORM =~ /darwin/i 
    s.add_dependency "rb-fchange", "~> 0.0.5" if RUBY_PLATFORM =~ /mswin|mingw/i 

end 

sobre la base de todos los documentos y las discusiones que se encontró en la red, lo que habría esperado t si instala la joya en

  • Linux, entonces, rb-inotify sería una dependencia e instalado automáticamente
  • Mac - se instalaría rb-fsevent
  • de Windows - se instalaría rb-fchange

sin embargo, parece que no es el caso. Las declaraciones "if" dentro del bloque se evalúan en el momento en que se construye y empaqueta la gema. Por lo tanto, si compila y empaqueta la gema en Linux, entonces, rb-inotify se agrega como una dependencia, Mac, luego, rb-fsevent, Windows-rb-fchange.

Todavía necesitando una solución, Cavé alrededor en el código rubygems y parece que el siguiente es un amplio Stoke de lo que sucede.

  • construir todo el código para su joya: foo.gem
  • crear un archivo foo.gemspec
  • acumulación, paquete, y suelte la gema a un servidor joya como rubygems.org
  • dejar que todos sepan
  • desarrolladores lo instalan localmente a través de: gem install foo
  • el archivo foo.gem se descarga, desempaqueta e instala. todas las dependencias están instaladas también.
  • todo se debe configurar y podemos comenzar a usar la gema.

Parece que cuando la gema está construido y puesto en libertad el archivo foo.gemspec se carga y el bloque de la gema :: Especificación se evalúa y se convierte en YAML, comprime como metadata.gz, y se incluye en foo.gem . El código de ruby ​​se comprime en data.tar.gz y se incluye también. Cuando se instala la gema en la máquina local del desarrollador, , el YAML se extrae de metadata.gz y se convierte nuevamente en un bloque Gem :: Specification, sin embargo, no se convierte de nuevo al bloque original.

lugar, verá algo como lo siguiente:

Gem::Specification.new do |s| 

    if s.respond_to? :specification_version then 
    s.specification_version = 3 

    if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 
     s.add_runtime_dependency(%q<rb-inotify>, ["~> 0.8.8"]) 
    else 
     s.add_dependency(%q<rb-inotify>, ["~> 0.8.8"]) 
    end 
    else 
    s.add_dependency(%q<rb-inotify>, ["~> 0.8.8"]) 
    end 

end 

Ok.Entonces, tengo una vista panorámica del proceso, sin embargo, eso no cambia mi deseo de construir una sola gema y especificar condicionalmente las dependencias para un rango de objetivos de SO.

Si alguien tiene una solución que no sea crear múltiples archivos .gemspec para cada sistema operativo de destino ... ¡¡soy todo oídos !!

+0

Mira mi respuesta a http://stackoverflow.com/a/10249133/309514, funciona muy bien. – Fotios

Respuesta

0

He investigado esto también y he llegado a la conclusión de que no es posible por diseño. Tener una sola 'mega joya' para todas las plataformas provoca el problema de no saber si una plataforma es compatible hasta que la gema se descargue e instale. Una Gema debería ser lo suficientemente inteligente como para determinar la forma correcta de instalar según la plataforma. Si una plataforma no es compatible en absoluto, la gema puede fallar horriblemente, abriendo una gran lata de gusanos. Solía ​​haber una devolución de llamada después de que se instaló una gema que se eliminó por la misma razón, no hay magia para lograr que una gema se instale correctamente. Algunas personas han pirateado esto utilizando mkmf, pero sugiero seguir la trayectoria desgastada de una gema por plataforma como la mejor solución.

Basado en esto, en un proyecto que construye una gema para ruby ​​y jruby, tengo que crear manualmente cada gema y subirla a RubyGem. Usar Jeweler esto es tan simple como especificar el Gemfile, pero tengo que reconstruir la especificación de la gema cada vez que empaco una gema. Bastante trivial cuando se admiten solo 2 plataformas, pero el proceso de compilación es lo suficientemente sencillo como para que se pueda automatizar para proporcionar compatibilidad con múltiples gemas de plataforma.

1

También he tropezado con este problema en el pasado. La única solución que pude encontrar fue crear una tarea de Rake para instalar las dependencias. Por supuesto, en esa etapa, es posible que desee dejar que el usuario descubra por sí mismo qué gema le falta basándose en el mensaje de error que está recibiendo. En mi caso, había varias dependencias dependientes de la plataforma para ser instaladas, por lo que no era una opción.

Rakefile:

task :install do |t| 
    require './lib/library/installer' 
    Library::Installer.install 
end 

Instalador:

module Library::Installer 

    require 'rubygems/dependency_installer' 

    def self.install 
    installer = Gem::DependencyInstaller.new 
    dependency = case RUBY_PLATFORM 
     when /darwin/i then ["rb-fsevent", "~> 0.4.3.1"] 
     when /linux/i then ["rb-inotify", "~> 0.8.8"] 
     when /mswin|mingw/i then ["rb-fchange", "~> 0.0.5"] 
    end 
    installer.install(*dependency)   
end 

A continuación, el usuario puede utilizar para obtener rake install instalar las dependencias apropiadas.

La instalación de dependencia condicional (no solo basada en la plataforma, sino en función de la entrada del usuario, por ejemplo) es una cruel falta de RubyGems. ¡Esperamos que se implemente en el futuro!

Cuestiones relacionadas