You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
4.0 KiB

  1. -module(rebar_prv_new).
  2. -behaviour(provider).
  3. -export([init/1,
  4. do/1,
  5. format_error/1]).
  6. -include("rebar.hrl").
  7. -define(PROVIDER, new).
  8. -define(DEPS, []).
  9. %% ===================================================================
  10. %% Public API
  11. %% ===================================================================
  12. -spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
  13. init(State) ->
  14. Provider = providers:create([
  15. {name, ?PROVIDER},
  16. {module, ?MODULE},
  17. {bare, false},
  18. {deps, ?DEPS},
  19. {example, "rebar3 new <template>"},
  20. {short_desc, "Create new project from templates."},
  21. {desc, info()},
  22. {opts, [{force, $f, "force", undefined, "overwrite existing files"}]}
  23. ]),
  24. State1 = rebar_state:add_provider(State, Provider),
  25. {ok, State1}.
  26. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
  27. do(State) ->
  28. case rebar_state:command_args(State) of
  29. ["help", TemplateName] ->
  30. case lists:keyfind(TemplateName, 1, rebar_templater:list_templates(State)) of
  31. false -> io:format("template not found.~n");
  32. Term -> show_template(Term)
  33. end,
  34. {ok, State};
  35. [TemplateName | Opts] ->
  36. Force = is_forced(State),
  37. ok = rebar_templater:new(TemplateName, parse_opts(Opts), Force, State),
  38. {ok, State};
  39. [] ->
  40. show_short_templates(rebar_templater:list_templates(State)),
  41. {ok, State}
  42. end.
  43. -spec format_error(any()) -> iolist().
  44. format_error(Reason) ->
  45. io_lib:format("~p", [Reason]).
  46. %% ===================================================================
  47. %% Internal functions
  48. %% ===================================================================
  49. info() ->
  50. io_lib:format(
  51. "Create rebar project based on template and vars.~n"
  52. "~n"
  53. "Valid command line options:~n"
  54. " template= [var=foo,...]~n", []).
  55. is_forced(State) ->
  56. {Args, _} = rebar_state:command_parsed_args(State),
  57. case proplists:get_value(force, Args) of
  58. undefined -> false;
  59. _ -> true
  60. end.
  61. parse_opts([]) -> [];
  62. parse_opts([Opt|Opts]) -> [parse_first_opt(Opt, "") | parse_opts1(Opts)].
  63. parse_opts1([]) -> [];
  64. parse_opts1([Opt|Opts]) -> [parse_opt(Opt, "") | parse_opts1(Opts)].
  65. %% If the first argument meets no '=', we got a default 'name' argument
  66. parse_first_opt("", Acc) -> {name, lists:reverse(Acc)};
  67. parse_first_opt("="++Rest, Acc) -> parse_opt("="++Rest, Acc);
  68. parse_first_opt([H|Str], Acc) -> parse_first_opt(Str, [H|Acc]).
  69. %% We convert to atoms dynamically. Horrible in general, but fine in a
  70. %% build system's templating tool.
  71. parse_opt("", Acc) -> {list_to_atom(lists:reverse(Acc)), "true"};
  72. parse_opt("="++Rest, Acc) -> {list_to_atom(lists:reverse(Acc)), Rest};
  73. parse_opt([H|Str], Acc) -> parse_opt(Str, [H|Acc]).
  74. show_short_templates(List) ->
  75. lists:map(fun show_short_template/1, lists:sort(List)).
  76. show_short_template({Name, Type, _Location, Description, _Vars}) ->
  77. io:format("~s (~s): ~s~n",
  78. [Name,
  79. format_type(Type),
  80. format_description(Description)]).
  81. show_template({Name, Type, Location, Description, Vars}) ->
  82. io:format("~s:~n"
  83. "\t~s~n"
  84. "\tDescription: ~s~n"
  85. "\tVariables:~n~s~n",
  86. [Name,
  87. format_type(Type, Location),
  88. format_description(Description),
  89. format_vars(Vars)]).
  90. format_type(escript) -> "built-in";
  91. format_type(file) -> "custom".
  92. format_type(escript, _) ->
  93. "built-in template";
  94. format_type(file, Loc) ->
  95. io_lib:format("custom template (~s)", [Loc]).
  96. format_description(Description) ->
  97. case Description of
  98. undefined -> "<missing description>";
  99. _ -> Description
  100. end.
  101. format_vars(Vars) -> [format_var(Var) || Var <- Vars].
  102. format_var({Var, Default}) ->
  103. io_lib:format("\t\t~p=~p~n",[Var, Default]);
  104. format_var({Var, Default, Doc}) ->
  105. io_lib:format("\t\t~p=~p (~s)~n", [Var, Default, Doc]).