diff options
-rw-r--r-- | src/rebar_dist_utils.erl | 89 | ||||
-rw-r--r-- | src/rebar_prv_shell.erl | 29 | ||||
-rw-r--r-- | test/rebar_dist_utils_SUITE.erl | 74 |
3 files changed, 165 insertions, 27 deletions
diff --git a/src/rebar_dist_utils.erl b/src/rebar_dist_utils.erl new file mode 100644 index 0000000..141c89d --- /dev/null +++ b/src/rebar_dist_utils.erl @@ -0,0 +1,89 @@ +%%% Common functions to boot/stop distributed setups for +%%% the rebar3 script. +-module(rebar_dist_utils). +-export([either/3, short/2, long/2, find_options/1]). +-include("rebar.hrl"). + +%%%%%%%%%%%%%%%%%% +%%% PUBLIC API %%% +%%%%%%%%%%%%%%%%%% +-spec either(Name::atom(), SName::atom(), Opts::[{setcookie,term()}]) -> atom(). +either(undefined, undefined, _) -> + 'nonode@nohost'; +either(Name, undefined, Opts) -> + long(Name, Opts), + node(); +either(undefined, SName, Opts) -> + short(SName, Opts), + node(); +either(_, _, _) -> + ?ABORT("Cannot have both short and long node names defined", []). + +short(Name, Opts) -> + start(Name, shortnames, Opts). + +long(Name, Opts) -> + start(Name, longnames, Opts). + +-spec find_options(rebar_state:state()) -> {Long, Short, Opts} when + Long :: atom(), + Short :: atom(), + Opts :: [{setcookie,term()}]. +find_options(State) -> + {Long, Short} = find_name_options(State), + case find_cookie_option(State) of + nocookie -> + {Long, Short, []}; + Cookie -> + {Long, Short, [{setcookie, Cookie}]} + end. + +%%%%%%%%%%%%%%% +%%% PRIVATE %%% +%%%%%%%%%%%%%%% +start(Name, Type, Opts) -> + check_epmd(net_kernel:start([Name, Type])), + setup_cookie(Opts). + +check_epmd({error,{{shutdown, {_,net_kernel,{'EXIT',nodistribution}}},_}}) -> + ?ERROR("Erlang Distribution failed, falling back to nonode@nohost. " + "Verify that epmd is running and try again.",[]); +check_epmd(_) -> + ok. + +setup_cookie(Opts) -> + case {node(), proplists:get_value(setcookie, Opts, nocookie)} of + {'nonode@nohost', _} -> nocookie; + {_, nocookie} -> nocookie; + {Node, Name} -> erlang:set_cookie(Node, Name) + end. + +find_name_options(State) -> + {Opts, _} = rebar_state:command_parsed_args(State), + %% First try the CLI + case {proplists:get_value(name, Opts), proplists:get_value(sname, Opts)} of + {undefined, undefined} -> + %% Else try the config file + DistOpts = rebar_state:get(State, dist, []), + %% Pick the first one seen to support profile merges + find_first_name(DistOpts); + Res -> + Res + end. + +find_first_name([]) -> {undefined, undefined}; +find_first_name([{sname,Val}|_]) -> {undefined, Val}; +find_first_name([{name,Val}|_]) -> {Val, undefined}; +find_first_name([_|Opts]) -> find_first_name(Opts). + +find_cookie_option(State) -> + {Opts, _} = rebar_state:command_parsed_args(State), + %% First try the CLI + case proplists:get_value(setcookie, Opts) of + undefined -> + %% Else try the config file + DistOpts = rebar_state:get(State, dist, []), + proplists:get_value(setcookie, DistOpts, nocookie); + Res -> + Res + end. diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl index d67f940..365ed66 100644 --- a/src/rebar_prv_shell.erl +++ b/src/rebar_prv_shell.erl @@ -269,33 +269,8 @@ simulate_proc_lib() -> put('$initial_call', {rebar_agent, init, 1}). 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} -> - check_epmd(net_kernel:start([Name, longnames])), - setup_cookie(Opts); - {undefined, SName} -> - check_epmd(net_kernel:start([SName, shortnames])), - setup_cookie(Opts); - {_, _} -> - ?ABORT("Cannot have both short and long node names defined", []) - end. - -check_epmd({error,{{shutdown, {_,net_kernel,{'EXIT',nodistribution}}},_}}) -> - ?ERROR("Erlang Distribution failed, falling back to nonode@nohost. " - "Verify that epmd is running and try again.",[]); -check_epmd(_) -> - ok. - -setup_cookie(Opts) -> - case {node(), proplists:get_value(setcookie, Opts, nocookie)} of - {'nonode@nohost', _} -> nocookie; - {_, nocookie} -> nocookie; - {Node, Name} -> erlang:set_cookie(Node, Name) - end. - + {Long, Short, Opts} = rebar_dist_utils:find_options(State), + rebar_dist_utils:either(Long, Short, Opts). find_apps_to_boot(State) -> %% Try the shell_apps option diff --git a/test/rebar_dist_utils_SUITE.erl b/test/rebar_dist_utils_SUITE.erl new file mode 100644 index 0000000..f0a71be --- /dev/null +++ b/test/rebar_dist_utils_SUITE.erl @@ -0,0 +1,74 @@ +%%% This suite currently only tests for options parsing since we do +%%% not know if epmd will be running to actually boot nodes. +-module(rebar_dist_utils_SUITE). +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-compile(export_all). + +all() -> [from_config, from_cli, overlap, from_config_profile]. + +init_per_testcase(_, Config0) -> + Config = rebar_test_utils:init_rebar_state(Config0), + AppDir = ?config(apps, Config), + Name = rebar_test_utils:create_random_name("app_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(filename:join([AppDir,"apps",Name]), Name, Vsn, [kernel, stdlib]), + Config. + + +end_per_testcase(_, _) -> + ok. + +from_config(Config) -> + ShortConfig = [{dist, [{sname, 'a@localhost'}, {setcookie, abc}]}], + LongConfig = [{dist, [{name, 'a@localhost.x'}, {setcookie, abc}]}], + BothConfig = [{dist, [{sname, 'a@localhost'}, {name, 'a@localhost.x'}, {setcookie,abc}]}], + NoConfig = [], + CookieConfig = [{dist, [{setcookie, def}]}], + NoCookie = [{dist, [{sname, 'a@localhost'}]}], + {ok, State0} = rebar_test_utils:run_and_check(Config, ShortConfig, ["version"], return), + {undefined, 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State0), + {ok, State1} = rebar_test_utils:run_and_check(Config, LongConfig, ["version"], return), + {'a@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State1), + %% only support the first name found, side-effect of wanting profile support + {ok, State2} = rebar_test_utils:run_and_check(Config, BothConfig, ["version"], return), + {undefined, 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State2), + {ok, State3} = rebar_test_utils:run_and_check(Config, NoConfig, ["version"], return), + {undefined, undefined, []} = rebar_dist_utils:find_options(State3), + {ok, State4} = rebar_test_utils:run_and_check(Config, CookieConfig, ["version"], return), + {undefined, undefined, [{setcookie, def}]} = rebar_dist_utils:find_options(State4), + {ok, State5} = rebar_test_utils:run_and_check(Config, NoCookie, ["version"], return), + {undefined, 'a@localhost', []} = rebar_dist_utils:find_options(State5), + ok. + +from_cli(Config) -> + {ok, State0} = rebar_test_utils:run_and_check(Config, [], ["version"], return), + {undefined, undefined, []} = rebar_dist_utils:find_options(State0), + State1 = rebar_state:command_parsed_args(State0, {[{sname, 'a@localhost'}, {setcookie,abc}], []}), + {undefined, 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State1), + State2 = rebar_state:command_parsed_args(State0, {[{name, 'a@localhost.x'}, {setcookie,abc}], []}), + {'a@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State2), + State3 = rebar_state:command_parsed_args(State0, {[{sname, 'a@localhost'}, {name, 'a@localhost.x'}, {setcookie,abc}], []}), + {'a@localhost.x', 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State3), + State4 = rebar_state:command_parsed_args(State0, {[{setcookie,def}], []}), + {undefined, undefined, [{setcookie, def}]} = rebar_dist_utils:find_options(State4), + State5 = rebar_state:command_parsed_args(State0, {[{sname, 'a@localhost'}], []}), + {undefined, 'a@localhost', []} = rebar_dist_utils:find_options(State5), + ok. + +overlap(Config) -> + %% Make sure that CLI config takes over rebar config without clash for names, though + %% cookies can pass through + RebarConfig = [{dist, [{sname, 'a@localhost'}, {setcookie, abc}]}], + {ok, State0} = rebar_test_utils:run_and_check(Config, RebarConfig, ["version"], return), + State1 = rebar_state:command_parsed_args(State0, {[{name, 'b@localhost.x'}], []}), + {'b@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State1), + ok. + +from_config_profile(Config) -> + %% running as a profile does not create name clashes + RebarConfig = [{dist, [{sname, 'a@localhost'}, {setcookie, abc}]}, + {profiles, [ {fake, [{dist, [{name, 'a@localhost.x'}]}]} ]}], + {ok, State0} = rebar_test_utils:run_and_check(Config, RebarConfig, ["as","fake","version"], return), + {'a@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State0), + ok. |