PubGrub version solving algorithm.
It consists in efficiently finding a set of packages and versions that satisfy all the constraints of a given project dependencies. In addition, when that is not possible, PubGrub tries to provide a very human-readable and clear explaination as to why that failed. Below is an example of explanation present in the introductory blog post about PubGrub (elm-pubgrub is almost there ^^).
Because dropdown >=2.0.0 depends on icons >=2.0.0 and
root depends on icons <2.0.0, dropdown >=2.0.0 is forbidden.
And because menu >=1.1.0 depends on dropdown >=2.0.0,
menu >=1.1.0 is forbidden.
And because menu <1.1.0 depends on dropdown >=1.0.0 <2.0.0
which depends on intl <4.0.0, every version of menu
requires intl <4.0.0.
So, because root depends on both menu >=1.0.0 and intl >=5.0.0,
version solving failed.
The algorithm is generic and works for any type of dependency system with the following caracteristics, not only Elm packages.
foo 1.0.0 depends bar 1.0.0)foo 1.0.0 depends on bar >= 1.0.0)foo 1.0.0 depends on bar < 2.0.0)foo 1.0.0 depends on bar 1.0.0 <= v < 2.0.0)The algorithm is provided in two forms, synchronous and asynchronous.
The synchronous API is quite straightforward.
The async one uses the Effect pattern to be easily integrated
into the TEA architecture.
PubGrub.solve config package version
Where config provides the list of available packages and versions,
as well as the dependencies of every available package.
The call to PubGrub.solve for a given package at a given version
will compute the set of packages and versions needed.
Sometimes, it is too expensive to provide upfront the list of all packages and versions, as well as all dependencies for every one of those. This may very well require some network or other async requests. For this reason, it is possible to run the PubGrub algorithm step by step. Every time an effect may be required, it stops and informs the caller, which may resume the algorithm once necessary data is loaded.
PubGrub.update : Cache -> Msg -> State -> ( State, Effect )
The Effect type is public to enable the caller to perform
the required task before resuming.
The Msg type is also public to drive the algorithm according
to what was expected in the last effect when resuming.
At any point between two update calls,
the caller can update the Cache of already loaded data.
The algorithm informs the caller that all is done
when the SignalEnd result effect is emitted.
Configuration of available packages to solve dependencies. The strategy of which version should be preferably picked in the list of available versions is implied by the order of the list: first version in the list will be tried first.
PubGrub version solving algorithm.
Convenient conversion of a cache into available packages configuration. This is basically:
packagesConfigFromCache cache =
{ listAvailableVersions = Cache.listVersions cache
, getDependencies = Cache.listDependencies cache
}
Internal state of the PubGrub algorithm.
Convert a state into a printable string (for human reading).
Those are the effects required by the PubGrub algorithm. Once emitted, they may require you to retrieve some data, and then send the adequate message to the algorithm.
Convert an effect into a printable string (for human reading).
Messages used to progress in the algorithm.
You should pick the one you need depending on the last effect emitted.
For example, the ListVersions effect is asking you to retrieve
available versions for a given package.
Once done, inform PubGrub with the AvailableVersions message
(and pass around the Term value).
Update the state of the PubGrub algorithm.
For messages of the AvailableVersions variant,
it is the caller responsability to order the versions in the list
with preferred versions at the beginning of the list.
As such, it is easy to try to pick the newest versions compatible
by ordering the versions with a decreasing order.
Alternatively, it can also be interesting to find the minimal versions
(oldest) in order to verify that the tests pass with those.
Solution of the algorithm containing the list of required packages with their version number.