Skip to content

Commit

Permalink
check if the dune constraint matches the dune-project file
Browse files Browse the repository at this point in the history
  • Loading branch information
moyodiallo committed Sep 7, 2023
1 parent 895275e commit 86ba28c
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 5 deletions.
81 changes: 81 additions & 0 deletions dune_constraints.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
(* This source code is comming from https://github.com/ocurrent/opam-repo-ci/blob/master/lib/lint.ml
* with a slight modification *)

type error =
| DuneConstraintMissing
| DuneIsBuild
| BadDuneConstraint of string * string

let is_dune name =
OpamPackage.Name.equal name (OpamPackage.Name.of_string "dune")

let get_dune_constraint opam =
let get_max = function
| None, None -> None
| Some x, None -> Some x
| None, Some x -> Some x
| Some x, Some y when OpamVersionCompare.compare x y >= 0 -> Some x
| Some _, Some y -> Some y
in
let get_min = function
| None, None | Some _, None | None, Some _ -> None
| Some x, Some y when OpamVersionCompare.compare x y >= 0 -> Some y
| Some x, Some _ -> Some x
in
let is_build = ref false in
let rec get_lower_bound = function
| OpamFormula.Atom (OpamTypes.Constraint ((`Gt | `Geq), OpamTypes.FString version)) -> Some version
| Atom (Filter (FIdent (_, var, _))) when String.equal (OpamVariable.to_string var) "build" -> is_build := true; None (* TODO: remove this hack *)
| Empty | Atom (Filter _) | Atom (Constraint _) -> None
| Block x -> get_lower_bound x
| And (x, y) -> get_max (get_lower_bound x, get_lower_bound y)
| Or (x, y) -> get_min (get_lower_bound x, get_lower_bound y)
in
let rec aux = function
| OpamFormula.Atom (pkg, constr) ->
if is_dune pkg then
let v = get_lower_bound constr in
Some (Option.value ~default:"1.0" v)
else
None
| Empty -> None
| Block x -> aux x
| And (x, y) -> get_max (aux x, aux y)
| Or (x, y) -> get_min (aux x, aux y)
in
(!is_build, aux opam.OpamFile.OPAM.depends)

let check_dune_constraints ~errors ~dune_version pkg_name opam =
let is_build, dune_constraint = get_dune_constraint opam in
let errors =
match dune_constraint with
| None ->
if is_dune pkg_name then
errors
else
(pkg_name, DuneConstraintMissing) :: errors
| Some dep ->
if OpamVersionCompare.compare dep dune_version >= 0 then
errors
else
(pkg_name, BadDuneConstraint (dep, dune_version)) :: errors
in
if is_build then (pkg_name, DuneIsBuild) :: errors else errors

let msg_of_errors =
List.iter (fun (package, err) ->
let pkg = OpamPackage.Name.to_string package in
match err with
| DuneConstraintMissing ->
Fmt.epr "Warning in %s: The package has a dune-project file but no explicit dependency on dune was found." pkg
| DuneIsBuild ->
Fmt.epr "Warning in %s: The package tagged dune as a build dependency. \
Due to a bug in dune (https://github.com/ocaml/dune/issues/2147) this should never be the case. \
Please remove the {build} tag from its filter."
pkg
| BadDuneConstraint (dep, ver) ->
Fmt.failwith
"Error in %s: Your dune-project file indicates that this package requires at least dune %s \
but your opam file only requires dune >= %s. Please check which requirement is the right one, and fix the other."
pkg ver dep
)
8 changes: 8 additions & 0 deletions dune_project.ml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ let packages t =
|> List.to_seq
|> Libraries.of_seq

let version t =
List.find_map (function
| Sexp.List [Atom "lang"; Atom "dune"; Atom version] -> Some version
| _ -> None) t
|> function
| None -> Fmt.failwith "dune-project file without `(lang dune _)` stanza"
| Some version -> version

let dune_format dune =
Bos.OS.Cmd.(in_string dune |> run_io Bos.Cmd.(v "dune" % "format-dune-file") |> out_string)
|> Bos.OS.Cmd.success
Expand Down
2 changes: 2 additions & 0 deletions dune_project.mli
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ val write_project_file : t -> unit

val packages : t -> string Paths.t

val version : t -> string

module Deps : sig
type t = Dir_set.t Libraries.t
(** The set of OCamlfind libraries needed, each with the directories needing it. *)
Expand Down
15 changes: 10 additions & 5 deletions main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ let () =
)
| x -> Fmt.epr "WARNING: bad sexp from opam config env: %a@." Sexplib.Sexp.pp_hum x

let get_libraries ~pkg ~target =
Dune_project.Deps.get_external_lib_deps ~pkg ~target
|> fun libs ->
if String.equal pkg "dune" then libs
else Libraries.add "dune" Dir_set.empty libs (* We always need dune *)
let get_libraries ~pkg ~target = Dune_project.Deps.get_external_lib_deps ~pkg ~target

let to_opam ~index lib =
match Astring.String.take ~sat:((<>) '.') lib with
Expand Down Expand Up @@ -210,6 +206,15 @@ let main force dir =
exit 1
)
);
let dune_version = Dune_project.version project in
get_opam_files ()
|> Paths.to_seq
|> List.of_seq
|> List.map (fun (path, opam) ->
let pkg_name = (OpamPackage.Name.of_string (Filename.chop_suffix path ".opam")) in
Dune_constraints.check_dune_constraints ~errors:[] ~dune_version pkg_name opam)
|> List.flatten
|> Dune_constraints.msg_of_errors;
if not (Paths.is_empty stale_files) then exit 1

open Cmdliner
Expand Down

0 comments on commit 86ba28c

Please sign in to comment.