[devel] posttrans filetriggers [2]
Alexey Tourbin
=?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Пн Сен 8 13:51:06 MSD 2008
Юрий Седунов просил меня реализовать posttrans filetriggers,
чтобы решить проблему c gtk icon cache в branch-4.1 (для предостящего
релиза дистрибутива).
Проблема это такая: библиотека libgtk+2 может использовать кеш
иконок /usr/share/icons/hicolor/icon-theme.cache, чтобы ускорить
загрузку иконок. По умолчанию этот кеш отсутствует; но если он создан,
то libgtk+2 не находит иконки, отсутствующие в кеше (но существующие в
файловой системе).
Пакет NetworkManager-gnome создаёт/обновляет этот кеш, а большая часть
других пакетов (около 700+ штук) не создаёт и не обновляет этот кеш. Это
означает, что после установки NetworkManager-gnome библиотека libgtk+2
будет использовать кеш, созданный на стадии установки NetworkManager-gnome,
а установка дополнительных пакетов с иконками на этот кеш никак не
повлияет, то есть, в конечном счёте, в приложениях будут битые иконки.
Возможное решение проблемы -- добавить %post-скрипт для обновления кеша
иконок во все пакеты, которые содержат /usr/share/icons/hicolor/*.
Возражения:
1) Пачить 700+ штук пакетов -- мартышкин труд.
2) Пакеты с иконками не обязаны знать специфику работы libgtk+2 кеша,
и даже что он вообще есть.
3) Можно сэкономить время на установке, если создать/обновить кеш
только один раз, в конце транзакции.
Идея posttrans filetriggers простая -- во время выполнения транзакции
создаётся список установленных/удалённых файлов. Дальше можно написать
скрипт, который, если транзакция успешно завершилась, получит на вход
этот список файлов и сможет выполнить определённые действия.
Упрощенный пример для обновления кеша иконок.
/usr/lib/rpm/gtk+2-icon-cache.filetrigger:
#!/bin/sh
if grep -qs ^/usr/share/icons/hicolor/; then
gtk-update-icon-cache --force --ignore-theme-index
fi
Упрощенный пример для регистрации GConf2 схем.
/usr/lib/rpm/GConf2-schemas.filetrigger:
#!/bin/sh
install=
remove=
while read -r f; do
case "$f" in
/etc/gconf/schemas/*.schemas) ;;
*) continue ;;
esac
if [ -f "$f" ]; then
install="$install $f"
else
remove="$remove $f"
fi
done
[ -z "$install" ] || gconftool-2 --makefile-install-rule $install
[ -z "$remove" ] || gconftool-2 --makefile-uninstall-rule $remove
Последний пример показывает, что можно реализовать достаточно сложные
случаи обработки аргументов, накапливая аргументы в цикле (чтобы
запустить прогрмму всего одни раз). На самом деле в реальном скрипте
лучше использовать xargs --delimiter='\n', потому что argv может
переполниться, а файлы могут содержать пробелы).
В отличие от мандривовского патча, я не стал делать у файлов префиксы
"+" и "-", т.к. из-за особенностей librpm нельзя сделать чтобы это
хорошо работало (т.е. "+" может и не означать, что файл был добавлен,
а "-" может не означать, что файл таки был удалён). В последнем примере
я просто явно проверяю [ -f "$f" ].
Changelog since common ancestor `4.0.4-alt95.M41.2' follows:
commit 462bd2a2b95b6946ccd347b8d1848943d5ae3c99
Author: Alexey Tourbin <at на altlinux>
Date: Mon Sep 8 10:57:19 2008 +0400
implemented posttrans filetriggers, vaguely based on Mandriva patch
Full diff since common ancestor `4.0.4-alt95.M41.2' follows:
diff --git a/a b/a
new file mode 100644
index 0000000..e69de29
diff --git a/configure.in b/configure.in
index 2e7b53e..82a959c 100644
--- a/configure.in
+++ b/configure.in
@@ -1022,6 +1022,7 @@ AC_OUTPUT([ Doxyfile Makefile rpmrc macros platform rpmpopt rpm.spec
scripts/strip_files
scripts/symlinks.req
scripts/verify-elf
+ scripts/posttrans-filetriggers
tests/Makefile tests/rpmrc tests/macros tests/hello-test/Makefile
po/Makefile.in
doc/Makefile doc/manual/Makefile
diff --git a/lib/psm.c b/lib/psm.c
index b9e6f8e..3ccaf60 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -900,7 +900,7 @@ static int runScript(PSM_t psm, Header h,
int freePrefixes = 0;
FD_t out;
rpmRC rc = RPMRC_OK;
- const char *n, *v, *r;
+ const char *n = NULL, *v = NULL, *r = NULL;
char arg1_str [sizeof(int)*3+1] = "";
char arg2_str [sizeof(int)*3+1] = "";
@@ -917,6 +917,7 @@ static int runScript(PSM_t psm, Header h,
argc = progArgc;
}
+ if (h)
xx = headerNVR(h, &n, &v, &r);
if (arg1 >= 0)
@@ -924,9 +925,9 @@ static int runScript(PSM_t psm, Header h,
if (arg2 >= 0)
sprintf(arg2_str, "%d", arg2);
- if (hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
+ if (h && hge(h, RPMTAG_INSTPREFIXES, &ipt, (void **) &prefixes, &numPrefixes)) {
freePrefixes = 1;
- } else if (hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
+ } else if (h && hge(h, RPMTAG_INSTALLPREFIX, NULL, (void **) &oldPrefix, NULL)) {
prefixes = &oldPrefix;
numPrefixes = 1;
} else {
@@ -1038,6 +1039,7 @@ static int runScript(PSM_t psm, Header h,
}
}
+ if (n)
dosetenv ("RPM_INSTALL_NAME", n, 1);
if (*arg1_str)
@@ -2130,3 +2132,58 @@ fprintf(stderr, "*** PSM_RDB_LOAD: header #%u not found\n", fi->record);
return rc;
/*@=nullstate@*/
}
+
+static
+void saveTriggerFiles(PSM_t psm)
+{
+ const rpmTransactionSet ts = psm->ts;
+ if (ts->transFlags & RPMTRANS_FLAG_TEST)
+ return;
+ if (ts->transFlags & (_noTransScripts | _noTransTriggers))
+ return;
+ const TFI_t fi = psm->fi;
+ if (fi->fc < 1)
+ return;
+ psmStage(psm, PSM_CHROOT_IN);
+ const char *file = rpmGetPath(ts->rpmdb->db_home, "/files-awaiting-filetriggers");
+ FILE *fp = fopen(file, "a");
+ if (fp == NULL)
+ rpmError(RPMERR_OPEN, "open of %s failed: %s\n", file, strerror(errno));
+ else {
+ int i;
+ for (i = 0; i < fi->fc; i++)
+ fprintf(fp, "%s%s\n", fi->dnl[fi->dil[i]], fi->bnl[i]);
+ fclose(fp);
+ }
+ file = _free(file);
+ psmStage(psm, PSM_CHROOT_OUT);
+}
+
+void psmTriggerAdded(PSM_t psm)
+{
+ saveTriggerFiles(psm);
+}
+
+void psmTriggerRemoved(PSM_t psm)
+{
+ saveTriggerFiles(psm);
+}
+
+void psmTriggerPosttrans(PSM_t psm)
+{
+ const rpmTransactionSet ts = psm->ts;
+ if (ts->transFlags & RPMTRANS_FLAG_TEST)
+ return;
+ if (ts->transFlags & (_noTransScripts | _noTransTriggers))
+ return;
+ psmStage(psm, PSM_CHROOT_IN);
+ const char *file = rpmGetPath(ts->rpmdb->db_home, "/files-awaiting-filetriggers");
+ const char *script = RPMCONFIGDIR "/posttrans-filetriggers";
+ const char *argv[] = { script, file, NULL };
+ rpmMessage(RPMMESS_VERBOSE, _("Running %s\n"), script);
+ int rc = runScript(psm, NULL, script, 2, argv, NULL, 0, 0);
+ if (rc == 0)
+ unlink(file);
+ file = _free(file);
+ psmStage(psm, PSM_CHROOT_OUT);
+}
diff --git a/lib/psm.h b/lib/psm.h
index 968178b..90f1419 100644
--- a/lib/psm.h
+++ b/lib/psm.h
@@ -233,6 +233,11 @@ int psmStage(PSM_t psm, pkgStage stage)
/*@modifies psm, rpmGlobalMacroContext,
fileSystem, internalState @*/;
+/* ALT: hack to implement file triggers */
+void psmTriggerAdded(PSM_t psm);
+void psmTriggerRemoved(PSM_t psm);
+void psmTriggerPosttrans(PSM_t psm);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/transaction.c b/lib/transaction.c
index 2073882..ade1c46 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -2068,6 +2068,9 @@ assert(alp == fi->ap);
ourrc++;
lastFailed = i;
}
+ else {
+ psmTriggerAdded(psm);
+ }
fi->h = headerFree(fi->h);
if (hsave) {
fi->h = headerLink(hsave);
@@ -2094,11 +2097,18 @@ assert(alp == fi->ap);
if (psmStage(psm, PSM_PKGERASE))
ourrc++;
+ else {
+ psmTriggerRemoved(psm);
+ }
break;
}
(void) rpmdbSync(ts->rpmdb);
}
+
+ if (ourrc == 0)
+ psmTriggerPosttrans(psm);
+
tsi = tsFreeIterator(tsi);
ts->flList = freeFl(ts, ts->flList);
diff --git a/rpm-4_0.spec b/rpm-4_0.spec
index 46c08b8..435831f 100644
--- a/rpm-4_0.spec
+++ b/rpm-4_0.spec
@@ -291,6 +291,7 @@ for dbi in \
do
touch "%buildroot%_localstatedir/%name/$dbi"
done
+touch %buildroot%_localstatedir/%name/files-awaiting-filetriggers
# Prepare documentation.
bzip2 -9 CHANGES ||:
@@ -444,6 +445,7 @@ fi
%rpmdbattr %_localstatedir/%name/Sigmd5
%rpmdbattr %_localstatedir/%name/Sha1header
%rpmdbattr %_localstatedir/%name/Triggername
+%rpmdbattr %_localstatedir/%name/files-awaiting-filetriggers
/bin/rpm
%_bindir/rpm
@@ -465,6 +467,8 @@ fi
%_prefix/lib/rpmpopt
%_prefix/lib/rpmrc
+%rpmattr %_rpmlibdir/posttrans-filetriggers
+
%rpmattr %_rpmlibdir/functions
%rpmattr %_rpmlibdir/find-package
%rpmdatattr %_rpmlibdir/.provides.sh
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 6d5a5c1..b9900ba 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -3,6 +3,7 @@
AUTOMAKE_OPTIONS = 1.4 foreign
EXTRA_DIST = \
+ posttrans-filetriggers \
functions find-package .provides.sh \
find-scriptlet-requires \
brp-adjust_libraries brp-alt brp-bytecompile_python \
@@ -32,6 +33,7 @@ all:
configdir = ${prefix}/lib/rpm
config_DATA = .provides.sh 0common-files.req.list
config_SCRIPTS = \
+ posttrans-filetriggers \
functions find-package \
find-scriptlet-requires \
brp-adjust_libraries brp-alt brp-bytecompile_python \
diff --git a/scripts/posttrans-filetriggers.in b/scripts/posttrans-filetriggers.in
new file mode 100755
index 0000000..1f80c51
--- /dev/null
+++ b/scripts/posttrans-filetriggers.in
@@ -0,0 +1,32 @@
+#!/bin/sh -efu
+#
+# File triggers are run at the end of successful transaction.
+#
+# Copyright (C) 2008 Alexey Tourbin <at на altlinux.org>
+#
+# Vaguely based on filetriggers.patch from Mandriva Linux.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+filelist=$1
+shift
+
+RC=0
+
+if [ -s "$filelist" ]; then
+ LC_ALL=C sort -u -o "$filelist" "$filelist"
+ set +f
+ for filetrigger in @RPMCONFIGDIR@/*.filetrigger; do
+ [ -x "$filetrigger" ] || continue
+ "$filetrigger" <"$filelist" ||
+ {
+ echo >&2 "$filetrigger failed"
+ RC=1
+ }
+ done
+fi
+
+exit $RC
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя : =?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/20080908/888a53d5/attachment-0002.bin>
Подробная информация о списке рассылки Devel