diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar.hrl | 2 | ||||
-rw-r--r-- | src/rebar_agent.erl | 17 | ||||
-rw-r--r-- | src/rebar_dist_utils.erl | 89 | ||||
-rw-r--r-- | src/rebar_git_resource.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_common_test.erl | 22 | ||||
-rw-r--r-- | src/rebar_prv_dialyzer.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_edoc.erl | 8 | ||||
-rw-r--r-- | src/rebar_prv_eunit.erl | 27 | ||||
-rw-r--r-- | src/rebar_prv_packages.erl | 32 | ||||
-rw-r--r-- | src/rebar_prv_path.erl | 8 | ||||
-rw-r--r-- | src/rebar_prv_report.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_shell.erl | 68 |
12 files changed, 210 insertions, 69 deletions
diff --git a/src/rebar.hrl b/src/rebar.hrl index f4e7f5e..0b7f0b1 100644 --- a/src/rebar.hrl +++ b/src/rebar.hrl @@ -22,7 +22,7 @@ -define(DEFAULT_TEST_DEPS_DIR, "test/lib"). -define(DEFAULT_RELEASE_DIR, "rel"). -define(DEFAULT_CONFIG_FILE, "rebar.config"). --define(DEFAULT_CDN, "https://s3.amazonaws.com/s3.hex.pm/"). +-define(DEFAULT_CDN, "https://repo.hex.pm/"). -define(REMOTE_PACKAGE_DIR, "tarballs"). -define(REMOTE_REGISTRY_FILE, "registry.ets.gz"). -define(LOCK_FILE, "rebar.lock"). diff --git a/src/rebar_agent.erl b/src/rebar_agent.erl index 2b69812..95818d8 100644 --- a/src/rebar_agent.erl +++ b/src/rebar_agent.erl @@ -86,6 +86,8 @@ refresh_paths(RState) -> || App <- rebar_state:project_apps(RState)] %% make sure to never reload self; halt()s the VM ) -- [filename:dirname(code:which(?MODULE))], + %% Modules from apps we can't reload without breaking functionality + Blacklist = [ec_cmd_log, providers, cf, cth_readable], %% Similar to rebar_utils:update_code/1, but also forces a reload %% of used modules. Also forces to reload all of ebin/ instead %% of just the modules in the .app file, because 'extra_src_dirs' @@ -102,11 +104,16 @@ refresh_paths(RState) -> undefined -> code:add_patha(Path), ok; - {ok, _} -> - ?DEBUG("reloading ~p from ~s", [Modules, Path]), - code:replace_path(App, Path), - [begin code:purge(M), code:delete(M), code:load_file(M) end - || M <- Modules] + {ok, Mods} -> + case {length(Mods), length(Mods -- Blacklist)} of + {X,X} -> + ?DEBUG("reloading ~p from ~s", [Modules, Path]), + code:replace_path(App, Path), + [begin code:purge(M), code:delete(M), code:load_file(M) end + || M <- Modules]; + {_,_} -> + ?DEBUG("skipping app ~p, stable copy required", [App]) + end end end, ToRefresh). diff --git a/src/rebar_dist_utils.erl b/src/rebar_dist_utils.erl new file mode 100644 index 0000000..f462826 --- /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_node, []), + %% 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_node, []), + proplists:get_value(setcookie, DistOpts, nocookie); + Res -> + Res + end. diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl index 876d047..5a6a5ef 100644 --- a/src/rebar_git_resource.erl +++ b/src/rebar_git_resource.erl @@ -201,7 +201,7 @@ parse_tags(Dir) -> {error, _} -> {undefined, "0.0.0"}; {ok, Line} -> - case re:run(Line, "(\\(|\\s)(HEAD,\\s)tag:\\s(v?([^,\\)]+))", [{capture, [3, 4], list}]) of + case re:run(Line, "(\\(|\\s)(HEAD[^,]*,\\s)tag:\\s(v?([^,\\)]+))", [{capture, [3, 4], list}]) of {match,[Tag, Vsn]} -> {Tag, Vsn}; nomatch -> diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index 6b94f79..5712fbf 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -37,6 +37,7 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> + setup_name(State), Tests = prepare_tests(State), case compile(State, Tests) of %% successfully compiled apps @@ -105,6 +106,10 @@ format_error({multiple_errors, Errors}) -> %% Internal functions %% =================================================================== +setup_name(State) -> + {Long, Short, Opts} = rebar_dist_utils:find_options(State), + rebar_dist_utils:either(Long, Short, Opts). + prepare_tests(State) -> %% command line test options CmdOpts = cmdopts(State), @@ -189,8 +194,10 @@ ensure_opts([{suite, Suites}|Rest], Acc) -> ensure_opts(Rest, [NewSuites|Acc]); ensure_opts([{K, V}|Rest], Acc) -> ensure_opts(Rest, [{K, V}|Acc]); -ensure_opts([V|_Rest], _Acc) -> - ?PRV_ERROR({badconfig, {"Member `~p' of option `~p' must be a 2-tuple", {V, ct_opts}}}). +%% pass through other options, in case of things like config terms +%% in `ct_opts` +ensure_opts([V|Rest], Acc) -> + ensure_opts(Rest, [V|Acc]). add_hooks(Opts, State) -> case {readable(State), lists:keyfind(ct_hooks, 1, Opts)} of @@ -637,7 +644,10 @@ ct_opts(_State) -> {create_priv_dir, undefined, "create_priv_dir", string, help(create_priv_dir)}, {include, undefined, "include", string, help(include)}, {readable, undefined, "readable", boolean, help(readable)}, - {verbose, $v, "verbose", boolean, help(verbose)} + {verbose, $v, "verbose", boolean, help(verbose)}, + {name, undefined, "name", atom, help(name)}, + {sname, undefined, "sname", atom, help(sname)}, + {setcookie, undefined, "setcookie", atom, help(setcookie)} ]. help(dir) -> @@ -692,5 +702,11 @@ help(readable) -> "Shows test case names and only displays logs to shell on failures"; help(verbose) -> "Verbose output"; +help(name) -> + "Gives a long name to the node"; +help(sname) -> + "Gives a short name to the node"; +help(setcookie) -> + "Sets the cookie if the node is distributed"; help(_) -> "". diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index 834eb98..622ee60 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -97,7 +97,7 @@ do(State) -> end. %% This is used to workaround dialyzer quirk discussed here -%% https://github.com/rebar/rebar3/pull/489#issuecomment-107953541 +%% https://github.com/erlang/rebar3/pull/489#issuecomment-107953541 %% Dialyzer gets default plt location wrong way by peeking HOME environment %% variable which usually is not defined on Windows. maybe_fix_env() -> diff --git a/src/rebar_prv_edoc.erl b/src/rebar_prv_edoc.erl index e7048b6..6cefe14 100644 --- a/src/rebar_prv_edoc.erl +++ b/src/rebar_prv_edoc.erl @@ -32,13 +32,19 @@ init(State) -> do(State) -> code:add_pathsa(rebar_state:code_paths(State, all_deps)), ProjectApps = rebar_state:project_apps(State), + Providers = rebar_state:providers(State), EDocOpts = rebar_state:get(State, edoc_opts, []), + Cwd = rebar_state:dir(State), + rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State), lists:foreach(fun(AppInfo) -> + rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, AppInfo, State), AppName = ec_cnv:to_list(rebar_app_info:name(AppInfo)), ?INFO("Running edoc for ~s", [AppName]), AppDir = rebar_app_info:dir(AppInfo), - ok = edoc:application(list_to_atom(AppName), AppDir, EDocOpts) + ok = edoc:application(list_to_atom(AppName), AppDir, EDocOpts), + rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, AppInfo, State) end, ProjectApps), + rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State), rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), {ok, State}. diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index 46ea48d..942fd10 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -51,6 +51,7 @@ do(State) -> do(State, Tests) -> ?INFO("Performing EUnit tests...", []), + setup_name(State), rebar_utils:update_code(rebar_state:code_paths(State, all_deps), [soft_purge]), %% Run eunit provider prehooks @@ -106,6 +107,10 @@ format_error({error, Error}) -> %% Internal functions %% =================================================================== +setup_name(State) -> + {Long, Short, Opts} = rebar_dist_utils:find_options(State), + rebar_dist_utils:either(Long, Short, Opts). + prepare_tests(State) -> %% parse and translate command line tests CmdTests = resolve_tests(State), @@ -479,11 +484,17 @@ eunit_opts(_State) -> {file, $f, "file", string, help(file)}, {module, $m, "module", string, help(module)}, {suite, $s, "suite", string, help(module)}, - {verbose, $v, "verbose", boolean, help(verbose)}]. - -help(app) -> "Comma separated list of application test suites to run. Equivalent to `[{application, App}]`."; -help(cover) -> "Generate cover data. Defaults to false."; -help(dir) -> "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`."; -help(file) -> "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`."; -help(module) -> "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`."; -help(verbose) -> "Verbose output. Defaults to false.". + {verbose, $v, "verbose", boolean, help(verbose)}, + {name, undefined, "name", atom, help(name)}, + {sname, undefined, "sname", atom, help(sname)}, + {setcookie, undefined, "setcookie", atom, help(setcookie)}]. + +help(app) -> "Comma separated list of application test suites to run. Equivalent to `[{application, App}]`."; +help(cover) -> "Generate cover data. Defaults to false."; +help(dir) -> "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`."; +help(file) -> "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`."; +help(module) -> "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`."; +help(verbose) -> "Verbose output. Defaults to false."; +help(name) -> "Gives a long name to the node"; +help(sname) -> "Gives a short name to the node"; +help(setcookie) -> "Sets the cookie if the node is distributed". diff --git a/src/rebar_prv_packages.erl b/src/rebar_prv_packages.erl index 998320c..7217ab8 100644 --- a/src/rebar_prv_packages.erl +++ b/src/rebar_prv_packages.erl @@ -28,22 +28,19 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> rebar_packages:packages(State), - print_packages(), + case rebar_state:command_args(State) of + [Name] -> + print_packages(get_packages(iolist_to_binary(Name))); + _ -> + print_packages(sort_packages()) + end, {ok, State}. -spec format_error(any()) -> iolist(). format_error(load_registry_fail) -> "Failed to load package regsitry. Try running 'rebar3 update' to fix". -print_packages() -> - SortedPkgs = ets:foldl(fun({package_index_version, _}, Acc) -> - Acc; - ({Pkg, Vsns}, Acc) -> - orddict:store(Pkg, Vsns, Acc); - (_, Acc) -> - Acc - end, orddict:new(), ?PACKAGE_TABLE), - +print_packages(Pkgs) -> orddict:map(fun(Name, Vsns) -> SortedVsns = lists:sort(fun(A, B) -> ec_semver:lte(ec_semver:parse(A) @@ -51,7 +48,20 @@ print_packages() -> end, Vsns), VsnStr = join(SortedVsns, <<", ">>), ?CONSOLE("~s:~n Versions: ~s~n", [Name, VsnStr]) - end, SortedPkgs). + end, Pkgs). + +sort_packages() -> + ets:foldl(fun({package_index_version, _}, Acc) -> + Acc; + ({Pkg, Vsns}, Acc) -> + orddict:store(Pkg, Vsns, Acc); + (_, Acc) -> + Acc + end, orddict:new(), ?PACKAGE_TABLE). + +get_packages(Name) -> + ets:lookup(?PACKAGE_TABLE, Name). + -spec join([binary()], binary()) -> binary(). join([Bin], _Sep) -> diff --git a/src/rebar_prv_path.erl b/src/rebar_prv_path.erl index 37c9834..4e88496 100644 --- a/src/rebar_prv_path.erl +++ b/src/rebar_prv_path.erl @@ -95,10 +95,14 @@ print_paths_if_exist(Paths, State) -> project_deps(State) -> Profiles = rebar_state:current_profiles(State), - List = lists:foldl(fun(Profile, Acc) -> rebar_state:get(State, {deps, Profile}, []) ++ Acc end, [], Profiles), - Deps = [normalize(Name) || {Name, _} <- List], + DepList = lists:foldl(fun(Profile, Acc) -> rebar_state:get(State, {deps, Profile}, []) ++ Acc end, [], Profiles), + LockList = lists:foldl(fun(Profile, Acc) -> rebar_state:get(State, {locks, Profile}, []) ++ Acc end, [], Profiles), + Deps = [normalize(name(Dep)) || Dep <- DepList++LockList], lists:usort(Deps). +name(App) when is_tuple(App) -> element(1, App); +name(Name) when is_binary(Name); is_list(Name); is_atom(Name) -> Name. + normalize(AppName) when is_list(AppName) -> AppName; normalize(AppName) when is_atom(AppName) -> atom_to_list(AppName); normalize(AppName) when is_binary(AppName) -> binary_to_list(AppName). diff --git a/src/rebar_prv_report.erl b/src/rebar_prv_report.erl index 587fad7..d6c8b60 100644 --- a/src/rebar_prv_report.erl +++ b/src/rebar_prv_report.erl @@ -13,7 +13,7 @@ -define(PROVIDER, report). -define(DEPS, []). --define(ISSUES_URL, "https://github.com/rebar/rebar3/issues"). +-define(ISSUES_URL, "https://github.com/erlang/rebar3/issues"). %% =================================================================== %% Public API diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl index 430d1e8..0ede495 100644 --- a/src/rebar_prv_shell.erl +++ b/src/rebar_prv_shell.erl @@ -133,11 +133,25 @@ kill_old_user() -> %% fully die [P] = [P || P <- element(2,process_info(whereis(user), links)), is_port(P)], user ! {'EXIT', P, normal}, % pretend the port died, then the port can die! + exit(P, kill), + wait_for_port_death(1000, P), OldUser. +wait_for_port_death(N, _) when N < 0 -> + %% This risks displaying a warning! + whatever; +wait_for_port_death(N, P) -> + case erlang:port_info(P) of + undefined -> + ok; + _ -> + timer:sleep(10), + wait_for_port_death(N-10, P) + end. + setup_new_shell() -> - %% terminate the current user supervision structure - ok = supervisor:terminate_child(kernel_sup, user), + %% terminate the current user supervision structure, if any + _ = supervisor:terminate_child(kernel_sup, user), %% start a new shell (this also starts a new user under the correct group) _ = user_drv:start(), %% wait until user_drv and user have been registered (max 3 seconds) @@ -178,7 +192,9 @@ rewrite_leaders(OldUser, NewUser) -> %% 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 - remove_error_handler(3) + remove_error_handler(3), + %% reset the tty handler once more for remote shells + error_logger:swap_handler(tty) catch E:R -> % may fail with custom loggers ?DEBUG("Logger changes failed for ~p:~p (~p)", [E,R,erlang:get_stacktrace()]), @@ -255,33 +271,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 @@ -339,7 +330,8 @@ reread_config(State) -> ConfigList -> try [application:set_env(Application, Key, Val) - || {Application, Items} <- ConfigList, + || Config <- ConfigList, + {Application, Items} <- Config, {Key, Val} <- Items] catch _:_ -> ?ERROR("The configuration file submitted could not be read " @@ -402,7 +394,7 @@ add_test_paths(State) -> ok. % First try the --config flag, then try the relx sys_config --spec find_config(rebar_state:t()) -> [tuple()] | no_config. +-spec find_config(rebar_state:t()) -> [[tuple()]] | no_config. find_config(State) -> case first_value([fun find_config_option/1, fun find_config_rebar/1, @@ -450,11 +442,17 @@ find_config_relx(State) -> debug_get_value(sys_config, rebar_state:get(State, relx, []), no_value, "Found config from relx."). --spec consult_config(rebar_state:t(), string()) -> [tuple()]. +-spec consult_config(rebar_state:t(), string()) -> [[tuple()]]. consult_config(State, Filename) -> Fullpath = filename:join(rebar_dir:root_dir(State), Filename), ?DEBUG("Loading configuration from ~p", [Fullpath]), - case rebar_file_utils:try_consult(Fullpath) of + Config = case rebar_file_utils:try_consult(Fullpath) of [T] -> T; [] -> [] - end. + end, + SubConfigs = [consult_config(State, Entry ++ ".config") || + Entry <- Config, is_list(Entry) + ], + + [Config | lists:merge(SubConfigs)]. + |