###############################################################################
import logging
+import os
+import chroot
import packages
+import util
from constants import *
from i18n import _
if binary_package:
self.pkg = binary_package
+ self.init()
+
def __cmp__(self, other):
return cmp(self.pkg, other.pkg)
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.pkg.friendly_name)
+ def init(self):
+ # A function to run additional initialization.
+ pass
+
@property
def needs_download(self):
return self.type in ("install", "reinstall", "upgrade", "downgrade",) \
class ActionScript(Action):
type = "script"
+ def init(self):
+ # Load the scriplet.
+ self.scriptlet = self.pkg.scriptlet
+
+ @property
+ def interpreter(self):
+ """
+ Get the interpreter of this scriptlet.
+ """
+ # XXX check, how to handle elf files here.
+
+ # If nothing was found, we return the default interpreter.
+ interpreter = SCRIPTLET_INTERPRETER
+
+ for line in self.scriptlet.splitlines():
+ if line.startswith("#!/"):
+ interpreter = line[2:]
+ interpreter = interpreter.split()[0]
+ break
+
+ return interpreter
+
+ @property
+ def args(self):
+ raise NotImplementedError
+
def run(self):
- #print "Pretending to run script: %s" % self.__class__.__name__
- pass
+ # Exit immediately, if the scriptlet is empty.
+ if not self.scriptlet:
+ return
+
+ # Actually run the scriplet.
+ logging.debug("Running scriptlet %s" % self)
+
+ # Check if the interpreter does exist and is executable.
+ interpreter = "%s/%s" % (self.pakfire.path, self.interpreter)
+ if not os.path.exists(interpreter):
+ raise ActionError, _("Cannot run scriptlet because no interpreter is available: %s" \
+ % self.interpreter)
+
+ if not os.access(interpreter, os.X_OK):
+ raise ActionError, _("Cannot run scriptlet because the interpreter is not executable: %s" \
+ % self.interpreter)
+
+ # Create a name for the temporary script file.
+ script_file_chroot = os.path.join("/", LOCAL_TMP_PATH,
+ "scriptlet_%s" % util.random_string(10))
+ script_file = os.path.join(self.pakfire.path, script_file_chroot[1:])
+ assert script_file.startswith("%s/" % self.pakfire.path)
+
+ # Create script directory, if it does not exist.
+ script_dir = os.path.dirname(script_file)
+ if not os.path.exists(script_dir):
+ os.makedirs(script_dir)
+
+ # Write the scriptlet to a file that we can execute it.
+ try:
+ f = open(script_file, "wb")
+ f.write(self.scriptlet)
+ f.close()
+
+ # The file is only accessable by root.
+ os.chmod(script_file, 700)
+ except:
+ # Remove the file if an error occurs.
+ try:
+ os.unlink(script_file)
+ except OSError:
+ pass
+
+ # XXX catch errors and return a beautiful message to the user
+ raise
+
+ command = [script_file_chroot,] + self.args
+
+ # If we are running in /, we do not need to chroot there.
+ chroot_dir = None
+ if not self.pakfire.path == "/":
+ chroot_dir = self.pakfire.path
+
+ try:
+ ret = chroot.do(command, cwd="/tmp",
+ chrootPath=chroot_path,
+ personality=self.pakfire.distro.personality,
+ shell=False,
+ timeout=SCRIPTLET_TIMEOUT,
+ logger=logging.getLogger())
+
+ except Error, e:
+ raise ActionError, _("The scriptlet returned an error:\n%s" % e)
+
+ except commandTimeoutExpired:
+ raise ActionError, _("The scriptlet ran more than %s seconds and was killed." \
+ % SCRIPTLET_TIMEOUT)
+
+ finally:
+ # Remove the script file.
+ try:
+ os.unlink(script_file)
+ except OSError:
+ logging.debug("Could not remove scriptlet file: %s" % script_file)
class ActionScriptPreIn(ActionScript):
- pass
+ @property
+ def args(self):
+ return ["prein",]
class ActionScriptPostIn(ActionScript):
- pass
+ @property
+ def args(self):
+ return ["postin",]
class ActionScriptPreUn(ActionScript):
- pass
+ @property
+ def args(self):
+ return ["preun",]
class ActionScriptPostUn(ActionScript):
- pass
+ @property
+ def args(self):
+ return ["postun",]
class ActionScriptPreUp(ActionScript):
- pass
+ @property
+ def args(self):
+ return ["preup",]
class ActionScriptPostUp(ActionScript):
- pass
+ @property
+ def args(self):
+ return ["postup",]
class ActionScriptPostTrans(ActionScript):
class ActionScriptPostTransIn(ActionScriptPostTrans):
- pass
+ @property
+ def args(self):
+ return ["posttransin",]
class ActionScriptPostTransUn(ActionScriptPostTrans):
- pass
+ @property
+ def args(self):
+ return ["posttransun",]
class ActionScriptPostTransUp(ActionScriptPostTrans):
- pass
+ @property
+ def args(self):
+ return ["posttransup",]
class ActionInstall(Action):
REPO_CACHE_DIR = os.path.join(CACHE_DIR, "repos")
LOCAL_BUILD_REPO_PATH = "/var/lib/pakfire/local"
-LOCAL_TMP_PATH = "/var/tmp/pakfire"
+LOCAL_TMP_PATH = "var/tmp/pakfire"
PACKAGES_DB_DIR = "var/lib/pakfire"
PACKAGES_DB = os.path.join(PACKAGES_DB_DIR, "packages.db")
# XXX make this configurable in pakfire.conf
PAKFIRE_MULTIINSTALL = ["kernel",]
+
+SCRIPTLET_INTERPRETER = "/bin/sh"
+SCRIPTLET_TIMEOUT = 60 * 15
+
+SCRIPTLET_TEMPLATE = """\
+#!/bin/sh
+
+function control_prein() {
+%(control_prein)s
+}
+
+function control_postin() {
+%(control_postin)s
+}
+
+function control_preun() {
+%(control_preun)s
+}
+
+function control_postun() {
+%(control_postun)s
+}
+
+function control_preup() {
+%(control_preup)s
+}
+
+function control_postup() {
+%(control_postup)s
+}
+
+function control_postransin() {
+%(control_posttransin)s
+}
+
+function control_posttransun() {
+%(control_posttransun)s
+}
+
+function control_posttransup() {
+%(control_posttransup)s
+}
+
+# Get right action from commandline.
+action=${1}
+shift
+
+case "${action}" in
+ prein|postin|preun|postun|preup|postup|posttransin|posttransun|posttransup)
+ control_${action} $@
+ ;;
+
+ *)
+ echo "Unknown action: ${action}" >&2
+ exit 2
+ ;;
+esac
+
+# Always exit with an okay status.
+exit 0
+"""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-08-07 13:23+0200\n"
+"POT-Creation-Date: 2011-08-10 18:10+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../pakfire/actions.py:123 ../pakfire/actions.py:180
+#: ../pakfire/actions.py:117
+#, python-format
+msgid "Cannot run scriptlet because no interpreter is available: %s"
+msgstr ""
+
+#: ../pakfire/actions.py:121
+#, python-format
+msgid "Cannot run scriptlet because the interpreter is not executable: %s"
+msgstr ""
+
+#: ../pakfire/actions.py:169
+#, python-format
+msgid ""
+"The scriptlet returned an error:\n"
+"%s"
+msgstr ""
+
+#: ../pakfire/actions.py:172
+#, python-format
+msgid "The scriptlet ran more than %s seconds and was killed."
+msgstr ""
+
+#: ../pakfire/actions.py:248 ../pakfire/actions.py:305
msgid "Installing"
msgstr ""
-#: ../pakfire/actions.py:133
+#: ../pakfire/actions.py:258
msgid "Updating"
msgstr ""
-#: ../pakfire/actions.py:147
+#: ../pakfire/actions.py:272
msgid "Removing"
msgstr ""
#. Cleaning up leftover files and stuff.
-#: ../pakfire/actions.py:165
+#: ../pakfire/actions.py:290
msgid "Cleanup"
msgstr ""
-#: ../pakfire/actions.py:190
+#: ../pakfire/actions.py:315
msgid "Downgrading"
msgstr ""
msgid "Path to input packages."
msgstr ""
-#: ../pakfire/errors.py:27
+#: ../pakfire/errors.py:30
msgid "An unhandled error occured."
msgstr ""
-#: ../pakfire/errors.py:48
+#: ../pakfire/errors.py:51
msgid "One or more dependencies could not been resolved."
msgstr ""
-#: ../pakfire/errors.py:63
+#: ../pakfire/errors.py:66
msgid ""
"The requested action cannot be done on offline mode.\n"
"Please connect your system to the network, remove --offline from the command "