]>
Commit | Line | Data |
---|---|---|
964aa579 | 1 | #!/usr/bin/python3 |
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 | ############################################################################### | |
47a4cb89 | 21 | |
bfa112c3 | 22 | import logging |
7c8f2953 MT |
23 | import os |
24 | import random | |
25 | import string | |
26 | ||
2b5ba3b7 | 27 | from . import _pakfire |
964aa579 | 28 | from . import distro |
bfa112c3 | 29 | from . import logger |
964aa579 | 30 | from . import packages |
964aa579 | 31 | from . import util |
7c8f2953 | 32 | |
36374696 | 33 | from .config import Config |
14dcd4ba MT |
34 | from .system import system |
35 | ||
964aa579 MT |
36 | from .constants import * |
37 | from .i18n import _ | |
7c8f2953 | 38 | |
6e46b18e | 39 | class Pakfire(_pakfire.Pakfire): |
cb16be57 | 40 | __version__ = PAKFIRE_VERSION |
73776c23 | 41 | |
69e754ab | 42 | def __init__(self, path=None, config=None, arch=None, distro=None, offline=False): |
72caad76 | 43 | _pakfire.Pakfire.__init__(self, path, arch, offline=offline) |
14dcd4ba | 44 | |
bfa112c3 MT |
45 | # Initialise logging system |
46 | self.log = self._setup_logger() | |
47 | ||
9e5e1f15 MT |
48 | # Default to system distribution |
49 | self.distro = distro or system.distro | |
50 | ||
a9d2c50d | 51 | # Load configuration |
36374696 | 52 | self.config = config or Config("general.conf") |
7c8f2953 | 53 | |
bfa112c3 MT |
54 | def _setup_logger(self): |
55 | log = logging.getLogger("pakfire") | |
56 | log.propagate = 0 | |
57 | ||
58 | # Always process all messages (include debug) | |
59 | log.setLevel(logging.DEBUG) | |
60 | ||
61 | # Pass everything down to libpakfire | |
62 | handler = logger.PakfireLogHandler(self) | |
63 | log.addHandler(handler) | |
64 | ||
65 | return log | |
66 | ||
a9d2c50d | 67 | def __enter__(self): |
36b328f2 | 68 | """ |
a9d2c50d MT |
69 | Called to initialize this Pakfire instance when |
70 | the context is entered. | |
36b328f2 | 71 | """ |
a9d2c50d MT |
72 | # Dump the configuration when we enter the context |
73 | self.config.dump() | |
36b328f2 | 74 | |
1b61ba46 | 75 | # Refresh repositories |
3265ba73 | 76 | self.refresh_repositories() |
36b328f2 | 77 | |
9ecdbcd1 | 78 | return PakfireContext(self) |
36b328f2 | 79 | |
a9d2c50d | 80 | def __exit__(self, type, value, traceback): |
1b61ba46 | 81 | pass |
36b328f2 | 82 | |
3265ba73 MT |
83 | def refresh_repositories(self, force=False): |
84 | for repo in self.repos: | |
cd2f27a0 | 85 | repo.refresh(force=force) |
3265ba73 | 86 | |
0c547b16 | 87 | def clean(self): |
cb6d631c MT |
88 | # Clean up repository caches |
89 | for repo in self.repos: | |
90 | repo.clean() | |
c49a002d | 91 | |
c49a002d | 92 | |
9ecdbcd1 MT |
93 | class PakfireContext(object): |
94 | """ | |
95 | This context has functions that require | |
96 | pakfire to be initialized. | |
97 | ||
98 | That means that repository data has to be downloaded | |
99 | and imported to be searchable, etc. | |
100 | """ | |
101 | def __init__(self, pakfire): | |
102 | self.pakfire = pakfire | |
103 | ||
0812ebe2 MT |
104 | @property |
105 | def repos(self): | |
106 | """ | |
107 | Shortcut to access any configured | |
108 | repositories for this Pakfire instance | |
109 | """ | |
110 | return self.pakfire.repos | |
111 | ||
f466d0db | 112 | def check(self, **kwargs): |
0dc4873e MT |
113 | """ |
114 | Try to fix any errors in the system. | |
115 | """ | |
116 | # Detect any errors in the dependency tree. | |
117 | # For that we create an empty request and solver and try to solve | |
118 | # something. | |
19f3d106 | 119 | request = _pakfire.Request(self.pakfire) |
0dc4873e MT |
120 | request.verify() |
121 | ||
f466d0db | 122 | return request.solve(**kwargs) |
0dc4873e | 123 | |
312fd26f | 124 | def info(self, args): |
9ecdbcd1 MT |
125 | pkgs = [] |
126 | ||
312fd26f MT |
127 | with _pakfire.Repo(self.pakfire, "tmp", clean=True) as r: |
128 | for arg in args: | |
129 | if os.path.exists(arg) and not os.path.isdir(arg): | |
130 | archive = _pakfire.Archive(self.pakfire, arg) | |
131 | ||
132 | # Add the archive to the repository | |
133 | pkg = r.add_archive(archive) | |
9ecdbcd1 MT |
134 | pkgs.append(pkg) |
135 | ||
312fd26f MT |
136 | else: |
137 | pkgs += self.pakfire.whatprovides(arg, name_only=True) | |
9ecdbcd1 MT |
138 | |
139 | return sorted(pkgs) | |
140 | ||
1edcccc0 MT |
141 | def provides(self, patterns): |
142 | pkgs = [] | |
143 | ||
144 | for pattern in patterns: | |
78d8c9ec | 145 | for pkg in self.pakfire.whatprovides(pattern): |
1edcccc0 MT |
146 | if pkg in pkgs: |
147 | continue | |
148 | ||
149 | pkgs.append(pkg) | |
150 | ||
151 | return sorted(pkgs) | |
152 | ||
d063a356 | 153 | def search(self, pattern): |
44b27b6f | 154 | return self.pakfire.search(pattern) |
d063a356 | 155 | |
e7da5970 MT |
156 | def extract(self, filenames, target=None): |
157 | if target and target == "/": | |
158 | raise ValueError("Cannot extract to: %s" % target) | |
159 | ||
160 | archives = [] | |
161 | ||
162 | # Open all archives | |
163 | for filename in filenames: | |
164 | a = _pakfire.Archive(self.pakfire, filename) | |
165 | archives.append(a) | |
166 | ||
167 | # Nothing to do when no archives where opened | |
168 | if not archives: | |
169 | return | |
170 | ||
171 | # Extract them all | |
172 | for archive in archives: | |
173 | archive.extract(target) | |
174 | ||
154f8448 MT |
175 | # Transactions |
176 | ||
b546c786 | 177 | def install(self, requires, **kwargs): |
19f3d106 | 178 | request = _pakfire.Request(self.pakfire) |
154f8448 | 179 | |
b546c786 | 180 | # XXX handle files and URLs |
154f8448 MT |
181 | |
182 | for req in requires: | |
8ad0a954 MT |
183 | # Handle groups |
184 | # TODO should move into libpakfire | |
185 | if req.startswith("@"): | |
186 | sel = _pakfire.Selector(self.pakfire) | |
187 | sel.set(_pakfire.PAKFIRE_PKG_GROUP, _pakfire.PAKFIRE_EQ, req[1:]) | |
188 | request.install(sel) | |
189 | continue | |
190 | ||
191 | # Handle everything else | |
44b27b6f | 192 | relation = _pakfire.Relation(self.pakfire, req) |
b546c786 | 193 | request.install(relation) |
154f8448 | 194 | |
b546c786 | 195 | return request.solve(**kwargs) |
154f8448 | 196 | |
532260e0 MT |
197 | def reinstall(self, pkgs, strict=False, logger=None): |
198 | """ | |
b546c786 | 199 | Reinstall one or more packages |
532260e0 | 200 | """ |
b546c786 | 201 | raise NotImplementedError |
532260e0 | 202 | |
2f1289eb | 203 | def erase(self, pkgs, **kwargs): |
19f3d106 | 204 | request = _pakfire.Request(self.pakfire) |
2f1289eb MT |
205 | |
206 | for pkg in pkgs: | |
44b27b6f | 207 | relation = _pakfire.Relation(self.pakfire, pkg) |
2f1289eb MT |
208 | request.erase(relation) |
209 | ||
210 | return request.solve(**kwargs) | |
211 | ||
47857184 | 212 | def update(self, reqs=None, excludes=None, **kwargs): |
19f3d106 | 213 | request = _pakfire.Request(self.pakfire) |
a0b428f8 | 214 | |
47857184 MT |
215 | # Add all packages that should be updated to the request |
216 | for req in reqs or []: | |
44b27b6f | 217 | relation = _pakfire.Relation(self.pakfire, req) |
47857184 | 218 | request.upgrade(relation) |
a0b428f8 | 219 | |
47857184 MT |
220 | # Otherwise we will try to upgrade everything |
221 | else: | |
222 | request.upgrade_all() | |
a0b428f8 | 223 | |
47857184 | 224 | # Exclude packages that should not be updated |
a0b428f8 | 225 | for exclude in excludes or []: |
44b27b6f | 226 | relation = _pakfire.Relation(self.pakfire, exclude) |
47857184 | 227 | request.lock(relation) |
a0b428f8 | 228 | |
47857184 | 229 | return request.solve(**kwargs) |
a0b428f8 | 230 | |
93f41006 MT |
231 | def downgrade(self, pkgs, logger=None, **kwargs): |
232 | assert pkgs | |
233 | ||
234 | if logger is None: | |
235 | logger = logging.getLogger("pakfire") | |
236 | ||
237 | # Create a new request. | |
44b27b6f | 238 | request = self.pakfire.create_request() |
93f41006 MT |
239 | |
240 | # Fill request. | |
241 | for pattern in pkgs: | |
242 | best = None | |
243 | for pkg in self.pakfire.repos.whatprovides(pattern): | |
244 | # Only consider installed packages. | |
245 | if not pkg.is_installed(): | |
246 | continue | |
247 | ||
248 | if best and pkg > best: | |
249 | best = pkg | |
250 | elif best is None: | |
251 | best = pkg | |
252 | ||
253 | if best is None: | |
254 | logger.warning(_("\"%s\" package does not seem to be installed.") % pattern) | |
255 | else: | |
44b27b6f | 256 | rel = self.pakfire.create_relation("%s < %s" % (best.name, best.friendly_version)) |
93f41006 MT |
257 | request.install(rel) |
258 | ||
259 | # Solve the request. | |
44b27b6f | 260 | solver = self.pakfire.solve(request, allow_downgrade=True, **kwargs) |
93f41006 MT |
261 | assert solver.status is True |
262 | ||
263 | # Create the transaction. | |
264 | t = transaction.Transaction.from_solver(self.pakfire, solver) | |
265 | t.dump(logger=logger) | |
266 | ||
267 | if not t: | |
268 | logger.info(_("Nothing to do")) | |
269 | return | |
270 | ||
271 | if not t.cli_yesno(): | |
272 | return | |
273 | ||
274 | t.run() | |
275 | ||
9ecdbcd1 | 276 | |
1f6c466e | 277 | class PakfireKey(Pakfire): |
f530fe71 | 278 | pass |