]>
Commit | Line | Data |
---|---|---|
ae20b05f MT |
1 | #!/usr/bin/python |
2 | ||
3 | import logging | |
4 | import os | |
5 | import progressbar | |
6 | import sys | |
0a9a2371 | 7 | import time |
ae20b05f | 8 | |
196c5da0 MT |
9 | import packages |
10 | import satsolver | |
11 | import util | |
ae20b05f | 12 | |
1e80d5d7 | 13 | from constants import * |
196c5da0 | 14 | from i18n import _ |
ae20b05f | 15 | |
022c792a | 16 | PKG_DUMP_FORMAT = " %-21s %-8s %-21s %-18s %6s " |
ae20b05f | 17 | |
1e80d5d7 MT |
18 | # Import all actions directly. |
19 | from actions import * | |
b3356c8c | 20 | |
ae20b05f | 21 | class Transaction(object): |
d767668b | 22 | action_classes = { |
c600820f MT |
23 | ActionInstall.type : [ActionScriptPreIn, ActionInstall, ActionScriptPostIn, ActionScriptPostTransIn], |
24 | ActionReinstall.type : [ActionScriptPreIn, ActionReinstall, ActionScriptPostIn, ActionScriptPostTransIn], | |
25 | ActionRemove.type : [ActionScriptPreUn, ActionRemove, ActionScriptPostUn, ActionScriptPostTransUn], | |
26 | ActionUpdate.type : [ActionScriptPreUp, ActionUpdate, ActionScriptPostUp, ActionScriptPostTransUp], | |
27 | ActionCleanup.type : [ActionCleanup,], | |
28 | ActionDowngrade.type : [ActionScriptPreUp, ActionDowngrade, ActionScriptPostUp, ActionScriptPostTransUp], | |
29 | ActionChange.type : [ActionChange,], | |
d767668b | 30 | } |
ae20b05f MT |
31 | |
32 | def __init__(self, pakfire): | |
33 | self.pakfire = pakfire | |
34 | self.actions = [] | |
35 | ||
ee6715aa MT |
36 | self.installsizechange = 0 |
37 | ||
ae20b05f | 38 | @classmethod |
c605d735 | 39 | def from_solver(cls, pakfire, solver, _transaction): |
ae20b05f MT |
40 | # Create a new instance of our own transaction class. |
41 | transaction = cls(pakfire) | |
42 | ||
ee6715aa MT |
43 | # Save installsizechange. |
44 | transaction.installsizechange = _transaction.get_installsizechange() | |
45 | ||
c9a51ed9 MT |
46 | # Get all steps that need to be done from the solver. |
47 | steps = _transaction.steps() | |
48 | if not steps: | |
49 | return | |
50 | ||
d767668b MT |
51 | actions = [] |
52 | actions_post = [] | |
53 | ||
c9a51ed9 | 54 | for step in steps: |
d767668b | 55 | action_name = step.get_type() |
c605d735 | 56 | pkg = packages.SolvPackage(pakfire, step.get_solvable()) |
ae20b05f | 57 | |
d767668b MT |
58 | try: |
59 | classes = transaction.action_classes[action_name] | |
60 | except KeyError: | |
61 | raise Exception, "Unknown action required: %s" % action_name | |
62 | ||
63 | for action_cls in classes: | |
64 | action = action_cls(pakfire, pkg) | |
65 | assert isinstance(action, Action), action | |
ae20b05f | 66 | |
d767668b MT |
67 | if isinstance(action, ActionScriptPostTrans): |
68 | actions_post.append(action) | |
69 | else: | |
70 | actions.append(action) | |
ae20b05f | 71 | |
d767668b | 72 | transaction.actions += actions + actions_post |
ae20b05f MT |
73 | |
74 | return transaction | |
75 | ||
d4c94aa5 MT |
76 | @property |
77 | def installs(self): | |
78 | return [a.pkg for a in self.actions if isinstance(a, ActionInstall)] | |
ae20b05f | 79 | |
d4c94aa5 MT |
80 | @property |
81 | def reinstalls(self): | |
82 | return [a.pkg for a in self.actions if isinstance(a, ActionReinstall)] | |
ae20b05f | 83 | |
d4c94aa5 MT |
84 | @property |
85 | def removes(self): | |
86 | return [a.pkg for a in self.actions if isinstance(a, ActionRemove)] | |
ae20b05f | 87 | |
d4c94aa5 MT |
88 | @property |
89 | def updates(self): | |
90 | return [a.pkg for a in self.actions if isinstance(a, ActionUpdate)] | |
ae20b05f | 91 | |
d4c94aa5 MT |
92 | @property |
93 | def downgrades(self): | |
94 | return [a.pkg for a in self.actions if isinstance(a, ActionDowngrade)] | |
ae20b05f | 95 | |
d4c94aa5 MT |
96 | @property |
97 | def downloads(self): | |
98 | return [a for a in self.actions if a.needs_download] | |
99 | ||
100 | def download(self): | |
0a9a2371 MT |
101 | # Get all download actions as a list. |
102 | downloads = [d for d in self.downloads] | |
103 | downloads.sort() | |
104 | ||
105 | # If there are no downloads, we can just stop here. | |
106 | if not downloads: | |
107 | return | |
108 | ||
109 | logging.info(_("Downloading packages:")) | |
110 | time_start = time.time() | |
111 | ||
112 | # Calculate downloadsize. | |
113 | download_size = 0 | |
114 | for action in downloads: | |
115 | download_size += action.pkg.size | |
d4c94aa5 MT |
116 | |
117 | i = 0 | |
0a9a2371 | 118 | for action in downloads: |
d4c94aa5 | 119 | i += 1 |
0a9a2371 MT |
120 | action.download(text="(%d/%d): " % (i, len(downloads))) |
121 | ||
122 | # Write an empty line to the console when there have been any downloads. | |
123 | width, height = util.terminal_size() | |
124 | ||
125 | # Print a nice line. | |
126 | logging.info("-" * width) | |
127 | ||
128 | # Format and calculate download information. | |
129 | time_stop = time.time() | |
130 | download_time = time_stop - time_start | |
131 | download_speed = download_size / download_time | |
132 | download_speed = util.format_speed(download_speed) | |
133 | download_size = util.format_size(download_size) | |
134 | download_time = util.format_time(download_time) | |
135 | ||
8cb74f39 | 136 | line = "%s | %5sB %s " % \ |
0a9a2371 MT |
137 | (download_speed, download_size, download_time) |
138 | line = " " * (width - len(line)) + line | |
139 | logging.info(line) | |
140 | logging.info("") | |
ae20b05f | 141 | |
ae20b05f MT |
142 | def dump_pkg(self, pkg): |
143 | ret = [] | |
144 | ||
145 | name = pkg.name | |
146 | if len(name) > 21: | |
147 | ret.append(" %s" % name) | |
148 | name = "" | |
149 | ||
150 | ret.append(PKG_DUMP_FORMAT % (name, pkg.arch, pkg.friendly_version, | |
151 | pkg.repo.name, util.format_size(pkg.size))) | |
152 | ||
153 | return ret | |
154 | ||
155 | def dump_pkgs(self, caption, pkgs): | |
156 | if not pkgs: | |
157 | return [] | |
158 | ||
159 | s = [caption,] | |
160 | for pkg in sorted(pkgs): | |
161 | s += self.dump_pkg(pkg) | |
162 | s.append("") | |
163 | return s | |
164 | ||
165 | def dump(self, logger=None): | |
166 | if not logger: | |
167 | logger = logging.getLogger() | |
168 | ||
169 | width = 80 | |
170 | line = "=" * width | |
171 | ||
d4c94aa5 | 172 | s = [""] |
ae20b05f | 173 | s.append(line) |
c64002fd MT |
174 | s.append(PKG_DUMP_FORMAT % (_("Package"), _("Arch"), _("Version"), |
175 | _("Repository"), _("Size"))) | |
ae20b05f MT |
176 | s.append(line) |
177 | ||
d4c94aa5 MT |
178 | actions = ( |
179 | (_("Installing:"), self.installs), | |
180 | (_("Reinstalling:"), self.reinstalls), | |
181 | (_("Updating:"), self.updates), | |
182 | (_("Downgrading:"), self.downgrades), | |
183 | (_("Removing:"), self.removes), | |
184 | ) | |
185 | ||
186 | for caption, pkgs in actions: | |
187 | s += self.dump_pkgs(caption, pkgs) | |
ae20b05f MT |
188 | |
189 | s.append(_("Transaction Summary")) | |
190 | s.append(line) | |
191 | ||
d4c94aa5 MT |
192 | for caption, pkgs in actions: |
193 | if not len(pkgs): | |
194 | continue | |
c64002fd MT |
195 | s.append("%-20s %-4d %s" % (caption, len(pkgs), |
196 | _("package", "packages", len(pkgs)))) | |
ae20b05f MT |
197 | |
198 | # Calculate the size of all files that need to be downloaded this this | |
199 | # transaction. | |
d4c94aa5 | 200 | download_size = sum([a.pkg.size for a in self.downloads]) |
ae20b05f MT |
201 | if download_size: |
202 | s.append(_("Total download size: %s") % util.format_size(download_size)) | |
ee6715aa MT |
203 | |
204 | # Show the size that is consumed by the new packages. | |
205 | if self.installsizechange > 0: | |
206 | s.append(_("Installed size: %s") % util.format_size(self.installsizechange)) | |
207 | elif self.installsizechange < 0: | |
208 | s.append(_("Freed size: %s") % util.format_size(self.installsizechange)) | |
ae20b05f MT |
209 | s.append("") |
210 | ||
211 | for line in s: | |
212 | logger.info(line) | |
213 | ||
c0fd807c MT |
214 | def cli_yesno(self, logger=None): |
215 | self.dump(logger) | |
216 | ||
217 | return util.ask_user(_("Is this okay?")) | |
218 | ||
ae20b05f MT |
219 | def run(self): |
220 | # Download all packages. | |
221 | self.download() | |
222 | ||
8cb74f39 | 223 | logging.info(_("Running transaction")) |
c64002fd MT |
224 | # Run all actions in order and catch all kinds of ActionError. |
225 | for action in self.actions: | |
226 | try: | |
227 | action.run() | |
228 | except ActionError, e: | |
229 | logging.error("Action finished with an error: %s - %s" % (action, e)) | |
6ee3d6b9 MT |
230 | |
231 | logging.info("") |