]> git.ipfire.org Git - people/stevee/pakfire.git/blame - python/pakfire/actions.py
logging: Make own pakfire logger.
[people/stevee/pakfire.git] / python / pakfire / actions.py
CommitLineData
1e80d5d7 1#!/usr/bin/python
b792d887
MT
2###############################################################################
3# #
4# Pakfire - The IPFire package management system #
5# Copyright (C) 2011 Pakfire development team #
6# #
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. #
11# #
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. #
16# #
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/>. #
19# #
20###############################################################################
1e80d5d7 21
94438733 22import os
1e80d5d7 23
94438733 24import chroot
1e80d5d7 25import packages
94438733 26import util
1e80d5d7 27
8b6bc023
MT
28import logging
29log = logging.getLogger("pakfire")
30
1e80d5d7
MT
31from constants import *
32from i18n import _
33
34class Action(object):
35 def __init__(self, pakfire, pkg):
36 self.pakfire = pakfire
6ee3d6b9 37 self.pkg_solv = self.pkg = pkg
1e80d5d7
MT
38
39 # Try to get the binary version of the package from the cache if
40 # any.
41 binary_package = self.pkg.get_from_cache()
42 if binary_package:
43 self.pkg = binary_package
44
94438733
MT
45 self.init()
46
aa9f2645
MT
47 def __cmp__(self, other):
48 return cmp(self.pkg, other.pkg)
49
1e80d5d7
MT
50 def __repr__(self):
51 return "<%s %s>" % (self.__class__.__name__, self.pkg.friendly_name)
52
94438733
MT
53 def init(self):
54 # A function to run additional initialization.
55 pass
56
862bea4d
MT
57 def check(self, filelist):
58 # This is just a dummy test that does nothing at all.
59 return filelist
60
1e80d5d7
MT
61 @property
62 def needs_download(self):
6ca2a97f 63 return self.type in ("install", "reinstall", "upgrade", "downgrade", "change",) \
1e80d5d7
MT
64 and not isinstance(self.pkg, packages.BinaryPackage)
65
66 def download(self, text):
67 if not self.needs_download:
68 return
69
70 self.pkg = self.pkg.download(text)
71
72 def run(self):
73 raise NotImplementedError
74
75 @property
76 def local(self):
77 """
78 Reference to local repository.
79 """
80 return self.pakfire.repos.local
81
d335c40e
MT
82 def do(self, cmd, **kwargs):
83 # If we are running in /, we do not need to chroot there.
84 chroot_path = None
85 if not self.pakfire.path == "/":
86 chroot_path = self.pakfire.path
87
88 # Find suitable cwd.
89 cwd = "/"
90 for i in ("tmp", "root"):
254f5e56
MT
91 if chroot_path:
92 _cwd = os.path.join(chroot_path, i)
93 else:
94 _cwd = i
95
d335c40e
MT
96 if os.path.exists(_cwd):
97 cwd = _cwd
98 break
99
100 args = {
101 "cwd" : cwd,
8b6bc023 102 "logger" : log,
d335c40e
MT
103 "personality" : self.pakfire.distro.personality,
104 "shell" : False,
105 "timeout" : SCRIPTLET_TIMEOUT,
106 }
107
108 # Overwrite by args that were passed.
109 args.update(kwargs)
110
111 # You can never overwrite chrootPath.
112 args.update({
113 "chrootPath" : chroot_path,
114 })
115
116 return chroot.do(cmd, **args)
117
1e80d5d7
MT
118
119class ActionScript(Action):
d767668b 120 type = "script"
c07a3ca7 121 script_action = None
d767668b 122
94438733
MT
123 def init(self):
124 # Load the scriplet.
c07a3ca7 125 self.scriptlet = self.pkg.get_scriptlet(self.script_action)
94438733
MT
126
127 @property
128 def interpreter(self):
129 """
130 Get the interpreter of this scriptlet.
131 """
c07a3ca7 132 return util.scriptlet_interpreter(self.scriptlet)
94438733
MT
133
134 @property
135 def args(self):
c07a3ca7 136 return []
94438733 137
1e80d5d7 138 def run(self):
94438733
MT
139 # Exit immediately, if the scriptlet is empty.
140 if not self.scriptlet:
141 return
142
143 # Actually run the scriplet.
8b6bc023 144 log.debug("Running scriptlet %s" % self)
94438733
MT
145
146 # Check if the interpreter does exist and is executable.
c07a3ca7
MT
147 if self.interpreter:
148 interpreter = "%s/%s" % (self.pakfire.path, self.interpreter)
149 if not os.path.exists(interpreter):
150 raise ActionError, _("Cannot run scriptlet because no interpreter is available: %s" \
151 % self.interpreter)
94438733 152
c07a3ca7
MT
153 if not os.access(interpreter, os.X_OK):
154 raise ActionError, _("Cannot run scriptlet because the interpreter is not executable: %s" \
155 % self.interpreter)
94438733
MT
156
157 # Create a name for the temporary script file.
158 script_file_chroot = os.path.join("/", LOCAL_TMP_PATH,
159 "scriptlet_%s" % util.random_string(10))
160 script_file = os.path.join(self.pakfire.path, script_file_chroot[1:])
254f5e56 161 assert script_file.startswith(self.pakfire.path)
94438733
MT
162
163 # Create script directory, if it does not exist.
164 script_dir = os.path.dirname(script_file)
165 if not os.path.exists(script_dir):
166 os.makedirs(script_dir)
167
168 # Write the scriptlet to a file that we can execute it.
169 try:
170 f = open(script_file, "wb")
171 f.write(self.scriptlet)
172 f.close()
173
174 # The file is only accessable by root.
175 os.chmod(script_file, 700)
176 except:
177 # Remove the file if an error occurs.
178 try:
179 os.unlink(script_file)
180 except OSError:
181 pass
182
183 # XXX catch errors and return a beautiful message to the user
184 raise
185
c07a3ca7
MT
186 # Generate the script command.
187 command = [script_file_chroot] + self.args
94438733 188
94438733 189 try:
d335c40e 190 self.do(command)
94438733
MT
191
192 except Error, e:
193 raise ActionError, _("The scriptlet returned an error:\n%s" % e)
194
195 except commandTimeoutExpired:
196 raise ActionError, _("The scriptlet ran more than %s seconds and was killed." \
197 % SCRIPTLET_TIMEOUT)
198
199 finally:
200 # Remove the script file.
201 try:
202 os.unlink(script_file)
203 except OSError:
8b6bc023 204 log.debug("Could not remove scriptlet file: %s" % script_file)
1e80d5d7
MT
205
206
207class ActionScriptPreIn(ActionScript):
c07a3ca7 208 script_action = "prein"
1e80d5d7
MT
209
210
211class ActionScriptPostIn(ActionScript):
c07a3ca7 212 script_action = "postin"
1e80d5d7
MT
213
214
215class ActionScriptPreUn(ActionScript):
c07a3ca7 216 script_action = "preun"
1e80d5d7
MT
217
218
219class ActionScriptPostUn(ActionScript):
c07a3ca7 220 script_action = "postun"
1e80d5d7
MT
221
222
d767668b 223class ActionScriptPreUp(ActionScript):
c07a3ca7 224 script_action = "preup"
d767668b
MT
225
226
227class ActionScriptPostUp(ActionScript):
c07a3ca7 228 script_action = "postup"
d767668b
MT
229
230
231class ActionScriptPostTrans(ActionScript):
232 pass
233
234
235class ActionScriptPostTransIn(ActionScriptPostTrans):
c07a3ca7 236 script_action = "posttransin"
d767668b
MT
237
238
239class ActionScriptPostTransUn(ActionScriptPostTrans):
c07a3ca7 240 script_action = "posttransun"
d767668b
MT
241
242
243class ActionScriptPostTransUp(ActionScriptPostTrans):
c07a3ca7 244 script_action = "posttransup"
d767668b
MT
245
246
1e80d5d7
MT
247class ActionInstall(Action):
248 type = "install"
249
862bea4d 250 def check(self, check):
8b6bc023 251 log.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
862bea4d
MT
252
253 # Check if this package can be installed.
254 check.install(self.pkg)
255
1e80d5d7 256 def run(self):
e871a081
MT
257 # Add package to the database.
258 self.local.add_package(self.pkg)
259
260 self.pkg.extract(_("Installing"), prefix=self.pakfire.path)
1e80d5d7 261
d335c40e
MT
262 # Check if shared objects were extracted. If this is the case, we need
263 # to run ldconfig.
264 ldconfig_needed = False
265 for file in self.pkg.filelist:
266 if ".so." in file.name:
267 ldconfig_needed = True
268 break
269
270 if "etc/ld.so.conf" in file.name:
271 ldconfig_needed = True
272 break
273
274 if ldconfig_needed:
275 # Check if ldconfig is present.
276 ldconfig = os.path.join(self.pakfire.path, LDCONFIG[1:])
277
278 if os.path.exists(ldconfig) and os.access(ldconfig, os.X_OK):
279 self.do(LDCONFIG)
280
281 else:
8b6bc023 282 log.debug("ldconfig is not present or not executable.")
d335c40e 283
1e80d5d7
MT
284
285class ActionUpdate(Action):
286 type = "upgrade"
287
862bea4d 288 def check(self, check):
8b6bc023 289 log.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
862bea4d
MT
290
291 # Check if this package can be updated.
292 check.update(self.pkg)
293
1e80d5d7 294 def run(self):
e871a081
MT
295 # Add new package to the database.
296 self.local.add_package(self.pkg)
297
298 self.pkg.extract(_("Updating"), prefix=self.pakfire.path)
1e80d5d7
MT
299
300
6ee3d6b9 301class ActionRemove(Action):
1e80d5d7
MT
302 type = "erase"
303
6ee3d6b9
MT
304 def __init__(self, *args, **kwargs):
305 Action.__init__(self, *args, **kwargs)
1e80d5d7 306
6ee3d6b9
MT
307 # XXX This is ugly, but works for the moment.
308 self.pkg = self.local.index.db.get_package_from_solv(self.pkg_solv)
309 assert self.pkg
310
862bea4d 311 def check(self, check):
8b6bc023 312 log.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
862bea4d
MT
313
314 # Check if this package can be removed.
315 check.remove(self.pkg)
316
6ee3d6b9 317 def run(self):
890c7e93 318 self.pkg.cleanup(_("Removing"), prefix=self.pakfire.path)
1e80d5d7 319
e871a081
MT
320 # Remove package from the database.
321 self.local.rem_package(self.pkg)
322
323
324class ActionCleanup(Action):
325 type = "ignore"
326
327 def __init__(self, *args, **kwargs):
328 Action.__init__(self, *args, **kwargs)
329
330 # XXX This is ugly, but works for the moment.
331 self.pkg = self.local.index.db.get_package_from_solv(self.pkg_solv)
332 assert self.pkg
333
862bea4d 334 def check(self, check):
8b6bc023 335 log.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
862bea4d
MT
336
337 # Check if this package can be removed.
338 check.cleanup(self.pkg)
339
e871a081
MT
340 def run(self):
341 # Cleaning up leftover files and stuff.
342 self.pkg.cleanup(_("Cleanup"), prefix=self.pakfire.path)
343
344 # Remove package from the database.
345 self.local.rem_package(self.pkg)
1e80d5d7
MT
346
347
348class ActionReinstall(Action):
349 type = "reinstall"
350
862bea4d 351 def check(self, check):
8b6bc023 352 log.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
862bea4d
MT
353
354 # Check if this package can be reinstalled.
355 check.remove(self.pkg)
356 check.install(self.pkg)
357
1e80d5d7 358 def run(self):
e871a081
MT
359 # Remove package from the database and add it afterwards.
360 # Sounds weird, but fixes broken entries in the database.
361 self.local.rem_package(self.pkg)
362 self.local.add_package(self.pkg)
363
364 self.pkg.extract(_("Installing"), prefix=self.pakfire.path)
1e80d5d7
MT
365
366
367class ActionDowngrade(Action):
368 type = "downgrade"
369
862bea4d 370 def check(self, check):
8b6bc023 371 log.debug(_("Running transaction test for %s") % self.pkg.friendly_name)
862bea4d
MT
372
373 # Check if this package can be downgraded.
374 check.install(self.pkg)
375
1e80d5d7 376 def run(self):
e871a081
MT
377 # Add new package to database.
378 self.local.add_package(self.pkg)
379
380 self.pkg.extract(_("Downgrading"), prefix=self.pakfire.path)