init.ml 6.01 KB
Newer Older
1 2 3 4 5 6
open Stdune
open Import

open Dune.Dune_init

(* TODO(shonfeder): Remove when nested subcommands are available *)
7
let validate_component_options kind unsupported_options =
8 9 10
  let report_invalid_option = function
    | _, false -> ()  (* The option wasn't supplied *)
    | option_name, true ->
11 12 13
      User_error.raise
        [ Pp.textf "The %s component does not support the %s option"
            (Kind.to_string kind) option_name ]
14 15 16 17 18 19
  in
  List.iter ~f:report_invalid_option unsupported_options

let doc = "Initialize dune components"
let man =
  [ `S "DESCRIPTION"
20 21 22 23 24 25
  ; `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
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
         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.|}
  ; `S "EXAMPLES"
  ; `Pre {|
Define an executable component named 'myexe' in a dune file in the
current directory:

          dune init exe myexe

Define a library component named 'mylib' in a dune file in the ./src
directory depending on the core and cmdliner libraries, the ppx_let
and ppx_inline_test preprocessors, and declared as using inline tests:

          dune init lib mylib src --libs core,cmdliner --ppx ppx_let,ppx_inline_test --inline-tests

Define a library component named mytest in a dune file in the ./test
directory that depends on mylib:

        dune init test myexe test --libs mylib|}
  ]

let info = Term.info "init" ~doc ~man

let term =
  let+ common_term = Common.term
  and+ kind =
    (* TODO(shonfeder): Replace with nested subcommand once we have support for that *)
    Arg.(required & pos 0 (some (enum Kind.commands)) None & info [] ~docv:"INIT_KIND")
  and+ name =
    Arg.(required & pos 1 (some string) None & info [] ~docv:"NAME")
  and+ path =
    Arg.(value & pos 2 (some string) None & info [] ~docv:"PATH" )
  and+ libraries =
    Arg.(value
         & opt (list string) []
         & info ["libs"]
             ~docv:"LIBRARIES"
             ~doc:"Libraries on which the component depends")
  and+ pps =
    Arg.(value
         & opt (list string) []
         & info ["ppx"]
             ~docv:"PREPROCESSORS"
             ~doc:"ppx preprocessors used by the component")
  and+ public =
    (* TODO(shonfeder): Move to subcommands {lib, exe} once implemented *)
    Arg.(value
         & opt ~vopt:(Some "") (some string) None
         & info ["public"]
             ~docv:"PUBLIC_NAME"
             ~doc:"If called with an argument, make the component public \
                   under the given PUBLIC_NAME. If supplied without an \
                   argument, use NAME.")
  and+ inline_tests =
    (* TODO Move to subcommand lib once implemented *)
    Arg.(value
         & flag
         & info ["inline-tests"]
             ~docv:"USE_INLINE_TESTS"
             ~doc:"Whether to use inline tests. \
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
                   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.")

111 112 113 114
  in

  validate_component_name name;
  Common.set_common common_term ~targets:[];
115

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

120
  let given_public = Option.is_some public in
121 122 123 124 125 126 127 128 129
  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

130 131
  begin match kind with
  | Kind.Executable ->
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    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 }
                    }
155
  | Kind.Test ->
156 157 158 159 160 161 162 163 164
    check_unsupported_options [ "public", given_public
                              ; "inline-tests", inline_tests
                              ; "kind", given_template
                              ; "pkg", given_pkg
                              ];
    init @@ Test { context
                 ; common
                 ; options = ()
                 }
165 166 167 168 169 170
  end;

  print_completion kind name

let command = term, info