tarides / opam-monorepo

Assemble dune workspaces to build your project and its dependencies as a whole
ISC License
130 stars 27 forks source link

Improve error messages when the solver fails #154

Open TheLortex opened 3 years ago

TheLortex commented 3 years ago

opam-monorepo has a very verbose error log when failing to solve packages. Its notably hard to distinguish the failing packages from the others.

For the same set of dependencies, here are the outputs of opam and opam-monorepo, where the failing packages are:

opam

The following dependencies couldn't be met:
  - dns-hvt → mirage-dns → mirage-kv-lwt → mirage-kv < 3.0.0
  - dns-hvt → mirage-dns → dns < 1.0.0 → cstruct < 3.0.0 → sexplib < 113.01.00 → ocaml < 4.03.0
      base of this switch (use `--unlock-base' to force)
  - dns-hvt → mirage-dns → dns < 1.0.0 → cstruct < 3.0.0 → ocaml < 4.08.0
      base of this switch (use `--unlock-base' to force)
  - dns-hvt → mirage-dns → dns < 1.0.0 → io-page < 1.3.0 → ocaml < 4.06.0
      base of this switch (use `--unlock-base' to force)
  - dns-hvt → mirage-dns → dns < 1.0.0 → lwt < 3.0.0 → ocaml < 4.06.0
      base of this switch (use `--unlock-base' to force)
  - dns-hvt → mirage-dns → dns < 1.0.0 → uri < 1.9.4 → sexplib < 113.01.00 → ocaml < 4.03.0
      base of this switch (use `--unlock-base' to force)
  - dns-hvt → mirage-dns → dns < 1.0.0 → uri < 1.9.4 → ocaml < 4.06.0
      base of this switch (use `--unlock-base' to force)
  - dns-hvt → mirage-kv-mem >= 3.0.0 → mirage-kv >= 3.0.0
      unmet availability conditions, e.g. false
Your request can't be satisfied:
  - No available version of mirage-kv satisfies the constraints

opam-monorepo

               - arp -> arp.2.2.1
                   arp-mirage 2.2.1 requires = 2.2.1
               - base -> (problem)
                   Rejected candidates:
                     base.v0.14.1: Requires ocaml >= 4.07.0 & < 4.12
                     base.v0.14.0: Requires ocaml >= 4.07.0 & < 4.12
                     base.v0.13.2: Requires ocaml >= 4.04.2 & < 4.12
                     base.v0.13.1: Requires ocaml >= 4.04.2 & < 4.12
                     base.v0.13.0: Requires ocaml >= 4.04.2 & < 4.10.0
                     ...
               - dns-lwt -> (problem)
                   Rejected candidates:
                     dns-lwt.1.1.3: Requires dns = 1.1.3
                     dns-lwt.1.1.1: Requires dns < 2.0.0
                     dns-lwt.1.1.0: Requires dns >= 1.1.0 & < 2.0.0
                     dns-lwt.1.0.1: Requires dns >= 1.0.0 & < 2.0.0
                     dns-lwt.1.0.0: Requires dns >= 1.0.0 & < 2.0.0
               - mirage-kv -> (problem)
                   crunch 3.2.0 requires not(< 3.0.0)
                   mirage-kv-lwt 2.0.0 requires >= 2.0.0 & < 3.0.0
                   Rejected candidates:
                     mirage-kv.1.0.0: Doesn't build with dune
                     mirage-kv.3.0.1: Incompatible with restriction: >= 2.0.0 & < 3.0.0
                     mirage-kv.2.0.0: Incompatible with restriction: not(< 3.0.0)
                     mirage-kv.1.1.1: Incompatible with restriction: not(< 3.0.0)
               - mirage-stack -> (problem)
                   mirage-stack-lwt 1.4.0 requires >= 1.3.0 & < 2.0.0
                   Rejected candidates:
                     mirage-stack.1.0.0: Doesn't build with dune
                     mirage-stack.2.2.0: Incompatible with restriction: >= 1.3.0 & < 2.0.0
                     mirage-stack.2.1.0: Incompatible with restriction: >= 1.3.0 & < 2.0.0
                     mirage-stack.2.0.1: Incompatible with restriction: >= 1.3.0 & < 2.0.0
                     mirage-stack.1.4.0: Requires mirage-device >= 1.0.0 & < 2.0.0
                     ...
               - mirage-time-lwt -> (problem)
                   Rejected candidates:
                     mirage-time-lwt.1.0.0: Doesn't build with dune
                     mirage-time-lwt.1.3.0: Requires mirage-time >= 1.0.0 & < 2.0.0
                     mirage-time-lwt.1.1.0: Requires mirage-time >= 1.0.0 & < 2.0.0
               - ocaml-base-compiler -> (problem)
                   Rejected candidates:
                     ocaml-base-compiler.4.12.0~beta1: Requires ocaml = 4.12.0
                     ocaml-base-compiler.4.12.0~alpha3: Requires ocaml = 4.12.0
                     ocaml-base-compiler.4.12.0~alpha2: Requires ocaml = 4.12.0
                     ocaml-base-compiler.4.12.0~alpha1: Requires ocaml = 4.12.0
                     ocaml-base-compiler.4.11.1: Requires ocaml = 4.11.1
                     ...
               - ppxlib -> (problem)
                   ppx_cstruct 6.0.0 requires >= 0.16.0
                   Rejected candidates:
                     ppxlib.0.20.0: Requires ocaml >= 4.04.1 & < 4.13
                     ppxlib.0.19.0: Requires ocaml >= 4.04.1 & < 4.13
                     ppxlib.0.18.0: Requires ocaml >= 4.04.1 & < 4.12
                     ppxlib.0.17.0: Requires ocaml >= 4.04.1 & < 4.12
                     ppxlib.0.16.0: Requires ocaml >= 4.04.1 & < 4.12
                     ...
               - tcpip -> (problem)
                   dns-hvt zdev requires >= 5.0.0 & < 6.0.0
                   Rejected candidates:
                     tcpip.3.1.4: Doesn't build with dune
                     tcpip.3.1.3: Doesn't build with dune
                     tcpip.3.1.2: Doesn't build with dune
                     tcpip.3.1.1: Doesn't build with dune
                     tcpip.3.1.0: Doesn't build with dune
                     ...
TheLortex commented 3 years ago

I have a proof of concept that is able to improve the quality of error messages by grouping identical messages together. It's actually a patch in opam-0install-solver but opam-monorepo will be the direct beneficiary of that. That results in very compact errors messages that contain all the same amount of information.

What do you think @NathanReb @Leonidas-from-XIV ?

An example, trying to lock mirage-dns without the overlay repository:

Before

               - astring -> (problem)
                   No usable implementations:
                     astring.0.8.5: Doesn't build with dune
                     astring.0.8.4: Doesn't build with dune
                     astring.0.8.3: Doesn't build with dune
                     astring.0.8.2: Doesn't build with dune
                     astring.0.8.1: Doesn't build with dune
                     ...
               - dns -> (problem)
                   dns-lwt 1.1.3 requires = 1.1.3
                   Rejected candidates:
                     dns.1.0.1: Doesn't build with dune
                     dns.1.0.0: Doesn't build with dune
                     dns.0.20.1: Doesn't build with dune
                     dns.0.20.0: Doesn't build with dune
                     dns.0.19.1: Doesn't build with dune
                     ...
               - fmt -> (problem)
                   No usable implementations:
                     fmt.0.8.10: Doesn't build with dune
                     fmt.0.8.9: Doesn't build with dune
                     fmt.0.8.8: Doesn't build with dune
                     fmt.0.8.7: Doesn't build with dune
                     fmt.0.8.6: Doesn't build with dune
                     ...
               - mirage-device -> mirage-device.1.2.0
                   mirage-kv 2.0.0 requires >= 1.0.0 & < 2.0.0
               - mirage-flow -> mirage-flow.1.6.0
                   mirage-protocols 3.1.0 requires >= 1.2.0 & < 2.0.0
               - mirage-kv -> mirage-kv.2.0.0
                   mirage-kv-lwt 2.0.0 requires >= 2.0.0 & < 3.0.0
               - mirage-net -> mirage-net.2.0.0
                   mirage-protocols 3.1.0 requires >= 2.0.0 & < 3.0.0
               - mirage-protocols -> mirage-protocols.3.1.0
                   mirage-stack 1.4.0 requires >= 1.4.0 & < 4.0.0
               - mirage-stack -> mirage-stack.1.4.0
                   mirage-stack-lwt 1.4.0 requires >= 1.3.0 & < 2.0.0
               - mirage-time -> mirage-time.1.3.0
                   mirage-time-lwt 1.3.0 requires >= 1.0.0 & < 2.0.0
               - num -> (problem)
                   Rejected candidates:
                     num.1.4: Doesn't build with dune
                     num.1.3: Doesn't build with dune
                     num.1.2: Doesn't build with dune
                     num.1.1: Doesn't build with dune
                     num.1.0: Doesn't build with dune
                     ...
               - ocaml -> ocaml.4.13.1
                   ocaml-base-compiler 4.13.1 requires = 4.13.1
               - ocamlfind -> (problem)
                   No usable implementations:
                     ocamlfind.1.9.1: Doesn't build with dune
                     ocamlfind.1.8.1: Doesn't build with dune
                     ocamlfind.1.8.0: Doesn't build with dune
                     ocamlfind.1.7.3-1: Doesn't build with dune
                     ocamlfind.1.7.3: Doesn't build with dune
                     ...

After

               - astring -> (problem)
                   No usable implementations:
                     astring all versions: Doesn't build with dune
               - dns -> (problem)
                   dns-lwt 1.1.3 requires = 1.1.3
                   Rejected candidates:
                     dns = 0.5.0 | >= 0.6.0 & < 1.1.0: Doesn't build with dune
                     dns >= 4.0.0: Incompatible with restriction: = 1.1.3
                     dns >= 1.1.0 & < 4.0.0: Requires cstruct >= 3.0.2 & < 6.0.0
                     dns = 0.5.1: Requires cstruct >= 0.5.1 & < 0.6.0
                     dns < 0.5.0: Requires cstruct >= 0.5.0 & < 0.6.0
               - fmt -> (problem)
                   No usable implementations:
                     fmt all versions: Doesn't build with dune
               - mirage-device -> mirage-device = 1.2.0
                   mirage-kv 2.0.0 requires >= 1.0.0 & < 2.0.0
               - mirage-flow -> mirage-flow = 1.6.0
                   mirage-protocols 3.1.0 requires >= 1.2.0 & < 2.0.0
               - mirage-kv -> mirage-kv = 2.0.0
                   mirage-kv-lwt 2.0.0 requires >= 2.0.0 & < 3.0.0
               - mirage-net -> mirage-net = 2.0.0
                   mirage-protocols 3.1.0 requires >= 2.0.0 & < 3.0.0
               - mirage-protocols -> mirage-protocols = 3.1.0
                   mirage-stack 1.4.0 requires >= 1.4.0 & < 4.0.0
               - mirage-stack -> mirage-stack = 1.4.0
                   mirage-stack-lwt 1.4.0 requires >= 1.3.0 & < 2.0.0
               - mirage-time -> mirage-time = 1.3.0
                   mirage-time-lwt 1.3.0 requires >= 1.0.0 & < 2.0.0
               - num -> (problem)
                   Rejected candidates:
                     num >= 1.0: Doesn't build with dune
                     num < 1.0: Requires ocaml < 4.06.0
               - ocaml -> ocaml = 4.13.1
                   ocaml-base-compiler 4.13.1 requires = 4.13.1
               - ocamlfind -> (problem)
                   No usable implementations:
                     ocamlfind all versions: Doesn't build with dune
NathanReb commented 3 years ago

Compacting the information does look much nicer indeed! Thanks for working on this!

In particular, I assume this remove the annoying ... ellipsis that sometime cut useful piece of information!

This definitely looks like a step in the right direction.

We haven't had time to look into error messages on our end but this is on the roadmap. I think something that could be done in opam-monorepo is to prioritize things a bit, e.g. by only showing a reduced set of "problems", selecting the ones that are most relevant to the user. It might be nice if you could expose parts of this in opam-0install-solver, for example, it would probably be useful for us to re-use the code showing the condensed report for a single package/role.

Either way we'll always need a fallback when there's nothing obvious to show and so having a nicer full error report is very important.

tmattio commented 1 year ago

@TheLortex were you able to submit a patch upstream for this?