summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFred Hebert <mononcqc@ferd.ca>2015-11-13 18:34:12 -0500
committerFred Hebert <mononcqc@ferd.ca>2015-11-13 18:34:12 -0500
commit2d6dc1cf16d2beae37a52eaad3e4abe9241eed51 (patch)
treed57ef25ce2b0aa658be7564366a86834712c2f29
parent0b01c9fcf7443d36c6c3d67c74a70bad789ede5f (diff)
parent748142838cd11ce5cd532dd598d220cab8424f75 (diff)
Merge pull request #893 from archaelus/shell_scripts
rebar3 shell improvements (escript, rebar.config shell defaults)
-rw-r--r--src/rebar_prv_shell.erl160
1 files changed, 131 insertions, 29 deletions
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index 4cf1e04..d93a21f 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -56,12 +56,23 @@ init(State) ->
{short_desc, "Run shell with project apps and deps in path."},
{desc, info()},
{opts, [{config, undefined, "config", string,
- "Path to the config file to use. Defaults to the "
- "sys_config defined for relx, if present."},
+ "Path to the config file to use. Defaults to "
+ "{shell, [{config, File}]} and then the relx "
+ "sys.config file if not specified."},
{name, undefined, "name", atom,
"Gives a long name to the node."},
{sname, undefined, "sname", atom,
- "Gives a short name to the node."}]}
+ "Gives a short name to the node."},
+ {script_file, undefined, "script", string,
+ "Path to an escript file to run before "
+ "starting the project apps. Defaults to "
+ "rebar.config {shell, [{script_file, File}]} "
+ "if not specified."},
+ {apps, undefined, "apps", string,
+ "A list of apps to boot before starting the "
+ "shell. (E.g. --apps app1,app2,app3) Defaults "
+ "to rebar.config {shell, [{apps, Apps}]} or "
+ "relx apps if not specified."}]}
])
),
{ok, State1}.
@@ -86,6 +97,7 @@ shell(State) ->
setup_name(State),
setup_paths(State),
setup_shell(),
+ maybe_run_script(State),
%% apps must be started after the change in shell because otherwise
%% their application masters never gets the new group leader (held in
%% their internal state)
@@ -134,6 +146,51 @@ setup_paths(State) ->
%% add project app test paths
ok = add_test_paths(State).
+maybe_run_script(State) ->
+ case first_value([fun find_script_option/1,
+ fun find_script_rebar/1], State) of
+ no_value ->
+ ?DEBUG("No script_file specified.", []),
+ ok;
+ "none" ->
+ ?DEBUG("Shell script execution skipped (--script none).", []),
+ ok;
+ RelFile ->
+ File = filename:absname(RelFile),
+ try run_script_file(File)
+ catch
+ C:E ->
+ ?ABORT("Couldn't run shell escript ~p - ~p:~p~nStack: ~p",
+ [File, C, E, erlang:get_stacktrace()])
+ end
+ end.
+
+-spec find_script_option(rebar_state:t()) -> no_value | list().
+find_script_option(State) ->
+ {Opts, _} = rebar_state:command_parsed_args(State),
+ debug_get_value(script_file, Opts, no_value,
+ "Found script file from command line option.").
+
+-spec find_script_rebar(rebar_state:t()) -> no_value | list().
+find_script_rebar(State) ->
+ Config = rebar_state:get(State, shell, []),
+ %% Either a string, or undefined
+ debug_get_value(script_file, Config, no_value,
+ "Found script file from rebar config file.").
+
+run_script_file(File) ->
+ ?DEBUG("Extracting escript from ~p", [File]),
+ {ok, Script} = escript:extract(File, [compile_source]),
+ Beam = proplists:get_value(source, Script),
+ Mod = proplists:get_value(module, beam_lib:info(Beam)),
+ ?DEBUG("Compiled escript as ~p", [Mod]),
+ FakeFile = "/fake_path/" ++ atom_to_list(Mod),
+ {module, Mod} = code:load_binary(Mod, FakeFile, Beam),
+ ?DEBUG("Evaling ~p:main([]).", [Mod]),
+ Result = Mod:main([]),
+ ?DEBUG("Result: ~p", [Result]),
+ Result.
+
maybe_boot_apps(State) ->
case find_apps_to_boot(State) of
undefined ->
@@ -172,17 +229,42 @@ check_epmd(_) ->
find_apps_to_boot(State) ->
%% Try the shell_apps option
- case rebar_state:get(State, shell_apps, undefined) of
- undefined ->
- %% Get to the relx tuple instead
- case lists:keyfind(release, 1, rebar_state:get(State, relx, [])) of
- {_, _, Apps} -> Apps;
- false -> undefined
- end;
+ case first_value([fun find_apps_option/1,
+ fun find_apps_rebar/1,
+ fun find_apps_relx/1], State) of
+ no_value ->
+ undefined;
Apps ->
Apps
end.
+-spec find_apps_option(rebar_state:t()) -> no_value | [atom()].
+find_apps_option(State) ->
+ {Opts, _} = rebar_state:command_parsed_args(State),
+ case debug_get_value(apps, Opts, no_value,
+ "Found shell apps from command line option.") of
+ no_value -> no_value;
+ AppsStr ->
+ [ list_to_atom(AppStr)
+ || AppStr <- string:tokens(AppsStr, " ,:") ]
+ end.
+
+-spec find_apps_rebar(rebar_state:t()) -> no_value | list().
+find_apps_rebar(State) ->
+ ShellOpts = rebar_state:get(State, shell, []),
+ debug_get_value(apps, ShellOpts, no_value,
+ "Found shell opts from command line option.").
+
+-spec find_apps_relx(rebar_state:t()) -> no_value | list().
+find_apps_relx(State) ->
+ case lists:keyfind(release, 1, rebar_state:get(State, relx, [])) of
+ {_, _, Apps} ->
+ ?DEBUG("Found shell apps from relx.", []),
+ Apps;
+ false ->
+ no_value
+ end.
+
load_apps(Apps) ->
[case application:load(App) of
ok ->
@@ -261,31 +343,51 @@ add_test_paths(State) ->
% First try the --config flag, then try the relx sys_config
-spec find_config(rebar_state:t()) -> [tuple()] | no_config.
find_config(State) ->
- case find_config_option(State) of
- no_config ->
- find_config_relx(State);
- Result ->
- Result
+ case first_value([fun find_config_option/1,
+ fun find_config_rebar/1,
+ fun find_config_relx/1], State) of
+ no_value ->
+ no_config;
+ Filename when is_list(Filename) ->
+ consult_config(State, Filename)
+ end.
+
+-spec first_value([Fun], State) -> no_value | Value when
+ Value :: any(),
+ State :: rebar_state:t(),
+ Fun :: fun ((State) -> no_value | Value).
+first_value([], _) -> no_value;
+first_value([Fun | Rest], State) ->
+ case Fun(State) of
+ no_value ->
+ first_value(Rest, State);
+ Value ->
+ Value
end.
--spec find_config_option(rebar_state:t()) -> [tuple()] | no_config.
+debug_get_value(Key, List, Default, Description) ->
+ case proplists:get_value(Key, List, Default) of
+ Default -> Default;
+ Value ->
+ ?DEBUG(Description, []),
+ Value
+ end.
+
+-spec find_config_option(rebar_state:t()) -> Filename::list() | no_value.
find_config_option(State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
- case proplists:get_value(config, Opts) of
- undefined ->
- no_config;
- Filename ->
- consult_config(State, Filename)
- end.
+ debug_get_value(config, Opts, no_value,
+ "Found config from command line option.").
--spec find_config_relx(rebar_state:t()) -> [tuple()] | no_config.
+-spec find_config_rebar(rebar_state:t()) -> [tuple()] | no_value.
+find_config_rebar(State) ->
+ debug_get_value(config, rebar_state:get(State, shell, []), no_value,
+ "Found config from rebar config file.").
+
+-spec find_config_relx(rebar_state:t()) -> [tuple()] | no_value.
find_config_relx(State) ->
- case proplists:get_value(sys_config, rebar_state:get(State, relx, [])) of
- undefined ->
- no_config;
- Filename ->
- consult_config(State, Filename)
- end.
+ debug_get_value(sys_config, rebar_state:get(State, relx, []), no_value,
+ "Found config from relx.").
-spec consult_config(rebar_state:t(), string()) -> [tuple()].
consult_config(State, Filename) ->