diff options
Diffstat (limited to 'src/rebar_templater.erl')
-rw-r--r-- | src/rebar_templater.erl | 242 |
1 files changed, 121 insertions, 121 deletions
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 1e015ee..0e1eef1 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -43,49 +43,64 @@ %% Public API %% =================================================================== -'create-app'(Config, File) -> +'create-app'(Config, _File) -> %% Alias for create w/ template=simpleapp - rebar_config:set_global(template, "simpleapp"), - create(Config, File). + create1(Config, "simpleapp"). -'create-node'(Config, File) -> +'create-node'(Config, _File) -> %% Alias for create w/ template=simplenode - rebar_config:set_global(template, "simplenode"), - create(Config, File). + create1(Config, "simplenode"). -'list-templates'(_Config, _File) -> - %% Load a list of all the files in the escript -- cache it in the pdict - %% since we'll potentially need to walk it several times over the course - %% of a run. - cache_escript_files(), +'list-templates'(Config, _File) -> + {AvailTemplates, Files} = find_templates(Config), + ?DEBUG("Available templates: ~p\n", [AvailTemplates]), - %% Build a list of available templates - AvailTemplates = find_disk_templates() ++ find_escript_templates(), - ?CONSOLE("Available templates:\n", []), - _ = [begin - BaseName = filename:basename(F, ".template"), - {ok, Template} = file:consult(F), - {_, VarList} = lists:keyfind(variables, 1, Template), - Vars = lists:foldl(fun({V,_}, Acc) -> - [atom_to_list(V) | Acc] - end, [], VarList), - ?CONSOLE("\t* ~s: ~s (~p) (variables: ~p)\n", - [BaseName, F, Type, string:join(Vars, ", ")]) - end || {Type, F} <- AvailTemplates], + lists:foreach( + fun({Type, F}) -> + BaseName = filename:basename(F, ".template"), + TemplateTerms = consult(load_file(Files, Type, F)), + {_, VarList} = lists:keyfind(variables, 1, TemplateTerms), + Vars = lists:foldl(fun({V,_}, Acc) -> + [atom_to_list(V) | Acc] + end, [], VarList), + ?CONSOLE(" * ~s: ~s (~p) (variables: ~p)\n", + [BaseName, F, Type, string:join(Vars, ", ")]) + end, AvailTemplates), ok. +create(Config, _) -> + TemplateId = template_id(Config), + create1(Config, TemplateId). -create(_Config, _) -> - %% Load a list of all the files in the escript -- cache it in the pdict - %% since we'll potentially need to walk it several times over the course - %% of a run. - cache_escript_files(), +%% +%% Given a list of key value pairs, for each string value attempt to +%% render it using Dict as the context. Storing the result in Dict as Key. +%% +resolve_variables([], Dict) -> + Dict; +resolve_variables([{Key, Value0} | Rest], Dict) when is_list(Value0) -> + Value = render(list_to_binary(Value0), Dict), + resolve_variables(Rest, dict:store(Key, Value, Dict)); +resolve_variables([_Pair | Rest], Dict) -> + resolve_variables(Rest, Dict). - %% Build a list of available templates - AvailTemplates = find_disk_templates() ++ find_escript_templates(), - ?DEBUG("Available templates: ~p\n", [AvailTemplates]), +%% +%% Render a binary to a string, using mustache and the specified context +%% +render(Bin, Context) -> + %% Be sure to escape any double-quotes before rendering... + ReOpts = [global, {return, list}], + Str0 = re:replace(Bin, "\\\\", "\\\\\\", ReOpts), + Str1 = re:replace(Str0, "\"", "\\\\\"", ReOpts), + mustache:render(Str1, Context). - TemplateId = template_id(), +%% =================================================================== +%% Internal functions +%% =================================================================== + +create1(Config, TemplateId) -> + {AvailTemplates, Files} = find_templates(Config), + ?DEBUG("Available templates: ~p\n", [AvailTemplates]), %% Using the specified template id, find the matching template file/type. %% Note that if you define the same template in both ~/.rebar/templates @@ -95,7 +110,7 @@ create(_Config, _) -> %% Load the template definition as is and get the list of variables the %% template requires. - TemplateTerms = consult(load_file(Type, Template)), + TemplateTerms = consult(load_file(Files, Type, Template)), case lists:keyfind(variables, 1, TemplateTerms) of {variables, Vars} -> case parse_vars(Vars, dict:new()) of @@ -115,7 +130,7 @@ create(_Config, _) -> end, %% Load variables from disk file, if provided - Context1 = case rebar_config:get_global(template_vars, undefined) of + Context1 = case rebar_config:get_global(Config, template_vars, undefined) of undefined -> Context0; File -> @@ -132,7 +147,7 @@ create(_Config, _) -> %% For each variable, see if it's defined in global vars -- if it is, %% prefer that value over the defaults - Context2 = update_vars(dict:fetch_keys(Context1), Context1), + Context2 = update_vars(Config, dict:fetch_keys(Context1), Context1), ?DEBUG("Template ~p context: ~p\n", [TemplateId, dict:to_list(Context1)]), %% Handle variables that possibly include other variables in their @@ -144,76 +159,59 @@ create(_Config, _) -> %% Now, use our context to process the template definition -- this %% permits us to use variables within the definition for filenames. - FinalTemplate = consult(render(load_file(Type, Template), Context)), + FinalTemplate = consult(render(load_file(Files, Type, Template), Context)), ?DEBUG("Final template def ~p: ~p\n", [TemplateId, FinalTemplate]), %% Execute the instructions in the finalized template - Force = rebar_config:get_global(force, "0"), - execute_template(FinalTemplate, Type, Template, Context, Force, []). - - -%% -%% Given a list of key value pairs, for each string value attempt to -%% render it using Dict as the context. Storing the result in Dict as Key. -%% -resolve_variables([], Dict) -> - Dict; -resolve_variables([{Key, Value0} | Rest], Dict) when is_list(Value0) -> - Value = render(list_to_binary(Value0), Dict), - resolve_variables(Rest, dict:store(Key, Value, Dict)); -resolve_variables([_Pair | Rest], Dict) -> - resolve_variables(Rest, Dict). - + Force = rebar_config:get_global(Config, force, "0"), + execute_template(Files, FinalTemplate, Type, Template, Context, Force, []). -%% -%% Render a binary to a string, using mustache and the specified context -%% -render(Bin, Context) -> - %% Be sure to escape any double-quotes before rendering... - ReOpts = [global, {return, list}], - Str0 = re:replace(Bin, "\\\\", "\\\\\\", ReOpts), - Str1 = re:replace(Str0, "\"", "\\\\\"", ReOpts), - mustache:render(Str1, Context). +find_templates(Config) -> + %% Load a list of all the files in the escript -- cache them since + %% we'll potentially need to walk it several times over the course of + %% a run. + Files = cache_escript_files(Config), + %% Build a list of available templates + AvailTemplates = find_disk_templates(Config) + ++ find_escript_templates(Files), -%% =================================================================== -%% Internal functions -%% =================================================================== + {AvailTemplates, Files}. %% -%% Scan the current escript for available files and cache in pdict. +%% Scan the current escript for available files %% -cache_escript_files() -> +cache_escript_files(Config) -> {ok, Files} = rebar_utils:escript_foldl( fun(Name, _, GetBin, Acc) -> [{Name, GetBin()} | Acc] end, - [], rebar_config:get_global(escript, undefined)), - erlang:put(escript_files, Files). + [], rebar_config:get_xconf(Config, escript)), + Files. - -template_id() -> - case rebar_config:get_global(template, undefined) of +template_id(Config) -> + case rebar_config:get_global(Config, template, undefined) of undefined -> ?ABORT("No template specified.\n", []); TemplateId -> TemplateId end. -find_escript_templates() -> - [{escript, Name} || {Name, _Bin} <- erlang:get(escript_files), - re:run(Name, ?TEMPLATE_RE, [{capture, none}]) == match]. +find_escript_templates(Files) -> + [{escript, Name} + || {Name, _Bin} <- Files, + re:run(Name, ?TEMPLATE_RE, [{capture, none}]) == match]. -find_disk_templates() -> - OtherTemplates = find_other_templates(), +find_disk_templates(Config) -> + OtherTemplates = find_other_templates(Config), HomeFiles = rebar_utils:find_files(filename:join([os:getenv("HOME"), ".rebar", "templates"]), ?TEMPLATE_RE), LocalFiles = rebar_utils:find_files(".", ?TEMPLATE_RE), [{file, F} || F <- OtherTemplates ++ HomeFiles ++ LocalFiles]. -find_other_templates() -> - case rebar_config:get_global(template_dir, undefined) of +find_other_templates(Config) -> + case rebar_config:get_global(Config, template_dir, undefined) of undefined -> []; TemplateDir -> @@ -233,10 +231,10 @@ select_template([{Type, Avail} | Rest], Template) -> %% %% Read the contents of a file from the appropriate source %% -load_file(escript, Name) -> - {Name, Bin} = lists:keyfind(Name, 1, erlang:get(escript_files)), +load_file(Files, escript, Name) -> + {Name, Bin} = lists:keyfind(Name, 1, Files), Bin; -load_file(file, Name) -> +load_file(_Files, file, Name) -> {ok, Bin} = file:read_file(Name), Bin. @@ -256,15 +254,15 @@ parse_vars(Other, _Dict) -> %% Given a list of keys in Dict, see if there is a corresponding value defined %% in the global config; if there is, update the key in Dict with it %% -update_vars([], Dict) -> +update_vars(_Config, [], Dict) -> Dict; -update_vars([Key | Rest], Dict) -> - Value = rebar_config:get_global(Key, dict:fetch(Key, Dict)), - update_vars(Rest, dict:store(Key, Value, Dict)). +update_vars(Config, [Key | Rest], Dict) -> + Value = rebar_config:get_global(Config, Key, dict:fetch(Key, Dict)), + update_vars(Config, Rest, dict:store(Key, Value, Dict)). %% -%% Given a string or binary, parse it into a list of terms, ala file:consult/0 +%% Given a string or binary, parse it into a list of terms, ala file:consult/1 %% consult(Str) when is_list(Str) -> consult([], Str, []); @@ -319,89 +317,91 @@ write_file(Output, Data, Force) -> %% %% Execute each instruction in a template definition file. %% -execute_template([], _TemplateType, _TemplateName, _Context, - _Force, ExistingFiles) -> +execute_template(_Files, [], _TemplateType, _TemplateName, + _Context, _Force, ExistingFiles) -> case ExistingFiles of [] -> ok; _ -> Msg = lists:flatten([io_lib:format("\t* ~p~n", [F]) || F <- lists:reverse(ExistingFiles)]), - Help = - "To force overwriting, specify force=1 on the command line.\n", + Help = "To force overwriting, specify -f/--force/force=1" + " on the command line.\n", ?ERROR("One or more files already exist on disk and " "were not generated:~n~s~s", [Msg , Help]) end; -execute_template([{template, Input, Output} | Rest], TemplateType, +execute_template(Files, [{template, Input, Output} | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> InputName = filename:join(filename:dirname(TemplateName), Input), - case write_file(Output, render(load_file(TemplateType, InputName), Context), - Force) of + File = load_file(Files, TemplateType, InputName), + case write_file(Output, render(File, Context), Force) of ok -> - execute_template(Rest, TemplateType, TemplateName, Context, - Force, ExistingFiles); + execute_template(Files, Rest, TemplateType, TemplateName, + Context, Force, ExistingFiles); {error, exists} -> - execute_template(Rest, TemplateType, TemplateName, Context, - Force, [Output|ExistingFiles]) + execute_template(Files, Rest, TemplateType, TemplateName, + Context, Force, [Output|ExistingFiles]) end; -execute_template([{file, Input, Output} | Rest], TemplateType, TemplateName, - Context, Force, ExistingFiles) -> +execute_template(Files, [{file, Input, Output} | Rest], TemplateType, + TemplateName, Context, Force, ExistingFiles) -> InputName = filename:join(filename:dirname(TemplateName), Input), - case write_file(Output, load_file(TemplateType, InputName), Force) of + File = load_file(Files, TemplateType, InputName), + case write_file(Output, File, Force) of ok -> - execute_template(Rest, TemplateType, TemplateName, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); {error, exists} -> - execute_template(Rest, TemplateType, TemplateName, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, [Output|ExistingFiles]) end; -execute_template([{dir, Name} | Rest], TemplateType, TemplateName, Context, - Force, ExistingFiles) -> +execute_template(Files, [{dir, Name} | Rest], TemplateType, + TemplateName, Context, Force, ExistingFiles) -> case filelib:ensure_dir(filename:join(Name, "dummy")) of ok -> - execute_template(Rest, TemplateType, TemplateName, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); {error, Reason} -> ?ABORT("Failed while processing template instruction " "{dir, ~s}: ~p\n", [Name, Reason]) end; -execute_template([{copy, Input, Output} | Rest], TemplateType, TemplateName, - Context, Force, ExistingFiles) -> +execute_template(Files, [{copy, Input, Output} | Rest], TemplateType, + TemplateName, Context, Force, ExistingFiles) -> InputName = filename:join(filename:dirname(TemplateName), Input), try rebar_file_utils:cp_r([InputName ++ "/*"], Output) of ok -> - execute_template(Rest, TemplateType, TemplateName, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles) catch _:_ -> ?ABORT("Failed while processing template instruction " "{copy, ~s, ~s}~n", [Input, Output]) end; -execute_template([{chmod, Mod, File} | Rest], TemplateType, TemplateName, - Context, Force, ExistingFiles) when is_integer(Mod) -> +execute_template(Files, [{chmod, Mod, File} | Rest], TemplateType, + TemplateName, Context, Force, ExistingFiles) + when is_integer(Mod) -> case file:change_mode(File, Mod) of ok -> - execute_template(Rest, TemplateType, TemplateName, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); {error, Reason} -> ?ABORT("Failed while processing template instruction " "{chmod, ~b, ~s}: ~p~n", [Mod, File, Reason]) end; -execute_template([{symlink, Existing, New} | Rest], TemplateType, TemplateName, - Context, Force, ExistingFiles) -> +execute_template(Files, [{symlink, Existing, New} | Rest], TemplateType, + TemplateName, Context, Force, ExistingFiles) -> case file:make_symlink(Existing, New) of ok -> - execute_template(Rest, TemplateType, TemplateName, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); {error, Reason} -> ?ABORT("Failed while processing template instruction " "{symlink, ~s, ~s}: ~p~n", [Existing, New, Reason]) end; -execute_template([{variables, _} | Rest], TemplateType, TemplateName, Context, - Force, ExistingFiles) -> - execute_template(Rest, TemplateType, TemplateName, +execute_template(Files, [{variables, _} | Rest], TemplateType, + TemplateName, Context, Force, ExistingFiles) -> + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); -execute_template([Other | Rest], TemplateType, TemplateName, Context, - Force, ExistingFiles) -> +execute_template(Files, [Other | Rest], TemplateType, TemplateName, + Context, Force, ExistingFiles) -> ?WARN("Skipping unknown template instruction: ~p\n", [Other]), - execute_template(Rest, TemplateType, TemplateName, Context, + execute_template(Files, Rest, TemplateType, TemplateName, Context, Force, ExistingFiles). |