]>
git.ipfire.org Git - people/stevee/pakfire.git/blob - src/pakfire/actions.py
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
30 log
= logging
.getLogger("pakfire")
32 from constants
import *
36 def __init__(self
, pakfire
, pkg_solv
, pkg_bin
=None):
37 self
.pakfire
= pakfire
39 self
.pkg_solv
= pkg_solv
41 self
.pkg_bin
= pkg_bin
45 def __cmp__(self
, other
):
46 return cmp(self
.pkg
, other
.pkg
)
49 return "<%s %s>" % (self
.__class
__.__name
__, self
.pkg
.friendly_name
)
52 # A function to run additional initialization.
55 def check(self
, filelist
):
56 # This is just a dummy test that does nothing at all.
60 assert self
.pkg
, "No package! %s" % self
.pkg
61 assert self
.pkg
.repo
, "Package has no repository? %s" % self
.pkg
63 # Local packages need no verification.
64 if self
.pkg
.repo
.local
:
67 # Check if there are any signatures at all.
68 if not self
.pkg
.signatures
:
69 raise SignatureError
, _("%s has got no signatures") % self
.pkg
.friendly_name
71 # Run the verification process and save the result.
72 sigs
= self
.pkg
.verify()
75 raise SignatureError
, _("%s has got no valid signatures") % self
.pkg
.friendly_name
80 Return the best version of the package we can use.
82 return self
.pkg_bin
or self
.pkg_solv
84 def get_binary_package(self
):
86 Tries to find the binary version of the package in the local cache.
88 return self
.pkg_solv
.get_from_cache()
90 def _get_pkg_bin(self
):
91 if not hasattr(self
, "_pkg_bin"):
92 self
._pkg
_bin
= self
.get_binary_package()
96 def _set_pkg_bin(self
, pkg
):
97 if pkg
and not self
.pkg_solv
.uuid
== pkg
.uuid
:
98 raise RuntimeError, "Not the same package: %s != %s" % (self
.pkg_solv
, pkg
)
102 pkg_bin
= property(_get_pkg_bin
, _set_pkg_bin
)
105 raise NotImplementedError
110 Reference to local repository.
112 return self
.pakfire
.repos
.local
114 def get_logger_name(self
):
115 return "pakfire.action.%s" % self
.pkg
.friendly_name
117 def get_logger(self
):
118 logger_name
= self
.get_logger_name()
120 logger
= logging
.getLogger(logger_name
)
121 logger
.setLevel(logging
.INFO
)
123 # Propagate everything to upstream logger.
124 logger
.propagate
= True
128 def execute(self
, command
, **kwargs
):
129 # If we are running in /, we do not need to chroot there.
131 if not self
.pakfire
.path
== "/":
132 chroot_path
= self
.pakfire
.path
136 for i
in ("tmp", "root"):
138 _cwd
= os
.path
.join(chroot_path
, i
)
142 if os
.path
.exists(_cwd
):
148 "env" : MINIMAL_ENVIRONMENT
,
149 "logger" : self
.get_logger(),
150 "personality" : self
.pakfire
.distro
.personality
,
152 "timeout" : SCRIPTLET_TIMEOUT
,
155 # Overwrite by args that were passed.
158 # You can never overwrite chrootPath.
159 args
["chroot_path"] = chroot_path
162 shellenv
= shell
.ShellExecuteEnvironment(command
, **args
)
166 class ActionScript(Action
):
171 self
._scriptlet
= None
173 def get_logger_name(self
):
174 logger_name
= Action
.get_logger_name(self
)
176 return "%s.%s" % (logger_name
, self
.script_action
or "unknown")
183 if self
._scriptlet
is None:
184 self
._scriptlet
= self
.pkg
.get_scriptlet(self
.script_action
)
186 return self
._scriptlet
189 if not self
.scriptlet
:
194 for line
in self
.scriptlet
.splitlines():
195 if line
.startswith("#!/"):
199 elif line
.startswith("#<lang: "):
200 interp
= line
[8:].replace(">", "")
206 def interpreter(self
):
208 Get the interpreter of this scriptlet.
210 return util
.scriptlet_interpreter(self
.scriptlet
)
217 # Exit immediately, if the scriptlet is empty.
218 if not self
.scriptlet
:
221 # Actually run the scriplet.
222 log
.debug("Running scriptlet %s" % self
)
224 # Check of what kind the scriptlet is and run the
225 # corresponding handler.
226 lang
= self
.get_lang()
231 elif lang
== "python":
235 raise ActionError
, _("Could not handle scriptlet of unknown type. Skipping.")
238 log
.debug(_("Executing scriptlet..."))
240 # Check if the interpreter does exist and is executable.
242 interpreter
= "%s/%s" % (self
.pakfire
.path
, self
.interpreter
)
243 if not os
.path
.exists(interpreter
):
244 raise ActionError
, _("Cannot run scriptlet because no interpreter is available: %s" \
247 if not os
.access(interpreter
, os
.X_OK
):
248 raise ActionError
, _("Cannot run scriptlet because the interpreter is not executable: %s" \
251 # Create a name for the temporary script file.
252 script_file_chroot
= os
.path
.join("/", LOCAL_TMP_PATH
,
253 "scriptlet_%s" % util
.random_string(10))
254 script_file
= os
.path
.join(self
.pakfire
.path
, script_file_chroot
[1:])
255 assert script_file
.startswith(self
.pakfire
.path
)
257 # Create script directory, if it does not exist.
258 script_dir
= os
.path
.dirname(script_file
)
259 if not os
.path
.exists(script_dir
):
260 os
.makedirs(script_dir
)
262 # Write the scriptlet to a file that we can execute it.
264 f
= open(script_file
, "wb")
265 f
.write(self
.scriptlet
)
268 # The file is only accessable by root.
269 os
.chmod(script_file
, 700)
271 # Remove the file if an error occurs.
273 os
.unlink(script_file
)
277 # XXX catch errors and return a beautiful message to the user
280 # Generate the script command.
281 command
= [script_file_chroot
] + self
.args
284 self
.execute(command
)
286 except ShellEnvironmentError
, e
:
287 raise ActionError
, _("The scriptlet returned an error:\n%s" % e
)
289 except commandTimeoutExpired
:
290 raise ActionError
, _("The scriptlet ran more than %s seconds and was killed." \
294 raise ActionError
, _("The scriptlet returned with an unhandled error:\n%s" % e
)
297 # Remove the script file.
299 os
.unlink(script_file
)
301 log
.debug("Could not remove scriptlet file: %s" % script_file
)
303 def run_python(self
):
304 # This functions creates a fork with then chroots into the
305 # pakfire root if necessary and then compiles the given scriptlet
308 log
.debug(_("Executing python scriptlet..."))
316 # The child chroots into the pakfire path.
317 if not self
.pakfire
.path
== "/":
318 os
.chroot(self
.pakfire
.path
)
320 # Create a clean global environment, where only
321 # builtin functions are available and the os and sys modules.
327 # Compile the scriptlet and execute it.
329 obj
= compile(self
.scriptlet
, "<string>", "exec")
330 eval(obj
, _globals
, {})
333 print _("Exception occured: %s") % e
336 # End the child process without cleaning up.
342 # Wait until the child process has finished.
346 class ActionScriptPreIn(ActionScript
):
347 script_action
= "prein"
350 class ActionScriptPostIn(ActionScript
):
351 script_action
= "postin"
354 class ActionScriptPreUn(ActionScript
):
355 script_action
= "preun"
358 class ActionScriptPostUn(ActionScript
):
359 script_action
= "postun"
362 class ActionScriptPreUp(ActionScript
):
363 script_action
= "preup"
366 class ActionScriptPostUp(ActionScript
):
367 script_action
= "postup"
370 class ActionScriptPreTrans(ActionScript
):
374 class ActionScriptPreTransIn(ActionScriptPreTrans
):
375 script_action
= "pretransin"
378 class ActionScriptPreTransUn(ActionScriptPreTrans
):
379 script_action
= "pretransun"
382 class ActionScriptPreTransUp(ActionScriptPreTrans
):
383 script_action
= "pretransup"
386 class ActionScriptPostTrans(ActionScript
):
390 class ActionScriptPostTransIn(ActionScriptPostTrans
):
391 script_action
= "posttransin"
394 class ActionScriptPostTransUn(ActionScriptPostTrans
):
395 script_action
= "posttransun"
398 class ActionScriptPostTransUp(ActionScriptPostTrans
):
399 script_action
= "posttransup"
402 class ActionInstall(Action
):
405 def check(self
, check
):
406 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
408 # Check if this package can be installed.
409 check
.install(self
.pkg
)
412 # Add package to the database.
413 self
.local
.add_package(self
.pkg
)
415 if isinstance(self
, ActionReinstall
):
416 msg
= _("Reinstalling")
417 elif isinstance(self
, ActionUpdate
):
419 elif isinstance(self
, ActionDowngrade
):
420 msg
= _("Downgrading")
422 msg
= _("Installing")
424 self
.pkg
.extract(msg
, prefix
=self
.pakfire
.path
)
426 # Check if shared objects were extracted. If this is the case, we need
428 ldconfig_needed
= False
429 for file in self
.pkg
.filelist
:
430 if ".so." in file.name
:
431 ldconfig_needed
= True
434 if "etc/ld.so.conf" in file.name
:
435 ldconfig_needed
= True
439 # Check if ldconfig is present.
440 ldconfig
= os
.path
.join(self
.pakfire
.path
, LDCONFIG
[1:])
442 if os
.path
.exists(ldconfig
) and os
.access(ldconfig
, os
.X_OK
):
443 self
.execute(LDCONFIG
)
446 log
.debug("ldconfig is not present or not executable.")
449 class ActionUpdate(ActionInstall
):
452 def check(self
, check
):
453 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
455 # Check if this package can be updated.
456 check
.update(self
.pkg
)
459 class ActionRemove(Action
):
462 def check(self
, check
):
463 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
465 # Check if this package can be removed.
466 check
.remove(self
.pkg
)
469 if isinstance(self
, ActionCleanup
):
474 self
.pkg
.cleanup(msg
, prefix
=self
.pakfire
.path
)
476 # Remove package from the database.
477 self
.local
.rem_package(self
.pkg
)
480 class ActionCleanup(ActionRemove
):
483 def check(self
, check
):
484 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
486 # Check if this package can be removed.
487 check
.cleanup(self
.pkg
)
490 class ActionReinstall(ActionInstall
):
494 class ActionDowngrade(ActionInstall
):