]>
git.ipfire.org Git - pakfire.git/blob - python/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
):
37 self
.pakfire
= pakfire
38 self
.pkg_solv
= self
.pkg
= pkg
40 # Try to get the binary version of the package from the cache if
42 binary_package
= self
.pkg
.get_from_cache()
44 self
.pkg
= binary_package
48 def __cmp__(self
, other
):
49 return cmp(self
.pkg
, other
.pkg
)
52 return "<%s %s>" % (self
.__class
__.__name
__, self
.pkg
.friendly_name
)
55 # A function to run additional initialization.
58 def check(self
, filelist
):
59 # This is just a dummy test that does nothing at all.
63 assert self
.pkg
, "No package! %s" % self
.pkg_solv
64 assert self
.pkg
.repo
, "Package has no repository? %s" % self
.pkg
66 # Local packages need no verification.
67 if self
.pkg
.repo
.local
:
70 # Check if there are any signatures at all.
71 if not self
.pkg
.signatures
:
72 raise SignatureError
, _("%s has got no signatures") % self
.pkg
.friendly_name
74 # Run the verification process and save the result.
75 sigs
= self
.pkg
.verify()
78 raise SignatureError
, _("%s has got no valid signatures") % self
.pkg
.friendly_name
81 def needs_download(self
):
82 return self
.type in ("install", "reinstall", "upgrade", "downgrade", "change",) \
83 and not isinstance(self
.pkg
, packages
.BinaryPackage
)
85 def download(self
, text
, logger
=None):
86 if not self
.needs_download
:
89 self
.pkg
= self
.pkg
.download(text
, logger
=logger
)
92 raise NotImplementedError
97 Reference to local repository.
99 return self
.pakfire
.repos
.local
101 def do(self
, cmd
, **kwargs
):
102 # If we are running in /, we do not need to chroot there.
104 if not self
.pakfire
.path
== "/":
105 chroot_path
= self
.pakfire
.path
109 for i
in ("tmp", "root"):
111 _cwd
= os
.path
.join(chroot_path
, i
)
115 if os
.path
.exists(_cwd
):
122 "personality" : self
.pakfire
.distro
.personality
,
124 "timeout" : SCRIPTLET_TIMEOUT
,
127 # Overwrite by args that were passed.
130 # You can never overwrite chrootPath.
132 "chrootPath" : chroot_path
,
135 return chroot
.do(cmd
, **args
)
138 class ActionScript(Action
):
144 self
.scriptlet
= self
.pkg
.get_scriptlet(self
.script_action
)
147 if not self
.scriptlet
:
152 for line
in self
.scriptlet
.splitlines():
153 if line
.startswith("#!/"):
157 elif line
.startswith("#<lang: "):
158 interp
= line
[8:].replace(">", "")
164 def interpreter(self
):
166 Get the interpreter of this scriptlet.
168 return util
.scriptlet_interpreter(self
.scriptlet
)
175 # Exit immediately, if the scriptlet is empty.
176 if not self
.scriptlet
:
179 # Actually run the scriplet.
180 log
.debug("Running scriptlet %s" % self
)
182 # Check of what kind the scriptlet is and run the
183 # corresponding handler.
184 lang
= self
.get_lang()
189 elif lang
== "python":
193 raise ActionError
, _("Could not handle scriptlet of unknown type. Skipping.")
196 log
.debug(_("Executing python scriptlet..."))
198 # Check if the interpreter does exist and is executable.
200 interpreter
= "%s/%s" % (self
.pakfire
.path
, self
.interpreter
)
201 if not os
.path
.exists(interpreter
):
202 raise ActionError
, _("Cannot run scriptlet because no interpreter is available: %s" \
205 if not os
.access(interpreter
, os
.X_OK
):
206 raise ActionError
, _("Cannot run scriptlet because the interpreter is not executable: %s" \
209 # Create a name for the temporary script file.
210 script_file_chroot
= os
.path
.join("/", LOCAL_TMP_PATH
,
211 "scriptlet_%s" % util
.random_string(10))
212 script_file
= os
.path
.join(self
.pakfire
.path
, script_file_chroot
[1:])
213 assert script_file
.startswith(self
.pakfire
.path
)
215 # Create script directory, if it does not exist.
216 script_dir
= os
.path
.dirname(script_file
)
217 if not os
.path
.exists(script_dir
):
218 os
.makedirs(script_dir
)
220 # Write the scriptlet to a file that we can execute it.
222 f
= open(script_file
, "wb")
223 f
.write(self
.scriptlet
)
226 # The file is only accessable by root.
227 os
.chmod(script_file
, 700)
229 # Remove the file if an error occurs.
231 os
.unlink(script_file
)
235 # XXX catch errors and return a beautiful message to the user
238 # Generate the script command.
239 command
= [script_file_chroot
] + self
.args
245 raise ActionError
, _("The scriptlet returned an error:\n%s" % e
)
247 except commandTimeoutExpired
:
248 raise ActionError
, _("The scriptlet ran more than %s seconds and was killed." \
252 raise ActionError
, _("The scriptlet returned with an unhandled error:\n%s" % e
)
255 # Remove the script file.
257 os
.unlink(script_file
)
259 log
.debug("Could not remove scriptlet file: %s" % script_file
)
261 def run_python(self
):
262 # This functions creates a fork with then chroots into the
263 # pakfire root if necessary and then compiles the given scriptlet
266 log
.debug(_("Executing python scriptlet..."))
274 # The child chroots into the pakfire path.
275 if not self
.pakfire
.path
== "/":
276 os
.chroot(self
.pakfire
.path
)
278 # Create a clean global environment, where only
279 # builtin functions are available and the os and sys modules.
285 # Compile the scriptlet and execute it.
287 obj
= compile(self
.scriptlet
, "<string>", "exec")
288 eval(obj
, _globals
, {})
291 print _("Exception occured: %s") % e
294 # End the child process without cleaning up.
300 # Wait until the child process has finished.
304 class ActionScriptPreIn(ActionScript
):
305 script_action
= "prein"
308 class ActionScriptPostIn(ActionScript
):
309 script_action
= "postin"
312 class ActionScriptPreUn(ActionScript
):
313 script_action
= "preun"
316 class ActionScriptPostUn(ActionScript
):
317 script_action
= "postun"
320 class ActionScriptPreUp(ActionScript
):
321 script_action
= "preup"
324 class ActionScriptPostUp(ActionScript
):
325 script_action
= "postup"
328 class ActionScriptPreTrans(ActionScript
):
332 class ActionScriptPreTransIn(ActionScriptPreTrans
):
333 script_action
= "pretransin"
336 class ActionScriptPreTransUn(ActionScriptPreTrans
):
337 script_action
= "pretransun"
340 class ActionScriptPreTransUp(ActionScriptPreTrans
):
341 script_action
= "pretransup"
344 class ActionScriptPostTrans(ActionScript
):
348 class ActionScriptPostTransIn(ActionScriptPostTrans
):
349 script_action
= "posttransin"
352 class ActionScriptPostTransUn(ActionScriptPostTrans
):
353 script_action
= "posttransun"
356 class ActionScriptPostTransUp(ActionScriptPostTrans
):
357 script_action
= "posttransup"
360 class ActionInstall(Action
):
363 def check(self
, check
):
364 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
366 # Check if this package can be installed.
367 check
.install(self
.pkg
)
370 # Add package to the database.
371 self
.local
.add_package(self
.pkg
)
373 self
.pkg
.extract(_("Installing"), prefix
=self
.pakfire
.path
)
375 # Check if shared objects were extracted. If this is the case, we need
377 ldconfig_needed
= False
378 for file in self
.pkg
.filelist
:
379 if ".so." in file.name
:
380 ldconfig_needed
= True
383 if "etc/ld.so.conf" in file.name
:
384 ldconfig_needed
= True
388 # Check if ldconfig is present.
389 ldconfig
= os
.path
.join(self
.pakfire
.path
, LDCONFIG
[1:])
391 if os
.path
.exists(ldconfig
) and os
.access(ldconfig
, os
.X_OK
):
395 log
.debug("ldconfig is not present or not executable.")
398 class ActionUpdate(Action
):
401 def check(self
, check
):
402 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
404 # Check if this package can be updated.
405 check
.update(self
.pkg
)
408 # Add new package to the database.
409 self
.local
.add_package(self
.pkg
)
411 self
.pkg
.extract(_("Updating"), prefix
=self
.pakfire
.path
)
414 class ActionRemove(Action
):
417 def __init__(self
, *args
, **kwargs
):
418 Action
.__init
__(self
, *args
, **kwargs
)
420 # XXX This is ugly, but works for the moment.
421 self
.pkg
= self
.local
.db
.get_package_from_solv(self
.pkg_solv
)
424 def check(self
, check
):
425 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
427 # Check if this package can be removed.
428 check
.remove(self
.pkg
)
431 self
.pkg
.cleanup(_("Removing"), prefix
=self
.pakfire
.path
)
433 # Remove package from the database.
434 self
.local
.rem_package(self
.pkg
)
437 class ActionCleanup(Action
):
440 def __init__(self
, *args
, **kwargs
):
441 Action
.__init
__(self
, *args
, **kwargs
)
443 # XXX This is ugly, but works for the moment.
444 self
.pkg
= self
.local
.db
.get_package_from_solv(self
.pkg_solv
)
447 def check(self
, check
):
448 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
450 # Check if this package can be removed.
451 check
.cleanup(self
.pkg
)
454 # Cleaning up leftover files and stuff.
455 self
.pkg
.cleanup(_("Cleanup"), prefix
=self
.pakfire
.path
)
457 # Remove package from the database.
458 self
.local
.rem_package(self
.pkg
)
461 class ActionReinstall(Action
):
464 def check(self
, check
):
465 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
467 # Check if this package can be reinstalled.
468 check
.remove(self
.pkg
)
469 check
.install(self
.pkg
)
472 # Remove package from the database and add it afterwards.
473 # Sounds weird, but fixes broken entries in the database.
474 self
.local
.rem_package(self
.pkg
)
475 self
.local
.add_package(self
.pkg
)
477 self
.pkg
.extract(_("Installing"), prefix
=self
.pakfire
.path
)
480 class ActionDowngrade(Action
):
483 def check(self
, check
):
484 log
.debug(_("Running transaction test for %s") % self
.pkg
.friendly_name
)
486 # Check if this package can be downgraded.
487 check
.install(self
.pkg
)
490 # Add new package to database.
491 self
.local
.add_package(self
.pkg
)
493 self
.pkg
.extract(_("Downgrading"), prefix
=self
.pakfire
.path
)