@@ -84,6 +84,33 @@ let resolve_project_pins project_pins =
8484 Pin. resolve project_pins ~scan_project
8585;;
8686
87+ module Platforms_by_message = struct
88+ module Message_map = Map. Make (struct
89+ type t = User_message.Style .t Pp .t
90+
91+ let to_dyn = Pp. to_dyn User_message.Style. to_dyn
92+ let compare = Pp. compare ~compare: User_message.Style. compare
93+ end )
94+
95+ (* Map messages to the list of platforms for which those messages are
96+ relevant. If a dependency problem has no solution on any platform, it's
97+ likely that the error from the solver will be identical across all
98+ platforms. We don't want to print the same error message once for each
99+ platform, so this type collects messages and the platforms for which they
100+ are relevant, deduplicating common messages. *)
101+ type t = Solver_env .t list Message_map .t
102+
103+ let singleton message platform : t = Message_map. singleton message [ platform ]
104+
105+ let to_list (t : t ) : (User_message.Style.t Pp.t * Solver_env.t list) list =
106+ Message_map. to_list t
107+ ;;
108+
109+ let union_all ts : t = Message_map. union_all ts ~f: (fun _ a b -> Some (a @ b))
110+ let all_platforms (t : t ) = Message_map. values t |> List. concat
111+ let all_messages (t : t ) = Message_map. keys t
112+ end
113+
87114let solve_multiple_platforms
88115 base_solver_env
89116 version_preference
@@ -117,7 +144,7 @@ let solve_multiple_platforms
117144 let solver_env = Solver_env. extend portable_solver_env platform_env in
118145 let + solver_result = solve_for_env solver_env in
119146 Result. map_error solver_result ~f: (fun (`Diagnostic_message message ) ->
120- platform_env, message))
147+ Platforms_by_message. singleton message platform_env ))
121148 in
122149 let solver_results, errors =
123150 List. partition_map results ~f: (function
@@ -126,14 +153,14 @@ let solve_multiple_platforms
126153 in
127154 match solver_results, errors with
128155 | [] , [] -> Code_error. raise " Solver did not run for any platforms." []
129- | [] , errors -> `All_error errors
156+ | [] , errors -> `All_error ( Platforms_by_message. union_all errors)
130157 | x :: xs , errors ->
131158 let merged_solver_result =
132159 List. fold_left xs ~init: x ~f: Dune_pkg.Opam_solver.Solver_result. merge
133160 in
134161 if List. is_empty errors
135162 then `All_ok merged_solver_result
136- else `Partial (merged_solver_result, errors)
163+ else `Partial (merged_solver_result, Platforms_by_message. union_all errors)
137164;;
138165
139166let summary_message
@@ -207,6 +234,23 @@ let summary_message
207234 @ maybe_unsolved_platforms_message
208235;;
209236
237+ let pp_solve_errors_by_platforms platforms_by_message =
238+ Platforms_by_message. to_list platforms_by_message
239+ |> List. map ~f: (fun (solver_error , platforms ) ->
240+ Pp. concat
241+ ~sep: Pp. cut
242+ [ Pp. nop
243+ ; Pp. box
244+ @@ Pp. text
245+ " The dependency solver failed to find a solution for the following \
246+ platforms:"
247+ ; Pp. enumerate platforms ~f: Solver_env. pp_oneline
248+ ; Pp. box @@ Pp. text " ...with this error:"
249+ ; solver_error
250+ ]
251+ |> Pp. vbox)
252+ ;;
253+
210254let solve_lock_dir
211255 workspace
212256 ~local_packages
@@ -285,14 +329,7 @@ let solve_lock_dir
285329 | `All_error messages -> Error messages
286330 | `All_ok solver_result -> Ok (solver_result, [] )
287331 | `Partial (solver_result , errors ) ->
288- Log. info
289- @@ List. map errors ~f: (fun (platform , solver_error ) ->
290- Pp. concat
291- ~sep: Pp. newline
292- [ Pp. box @@ Pp. text " Failed to find package solution for platform:"
293- ; Solver_env. pp platform
294- ; solver_error
295- ]);
332+ Log. info @@ pp_solve_errors_by_platforms errors;
296333 Ok
297334 ( solver_result
298335 , [ Pp. nop
@@ -303,8 +340,9 @@ let solve_lock_dir
303340 @@ Pp. text " No package solution was found for some requsted platforms."
304341 ; Pp. nop
305342 ; Pp. box @@ Pp. text " Platforms with no solution:"
306- ; Pp. enumerate errors ~f: (fun (platform , _ ) ->
307- Solver_env. pp_oneline platform)
343+ ; Pp. enumerate
344+ (Platforms_by_message. all_platforms errors)
345+ ~f: Solver_env. pp_oneline
308346 ; Pp. nop
309347 ; Pp. box
310348 @@ Pp. text
@@ -395,13 +433,24 @@ let solve
395433 | _ -> Error errors)
396434 >> | function
397435 | Error errors ->
398- User_error. raise
399- ([ Pp. text " Unable to solve dependencies for the following lock directories:" ]
400- @ List. concat_map errors ~f: (fun (path , messages_by_platform ) ->
401- let messages = List. map messages_by_platform ~f: snd in
402- [ Pp. textf " Lock directory %s:" (Path. to_string_maybe_quoted path)
403- ; Pp. hovbox (Pp. concat ~sep: Pp. newline messages)
404- ]))
436+ if portable_lock_dir
437+ then
438+ User_error. raise
439+ (List. concat_map errors ~f: (fun (path , errors ) ->
440+ [ Pp. box
441+ @@ Pp. textf
442+ " Unable to solve dependencies while generating lock directory: %s"
443+ (Path. to_string_maybe_quoted path)
444+ ; Pp. vbox (Pp. concat ~sep: Pp. cut (pp_solve_errors_by_platforms errors))
445+ ]))
446+ else
447+ User_error. raise
448+ ([ Pp. text " Unable to solve dependencies for the following lock directories:" ]
449+ @ List. concat_map errors ~f: (fun (path , errors ) ->
450+ let messages = Platforms_by_message. all_messages errors in
451+ [ Pp. textf " Lock directory %s:" (Path. to_string_maybe_quoted path)
452+ ; Pp. vbox (Pp. concat ~sep: Pp. cut messages)
453+ ]))
405454 | Ok write_disks_with_summaries ->
406455 let write_disk_list, summary_messages = List. split write_disks_with_summaries in
407456 List. iter summary_messages ~f: Console. print_user_message;
0 commit comments