Знакомство со схемой упаковки pam-pkcs11
На примере pam_pkcs11 познакомимся с одной довольно удобной схемой организации gear-репозитория.
Зачем такая схема gear-репозитория?
Удобства такой схемы:
- Подходит для pull-request-ов к upstream-ному проекту.
- Поддерживается дисциплина, при которой ясно (читающему и любому новому мейнтейнеру) актуальное состояние набора патчей и актуальный вид каждого патча (а не так, что исходное изменение утонуло глубоко в историю -- но этого мало -- ещё и претерпевало изменение во время мёрджей с апстримом, при этом актуальность изначальной задумки и правильность результата никому непонятна, кроме, возможно, тех, кто делал мёрджи).
Неудобства такой схемы:
- Много merg-ей. (Но это только для мейнтейнера пакета, а не в потенциальных pull-request-ах.)
- Длинные .gear/rules. (Но это необязательно считать явным неудобством, т.к. там каждая запись на самом деле осмысленна, по делу, выражает имеющиеся патчи, и прочитать .gear/rules достаточно, чтобы понять, какие сделаны патчи.)
- Сложные .gear/rules в случае взаимозависимых патчей.
Когда я брался за чужой незнакомый пакет с утонувшими патчами, иногда было ничего непонятно в мешанине кода. Переделка (довольно трудоёмкая на начальном этапе взятия чужого пакета) в такую схему приводит к большей ясности для себя и других.
Основа схемы. Апстримный тег с версией
Схема такая.
Есть тег, соответствующий апстримной версии. От него ответвляются ветки (на разные темы) с нашими изменениями. И так в общем случае для каждой апстримной версии; это отражено в именах веток с патчами: в их именах присутствует апстримная версия.
Соотвествие между ветками и файлами с патчами
Получается, что имена веток с патчами соответствуют именам самих файлов с патчами, которые в ALT Packaging HOWTO рекомендуется давать со включением базовой апстримной версии. Т.е. соответствие очень простое.
Сюда же укладывается возможное "отклонение" от общего случая: Вы бы не стали специально переделывать файл с патчем, если он прикладывается к новой версии апстрима. В имени файла осталась бы старая версия. Так же менять соответствующее diff
-правило в .gear/rules и соотвествующую сохранённую запись о теге в .gear/tags не надо в таком случае (поэтому оно пишется без использования переменной @version@
, а явным прописыванием базовой версии).
Однако, принцип, что патч не переделывается без необходимости, может вступать в противоречие с другим желанием мейнтейнера пакета: иметь смёрдженные пачти и исходники в одном каком-то коммите. Над этим надо подумать (что кому удобнее).
Знакомство со схемой упаковки pam_pkcs11
[imz@ovicaa TMP]$ git clone git://git.altlinux.org/gears/p/pam_pkcs11.git [imz@ovicaa TMP]$ cd pam_pkcs11/
git tag; git branch -a
Посмотрим какие там есть теги и бранчи:
[imz@ovicaa pam_pkcs11]$ git tag 0.6.1-alt1 0.6.1-alt2 0.6.1-alt3 0.6.1-alt4 0.6.1-alt5 0.6.4-alt1 0.6.4-alt1.1 0.6.4-alt1.M60P.1 0.6.4-alt1.M60T.1 0.6.4-alt2 0.6.8-alt0.git20140828.M70C.1 0.6.8-alt1.git20140828 0.6.8.0.48-alt1 0.6.9-alt0.M70C.1 0.6.9-alt0.M80P.1 0.6.9-alt1 0.6.9-alt1.M70T.1 0.6.9-alt2 0.6.9-alt2.M70T.0.M70C.1 0.6.9-alt2.M70T.1 0.6.9-alt2.M80P.1 0.6.9-alt3
-- это сборочные теги, которые создал мейнтенер пакета для сборок очередных релизов пакета в репозитории пакетов ALT;
gb-c7-task169526.200 gb-c7-task172681.100 gb-p6-task172398.100 gb-p8-task171625.200 gb-p8-task173707.200 gb-sisyphus-task130048.100 gb-sisyphus-task171630.100 gb-sisyphus-task172550.200 gb-sisyphus-task172679.100 gb-sisyphus-task75437 gb-t6-task172356.200 gb-t7-task172416.200 gb-t7-task172538.200
-- эти теги проставила сама сборочница по завершении заданий на сборку, чтобы отметить, какие коммиты/теги успешно привели к помещению нового пакета в репозитории пакетов ALT;
imz/0.6.1-alt1 imz/0.6.1-alt2 imz/0.6.1-alt3 imz/0.6.1-alt4 imz/0.6.1-alt5 imz/0.6.4-alt1.1 imz/0.6.4-alt2
-- это тоже сборочные теги (на их имена нет никаких ограничений), которые создал мейнтенер пакета для сборок очередных релизов пакета в репозитории пакетов ALT или с подобными целями;
pam_pkcs11-0.6.1 pam_pkcs11-0.6.2 pam_pkcs11-0.6.3 pam_pkcs11-0.6.4 pam_pkcs11-0.6.7 pam_pkcs11-0.6.8
-- эти теги отмечали апстримные версии (в чистом виде).
[imz@ovicaa pam_pkcs11]$ git branch -a * sisyphus remotes/origin/5.1 remotes/origin/HEAD -> origin/sisyphus remotes/origin/c7 remotes/origin/p6 remotes/origin/p7 remotes/origin/p8 remotes/origin/sisyphus remotes/origin/t6 remotes/origin/t7 [imz@ovicaa pam_pkcs11]$
Эти ветки представляют историю пакета в каждом из репозиториев пакетов ALT. При клонировании нашей рабочей веткой стала sisyphus
; она сейчас checked out.
gear-restore-tags
В .gear/tags сохранены теги/ссылки-бранчи, которые участвовали в правилах .gear/rules при последней сборке в Sisyphus (у нас же эта ветка сейчас checked out). (Git использовался мейнтейнером как способ описать, что откуда брать, путём именования коммитов и использования этих имён в .gear/rules. После того, как эти "именованые ссылки" были сохранены в файле, их можно и стереть из репозитория Git без потери информации.)
Тут можно отметить важный принцип gear: Благодаря этому вся информация, нужная для повторения сборки, сохранена внутри "сборочного" коммита (.gear/tags и история Git со всеми предками). (В случае specsubst нужно уточнить: "внутри сборочного тега".) Это не зависит от того, скопировал ли человек чужие теги. (Теги всё-таки во многом дело более индивидуальное, и их не обязаны все копировать и распространять.)
Восстановим их и познакомимся:
[imz@ovicaa pam_pkcs11]$ gear-restore-tags [imz@ovicaa pam_pkcs11]$ git tag ...
...тут новых не появилось;
... [imz@ovicaa pam_pkcs11]$ git branch -a pam_pkcs11-0.6.9 pam_pkcs11-0.6.9-alt-build pam_pkcs11-0.6.9-ask-pin-later pam_pkcs11-0.6.9-ask-pin-later-with-option-ask_pin pam_pkcs11-0.6.9-buffer pam_pkcs11-0.6.9-docs pam_pkcs11-0.6.9-option-global_ca pam_pkcs11-0.6.9-ru.po
-- а вот это новые, для сборки (вызывает некоторое непонимание наличие ветки pam_pkcs11-0.6.9
, а не тега; TODO: разобраться, откуда взялось!); эти неновые, были после клонирования:
* sisyphus remotes/origin/5.1 remotes/origin/HEAD -> origin/sisyphus remotes/origin/c7 remotes/origin/p6 remotes/origin/p7 remotes/origin/p8 remotes/origin/sisyphus remotes/origin/t6 remotes/origin/t7 [imz@ovicaa pam_pkcs11]$
Пример добавления ещё одного патча в сборку
Делаем наши изменения
[imz@ovicaa pam_pkcs11]$ git checkout -b pam_pkcs11-0.6.9-my-changes pam_pkcs11-0.6.9 Switched to a new branch 'pam_pkcs11-0.6.9-my-changes' [imz@ovicaa pam_pkcs11]$ echo '/* My changes. */' >>src/pam_pkcs11/pam_config.h [imz@ovicaa pam_pkcs11]$ git --no-pager diff diff --git a/src/pam_pkcs11/pam_config.h b/src/pam_pkcs11/pam_config.h index cf4e089..8096ff6 100644 --- a/src/pam_pkcs11/pam_config.h +++ b/src/pam_pkcs11/pam_config.h @@ -51,3 +51,4 @@ struct configuration_st { struct configuration_st *pk_configure( int argc, const char **argv ); #endif +/* My changes. */ [imz@ovicaa pam_pkcs11]$ git commit -a -m 'My changes' [pam_pkcs11-0.6.9-my-changes 3285e31] My changes 1 file changed, 1 insertion(+) [imz@ovicaa pam_pkcs11]$
Подшиваем коммиты с нашими изменениями в историю сборочной ветки
[imz@ovicaa pam_pkcs11]$ git checkout sisyphus Switched to branch 'sisyphus' Your branch is up-to-date with 'origin/sisyphus'. [imz@ovicaa pam_pkcs11]$
Возможны разные варианты (как добиться, чтобы коммит был в истории):
- git merge -s ours pam_pkcs11-0.6.9-my-changes -m 'merge -s ours pam_pkcs11-0.6.9-my-changes'
- git merge pam_pkcs11-0.6.9-my-changes
- или, как делал мейнтейнер раньше, с отдельной веткой (скажем,
0.6.9-ALT
) для всех пропатченных исходников; для этого сначала восстановим0.6.9-ALT
, как она была у менйтейнера (TODO: к сожаленью, gear-restore-tags её не восстановил, потому что она "вспомогательная" и не участвует в правилах .gear/rules):
[imz@ovicaa pam_pkcs11]$ git checkout -b 0.6.9-ALT 2ccbc36d4297de4de9b99b89c399c6f6879cdaa3 Switched to a new branch '0.6.9-ALT' [imz@ovicaa pam_pkcs11]$ git merge pam_pkcs11-0.6.9-my-changes Auto-merging src/pam_pkcs11/pam_config.h Merge made by the 'recursive' strategy. src/pam_pkcs11/pam_config.h | 1 + 1 file changed, 1 insertion(+) [imz@ovicaa pam_pkcs11]$ git checkout sisyphus Switched to branch 'sisyphus' Your branch is up-to-date with 'origin/sisyphus'. [imz@ovicaa pam_pkcs11]$ git merge 0.6.9-ALT -m 'Merge 0.6.9-ALT with my-changes into sisyphus' Merge made by the 'recursive' strategy. src/pam_pkcs11/pam_config.h | 1 + 1 file changed, 1 insertion(+) [imz@ovicaa pam_pkcs11]$
Разные варианты -- дело предпочтений мейнтейнеров, но не является требованием gear. Главное, чтобы коммит оказался в истории "сборочного" тега, а как будет сделан merge, конечно, неважно для gear; важно, что мы сможем сослаться на него в .gear/rules.
У мейнтейнера были соображения, почему удобнее делать так, как он делал, и будет неудобно для него нарушать его схему, если планируется отправить коммит на сборку в Sisyphus.
(3-ий вариант делался мейнтейнером вот ради чего; см. также #Дополнительная ветка для пропатченных исходников. В сборочной ветке хотелось иметь сразу после checkout-а все исходники в пропатченном виде, для изучения. Для этого подошёл бы и 2-ой вариант. А также хотелось при выходе новых апстримных версий ребейзить ветки с патчами -- про это сказано во введении к этой статье. И тут возникает неудобство: при мёрдже rebased ветки в сборочную ветку она сталкивается с теми же изменениями, но на основе прошлой версии; того же рода трудность при мёрдже новой апстримной версии или при убирании старого ненужного больше патча. Есть 1-ый вариант, когда всегда делается merge -s ours, и тогда бы в "сборочной" ветке была бы история только файлов, описывающих сборку пакета, а сами исходники в чистом виде были бы в других ветках, и разрешать столкновения патчей и новых версий в сборочной ветке не надо было бы. Но тогда не было бы реализовано пожелание иметь исходники сразу checked out для изучения. 3-ий вариант позволяет хорошо "объяснить" Git-у как автоматически делать мёрджи новых версий в сборочную ветку, а именно, в ветке 0.6.9-ALT
просто делается git merge -s ours 0.6.8-ALT и всё: Git знает, что то, что было в сборочной ветке из 0.6.8-ALT
, можно забыть при очередном мёрдже; не надо вручную вычищать файлы.)
Готовы к сборке
Поменяем правила, .spec, сохраним теги.
[imz@ovicaa pam_pkcs11]$ echo 'diff: @name@-@version@:. @name@-@version@-my-changes:. name=@name@-@version@-my-changes.patch' >>.gear/rules [imz@ovicaa pam_pkcs11]$ emacs .gear/pam_pkcs11.spec & [imz@ovicaa pam_pkcs11]$ git --no-pager diff diff --git a/.gear/pam_pkcs11.spec b/.gear/pam_pkcs11.spec index a84b3eb..15a4c9c 100644 --- a/.gear/pam_pkcs11.spec +++ b/.gear/pam_pkcs11.spec @@ -2,7 +2,7 @@ Name: pam_pkcs11 Version: 0.6.9 -Release: alt3 +Release: alt4 Summary: PKCS #11 PAM Module and Login Tools Group: System/Base @@ -17,6 +17,7 @@ Patch3: %name-%version-ru.po.patch Patch4: %name-%version-buffer.patch Patch5: %name-%version-ask-pin-later.patch Patch6: %name-%version-option-ask_pin.patch +Patch7: %name-%version-my-changes.patch BuildRequires: docbook-style-xsl flex libldap-devel libpam-devel libpcsclite-devel libssl-devel xsltproc BuildRequires: doxygen @@ -71,6 +72,7 @@ as a separate package. %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 # fixup configs sed -i -e ' @@ -153,6 +155,9 @@ rm %buildroot/%_lib/*/*.la /%_lib/%name/ldap_mapper.so %changelog +* Mon Feb 13 2017 Ivan Zakharyaschev <imz@altlinux.org> 0.6.9-alt4 +- My changes. + * Mon Nov 21 2016 Ivan Zakharyaschev <imz@altlinux.org> 0.6.9-alt3 - ask_pin (by default: true) option added (thx cas@); the corresponding PAM options are: ask_pin, dont_ask_pin. diff --git a/.gear/rules b/.gear/rules index 797929a..ece57e0 100644 --- a/.gear/rules +++ b/.gear/rules @@ -8,3 +8,4 @@ diff: @name@-@version@:. @name@-@version@-ru.po:. name=@name@-@version@-ru.po.pa diff: @name@-@version@:. @name@-@version@-buffer:. name=@name@-@version@-buffer.patch diff: @name@-@version@-buffer:. @name@-@version@-ask-pin-later:. name=@name@-@version@-ask-pin-later.patch diff: @name@-@version@-ask-pin-later:. @name@-@version@-ask-pin-later-with-option-ask_pin:. name=@name@-@version@-option-ask_pin.patch +diff: @name@-@version@:. @name@-@version@-my-changes:. name=@name@-@version@-my-changes.patch [imz@ovicaa pam_pkcs11]$ gear-store-tags -a [imz@ovicaa pam_pkcs11]$ gear-commit -a --no-edit [sisyphus b0e7bc5] 0.6.9-alt4 3 files changed, 8 insertions(+), 1 deletion(-) [imz@ovicaa pam_pkcs11]$ git --no-pager diff HEAD^.. diff --git a/.gear/pam_pkcs11.spec b/.gear/pam_pkcs11.spec index a84b3eb..15a4c9c 100644 --- a/.gear/pam_pkcs11.spec +++ b/.gear/pam_pkcs11.spec @@ -2,7 +2,7 @@ Name: pam_pkcs11 Version: 0.6.9 -Release: alt3 +Release: alt4 Summary: PKCS #11 PAM Module and Login Tools Group: System/Base @@ -17,6 +17,7 @@ Patch3: %name-%version-ru.po.patch Patch4: %name-%version-buffer.patch Patch5: %name-%version-ask-pin-later.patch Patch6: %name-%version-option-ask_pin.patch +Patch7: %name-%version-my-changes.patch BuildRequires: docbook-style-xsl flex libldap-devel libpam-devel libpcsclite-devel libssl-devel xsltproc BuildRequires: doxygen @@ -71,6 +72,7 @@ as a separate package. %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 # fixup configs sed -i -e ' @@ -153,6 +155,9 @@ rm %buildroot/%_lib/*/*.la /%_lib/%name/ldap_mapper.so %changelog +* Mon Feb 13 2017 Ivan Zakharyaschev <imz@altlinux.org> 0.6.9-alt4 +- My changes. + * Mon Nov 21 2016 Ivan Zakharyaschev <imz@altlinux.org> 0.6.9-alt3 - ask_pin (by default: true) option added (thx cas@); the corresponding PAM options are: ask_pin, dont_ask_pin. diff --git a/.gear/rules b/.gear/rules index 797929a..ece57e0 100644 --- a/.gear/rules +++ b/.gear/rules @@ -8,3 +8,4 @@ diff: @name@-@version@:. @name@-@version@-ru.po:. name=@name@-@version@-ru.po.pa diff: @name@-@version@:. @name@-@version@-buffer:. name=@name@-@version@-buffer.patch diff: @name@-@version@-buffer:. @name@-@version@-ask-pin-later:. name=@name@-@version@-ask-pin-later.patch diff: @name@-@version@-ask-pin-later:. @name@-@version@-ask-pin-later-with-option-ask_pin:. name=@name@-@version@-option-ask_pin.patch +diff: @name@-@version@:. @name@-@version@-my-changes:. name=@name@-@version@-my-changes.patch diff --git a/.gear/tags/list b/.gear/tags/list index 6cdd076..c8f07c7 100644 --- a/.gear/tags/list +++ b/.gear/tags/list @@ -6,3 +6,4 @@ 4198e4bc3818a76e9fa71842a847a356f9873749 pam_pkcs11-0.6.9-buffer 9a268c67b78e8a668d26a37b41bd2db39675914f pam_pkcs11-0.6.9-ask-pin-later 8247217c608dee7c3d429fce61068c4cde7df07e pam_pkcs11-0.6.9-ask-pin-later-with-option-ask_pin +3285e3136b23aee1f214386cdf86ebbea38385f9 pam_pkcs11-0.6.9-my-changes [imz@ovicaa pam_pkcs11]$
Пробуем собрать
Пробуем собрать:
[imz@ovicaa pam_pkcs11]$ gear ../pam_pkcs11.tar [imz@ovicaa pam_pkcs11]$ tar tvf ../pam_pkcs11.tar V--------- 0/0 0 2017-02-13 13:44 pam_pkcs11.spec--Volume Header-- drwxr-xr-x root/root 0 2017-02-13 13:44 ./ -rw-r--r-- root/root 6409 2017-02-13 13:43 ./pam_pkcs11.spec -rw-r--r-- root/root 381 2017-02-13 13:44 ./pam_pkcs11-0.6.9-my-changes.patch -rw-r--r-- root/root 9140 2017-02-13 13:43 ./pam_pkcs11-0.6.9-option-ask_pin.patch -rw-r--r-- root/root 6934 2017-02-13 13:43 ./pam_pkcs11-0.6.9-ask-pin-later.patch -rw-r--r-- root/root 4557 2017-02-13 13:43 ./pam_pkcs11-0.6.9-buffer.patch -rw-r--r-- root/root 2478 2017-02-13 13:43 ./pam_pkcs11-0.6.9-ru.po.patch -rw-r--r-- root/root 3827 2017-02-13 13:43 ./pam_pkcs11-0.6.9-option-global_ca.patch -rw-r--r-- root/root 4028 2017-02-13 13:43 ./pam_pkcs11-0.6.9-docs.patch -rw-r--r-- root/root 408 2017-02-13 13:43 ./pam_pkcs11-0.6.9-alt-build.patch -rw-r--r-- root/root 1249280 2017-02-13 13:43 ./pam_pkcs11-0.6.9.tar [imz@ovicaa pam_pkcs11]$
Жалоб нет.
Замечания
@version@
или не обновлять базовую версию апстрима для патча и не ребейзить?
Во введении говорилось, что в .gear/rules можно писать базовые апстримные версии для патчей явно, а не с помощью переменной @version@
, и это позволит не ребейзить патчи каждый раз, пока они прикладываются (так, как это обычно делается при работе с .src.rpm.).
Но pam_pkcs11 оказался примером Gear-репозитория, где таких правил нет, а все с переменной, т.е. требуют ребейза с каждой апстримной версией.
Во многом это вызвано тем, что мы кладём-таки исходники в сборочную ветку. Если бы мы делали git merge -s ours, то можно было бы оставлять старые базовые версии в патчах в .gear/rules. Примеры таких реальных пакетов у меня тоже есть.
Дополнительная ветка для пропатченных исходников
Пример, когда без неё плохо, с rebased ветками
Без дополнительной ветки, например, было:
- upstream:
N
- патч:
pkg-N-my-changes
- сборочная ветка: включает спек и пр. и merge N pkg-N-my-changes
Выходит новая апстримная версия, требующая ребейза патча:
- upstream:
(N+1)
- патч:
pkg-(N+1)-my-changes
Если в "сборочной" ветке (которая включает спек и пр.) начать делать merge (N+1) pkg-(N+1)-my-changes, то мы столкнёмся с конфликтами между pkg-N-my-changes
и pkg-(N+1)-my-changes
. (Другими словами, старая версия патча не будет отменена.)
Очевидно, разрешить эту ситуацию такой простой командой как git merge -s ours ... не получается (пропадудт либо спеки, либо новая версия исхдников и патча).
А с дополнительной веткой N-ALT
, например, было:
- upstream:
N
- патч:
pkg-N-my-changes
- N-ALT: результат git checkout -b N-ALT N && git merge pkg-N-my-changes
- сборочная ветка: включает спек и пр. и merge N-ALT (включает merge N pkg-N-my-changes)
С выходом новой апстримной версии, требующей ребейза патча:
- upstream:
(N+1)
- патч:
pkg-(N+1)-my-changes
- (N+1)-ALT: результат git checkout -b (N+1)-ALT (N+1) && git merge pkg-(N+1)-my-changes и специально: git merge -s ours N-ALT
- сборочная ветка: включает спек и пр. и merge (N+1)-ALT
-- и всё то, что приехало в сборочную ветку из N-ALT
будет заменено на (N+1)-ALT
!
Пример, когда без неё можно, если не было rebase?
Я задумался, а что если какой-то мейнтейнер впопыхах (или ради экономии количества мёрджей) не соблюдёт эту схему с дополнительной веткой и зальёт новую апстримную версию исходников N+1
в пакет, минуя дополнительную ветку (N+1)-ALT
?
Понятно, что если изменения в апстриме такие, что патч требует ребейза, ничего не получится.
А если не требует, то испортит ли такое поспешное действие дальнейшую работу схемы?
Продумаем это. Например, было:
- upstream:
N
- патч:
pkg-N-my-changes
- N-ALT: результат git checkout -b N-ALT N && git merge pkg-N-my-changes
- сборочная ветка: включает спек и пр. и merge N-ALT (включает merge N pkg-N-my-changes)
С выходом новой апстримной версии, не требующей ребейза патча, было по-быстрому сделано:
- upstream:
(N+1)
- патч: накладывается старый
pkg-N-my-changes
- сборочная ветка: включает спек и пр. и merge (N+1) (раньше уже было: merge N-ALT).
Теперь выходит новая апстримная версия, требующая ребейза патча:
- upstream:
(N+2)
- патч:
pkg-(N+2)-my-changes
- (N+2)-ALT: результат git checkout -b (N+2)-ALT (N+2) && git merge pkg-(N+2)-my-changes и специально: git merge -s ours N-ALT
- сборочная ветка: включает спек и пр. и merge (N+2)-ALT
Что должно произойти? При последнем мёрдже новое что приезжает в сборочную ветку: (N+2)-ALT ^N-ALT ^(N+1)
. То, что было из N-ALT
и из (N+1)
как раз должно замениться на содержание (N+2)-ALT
. Отличие от более простого проверенного случая с (N+1)-ALT
в том, что этих точек "отреза" две, а не одна; и стало быть, эти два коммита были независимо смёрджены в сборочную ветку от истории (N+2)-ALT
-- сможет ли Git разобраться?
(Можно будет опробовать на пакете puppet, где я сейчас немного навожу порядок с патчами ради сборки puppet3 рядом с puppet >= 4.)