From f35a2c433f99943c7c4414a65c6bbd8299be7185 Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Thu, 28 Oct 2021 19:31:26 +0200 Subject: [PATCH 1/4] Update examples --- examples/binary/.ocamlformat | 2 +- examples/binary/CONTRIBUTING.md | 2 +- examples/binary/dune-project | 2 +- examples/binary/lib/dune | 1 + examples/executable/dune-project | 2 +- examples/library/.ocamlformat | 2 +- examples/library/CONTRIBUTING.md | 2 +- examples/library/dune-project | 2 +- examples/library/src/dune | 1 + 9 files changed, 9 insertions(+), 7 deletions(-) diff --git a/examples/binary/.ocamlformat b/examples/binary/.ocamlformat index 0eac260..bc9c6ce 100644 --- a/examples/binary/.ocamlformat +++ b/examples/binary/.ocamlformat @@ -1 +1 @@ -version = 0.12 +version = 0.19.0 diff --git a/examples/binary/CONTRIBUTING.md b/examples/binary/CONTRIBUTING.md index 0ee9ff6..ef9f5e8 100644 --- a/examples/binary/CONTRIBUTING.md +++ b/examples/binary/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Setting up your working environment -binary requires OCaml 4.09.0 or higher so you will need a corresponding opam +binary requires OCaml 4.14.0 or higher so you will need a corresponding opam switch. You can install a switch with the latest OCaml version by running: ``` diff --git a/examples/binary/dune-project b/examples/binary/dune-project index 09129c7..42fd4f2 100644 --- a/examples/binary/dune-project +++ b/examples/binary/dune-project @@ -1,4 +1,4 @@ -(lang dune 2.0) +(lang dune 2.9.1) (name binary) (implicit_transitive_deps false) diff --git a/examples/binary/lib/dune b/examples/binary/lib/dune index 24976ea..b542398 100644 --- a/examples/binary/lib/dune +++ b/examples/binary/lib/dune @@ -1,3 +1,4 @@ (library (name binary) + (public_name binary) (libraries logs)) diff --git a/examples/executable/dune-project b/examples/executable/dune-project index 929c696..3aad160 100644 --- a/examples/executable/dune-project +++ b/examples/executable/dune-project @@ -1 +1 @@ -(lang dune 2.0) +(lang dune 2.9.1) diff --git a/examples/library/.ocamlformat b/examples/library/.ocamlformat index 0eac260..bc9c6ce 100644 --- a/examples/library/.ocamlformat +++ b/examples/library/.ocamlformat @@ -1 +1 @@ -version = 0.12 +version = 0.19.0 diff --git a/examples/library/CONTRIBUTING.md b/examples/library/CONTRIBUTING.md index f5c8493..21ab694 100644 --- a/examples/library/CONTRIBUTING.md +++ b/examples/library/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Setting up your working environment -library requires OCaml 4.09.0 or higher so you will need a corresponding opam +library requires OCaml 4.14.0 or higher so you will need a corresponding opam switch. You can install a switch with the latest OCaml version by running: ``` diff --git a/examples/library/dune-project b/examples/library/dune-project index 8c32354..9b7e3e4 100644 --- a/examples/library/dune-project +++ b/examples/library/dune-project @@ -1,4 +1,4 @@ -(lang dune 2.0) +(lang dune 2.9.1) (name library) (implicit_transitive_deps false) diff --git a/examples/library/src/dune b/examples/library/src/dune index 15c6ac2..02893e0 100644 --- a/examples/library/src/dune +++ b/examples/library/src/dune @@ -1,3 +1,4 @@ (library (name library) + (public_name library) (libraries logs)) From 36b9e41165b2733f55fa2f8c09e950feefdfc07e Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Thu, 28 Oct 2021 19:18:34 +0200 Subject: [PATCH 2/4] dune-project: Add the :with-test filter on alcotest --- examples/binary/dune-project | 2 +- examples/library/dune-project | 2 +- lib/config.ml | 7 ++++++- lib/contents.ml | 13 +++++++++---- lib/layouts.ml | 2 +- lib/oskel.ml | 5 +++++ 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/examples/binary/dune-project b/examples/binary/dune-project index 42fd4f2..7cfa173 100644 --- a/examples/binary/dune-project +++ b/examples/binary/dune-project @@ -14,4 +14,4 @@ Binary that depends on a tested library ") (documentation https://JoeBloggs.github.io/binary/) - (depends alcotest fmt logs)) + (depends (alcotest :with-test) fmt logs)) diff --git a/examples/library/dune-project b/examples/library/dune-project index 9b7e3e4..d019d73 100644 --- a/examples/library/dune-project +++ b/examples/library/dune-project @@ -14,4 +14,4 @@ Single package in `src` ") (documentation https://JoeBloggs.github.io/library/) - (depends alcotest fmt logs)) + (depends (alcotest :with-test) fmt logs)) diff --git a/lib/config.ml b/lib/config.ml index e704661..1f4d515 100644 --- a/lib/config.ml +++ b/lib/config.ml @@ -7,6 +7,11 @@ type versions = { ocamlformat : string; } +type dependency = { + dep_name : string; + dep_filter : string option; (** For example, ["with-test"]. *) +} + type t = { name : string; project_synopsis : string; @@ -15,7 +20,7 @@ type t = { github_organisation : string; initial_version : string; license : License.t; - dependencies : string list; + dependencies : dependency list; versions : versions; ocamlformat_options : (string * string) list; current_year : int; diff --git a/lib/contents.ml b/lib/contents.ml index d803162..699f9e2 100644 --- a/lib/contents.ml +++ b/lib/contents.ml @@ -3,12 +3,17 @@ open Utils type file_printer = Config.t -> Format.formatter -> unit +let dep_alcotest = { dep_name = "alcotest"; dep_filter = Some "with-test" } + module Dune_project = struct + let pp_depend ppf dep = + match dep.dep_filter with + | None -> Fmt.string ppf dep.dep_name + | Some filter -> Fmt.pf ppf "(%s :%s)" dep.dep_name filter + let package c ppf = let dependencies = - c.dependencies - |> List.append [ "alcotest" ] - |> List.sort_uniq String.compare + c.dependencies |> List.append [ dep_alcotest ] |> List.sort_uniq compare in Fmt.pf ppf {|(lang dune %s) (name %s) @@ -35,7 +40,7 @@ module Dune_project = struct (documentation https://%s.github.io/%s/) (depends %a))|} c.name c.project_synopsis c.project_synopsis c.github_organisation c.name - Fmt.(list ~sep:(const string " ") string) + Fmt.(list ~sep:(const string " ") pp_depend) dependencies let minimal config ppf = Fmt.pf ppf "(lang dune %s)" config.versions.dune diff --git a/lib/layouts.ml b/lib/layouts.ml index 3a66692..0e5359c 100644 --- a/lib/layouts.ml +++ b/lib/layouts.ml @@ -152,7 +152,7 @@ let binary = { layout = binary; post_init = [] } let executable (config : Config.t) = let name = config.name in let toplevel_file = Utils.Utils_naming.file_of_project name in - let libraries = config.dependencies in + let libraries = List.map (fun d -> d.Config.dep_name) config.dependencies in let open Contents in Folder ( config.name, diff --git a/lib/oskel.ml b/lib/oskel.ml index f86ca00..913157d 100644 --- a/lib/oskel.ml +++ b/lib/oskel.ml @@ -180,6 +180,11 @@ let run ~project_kind ?name ?project_synopsis ~maintainer_fullname if !progress_bar_active then Printf.printf "\r\n%!"; return ()) and+ c = config >* progress in + let dependencies = + List.map + (fun dep_name -> { Config.dep_name; dep_filter = None }) + dependencies + in let versions = versions |> function From f99093f7a8d7bee34638681e3a2a323c4173f5e2 Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Thu, 28 Oct 2021 19:24:26 +0200 Subject: [PATCH 3/4] Opam: Generate the same dependencies as Dune --- lib/contents.ml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/contents.ml b/lib/contents.ml index 699f9e2..85adb16 100644 --- a/lib/contents.ml +++ b/lib/contents.ml @@ -5,6 +5,9 @@ type file_printer = Config.t -> Format.formatter -> unit let dep_alcotest = { dep_name = "alcotest"; dep_filter = Some "with-test" } +let project_dependencies config = + config.dependencies |> List.append [ dep_alcotest ] |> List.sort_uniq compare + module Dune_project = struct let pp_depend ppf dep = match dep.dep_filter with @@ -12,9 +15,6 @@ module Dune_project = struct | Some filter -> Fmt.pf ppf "(%s :%s)" dep.dep_name filter let package c ppf = - let dependencies = - c.dependencies |> List.append [ dep_alcotest ] |> List.sort_uniq compare - in Fmt.pf ppf {|(lang dune %s) (name %s) (implicit_transitive_deps false) @@ -41,7 +41,7 @@ module Dune_project = struct (depends %a))|} c.name c.project_synopsis c.project_synopsis c.github_organisation c.name Fmt.(list ~sep:(const string " ") pp_depend) - dependencies + (project_dependencies c) let minimal config ppf = Fmt.pf ppf "(lang dune %s)" config.versions.dune end @@ -203,6 +203,9 @@ let opam config ppf = Fmt.pf ppf "git+https://github.com/%s/%s.git" config.github_organisation config.name in + let pp_depend ppf dep = + Fmt.pf ppf "%S%a" dep.dep_name Fmt.(option (fmt " {%s}")) dep.dep_filter + in Fmt.pf ppf {|opam-version: "%s" maintainer: "%s" @@ -221,14 +224,14 @@ build: [ depends: [ "ocaml" {>= "%s"} "dune" {build & >= "%s"} - "fmt" - "logs" - "alcotest" {with-test} + @[%a@] ] synopsis: "%s"|} config.versions.opam config.maintainer_fullname config.maintainer_fullname Config.pp_license config.license pp_homepage config pp_bugreports config pp_devrepo config config.versions.ocaml config.versions.dune + Fmt.(list ~sep:cut pp_depend) + (project_dependencies config) config.project_synopsis let test_main_ml config ppf = From e5e5790afc03bee408c29dd972a77462c6d06e7f Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Thu, 28 Oct 2021 20:44:51 +0200 Subject: [PATCH 4/4] Add an abstraction to format dune files --- examples/binary/bin/dune | 1 - examples/binary/dune-project | 13 ++- examples/library/dune-project | 13 ++- lib/contents.ml | 185 +++++++++++++++++++--------------- lib/layouts.ml | 2 +- lib/sexp_contents.ml | 24 +++++ lib/sexp_contents.mli | 21 ++++ 7 files changed, 164 insertions(+), 95 deletions(-) create mode 100644 lib/sexp_contents.ml create mode 100644 lib/sexp_contents.mli diff --git a/examples/binary/bin/dune b/examples/binary/bin/dune index b9ab10f..3bf9319 100644 --- a/examples/binary/bin/dune +++ b/examples/binary/bin/dune @@ -1,7 +1,6 @@ (executable (name main) (libraries binary cmdliner fmt fmt.cli fmt.tty logs logs.cli logs.fmt)) - (install (section bin) (files diff --git a/examples/binary/dune-project b/examples/binary/dune-project index 7cfa173..8130969 100644 --- a/examples/binary/dune-project +++ b/examples/binary/dune-project @@ -1,17 +1,16 @@ (lang dune 2.9.1) (name binary) (implicit_transitive_deps false) - (generate_opam_files true) -(source (github JoeBloggs/binary)) +(source + (github JoeBloggs/binary)) (maintainers "Joe Bloggs ") + (authors "Joe Bloggs ") (package (name binary) (synopsis "Binary that depends on a tested library") - (description "\ -Binary that depends on a tested library -") - (documentation https://JoeBloggs.github.io/binary/) - (depends (alcotest :with-test) fmt logs)) + (description "Binary that depends on a tested library") + (documentation "https://JoeBloggs.github.io/binary/") + (depends fmt logs)) diff --git a/examples/library/dune-project b/examples/library/dune-project index d019d73..9d91126 100644 --- a/examples/library/dune-project +++ b/examples/library/dune-project @@ -1,17 +1,16 @@ (lang dune 2.9.1) (name library) (implicit_transitive_deps false) - (generate_opam_files true) -(source (github JoeBloggs/library)) +(source + (github JoeBloggs/library)) (maintainers "Joe Bloggs ") + (authors "Joe Bloggs ") (package (name library) (synopsis "Single package in `src`") - (description "\ -Single package in `src` -") - (documentation https://JoeBloggs.github.io/library/) - (depends (alcotest :with-test) fmt logs)) + (description "Single package in `src`") + (documentation "https://JoeBloggs.github.io/library/") + (depends fmt logs)) diff --git a/lib/contents.ml b/lib/contents.ml index 85adb16..12610be 100644 --- a/lib/contents.ml +++ b/lib/contents.ml @@ -3,105 +3,132 @@ open Utils type file_printer = Config.t -> Format.formatter -> unit +let sexp_file_printer sexps ppf = Sexp_contents.pps ppf sexps + let dep_alcotest = { dep_name = "alcotest"; dep_filter = Some "with-test" } let project_dependencies config = config.dependencies |> List.append [ dep_alcotest ] |> List.sort_uniq compare module Dune_project = struct - let pp_depend ppf dep = - match dep.dep_filter with - | None -> Fmt.string ppf dep.dep_name - | Some filter -> Fmt.pf ppf "(%s :%s)" dep.dep_name filter - - let package c ppf = - Fmt.pf ppf {|(lang dune %s) -(name %s) -(implicit_transitive_deps false) - -|} - c.versions.dune c.name; - Fmt.pf ppf - {|(generate_opam_files true) -(source (github %s/%s)) -(maintainers "%s <%s>") -(authors "%s <%s>") - -|} - c.github_organisation c.name c.maintainer_fullname c.maintainer_email - c.maintainer_fullname c.maintainer_email; - Fmt.pf ppf - {|(package - (name %s) - (synopsis "%s") - (description "\ -%s -") - (documentation https://%s.github.io/%s/) - (depends %a))|} - c.name c.project_synopsis c.project_synopsis c.github_organisation c.name - Fmt.(list ~sep:(const string " ") pp_depend) - (project_dependencies c) + let package c = + let open Sexp_contents in + let author_contact = + quoted (Fmt.str "%s <%s>" c.maintainer_fullname c.maintainer_email) + in + let depend dep = + let name = atom dep.dep_name in + match dep.dep_filter with + | Some filter -> list [ name; atom (Fmt.str ":%s" filter) ] + | None -> name + in + sexp_file_printer + [ + atoms [ "lang"; "dune"; c.versions.dune ]; + atoms [ "name"; c.name ]; + atoms [ "implicit_transitive_deps"; "false" ]; + atoms [ "generate_opam_files"; "true" ]; + field "source" + [ field "github" [ atom (Fmt.str "%s/%s" c.github_organisation c.name) ] ]; + field "maintainers" [ author_contact ]; + field "authors" [ author_contact ]; + field "package" + [ + field "name" [ atom c.name ]; + field "synopsis" [ quoted c.project_synopsis ]; + field "description" [ quoted c.project_synopsis ]; + field "documentation" + [ quoted (Fmt.str "https://%s.github.io/%s/" c.github_organisation c.name) ]; + field "depends" (List.map depend c.dependencies); + ]; + ] let minimal config ppf = Fmt.pf ppf "(lang dune %s)" config.versions.dune end module Dune = struct - let library { name; _ } ppf = - let file = Utils_naming.file_of_project name in - Fmt.pf ppf {|(library - (name %s) - (public_name %s) - (libraries logs))|} file - name - - let pp_libraries ppf deps = - match deps with - | [] -> () - | _ :: _ -> - let open Fmt in - pf ppf "@,(libraries %a)" (list ~sep:(const string " ") string) deps - - let executable ~name ?(libraries = []) ppf = - let file = Utils_naming.file_of_project name in - Fmt.pf ppf "@[(executable@,(name %s)%a)@]" file pp_libraries libraries + open Sexp_contents - let install ~exe_name ~bin_name ppf = - Fmt.pf ppf - "@[(install@,(section bin)@,@[(files@,(%s.exe as %s))@])@]" - exe_name bin_name + let field_libraries = function + | [] -> [] + | _ :: _ as deps -> [ field "libraries" (List.map atom deps) ] - let test config ppf = + let library { name; _ } = + let file = Utils_naming.file_of_project name in + sexp_file_printer + [ + field "library" + ( [ field "name" [ atom file ]; field "public_name" [ atom name ] ] + @ field_libraries [ "logs" ] ); + ] + + let executable ~name ?(libraries = []) = + let file = Utils_naming.file_of_project name in + sexp_file_printer + [ + field "executable" + ([ field "name" [ atom file ] ] @ field_libraries libraries); + ] + + let install ~exe_name ~bin_name = + sexp_file_printer + [ + field "install" + [ + field "section" [ atom "bin" ]; + field "files" + [ list [ atom (Fmt.str "%s.exe" exe_name); atom "as"; atom bin_name ] ]; + ]; + ] + + let test config = let dependencies = [ config.name; "alcotest"; "logs"; "logs.fmt" ] |> List.sort String.compare in - Fmt.pf ppf "@[(test@,(name main)%a)@]" pp_libraries dependencies - - let ppx_deriver { name = n; _ } ppf = - Fmt.pf ppf - {|(library - (public_name %s) - (kind ppx_deriver) - (libraries %s_lib ppxlib))|} - n n + sexp_file_printer + [ + field "test" + ([ field "name" [ atom "main" ] ] @ field_libraries dependencies); + ] + + let ppx_deriver { name = n; _ } = + sexp_file_printer + [ + field "library" + ( [ + field "public_name" [ atom n ]; field "kind" [ atom "ppx_deriver" ]; + ] + @ field_libraries [ n ^ "_lib"; "ppxlib" ] ); + ] let ppx_deriver_lib _ _ppf = () - let generate_help { name = n; _ } ppf = - Fmt.pf ppf - {|(rule - (targets %s-help.txt.gen) - (action - (with-stdout-to - %%{targets} - (run %s --help=plain)))) - -(rule - (alias runtest) - (action - (diff %s-help.txt %s-help.txt.gen)))|} - n n n n + let generate_help { name = n; _ } = + sexp_file_printer + [ + field "rule" + [ + field "targets" [ atom (Fmt.str "%s-help.txt.gen" n) ]; + field "action" + [ + field "with-stdout-to" + [ + atom "%{targets}"; + field "run" [ atom n; atom "--help=plain" ]; + ]; + ]; + ]; + field "rule" + [ + field "alias" [ atom "runtest" ]; + field "action" + [ + field "diff" + [ atom (Fmt.str "%s-help.txt" n); atom (Fmt.str "%s-help.txt.gen" n) ]; + ]; + ]; + ] end let hello_world_bin _config ppf = diff --git a/lib/layouts.ml b/lib/layouts.ml index 0e5359c..5faee7d 100644 --- a/lib/layouts.ml +++ b/lib/layouts.ml @@ -105,7 +105,7 @@ let binary (config : Config.t) = |> List.sort String.compare in Dune.executable ~name:exe_name ~libraries ppf; - Fmt.pf ppf "\n"; + Fmt.pf ppf "@\n"; Dune.install ~exe_name ~bin_name:config.name ppf in Folder diff --git a/lib/sexp_contents.ml b/lib/sexp_contents.ml new file mode 100644 index 0000000..52147c7 --- /dev/null +++ b/lib/sexp_contents.ml @@ -0,0 +1,24 @@ +type t = Atom of string | Quoted of string | List of t list + +let atom s = Atom s + +let quoted s = Quoted s + +let list ts = List ts + +let atoms ss = List (List.map (fun s -> Atom s) ss) + +let field name arguments = List (Atom name :: arguments) + +open Fmt + +let only_atoms = + List.for_all (function Atom _ | Quoted _ -> true | List _ -> false) + +let rec pp ppf = function + | Atom s -> string ppf s + | Quoted s -> pf ppf "%S" s + | List ts when only_atoms ts -> pf ppf "(@[%a)@]" (list ~sep:sp pp) ts + | List ts -> pf ppf "(@[%a)@]" (list ~sep:sp pp) ts + +let pps = list ~sep:(any "@,@\n") pp diff --git a/lib/sexp_contents.mli b/lib/sexp_contents.mli new file mode 100644 index 0000000..bde2196 --- /dev/null +++ b/lib/sexp_contents.mli @@ -0,0 +1,21 @@ +(** Pretty-print sexps. *) + +type t + +val atom : string -> t +(** Never quoted. *) + +val quoted : string -> t +(** Always quoted. *) + +val list : t list -> t + +val atoms : string list -> t +(** A list containing atoms. *) + +val field : string -> t list -> t +(** [(name arguments)] *) + +val pp : t Fmt.t + +val pps : t list Fmt.t