]> git.ipfire.org Git - pakfire.git/blame - pakfire/transaction.py
Implement "localinstall" command.
[pakfire.git] / pakfire / transaction.py
CommitLineData
ae20b05f
MT
1#!/usr/bin/python
2
3import logging
4import os
5import progressbar
6import sys
0a9a2371 7import time
ae20b05f 8
196c5da0
MT
9import packages
10import satsolver
11import util
ae20b05f 12
1e80d5d7 13from constants import *
196c5da0 14from i18n import _
ae20b05f
MT
15
16PKG_DUMP_FORMAT = " %-21s %-8s %-21s %-19s %5s "
17
1e80d5d7
MT
18# Import all actions directly.
19from actions import *
b3356c8c 20
ae20b05f
MT
21class 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))