Подтвердить что ты не робот

Построить рубиновый камень и условно определить зависимости

Я работаю над самоцветом, которому необходимо установить зависимости условно, когда камень установлен. Я проделал кое-какие операции вокруг

и похоже, что я не одинок в этой необходимости.

Rubygems: как добавить зависимую от платформы зависимость?

это длинный поток

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

Единственный способ, с помощью которого я могу добавить зависимости к gem, - это использовать метод add_dependency в блоке Gem:: Specifiction в файле .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

Основываясь на всех документах и ​​потоках, найденных в сети, я ожидал, что если вы установите драгоценный камень на

  • Linux, тогда rb-inotify будет зависимым и автоматически установленным
  • Mac-rb-fsevent будет установлен
  • Windows-rb-fchange будет установлен

Однако, похоже, это не так. Операторы "if" внутри блока оцениваются во время создания и упаковки драгоценного камня. Следовательно, если вы создаете и упаковываете драгоценный камень в Linux, тогда rb-inotify добавляется как зависимость, Mac, затем rb-fsevent, Windows-rb-fchange.

Все еще нуждаясь в решении, я выкопался в коде rubygems, и, похоже, следующее - это широкий ответ о том, что происходит.

  • постройте весь свой код для своего драгоценного камня: foo.gem
  • создать файл foo.gemspec
  • построить, пакет и выпустить драгоценный камень на сервер драгоценных камней, например rubygems.org
  • пусть все знают
  • разработчики устанавливают его локально через: gem install foo
  • файл foo.gem загружается, распаковывается и устанавливается. все зависимости также установлены.
  • все должно быть установлено, и мы можем попросить использовать драгоценный камень.

Похоже, что когда камень построен и выпущен, файл foo.gemspec загружается и блок Gem:: Specification вычисляется и преобразуется в YAML, сжатый как metadata.gz и включен в foo.gem. Код ruby ​​сжимается в data.tar.gz и включается также. Когда камень установлен на локальной машине разработчика, YAML извлекается из metadata.gz и преобразуется обратно в блок Gem:: Specification, однако он не преобразовывается обратно в исходный блок.

вместо этого вы увидите что-то вроде следующего:

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. Тем не менее, у меня есть взгляд на птицу, но это не меняет моего желания построить один драгоценный камень и условно определять зависимости для целого ряда целей ОС.

Если у кого-то есть решение, отличное от создания нескольких файлов .gemspec для каждой целевой ОС... Я все уши!

4b9b3361

Ответ 1

Я никогда не делал этого сам, но есть некоторые драгоценные камни, которые доступны в конкретных версиях платформы: http://rubygems.org/gems/libv8/versions

от того, что я понимаю, это всего лишь именование, которое можно настроить, установив платформенный вариант вашего gemspec. взгляните на документ: http://guides.rubygems.org/specification-reference/#platform=

Ответ 2

Я также наткнулся на эту проблему в прошлом. Единственным обходным решением, которое я смог найти, было создание задачи Rake для установки зависимостей. Конечно, на этом этапе вы можете просто хотеть, чтобы пользователь сам определил, какой жемчуг он отсутствует на основании сообщения об ошибке, которое он получает. В моем случае было установлено несколько зависимых от платформы зависимостей, поэтому это не вариант.

Rakefile:

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

Установщик:

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

Затем пользователь может использовать rake install для установки соответствующих зависимостей.

Условная установка зависимостей (не только основанная на платформе, но и основанная на пользовательском вводе, например) жестоко отсутствует для RubyGems. Пусть надеется, что это будет реализовано в будущем!

Ответ 3

Я также изучил это и пришел к выводу, что это невозможно по дизайну. Наличие единого "мега-жемчужина" для всех платформ вызывает проблему незнания поддержки платформы, пока не будет загружена и установлена ​​копия. Драгоценный камень должен был быть достаточно умным, чтобы определить, какой правильный способ установить в зависимости от платформы. Если платформа вообще не поддерживается, жемчужина может сильно потерпеть неудачу, открыв большую банку червей. Там используется обратный вызов после того, как был установлен камень, который был удален по той же причине, без магии, чтобы правильно установить жемчужину. Некоторые люди взломали это, используя mkmf, но я предлагаю использовать более дорогой путь драгоценного камня на платформу.

Основываясь на этом, в проекте, который создает драгоценный камень для ruby ​​и jruby, я должен вручную создать каждый камень и загрузить их в RubyGem. Используя Jeweler, это так же просто, как указано Gemfile, но мне нужно перестроить спецификацию gem каждый раз, когда я упаковываю драгоценный камень. Довольно тривиально, когда поддерживаем только 2 платформы, но процесс сборки достаточно прост, чтобы его можно было автоматизировать, чтобы обеспечить поддержку многоплатформенных камней.