elm_solve_deps/
lib.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! # Dependency solving for the elm ecosystem
4//!
5//! The elm-solve-deps crate provides a set of types, functions and traits
6//! to deal with dependencies in the elm ecosystem.
7//! It is based on the [pubgrub crate][pubgrub] and powers the dependency solvers
8//! of some of the tools in the elm ecosystem such as:
9//!  - [elm-solve-deps]: a dedicated dependency solver executable
10//!  - [elm-test-rs]: an alternative tests runner for elm
11//!
12//! [pubgrub]: https://github.com/pubgrub-rs/pubgrub
13//! [elm-solve-deps]: https://github.com/mpizenberg/elm-solve-deps
14//! [elm-test-rs]: https://github.com/mpizenberg/elm-test-rs
15//!
16//! The main objective of dependency solving is to start from
17//! a set of dependency constraints, provided for example by the `elm.json` of a package:
18//!
19//! ```json
20//! {
21//!   ...,
22//!   "dependencies": {
23//!     "elm/core": "1.0.2 <= v < 2.0.0",
24//!     "elm/http": "2.0.0 <= v < 3.0.0",
25//!     "elm/json": "1.1.2 <= v < 2.0.0",
26//!   },
27//!   "test-dependencies": {
28//!     "elm-explorations/test": "1.2.0 <= v < 2.0.0"
29//!   }
30//! }
31//! ```
32//!
33//! And then find a set of package versions satisfying these constraints.
34//! In general we also want some prioritization, such as picking the newest versions compatible.
35//! In this case and at this date, without considering the test dependencies, the newest solution is:
36//!
37//! ```json
38//! {
39//!   "direct": {
40//!     "elm/core": "1.0.5",
41//!     "elm/http": "2.0.0",
42//!     "elm/json": "1.1.3"
43//!   },
44//!   "indirect": {
45//!     "elm/bytes": "1.0.8",
46//!     "elm/file": "1.0.5",
47//!     "elm/time": "1.0.0"
48//!   }
49//! }
50//! ```
51//!
52//! And if we also consider the tests dependencies, we get instead:
53//!
54//! ```json
55//! {
56//!   "direct": {
57//!     "elm/core": "1.0.5",
58//!     "elm/http": "2.0.0",
59//!     "elm/json": "1.1.3",
60//!     "elm-explorations/test": "1.2.2"
61//!   },
62//!   "indirect": {
63//!     "elm/bytes": "1.0.8",
64//!     "elm/file": "1.0.5",
65//!     "elm/html": "1.0.0",
66//!     "elm/random": "1.0.0",
67//!     "elm/time": "1.0.0",
68//!     "elm/virtual-dom": "1.0.2"
69//!   }
70//! }
71//! ```
72//!
73//! ## Simple offline dependency solver
74//!
75//! This library already provides a dependency solver ready for offline use cases.
76//! The [`solver::Offline`] struct has to be initialized with the path to `ELM_HOME`,
77//! as well as the version of elm used (concretely, this should only be `"0.19.1"` for now).
78//! Then it provides a [`solve_deps`](solver::Offline::solve_deps) function,
79//! which will either succeed and return a solution, or fail with an error.
80//!
81//! The offline solver will only ever look for packages inside `ELM_HOME` and thus
82//! should work with other "elm-compatible" ecosystems such as Lamdera.
83//! You can use it as follows.
84//!
85//! ```no_run
86//! # use elm_solve_deps::solver;
87//! # let elm_home = || "";
88//! // Define an offline solver.
89//! let offline_solver = solver::Offline::new(elm_home(), "0.19.1");
90//!
91//! // Load the project elm.json.
92//! let elm_json_str = std::fs::read_to_string("elm.json")
93//!     .expect("Are you in an elm project? there was an issue loading the elm.json");
94//! let project_elm_json = serde_json::from_str(&elm_json_str)
95//!     .expect("Failed to decode the elm.json");
96//!
97//! // Solve with tests dependencies.
98//! let use_test = true;
99//!
100//! // Do not add any extra additional dependency.
101//! let extras = &[];
102//!
103//! // Solve dependencies.
104//! let solution = offline_solver
105//!     .solve_deps(&project_elm_json, use_test, extras)
106//!     .expect("Dependency solving failed");
107//! ```
108//!
109//! Note that it is possible to provide additional package constraints,
110//! which is convenient for tooling when requiring additional packages that are not recorded
111//! directly in the original `elm.json` file.
112//!
113//! ## Online dependency solver
114//!
115//! We also provide an online solver for convenience.
116//! When initialized, it starts by updating its database of known packages.
117//! Then when solving dependencies, it works similarly than the offline solver,
118//! but with a set of packages that is the union of those existing locally,
119//! and those existing on the package server.
120//! Refer to [`solver::Online`] documentation for more info.
121//!
122//! ## Custom dependency solver
123//!
124//! Finally, if you want more control over the process of choosing dependencies,
125//! you can either use the configurable function [`solver::solve_deps_with`],
126//! or go with full customization by writing your own dependency provider
127//! and use directly the pubgrub crate.
128//!
129//! When using [`solver::solve_deps_with`], you are required to provide
130//! two functions, namely `fetch_elm_json` and `list_available_versions`,
131//! implementing the following pseudo trait bounds:
132//!
133//! ```ignore
134//! fetch_elm_json: Fn(&Pkg, SemVer) -> Result<PackageConfig, Error>
135//! list_available_versions: Fn(&Pkg) -> Result<Iterator<SemVer>, Error>
136//! ```
137//!
138//! It is up to you to figure out where to look for those config `elm.json`
139//! and how to provide the list of existing versions.
140//! Remark that the order in the versions iterator returned will correspond
141//! to the prioritization for picking versions.
142//! This means prioritizing newest or oldest versions is just a `.reverse()` on your part.
143//!
144//! ## Other helper modules
145//!
146//! In order for the different solver types to come together nicely,
147//! a bunch of helper modules are also provided by this crate.
148//!
149//! - [`project_config`]: module dealing with the serialization and deserialization of config `elm.json` files.
150//! - [`pkg_version`]: module defining the base type identifying a unique package version. It also
151//! provides a few helper types and functions to read/write to a cache in `ELM_HOME` and to fetch
152//! packages from a server following the same API than the official elm package server.
153//! - [`constraint`]: module helping with serialization and deserialization of version constraints.
154//! - [`dependency_provider`]: module with a helper implementation converting a generic dependency
155//! provider into one that is using a project `elm.json` as root.
156
157#![warn(missing_docs)]
158
159pub mod constraint;
160pub mod dependency_provider;
161pub mod pkg_version;
162pub mod project_config;
163pub mod solver;