Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dune init proj subcommand to initialize project skeletons #2185

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
1.10.0 (04/06/2019)
-------------------

- Add `$ dune init project` subcommand to create project boilerplate according
to a common template. (#2185, fixes #159, @shonfeder)

- Restricted the set of variables available for expansion in the destination
filename of `install` stanza to simplify implementation and avoid dependency
cycles. (#2073, @aalekseyev, @diml)
Expand Down
96 changes: 75 additions & 21 deletions bin/init.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ open Import
open Dune.Dune_init

(* TODO(shonfeder): Remove when nested subcommands are available *)
let validate_component_options kind ~unsupported_options =
let validate_component_options kind unsupported_options =
let report_invalid_option = function
| _, false -> () (* The option wasn't supplied *)
| option_name, true ->
Expand All @@ -16,10 +16,12 @@ let validate_component_options kind ~unsupported_options =
let doc = "Initialize dune components"
let man =
[ `S "DESCRIPTION"
; `P {|$(b,dune init {lib,exe,test} NAME [PATH]) initialize a new dune
component of the specified kind, named $(b,NAME), with fields
determined by the supplied options.|}
; `P {|If the optional $(b,PATH) is provided, the project will be created
; `P {|$(b,dune init {library,executable,test,project} NAME [PATH]) initialize
a new dune component of the specified kind, named $(b,NAME), with
fields determined by the supplied options.|}
; `P {|Any prefix of the component kinds can be supplied, e.g., $(b,dune init
proj myproject).|}
; `P {|If the optional $(b,PATH) is provided, the component will be created
there. Otherwise, it is created in the current working directory.|}
; `P {|The command can be used to add stanzas to existing dune files as
well as for creating new dune files and basic component templates.|}
Expand Down Expand Up @@ -81,32 +83,84 @@ let term =
& info ["inline-tests"]
~docv:"USE_INLINE_TESTS"
~doc:"Whether to use inline tests. \
Only applicable for lib components.")
Only applicable for $(b,library) and $(b,project) components.")
and+ template =
Arg.(value
& opt
(some (enum Component.Options.Project.Template.commands))
None
& info ["kind"]
~docv:"PROJECT_KIND"
~doc:"The kind of project to initialize. \
Valid options are $(b,e[xecutable]) or $(b,l[ibrary]). \
Defaults to $(b,executable). \
Only applicable for $(b,project) components.")
and+ pkg =
Arg.(value
& opt
(some (enum Component.Options.Project.Pkg.commands))
None
& info ["pkg"]
~docv:"PACKAGE_MANAGER"
~doc:"Which package manager to use. \
Valid options are $(b,o[pam]) or $(b,e[sy]). \
Defaults to $(b,opam). \
Only applicable for $(b,project) components.")

in

validate_component_name name;

Common.set_common common_term ~targets:[];

let open Component in
let context = Init_context.make path in
let common : Options.common = { name; libraries; pps } in
let common : Options.Common.t = { name; libraries; pps } in

let given_public = Option.is_some public in
let given_pkg = Option.is_some pkg in
let given_template = Option.is_some template in

let pkg = Option.value pkg ~default:Options.Project.Pkg.Opam in
let template = Option.value template ~default:Options.Project.Template.Exec in

(* for the [kind] of initialization *)
let check_unsupported_options = validate_component_options kind in

begin match kind with
| Kind.Library ->
init @@ Library { context; common; options = {public; inline_tests} }
| Kind.Executable ->
let unsupported_options =
["inline-tests", inline_tests]
in
validate_component_options kind ~unsupported_options;
init @@ Executable { context; common; options = {public} }
check_unsupported_options [ "inline-tests", inline_tests
; "kind", given_template
; "pkg", given_pkg
];
init @@ Executable { context
; common
; options = {public}
}
| Kind.Library ->
check_unsupported_options [ "kind", given_template
; "pkg", given_pkg
];
init @@ Library { context
; common
; options = {public; inline_tests}
}
| Kind.Project ->
check_unsupported_options ["public", given_public
];
init @@ Project { context
; common
; options = { inline_tests; pkg; template }
}
| Kind.Test ->
let unsupported_options =
[ "public", given_public
; "inline-tests", inline_tests]
in
validate_component_options kind ~unsupported_options;
init @@ Test { context; common; options = () }
check_unsupported_options [ "public", given_public
; "inline-tests", inline_tests
; "kind", given_template
; "pkg", given_pkg
];
init @@ Test { context
; common
; options = ()
}
end;

print_completion kind name
Expand Down
35 changes: 29 additions & 6 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,32 @@ change.

Dune's ``init`` subcommand provides limited support for generating dune file
stanzas and folder structures to define components. ``dune init`` can be used to
quickly add new libraries, tests, or executables without having to manually edit
a dune file, or it can be composed to programmatically generate parts of a
multi-component project.
quickly add new projects, libraries, tests, or executables without having to
manually create dune files, or it can be composed to programmatically generate
parts of a multi-component project.

For example, to add a new executable to a ``dune`` file in the current directory
(creating the file if necessary), you can run
Initializing a project
----------------------

To initialize a new ``dune`` project that uses the ``base`` and ``cmdliner``,
libraries and supports inline tests, you can run

.. code:: bash

$ dune init proj myproj --libs base,cmdliner --inline-tests --ppx ppx_inline_test

This will create a new directory called ``myproj`` including sub directories and
``dune`` files for library, executable, and test components. Each component's
``dune`` file will also include the declarations required for the given
dependencies.

This is the quickest way to get a basic ``dune`` project up and building.

Initializing an executable
-----------------------------

To add a new executable to a ``dune`` file in the current directory
(creating the file if necessary), run

.. code:: bash

Expand All @@ -35,7 +55,10 @@ This will add the following stanza to the ``dune`` file:
(preprocess
(pps ppx_deriving)))

Or, to create a new directory ``src``, initialized as a library, you can run:
Initializing a library
----------------------

To create a new directory ``src``, initialized as a library, can run:

.. code:: bash

Expand Down
Loading