summaryrefslogtreecommitdiff
path: root/src/rebar_prv_shell.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rebar_prv_shell.erl')
-rw-r--r--src/rebar_prv_shell.erl151
1 files changed, 115 insertions, 36 deletions
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index 8c0b7ff..c80badf 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -45,14 +45,25 @@
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
- State1 = rebar_state:add_provider(State, providers:create([{name, ?PROVIDER},
- {module, ?MODULE},
- {bare, false},
- {deps, ?DEPS},
- {example, "rebar3 shell"},
- {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."}]}])),
+ State1 = rebar_state:add_provider(
+ State,
+ providers:create([
+ {name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "rebar3 shell"},
+ {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."},
+ {name, undefined, "name", atom,
+ "Gives a long name to the node."},
+ {sname, undefined, "sname", atom,
+ "Gives a short name to the node."}]}
+ ])
+ ),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
@@ -72,6 +83,18 @@ format_error(Reason) ->
%% immediately kill the script. ctrl-g, however, works fine
shell(State) ->
+ setup_name(State),
+ setup_paths(State),
+ maybe_boot_apps(State),
+ setup_shell(),
+ rebar_agent:start_link(State),
+ %% this call never returns (until user quits shell)
+ timer:sleep(infinity).
+
+info() ->
+ "Start a shell with project and deps preloaded similar to~n'erl -pa ebin -pa deps/*/ebin'.~n".
+
+setup_shell() ->
%% scan all processes for any with references to the old user and save them to
%% update later
NeedsUpdate = [Pid || Pid <- erlang:processes(),
@@ -91,18 +114,85 @@ shell(State) ->
%% disable the simple error_logger (which may have been added multiple
%% times). removes at most the error_logger added by init and the
%% error_logger added by the tty handler
- ok = remove_error_handler(3),
+ ok = remove_error_handler(3).
+
+setup_paths(State) ->
%% Add deps to path
code:add_pathsa(rebar_state:code_paths(State, all_deps)),
%% add project app test paths
- ok = add_test_paths(State),
- %% try to read in sys.config file
- ok = reread_config(State),
- %% this call never returns (until user quits shell)
- timer:sleep(infinity).
+ ok = add_test_paths(State).
-info() ->
- "Start a shell with project and deps preloaded similar to~n'erl -pa ebin -pa deps/*/ebin'.~n".
+maybe_boot_apps(State) ->
+ case find_apps_to_boot(State) of
+ undefined ->
+ %% try to read in sys.config file
+ ok = reread_config(State);
+ Apps ->
+ %% load apps, then check config, then boot them.
+ load_apps(Apps),
+ ok = reread_config(State),
+ boot_apps(Apps)
+ end.
+
+setup_name(State) ->
+ {Opts, _} = rebar_state:command_parsed_args(State),
+ case {proplists:get_value(name, Opts), proplists:get_value(sname, Opts)} of
+ {undefined, undefined} ->
+ ok;
+ {Name, undefined} ->
+ net_kernel:start([Name, longnames]);
+ {undefined, SName} ->
+ net_kernel:start([SName, shortnames]);
+ {_, _} ->
+ ?ABORT("Cannot have both short and long node names defined", [])
+ end.
+
+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;
+ Apps ->
+ Apps
+ end.
+
+load_apps(Apps) ->
+ [case application:load(App) of
+ ok ->
+ {ok, Ks} = application:get_all_key(App),
+ load_apps(proplists:get_value(applications, Ks));
+ _ ->
+ error % will be caught when starting the app
+ end || App <- Apps,
+ not lists:keymember(App, 1, application:loaded_applications())],
+ ok.
+
+reread_config(State) ->
+ case find_config(State) of
+ no_config ->
+ ok;
+ ConfigList ->
+ _ = [application:set_env(Application, Key, Val)
+ || {Application, Items} <- ConfigList,
+ {Key, Val} <- Items],
+ ok
+ end.
+
+boot_apps(Apps) ->
+ ?WARN("The rebar3 shell is a development tool; to deploy "
+ "applications in production, consider using releases "
+ "(http://www.rebar3.org/v3.0/docs/releases)", []),
+ Res = [application:ensure_all_started(App) || App <- Apps],
+ _ = [?INFO("Booted ~p", [App])
+ || {ok, Booted} <- Res,
+ App <- Booted],
+ _ = [?ERROR("Failed to boot ~p for reason ~p", [App, Reason])
+ || {error, {App, Reason}} <- Res],
+ ok.
remove_error_handler(0) ->
?WARN("Unable to remove simple error_logger handler", []);
@@ -124,28 +214,14 @@ wait_until_user_started(Timeout) ->
end.
add_test_paths(State) ->
- lists:foreach(fun(App) ->
- AppDir = rebar_app_info:out_dir(App),
- %% ignore errors resulting from non-existent directories
- _ = code:add_path(filename:join([AppDir, "test"]))
- end, rebar_state:project_apps(State)),
+ _ = [begin
+ AppDir = rebar_app_info:out_dir(App),
+ %% ignore errors resulting from non-existent directories
+ _ = code:add_path(filename:join([AppDir, "test"]))
+ end || App <- rebar_state:project_apps(State)],
_ = code:add_path(filename:join([rebar_dir:base_dir(State), "test"])),
ok.
-reread_config(State) ->
- case find_config(State) of
- no_config ->
- ok;
- ConfigList ->
- lists:foreach(fun ({Application, Items}) ->
- lists:foreach(fun ({Key, Val}) ->
- application:set_env(Application, Key, Val)
- end,
- Items)
- end,
- ConfigList)
- end.
-
% First try the --config flag, then try the relx sys_config
-spec find_config(rebar_state:t()) -> [tuple()] | no_config.
find_config(State) ->
@@ -179,4 +255,7 @@ find_config_relx(State) ->
consult_config(State, Filename) ->
Fullpath = filename:join(rebar_dir:root_dir(State), Filename),
?DEBUG("Loading configuration from ~p", [Fullpath]),
- rebar_file_utils:try_consult(Fullpath).
+ case rebar_file_utils:try_consult(Fullpath) of
+ [T] -> T;
+ [] -> []
+ end.