DistroDB и DistroDB utils.

Уважаемые коллеги!

хотел бы продолжить рассказ о стеке решений для автоматизации.

Напомню, прошлый раз я выделял
* библиотеки и утилиты для преобразования или создания отдельного пакета.
* библиотеки и утилиты для обработки пакетов по списку на уровне репозиториев.
* утилиты обслуживания автономных нод (наподобие autoports.altlinux.org или
autoimports.altlinux.org).

Сегодня хочу рассказать о ведущейся разработке DistroDB utils.

Что это такое?

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

== DistroDB. Введение.

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

* SourceAnalyzer - библиотеки для генерации сборочных зависимостей
приложения по его исходным текстам (отдельно можно использовать 
через утилиту buildreq-src; собираюсь также встроить эту 
функциональность в утилиты общего назначения srpmnmu и srpmtool).

* DistroMap - базы данных и библиотеки для трансляции имен 
бинарных и исходных пакетов из одного дистрибутива в другой.
В частности, используется для трансляции сборочных и установочных
зависимостей в утилитах импорта.


Для работы SourceAnalyzer нужна база DistroDB.
Процесс создания баз DistroDB встроен в repocop, который ежедневно 
обновляет и выкладывает свежую базу DistroDB для скачивания.
Скачиваемый архив сейчас весит около 3мб.

Для упрощения скачиваения есть специальные утилиты

distrodb-update-repocop-db-altlinux-sisyphus -
скачивает базу DistroDB для Сизифа и распаковывает ее 
в ~/.cache/distrodb/altlinux/sisyphus

distrodb-update-repocop-db-altlinux-t6 - то же, но для t6.
~/.cache/distrodb/altlinux/t6

С появлением t7 будет и база DistroDB для t7.

база DistroDB содержит информацию в виде текстовых
таблиц, предназначенную для SourceAnalyzer.
Например, таблица devel-libs содержит информацию,
в каких пакетах содержится данная библиотека.
Записи там имеют вид
2geom   lib2geom-devel
3dkit   svgalib-devel
3ds     lib3ds-devel
...
означают, например, что -l3dkit, т.е. lib3dkit.so, 
содержится в пакете svgalib-devel.

Есть таблица path для имен executable приложений в default $PATH.
Есть таблица gir для .gir файлов, таблица headers для файлов в /usr/include,
таблица pkg-config для имен pkg-config файлов, таблицы perl, python2 и python3,
для поддержки этих скриптовых языков, таблица provides,
таблица sourcename для быстрого поиска имени исходного пакета по имени бинарного пакета,
и ряд других таблиц.

DistroDB находится в постоянной разработке, так же, как и SourceAnalyzer.
Например, сейчас в SourceAnalyzer еще нет поддержки ruby. Но когда она появится,
то она будет опираться на соответствующие таблицы для ruby в DistroDB.

repocop-report-distrodb является стандартным предпочтительным методом для генерации
DistroDB для репозитория пакетов. В настоящее время для генерации DistroDB
хватает той информации, которая содержится в rpm headers пакета, без заглядывания 
в собственно файлы пакета. 
Соответственно, в составе DistroDB utils существует и развивается другая утилита, 
которая создает большую часть таблиц базы DistroDB либо из индексов apt, 
либо из сырого набора бинарных пакетов.
Однако достаточно очевидно, что по мере развития SourceAnalyzer информации из 
rpm headers уже не будет хватать. 

Для примера, чтобы корректно отобразить модули питона, которые загружаются директивой
import, в имена пакетов, нужно еще заглядывать внутрь .so и .pth файлов.

Это же, кстати, хорошо было бы научить делать и python*.prov,
чтобы он находил там provides.

Поэтому repocop-report-distrodb в перспективе более удобен,
там легче заглядывать внутрь пакетов.

== DistroDB maintainance.

Алгоритм работы библиотеки SourceAnalyzer достаточно прост в случае, 
если найденная зависимость разрешается однозначно. Но что будет, 
если найденная зависимость разрешается неоднозначно? 
Например, найденное в файле configure.ac выражение AC_CHECK_LIB(png) 
распознается как зависимость на libpng.so. Но libpng.so 
предоставляется сразу двумя пакетами: libpng-devel и libpng12-devel.
Что делать в таком случае?

Рассчитанная на пользователя утилита buildreq-src из пакета perl-RPM-Source-Editor
в таком случае просто выдаст педупреждение и вставит в спек-файл пакета
сразу обе зависимости. Ясно, что с двумя конфликтующими зависимостями 
пакет заведомо не соберется, пользователю необходимо будет самостоятельно 
выбрать одну из зависимостей и удалить альтернативы, о чем его утилита 
и предупреждает.

Правда, buildreq-src ведет себя несколько умнее. Именно, если среди 
ее аргументов указан старый спек-файл пакета, то библиотека SourceAnalyzer
дополнительно проверяет, нет ли случаем одной из альтернатив
среди уже указанных имеющихся зависимостей пакета?

Если в спек-файле уже явно указано BuildRequires: libpng-devel 
или BuildRequires: libpng12-devel,
то утилита buildreq-src ничего тогда вставлять не будет.
Вообще здесь надо подчеркнуть, что утилита buildreq-src
ничего в спек-файле не удаляет, а только добавляет в спек-файл те зависимости,
которые обнаружены библиотекой SourceAnalyzer но явно не указаны в спек-файле.
Эти зависимости оформляются в отдельную секцию комментарием специального
вида, которую можно обновить (перегенерировать) опцией --update.

Однако, если зависимость на libpng неявная, и в спек-файле она явно не указана,
то разрешение конфликта между libpng-devel и libpng12-devel будет по-прежнему
переложено на плечи пользователя.

Для робота такое поведение, конечно, не годится.
В библиотеке RPM::Source::Convert::Plugins::DistroMap::SourceAnalyzer,
которая является оберткой над основной библиотекой SourceAnalyzer
(RPM::Source::Editor::Tools::SourceAnalyzer), реализован следующий
алгоритм: сначала проходит проверка, нет ли случаем одной из альтернатив
среди уже указанных имеющихся зависимостей пакета, как и для buildreq-src.
Например, если пакет импортируется, то у него уже есть набор зависимостей,
сконвертированных с помощью DisrtoMap.

Если же разрешение выбора альтернатив там не указано, то робот смотрит
в таблицы разрешения конфликтов. например, для libpng.so там выбран
пакет libpng-devel. Это разумное умолчание для сотен пакетов,
для тех же нескольких пакетов, которым нужен все-таки libpng12-devel,
это можно явно указать в настройках импорта данного конкретного пакета.

Проблема в том, что таблицы разрешения конфликтов сами представляют собой
большую БД. Как показывает утилита

./distrodb-list-duplicates.pl | sort -u | wc -l
1159

в Сизифе на момент ее запуска было 1159 наборов бинарных пакетов,
которые как-то между собой пересекаются по данным DistroDB, 
и тем самым для них надо в таблице разрешения конфликтов 
выбирать один пакет из набора.

Например, исходный пакет libpng там представлен двумя наборами 
пересекающихся бинарных пакетов: 
libpng12:libpng15 и libpng-devel:libpng12-devel, где

libpng12 и libpng15 слабо пересекаются по Provides: libpng,

libpng12-devel libpng-devel сильно пересекаются по 
bin: /usr/bin/libpng-config
devel-libs: libpng.so
headers: pngconf.h
headers: png.h
path: libpng-config
pkg-config: libpng

Поэтому таблицы разрешения конфликтов тоже нужно генерировать
отдельной утилитой из метатаблиц, в которых хранится набор пакетов
на момент выбора, выбранный пакет, и кем выбрано (явно человеком 
вручную или скриптом эвристики).

И нужен скрипт эвристики, чтобы не просматривать эти тысячи пар глазами,
а сократить число пар, где требуется вмешательство человека, до
десятков.

== DistroMap maintainance.

Создание и сопровождение баз DistroMap представляет собой гораздо более
ресурсоемкую задачу по сревнению с таблицами разрешения конфликтов.

Первая база DistroMap для отображения репозитория Fedora Rawhide 
в репозиторий ALTLinux Sisyphus создавалась на протяжении нескольких лет,
пока не достигла достаточной зрелости, позволяющей добиться достаточно
качественного импорта пакетов из репозитория Fedora Rawhide.

Здесь надо отметить, что при этом собственно Fedora-специфический код в
библиотеке импорта, молуль RPM::Source::Convert::Plugins::Fedora2ALT,
занимает всего 600 строк кода, что составляет доли процента в общем объеме кода.
Этот модуль занимается преобразованием специфических для Fedora синтаксических
конструкций в спек-файле, в основном макросов RPM.

Как видим, при условии наличия полноценной базы DistroMap,
добавление поддержки нового репозитория в библиотеки импорта
представляет собой достаточно легкую задачу, и наоборот, ее отсутствие
не позволяет проводить качественный импорт пакетов из репозитория,
даже при полной поддержке всех синтаксических конструкций.

Это подчеркивает важность и необходимость скриптов генерации баз DistroMap.

Однако разработанные в настоящий момент эвристики не покрывают все 100%
случаев, поэтому для баз DistroMap остается необходимость в явном
задании некоторых отображений вручную оператором,
Поэтому также важной является задача ухода за базой DistroMap,
так как нельзя просто перегенерировать базу - необходимо 
проверять, согласовывать и корректировать сгенерированную и
внесенную вручную информацию.

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

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

Таким образом, процесс генерации базы DistroMap трехступенчатый:
на первом этапе генерируются базы DistroDB рерозитория - источника и
репозитория назначения. На втором этапе создается генерируемая часть
базы DistroMap, на третьем этапе она и ранее внесенная вручную
информация совместно проверяются, согласовываются и корректируются.

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

Скрипты генерации и сопровождения находятся а разработке,
в качестве подопытной морской свинки выступает репозиторий "Mageia".

== Сопровождение списков задач для автономных нод.

Списки задач для автономных нод неразрывно связаны с
DistroMap. Именно, список начального импорта получается как разность
списка пакетов репозитория — источника, преобразованного обратным
отображением  DistroMap  списка пакетов репозитория — приемника и
списка исключений. 

Также, список пакетов в autoimpots необходимо периодически проверять
на пересечение с  преобразованным обратным отображением  DistroMap
списком пакетов основного репозитория — приемника. 

Соответствующие утилиты также реализованы в составе distrodb-utils. 
