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