2012-01-20 12 views
18

Sto lavorando su una gemma che ha bisogno di impostare le dipendenze in modo condizionale quando la gemma è installata. Ho fatto qualche ricerca intorno allocrea una gemma di rubino e specifica dipendenze condizionali

e sembra che non sia il solo a farlo.

Rubygems: How do I add platform-specific dependency?

questo è un lungo filo

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

L'unico modo che posso vedere per aggiungere le dipendenze a una gemma è quello di utilizzare il metodo add_dependency all'interno di un blocco Gem :: Specifiction in una. file 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 

Sulla base di tutti i documenti e thread che ho trovato in rete, mi sarei aspettato che t se si installa la gemma sul

  • Linux, quindi, rb-inotify sarebbe una dipendenza e auto-installato
  • Mac - rb-fsevent sarebbe stato installato
  • Windows - rb-fchange sarebbe installato

Tuttavia, sembra che non sia il caso. Le istruzioni "if" all'interno del blocco vengono valutate nel momento in cui la gemma viene creata e pacchettizzata. Pertanto, se si crea e si impacchetta la gemma su Linux, quindi, rb-inotify viene aggiunto come dipendenza, Mac, quindi, rb-fsevent, Windows - rb-fchange.

Ancora bisogno di una soluzione, ho scavato nel codice rubygems e sembra che il seguente è un ampio entusiasmo di ciò che accade.

  • costruire tutto il codice per il vostro gioiello: foo.gem
  • creare un file foo.gemspec
  • costruire, pacchetto, e rilasciare la gemma a un server gioiello come rubygems.org
  • fatecelo sapere allo
  • gli sviluppatori lo installano localmente tramite: gem install foo
  • il file foo.gem viene scaricato, decompresso e installato. anche tutte le dipendenze sono installate.
  • tutto dovrebbe essere impostato e possiamo iniziare usando la gemma.

Sembra che quando la gemma è costruito e rilasciato il file foo.gemspec viene caricato e il blocco Gem :: specifica viene valutata e convertita in YAML, compresso come metadata.gz, e incluso nel foo.gem . Il codice ruby ​​è compresso in data.tar.gz e incluso. Quando la gemma viene installata sul computer dello sviluppatore locale, , lo YAML viene estratto da metadata.gz e riconvertito in un blocco Gem :: Specification, tuttavia, non viene riconvertito nel blocco originale.

invece, si vedrà qualcosa di simile a quanto segue:

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.Quindi, ho una visione a volo d'uccello del processo, tuttavia, ciò non cambia il mio desiderio di costruire un singolo gioiello e di specificare condizionalmente le dipendenze per una gamma di obiettivi del sistema operativo.

Se qualcuno ha una soluzione diversa dalla costruzione di più file .gemspec per ogni sistema operativo di destinazione ... Sono tutte orecchie !!

+0

Guarda la mia risposta a http://stackoverflow.com/a/10249133/309514, funziona bene. – Fotios

risposta

0

Ho esaminato anche questo e sono giunto alla conclusione che non è possibile per progettazione. Avere un singolo "mega gem" per tutte le piattaforme causa il problema di non sapere se una piattaforma è supportata fino a quando la gem viene scaricata e installata. Una gemma dovrebbe essere abbastanza intelligente da determinare quale sia il modo corretto di installare a seconda della piattaforma. Se una piattaforma non è supportata affatto, la gemma potrebbe fallire in modo orribile, aprendo una grande scatola di worm. Ci sarebbe stata una richiamata dopo l'installazione di una gemma che è stata rimossa per lo stesso motivo, nessuna magia per far installare correttamente una gemma. Alcune persone lo hanno hackerato usando mkmf, ma suggerisco di seguire il percorso logoro di una gemma per piattaforma come la soluzione migliore.

Sulla base di questo, in un progetto che crea una gemma per rubino e jruby, devo creare manualmente ogni gemma e caricarli in RubyGem. Usare Jeweler questo è semplice come specificare il Gemfile, ma devo ricostruire le specifiche gemma ogni volta che pacco un gioiello. Abbastanza banale quando supporta solo 2 piattaforme, ma il processo di compilazione è abbastanza semplice da poter essere automatizzato per fornire supporto multipiattaforma di piattaforme.

1

In passato mi sono imbattuto in questo problema. L'unica soluzione alternativa che ho trovato è stata la creazione di un'attività Rake per l'installazione delle dipendenze. Ovviamente, a quel punto, potresti semplicemente voler permettere all'utente di capire da solo quale gemma è mancante in base al messaggio di errore che sta ricevendo. Nel mio caso, c'erano diverse dipendenze dipendenti dalla piattaforma da installare, quindi non era un'opzione.

Rakefile:

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

Installer:

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 

Quindi, l'utente può utilizzare per ottenere rake install installare le dipendenze appropriate.

L'installazione di dipendenze condizionali (non solo basata sulla piattaforma, ma basata sull'input dell'utente, ad esempio) è crudelmente mancante a RubyGems. Speriamo che venga implementato in futuro!