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