Babel: opam repository with pubgrub-opam
X tests
-
- Uv is using the development branch of PubGrub.
- There’s a lot of improvements to be had since the last release was 4
years ago.
- The new version bounds will cleanly express version constraints,
e.g. stop converting
<= 1.0.0
to< 1.0.0.1
- It looks like we might be able to manually add conflicts with
add_incompatibility
- Ah, actually this is an internal thing.
- The new version bounds will cleanly express version constraints,
e.g. stop converting
- Completed here.
X conjunctions and disjunctions in filtered package formula
Take
"D" { test & > "2.0.0"}
as an example. We encode this as,(filtered-package-formula-variable-version, 1.0.0) -> (D {(test & = >2.0.0)}, *) (D {(test & = >2.0.0)}, false) -> (`test`, false) (D {(test & = >2.0.0)}, true) -> (`test`, true), (A, >1.0.0) (`test`, false) (`test`, true) (A, 2.0.0) -> ...
Note we introduce a proxy package that depends on either the filter being false (with versions stripped out), or the filter being true (with versions part of the equation, taking the union on conjunctions and intersection on disjunctions).
Take
"A" { test | !test }
as an example. We encode this as,(filtered-package-formula-or, 1.0.0) -> (A {(test | !test)}, *) (A {(test | !test)}, false) -> (`test`, ∅) (A {(test | !test)}, true) -> (A {(test | !test)}, *) (A {(test | !test)}, lhs) -> (`test`, true), (A, *) (`test`, true) (A, 1.0.0) -> ...
Note we combine the versions of the variable
test
with an intersection which leads to the empty set.X comparison of booleans
done here e.g.
(filtered-package-formula-equality, 1.0.0) -> (A {(test = build)}, *) versions of A {(test = build)}: false, true (A {(test = build)}, false) -> ({(test != build)}, *) versions of {(test != build)}: lhs, rhs ({(test != build)}, lhs) -> (`test`, true), (`build`, false) versions of `test`: false, true (`test`, true) versions of `build`: false, true (`build`, false)
X add support for a ‘root’ package to support setting variable values
done here
X
ocaml-variants.5.3.1+trunk
I’m reproducing a bug in opam-repository’s constraints that Patrick found.
$ opam sw create 5.3.1+trunk <><> Installing new switch packages <><><><><><><><><><><><><><><><><><><><> 🐫 Switch invariant: ["ocaml-variants" {= "5.3.1+trunk"}] [ERROR] Could not determine which packages to install for this switch: * No agreement on the version of ocaml-variants: - (invariant) → ocaml-variants = 5.3.1+trunk → ocaml-compiler < 5.3.0~alpha1 → ocaml = 5.3.0 → ocaml-variants < 5.3.1~ - (invariant) → ocaml-variants = 5.3.1+trunk You can temporarily relax the switch invariant with `--update-invariant' * Incompatible packages: - (invariant) → ocaml-variants = 5.3.1+trunk → ocaml-compiler < 5.3.0~alpha1 → ocaml = 5.3.0 → dkml-base-compiler < 5.3.1~ - (invariant) → ocaml-variants = 5.3.1+trunk * Incompatible packages: - (invariant) → ocaml-variants = 5.3.1+trunk → ocaml-compiler < 5.3.0~alpha1 → ocaml = 5.3.0 → ocaml-base-compiler >= 5.3.0~ - (invariant) → ocaml-variants = 5.3.1+trunk * Missing dependency: - (invariant) → ocaml-variants = 5.3.1+trunk → ocaml-compiler < 5.3.0~alpha1 → ocaml = 5.3.0 → ocaml-variants < 5.3.1~ → system-msvc unmet availability conditions: 'os = "win32"'
After adding conflict-class support (which are required for the ocaml compiler packages) we can reproduce the error:
Because ocaml-system >=5.3.0~, <5.3.1~ depends on Conflict class ocaml-core-compiler ocaml-system and ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) rhs depends on ocaml-system >=5.3.0~, <5.3.1~, ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) rhs depends on Conflict class ocaml-core-compiler ocaml-system. (1) Because ocaml-base-compiler >=5.3.0~, <5.3.1~ depends on Conflict class ocaml-core-compiler ocaml-base-compiler and (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}) lhs depends on ocaml-base-compiler >=5.3.0~, <5.3.1~, (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}) lhs depends on Conflict class ocaml-core-compiler ocaml-base-compiler. And because (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}) <lhs | >lhs depends on ocaml-variants >=5.3.0~, <5.3.1~ and ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) lhs depends on (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}), Conflict class ocaml-core-compiler Not ( ocaml-base-compiler ), ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) lhs, ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. And because ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) rhs depends on Conflict class ocaml-core-compiler ocaml-system (1), Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) *, ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. And because (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) lhs depends on ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) and (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) <lhs | >lhs depends on dkml-base-compiler >=5.3.0~, <5.3.1~, Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) *, ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. And because ocaml 5.3.0 depends on (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) and ocaml {(= 5.3.0 & post)} true depends on ocaml 5.3.0, ocaml {(= 5.3.0 & post)} true, Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. And because ocaml {(= 5.3.0 & post)} false depends on `post` false and ocaml-compiler 5.3 depends on ocaml {(= 5.3.0 & post)}, ocaml-compiler 5.3, Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), `post` Not ( false ), ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. And because ocaml-variants 5.3.1+trunk depends on ocaml-compiler 5.3 and ocaml-variants 5.3.1+trunk depends on Conflict class ocaml-core-compiler ocaml-variants, ocaml-variants 5.3.1+trunk depends on `post` false. And because Root depends on `post` true and Root depends on ocaml-variants 5.3.1+trunk, Root is forbidden.
Let’s break this down.
Because ocaml-system >=5.3.0~, <5.3.1~ depends on Conflict class ocaml-core-compiler ocaml-system and ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) rhs depends on ocaml-system >=5.3.0~, <5.3.1~, ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) rhs depends on Conflict class ocaml-core-compiler ocaml-system. (1)
Because
ocaml-system
is in conflict classocaml-core-compiler
and this formula’s right hand side (RHS) depends onocaml-system
, the RHS of the formula depends onocaml-system
in theocaml-core-compiler
conflict class.Because ocaml-base-compiler >=5.3.0~, <5.3.1~ depends on Conflict class ocaml-core-compiler ocaml-base-compiler and (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}) lhs depends on ocaml-base-compiler >=5.3.0~, <5.3.1~, (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}) lhs depends on Conflict class ocaml-core-compiler ocaml-base-compiler.
Because
ocaml-base-compiler
is in conflict classocaml-core-compiler
and this formula’s left hand side (LHS) depends onocaml-base-compiler
, the LHS of the formula depends onocaml-base-compiler
in theocaml-core-compiler
conflict class.And because (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})
lhs depends on ocaml-variants >=5.3.0~, <5.3.1~ and ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) lhs depends on (ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~}), Conflict class ocaml-core-compiler Not ( ocaml-base-compiler ), ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) lhs, ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. And because the parent formula’s LHS has it’s RHS depends on
ocaml-variants
, and the formula’s LHS depends on the formula’s LHS (duh), then we can’t select the LHS of the formula (ocaml-base-compiler
orocaml-variants
) and not selectocaml-base-compiler
and not select ocaml-variants (phew).Basically, the LHS of the formula depends on either
ocaml-base-compiler
orocaml-variants
.And because ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) rhs depends on Conflict class ocaml-core-compiler ocaml-system (1), Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) *, ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible.
Because the formula’s RHS selects
ocaml-system
in conflict classocaml-core-compiler
, then we can’t select (either side of) the formula without selectingocaml-base-compiler
orocaml-system
inocaml-core-compiler
, andocam-variants
.And because (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) lhs depends on ((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~}) and (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~})
lhs depends on dkml-base-compiler >=5.3.0~, <5.3.1~, Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) *, ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible. We can’t select this formula without selecting
ocaml-base-compiler
orocaml-system
inocaml-core-compiler
, andocam-variants
. Notedkml-base-compiler
is ignored as there’s not compatible versions.And because ocaml 5.3.0 depends on (((ocaml-base-compiler {= >=5.3.0~, <5.3.1~}) | (ocaml-variants {= >=5.3.0~, <5.3.1~})) | (ocaml-system {= >=5.3.0~, <5.3.1~})) | (dkml-base-compiler {= >=5.3.0~, <5.3.1~}) and ocaml {(= 5.3.0 & post)} true depends on ocaml 5.3.0, ocaml {(= 5.3.0 & post)} true, Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible.
If the proxy package associated with the filtered package formula ocaml
ocaml {(= 5.3.0 & post)}
is selected (i.e. versiontrue
) then we must haveocaml-base-compiler
orocaml-system
inocaml-core-compiler
, andocam-variants
.And because ocaml {(= 5.3.0 & post)} false depends on `post` false and ocaml-compiler 5.3 depends on ocaml {(= 5.3.0 & post)}, ocaml-compiler 5.3, Conflict class ocaml-core-compiler Not ( ocaml-base-compiler | ocaml-system ), `post` Not ( false ), ocaml-variants Not ( >=5.3.0~, <5.3.1~ ) are incompatible.
If we don’t select this package formula, we need post to be false, and
ocaml-compiler
depends on this formula, so we can’t select ocaml-compiler withpost=true
withoutocaml-base-compiler
orocaml-system
inocaml-core-compiler
, andocam-variants
.And because ocaml-variants 5.3.1+trunk depends on ocaml-compiler 5.3 and ocaml-variants 5.3.1+trunk depends on Conflict class ocaml-core-compiler ocaml-variants, ocaml-variants 5.3.1+trunk depends on `post` false.
Because
ocaml-variants
depends onocaml-compiler
and is in conflict classocaml-core-compiler
, we can’t select it without havingpost=false
.And because Root depends on `post` true and Root depends on ocaml-variants 5.3.1+trunk, Root is forbidden.
Since we set
post=true
at the root, we have a conflict.This is all a very roundabout way of telling us that we have a conflict class. This provides a good example to explore using a custom error provider for.
After applying the fix, we successfully solve the dependencies:
Solution Set: opam-version = 2.1.0 (host-arch-arm64, 1) (base-domains, base) (ocaml, 5.3.1) (host-system-other, 1) (base-threads, base) os = macos (base-unix, base) (ocaml-compiler, 5.3) (base-bigarray, base) (ocaml-config, 3) (base-nnp, base) (base-effects, base) (ocaml-variants, 5.3.1+trunk) post = true arch = arm64 Resolved Dependency Graph: (base-bigarray, base) (base-domains, base) -> (ocaml, 5.3.1) (base-effects, base) -> (ocaml, 5.3.1) (base-nnp, base) -> (base-domains, base) (base-threads, base) (base-unix, base) (host-arch-arm64, 1) (host-system-other, 1) (ocaml, 5.3.1) -> (ocaml-config, 3), (ocaml-variants, 5.3.1+trunk) (ocaml-compiler, 5.3) -> (`arch`, arm64), (`opam-version`, 2.1.0), (`os`, macos), (`post`, true), (base-bigarray, base), (base-domains, base), (base-effects, base), (base-nnp, base), (base-threads, base), (base-unix, base), (host-arch-arm64, 1), (host-system-other, 1), (ocaml, 5.3.1) (ocaml-config, 3) -> (`os`, macos) (ocaml-variants, 5.3.1+trunk) -> (`opam-version`, 2.1.0), (ocaml-compiler, 5.3)
O a Debian/Alpine encoding in PubGrub, which I think should be much simpler than Opam
O and tie into opam with depexts for cross-ecosystem resolutions
O PubGrub custom error provider
- look at
test_package_formula_or_error
- look at
test_opam_repository_ocaml_variants
- look at
O optional dependencies
O conflicts
tracking issue here
O boolean and integer filter literals
O statically configure possible variable values
O read up on answer set programming
https://pubgrub-rs-guide.pages.dev/internals/intro is a good starting point
Teaching
Supervision 2 of Robinson Computer Networking
17 Feb 2025
Previous: 10 Feb 2025
Next: 25 Feb 2025