]>
Commit | Line | Data |
---|---|---|
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 | |
22 | import logging | |
94438733 | 23 | import os |
1e80d5d7 | 24 | |
94438733 | 25 | import chroot |
1e80d5d7 | 26 | import packages |
94438733 | 27 | import util |
1e80d5d7 MT |
28 | |
29 | from constants import * | |
30 | from i18n import _ | |
31 | ||
32 | class 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 | |
77 | class 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 | ||
175 | class ActionScriptPreIn(ActionScript): | |
c07a3ca7 | 176 | script_action = "prein" |
1e80d5d7 MT |
177 | |
178 | ||
179 | class ActionScriptPostIn(ActionScript): | |
c07a3ca7 | 180 | script_action = "postin" |
1e80d5d7 MT |
181 | |
182 | ||
183 | class ActionScriptPreUn(ActionScript): | |
c07a3ca7 | 184 | script_action = "preun" |
1e80d5d7 MT |
185 | |
186 | ||
187 | class ActionScriptPostUn(ActionScript): | |
c07a3ca7 | 188 | script_action = "postun" |
1e80d5d7 MT |
189 | |
190 | ||
d767668b | 191 | class ActionScriptPreUp(ActionScript): |
c07a3ca7 | 192 | script_action = "preup" |
d767668b MT |
193 | |
194 | ||
195 | class ActionScriptPostUp(ActionScript): | |
c07a3ca7 | 196 | script_action = "postup" |
d767668b MT |
197 | |
198 | ||
199 | class ActionScriptPostTrans(ActionScript): | |
200 | pass | |
201 | ||
202 | ||
203 | class ActionScriptPostTransIn(ActionScriptPostTrans): | |
c07a3ca7 | 204 | script_action = "posttransin" |
d767668b MT |
205 | |
206 | ||
207 | class ActionScriptPostTransUn(ActionScriptPostTrans): | |
c07a3ca7 | 208 | script_action = "posttransun" |
d767668b MT |
209 | |
210 | ||
211 | class ActionScriptPostTransUp(ActionScriptPostTrans): | |
c07a3ca7 | 212 | script_action = "posttransup" |
d767668b MT |
213 | |
214 | ||
1e80d5d7 MT |
215 | class 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 | ||
225 | class 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 | 235 | class 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 | ||
252 | class 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 | ||
270 | class 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 | ||
282 | class 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 | ||
292 | class 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 |