Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

161 rinda
5.3 KiB

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