]>
Commit | Line | Data |
---|---|---|
47a4cb89 | 1 | #!/usr/bin/python |
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 | |
7c8f2953 MT |
22 | import os |
23 | import random | |
24 | import string | |
25 | ||
0ca71090 | 26 | import actions |
18edfe75 | 27 | import builder |
7c8f2953 | 28 | import distro |
862bea4d | 29 | import filelist |
68c0e769 | 30 | import keyring |
7c8f2953 | 31 | import logger |
ae20b05f | 32 | import packages |
0ca71090 | 33 | import repository |
c605d735 | 34 | import satsolver |
0ca71090 | 35 | import transaction |
7c8f2953 MT |
36 | import util |
37 | ||
8b6bc023 MT |
38 | import logging |
39 | log = logging.getLogger("pakfire") | |
40 | ||
854d8ccf | 41 | from config import Config |
7c8f2953 | 42 | from constants import * |
7c8f2953 MT |
43 | from i18n import _ |
44 | ||
7c8f2953 | 45 | class Pakfire(object): |
018127aa MT |
46 | RELATIONS = ( |
47 | (">=", satsolver.REL_GE,), | |
48 | ("<=", satsolver.REL_LE,), | |
49 | ("=" , satsolver.REL_EQ,), | |
50 | ("<" , satsolver.REL_LT,), | |
51 | (">" , satsolver.REL_GT,), | |
52 | ) | |
53 | ||
854d8ccf | 54 | def __init__(self, mode=None, path="/", config=None, configs=None, arch=None, |
a6bd96bc | 55 | enable_repos=None, disable_repos=None, **kwargs): |
6557ff4c | 56 | # Set the mode. |
6a509182 | 57 | assert mode in ("normal", "builder", "server",) |
6557ff4c MT |
58 | self.mode = mode |
59 | ||
7c8f2953 MT |
60 | # Check if we are operating as the root user. |
61 | self.check_root_user() | |
62 | ||
63 | # The path where we are operating in. | |
6557ff4c MT |
64 | self.path = path |
65 | ||
66 | # Configure the instance of Pakfire we just started. | |
67 | if mode == "builder": | |
7c8f2953 | 68 | self.path = os.path.join(BUILD_ROOT, util.random_string()) |
7c8f2953 | 69 | |
6557ff4c | 70 | elif mode == "normal": |
7b1e25fd | 71 | # check if we are actually running on an ipfire system. |
0891edd2 MT |
72 | if self.path == "/": |
73 | self.check_is_ipfire() | |
7c8f2953 | 74 | |
854d8ccf MT |
75 | # Get the configuration. |
76 | if config: | |
77 | assert configs is None, "You cannot pass configs and config." | |
78 | self.config = config | |
a6bd96bc | 79 | else: |
854d8ccf MT |
80 | # Read configuration file(s). |
81 | self.config = Config(files=configs) | |
7c8f2953 | 82 | |
98733451 MT |
83 | # Update configuration with additional arguments. |
84 | for section, settings in kwargs.items(): | |
85 | self.config.update(section, settings) | |
86 | ||
a6bd96bc | 87 | # Dump the configuration. |
7c8f2953 MT |
88 | self.config.dump() |
89 | ||
68c0e769 MT |
90 | # Initialize the keyring. |
91 | self.keyring = keyring.Keyring(self) | |
92 | ||
7c8f2953 MT |
93 | # Get more information about the distribution we are running |
94 | # or building | |
a6bd96bc MT |
95 | self.distro = distro.Distribution(self) |
96 | if arch: | |
97 | self.distro.arch = arch | |
98 | ||
c605d735 | 99 | self.pool = satsolver.Pool(self.distro.arch) |
ae20b05f MT |
100 | self.repos = repository.Repositories(self, |
101 | enable_repos=enable_repos, disable_repos=disable_repos) | |
7c8f2953 | 102 | |
60845a36 MT |
103 | def __del__(self): |
104 | # Reset logging. | |
105 | logger.setup_logging() | |
106 | ||
c901e1f8 MT |
107 | def expand_requires(self, requires): |
108 | if requires is None: | |
109 | return [] | |
c605d735 | 110 | |
c901e1f8 MT |
111 | ret = [] |
112 | for req in requires: | |
113 | if isinstance(req, packages.BinaryPackage): | |
114 | ret.append(req) | |
115 | continue | |
116 | ||
117 | if isinstance(req, packages.SolvPackage): | |
118 | ret.append(req.solvable) | |
119 | continue | |
120 | ||
121 | assert type(req) == type("a"), req | |
122 | ||
123 | # Expand all groups. | |
124 | if req.startswith("@"): | |
125 | reqs = self.grouplist(req[1:]) | |
126 | else: | |
127 | reqs = [req,] | |
128 | ||
129 | for req in reqs: | |
130 | req = self.create_relation(req) | |
131 | ret.append(req) | |
132 | ||
133 | return ret | |
134 | ||
135 | def create_request(self, builder=False, install=None, remove=None, update=None): | |
063606f6 MT |
136 | request = satsolver.Request(self.pool) |
137 | ||
138 | # Add multiinstall information. | |
139 | for solv in PAKFIRE_MULTIINSTALL: | |
140 | request.noobsoletes(solv) | |
141 | ||
c901e1f8 MT |
142 | # Apply all installs. |
143 | for req in self.expand_requires(install): | |
144 | request.install(req) | |
145 | ||
146 | # Apply all removes. | |
147 | for req in self.expand_requires(remove): | |
148 | request.remove(req) | |
149 | ||
150 | # Apply all updates. | |
151 | for req in self.expand_requires(update): | |
152 | request.update(req) | |
153 | ||
154 | # Return the request. | |
063606f6 | 155 | return request |
7c8f2953 | 156 | |
018127aa MT |
157 | def create_relation(self, s): |
158 | assert s | |
159 | ||
862bea4d MT |
160 | if isinstance(s, filelist._File): |
161 | return satsolver.Relation(self.pool, s.name) | |
162 | ||
163 | elif s.startswith("/"): | |
018127aa MT |
164 | return satsolver.Relation(self.pool, s) |
165 | ||
166 | for pattern, type in self.RELATIONS: | |
167 | if not pattern in s: | |
168 | continue | |
169 | ||
170 | name, version = s.split(pattern, 1) | |
171 | ||
63029754 MT |
172 | # Trim spaces from strings. |
173 | name = name.strip() | |
174 | version = version.strip() | |
175 | ||
018127aa MT |
176 | return satsolver.Relation(self.pool, name, version, type) |
177 | ||
178 | return satsolver.Relation(self.pool, s) | |
179 | ||
7c8f2953 MT |
180 | def destroy(self): |
181 | if not self.path == "/": | |
182 | util.rm(self.path) | |
183 | ||
c07a3ca7 MT |
184 | @property |
185 | def environ(self): | |
186 | env = {} | |
187 | ||
188 | # Get distribution information. | |
189 | env.update(self.distro.environ) | |
190 | ||
191 | return env | |
192 | ||
7c8f2953 MT |
193 | @property |
194 | def supported_arches(self): | |
a6bd96bc | 195 | return system.supported_arches |
7c8f2953 | 196 | |
6a509182 MT |
197 | @property |
198 | def offline(self): | |
199 | """ | |
200 | A shortcut that indicates if the system is running in offline mode. | |
201 | """ | |
98733451 | 202 | return self.config.get("downloader", "offline", False) |
6a509182 | 203 | |
7c8f2953 MT |
204 | def check_root_user(self): |
205 | if not os.getuid() == 0 or not os.getgid() == 0: | |
206 | raise Exception, "You must run pakfire as the root user." | |
207 | ||
208 | def check_build_mode(self): | |
209 | """ | |
210 | Check if we are running in build mode. | |
211 | Otherwise, raise an exception. | |
212 | """ | |
6557ff4c | 213 | if not self.mode == "builder": |
7c8f2953 MT |
214 | raise BuildError, "Cannot build when not in build mode." |
215 | ||
216 | def check_host_arch(self, arch): | |
217 | """ | |
218 | Check if we can build for arch. | |
219 | """ | |
7c8f2953 MT |
220 | # If no arch was given on the command line we build for our |
221 | # own arch which should always work. | |
222 | if not arch: | |
223 | return True | |
224 | ||
a6bd96bc | 225 | if not system.host_supports_arch(arch): |
7c8f2953 MT |
226 | raise BuildError, "Cannot build for the target architecture: %s" % arch |
227 | ||
228 | raise BuildError, arch | |
18edfe75 | 229 | |
7b1e25fd MT |
230 | def check_is_ipfire(self): |
231 | ret = os.path.exists("/etc/ipfire-release") | |
232 | ||
233 | if not ret: | |
234 | raise NotAnIPFireSystemError, "You can run pakfire only on an IPFire system" | |
235 | ||
6557ff4c MT |
236 | @property |
237 | def builder(self): | |
238 | # XXX just backwards compatibility | |
239 | return self.mode == "builder" | |
240 | ||
c901e1f8 MT |
241 | def resolvdep(self, pkg, logger=None): |
242 | assert os.path.exists(pkg) | |
243 | ||
244 | # Open the package file. | |
245 | pkg = packages.open(self, None, pkg) | |
246 | ||
b25a3d84 | 247 | # Create a new request. |
c901e1f8 | 248 | request = self.create_request(install=pkg.requires) |
b25a3d84 | 249 | |
c901e1f8 MT |
250 | # Add build dependencies if needed. |
251 | if isinstance(pkg, packages.Makefile) or isinstance(pkg, packages.SourcePackage): | |
252 | for req in self.expand_requires(BUILD_PACKAGES): | |
253 | request.install(req) | |
b25a3d84 | 254 | |
c901e1f8 MT |
255 | # Solv the request. |
256 | solver = self.solv(request, logger=logger) | |
257 | ||
258 | if solver.status: | |
259 | return solver | |
260 | ||
261 | raise DependencyError, solver.get_problem_string() | |
262 | ||
263 | def solv(self, request, interactive=False, logger=None, **kwargs): | |
264 | # XXX implement interactive | |
b25a3d84 | 265 | |
c07a3ca7 | 266 | if not logger: |
8b6bc023 | 267 | logger = logging.getLogger("pakfire") |
c07a3ca7 | 268 | |
c901e1f8 MT |
269 | # Create a solver. |
270 | solver = satsolver.Solver(self, request, logger=logger) | |
c07a3ca7 | 271 | |
c901e1f8 MT |
272 | # Apply configuration to solver. |
273 | for key, val in kwargs.items(): | |
274 | solver.set(key, val) | |
c07a3ca7 | 275 | |
c901e1f8 MT |
276 | # Do the solving. |
277 | solver.solve() | |
c07a3ca7 | 278 | |
c901e1f8 MT |
279 | # Return the solver so one can do stuff with it... |
280 | return solver | |
281 | ||
4fffe3c4 | 282 | def install(self, requires, interactive=True, logger=None, signatures_mode=None, **kwargs): |
c901e1f8 MT |
283 | if not logger: |
284 | logger = logging.getLogger("pakfire") | |
18edfe75 | 285 | |
4fffe3c4 MT |
286 | # Pointer to temporary repository. |
287 | repo = None | |
c0fd807c | 288 | |
4fffe3c4 MT |
289 | # Sort out what we got... |
290 | files = [] | |
291 | relations = [] | |
18edfe75 | 292 | |
4fffe3c4 MT |
293 | for req in requires: |
294 | if isinstance(req, packages.Package): | |
295 | relations.append(req) | |
296 | continue | |
c901e1f8 | 297 | |
4fffe3c4 MT |
298 | # This looks like a file. |
299 | if req.endswith(".%s" % PACKAGE_EXTENSION) and os.path.exists(req): | |
300 | files.append(req) | |
301 | continue | |
e0b99370 | 302 | |
4fffe3c4 MT |
303 | # We treat the rest as relations. The solver will return any errors. |
304 | relations.append(req) | |
e0b99370 | 305 | |
4fffe3c4 MT |
306 | # Redefine requires, which will be the list that will be passed to the |
307 | # solver. | |
308 | requires = relations | |
e0b99370 | 309 | |
022c792a | 310 | try: |
4fffe3c4 MT |
311 | # If we have got files to install, we need to create a temporary repository |
312 | # called 'localinstall'. | |
313 | # XXX FIX TMP PATH | |
314 | if files: | |
315 | repo = repository.RepositoryDir(self, "localinstall", _("Local install repository"), | |
316 | os.path.join(LOCAL_TMP_PATH, "repo_%s" % util.random_string())) | |
e0b99370 | 317 | |
4fffe3c4 MT |
318 | # Register the repository. |
319 | self.repos.add_repo(repo) | |
e0b99370 | 320 | |
4fffe3c4 MT |
321 | # Add all packages to the repository index. |
322 | repo.add_packages(*files) | |
e0b99370 | 323 | |
4fffe3c4 MT |
324 | # Add all packages to the requires. |
325 | requires += repo | |
e0b99370 | 326 | |
4fffe3c4 MT |
327 | # Do the solving. |
328 | request = self.create_request(install=requires) | |
329 | solver = self.solv(request, logger=logger, interactive=interactive, **kwargs) | |
c0fd807c | 330 | |
4fffe3c4 | 331 | # Create the transaction. |
c901e1f8 | 332 | t = solver.transaction |
4fffe3c4 | 333 | t.dump(logger=logger) |
c901e1f8 | 334 | |
4fffe3c4 MT |
335 | # Ask if the user acknowledges the transaction. |
336 | if interactive and not t.cli_yesno(): | |
022c792a MT |
337 | return |
338 | ||
4fffe3c4 MT |
339 | # Run the transaction. |
340 | t.run(logger=logger, signatures_mode=signatures_mode) | |
022c792a MT |
341 | |
342 | finally: | |
4fffe3c4 MT |
343 | if repo: |
344 | # Remove the temporary repository we have created earlier. | |
345 | repo.remove() | |
346 | self.repos.rem_repo(repo) | |
e0b99370 | 347 | |
0ca71090 MT |
348 | def reinstall(self, pkgs, strict=False): |
349 | """ | |
350 | Reinstall one or more packages. | |
351 | ||
352 | If strict is True, only a package with excatly the same UUID | |
353 | will replace the currently installed one. | |
354 | """ | |
4fffe3c4 MT |
355 | if logger is None: |
356 | logger = logging.getLogger("pakfire") | |
357 | ||
0ca71090 MT |
358 | # XXX it is possible to install packages without fulfulling |
359 | # all dependencies. | |
360 | ||
361 | reinstall_pkgs = [] | |
362 | for pattern in pkgs: | |
363 | _pkgs = [] | |
364 | for pkg in self.repos.whatprovides(pattern): | |
365 | # Do not reinstall non-installed packages. | |
366 | if not pkg.is_installed(): | |
367 | continue | |
368 | ||
369 | _pkgs.append(pkg) | |
370 | ||
371 | if not _pkgs: | |
4fffe3c4 | 372 | logger.warning(_("Could not find any installed package providing \"%s\".") \ |
0ca71090 MT |
373 | % pattern) |
374 | elif len(_pkgs) == 1: | |
375 | reinstall_pkgs.append(_pkgs[0]) | |
376 | #t.add("reinstall", _pkgs[0]) | |
377 | else: | |
4fffe3c4 | 378 | logger.warning(_("Multiple reinstall candidates for \"%(pattern)s\": %(pkgs)s") \ |
4cdde79f | 379 | % { "pattern" : pattern, "pkgs" : ", ".join(p.friendly_name for p in sorted(_pkgs)) }) |
0ca71090 MT |
380 | |
381 | if not reinstall_pkgs: | |
4fffe3c4 | 382 | logger.info(_("Nothing to do")) |
0ca71090 MT |
383 | return |
384 | ||
385 | # Packages we want to replace. | |
386 | # Contains a tuple with the old and the new package. | |
387 | pkgs = [] | |
388 | ||
389 | # Find the package that is installed in a remote repository to | |
390 | # download it again and re-install it. We need that. | |
391 | for pkg in reinstall_pkgs: | |
392 | # Collect all candidates in here. | |
393 | _pkgs = [] | |
394 | ||
395 | provides = "%s=%s" % (pkg.name, pkg.friendly_version) | |
396 | for _pkg in self.repos.whatprovides(provides): | |
397 | if _pkg.is_installed(): | |
398 | continue | |
399 | ||
400 | if strict: | |
401 | if pkg.uuid == _pkg.uuid: | |
402 | _pkgs.append(_pkg) | |
403 | else: | |
404 | _pkgs.append(_pkg) | |
405 | ||
406 | if not _pkgs: | |
4fffe3c4 | 407 | logger.warning(_("Could not find package %s in a remote repository.") % \ |
0ca71090 MT |
408 | pkg.friendly_name) |
409 | else: | |
410 | # Sort packages to reflect repository priorities, etc... | |
411 | # and take the best (first) one. | |
412 | _pkgs.sort() | |
413 | ||
414 | # Re-install best package and cleanup the old one. | |
415 | pkgs.append((pkg, _pkgs[0])) | |
416 | ||
417 | # Eventually, create a request. | |
418 | request = None | |
419 | ||
420 | _pkgs = [] | |
421 | for old, new in pkgs: | |
422 | if old.uuid == new.uuid: | |
423 | _pkgs.append((old, new)) | |
424 | else: | |
425 | if request is None: | |
426 | # Create a new request. | |
427 | request = self.create_request() | |
428 | ||
429 | # Install the new package, the old will | |
430 | # be cleaned up automatically. | |
431 | request.install(new.solvable) | |
432 | ||
433 | if request: | |
c901e1f8 MT |
434 | solver = self.solv(request) |
435 | assert solver.status | |
436 | ||
437 | t = solver.transaction | |
0ca71090 MT |
438 | else: |
439 | # Create new transaction. | |
440 | t = transaction.Transaction(self) | |
441 | ||
442 | for old, new in _pkgs: | |
443 | # Install the new package and remove the old one. | |
444 | t.add(actions.ActionReinstall.type, new) | |
445 | t.add(actions.ActionCleanup.type, old) | |
446 | ||
447 | t.sort() | |
448 | ||
449 | if not t: | |
4fffe3c4 | 450 | logger.info(_("Nothing to do")) |
0ca71090 MT |
451 | return |
452 | ||
4fffe3c4 MT |
453 | t.dump(logger=logger) |
454 | ||
0ca71090 MT |
455 | if not t.cli_yesno(): |
456 | return | |
457 | ||
4fffe3c4 | 458 | t.run(logger=logger) |
0ca71090 | 459 | |
3817ae8e | 460 | def update(self, pkgs=None, check=False, excludes=None, interactive=True, logger=None, **kwargs): |
e38914be MT |
461 | """ |
462 | check indicates, if the method should return after calculation | |
463 | of the transaction. | |
464 | """ | |
c901e1f8 MT |
465 | if logger is None: |
466 | logger = logging.getLogger("pakfire") | |
0c1a80b8 | 467 | |
6c395339 MT |
468 | # If there are given any packets on the command line, we will |
469 | # only update them. Otherwise, we update the whole system. | |
470 | if pkgs: | |
471 | update = False | |
6c395339 MT |
472 | else: |
473 | update = True | |
0c1a80b8 | 474 | |
c901e1f8 MT |
475 | request = self.create_request(update=pkgs) |
476 | ||
8834f7c9 | 477 | # Exclude packages that should not be updated. |
c901e1f8 MT |
478 | for exclude in excludes or []: |
479 | logger.info(_("Excluding %s.") % exclude) | |
8834f7c9 | 480 | |
c901e1f8 MT |
481 | exclude = self.create_relation(exclude) |
482 | request.lock(exclude) | |
8834f7c9 | 483 | |
c901e1f8 | 484 | solver = self.solv(request, logger=logger, update=update, **kwargs) |
0c1a80b8 | 485 | |
c901e1f8 MT |
486 | if not solver.status: |
487 | logger.info(_("Nothing to do")) | |
e38914be MT |
488 | |
489 | # If we are running in check mode, we return a non-zero value to | |
490 | # indicate, that there are no updates. | |
491 | if check: | |
492 | return 1 | |
493 | else: | |
494 | return | |
495 | ||
c901e1f8 MT |
496 | # Create the transaction. |
497 | t = solver.transaction | |
4fffe3c4 | 498 | t.dump(logger=logger) |
c901e1f8 | 499 | |
e38914be MT |
500 | # Just exit here, because we won't do the transaction in this mode. |
501 | if check: | |
0c1a80b8 MT |
502 | return |
503 | ||
c0fd807c | 504 | # Ask the user if the transaction is okay. |
3817ae8e | 505 | if interactive and not t.cli_yesno(): |
c0fd807c | 506 | return |
0c1a80b8 | 507 | |
c0fd807c | 508 | # Run the transaction. |
516fc709 | 509 | t.run(logger=logger) |
18edfe75 | 510 | |
67d1ddbd MT |
511 | def downgrade(self, pkgs, allow_vendorchange=False, allow_archchange=False): |
512 | assert pkgs | |
513 | ||
514 | # Create a new request. | |
515 | request = self.create_request() | |
516 | ||
517 | # Fill request. | |
518 | for pattern in pkgs: | |
519 | best = None | |
520 | for pkg in self.repos.whatprovides(pattern): | |
521 | # Only consider installed packages. | |
522 | if not pkg.is_installed(): | |
523 | continue | |
524 | ||
525 | if best and pkg > best: | |
526 | best = pkg | |
527 | elif best is None: | |
528 | best = pkg | |
529 | ||
530 | if best is None: | |
8b6bc023 | 531 | log.warning(_("\"%s\" package does not seem to be installed.") % pattern) |
67d1ddbd MT |
532 | else: |
533 | rel = self.create_relation("%s<%s" % (best.name, best.friendly_version)) | |
534 | request.install(rel) | |
535 | ||
536 | # Solve the request. | |
5ae75344 | 537 | solver = self.solv(request, allow_downgrade=True, allow_vendorchange=allow_vendorchange, |
67d1ddbd | 538 | allow_archchange=allow_archchange) |
c901e1f8 MT |
539 | assert solver.status is True |
540 | ||
541 | # Create the transaction. | |
542 | t = solver.transaction | |
4fffe3c4 | 543 | t.dump(logger=logger) |
67d1ddbd MT |
544 | |
545 | if not t: | |
8b6bc023 | 546 | log.info(_("Nothing to do")) |
67d1ddbd MT |
547 | return |
548 | ||
549 | if not t.cli_yesno(): | |
550 | return | |
551 | ||
552 | t.run() | |
553 | ||
a39fd08b MT |
554 | def remove(self, pkgs): |
555 | # Create a new request. | |
c901e1f8 | 556 | request = self.create_request(remove=pkgs) |
a39fd08b MT |
557 | |
558 | # Solve the request. | |
5ae75344 | 559 | solver = self.solv(request, uninstall=True) |
c901e1f8 MT |
560 | assert solver.status is True |
561 | ||
562 | # Create the transaction. | |
563 | t = solver.transaction | |
4fffe3c4 | 564 | t.dump() |
a39fd08b MT |
565 | |
566 | if not t: | |
8b6bc023 | 567 | log.info(_("Nothing to do")) |
a39fd08b MT |
568 | return |
569 | ||
c0fd807c MT |
570 | # Ask the user if okay. |
571 | if not t.cli_yesno(): | |
572 | return | |
573 | ||
574 | # Process the transaction. | |
a39fd08b MT |
575 | t.run() |
576 | ||
c1e7f927 | 577 | def info(self, patterns): |
18edfe75 MT |
578 | pkgs = [] |
579 | ||
1f27e8fe MT |
580 | # For all patterns we run a single search which returns us a bunch |
581 | # of solvables which are transformed into Package objects. | |
18edfe75 | 582 | for pattern in patterns: |
5dda5744 | 583 | if os.path.exists(pattern) and not os.path.isdir(pattern): |
c07a3ca7 MT |
584 | pkg = packages.open(self, self.repos.dummy, pattern) |
585 | if pkg: | |
586 | pkgs.append(pkg) | |
1f27e8fe | 587 | |
c07a3ca7 MT |
588 | else: |
589 | solvs = self.pool.search(pattern, satsolver.SEARCH_GLOB, "solvable:name") | |
e1972777 | 590 | |
c07a3ca7 MT |
591 | for solv in solvs: |
592 | pkg = packages.SolvPackage(self, solv) | |
593 | if pkg in pkgs: | |
594 | continue | |
595 | ||
596 | pkgs.append(pkg) | |
18edfe75 | 597 | |
e1972777 | 598 | return sorted(pkgs) |
18edfe75 MT |
599 | |
600 | def search(self, pattern): | |
601 | # Do the search. | |
c2e67297 | 602 | pkgs = {} |
884cd2fb | 603 | for solv in self.pool.search(pattern, satsolver.SEARCH_STRING|satsolver.SEARCH_FILES): |
c2e67297 | 604 | pkg = packages.SolvPackage(self, solv) |
18edfe75 | 605 | |
c2e67297 MT |
606 | # Check, if a package with the name is already in the resultset |
607 | # and always replace older ones by more recent ones. | |
608 | if pkgs.has_key(pkg.name): | |
609 | if pkgs[pkg.name] < pkg: | |
610 | pkgs[pkg.name] = pkg | |
611 | else: | |
612 | pkgs[pkg.name] = pkg | |
613 | ||
614 | # Return a list of the packages, alphabetically sorted. | |
615 | return sorted(pkgs.values()) | |
18edfe75 | 616 | |
c07a3ca7 MT |
617 | def groupinstall(self, group, **kwargs): |
618 | self.install("@%s" % group, **kwargs) | |
18edfe75 MT |
619 | |
620 | def grouplist(self, group): | |
fec9a917 MT |
621 | pkgs = [] |
622 | ||
623 | for solv in self.pool.search(group, satsolver.SEARCH_SUBSTRING, "solvable:group"): | |
624 | pkg = packages.SolvPackage(self, solv) | |
18edfe75 | 625 | |
fec9a917 MT |
626 | if group in pkg.groups and not pkg.name in pkgs: |
627 | pkgs.append(pkg.name) | |
18edfe75 | 628 | |
fec9a917 | 629 | return sorted(pkgs) |
18edfe75 MT |
630 | |
631 | @staticmethod | |
1710ccec | 632 | def build(pkg, resultdirs=None, shell=False, install_test=True, after_shell=False, **kwargs): |
18edfe75 MT |
633 | if not resultdirs: |
634 | resultdirs = [] | |
635 | ||
ff9299d0 | 636 | b = builder.BuildEnviron(pkg, **kwargs) |
18edfe75 MT |
637 | p = b.pakfire |
638 | ||
639 | # Always include local repository. | |
640 | resultdirs.append(p.repos.local_build.path) | |
641 | ||
642 | try: | |
8930b228 MT |
643 | # Start to prepare the build environment by mounting |
644 | # the filesystems and extracting files. | |
645 | b.start() | |
646 | ||
1710ccec MT |
647 | try: |
648 | # Build the package. | |
649 | b.build(install_test=install_test) | |
4fffe3c4 | 650 | |
1710ccec MT |
651 | except BuildError: |
652 | # Raise the error, if the user does not want to | |
653 | # have a shell. | |
654 | if not shell: | |
655 | raise | |
18edfe75 | 656 | |
1710ccec MT |
657 | # Run a shell to debug the issue. |
658 | b.shell() | |
659 | ||
660 | # If the user requests a shell after a successful build, | |
661 | # we run it here. | |
662 | if after_shell: | |
663 | b.shell() | |
664 | ||
665 | # Copy-out all resultfiles if the build was successful. | |
18edfe75 MT |
666 | for resultdir in resultdirs: |
667 | if not resultdir: | |
668 | continue | |
669 | ||
670 | b.copy_result(resultdir) | |
18edfe75 | 671 | finally: |
8930b228 | 672 | b.stop() |
18edfe75 | 673 | |
c07a3ca7 | 674 | def _build(self, pkg, resultdir, nodeps=False, **kwargs): |
ff9299d0 | 675 | b = builder.Builder(self, pkg, resultdir, **kwargs) |
c07a3ca7 MT |
676 | |
677 | try: | |
678 | b.build() | |
4fffe3c4 | 679 | |
c07a3ca7 MT |
680 | except Error: |
681 | raise BuildError, _("Build command has failed.") | |
0d96815e MT |
682 | |
683 | # If the build was successful, cleanup all temporary files. | |
684 | b.cleanup() | |
c07a3ca7 | 685 | |
18edfe75 MT |
686 | @staticmethod |
687 | def shell(pkg, **kwargs): | |
ff9299d0 | 688 | b = builder.BuildEnviron(pkg, **kwargs) |
18edfe75 MT |
689 | |
690 | try: | |
8930b228 | 691 | b.start() |
18edfe75 MT |
692 | b.shell() |
693 | finally: | |
8930b228 | 694 | b.stop() |
18edfe75 | 695 | |
7d40ac70 MT |
696 | def dist(self, pkg, resultdir): |
697 | pkg = packages.Makefile(self, pkg) | |
18edfe75 | 698 | |
7d40ac70 | 699 | return pkg.dist(resultdir=resultdir) |
18edfe75 MT |
700 | |
701 | def provides(self, patterns): | |
702 | pkgs = [] | |
703 | for pattern in patterns: | |
e1972777 MT |
704 | for pkg in self.repos.whatprovides(pattern): |
705 | if pkg in pkgs: | |
706 | continue | |
18edfe75 | 707 | |
e1972777 | 708 | pkgs.append(pkg) |
18edfe75 | 709 | |
e1972777 | 710 | return sorted(pkgs) |
18edfe75 | 711 | |
0f8d6745 | 712 | def repo_create(self, path, input_paths, name=None, key_id=None, type="binary"): |
8276111d MT |
713 | assert type in ("binary", "source",) |
714 | ||
0f8d6745 MT |
715 | if not name: |
716 | name = _("New repository") | |
18edfe75 | 717 | |
0f8d6745 MT |
718 | # Create new repository. |
719 | repo = repository.RepositoryDir(self, name=name, description="New repository.", | |
720 | path=path, type=type, key_id=key_id) | |
18edfe75 | 721 | |
0f8d6745 MT |
722 | # Add all packages. |
723 | repo.add_packages(*input_paths) | |
68c0e769 | 724 | |
0f8d6745 | 725 | # Write metadata to disk. |
18edfe75 MT |
726 | repo.save() |
727 | ||
0f8d6745 | 728 | # Return the new repository. |
8276111d MT |
729 | return repo |
730 | ||
18edfe75 | 731 | def repo_list(self): |
c605d735 | 732 | return [r for r in self.repos] |
31267a64 MT |
733 | |
734 | def clean_all(self): | |
8b6bc023 | 735 | log.debug("Cleaning up everything...") |
31267a64 MT |
736 | |
737 | # Clean up repository caches. | |
738 | self.repos.clean() | |
35d89fd7 MT |
739 | |
740 | def check(self, downgrade=True, uninstall=True): | |
741 | """ | |
742 | Try to fix any errors in the system. | |
743 | """ | |
744 | # Detect any errors in the dependency tree. | |
745 | # For that we create an empty request and solver and try to solve | |
746 | # something. | |
747 | request = self.create_request() | |
5ae75344 | 748 | solver = self.solv(request, fix_system=True, allow_downgrade=downgrade, |
35d89fd7 MT |
749 | uninstall=uninstall) |
750 | ||
c901e1f8 | 751 | if solver.status is False: |
8b6bc023 | 752 | log.info(_("Everything is fine.")) |
35d89fd7 MT |
753 | return |
754 | ||
c901e1f8 MT |
755 | # Create the transaction. |
756 | t = solver.transaction | |
4fffe3c4 | 757 | t.dump() |
c901e1f8 | 758 | |
35d89fd7 MT |
759 | # Ask the user if okay. |
760 | if not t.cli_yesno(): | |
761 | return | |
762 | ||
763 | # Process the transaction. | |
764 | t.run() | |
3817ae8e MT |
765 | |
766 | @staticmethod | |
767 | def cache_create(**kwargs): | |
768 | # Create a build environment that we are going to pack into | |
769 | # a shiny tarball. | |
770 | b = builder.BuildEnviron(**kwargs) | |
771 | p = b.pakfire | |
772 | ||
773 | # Get filename of the file from builder instance. | |
774 | filename = b.cache_file | |
775 | ||
776 | try: | |
777 | b.start() | |
778 | ||
779 | # Create directory if not existant. | |
780 | dirname = os.path.dirname(filename) | |
781 | if not os.path.exists(dirname): | |
782 | os.makedirs(dirname) | |
783 | ||
784 | b.cache_export(filename) | |
785 | finally: | |
786 | b.stop() |