From 63d5ceb61d68af7f1847e3442a1d3f56b6808672 Mon Sep 17 00:00:00 2001 From: David Reid Date: Thu, 11 Nov 2010 09:41:13 -0800 Subject: Support single level of nested template variables Add support for defining template variables of the following form: {variables, [{appid, "mochiwebapp"}, {author, "Mochi Media "}, {year, "2010"}, {version, "0.1"}, {port, 8080}, {dest, "{{appid}}"}]}. Where dest may be overridden on the commandline but will default to being the appid. Mochiweb uses this so that we can create new projects from the template in a configurable directory. So $ rebar create template=mochiwebapp dest=foo appid=bar I thought about special casing dest but figured it might be generally useful to be able to nest template vars. However this patch only does one level of resolution. So if {variables, [{foo, "{{bar}}"}, {bar, "{{foo}}"}]}. then bar will end up being the literal string {{bar}} and foo the literal string {{foo}}. --- src/rebar_templater.erl | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src/rebar_templater.erl') diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 4aa5ed6..e251f40 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -104,8 +104,14 @@ create(_Config, _) -> %% For each variable, see if it's defined in global vars -- if it is, prefer that %% value over the defaults - Context = update_vars(dict:fetch_keys(Context0), Context0), - ?DEBUG("Template ~p context: ~p\n", [template_id(), dict:to_list(Context)]), + Context1 = update_vars(dict:fetch_keys(Context0), Context0), + ?DEBUG("Template ~p context: ~p\n", [template_id(), dict:to_list(Context1)]), + + %% Handle variables that possibly include other variables in their + %% definition + Context = resolve_recursive_vars(dict:to_list(Context1), Context1), + + ?DEBUG("Resolved Template ~p context: ~p\n", [template_id(), dict:to_list(Context1)]), %% Now, use our context to process the template definition -- this permits us to %% use variables within the definition for filenames. @@ -206,6 +212,19 @@ update_vars([Key | Rest], Dict) -> %% +%% 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_recursive_vars([], Dict) -> + Dict; +resolve_recursive_vars([{Key, Value0} | Rest], Dict) when is_list(Value0) -> + Value = render(list_to_binary(Value0), Dict), + resolve_recursive_vars(Rest, dict:store(Key, Value, Dict)); +resolve_recursive_vars([_Pair | Rest], Dict) -> + resolve_recursive_vars(Rest, Dict). + +%% %% Given a string or binary, parse it into a list of terms, ala file:consult/0 %% consult(Str) when is_list(Str) -> @@ -319,4 +338,3 @@ execute_template([{variables, _} | Rest], TemplateType, TemplateName, Context, F execute_template([Other | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> ?WARN("Skipping unknown template instruction: ~p\n", [Other]), execute_template(Rest, TemplateType, TemplateName, Context, Force, ExistingFiles). - -- cgit v1.1 From a8870807fc6e677b471591ba9313179a5c6c78b6 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Fri, 7 Jan 2011 14:58:30 +0100 Subject: Fix code clarity --- src/rebar_templater.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/rebar_templater.erl') diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index e251f40..b241fd5 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -263,8 +263,8 @@ write_file(Output, Data, Force) -> %% perform the function if we're allowed, %% otherwise just process the next template - if - Force =:= "1"; FileExists =:= false -> + case Force =:= "1" orelse FileExists =:= false of + true -> ok = filelib:ensure_dir(Output), if {Force, FileExists} =:= {"1", true} -> @@ -280,7 +280,7 @@ write_file(Output, Data, Force) -> ?ABORT("Failed to write output file ~p: ~p\n", [Output, Reason]) end; - true -> + false -> {error, exists} end. -- cgit v1.1 From 58fd80917a2fab2353bc19f9f4bc648d8e54db92 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Fri, 7 Jan 2011 16:32:36 +0100 Subject: Fix file existence checks --- src/rebar_templater.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rebar_templater.erl') diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index b241fd5..748c8b6 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -259,7 +259,7 @@ render(Bin, Context) -> write_file(Output, Data, Force) -> %% determine if the target file already exists - FileExists = filelib:is_file(Output), + FileExists = filelib:is_regular(Output), %% perform the function if we're allowed, %% otherwise just process the next template -- cgit v1.1 From 3b0568ebb7a43b2e3d30aab97265e60bc618f1a9 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Sun, 9 Jan 2011 12:29:41 +0100 Subject: Simplify and cleanup rebar_templater --- src/rebar_templater.erl | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src/rebar_templater.erl') diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 748c8b6..5a02511 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -75,11 +75,13 @@ create(_Config, _) -> AvailTemplates = find_disk_templates() ++ find_escript_templates(), ?DEBUG("Available templates: ~p\n", [AvailTemplates]), + TemplateId = template_id(), + %% Using the specified template id, find the matching template file/type. %% Note that if you define the same template in both ~/.rebar/templates %% that is also present in the escript, the one on the file system will %% be preferred. - {Type, Template} = select_template(AvailTemplates, template_id()), + {Type, Template} = select_template(AvailTemplates, TemplateId), %% Load the template definition as is and get the list of variables the %% template requires. @@ -92,31 +94,31 @@ create(_Config, _) -> ?ABORT("Failed while processing variables from template ~p." "Variable definitions must follow form of " "[{atom(), term()}]. Failed at: ~p\n", - [template_id(), Entry]); + [TemplateId, Entry]); Context0 -> ok end; false -> ?WARN("No variables section found in template ~p; using empty context.\n", - [template_id()]), + [TemplateId]), Context0 = dict:new() end, %% For each variable, see if it's defined in global vars -- if it is, prefer that %% value over the defaults Context1 = update_vars(dict:fetch_keys(Context0), Context0), - ?DEBUG("Template ~p context: ~p\n", [template_id(), dict:to_list(Context1)]), + ?DEBUG("Template ~p context: ~p\n", [TemplateId, dict:to_list(Context1)]), %% Handle variables that possibly include other variables in their %% definition Context = resolve_recursive_vars(dict:to_list(Context1), Context1), - ?DEBUG("Resolved Template ~p context: ~p\n", [template_id(), dict:to_list(Context1)]), + ?DEBUG("Resolved Template ~p context: ~p\n", [TemplateId, dict:to_list(Context1)]), %% 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)), - ?DEBUG("Final template def ~p: ~p\n", [template_id(), FinalTemplate]), + ?DEBUG("Final template def ~p: ~p\n", [TemplateId, FinalTemplate]), %% Execute the instructions in the finalized template Force = rebar_config:get_global(force, "0"), @@ -215,7 +217,6 @@ update_vars([Key | Rest], Dict) -> %% 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_recursive_vars([], Dict) -> Dict; resolve_recursive_vars([{Key, Value0} | Rest], Dict) when is_list(Value0) -> @@ -266,11 +267,11 @@ write_file(Output, Data, Force) -> case Force =:= "1" orelse FileExists =:= false of true -> ok = filelib:ensure_dir(Output), - if - {Force, FileExists} =:= {"1", true} -> + case {Force, FileExists} of + {"1", true} -> ?CONSOLE("Writing ~s (forcibly overwriting)~n", [Output]); - true -> + _ -> ?CONSOLE("Writing ~s~n", [Output]) end, case file:write_file(Output, Data) of -- cgit v1.1 From c466076ffb5a1ea4c00d49fefff0dcfbceb58236 Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Mon, 31 Jan 2011 17:43:31 +0100 Subject: Clean up emacs file local variables --- src/rebar_templater.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rebar_templater.erl') diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 5a02511..7716066 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -1,4 +1,4 @@ -%% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 et %% ------------------------------------------------------------------- %% -- cgit v1.1 From 63de05d914f3c2bef6dcfc6cf966400d93c9c80d Mon Sep 17 00:00:00 2001 From: Tuncer Ayaz Date: Fri, 28 Jan 2011 16:08:27 +0100 Subject: Clean up code --- src/rebar_templater.erl | 87 +++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 35 deletions(-) (limited to 'src/rebar_templater.erl') diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index 7716066..487a578 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -99,13 +99,13 @@ create(_Config, _) -> ok end; false -> - ?WARN("No variables section found in template ~p; using empty context.\n", - [TemplateId]), + ?WARN("No variables section found in template ~p; " + "using empty context.\n", [TemplateId]), Context0 = dict:new() end, - %% For each variable, see if it's defined in global vars -- if it is, prefer that - %% value over the defaults + %% For each variable, see if it's defined in global vars -- if it is, + %% prefer that value over the defaults Context1 = update_vars(dict:fetch_keys(Context0), Context0), ?DEBUG("Template ~p context: ~p\n", [TemplateId, dict:to_list(Context1)]), @@ -113,10 +113,11 @@ create(_Config, _) -> %% definition Context = resolve_recursive_vars(dict:to_list(Context1), Context1), - ?DEBUG("Resolved Template ~p context: ~p\n", [TemplateId, dict:to_list(Context1)]), + ?DEBUG("Resolved Template ~p context: ~p\n", + [TemplateId, dict:to_list(Context1)]), - %% Now, use our context to process the template definition -- this permits us to - %% use variables within the definition for filenames. + %% 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)), ?DEBUG("Final template def ~p: ~p\n", [TemplateId, FinalTemplate]), @@ -136,10 +137,10 @@ create(_Config, _) -> %% cache_escript_files() -> {ok, Files} = rebar_utils:escript_foldl( - fun(Name, _, GetBin, Acc) -> - [{Name, GetBin()} | Acc] - end, - [], rebar_config:get_global(escript, undefined)), + fun(Name, _, GetBin, Acc) -> + [{Name, GetBin()} | Acc] + end, + [], rebar_config:get_global(escript, undefined)), erlang:put(escript_files, Files). @@ -158,7 +159,8 @@ find_escript_templates() -> find_disk_templates() -> OtherTemplates = find_other_templates(), HomeFiles = rebar_utils:find_files(filename:join(os:getenv("HOME"), - ".rebar/templates"), ?TEMPLATE_RE), + ".rebar/templates"), + ?TEMPLATE_RE), LocalFiles = rebar_utils:find_files(".", ?TEMPLATE_RE), [{file, F} || F <- OtherTemplates ++ HomeFiles ++ LocalFiles]. @@ -289,18 +291,24 @@ write_file(Output, Data, Force) -> %% %% Execute each instruction in a template definition file. %% -execute_template([], _TemplateType, _TemplateName, _Context, _Force, ExistingFiles) -> +execute_template([], _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", - ?ERROR("One or more files already exist on disk and were not generated:~n~s~s", [Msg , Help]) + 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", + ?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, TemplateName, Context, Force, ExistingFiles) -> +execute_template([{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 + case write_file(Output, render(load_file(TemplateType, InputName), Context), + Force) of ok -> execute_template(Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); @@ -308,34 +316,43 @@ execute_template([{template, Input, Output} | Rest], TemplateType, TemplateName, execute_template(Rest, TemplateType, TemplateName, Context, Force, [Output|ExistingFiles]) end; -execute_template([{file, Input, Output} | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> +execute_template([{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 ok -> - execute_template(Rest, TemplateType, TemplateName, Context, - Force, ExistingFiles); + execute_template(Rest, TemplateType, TemplateName, + Context, Force, ExistingFiles); {error, exists} -> - execute_template(Rest, TemplateType, TemplateName, Context, - Force, [Output|ExistingFiles]) + execute_template(Rest, TemplateType, TemplateName, + Context, Force, [Output|ExistingFiles]) end; -execute_template([{dir, Name} | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> +execute_template([{dir, Name} | Rest], TemplateType, TemplateName, Context, + Force, ExistingFiles) -> case filelib:ensure_dir(filename:join(Name, "dummy")) of ok -> - execute_template(Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); + execute_template(Rest, TemplateType, TemplateName, + Context, Force, ExistingFiles); {error, Reason} -> - ?ABORT("Failed while processing template instruction {dir, ~s}: ~p\n", - [Name, Reason]) + ?ABORT("Failed while processing template instruction " + "{dir, ~s}: ~p\n", [Name, Reason]) end; -execute_template([{chmod, Mod, File} | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) when is_integer(Mod) -> +execute_template([{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, Context, Force, ExistingFiles); + execute_template(Rest, TemplateType, TemplateName, + Context, Force, ExistingFiles); {error, Reason} -> - ?ABORT("Failed while processing template instruction {cmod, ~b, ~s}: ~p~n", - [Mod, File, Reason]) + ?ABORT("Failed while processing template instruction " + "{cmod, ~b, ~s}: ~p~n", [Mod, File, Reason]) end; -execute_template([{variables, _} | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> - execute_template(Rest, TemplateType, TemplateName, Context, Force, ExistingFiles); -execute_template([Other | Rest], TemplateType, TemplateName, Context, Force, ExistingFiles) -> +execute_template([{variables, _} | Rest], TemplateType, TemplateName, Context, + Force, ExistingFiles) -> + execute_template(Rest, TemplateType, TemplateName, + Context, Force, ExistingFiles); +execute_template([Other | Rest], TemplateType, TemplateName, Context, + Force, ExistingFiles) -> ?WARN("Skipping unknown template instruction: ~p\n", [Other]), - execute_template(Rest, TemplateType, TemplateName, Context, Force, ExistingFiles). + execute_template(Rest, TemplateType, TemplateName, Context, + Force, ExistingFiles). -- cgit v1.1