Ruby Bundler — несколько версий Ruby в одном файле gemfile

#ruby #rubygems #bundler

#ruby #rubygems #bundler

Вопрос:

Я использую rbenv и bundler на macos.

Мне нужно поддерживать несколько версий Ruby для моего приложения. В частности, 2.2.4 и 2.5.5. У разных пользователей будут разные версии.

В настоящее время я работаю только с 2.2.4, поэтому я делаю следующее. Мой gemfile выглядит так

 source "https://rubygems.org"
ruby '2.2.4'

gem "net-ssh", "4.1.0"
gem "net-scp", "2.0.0"
.....
  

Для установки я запускаю bundle install , а затем для развертывания с моим приложением я запускаю

 bundle install --deployment --path src/mct-tools/ext/gems
  

Это создает папку src/mct-tools/ext/gems/ruby/2.2.0 в моем приложении, которую я затем распространяю.

Теперь я хотел бы добавить ruby 2.5.5 с обновленными gems, поэтому мне было интересно, будет ли приемлемо иметь gemfile, похожий на этот

 source "https://rubygems.org"
ruby '2.2.4'

gem "net-ssh", "4.1.0"
gem "net-scp", "2.0.0"
.....

ruby '2.5.5'

gem "net-ssh", "6.1.0"
gem "net-scp", "3.0.0"
.....
  

так что при развертывании bundle install --deployment --path src/mct-tools/ext/gems две версии добавляются в папку gems.

Это правильный подход? Альтернативой было бы указать два разных файла gemfile для каждой версии, а затем переключаться между ними.

Комментарии:

1. Извините, если это звучит ехидно, но… Почему?? Вы должны ожидать, что пользователи вашего приложения установят четко определенный список зависимостей. Если у одного клиента более старая версия приложения, которая давно не обновлялась, это раздражает, но нормально — они могут догнать позже и установить все новые зависимости.

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

3. Теоретически вы правы. Однако я использую Ruby для написания плагинов для другого программного обеспечения (SketchUp, если вам интересно). Разные версии SketchUp поддерживают разные версии Ruby. Некоторые клиенты не хотят обновлять свое программное обеспечение, потому что это дорого или по какой-либо другой причине. Самая обновленная версия Ruby просто не будет работать в предыдущей версии программного обеспечения. Если я хочу их поддерживать, мне нужно обрабатывать разные версии.

4. @TomLord Я надеюсь, что в какой-то момент все обновятся, чтобы я мог избавиться от старой версии.

5. Вы должны протестировать несколько версий, но ваш вариант использования противоречит указанию жестко запрограммированной версии Ruby в качестве зависимости в вашем дереве исходных текстов. Я предоставляю более подробное объяснение и несколько различных альтернатив ниже.

Ответ №1:

Gemfiles объявляют зависимости

Gemfile объявляет зависимость от версии Ruby с ограничениями семантического управления версиями или без них. Он не предназначен для управления несколькими целями сборки для вашего приложения. Это просто гарантирует, что версия Ruby, доступная для вашего приложения / gem, соответствует тому, что вы определили. Например:

 # Will fail if run with a different RUBY_VERSION.
ruby '2.2.4'

# Allows RUBY_VERSION >= 2.2.4, but <= 2.3.
ruby '~> 2.2.4'

# Allows either Ruby 2.2.4  or 2.5.5 , with
# a minimum (but no maximum) patch version.
ruby '~> 2.2.4', '~> 2.5.5'
  

Однако он не будет устанавливать данный Ruby и не будет делать ничего, кроме как выдавать ошибку и ненулевое состояние выхода при запуске bundler install . Вам нужно использовать другой подход для тестирования нескольких целей.

Изменение целей сборки с помощью инструментов непрерывной интеграции (CI)

Если вы используете внешний CI, такой как TravisCI, вы можете создать матрицу сборки, предназначенную для нескольких версий Ruby для тестирования. Вам решать, удаляете ли вы ограничение версии Ruby вообще или указываете поддерживаемый диапазон. Использование вашего инструмента CI для сборки с версиями Ruby, которые вы планируете поддерживать, действительно лучший подход, независимо от того, ограничиваете ли вы время выполнения Ruby в файле Gemfile.

Например, вы можете использовать матрицу в своем travis.yml вот так:

 language: ruby
rvm:
  - 2.2.4
  - 2.5.5
  

Переключение файлов Gemfile

Если вы настаиваете на том, чтобы делать это так, как вы это делаете, с единственной версией Ruby, разрешенной в вашем файле Gemfile, тогда вы можете рассмотреть возможность наличия двух отдельных файлов gemfile с разными именами в вашем дереве исходных текстов, таких как Gemfile-2.2.4 и Gemfile-2.5.5. Затем вы можете указать, какой файл --gemfile Gemfile использовать сустановите флажок или символически свяжите пользовательский файл Gemfile с canonical Gemfile для вашего проекта.

Вот несколько примеров для рассмотрения:

 # Resolve against a specific Gemfile with
# hard-coded Ruby version.

$ ls Gemfile*
Gemfile-2.2.4  Gemfile-2.5.5

$ bundle install --gemfile="Gemfile-2.2.4"
  
 # Resolve against whatever custom file is
# symlinked to your ./Gemfile.

$ ln -sf Gemfile{-2.5.5,}

$ ls -F Gemfile*
Gemfile@       Gemfile-2.2.4  Gemfile-2.5.5

$ bundle install
  

Оба подхода работают, но первый является более гибким за счет необходимости каждый раз указывать выбранный вами файл Gemfile, в то время как второй может помочь, когда у вас есть рабочий процесс разработки / тестирования, который не поддерживает --gemfile флаг Bundler.

Изменение Rubies с помощью Ruby Manager

Если у вас в разработке несколько версий Ruby, лучше всего использовать менеджер версий, такой как rvm, rbenv или chruby. Вы можете использовать свой менеджер версий для изменения rubies туда и обратно вручную по мере необходимости.

Вы также можете проверить, поддерживает ли ваш менеджер версий автоматическое включение .ruby-version или другие файлы конфигурации. Вам все равно придется обновлять этот файл каждый раз, когда вы хотите выполнить сборку или тестирование на другом Ruby, но вам не придется постоянно изменять содержимое вашего Gemfile, повторно указывать символическую ссылку Gemfile или обновлять флаг при каждом вызове Bundler.

Будет ли какой-либо данный подход лучше других, будет зависеть от вашего рабочего процесса. Ни одно техническое решение не подходит для всех обстоятельств, поэтому ваш пробег может законно отличаться.

Комментарии:

1. Спасибо за отличное объяснение. Я думаю, что попробую с несколькими файлами gemfile.