Solution and error reporting

When everything goes well, the algorithm finds and returns a set of packages and versions satisfying all the constraints of direct and indirect dependencies. Sometimes however, there is no solution because dependencies are incompatible. In such cases, the algorithm returns a PubGrubError::NoSolution(derivation_tree) where the provided derivation tree is a binary tree containing the chain of reasons why there is no solution.

The items in the tree are called incompatibilities and may be either external, derived or custom. Leaves of the tree are external and custom incompatibilities, and nodes are derived. External incompatibilities express facts that are independent of the way this algorithm is implemented such as package "a" at version 1 depends on package "b" at version 4, or that there is no version of package "a" higher than version 5. Custom incompatibilities are a user provided generic type parameter that can express missing versions, such as that dependencies of package "a" are not in cache, but the user requested an offline resolution.

In contrast, derived incompatibilities are obtained during the algorithm execution by deduction, such as if "a" depends on "b" and "b" depends on "c", then "a" depends on "c".

Processing a derivation tree in a custom way to generate a failure report that is human-friendly is not an easy task. For convenience, this crate provides a DefaultStringReporter able to convert a derivation tree into a human-friendly String explanation of the failure. You may use it as follows.

#![allow(unused)]
fn main() {
use pubgrub::{resolve, DefaultStringReporter, PubGrubError, Reporter};

match resolve(&dependency_provider, root_package, root_version) {
    Ok(solution) => println!("{:?}", solution),
    Err(PubGrubError::NoSolution(mut derivation_tree)) => {
        derivation_tree.collapse_no_versions();
        eprintln!("{}", DefaultStringReporter::report(&derivation_tree));
    }
    Err(err) => panic!("{:?}", err),
};
}

Notice that we also used collapse_no_versions() above. This method simplifies the derivation tree to get rid of the NoVersions external incompatibilities in the derivation tree. So instead of seeing things like this in the report:

Because there is no version of foo in 1.0.1 <= v < 2.0.0
and foo 1.0.0 depends on bar 2.0.0 <= v < 3.0.0,
foo 1.0.0 <= v < 2.0.0 depends on bar 2.0.0 <= v < 3.0.0.
...

You will directly see something like:

Because foo 1.0.0 <= v < 2.0.0 depends on bar 2.0.0,
...