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/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 09129c7..8130969 100644 --- a/examples/binary/dune-project +++ b/examples/binary/dune-project @@ -1,17 +1,16 @@ -(lang dune 2.0) +(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 fmt logs)) + (description "Binary that depends on a tested library") + (documentation "https://JoeBloggs.github.io/binary/") + (depends fmt logs)) 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..9d91126 100644 --- a/examples/library/dune-project +++ b/examples/library/dune-project @@ -1,17 +1,16 @@ -(lang dune 2.0) +(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 fmt logs)) + (description "Single package in `src`") + (documentation "https://JoeBloggs.github.io/library/") + (depends fmt logs)) 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)) 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..12610be 100644 --- a/lib/contents.ml +++ b/lib/contents.ml @@ -3,100 +3,132 @@ open Utils type file_printer = Config.t -> Format.formatter -> unit -module Dune_project = struct - let package c ppf = - let dependencies = - c.dependencies - |> List.append [ "alcotest" ] - |> List.sort_uniq String.compare - in - Fmt.pf ppf {|(lang dune %s) -(name %s) -(implicit_transitive_deps false) +let sexp_file_printer sexps ppf = Sexp_contents.pps ppf sexps -|} - c.versions.dune c.name; - Fmt.pf ppf - {|(generate_opam_files true) -(source (github %s/%s)) -(maintainers "%s <%s>") -(authors "%s <%s>") +let dep_alcotest = { dep_name = "alcotest"; dep_filter = Some "with-test" } -|} - 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 " ") string) - dependencies +let project_dependencies config = + config.dependencies |> List.append [ dep_alcotest ] |> List.sort_uniq compare + +module Dune_project = struct + 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 = @@ -198,6 +230,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" @@ -216,14 +251,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 = diff --git a/lib/layouts.ml b/lib/layouts.ml index 3a66692..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 @@ -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 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