ソースを参照

Merge pull request #987 from ferd/plugin-templates

Plugin templates
pull/990/head
Tristan Sloughter 9年前
コミット
d7def6e9ff
14個のファイルの変更181行の追加8行の削除
  1. +5
    -0
      src/rebar_app_info.erl
  2. +3
    -0
      src/rebar_prv_new.erl
  3. +27
    -7
      src/rebar_templater.erl
  4. +30
    -1
      test/rebar_new_SUITE.erl
  5. +19
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/.gitignore
  6. +2
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/priv/module.erl.dtl
  7. +7
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/priv/tpl.template
  8. +2
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/rebar.config
  9. +15
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/src/tpl.app.src
  10. +8
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/src/tpl.erl
  11. +32
    -0
      test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/src/tpl_prv.erl
  12. +3
    -0
      test/rebar_new_SUITE_data/plugin_tpl/rebar.config
  13. +15
    -0
      test/rebar_new_SUITE_data/plugin_tpl/src/plugin_tpl.app.src
  14. +13
    -0
      test/rebar_new_SUITE_data/plugin_tpl/src/plugin_tpl.erl

+ 5
- 0
src/rebar_app_info.erl ファイルの表示

@ -23,6 +23,7 @@
original_vsn/1,
original_vsn/2,
ebin_dir/1,
priv_dir/1,
applications/1,
applications/2,
profiles/1,
@ -361,6 +362,10 @@ out_dir(AppInfo=#app_info_t{}, OutDir) ->
ebin_dir(#app_info_t{out_dir=OutDir}) ->
ec_cnv:to_list(filename:join(OutDir, "ebin")).
-spec priv_dir(t()) -> file:name().
priv_dir(#app_info_t{out_dir=OutDir}) ->
ec_cnv:to_list(filename:join(OutDir, "priv")).
-spec resource_type(t(), pkg | src) -> t().
resource_type(AppInfo=#app_info_t{}, Type) ->
AppInfo#app_info_t{resource_type=Type}.

+ 3
- 0
src/rebar_prv_new.erl ファイルの表示

@ -132,10 +132,13 @@ show_template({Name, Type, Location, Description, Vars}) ->
format_vars(Vars)]).
format_type(escript) -> "built-in";
format_type(plugin) -> "plugin";
format_type(file) -> "custom".
format_type(escript, _) ->
"built-in template";
format_type(plugin, Loc) ->
io_lib:format("plugin template (~s)", [Loc]);
format_type(file, Loc) ->
io_lib:format("custom template (~s)", [Loc]).

+ 27
- 7
src/rebar_templater.erl ファイルの表示

@ -239,6 +239,7 @@ replace_var([H|T], Acc, Vars) ->
%% Load a list of all the files in the escript and on disk
find_templates(State) ->
DiskTemplates = find_disk_templates(State),
PluginTemplates = find_plugin_templates(State),
{MainTemplates, Files} =
case rebar_state:escript_path(State) of
undefined ->
@ -249,19 +250,23 @@ find_templates(State) ->
F = cache_escript_files(State),
{find_escript_templates(F), F}
end,
AvailTemplates = find_available_templates(DiskTemplates,
MainTemplates),
AvailTemplates = find_available_templates([MainTemplates,
PluginTemplates,
DiskTemplates]),
?DEBUG("Available templates: ~p\n", [AvailTemplates]),
{AvailTemplates, Files}.
find_available_templates(TemplateList1, TemplateList2) ->
AvailTemplates = prioritize_templates(
tag_names(TemplateList1),
tag_names(TemplateList2)),
find_available_templates(TemplateListList) ->
AvailTemplates = prioritize_templates(TemplateListList),
?DEBUG("Available templates: ~p\n", [AvailTemplates]),
AvailTemplates.
prioritize_templates([TemplateList]) ->
tag_names(TemplateList);
prioritize_templates([TemplateList | TemplateListList]) ->
prioritize_templates(tag_names(TemplateList),
prioritize_templates(TemplateListList)).
%% Scan the current escript for available files
cache_escript_files(State) ->
{ok, Files} = rebar_utils:escript_foldl(
@ -299,6 +304,14 @@ find_other_templates(State) ->
rebar_utils:find_files(TemplateDir, ?TEMPLATE_RE)
end.
%% Fetch template indexes that sit on disk in plugins
find_plugin_templates(State) ->
[{plugin, File}
|| App <- rebar_state:all_plugin_deps(State),
Priv <- [rebar_app_info:priv_dir(App)],
Priv =/= undefined,
File <- rebar_utils:find_files(Priv, ?TEMPLATE_RE)].
%% Take an existing list of templates and tag them by name the way
%% the user would enter it from the CLI
tag_names(List) ->
@ -316,6 +329,10 @@ prioritize_templates([{Name, Type, File} | Rest], Valid) ->
?DEBUG("Skipping template ~p, due to presence of a built-in "
"template with the same name", [Name]),
prioritize_templates(Rest, Valid);
{_, plugin, _} ->
?DEBUG("Skipping template ~p, due to presence of a plugin "
"template with the same name", [Name]),
prioritize_templates(Rest, Valid);
{_, file, _} ->
?DEBUG("Skipping template ~p, due to presence of a custom "
"template at ~s", [Name, File]),
@ -327,6 +344,9 @@ prioritize_templates([{Name, Type, File} | Rest], Valid) ->
load_file(Files, escript, Name) ->
{Name, Bin} = lists:keyfind(Name, 1, Files),
Bin;
load_file(_Files, plugin, Name) ->
{ok, Bin} = file:read_file(Name),
Bin;
load_file(_Files, file, Name) ->
{ok, Bin} = file:read_file(Name),
Bin.

+ 30
- 1
test/rebar_new_SUITE.erl ファイルの表示

@ -7,9 +7,25 @@
-include_lib("eunit/include/eunit.hrl").
all() -> [app_git_user, app_hg_user, app_with_fallbacks,
app_with_flags1, app_with_flags2].
app_with_flags1, app_with_flags2, plugin_tpl].
init_per_testcase(plugin_tpl, Config) ->
application:load(rebar),
DataDir = ?config(data_dir, Config),
PrivDir = ?config(priv_dir, Config),
Name = rebar_test_utils:create_random_name("plugin_tpl"),
AppsDir = filename:join([PrivDir, rebar_test_utils:create_random_name(Name)]),
ec_file:copy(filename:join([DataDir, "plugin_tpl"]), AppsDir, [recursive]),
Verbosity = rebar3:log_level(),
rebar_log:init(command_line, Verbosity),
GlobalDir = filename:join([DataDir, "cache"]),
State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
,{global_rebar_dir, GlobalDir}
,{root_dir, AppsDir}]),
mock_home_dir(DataDir),
mock_empty_escript_templates(),
[{apps, AppsDir}, {state, State}, {name, Name} | Config];
init_per_testcase(Case, Config0) ->
Config = rebar_test_utils:init_rebar_state(Config0),
Name = rebar_test_utils:create_random_name(atom_to_list(Case)),
@ -132,11 +148,24 @@ app_with_flags2(Config) ->
{filename:join(["src", Name++"_app.erl"]), [Name]}
]).
plugin_tpl(Config) ->
Name = ?config(name, Config),
rebar_test_utils:run_and_check(
Config, [],
["new", "-f", "tpl", Name],
{ok, []}
),
Result = filename:join(["src", Name++".erl"]), % In CWD
{ok, Bin} = file:read_file(Result),
{match, _} = re:run(Bin, Name, [multiline,global]).
validate_files(_Config, Name, Checks) ->
[begin
Path = filename:join([Name, File]),
ct:pal("validating ~s for content", [Path]),
{ok, Bin} = file:read_file(Path),
[{match, _} = re:run(Bin, Pattern, [multiline,global])
|| Pattern <- Patterns]
end || {File, Patterns} <- Checks],
ok.

+ 19
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/.gitignore ファイルの表示

@ -0,0 +1,19 @@
.rebar3
_*
.eunit
*.o
*.beam
*.plt
*.swp
*.swo
.erlang.cookie
ebin
log
erl_crash.dump
.rebar
_rel
_deps
_plugins
_tdeps
logs
_build

+ 2
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/priv/module.erl.dtl ファイルの表示

@ -0,0 +1,2 @@
-module({{name}}).

+ 7
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/priv/tpl.template ファイルの表示

@ -0,0 +1,7 @@
{description, "A basic template"}.
{variables, [
{name, "mod", "Name of the module"}
]}.
{dir, "test"}.
{template, "module.erl.dtl", "src/{{name}}.erl"}.

+ 2
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/rebar.config ファイルの表示

@ -0,0 +1,2 @@
{erl_opts, [debug_info]}.
{deps, []}.

+ 15
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/src/tpl.app.src ファイルの表示

@ -0,0 +1,15 @@
{application, 'tpl',
[{description, "A rebar plugin"},
{vsn, "0.1.0"},
{registered, []},
{applications,
[kernel,
stdlib
]},
{env,[]},
{modules, []},
{contributors, []},
{licenses, []},
{links, []}
]}.

+ 8
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/src/tpl.erl ファイルの表示

@ -0,0 +1,8 @@
-module('tpl').
-export([init/1]).
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
{ok, State1} = 'tpl_prv':init(State),
{ok, State1}.

+ 32
- 0
test/rebar_new_SUITE_data/plugin_tpl/_checkouts/tpl/src/tpl_prv.erl ファイルの表示

@ -0,0 +1,32 @@
-module('tpl_prv').
-export([init/1, do/1, format_error/1]).
-define(PROVIDER, 'tpl').
-define(DEPS, [app_discovery]).
%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
Provider = providers:create([
{name, ?PROVIDER}, % The 'user friendly' name of the task
{module, ?MODULE}, % The module implementation of the task
{bare, true}, % The task can be run by the user, always true
{deps, ?DEPS}, % The list of dependencies
{example, "rebar3 tpl"}, % How to use the plugin
{opts, []}, % list of options understood by the plugin
{short_desc, "A rebar plugin"},
{desc, "A rebar plugin"}
]),
{ok, rebar_state:add_provider(State, Provider)}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{ok, State}.
-spec format_error(any()) -> iolist().
format_error(Reason) ->
io_lib:format("~p", [Reason]).

+ 3
- 0
test/rebar_new_SUITE_data/plugin_tpl/rebar.config ファイルの表示

@ -0,0 +1,3 @@
{erl_opts, [debug_info]}.
{deps, []}.
{plugins, [tpl]}.

+ 15
- 0
test/rebar_new_SUITE_data/plugin_tpl/src/plugin_tpl.app.src ファイルの表示

@ -0,0 +1,15 @@
{application, 'plugin_tpl',
[{description, "An OTP library"},
{vsn, "0.1.0"},
{registered, []},
{applications,
[kernel,
stdlib
]},
{env,[]},
{modules, []},
{contributors, []},
{licenses, []},
{links, []}
]}.

+ 13
- 0
test/rebar_new_SUITE_data/plugin_tpl/src/plugin_tpl.erl ファイルの表示

@ -0,0 +1,13 @@
-module('plugin_tpl').
%% API exports
-export([]).
%%====================================================================
%% API functions
%%====================================================================
%%====================================================================
%% Internal functions
%%====================================================================

読み込み中…
キャンセル
保存