From: Michael Tremer Date: Fri, 13 Apr 2012 15:41:32 +0000 (+0200) Subject: New feature: python scriptlets. X-Git-Tag: 0.9.22~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=536bec815a842b0ea3d482c183257905f84debf6;p=pakfire.git New feature: python scriptlets. --- diff --git a/python/pakfire/actions.py b/python/pakfire/actions.py index 1434841f4..cdc277891 100644 --- a/python/pakfire/actions.py +++ b/python/pakfire/actions.py @@ -20,6 +20,7 @@ ############################################################################### import os +import sys import chroot import packages @@ -142,6 +143,23 @@ class ActionScript(Action): # Load the scriplet. self.scriptlet = self.pkg.get_scriptlet(self.script_action) + def get_lang(self): + if not self.scriptlet: + return + + interp = None + + for line in self.scriptlet.splitlines(): + if line.startswith("#!/"): + interp = "exec" + break + + elif line.startswith("#", "") + break + + return interp + @property def interpreter(self): """ @@ -161,6 +179,22 @@ class ActionScript(Action): # Actually run the scriplet. log.debug("Running scriptlet %s" % self) + # Check of what kind the scriptlet is and run the + # corresponding handler. + lang = self.get_lang() + + if lang == "exec": + self.run_exec() + + elif lang == "python": + self.run_python() + + else: + raise ActionError, _("Could not handle scriptlet of unknown type. Skipping.") + + def run_exec(self): + log.debug(_("Executing python scriptlet...")) + # Check if the interpreter does exist and is executable. if self.interpreter: interpreter = "%s/%s" % (self.pakfire.path, self.interpreter) @@ -224,6 +258,48 @@ class ActionScript(Action): except OSError: log.debug("Could not remove scriptlet file: %s" % script_file) + def run_python(self): + # This functions creates a fork with then chroots into the + # pakfire root if necessary and then compiles the given scriptlet + # code and runs it. + + log.debug(_("Executing python scriptlet...")) + + # Create fork. + pid = os.fork() + + if not pid: + # child code + + # The child chroots into the pakfire path. + if not self.pakfire.path == "/": + os.chroot(self.pakfire.path) + + # Create a clean global environment, where only + # builtin functions are available and the os and sys modules. + _globals = { + "os" : os, + "sys" : sys, + } + + # Compile the scriptlet and execute it. + try: + obj = compile(self.scriptlet, "", "exec") + eval(obj, _globals, {}) + + except Exception, e: + print _("Exception occured: %s") % e + os._exit(1) + + # End the child process without cleaning up. + os._exit(0) + + else: + # parent code + + # Wait until the child process has finished. + os.waitpid(pid, 0) + class ActionScriptPreIn(ActionScript): script_action = "prein" diff --git a/python/pakfire/packages/lexer.py b/python/pakfire/packages/lexer.py index 2e662c9a0..09a8215eb 100644 --- a/python/pakfire/packages/lexer.py +++ b/python/pakfire/packages/lexer.py @@ -51,7 +51,7 @@ LEXER_PACKAGE_LINE = LEXER_BLOCK_LINE LEXER_PACKAGE_END = LEXER_BLOCK_END LEXER_PACKAGE_INHERIT = re.compile(r"^template ([A-Z0-9]+)$") -LEXER_SCRIPTLET_BEGIN = re.compile(r"^script ([a-z]+)\s?(/[A-Za-z0-9\-\_/]+)?$") +LEXER_SCRIPTLET_BEGIN = re.compile(r"^script ([a-z]+)\s?(shell|python)?$") LEXER_SCRIPTLET_LINE = LEXER_BLOCK_LINE LEXER_SCRIPTLET_END = LEXER_BLOCK_END @@ -626,15 +626,11 @@ class TemplateLexer(DefaultLexer): if self.scriptlets.has_key(name): raise Exception, "Scriptlet %s is already defined" % name - path = m.group(2) - if path: - self.scriptlets[name] = { - "lang" : "bin", - "path" : self.expand_string(path), - } - return + lang = m.group(2) or "shell" + lines = [ + "#" % lang, + ] - lines = [] while True: line = self.get_line(self._lineno, raw=True) @@ -658,8 +654,8 @@ class TemplateLexer(DefaultLexer): raise LexerUnhandledLine, "%d: %s" % (self.lineno, line) self.scriptlets[name] = { - "lang" : "shell", - "scriptlet" : "\n".join(lines), + "lang" : lang, + "scriptlet" : self.expand_string("\n".join(lines)), } def get_scriptlet(self, name): diff --git a/python/pakfire/packages/packager.py b/python/pakfire/packages/packager.py index 3ff3c384d..c756b0c5a 100644 --- a/python/pakfire/packages/packager.py +++ b/python/pakfire/packages/packager.py @@ -455,7 +455,9 @@ class BinaryPackager(Packager): # Write script to a file. scriptlet_file = self.mktemp() - if scriptlet["lang"] == "bin": + lang = scriptlet["lang"] + + if lang == "bin": path = lang["path"] try: f = open(path, "b") @@ -474,14 +476,13 @@ class BinaryPackager(Packager): f.close() s.close() - elif scriptlet["lang"] == "shell": + elif lang == "shell": s = open(scriptlet_file, "w") # Write shell script to file. s.write("#!/bin/sh -e\n\n") s.write(scriptlet["scriptlet"]) s.write("\n\nexit 0\n") - s.close() if scriptlet_name in SCRIPTS_PREREQUIRES: @@ -490,6 +491,12 @@ class BinaryPackager(Packager): prerequires += self.builder.find_prerequires(scriptlet_file) + elif lang == "python": + # Write the code to the scriptlet file. + s = open(scriptlet_file, "w") + s.write(scriptlet["scriptlet"]) + s.close() + else: raise Exception, "Unknown scriptlet language: %s" % scriptlet["lang"]