]> git.ipfire.org Git - pakfire.git/commitdiff
New feature: python scriptlets.
authorMichael Tremer <michael.tremer@ipfire.org>
Fri, 13 Apr 2012 15:41:32 +0000 (17:41 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Fri, 13 Apr 2012 15:41:32 +0000 (17:41 +0200)
python/pakfire/actions.py
python/pakfire/packages/lexer.py
python/pakfire/packages/packager.py

index 1434841f4aefd5f26f2e08dd3b9b11c9ec2e07a0..cdc2778915ae2ce2dccc187535a3d25b8a76d62f 100644 (file)
@@ -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("#<lang: "):
+                               interp = line[8:].replace(">", "")
+                               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, "<string>", "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"
index 2e662c9a0761117eef33b88091182b87bfb102fc..09a8215eb099adcb2ecf8233f16c12bc701f9bfc 100644 (file)
@@ -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: %s>" % 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):
index 3ff3c384d81a69edd58861f248fc1083042460db..c756b0c5aed60363b96341573e8d8cc5815ffb80 100644 (file)
@@ -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"]