From c35016925126c23bdde56eab91a3003a7b49dd19 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 5 Jul 2011 13:15:31 -0400 Subject: [PATCH] Add post-installation trigger scripts Several things in the GNOME stack have file-based caches, like gdk-pixbuf's loaders.cache. These need to be regenerated, and historically that worked in jhbuild because these modules include bits in their Makefile to run then relevant commands, if DESTDIR is not set. Package managers have post-installation scripts in packages, and OS builders typically support this as well. Jhbuild historically relied on the post-installation scripts in modules, but in (see bug 647231) we switched to using DESTDIR for all module types. So we need to move closer to the package model here. We call them "triggers" as they're run after any kind of build operation (including "uninstall"). This patch adds a proof-of-concept trigger script for gdk-pixbuf loaders. https://bugzilla.gnome.org/show_bug.cgi?id=653842 --- Makefile.am | 2 +- configure.ac | 1 + jhbuild/frontends/buildscript.py | 20 +++++++ jhbuild/utils/Makefile.am | 1 + jhbuild/utils/trigger.py | 89 ++++++++++++++++++++++++++++++++ triggers/Makefile.am | 2 + triggers/README | 23 +++++++++ triggers/gdk-pixbuf.trigger | 24 +++++++++ 8 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 jhbuild/utils/trigger.py create mode 100644 triggers/Makefile.am create mode 100644 triggers/README create mode 100644 triggers/gdk-pixbuf.trigger diff --git a/Makefile.am b/Makefile.am index 5cfd6b28c..65be11037 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = po scripts jhbuild buildbot +SUBDIRS = po scripts triggers jhbuild buildbot if DOC_INSTALLATION_ENABLED SUBDIRS += doc diff --git a/configure.ac b/configure.ac index 767523975..4ca77a67c 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,7 @@ AC_CONFIG_FILES([ doc/Makefile po/Makefile.in scripts/Makefile + triggers/Makefile jhbuild/Makefile jhbuild/buildbot/Makefile jhbuild/buildbot/status/web/Makefile diff --git a/jhbuild/frontends/buildscript.py b/jhbuild/frontends/buildscript.py index 0141fcddf..513ef9fd7 100644 --- a/jhbuild/frontends/buildscript.py +++ b/jhbuild/frontends/buildscript.py @@ -19,8 +19,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import os +import logging from jhbuild.utils import packagedb +from jhbuild.utils import trigger from jhbuild.errors import FatalError, CommandError, SkipToPhase, SkipToEnd class BuildScript: @@ -84,6 +86,7 @@ def build(self, phases=None): self.start_build() failures = [] # list of modules that couldn't be built + successes = [] self.module_num = 0 for module in self.modulelist: self.module_num = self.module_num + 1 @@ -197,11 +200,28 @@ def build(self, phases=None): num_phase += 1 self.end_module(module.name, failed) + if not failed: + self.run_triggers(module.name) self.end_build(failures) if failures: return 1 return 0 + def run_triggers(self, module_name): + """See triggers/README.""" + all_triggers = trigger.load_all(os.path.join(PKGDATADIR, 'triggers')) + triggers_to_run = [] + for trig in all_triggers: + # Skip if somehow the module isn't really installed + if self.packagedb.installdate(module_name) is None: + continue + pkg = self.packagedb.entries[module_name] + if trig.matches(pkg.manifest): + triggers_to_run.append(trig) + for trig in triggers_to_run: + logging.info(_('Running post-installation trigger script: %r') % (trig.name, )) + trig.run() + def get_build_phases(self, module, targets=None): '''returns the list of required phases''' if targets: diff --git a/jhbuild/utils/Makefile.am b/jhbuild/utils/Makefile.am index b6d63bfac..01a23e3e2 100644 --- a/jhbuild/utils/Makefile.am +++ b/jhbuild/utils/Makefile.am @@ -7,6 +7,7 @@ app_PYTHON = \ notify.py \ packagedb.py \ sxml.py \ + trigger.py \ trayicon.py \ unpack.py diff --git a/jhbuild/utils/trigger.py b/jhbuild/utils/trigger.py new file mode 100644 index 000000000..5df45af25 --- /dev/null +++ b/jhbuild/utils/trigger.py @@ -0,0 +1,89 @@ +# jhbuild - a build script for GNOME 1.x and 2.x +# Copyright (C) 2011 Red Hat, Inc. +# +# trigger.py - Run scripts after packages are installed +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import sys +import subprocess +import re + +from . import cmds + +class Trigger(object): + SUFFIX = '.trigger' + def __init__(self, filepath): + assert filepath.endswith(self.SUFFIX) + self._rematches = [] + self._literal_matches = [] + self._executable = None + self._file = filepath + self.name = os.path.basename(filepath)[:-len(self.SUFFIX)] + + f = open(self._file) + for line in f: + key = '# IfExecutable: ' + if line.startswith(key): + text = line[len(key):].strip() + self._executable = text + continue + key = '# REMatch: ' + if line.startswith(key): + text = line[len(key):].strip() + r = re.compile(text) + self._rematches.append(r) + continue + key = '# LiteralMatch: ' + if line.startswith(key): + text = line[len(key):].strip() + self._literal_matches.append(text) + continue + f.close() + if len(self._rematches) == 0 and len(self._literal_matches) == 0: + raise ValueError("No keys specified in trigger script %r" % (filepath, )) + + def matches(self, files_list): + """@files_list should be a list of absolute file paths. Return True if this trigger script +should be run.""" + if self._executable is not None: + if not cmds.has_command(self._executable): + return False + for path in files_list: + for r in self._rematches: + match = r.search(path) + if match: + return True + for literal in self._literal_matches: + if path.find(literal) >= 0: + return True + return False + + def run(self): + """Synchronously execute this trigger script.""" + assert 'JHBUILD_PREFIX' in os.environ + subprocess.check_call(['/bin/sh', self._file], stdin=open('/dev/null')) + +def load_all(dirpath): + result = [] + for filename in os.listdir(dirpath): + if not filename.endswith(Trigger.SUFFIX): + continue + filepath = os.path.join(dirpath, filename) + p = Trigger(filepath) + result.append(p) + return result + diff --git a/triggers/Makefile.am b/triggers/Makefile.am new file mode 100644 index 000000000..4e1cd6065 --- /dev/null +++ b/triggers/Makefile.am @@ -0,0 +1,2 @@ +triggerdir = $(datadir)/jhbuild/triggers +trigger_DATA = gdk-pixbuf.trigger diff --git a/triggers/README b/triggers/README new file mode 100644 index 000000000..242ad74bb --- /dev/null +++ b/triggers/README @@ -0,0 +1,23 @@ +This directory contains GNOME post-installation trigger scripts (in +theory these could go with the modules, but there aren't many of them, +so eh). + +A .trigger file is a set of regular expressions (or literal matches) +which are evaluated against files installed after any "make install +DESTDIR=", combined with a shell script to run if any of them match. +In the future, these may also be matched against deleted files. + +The contents of a .trigger file are just /bin/sh shell script, with a +few magic comments. During the run of a .trigger file, the +environment variable JHBUILD_PREFIX is guaranteed to be set. + +Currently recognized comments: + +# IfExecutable: STRING + Only run if the given executable is available in $PATH +# LiteralMatch: STRING + Match against installed/removed manifest if the given STRING is a substring of a file or directory. +# REMatch: REGEXP + Match against installed/removed manifest using the given REGEXP in Python syntax. + + diff --git a/triggers/gdk-pixbuf.trigger b/triggers/gdk-pixbuf.trigger new file mode 100644 index 000000000..58b632a32 --- /dev/null +++ b/triggers/gdk-pixbuf.trigger @@ -0,0 +1,24 @@ +# Post-installation hook for gdk-pixbuf. -*- mode: sh -*- +# Corresponds to gdk-pixbuf/gdk-pixbuf/Makefile.am:install-data-hook +# +# Written by Colin Walters +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +# IfExecutable: gdk-pixbuf-query-loaders +# LiteralMatch: /gdk-pixbuf-2.0/2.10.0/loaders/ + +gdk-pixbuf-query-loaders --update-cache