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