Object
Based on solution_constraints, this method tries to find an assignment of PackageVersions that is compatible with the DependencyGraph. If one cannot be found, the constraints are added one at a time until the first unsatisfiable constraint is detected. Once the unsatisfiable solution constraint is identified, required non-existent packages and the most constrained packages are identified and thrown in a NoSolutionExists exception.
If a solution constraint refers to a package that doesn't exist or the constraint matches no versions, it is considered invalid. All invalid solution constraints are collected and raised in an InvalidSolutionConstraints exception. If valid_packages is non-nil, it is considered the authoritative list of extant Packages; otherwise, Package#valid? is used. This is useful if the dependency graph represents an already filtered set of packages such that a Package actually exists in your domain but is added to the dependency graph with no versions, in which case Package#valid? would return false even though we don't want to report that the package is non-existent.
# File lib/dep_selector/selector.rb, line 61 def find_solution(solution_constraints, valid_packages = nil) # this is a performance optimization so that packages that are # completely unreachable by the solution constraints don't get # added to the CSP packages_to_include_in_solve = trim_unreachable_packages(dep_graph, solution_constraints) begin # first, try to solve the whole set of constraints solve(dep_graph.clone, solution_constraints, valid_packages, packages_to_include_in_solve) rescue Exceptions::NoSolutionFound # since we're here, solving the whole system failed, so add # the solution_constraints one-by-one and try to solve in # order to find the constraint that breaks the system in order # to give helpful debugging info # # TODO [cw,2010/11/28]: for an efficiency gain, instead of # continually re-building the problem and looking for a # solution, turn solution_constraints into a Generator and # iteratively add and solve in order to re-use # propagations. This will require separating setting up the # constraints from searching for the solution. solution_constraints.each_index do |idx| workspace = dep_graph.clone begin solve(workspace, solution_constraints[0..idx], valid_packages, packages_to_include_in_solve) rescue Exceptions::NoSolutionFound => nsf disabled_packages = packages_to_include_in_solve.inject([]) do |acc, elt| pkg = workspace.package(elt.name) acc << pkg if nsf.unsatisfiable_problem.is_package_disabled?(pkg.gecode_package_id) acc end # disambiguate between packages disabled becuase they # don't exist and those that have otherwise problematic # constraints disabled_non_existent_packages = [] disabled_most_constrained_packages = [] disabled_packages.each do |disabled_pkg| disabled_collection = if disabled_pkg.valid? || (valid_packages && valid_packages.include?(disabled_pkg)) disabled_most_constrained_packages else disabled_non_existent_packages end disabled_collection << disabled_pkg end # Pick the first non-existent or most-constrained package # that was required or the package whose constraints had # to be disabled in order to find a solution and generate # feedback for it. We only report feedback for one # package, because it is in fact actionable and dispalying # feedback for every disabled package would probably be # too long. The full set of disabled packages is # accessible in the NoSolutionExists exception. disabled_package_to_report_on = disabled_non_existent_packages.first || disabled_most_constrained_packages.first feedback = error_reporter.give_feedback(dep_graph, solution_constraints, idx, disabled_package_to_report_on) raise Exceptions::NoSolutionExists.new(feedback, solution_constraints[idx], disabled_non_existent_packages, disabled_most_constrained_packages) end end end end
Generated with the Darkfish Rdoc Generator 2.