# Reset logging.
logger.setup_logging()
- def create_solver(self):
- return satsolver.Solver(self, self.pool)
+ def expand_requires(self, requires):
+ if requires is None:
+ return []
- def create_request(self, builder=False):
+ ret = []
+ for req in requires:
+ if isinstance(req, packages.BinaryPackage):
+ ret.append(req)
+ continue
+
+ if isinstance(req, packages.SolvPackage):
+ ret.append(req.solvable)
+ continue
+
+ assert type(req) == type("a"), req
+
+ # Expand all groups.
+ if req.startswith("@"):
+ reqs = self.grouplist(req[1:])
+ else:
+ reqs = [req,]
+
+ for req in reqs:
+ req = self.create_relation(req)
+ ret.append(req)
+
+ return ret
+
+ def create_request(self, builder=False, install=None, remove=None, update=None):
request = satsolver.Request(self.pool)
# Add multiinstall information.
for solv in PAKFIRE_MULTIINSTALL:
request.noobsoletes(solv)
+ # Apply all installs.
+ for req in self.expand_requires(install):
+ request.install(req)
+
+ # Apply all removes.
+ for req in self.expand_requires(remove):
+ request.remove(req)
+
+ # Apply all updates.
+ for req in self.expand_requires(update):
+ request.update(req)
+
+ # Return the request.
return request
def create_relation(self, s):
# XXX just backwards compatibility
return self.mode == "builder"
- def resolvdep(self, requires):
+ def resolvdep(self, pkg, logger=None):
+ assert os.path.exists(pkg)
+
+ # Open the package file.
+ pkg = packages.open(self, None, pkg)
+
# Create a new request.
- request = self.create_request()
- for req in requires:
- req = self.create_relation(req)
- request.install(req)
+ request = self.create_request(install=pkg.requires)
- # Do the solving.
- solver = self.create_solver()
- t = solver.solve(request)
+ # Add build dependencies if needed.
+ if isinstance(pkg, packages.Makefile) or isinstance(pkg, packages.SourcePackage):
+ for req in self.expand_requires(BUILD_PACKAGES):
+ request.install(req)
- if t:
- t.dump()
- else:
- log.info(_("Nothing to do"))
+ # Solv the request.
+ solver = self.solv(request, logger=logger)
+
+ if solver.status:
+ return solver
+
+ raise DependencyError, solver.get_problem_string()
+
+ def solv(self, request, interactive=False, logger=None, **kwargs):
+ # XXX implement interactive
- def install(self, requires, interactive=True, logger=None, **kwargs):
if not logger:
logger = logging.getLogger("pakfire")
- # Create a new request.
- request = self.create_request()
+ # Create a solver.
+ solver = satsolver.Solver(self, request, logger=logger)
- # Expand all groups.
- for req in requires:
- if req.startswith("@"):
- reqs = self.grouplist(req[1:])
- else:
- reqs = [req,]
+ # Apply configuration to solver.
+ for key, val in kwargs.items():
+ solver.set(key, val)
- for req in reqs:
- if not isinstance(req, packages.BinaryPackage):
- req = self.create_relation(req)
+ # Do the solving.
+ solver.solve()
- request.install(req)
+ # Return the solver so one can do stuff with it...
+ return solver
+
+ def install(self, requires, interactive=True, logger=None, **kwargs):
+ if not logger:
+ logger = logging.getLogger("pakfire")
# Do the solving.
- solver = self.create_solver()
- t = solver.solve(request, logger=logger, **kwargs)
+ request = self.create_request(install=requires)
+ solver = self.solv(request, logger=logger, interactive=interactive, **kwargs)
- if not t:
+ if not solver.status:
if not interactive:
raise DependencyError
- log.info(_("Nothing to do"))
+ logger.info(_("Nothing to do"))
return
+ # Create the transaction.
+ t = solver.transaction
+
if interactive:
# Ask if the user acknowledges the transaction.
if not t.cli_yesno():
t.run(logger=logger)
def localinstall(self, files, yes=None, allow_uninstall=False, logger=None):
+ if logger is None:
+ logger = logging.getLogger("pakfire")
+
repo_name = repo_desc = "localinstall"
# Create a new repository that holds all packages we passed on
# Create a new request that installs all solvables from the
# repository.
- request = self.create_request()
- for solv in [p.solvable for p in repo]:
- request.install(solv)
+ request = self.create_request(install=repo)
- solver = self.create_solver()
- t = solver.solve(request, uninstall=allow_uninstall)
+ solver = self.solv(request, logger=logger, uninstall=allow_uninstall)
# If solving was not possible, we exit here.
- if not t:
- log.info(_("Nothing to do"))
+ if not solver.status:
+ logger.info(_("Nothing to do"))
return
+ # Create transaction.
+ t = solver.transaction
+
if yes is None:
# Ask the user if this is okay.
if not t.cli_yesno():
request.install(new.solvable)
if request:
- solver = self.create_solver()
- t = solver.solve(request)
+ solver = self.solv(request)
+ assert solver.status
+
+ t = solver.transaction
else:
# Create new transaction.
t = transaction.Transaction(self)
check indicates, if the method should return after calculation
of the transaction.
"""
- request = self.create_request()
+ if logger is None:
+ logger = logging.getLogger("pakfire")
# If there are given any packets on the command line, we will
# only update them. Otherwise, we update the whole system.
if pkgs:
update = False
- for pkg in pkgs:
- pkg = self.create_relation(pkg)
- request.update(pkg)
else:
update = True
+ request = self.create_request(update=pkgs)
+
# Exclude packages that should not be updated.
- if excludes:
- for exclude in excludes:
- log.info(_("Excluding %s.") % exclude)
+ for exclude in excludes or []:
+ logger.info(_("Excluding %s.") % exclude)
- exclude = self.create_relation(exclude)
- request.lock(exclude)
+ exclude = self.create_relation(exclude)
+ request.lock(exclude)
- solver = self.create_solver()
- t = solver.solve(request, update=update, logger=logger, **kwargs)
+ solver = self.solv(request, logger=logger, update=update, **kwargs)
- if not t:
- log.info(_("Nothing to do"))
+ if not solver.status:
+ logger.info(_("Nothing to do"))
# If we are running in check mode, we return a non-zero value to
# indicate, that there are no updates.
else:
return
+ # Create the transaction.
+ t = solver.transaction
+
# Just exit here, because we won't do the transaction in this mode.
if check:
t.dump(logger=logger)
request.install(rel)
# Solve the request.
- solver = self.create_solver()
- t = solver.solve(request, allow_downgrade=True,
- allow_vendorchange=allow_vendorchange,
+ solver = self.solve(request, allow_downgrade=True, allow_vendorchange=allow_vendorchange,
allow_archchange=allow_archchange)
+ assert solver.status is True
+
+ # Create the transaction.
+ t = solver.transaction
if not t:
log.info(_("Nothing to do"))
def remove(self, pkgs):
# Create a new request.
- request = self.create_request()
- for pkg in pkgs:
- pkg = self.create_relation(pkg)
- request.remove(pkg)
+ request = self.create_request(remove=pkgs)
# Solve the request.
- solver = self.create_solver()
- t = solver.solve(request, uninstall=True)
+ solver = self.solve(request, uninstall=True)
+ assert solver.status is True
+
+ # Create the transaction.
+ t = solver.transaction
if not t:
log.info(_("Nothing to do"))
# For that we create an empty request and solver and try to solve
# something.
request = self.create_request()
- solver = self.create_solver()
-
- # XXX the solver does crash if we call it with fix_system=1,
- # allow_downgrade=1 and uninstall=1. Need to fix this.
- allow_downgrade = False
- uninstall = False
-
- t = solver.solve(request, fix_system=True, allow_downgrade=downgrade,
+ solver = self.solve(request, fix_system=True, allow_downgrade=downgrade,
uninstall=uninstall)
- if not t:
+ if solver.status is False:
log.info(_("Everything is fine."))
return
+ # Create the transaction.
+ t = solver.transaction
+
# Ask the user if okay.
if not t.cli_yesno():
return
# #
###############################################################################
+import time
+
import logging
log = logging.getLogger("pakfire")
import _pakfire
from _pakfire import *
+from i18n import _
import transaction
import util
-from i18n import _
-
class Request(_pakfire.Request):
def install(self, what):
if isinstance(what, Solvable):
class Solver(object):
- def __init__(self, pakfire, pool):
+ def __init__(self, pakfire, request, logger=None):
+ if logger is None:
+ logger = logging.getLogger("pakfire")
+ self.logger = logger
+
self.pakfire = pakfire
- self.pool = pool
+ self.pool = self.pakfire.pool
- def solve(self, request, update=False, uninstall=False, allow_downgrade=False,
- allow_vendorchange=False, allow_archchange=False, fix_system=False,
- interactive=False, logger=None):
+ # Default settings.
+ self.settings = {
+ # Update all installed packages?
+ "update" : False,
- # If no logger was provided, we use the root logger.
- if logger is None:
- logger = log
+ # Allow to uninstall any packages?
+ "uninstall" : False,
+
+ # Allow to downgrade any packages?
+ "allow_downgrade" : False,
+
+ # Allow packages to change their vendors?
+ "allow_vendorchange" : False,
+
+ # Allow packages to change their arch?
+ "allow_archchange" : False,
+
+ # Fix system?
+ "fix_system" : False,
+ }
+
+ self.request = request
+ assert self.request, "Empty request?"
# Create a new solver.
- solver = _pakfire.Solver(self.pool)
+ self.solver = _pakfire.Solver(self.pool)
+
+ # The status of the solver.
+ # None when the solving was not done, yet.
+ # True when the request could be solved.
+ # False when the request could not be solved.
+ self.status = None
+
+ # Time that was needed to solve the request.
+ self.time = None
+
+ # Cache the transaction and problems.
+ self.__problems = None
+ self.__transaction = None
+
+ def set(self, key, value):
+ assert self.settings.has_key(key), "Unknown configuration setting: %s" % key
+ assert value in (True, False), "Invalid value: %s" % value
+
+ try:
+ self.settings[key] = value
+ except KeyError:
+ pass
+
+ def get(self, key):
+ assert self.settings.has_key(key), "Unknown configuration setting: %s" % key
- solver.set_fix_system(fix_system)
- solver.set_allow_uninstall(uninstall)
- solver.set_allow_downgrade(allow_downgrade)
+ return self.settings.get(key)
+
+ def solve(self):
+ assert self.status is None, "Solver did already solve something."
+
+ # Apply solver configuration.
+ self.solver.set_fix_system(self.get("fix_system"))
+ self.solver.set_allow_uninstall(self.get("uninstall"))
+ self.solver.set_allow_downgrade(self.get("allow_downgrade"))
# Optionally allow packages to change their vendors.
# This is not recommended because it may have weird effects.
- solver.set_allow_vendorchange(allow_vendorchange)
+ self.solver.set_allow_vendorchange(self.get("allow_vendorchange"))
# Optionally allow packages ot change their architecture.
- solver.set_allow_archchange(allow_archchange)
+ self.solver.set_allow_archchange(self.get("allow_archchange"))
# Configure the solver for an update.
- if update:
+ if self.get("update"):
solver.set_updatesystem(True)
solver.set_do_split_provides(True)
# Actually solve the request.
- res = solver.solve(request)
+ start_time = time.time()
+ self.status = self.solver.solve(self.request)
+
+ # Save the amount of time that was needed to solve the request.
+ self.time = time.time() - start_time
+
+ self.logger.debug("Solver status: %s (%.2f ms)" % (self.status, self.time / 1000))
+
+ @property
+ def transaction(self):
+ if not self.status is True:
+ return
+
+ if self.__transaction is None:
+ self.__transaction = \
+ transaction.Transaction.from_solver(self.pakfire, self)
+
+ return self.__transaction
+
+ @property
+ def problems(self):
+ if self.__problems is None:
+ self.__problems = self.solver.get_problems(self.request)
+
+ return self.__problems
+
+ def get_problem_string(self):
+ assert self.status is False
+
+ lines = [
+ _("The solver returned one problem:", "The solver returned %(num)s problems:",
+ len(self.problems)) % { "num" : len(self.problems) },
+ ]
+
+ i = 0
+ for problem in self.problems:
+ i += 1
+
+ # Print information about the problem.
+ lines.append(" #%d: %s" % (i, problem))
+
+ return "\n".join(lines)
- logger.debug("Solver status: %s" % res)
+ def DEADCODE(self):
# If the solver succeeded, we return the transaction and return.
if res:
# Return a resulting Transaction.