[devel] rebuild without bumping release

Alexey Tourbin alexey.tourbin на gmail.com
Пт Мар 29 13:43:48 MSK 2019


Мужчины, оказывается у вас теперь можно пересобирать пакеты без
увеличения релиса.  Файлы %{Name}-%{Version}-%{Release}.%{Arch}.rpm
в репозитории переписываются поверх старых, а apt будет обновлять
их по изменившемуся %{BuildTime}.  В связи с этим несколько технических
замечаний.

== Перезапись .src.rpm ==

При пересборке из /gears будет замещен .src.rpm пакет
https://bugzilla.altlinux.org/show_bug.cgi?id=27840#c16
тогда как почти всегда этого можно не делать.
В частности, если у .src.rpm пакета не изменились запакованные файлы
и зависимости, то этого точно можно не делать (это похоже на критерий
"extensional equality", который советует делать noarch пакеты).

Репозиторий src.rpm пакетов не бесполезен, на нем можно проверять
сборочные зависимости (почти так же, как apt-cache unmet проверят
установочные зависимости).  Строгая проверка, которая не дает ложных
срабатываний, возможна только для той архитектуры, для которой .src.rpm
файлы отбираются в files/SRPMS; по-моему сейчас это i586.  Вероятно,
есть смысл отбирать пакеты в files/SRPMS из x86_64, поскольку именно она
давно уже стала основной архитектурой.

== Перезапись .noarch.rpm ==

Пересборка без увеличения релиса удобна в случае пересборки клиентов
с новыми версиями библиотек; при этом noarch-подпакеты, такие как foo-doc,
должны остаться без изменений; их тоже можно было бы не замещать.
Но теперь они получат зависимости с disttag+task, и поэтому критерий
extensional equality к ним не применим (пересобранные пакеты всегда
будут отличаться из-за таска).  Возможно, стоило бы ослабить межпакетные
зависимости при пересечении границы arch/noarch: вместо EVR:disttag+task
требовать только EVR:disttag.  Это дало бы возможность не переписывать
noarch-пакеты.

Но ведь noarch-пакетами все не ограничивается.  Так, при пересборке
библиотеки по идее должен измениться только подпакет libfoo, а libfoo-devel
должен остаться прежним.  Хорошо бы не переписывать и libfoo-devel.
Сделать это, к сожалению, сложно.  Я продумывал схему, как передать в
rpmbuild информацию об уже имеющихся собранных подпакетах.  Тогда
в конце сборки rpmbuild сможет решить, какие подпакеты экзистенционально
равны, и скорректировать зависимости у некоторых подпакетов, чтобы
исключить переписывание/обновление.  Но это не работает как следует,
потому что у зависимостей есть направление: пакет libfoo-devel требует
libfoo.  Если в libfoo-devel зашита строгая зависимость на libfoo, то не
обновлять его нельзя.

Почему не удается придумать хорошей схемы с частичным переписыванием
подпакетов?  Может, это очевидно, но до меня почему-то не сразу дошло.
Строгие зависимости с EVR:disttag+task направлены на то, чтобы запретить
совмещение пакетов из разных сборок.  А частичное переписывание как раз
направлено на совмещение пакетов из разных сборок.  Это не просто
разные, а противоположные цели.

== Пропатчивание индексов ==

Переписывание *.rpm пакетов поверх старых усложняет генерацию нового
pkglist.classic файла на основе старого pkglist.classic файла (это еще
как следует не реализовано).  Если исходить из того, что сборочная
система не переписывает *.rpm пакеты, то перекомпоновка записей в
pkglist.classic реализуется легко: пусть имеется предыдущее состояние
pkglist.classic и новое состояние RPMS.classic/.  Тогда все записи из
pkglist.classic, для которых в RPMS.classic/ есть пакет, кочуют в новый
pkglist.classic (совпадения по имени .rpm файла достаточно).  

Теперь же совпадения по имени .rpm файла становится недостаточно.
Причем чтобы схема перекомпоновки работала быстро, нужно ограничиваться
только stat-информацией (читать каждый .rpm пакет - гиблое дело).
На практике для идентификации пакетов st_size+st_mtime работают достаточно
хорошо.  Тогда для сравнения записей и пакетов нужно хранить в записи
дополнительный таг, CRPMTAG_FILEMTIME (а CRPMTAG_FILESIZE уже хранится).
Поскольку там уже хранится и RPMTAG_BUILDTIME, то можно попытаться
отождествить FILEMTIME и BUILDTIME.  Для этого придется выставлять
st_mtime в BUILDTIME.  Но может это и не очень хорошо, поскольку
st_mtime может меняться по уважительной причине (из-за подписывания
пакета).

Вообще, чтобы перекомпоновка работала как следует, нужно держать две
версии записей: более полную версию в pkglist.classic+bloat и обычную
версию для пользователя pkglist.classic.  В pkglist.classic+bloat
у каждой записи будет полный список файлов, а в pkglist.classic -
урезанный, направленный на удовлетворение файловых зависимостей.
Поэтому обычный pkglist.classic использовать для перекомпоновки нельзя.
Потому что список требуемых файлов у каждой записи зависит от других
записей.  Так что новый genpkglist должен концептуально работать в два
прохода: сначала перекомпоновать pkglist.classic+bloat, а потом отжать
из него pkglist.classic.  При такой схеме хранить таг CRPMTAG_FILEMTIME
можно только в pkglist.classic+bloat.

Индекс pkglist.classic+bloat и псевдорепозиторий classic+bloat не
бесполезны, у них просматривается несколько применений:

- сборочная система в любом случае генерирует bloat-репозиторий,
  когда пакетов в таске больше одного;
- аналогично при сборке нескольких пакетов в хешере иногда возникают
  неудовлетворенные файловые зависимости; для обхода этой проблемы можно
  вручную скопировать пакет из репозитория в RPMS.hasher, но это тяжело
  автоматизировать; вместо этого можно будет настроить хешер на
  classic+bloat;
- генерация contents_index;
- отслеживание файловых конфликтов (об этом - в другой раз).


Подробная информация о списке рассылки Devel