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