]>
Commit | Line | Data |
---|---|---|
ae20b05f MT |
1 | #!/usr/bin/python |
2 | ||
3 | import logging | |
4 | import os | |
5 | import progressbar | |
0c1a80b8 | 6 | import satsolver |
ae20b05f MT |
7 | import sys |
8 | ||
9 | import pakfire.packages as packages | |
10 | import pakfire.util as util | |
11 | ||
12 | from pakfire.i18n import _ | |
13 | ||
14 | PKG_DUMP_FORMAT = " %-21s %-8s %-21s %-19s %5s " | |
15 | ||
16 | class ActionError(Exception): | |
17 | pass | |
18 | ||
19 | ||
20 | class Action(object): | |
21 | def __init__(self, pakfire, pkg, deps=None): | |
22 | self.pakfire = pakfire | |
23 | self.pkg = pkg | |
24 | self.deps = deps or [] | |
25 | ||
26 | def __cmp__(self, other): | |
27 | # XXX ugly | |
28 | return cmp(self.__repr__(), other.__repr__()) | |
29 | ||
30 | def __repr__(self): | |
31 | return "<%s %s>" % (self.__class__.__name__, self.pkg.friendly_name) | |
32 | ||
33 | def remove_dep(self, dep): | |
34 | if not self.deps: | |
35 | return | |
36 | ||
37 | while dep in self.deps: | |
38 | logging.debug("Removing dep %s from %s" % (dep, self)) | |
39 | self.deps.remove(dep) | |
40 | ||
41 | def run(self): | |
42 | raise NotImplementedError | |
43 | ||
44 | @property | |
45 | def local(self): | |
46 | """ | |
47 | Reference to local repository (database). | |
48 | """ | |
49 | return self.pakfire.repos.local | |
50 | ||
51 | ||
52 | class ActionCleanup(Action): | |
0c1a80b8 | 53 | type = "ignore" |
ae20b05f MT |
54 | |
55 | def run(self): | |
0c1a80b8 | 56 | print "XXX Cleanup: %s" % self.pkg |
ae20b05f MT |
57 | |
58 | ||
59 | class ActionScript(Action): | |
60 | def run(self): | |
61 | pass # XXX TBD | |
62 | ||
63 | ||
64 | class ActionScriptPreIn(ActionScript): | |
65 | pass | |
66 | ||
67 | ||
68 | class ActionScriptPostIn(ActionScript): | |
69 | pass | |
70 | ||
71 | ||
72 | class ActionScriptPreUn(ActionScript): | |
73 | pass | |
74 | ||
75 | ||
76 | class ActionScriptPostUn(ActionScript): | |
77 | pass | |
78 | ||
79 | ||
80 | class ActionInstall(Action): | |
81 | type = "install" | |
82 | ||
83 | def extract(self, message, prefix=None): | |
84 | logging.debug("Extracting package %s" % self.pkg.friendly_name) | |
85 | ||
86 | if prefix is None: | |
87 | prefix = self.pakfire.path | |
88 | ||
89 | self.pkg.extract(message, prefix=prefix) | |
90 | ||
91 | # Create package in the database | |
92 | self.local.index.add_package(self.pkg) | |
93 | ||
94 | def run(self): | |
95 | self.extract(_("Installing: %s") % self.pkg.name) | |
96 | ||
97 | self.pakfire.solver.add_package(self.pkg, "installed") | |
98 | ||
99 | ||
100 | class ActionUpdate(ActionInstall): | |
0c1a80b8 | 101 | type = "upgrade" |
ae20b05f MT |
102 | |
103 | def run(self): | |
104 | self.extract(_("Updating: %s") % self.pkg.name) | |
105 | ||
106 | ||
107 | class ActionRemove(ActionCleanup): | |
a39fd08b | 108 | type = "erase" |
ae20b05f MT |
109 | |
110 | def run(self): | |
111 | files = self.pkg.filelist | |
112 | ||
113 | if not files: | |
114 | return | |
115 | ||
116 | self.remove_files(_("Removing: %s") % self.pkg.name, files) | |
117 | ||
118 | ||
119 | class Transaction(object): | |
120 | action_classes = [ | |
121 | ActionInstall, | |
122 | ActionUpdate, | |
123 | ActionRemove, | |
0c1a80b8 | 124 | ActionCleanup, |
ae20b05f MT |
125 | ] |
126 | ||
127 | def __init__(self, pakfire): | |
128 | self.pakfire = pakfire | |
129 | self.actions = [] | |
130 | ||
131 | self.downloads = [] | |
132 | ||
0c1a80b8 MT |
133 | self.installs = [] |
134 | self.updates = [] | |
135 | self.removes = [] | |
136 | ||
ae20b05f MT |
137 | @classmethod |
138 | def from_solver(cls, pakfire, solver1, solver2): | |
139 | # Grab the original transaction object from the solver. | |
140 | _transaction = solver2.transaction() | |
141 | ||
142 | # Order the objects in the transaction in that way we will run the | |
143 | # installation. | |
144 | _transaction.order() | |
145 | ||
146 | # Create a new instance of our own transaction class. | |
147 | transaction = cls(pakfire) | |
148 | ||
0c1a80b8 MT |
149 | # Copy all information. |
150 | transaction.installs = solver1.solvables2packages(solver2.installs()) | |
151 | transaction.updates = \ | |
152 | [p for p in solver1.solvables2packages(solver2.updates()) if not p.repo.name == "installed"] | |
153 | transaction.removes = solver1.solvables2packages(solver2.removes()) | |
154 | ||
ae20b05f | 155 | for step in _transaction.steps(): |
0c1a80b8 | 156 | action = step.type_s(satsolver.TRANSACTION_MODE_ACTIVE) |
ae20b05f MT |
157 | pkg = solver1.id2pkg[step.solvable().id()] |
158 | ||
0c1a80b8 | 159 | if action in ("install", "upgrade") and not isinstance(pkg, packages.BinaryPackage): |
ae20b05f MT |
160 | transaction.downloads.append(pkg) |
161 | ||
162 | for action_cls in cls.action_classes: | |
163 | if action_cls.type == action: | |
164 | action = action_cls(pakfire, pkg) | |
165 | ||
166 | if not isinstance(action, Action): | |
167 | raise Exception, "Unknown action required: %s" % action | |
168 | ||
169 | transaction.add_action(action) | |
170 | ||
171 | return transaction | |
172 | ||
173 | def download(self): | |
174 | if not self.downloads: | |
175 | return | |
176 | ||
177 | i = 0 | |
178 | for pkg in self.downloads: | |
179 | i += 1 | |
180 | ||
181 | # Actually download the package. | |
182 | pkg_bin = pkg.download(text="(%2d/%02d): " % (i, len(self.downloads))) | |
183 | ||
184 | # Replace the package in all actions where it matches. | |
185 | actions = [a for a in self.actions if a.pkg == pkg] | |
186 | ||
187 | for action in actions: | |
188 | action.pkg = pkg_bin | |
189 | ||
190 | # Reset packages to be downloaded. | |
191 | self.downloads = [] | |
192 | ||
193 | ||
ae20b05f MT |
194 | def dump_pkg(self, pkg): |
195 | ret = [] | |
196 | ||
197 | name = pkg.name | |
198 | if len(name) > 21: | |
199 | ret.append(" %s" % name) | |
200 | name = "" | |
201 | ||
202 | ret.append(PKG_DUMP_FORMAT % (name, pkg.arch, pkg.friendly_version, | |
203 | pkg.repo.name, util.format_size(pkg.size))) | |
204 | ||
205 | return ret | |
206 | ||
207 | def dump_pkgs(self, caption, pkgs): | |
208 | if not pkgs: | |
209 | return [] | |
210 | ||
211 | s = [caption,] | |
212 | for pkg in sorted(pkgs): | |
213 | s += self.dump_pkg(pkg) | |
214 | s.append("") | |
215 | return s | |
216 | ||
217 | def dump(self, logger=None): | |
218 | if not logger: | |
219 | logger = logging.getLogger() | |
220 | ||
221 | width = 80 | |
222 | line = "=" * width | |
223 | ||
224 | s = [] | |
225 | s.append(line) | |
226 | s.append(PKG_DUMP_FORMAT % (_("Package"), _("Arch"), _("Version"), _("Repository"), _("Size"))) | |
227 | s.append(line) | |
228 | ||
0c1a80b8 MT |
229 | s += self.dump_pkgs(_("Installing:"), self.installs) |
230 | s += self.dump_pkgs(_("Updating:"), self.updates) | |
231 | s += self.dump_pkgs(_("Removing:"), self.removes) | |
ae20b05f MT |
232 | |
233 | s.append(_("Transaction Summary")) | |
234 | s.append(line) | |
235 | ||
236 | format = "%-20s %-4d %s" | |
237 | ||
238 | if self.installs: | |
239 | s.append(format % (_("Install"), len(self.installs), _("Package(s)"))) | |
240 | ||
241 | if self.updates: | |
242 | s.append(format % (_("Updates"), len(self.updates), _("Package(s)"))) | |
243 | ||
244 | if self.removes: | |
245 | s.append(format % (_("Remove"), len(self.removes), _("Package(s)"))) | |
246 | ||
247 | # Calculate the size of all files that need to be downloaded this this | |
248 | # transaction. | |
249 | download_size = sum([p.size for p in self.downloads]) | |
250 | if download_size: | |
251 | s.append(_("Total download size: %s") % util.format_size(download_size)) | |
252 | s.append("") | |
253 | ||
254 | for line in s: | |
255 | logger.info(line) | |
256 | ||
257 | def run_action(self, action): | |
258 | try: | |
259 | action.run() | |
260 | except ActionError, e: | |
261 | logging.error("Action finished with an error: %s - %s" % (action, e)) | |
262 | ||
263 | def add_action(self, action): | |
264 | logging.debug("New action added: %s" % action) | |
265 | ||
266 | self.actions.append(action) | |
267 | ||
268 | def remove_action(self, action): | |
269 | logging.debug("Removing action: %s" % action) | |
270 | ||
271 | self.actions.remove(action) | |
272 | for action in self.actions: | |
273 | action.remove_dep(action) | |
274 | ||
275 | def run(self): | |
276 | # Download all packages. | |
277 | self.download() | |
278 | ||
279 | while True: | |
280 | if not [a for a in self.actions]: | |
281 | break | |
282 | ||
283 | for action in self.actions: | |
284 | if action.deps: | |
285 | #logging.debug("Skipping %s which cannot be run now." % action) | |
286 | continue | |
287 | ||
288 | self.run_action(action) | |
289 | self.remove_action(action) |