[devel] gtk-update-icon-cache filetrigger (+ libtcl deficiency)
Alexey Tourbin
=?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Ср Сен 10 00:23:45 MSD 2008
Напомню, что filetriggers -- это скрипты /usr/lib/rpm/*.filetrigger,
которые запускаются после успешного завершения транзакции. Они получают
на вход список файлов, затронутых транзакцией (построчно на stdin),
то есть как бы вывод 'rpm -ql' от вновь установленных, обновлённых
и удалённых пакетов. Механизм специально сделан максимально упрощенным
(дополнительную информацию можно получить естественным образом --
например, чтобы определить, был ли файл добавлен/обновлен или же удалён,
можно использовать простой тест типа [ -f "$f"] ).
* * *
Посмотрим, какой расклад мы имеем с кешем gtk2. Библиотека libgtk+2
использует кеш по умолчанию, если он существует (это ускоряет запуск
приложений, а также экономит память, т.к. иконки расшариваются между
приложениями). Есть стандартная программа обновления кеша
gtk-update-icon-cache. Кроме библиотеки libgtk+2 этот кеш больше никто
не использует.
Следуя принципу правильной группировки файлов в пакетах, можно
заключить, что библиотеку libgtk+2, программу gtk-update-icon-cache
и триггер /usr/lib/rpm/gtk-icon-cache.filetrigger следует запаковать
в один и тот же пакет (libgtk+2).
Принцип правильной группировки файлов между пакетами состоит в том,
что совместно используемые файлы нужно паковать в один и тот же пакет.
Действительно, программа gtk-update-icon-cache сама по себе, по
отдельности, имеет мало смысла (т.к. результат её работы представляет
интерес только для библиотеки libgtk+2). А триггер
/usr/lib/rpm/gtk-icon-cache.filetrigger, в свою очередь, сможет сделать
что-либо только при наличии программы gtk-update-icon-cache. Короче,
эти две программы просто "обслуживают" библиотеку libgtk+2.
С другой стороны, этот принцип не является настолько однозначным, чтобы
можно было применять его механически. Нужно думать. Ведь библиотека
libgtk+2, хотя и использует кеш иконок по умолчанию, всё же обходится
без него, если кеш отсутствует. Так что кто-то может возразить, что
мы кладём в libgtk+2 лишние файлы, без которых, строго говоря, можно
обойтись. На что мы можем парировать позитивной интерпретацией: кеш
иконок работает "из коробки" (а в противном случае возможны проблемы
с инвалидацией кеша, то есть битые иконки в приложениях).
* * *
Хотя принцип правильной группировки файлов не всегда можно толковать
однозначно, на практике он имеет большое значение. Приведу пример
пакета, в котором принцип правильной группировки файлов между пакетами
явно нарушен -- это пакет libtcl. Tcl может использоваться как embedded
language, т.е. приложения пишут обёртку для libtcl и дальше Tcl как язык
может использоваться внутри приложения. Такие приложения получают
зависимость на libtcl soname.
Напишем простейшую программу, которая встраивает libtcl.
$ cat test.c
#include <tcl.h>
int main(int argc, char **argv)
{
Tcl_Main(argc,argv,Tcl_Init);
return 0;
}
$ gcc -Wall test.c -o test -ltcl
$
Теперь посмотрим, будет ли она работать в среде, где установлена
одна только библиотека libtcl.
$ hsh --init
$ hsh-install
...
$ hsh-install libtcl
<13>Sep 9 23:05:07 rpmi: libtcl-8.5.4-alt1 installed
$ cp -pv ./test ~tmp/build/chroot/.in/ && hsh-run ./test
`./test' -> `/tmp/.private/at/build/chroot/.in/test'
application-specific initialization failed: Can't find a usable init.tcl in the following directories:
/usr/share/tcl/tcl8.5 /lib/tcl8.5 /lib/tcl8.5 /library /library /tcl8.5.4/library /tcl8.5.4/library
This probably means that Tcl wasn't installed properly.
$
Увы. Приложения, слинковавшиеся с libtcl, громко обломятся (с диагностикой
"Tcl wasn't installed properly"!). Если же установить пакет tcl, то уже
всё работает.
$ cp -pv ./test ~tmp/build/chroot/.in/ && hsh-run ./test && echo $?
`./test' -> `/tmp/.private/at/build/chroot/.in/test'
0
$
Библиотека libtcl имеет "непрозрачную" зависимость на init.tcl, этот
файл загружается при инициализации библиотеки. Без init.tcl приложения,
слинованные c libtcl, обламываются; а файл init.tcl имеет смысл только
в связи с наличием конкретной библиотеки libtcl. Это достаточное
основание для того, чтобы применить принцип правильной группировки
файлов между пакетами -- файлы libtcl*so* и init.tcl должны быть
запакованы в один и тот же пакет. На практике возможны два решения:
либо перенести init.tcl (и, возможно, ещё некоторые файлы) из пакета tcl
в пакет libtcl, либо полностью внести libtcl в tcl (то есть исключить
отдельный пакет с библиотекой, если библиотека "сама по себе"
не работает).
* * *
Вернёмся к кешу иконок libgtk+2 и его специфике. Кеш создаётся для
каждой отдельной "темы" иконок, а темы раскладываются по отдельным
каталогам. Для каждой темы должен существовать файл index.theme
(для темы "hicolor", используемой по умолчанию, это будет
/usr/share/icons/hicolor/index.theme в пакете icon-theme-hicolor).
Программа gtk-update-icon-cache по умолчанию отказывается создавать
кеш, если отсутствует файл index.theme.
Однако пакет libgtk+2 не имеет зависимости на icon-theme-hicolor,
то есть в базовой установке для дефолтной темы hicolor отсутствует файл
index.theme. Хотелось бы выяснить, в какой степени файл index.theme
реально необходим для использования иконок (и для создания кеша иконок).
Кроме того, тема hicolor является "расширяемой", т.е. пакеты приложений
кладут свои дополнительные иконки в /usr/share/icons/hicolor. Остальные
темы являются как бы замкнутыми и независимыми (например, всё содержимое
каталога /usr/share/icons/gnome принадлежит пакету gnome-icon-theme,
а другие приложения туда иконок не кладут.
Короче, для триггера возможна следующая логика обновления кеша иконок:
1) каталог /usr/share/icons/hicolor обрабатывается специально;
2) остальные темы обрабатываются по факту наличия в траназкции файла
index.theme.
Тогда возможна следующая реализация /usr/lib/rpm/gtk-icon-cache.filetrigger:
#!/bin/sh
hicolor=
while read -r f; do
case "$f" in
/usr/share/icons/hicolor/*)
hicolor=1
;;
/usr/share/icons/*/index.theme)
if [ -f "$f" ]; then
gtk-update-icon-cache "${f%/*}"
else
rm -f "${f%/*}"/icon-theme.cache
fi
;;
esac
done
if [ -n "$hicolor" ]; then
gtk-update-icon-cache --ignore-theme-index /usr/share/icons/hicolor
fi
То есть для любых изменений в /usr/share/icons/hicolor вызывается
gtk-update-icon-cache с опцией --ignore-theme-index (отключается
проверка наличия index.theme). Все остальные темы обрабатываются по
файлу index.theme: если он добавился или обновился, то gtk-update-icon-cache
запускается обычным способом; если же файл index.theme удалился, то
удаляется и соответствующий ему кеш icon-theme.cache.
Мы исходили из предположения, что все остальные темы, кроме hicolor,
являются замкнутыми и независимыми, поэтому обновления кеша этих тем
можно привязать к соответствующему файлу index.theme. Я сейчас на
всякий случай проверил, и оказалось, что предположение не всегда
выполняется.
$ grep /usr/share/icons/gnome/ ~tmp/build/cache/contents/contents_index_all |awk '$2!="gnome-icon-theme"'
/usr/share/icons/gnome/32x32 /usr/share/icons/gnome/32x32
/usr/share/icons/gnome/32x32/apps /usr/share/icons/gnome/32x32/apps
/usr/share/icons/gnome/48x48 /usr/share/icons/gnome/48x48
/usr/share/icons/gnome/48x48/apps /usr/share/icons/gnome/48x48/apps
/usr/share/icons/gnome/48x48/mimetypes gdesklets
/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-anjuta.png anjuta2
/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-codeblocks-workspace.png codeblocks
/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-codeblocks.png codeblocks
/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-gdesklets-display.png gdesklets
/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-littlewizard.png littlewizard
/usr/share/icons/gnome/48x48/mimetypes/gnome-mime-application-x-ptoptimizer-script.png hugin
/usr/share/icons/gnome/scalable/mimetypes/gnome-mime-application-x-anjuta.svg anjuta2
/usr/share/icons/gnome/scalable/mimetypes/gnome-mime-application-x-littlewizard.svg littlewizard
$
То есть существуют приложения, хотя и немногочисленные, которые кладут
иконки в тему "gnome". По-видимому, в таких случаях кеш темы gnome
также следует обновлять; так что предложенная логика обновления
дополнительных тем уже оказывается недостаточной.
* * *
Триггер после транзакции -- это хорошо, но нужно также рассмотреть
вопрос, что происходит в самом начале и в самом конце. Когда библиотека
libgtk+2 устанавливается в первый раз, некоторые темы иконок уже могут
быть установлены (в более ранних транзакциях). Также, при обновлении
библиотеки libgtk+2 формат кеша может измениться (более или менее
совместимым образом). Короче, после установки или обновления libgtk+2
желательно обновить кеш всех существующих тем. Смотрите, как красиво
это можно сделать:
%post
find /usr/share/icons -type f |/usr/lib/rpm/gtk-icon-cache.filetrigger
То есть мы запускаем триггер от имени %post-скрипта и как бы говорим
ему: "посмотри, все эти иконки как будто только что добавились".
Дальше триггер уже сам решит, какие там есть темы и как обновлять кеш.
А при окончательном удалении библиотеки libgtk+2 кеш иконок больше
никому не нужен. Так что можно написать
%postun
if [ $1 = 0 ]; then
rm -f /usr/share/icons/*/icon-theme.cache
fi
* * *
Что до самой библиотеки libgtk+2, то, во-первых, недавно вышла новая
версия 2.14. Во-вторых, мне не нравится существующий распил на libgtk+2
и libgtk+2-common. Может быть, вместе с триггером я бы посмотрел новую
версию и попилил бы её на свой вкус.
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип : application/pgp-signature
Размер : 197 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url : <http://lists.altlinux.org/pipermail/devel/attachments/20080910/b22e10d3/attachment-0002.bin>
Подробная информация о списке рассылки Devel