Общие правила написания спек файлов в ALT Linux

Материал из ALT Linux Wiki

Источник

Статья импортирована из двух источников ftp://ftp.altlinux.org/pub/distributions/ALTLinux/Sisyphus/doc/alt-packaging/conventions.tex и ftp://ftp.altlinux.org/pub/distributions/ALTLinux/Sisyphus/doc/alt-packaging/spp.tex На Wiki уже есть аналогичные статьи, но я думаю, сама статья имеет определённый интерес. --HihinRuslan 11:02, 12 июня 2016 (MSK)

Автор статьи Dmitry V. Levin <ldv@altlinux.ru> ALT Linux Team

Обоснование

При разработке этих правил решались следующие задачи:

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

Spec-файлы.

Устаревшие конструкции.

Не следует использовать устаревшие конструкции - они лишь загромождают spec-файл, снижая тем самым его читабельность. К устаревшим конструкциям, в частности, относятся:

  • тэг BuildRoot:;
  • строки вида rm -rf $RPM_BUILD_ROOT;
  • %_defattr со стандартными аргументами в начале файлов и секций %files;
  • секция %clean, пустая либо без разумного содержания.

Фигурные скобки.

Нет смысла засорять текст spec-файла ненужными фигурными скобками. Избавится от них можно с помощью команды

cleanup_spec spec-файл

Выравнивание.

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

Порядок тэгов.

Рекомендуемый порядок заголовочных тэгов: Name, Version, Release, Epoch, далее Summary, License, Group, Url, Vcs, Packager, BuildArch, потом Source*, Patch*, далее Provides, Requires(pre):, Requires, Conflicts, Obsoletes, и, наконец, BuildRequires(pre):, BuildPreReq, BuildRequires. Разумеется, не все из вышеперечисленных тэгов используются, равно как встречаются и другие редко используемые тэги.

В связи с тем, что BuildRequires зарезервирован для автоматически вычисляемых с помощью buildreq зависимостей, для указания особых зависимостей следует использовать BuildPreReq. BuildRequires(pre): имеет особое значение в том числе для hasher. См. также Spec#BuildRequires, BuildPreReq, BuildRequires(pre).

Значения тэгов.

Значение тэга от его имени следует разделять одним пробелом. Элементы списка значений следует разделять запятой с последующим пробелом. Значение тэга Summary следует начинать с прописной буквы. Значение тэга Summary не следует завершать точкой. Значения тэгов Summary и %description могут содержать названия команд только в не измененном виде.

Номера релизов.

Значение тэга Release должно иметь вид

altREVISION

Eсли пакет содержит альфа-/бета-/пререлиз- версию какого-то программного обеспечения и параметр Version содержит будущий номер версии, то номер релиза такого пакета должен иметь вид

alt0.REVISION

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

BRANCH_POINT_RELEASE.BRANCH.REVISION

где:

REVISION
- номер ревизии пакета внутри репозитория, увеличивающийся при каждом обновлении;
BRANCH_POINT_RELEASE
- строка, описывающая релиз, из которого “растет” данная ветка;
BRANCH
- версия ветки (например, “M24” в “ALT Linux 2.4 Master”).

При обновлении до новой версии REVISION сбрасывается в 1 и, в случае старой ветки,
BRANCH_POINT_RELEASE устанавливается в “alt0”.

Группы.

Значение тэга Group должно соответствовать действительности и при этом принадлежать фиксированному множеству, перечисленному в файле /usr/lib/rpm/GROUPS.

ChangeLog.

При формировании первой строки changelog-записи используйте утилиту

add_changelog spec-файл

Описание изменений должно быть информативным; недостаточно объявить о наличии изменений, необходимо их все явно перечислить.

Файлы локализации.

Если в состав пакета входят файлы локализации либо другие файлы на разных языках, следует использовать макрос %find_lang. Подробную информацию можно получить, выполнив команду /usr/lib/rpm/find-lang -h.

Внутрипакетные зависимости.

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

Requires: %name = %version-%release

или

Requires: %name = %serial:%version-%release

Обратите внимание на синтаксис: знак равенства, в отличие от дефиса, окружен пробелами.

Разделяемые библиотеки.

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

Каждый пакет, содержащий разделяемые библиотеки в каталоге /lib, /usr/lib или /usr/X11R6/lib, должен их регистрировать при установке/обновлениях и удалении с помощью макросов %post_ldconfig и %postun_ldconfig соответственно.

Статические библиотеки.

Статические библиотеки должны паковаться в отдельные подпакеты, что связано со спецификой их использования. Если имя devel-подпакета заканчивается суффиксом -devel, то имя нового devel-static-подпакета будет заканчиваться суффиксом -devel-static. При разделении подпакетов следует помнить о внутрипакетных зависимостях: В списке зависимостей devel-static-подпакета должна присутствовать зависимость от -devel = %version-%release.

Переименование пакетов.

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

  • тэг Provides: старое_имя = %version
  • тэг Obsoletes: старое_имя

(Примечание: Реагирует ли сборочница на переименование пакетов.)

Патчи.

Наименование патчей.

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

NAME-VERSION-ORIGIN-WHAT.patch

где

  • NAME и VERSION – имя и версия пакета, для которого сделан патч;
  • ORIGIN - аббревиатуры источников патча (обычно дистрибутивов);
  • WHAT - краткое описание патча.

В случае, когда патч образован из нескольких частей, полученных из разных источников, компонента имени ORIGIN должна содержать аббревиатуры всех источников, перечисленные в порядке убывания важности. Если патч был создан или адаптирован для ALT Linux, то в ORIGIN, соответственно, должно присутствовать -alt-. Для патчей, взятых из репозитория, в котором разрабатывается программа (например, из CVS), компонента имени ORIGIN должна начинаться с cvs-YYYYMMDD. Исправления от основных разработчиков могут содержать "up" в поле ORIGIN.

Если описание патча WHAT состоит из нескольких слов, следует разделять их дефисами. Не следует использовать в этом качестве знаки подчёркивания.

При составлении описания патча следует иметь в виду следующие общепринятые сокращения:

makefile
патчи, затрагивающие исключительно makefile*;
bound
проверки на границы (буфера, целых чисел, и т.п.);
config
патчи, затрагивающие исключительно конфигурационные файлы;
configure
патчи, затрагивающие исключительно configure*;
doc
патчи, затрагивающие исключительно документацию;
fixes
кумулятивные патчи и/или исправления по надежности и/или безопасности;
format
патчи на использование форматирования строк (printf);
install
патчи, направленные на возможность выполнения “make install” непривилегированным пользователем;
linux
патчи, предназначенные для портирования ПО на Linux;
man
патчи, затрагивающие исключительно man-страницы;
texinfo
патчи, затрагивающие исключительно документацию в формате texinfo;
tmp
патчи, предназначенные для решения различных вопросов, связанных с временными файлами;
vitmp
патчи, направленные на поддержку vitmp(1);
warnings
патчи, исправляющие ошибки, найденные компилятором.

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

Исходный код.

Формат хранения.

Исходный код большого объема (как архивы, так и патчи, по статусу приравненные к ним) следует хранить в упакованном виде. Метод сжатия, gzip или bzip2, следует выбирать таким образом, чтобы размер архива был минимальным, например, с помощью утилиты zme. Исключение составляют nosurce-пакеты: в них отсутствующие файлы следует указывать в виде корректных URL.

См: ALT Linux packaging: ftp://ftp.altlinux.ru/pub/distributions/ALTLinux/Sisyphus/doc/alt-packaging/

Массовые операции над файлами и каталогами.

(секции: %setup, %build, %install, %pre*, %post*, %trigger*).

При массовой обработке файлов и каталогов (glob expansion, find и др.) НЕОБХОДИМО отделять команду с параметрами от списка аргументов разделителем “–” везде, где это поддерживается.

Обоснование: Массовые операции над файлами, имена которых начинаются на “-”, могут давать неверный результат в случае неиспользования “–”.

При использовании утилиты find для изменения файлов и каталогов НЕОБХОДИМО использовать параметр -print0; соответствующие ему параметры других утилит:

xargs
-r0
grep
-Z
sort
-z

Обоснование: Использование find при работе с каталогами, содержащими объекты с нестандартными именами (пробелами и др.), без использования -print0 приводит неправильному результату.

Пример использования:

find -type f -print0 |
    xargs -r0 %__grep -FZl 'mawk gawk' -- |
    xargs -r0 %__subst 's/mawk gawk/gawk mawk/g' --

Использование subshells.

Следует всеми силами избегать использовать subshells в скриптах сборки, установки/удаления и триггеров, так как они скрывают возможные ошибки. Если вы хотите временно сменить текущий каталог, лучше воспользуйтесь командами pushd и popd. Если же вам действительно необходимо использовать subshell, то предполагается, что вы передаете статус выполняемой команды процессу-предку самостоятельно.

Операции с временными файлами.

При необходимости создания временных файлов и/или каталогов в shell-скриптах следует использовать утилиту mktemp(1) совместно с командой trap, например:

TMPFILE="`mktemp -t progname.XXXXXXXXXX`" || exit 1
exit_handler()
{
    local rc=$?
    trap - EXIT
    rm -f -- "$TMPFILE"
    exit $rc
}
trap exit_handler EXIT HUP INT QUIT PIPE TERM

Не следует пользоваться фиксированными либо предсказуемыми именами для создания временных файлов в общедоступных каталогах, таких как /tmp. Не следует оставлять временные файлы в случае успешного окончания текущей стадии сборки пакета.

При использовании mktemp -t в shell-скриптах необходимо добавлять mktemp >= 1:1.3.1 в список зависимостей пакета.

Чужие и системные каталоги и файлы.

(секции: %install, %files).

Пакеты НЕ ДОЛЖНЫ включать в свой состав чужие каталоги и файлы, в частности, системные объекты файловой системы, а также файлы устройств (последнее - прерогатива пакета dev).

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

Атрибуты файлов и каталогов.

(секции: %install, %files).

Права доступа на привилегированные исполняемые файлы.

Привилегированные исполняемые файлы, т.е. исполняемые файлы с установленными битами suid и/или sgid, НЕ ДОЛЖНЫ быть доступны по чтению (и тем более по записи) кому-либо, кроме процессов с uid==0.

Разделы, предназначенные для использования readonly.

Пакеты НЕ ДОЛЖНЫ содержать файлы и каталоги в поддереве /usr, разрешающие доступ по записи кому-либо, кроме процессов с uid==0. Более того, программам, входящим в пакет, во время своей работы НЕ СЛЕДУЕТ полагаться на то, что файловые объекты, находящиеся в /usr, доступны по записи.

Файлы и каталоги, доступные для записи.

Пакеты НЕ ДОЛЖНЫ содержать файлы и каталоги, доступные для записи всем пользователям. Должны быть предусмотрены меры по разграничению доступа, например, путем предоставления доступа по записи определенной группе(ам).

Владельцы файлов.

Пакеты НЕ ДОЛЖНЫ содержать файлы, принадлежащие псевдо-пользователям, если в процессе работы к этим файлам осуществляется доступ процессов с другим uid либо с более широкими правами доступа. К таким файлам, в частности, относятся исполняемые, конфигурационные и неизменяемые файлы.

Обоснование: Псевдо-пользователь не должен иметь право изменять эти файлы; нарушение этого правила, как правило приводит к очевидной возможности осуществления pseudouser/root compromise.

Владельцы каталогов.

Пакеты НЕ ДОЛЖНЫ содержать каталоги, принадлежащие псевдо-пользователям. Вместо этого следует использовать каталоги, принадлежащие root, с установленным sticky bit и доступом группы по записи.

Обоснование: Псевдо-пользователь не должен иметь право изменять атрибуты каталогов, а также файлы и каталоги, созданные другими пользователями; нарушение этого правила, как правило приводит к возможности осуществления pseudouser/root compromise.

Блокировки.

(секции: %build, %install, %files).

Разные пакеты, использующие блокировки для работы с общими файловыми объектами, такими как mbox’ы, во избежание потери данных ДОЛЖНЫ придерживаться единого механизма блокировки.

Например, для блокировки mbox’ов НЕОБХОДИМО использовать метод, за которым закрепилось имя fcntl. Не допускается использование привилегированных программ для dotlocking’а.

Обоснование: Каждая привилегированная программа - это дополнительная степень риска для системы, в которой такая программа установлена. Поэтому следует минимизировать потребность в подобных средствах. Метод блокировки fcntl опирается на системный вызов fcntl(2), удовлетворяющий стандарту POSIX, и, следовательно, более широко распространенный, чем его аналог flock(2).