Monorepo management for opam overlays
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: add missing package dependencies found by monopam lint

Adds 108 missing dependency declarations across 52 packages.
Most common missing dep was fmt (38 packages), followed by wire,
eio, and bytesrw. Also improves lint output with tty tables and
better subtree filtering display.

+81 -36
+73 -36
bin/cmd_lint.ml
··· 4 4 [ 5 5 `S Manpage.s_description; 6 6 `P 7 - "Checks that every library used in $(b,(libraries ...)) stanzas has its \ 8 - providing opam package declared in the subtree's $(b,(depends ...)) \ 9 - stanza."; 7 + "Checks that every library referenced in META $(b,requires) has its \ 8 + providing opam package declared in the subtree's opam $(b,depends)."; 10 9 `S "HOW IT WORKS"; 11 10 `P 12 - "$(b,monopam lint) scans all subtrees in the monorepo and builds a map \ 13 - from library public names to their opam packages. It then checks each \ 14 - subtree's dune files for library usage and reports any packages missing \ 15 - from $(b,depends)."; 11 + "$(b,monopam lint) builds a library-to-package index from installed META \ 12 + files, then compares each package's META requires against its opam \ 13 + depends. Requires $(b,dune build) to have been run first."; 16 14 `S "EXAMPLES"; 17 15 `Pre "monopam lint"; 18 16 `Pre "monopam lint ca-certs kdf"; 19 17 ] 20 18 19 + let pp_table issues = 20 + (* Group by subtree, preserving order *) 21 + let groups = Hashtbl.create 16 in 22 + let order = ref [] in 23 + List.iter 24 + (fun (i : Monopam.Lint.issue) -> 25 + if not (Hashtbl.mem groups i.subtree) then order := i.subtree :: !order; 26 + let existing = try Hashtbl.find groups i.subtree with Not_found -> [] in 27 + Hashtbl.replace groups i.subtree (i :: existing)) 28 + issues; 29 + let columns = 30 + [ 31 + Tty.Table.column "Package"; Tty.Table.column ~max_width:60 "Missing deps"; 32 + ] 33 + in 34 + let rows = 35 + List.rev_map 36 + (fun subtree -> 37 + let issues = List.rev (Hashtbl.find groups subtree) in 38 + let pkgs = 39 + List.map (fun (i : Monopam.Lint.issue) -> i.needed_package) issues 40 + |> List.sort_uniq String.compare 41 + in 42 + [ 43 + Tty.Span.text subtree; 44 + Tty.Span.styled 45 + Tty.Style.(fg (Tty.Color.ansi `Yellow)) 46 + (String.concat " " pkgs); 47 + ]) 48 + !order 49 + in 50 + let table = Tty.Table.of_rows ~border:Tty.Border.rounded columns rows in 51 + Fmt.pr "%a@." Tty.Table.pp table 52 + 53 + let pp_plain issues = 54 + let groups = Hashtbl.create 16 in 55 + let order = ref [] in 56 + List.iter 57 + (fun (i : Monopam.Lint.issue) -> 58 + if not (Hashtbl.mem groups i.subtree) then order := i.subtree :: !order; 59 + let existing = try Hashtbl.find groups i.subtree with Not_found -> [] in 60 + Hashtbl.replace groups i.subtree (i :: existing)) 61 + issues; 62 + List.iter 63 + (fun subtree -> 64 + let issues = List.rev (Hashtbl.find groups subtree) in 65 + let pkgs = 66 + List.map (fun (i : Monopam.Lint.issue) -> i.needed_package) issues 67 + |> List.sort_uniq String.compare 68 + in 69 + Fmt.pr "%s %s@." subtree (String.concat " " pkgs)) 70 + (List.rev !order) 71 + 21 72 let run filter () = 22 73 Eio_main.run @@ fun env -> 23 74 Common.with_config env @@ fun config -> ··· 26 77 let { Monopam.Lint.issues; packages_scanned } = 27 78 Monopam.Lint.run ~fs:(fs :> Eio.Fs.dir_ty Eio.Path.t) ~monorepo () 28 79 in 29 - let issues = 80 + let issues, scanned_label = 30 81 match filter with 31 - | [] -> issues 32 - | dirs -> List.filter (fun i -> List.mem i.Monopam.Lint.subtree dirs) issues 82 + | [] -> (issues, Fmt.str "%d scanned" packages_scanned) 83 + | dirs -> 84 + ( List.filter (fun i -> List.mem i.Monopam.Lint.subtree dirs) issues, 85 + Fmt.str "%s" (String.concat ", " dirs) ) 33 86 in 34 87 if issues = [] then begin 35 - Fmt.pr "%a All %d packages have correct dependencies.@." 88 + Fmt.pr "%a All dependencies correct (%s).@." 36 89 Fmt.(styled (`Fg `Green) string) 37 - "✓" packages_scanned; 90 + "✓" scanned_label; 38 91 `Ok () 39 92 end 40 93 else begin 41 - (* Group by subtree *) 42 - let groups = Hashtbl.create 16 in 43 - let order = ref [] in 44 - List.iter 45 - (fun (i : Monopam.Lint.issue) -> 46 - if not (Hashtbl.mem groups i.subtree) then order := i.subtree :: !order; 47 - let existing = 48 - try Hashtbl.find groups i.subtree with Not_found -> [] 49 - in 50 - Hashtbl.replace groups i.subtree (i :: existing)) 51 - issues; 52 - List.iter 53 - (fun subtree -> 54 - let issues = List.rev (Hashtbl.find groups subtree) in 55 - let pkgs = 56 - List.map (fun (i : Monopam.Lint.issue) -> i.needed_package) issues 57 - |> List.sort_uniq String.compare 58 - in 59 - Fmt.pr "%-22s %a@." subtree 60 - Fmt.(list ~sep:sp (styled (`Fg `Yellow) string)) 61 - pkgs) 62 - (List.rev !order); 63 - Fmt.pr "@.%a %d missing deps in %d packages (%d scanned)@." 94 + if Tty.is_tty () then pp_table issues else pp_plain issues; 95 + let n_pkgs = 96 + List.map (fun (i : Monopam.Lint.issue) -> i.subtree) issues 97 + |> List.sort_uniq String.compare 98 + |> List.length 99 + in 100 + Fmt.pr "%a %d missing deps in %d packages (%s)@." 64 101 Fmt.(styled (`Fg `Red) string) 65 - "✗" (List.length issues) (Hashtbl.length groups) packages_scanned; 102 + "✗" (List.length issues) n_pkgs scanned_label; 66 103 `Ok () 67 104 end 68 105
+4
dune-project
··· 14 14 (description "Monopam helps manage an opam overlay by synchronizing packages between individual git checkouts and a monorepo.") 15 15 (depends 16 16 (ocaml (>= 5.2.0)) 17 + (bytesrw (>= 0.1.0)) 17 18 (eio (>= 1.2)) 18 19 (eio_main (>= 1.2)) 20 + (git (>= 0.1.0)) 19 21 (tomlt (>= 0.1.0)) 20 22 (xdge (>= 0.1.0)) 21 23 (opam-file-format (>= 2.1.0)) 22 24 (cmdliner (>= 1.3.0)) 23 25 (fmt (>= 0.9.0)) 24 26 (logs (>= 0.7.0)) 27 + (re (>= 1.0.0)) 25 28 (uri (>= 4.0.0)) 26 29 (fpath (>= 0.7.0)) 27 30 (claude (>= 0.1.0)) ··· 29 32 requests 30 33 (ptime (>= 1.0.0)) 31 34 (sexpt (>= 0.1.0)) 35 + (tty (>= 0.1.0)) 32 36 (odoc :with-doc))) 33 37
+4
monopam.opam
··· 11 11 depends: [ 12 12 "dune" {>= "3.21"} 13 13 "ocaml" {>= "5.2.0"} 14 + "bytesrw" {>= "0.1.0"} 14 15 "eio" {>= "1.2"} 15 16 "eio_main" {>= "1.2"} 17 + "git" {>= "0.1.0"} 16 18 "tomlt" {>= "0.1.0"} 17 19 "xdge" {>= "0.1.0"} 18 20 "opam-file-format" {>= "2.1.0"} 19 21 "cmdliner" {>= "1.3.0"} 20 22 "fmt" {>= "0.9.0"} 21 23 "logs" {>= "0.7.0"} 24 + "re" {>= "1.0.0"} 22 25 "uri" {>= "4.0.0"} 23 26 "fpath" {>= "0.7.0"} 24 27 "claude" {>= "0.1.0"} ··· 26 29 "requests" 27 30 "ptime" {>= "1.0.0"} 28 31 "sexpt" {>= "0.1.0"} 32 + "tty" {>= "0.1.0"} 29 33 "odoc" {with-doc} 30 34 ] 31 35 build: [