Ruby Policy 2.0
Ruby Policy
Rules for ruby module and application packages
Introduction
Ruby and modularity
NOTE: To simplify link usage, they will be treated as for 2.6.1 ruby version.
The ruby language have the modularity feature begginging with the day-spring of its invention in 1993th, so if we have the core functions of ruby are placed into the libruby.so, are built-in part of the language, then ruby's standard library is modularized, and its modules are resided in the /usr/lib/ruby/ folder that has the interpreted modules inside the consequently named folders. For example: parser module is placed in the racc module:
/usr/lib/ruby/racc/parser.rb
Inside the folder named as <arch>-<os>, there are some compiled parts for the respective modules, so 'cparse modules is placed in racc module:
/usr/lib/ruby/x86_64-linux/racc/cparse.so
Therefore the when a side library (module) ought to be be used in ordinal ruby applications, then its library modules must be placed into the respective folders in /usr/lib/ruby/site_ruby/, and the last is the only place to reside libraries not from the ruby standard set.
В нынешней ситуации действительной на 2019 год, для развертывания дополнительных модулей используются модули rubygems и bundler, ныне поставляющиеся в виде пакета вида с англоязычным назанием gem (русское название бисер будет употребляться далее), хотя первый был когда-то обычным сторонним модулем. Проект rubygems был начат в апреле 2009, bundler четырьмя месяцами позднее в августе того же года. На текущий момент пара этих бисеров является по праву и на деле единственной системой определения зависимостей рубишной системы.
Зависимости в текущих проектах руби бывают 2-х видов:
- через <gem>.gemspec;
- через Gemfile.
.gemspec является единственным файлом описания зависимостей для системы rubygems бисеров, зависимости в котором могут быть скучены в 2 группы, зависимости исполения (runtime), и зависимости разработки (development), и последние также используются для тестирования проектов.
Gemfile является файлом описания как зависимостей разработки для бисеров (в дополнение к .gemspec), а также зависимостей различного рода для иных проектов, напр. для окружений разработки, тестирования, боевого, и прочих, не являющихся собственно бисерами. В современных проектах для рельс (rails), или других напр. синатры (sinatra), файла требуемые для определенного окружения описываются практически полностью только файлом Gemfile, то есть bundler сам решает в зависимости от писанного в том файле какие бисеры и их модули загружать для текущего окружения. Что во многих проектах приводит к тому, что явные вызовы метода require опускаются, например в проектах chef, puppet, или foreman современных версий. Типичный Gemfile можно найти тут.
Зависимости на версию ruby также определяется на основе Gemfile и .gemspec.
Версионирование
В руби и подсистеме бисеров для изменения правок бисеров применяется так называемый подход семантического версионирования, при котором первое число отражает "великое" изменение в библиотеке, когда меняется скажем API, второе число - "малое" изменение, при добавлении функциональности без ломки обратной совместимости, а третье - заплаточное изменение (patch number).
Сравнение с предыдущей политикою
Собственно подход с поиском зависимостей сугубо по вызовам метода require к текущему моменту существенно ограничивается следующими моментами:
- вызовы этого метода не всегда являются определяющими для точного обнаружения и составления списка зависимостей, для бисеров, а в большей мере для проектов на основе Gemfile, поскольку в коде могут быть фиктивные вызовы обрамленные некоторым кодом, который делает этот вызов не обязательным, но возможным для работы бисера;
- для Gemfile проектов потому, что вызовы require являются неявными и выполняются bundler-ом опосредованно на основе анализа Gemfile и .gemspec если таковой присутствует. также bundler следит за тем, чтобы среда и окружение разработки таких проектов были целостными, это приводит к том, что вызов require к внешнему модулю при необъявленная зависимость на него в Gemfile, приведет к критическому затруднения разработки проекта;
- имя внешнего модуля не всегда может быть извлечено из анализа вызова require, из-за нестанрдартного объявления имен модулей в таких библиотеках, напр. бисер имеет имя 'foo-bar', модули в нем могу быть вида: FooBar, FooBar, или Foo/Bar, с файловыми соответствиями foo_bar, foo/bar, последний вызовет ложное срабатывание на модуль с именем foo;
- из-за неявности загрузки как внешних модулей проекта, поскольку вызовы require к внешним библиотекам делает сам bundler;
- методика определения зависимостей из require не способна проконтролировать версии API зависимого пакета при смене оного, особенно в случае, когда под зависимостям на деле пакету требуется старое, и необновленное API.
Посему в нынешнюю пору намного надежнее использовать анализ пары Gemfile/.gemspec файлов для определения зависимостей.
Пакет ruby
В системе может быть только единственная библиотека libruby, с единственным набором модулей stdlibs.
При сборке новой версии libruby должны быть пересобраны все модули stdlibs, также все бисеры, которые содержат подгружаемые .so библиотеки, и все модули, для которых в файлах Gemfile/.gemspec прописано явное требование к версии руби, которое удовлетворяет новая версия libruby.
Внешний вид пакета
- пакеты собранные на основе бисера имеют префикс gem-;
- исходные пакеты с приложениями на рельсах, синатре или подобных средах могут быть без префикса, при конфликтах возможен префикс rubyapp-;
- модули stdlibs, а также иные проекты, не попадающие в предыдущие два пункта, и библиотеки которых кладутся в папку site_ruby, должны иметь префикс ruby-;
- символы подчёркивания "_" заменяются в имени пакета на символы дефиса "-".
Зависимости
Зависимости теперь отслеживаются на основе анализа пары Gemfile/.gemspec.
Экспорт зависимостей на бисеры имеет вид gem(gemname) = version и rubygem(gemname) = version, для совместимости с пакетами rpm от redhat.
Конфликт зависимостей
В случае конфликта зависимостей применяются один из двух способов их разрешения:
- в случае сохранения работоспособности бисера следует применять схему с явным объявлением макроса подмены версии требуемой библиотеки, имеющим имя gem_replace_version, напр. с ~> 1.1.7 на ~> 1.7:
%gem_replace_version '~> 1.1.7' '~> 1.7'
- поскольку bundler позволяет хранить в одном и том же дереве бисеров несколько версий для каждого из них, а система альта такого не позволяет делать, требуется создание пакета совместимости версии, который будет содержать заполненную дефисами версию бисера без заплаточного числа (patch number), в дополнение к его имени, напр. такой бисер compat-gem будет иметь имя пакета: gem-compat-gem-1-2-1.2.0.src.rpm;
- зависимость бисеров, в которых явным образом проводится сборка библиотек .so из исходников, автоматически проставляется зависимость на текущую версию руби, чтобы при пересборке самого руби с новой версиею, при ее изменении принудительно приходилось пересобирать и такие пакеты.
Макросы RPM
Макросы, требуемые для опакечивания бисеров и приложений руби, определены в rpm-, который советуем объявить в спецификации пакета в сборочном требовании в пометой (pre), так BuildRequires(pre): rpm-build-ruby:
Сборочные макросы таковы:
%__ruby %_bindir/ruby %__setup_rb %_bindir/setup.rb %ruby_func() %__ruby -rrubygems -rrbconfig -e %* %ruby_rubyconf_func() %__ruby -rrubygems -rrbconfig -e 'print RbConfig::CONFIG["%*"]' %ruby_gemspecdir %(%ruby_func 'print File.join( Gem.dir, "specifications" )') %ruby_gemextdir %(%ruby_func 'print File.join( Gem.dir, "extensions", RbConfig::CONFIG["sitearch"], RbConfig::CONFIG["ruby_version"] )') %ruby_gemlibdir %(%ruby_func 'print File.join( Gem.dir, "gems" )') %ruby_ridir %(%ruby_rubyconf_func ridir) %gem_build %__setup_rb build %gem_install %__setup_rb install --install_prefix=%buildroot %gem_test %__setup_rb test %gem_show %__setup_rb show --install_prefix=%buildroot
Расположение файлов
Файлы бисеров будут располагаться в соответствующих подпапках для бисеров папки /usr/lib/ruby/gems/2.5.0/, где 2.5.0 версия руби без учета заплаточного числа.
Заметки по спецификации пакета
- также пакеты содержащие основной код бисера, должны иметь группу Development/Ruby. А пакеты содержащие исполняемый код из того или иного бисера, должны иметь группу соответствующую назначению пакета;
- пакеты, не содержащие двоичного исполняемого кода модуля, должны содержать явное объявление архитектуры noarch.
Типовой .spec
Для исправления старых или сломанных пактов, а также создания новых можно использовать такой типовой файл спецификации:
%define pkgname gemmodule Name: ruby-%pkgname Version: 0.0.0 Release: alt1 Summary: summary Group: Development/Ruby License: <LICENSE> URL: https://site.org/ # VCS: https://github.com/user/gemmodule.git Source: %pkgname-%version.tar BuildRequires(pre): rpm-build-ruby BuildRequires: gem(another_gem) %description %summary %package -n %pkgname Summary: summary Group: Development/Other BuildArch: noarch %description -n %pkgname %summary %package doc Summary: Documentation for <package> Group: Development/Documentation BuildArch: noarch %description doc Documentation for <package>. %prep %setup -q -n %pkgname-%version %build %gem_build %install %gem_show %gem_install %check %gem_test %files %rubygem_gemdir/* %rubygem_extdir/* %rubygem_specdir/* %files -n %pkgname %_bindir/* %files doc %ruby_ridir/* %changelog
Тестирование
Тестирование пакетов руби подсистемы проводится с помощью пакета gem-setup, который определяет и запускает необходимые для проверки руби пакета тесты, определенные в Gemspec/.gemspec. Для включения тестирования пакета необходимо включать в .spec пакета явные требования к зависимым пакетам на этапе сборки, напр.:
BuildRequires: gem(another_gem) >= 1.0
Правила перехода на схему сию
- Все зависимости Requires для всех подпакетов определяются автоматически, посему все такие зависимости должны быть отвержены;
- Зависимости BuildRequires для пакета в случае, если проводится тестиование (раздел %check) или если это является крайне необходимым, должны быть прописаны явно, получены они могут быть с помощью приложения setup.rb;
- Также в случае, если пакет был переименован, требуется явным образом прописать в Provides старое имя пакета;
- В разделе %prep отвергаются все макросы указывающие на ruby, в частности %update_setup_rb;
- В разделе %build все макросы указывающие на ruby, например %ruby_build, %ruby_config заменяются на %gem_build;
- В разделе %install все макросы указывающие на ruby заменяются на %gem_install;
- В разделе %check все макросы указывающие на ruby заменяются на %gem_test, хотя при крайней и неотложной необходимсти этот макрос может быть засерен;
- В разделе %files для корневого пакета заменяются следующие макросы %[ruby]gem_specdir на %ruby_gemspecdir, %ruby_sitelibdir на %ruby_gemlibdir, %ruby_sitearchdir на %ruby_gemextdir;
- В разделе %files для пакета документации %ruby_ri_sitedir макрос заменяется на %ruby_ridir.
Автоматизация
Для автоматизации надзора и обновления рубишных пакетов используется бисер gem-rubobot, который будет выполнять следующие функции:
- проводить надзор за новыми версиями пакетов и уведомлять об их появлении на rubygems.org;
- проводить надзор за новыми версиями руби и уведомлять об их появлении;
- осуществлять контроль целостности подсистемы бисеров с помощью специально созданного Gemfile;
- при достижении числа скачиваний бисера более определенного значения (по умолчанию 1 миллион), в автоматизированном пытаться опакечивать такой бисер, и уведомлять в случае как успеха, так и обратном случае;
- в автоматическом режиме пытаться обновить бисеры с учётом сохранения целостности бисерной подсистемы и уведомлять в случае невозможности обновить бисерный пакет;
- в автоматическом режиме пытаться обновить пакеты с приложениями на руби, который здесь также подразумевает попытку собирать приложение с заменой версии с помощью макроса, и уведомлять при невозможности собрать пакеты с приведенными правками;
- в полуавтоматическом режиме (то есть по прямой указивке оператора) собирать приложения руби с автоматическим созданием пакетов совместимости.
- в полуавтоматическом режиме (то есть по прямой указивке оператора) собирать руби с автоматическою пересборкою необходимых пакетов по зависимостям.