]> git.ipfire.org Git - pakfire.git/blame - pakfire/actions.py
macros: Move make_*_targets into build section.
[pakfire.git] / 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
MT
21
22import logging
94438733 23import os
1e80d5d7 24
94438733 25import chroot
1e80d5d7 26import packages
94438733 27import util
1e80d5d7
MT
28
29from constants import *
30from i18n import _
31
32class Action(object):
33 def __init__(self, pakfire, pkg):
34 self.pakfire = pakfire
6ee3d6b9 35 self.pkg_solv = self.pkg = pkg
1e80d5d7
MT
36
37 # Try to get the binary version of the package from the cache if
38 # any.
39 binary_package = self.pkg.get_from_cache()
40 if binary_package:
41 self.pkg = binary_package
42
94438733
MT
43 self.init()
44
aa9f2645
MT
45 def __cmp__(self, other):
46 return cmp(self.pkg, other.pkg)
47
1e80d5d7
MT
48 def __repr__(self):
49 return "<%s %s>" % (self.__class__.__name__, self.pkg.friendly_name)
50
94438733
MT
51 def init(self):
52 # A function to run additional initialization.
53 pass
54
1e80d5d7
MT
55 @property
56 def needs_download(self):
57 return self.type in ("install", "reinstall", "upgrade", "downgrade",) \
58 and not isinstance(self.pkg, packages.BinaryPackage)
59
60 def download(self, text):
61 if not self.needs_download:
62 return
63
64 self.pkg = self.pkg.download(text)
65
66 def run(self):
67 raise NotImplementedError
68
69 @property
70 def local(self):
71 """
72 Reference to local repository.
73 """
74 return self.pakfire.repos.local
75
1e80d5d7
MT
76
77class ActionScript(Action):
d767668b 78 type = "script"
c07a3ca7 79 script_action = None
d767668b 80
94438733
MT
81 def init(self):
82 # Load the scriplet.
c07a3ca7 83 self.scriptlet = self.pkg.get_scriptlet(self.script_action)
94438733
MT
84
85 @property
86 def interpreter(self):
87 """
88 Get the interpreter of this scriptlet.
89 """
c07a3ca7 90 return util.scriptlet_interpreter(self.scriptlet)
94438733
MT
91
92 @property
93 def args(self):
c07a3ca7 94 return []
94438733 95
1e80d5d7 96 def run(self):
94438733
MT
97 # Exit immediately, if the scriptlet is empty.
98 if not self.scriptlet:
99 return
100
101 # Actually run the scriplet.
102 logging.debug("Running scriptlet %s" % self)
103
104 # Check if the interpreter does exist and is executable.
c07a3ca7
MT
105 if self.interpreter:
106 interpreter = "%s/%s" % (self.pakfire.path, self.interpreter)
107 if not os.path.exists(interpreter):
108 raise ActionError, _("Cannot run scriptlet because no interpreter is available: %s" \
109 % self.interpreter)
94438733 110
c07a3ca7
MT
111 if not os.access(interpreter, os.X_OK):
112 raise ActionError, _("Cannot run scriptlet because the interpreter is not executable: %s" \
113 % self.interpreter)
94438733
MT
114
115 # Create a name for the temporary script file.
116 script_file_chroot = os.path.join("/", LOCAL_TMP_PATH,
117 "scriptlet_%s" % util.random_string(10))
118 script_file = os.path.join(self.pakfire.path, script_file_chroot[1:])
119 assert script_file.startswith("%s/" % self.pakfire.path)
120
121 # Create script directory, if it does not exist.
122 script_dir = os.path.dirname(script_file)
123 if not os.path.exists(script_dir):
124 os.makedirs(script_dir)
125
126 # Write the scriptlet to a file that we can execute it.
127 try:
128 f = open(script_file, "wb")
129 f.write(self.scriptlet)
130 f.close()
131
132 # The file is only accessable by root.
133 os.chmod(script_file, 700)
134 except:
135 # Remove the file if an error occurs.
136 try:
137 os.unlink(script_file)
138 except OSError:
139 pass
140
141 # XXX catch errors and return a beautiful message to the user
142 raise
143
c07a3ca7
MT
144 # Generate the script command.
145 command = [script_file_chroot] + self.args
94438733
MT
146
147 # If we are running in /, we do not need to chroot there.
c07a3ca7 148 chroot_path = None
94438733 149 if not self.pakfire.path == "/":
c07a3ca7 150 chroot_path = self.pakfire.path
94438733
MT
151
152 try:
153 ret = chroot.do(command, cwd="/tmp",
154 chrootPath=chroot_path,
155 personality=self.pakfire.distro.personality,
156 shell=False,
157 timeout=SCRIPTLET_TIMEOUT,
158 logger=logging.getLogger())
159
160 except Error, e:
161 raise ActionError, _("The scriptlet returned an error:\n%s" % e)
162
163 except commandTimeoutExpired:
164 raise ActionError, _("The scriptlet ran more than %s seconds and was killed." \
165 % SCRIPTLET_TIMEOUT)
166
167 finally:
168 # Remove the script file.
169 try:
170 os.unlink(script_file)
171 except OSError:
172 logging.debug("Could not remove scriptlet file: %s" % script_file)
1e80d5d7
MT
173
174
175class ActionScriptPreIn(ActionScript):
c07a3ca7 176 script_action = "prein"
1e80d5d7
MT
177
178
179class ActionScriptPostIn(ActionScript):
c07a3ca7 180 script_action = "postin"
1e80d5d7
MT
181
182
183class ActionScriptPreUn(ActionScript):
c07a3ca7 184 script_action = "preun"
1e80d5d7
MT
185
186
187class ActionScriptPostUn(ActionScript):
c07a3ca7 188 script_action = "postun"
1e80d5d7
MT
189
190
d767668b 191class ActionScriptPreUp(ActionScript):
c07a3ca7 192 script_action = "preup"
d767668b
MT
193
194
195class ActionScriptPostUp(ActionScript):
c07a3ca7 196 script_action = "postup"
d767668b
MT
197
198
199class ActionScriptPostTrans(ActionScript):
200 pass
201
202
203class ActionScriptPostTransIn(ActionScriptPostTrans):
c07a3ca7 204 script_action = "posttransin"
d767668b
MT
205
206
207class ActionScriptPostTransUn(ActionScriptPostTrans):
c07a3ca7 208 script_action = "posttransun"
d767668b
MT
209
210
211class ActionScriptPostTransUp(ActionScriptPostTrans):
c07a3ca7 212 script_action = "posttransup"
d767668b
MT
213
214
1e80d5d7
MT
215class ActionInstall(Action):
216 type = "install"
217
218 def run(self):
e871a081
MT
219 # Add package to the database.
220 self.local.add_package(self.pkg)
221
222 self.pkg.extract(_("Installing"), prefix=self.pakfire.path)
1e80d5d7
MT
223
224
225class ActionUpdate(Action):
226 type = "upgrade"
227
228 def run(self):
e871a081
MT
229 # Add new package to the database.
230 self.local.add_package(self.pkg)
231
232 self.pkg.extract(_("Updating"), prefix=self.pakfire.path)
1e80d5d7
MT
233
234
6ee3d6b9 235class ActionRemove(Action):
1e80d5d7
MT
236 type = "erase"
237
6ee3d6b9
MT
238 def __init__(self, *args, **kwargs):
239 Action.__init__(self, *args, **kwargs)
1e80d5d7 240
6ee3d6b9
MT
241 # XXX This is ugly, but works for the moment.
242 self.pkg = self.local.index.db.get_package_from_solv(self.pkg_solv)
243 assert self.pkg
244
245 def run(self):
890c7e93 246 self.pkg.cleanup(_("Removing"), prefix=self.pakfire.path)
1e80d5d7 247
e871a081
MT
248 # Remove package from the database.
249 self.local.rem_package(self.pkg)
250
251
252class ActionCleanup(Action):
253 type = "ignore"
254
255 def __init__(self, *args, **kwargs):
256 Action.__init__(self, *args, **kwargs)
257
258 # XXX This is ugly, but works for the moment.
259 self.pkg = self.local.index.db.get_package_from_solv(self.pkg_solv)
260 assert self.pkg
261
262 def run(self):
263 # Cleaning up leftover files and stuff.
264 self.pkg.cleanup(_("Cleanup"), prefix=self.pakfire.path)
265
266 # Remove package from the database.
267 self.local.rem_package(self.pkg)
1e80d5d7
MT
268
269
270class ActionReinstall(Action):
271 type = "reinstall"
272
273 def run(self):
e871a081
MT
274 # Remove package from the database and add it afterwards.
275 # Sounds weird, but fixes broken entries in the database.
276 self.local.rem_package(self.pkg)
277 self.local.add_package(self.pkg)
278
279 self.pkg.extract(_("Installing"), prefix=self.pakfire.path)
1e80d5d7
MT
280
281
282class ActionDowngrade(Action):
283 type = "downgrade"
284
285 def run(self):
e871a081
MT
286 # Add new package to database.
287 self.local.add_package(self.pkg)
288
289 self.pkg.extract(_("Downgrading"), prefix=self.pakfire.path)
1e80d5d7
MT
290
291
292class ActionChange(Action):
293 type = "change"
294
e871a081
MT
295 # XXX still need to find out what this should be doing
296
1e80d5d7
MT
297 def run(self):
298 print "XXX Change: %s" % self.pkg