diff options
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | priv/shell-completion/bash/rebar3 | 2 | ||||
-rw-r--r-- | priv/shell-completion/fish/rebar3.fish | 8 | ||||
-rw-r--r-- | priv/shell-completion/zsh/_rebar3 | 8 | ||||
-rw-r--r-- | src/rebar.app.src | 1 | ||||
-rw-r--r-- | src/rebar3.erl | 8 | ||||
-rw-r--r-- | src/rebar_hooks.erl | 7 | ||||
-rw-r--r-- | src/rebar_packages.erl | 39 | ||||
-rw-r--r-- | src/rebar_prv_common_test.erl | 13 | ||||
-rw-r--r-- | src/rebar_prv_eunit.erl | 14 | ||||
-rw-r--r-- | src/rebar_prv_state.erl | 44 | ||||
-rw-r--r-- | src/rebar_relx.erl | 4 | ||||
-rw-r--r-- | src/rebar_state.erl | 17 | ||||
-rw-r--r-- | test/rebar_ct_SUITE.erl | 22 | ||||
-rw-r--r-- | test/rebar_hooks_SUITE.erl | 22 |
15 files changed, 173 insertions, 37 deletions
@@ -169,3 +169,4 @@ General rebar community resources and links: - [Documentation](http://www.rebar3.org/v3.0/docs) To contribute to rebar3, please refer to [CONTRIBUTING](CONTRIBUTING.md). + diff --git a/priv/shell-completion/bash/rebar3 b/priv/shell-completion/bash/rebar3 index eec9208..be9af44 100644 --- a/priv/shell-completion/bash/rebar3 +++ b/priv/shell-completion/bash/rebar3 @@ -93,7 +93,7 @@ _rebar3() elif [[ ${prev} == escriptize ]] ; then : elif [[ ${prev} == eunit ]] ; then - sopts="-c -e -v" + sopts="-c -e -v -d -f -m -s" lopts="--app --application --cover --dir --error_on_warning --file --module --suite --verbose" elif [[ ${prev} == help ]] ; then : diff --git a/priv/shell-completion/fish/rebar3.fish b/priv/shell-completion/fish/rebar3.fish index 1c0f155..fd28c97 100644 --- a/priv/shell-completion/fish/rebar3.fish +++ b/priv/shell-completion/fish/rebar3.fish @@ -131,11 +131,11 @@ complete -f -c 'rebar3' -n '__fish_rebar3_needs_command' -a eunit -d "Run EUnit complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l app -d "Comma separated list of application test suites to run. Equivalent to `[{application, App}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l application -d "Comma separated list of application test suites to run. Equivalent to `[{application, App}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s c -l cover -d "Generate cover data" -complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l dir -d "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`" +complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s d -l dir -d "Comma separated list of dirs to load tests from. Equivalent to `[{dir, Dir}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunut' -s e -l error_on_warning -d "Error on invalid test specifications instead of warning" -complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l file -d "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`" -complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l module -d "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`" -complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l suite -d "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`" +complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s f -l file -d "Comma separated list of files to load tests from. Equivalent to `[{file, File}]`" +complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s m -l module -d "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`" +complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s s -l suite -d "Comma separated list of modules to load tests from. Equivalent to `[{module, Module}]`" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -s v -l verbose -d "Verbose output" complete -f -c 'rebar3' -n '__fish_rebar3_using_command eunit' -l suite -d "Lists of test suites to run" diff --git a/priv/shell-completion/zsh/_rebar3 b/priv/shell-completion/zsh/_rebar3 index 76a76e5..95d1fa0 100644 --- a/priv/shell-completion/zsh/_rebar3 +++ b/priv/shell-completion/zsh/_rebar3 @@ -90,11 +90,11 @@ _rebar3 () { '(--app)--app[Comma separated list of application test suites to run]:suites' \ '(--application)--application[Comma separated list of application test suites to run]:applications' \ '(-c --cover)'{-c,--cover}'[Generate cover data]' \ - '(--dir)--dir[Comma separated list of dirs to load tests from]:dirs' \ + '(-d --dir)'{-d,--dir}'[Comma separated list of dirs to load tests from]:dirs' \ '(-e --error_on_warning)'{-e,--error_on_warning}'[Error on invalid test specifications instead of warning]' \ - '(--file)--file[Comma separated list of files to load tests from]:files' \ - '(--module)--module[Comma separated list of modules to load tests from]:modules' \ - '(--suite)--suite[Comma separated list of modules to load tests from]:modules' \ + '(-f --file)'{-f,--file}'[Comma separated list of files to load tests from]:files' \ + '(-m --module)'{-m,--module}'[Comma separated list of modules to load tests from]:modules' \ + '(-s --suite)'{-s,--suite}'[Comma separated list of modules to load tests from]:modules' \ '(-v --verbose)'{-v,--verbose}'[Verbose output]' \ && ret=0 ;; diff --git a/src/rebar.app.src b/src/rebar.app.src index 58fee02..bd0f871 100644 --- a/src/rebar.app.src +++ b/src/rebar.app.src @@ -66,6 +66,7 @@ rebar_prv_relup, rebar_prv_report, rebar_prv_shell, + rebar_prv_state, rebar_prv_tar, rebar_prv_unlock, rebar_prv_update, diff --git a/src/rebar3.erl b/src/rebar3.erl index 10eccfd..c1a1ae4 100644 --- a/src/rebar3.erl +++ b/src/rebar3.erl @@ -252,10 +252,10 @@ set_global_flag(State, Options, Flag) -> %% global_option_spec_list() -> [ - %% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg} - {help, $h, "help", undefined, "Print this help."}, - {version, $v, "version", undefined, "Show version information."}, - {task, undefined, undefined, string, "Task to run."} + %% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg} + {help, $h, "help", undefined, "Print this help."}, + {version, $v, "version", undefined, "Show version information."}, + {task, undefined, undefined, string, "Task to run."} ]. handle_error(rebar_abort) -> diff --git a/src/rebar_hooks.erl b/src/rebar_hooks.erl index 4e6d486..3af17ca 100644 --- a/src/rebar_hooks.erl +++ b/src/rebar_hooks.erl @@ -2,6 +2,7 @@ -export([run_all_hooks/5 ,run_all_hooks/6 + ,run_project_and_app_hooks/5 ,format_error/1]). -include("rebar.hrl"). @@ -20,6 +21,11 @@ run_all_hooks(Dir, Type, Command, Providers, State) -> run_provider_hooks(Dir, Type, Command, Providers, rebar_state:opts(State), State), run_hooks(Dir, Type, Command, rebar_state:opts(State), State). +run_project_and_app_hooks(Dir, Type, Command, Providers, State) -> + ProjectApps = rebar_state:project_apps(State), + [rebar_hooks:run_all_hooks(Dir, Type, Command, Providers, AppInfo, State) || AppInfo <- ProjectApps], + run_all_hooks(Dir, Type, Command, Providers, State). + run_provider_hooks(Dir, Type, Command, Providers, Opts, State) -> case rebar_opts:get(Opts, provider_hooks, []) of [] -> @@ -81,6 +87,7 @@ run_hooks(Dir, post, Command, Opts, State) -> run_hooks(Dir, Type, Command, Opts, State) -> case rebar_opts:get(Opts, Type, []) of [] -> + ?DEBUG("run_hooks(~p, ~p, ~p) -> no hooks defined\n", [Dir, Type, Command]), ok; Hooks -> Env = create_env(State, Opts), diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl index b5e0923..d4b8a14 100644 --- a/src/rebar_packages.erl +++ b/src/rebar_packages.erl @@ -67,22 +67,28 @@ deps(Name, Vsn, State) -> deps_(Name, Vsn, State) catch _:_ -> - handle_missing_package(Name, Vsn, State) + handle_missing_package({Name, Vsn}, State, fun(State1) -> deps_(Name, Vsn, State1) end) end. deps_(Name, Vsn, State) -> ?MODULE:verify_table(State), ets:lookup_element(?PACKAGE_TABLE, {ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)}, 2). -handle_missing_package(Name, Vsn, State) -> - ?INFO("Package ~s-~s not found. Fetching registry updates and trying again...", [Name, Vsn]), +handle_missing_package(Dep, State, Fun) -> + case Dep of + {Name, Vsn} -> + ?INFO("Package ~s-~s not found. Fetching registry updates and trying again...", [Name, Vsn]); + _ -> + ?INFO("Package ~p not found. Fetching registry updates and trying again...", [Dep]) + end, + {ok, State1} = rebar_prv_update:do(State), try - deps_(Name, Vsn, State1) + Fun(State1) catch _:_ -> %% Even after an update the package is still missing, time to error out - throw(?PRV_ERROR({missing_package, ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)})) + throw(?PRV_ERROR({missing_package, Dep})) end. registry_dir(State) -> @@ -144,6 +150,23 @@ find_highest_matching(Dep, Constraint, Table, State) -> find_highest_matching(undefined, undefined, Dep, Constraint, Table, State). find_highest_matching(Pkg, PkgVsn, Dep, Constraint, Table, State) -> + try find_highest_matching_(Pkg, PkgVsn, Dep, Constraint, Table, State) of + none -> + handle_missing_package(Dep, State, + fun(State1) -> + find_highest_matching_(Pkg, PkgVsn, Dep, Constraint, Table, State1) + end); + Result -> + Result + catch + _:_ -> + handle_missing_package(Dep, State, + fun(State1) -> + find_highest_matching_(Pkg, PkgVsn, Dep, Constraint, Table, State1) + end) + end. + +find_highest_matching_(Pkg, PkgVsn, Dep, Constraint, Table, State) -> try find_all(Dep, Table, State) of {ok, [Vsn]} -> handle_single_vsn(Pkg, PkgVsn, Dep, Vsn, Constraint); @@ -193,8 +216,10 @@ handle_single_vsn(Pkg, PkgVsn, Dep, Vsn, Constraint) -> {ok, Vsn} end. -format_error({missing_package, Package, Version}) -> - io_lib:format("Package not found in registry: ~s-~s.", [Package, Version]). +format_error({missing_package, {Name, Vsn}}) -> + io_lib:format("Package not found in registry: ~s-~s.", [ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)]); +format_error({missing_package, Dep}) -> + io_lib:format("Package not found in registry: ~p.", [Dep]). verify_table(State) -> ets:info(?PACKAGE_TABLE, named_table) =:= true orelse load_and_verify_version(State). diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl index ff1589c..8c5c4fa 100644 --- a/src/rebar_prv_common_test.erl +++ b/src/rebar_prv_common_test.erl @@ -52,14 +52,16 @@ do(State, Tests) -> %% Run ct provider prehooks Providers = rebar_state:providers(State), Cwd = rebar_dir:get_cwd(), - rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State), + + %% Run ct provider pre hooks for all project apps and top level project hooks + rebar_hooks:run_project_and_app_hooks(Cwd, pre, ?PROVIDER, Providers, State), case Tests of {ok, T} -> case run_tests(State, T) of ok -> - %% Run ct provider posthooks - rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State), + %% Run ct provider post hooks for all project apps and top level project hooks + rebar_hooks:run_project_and_app_hooks(Cwd, post, ?PROVIDER, Providers, State), rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), {ok, State}; Error -> @@ -167,7 +169,9 @@ cfgopts(State) -> ensure_opts([], Acc) -> lists:reverse(Acc); ensure_opts([{test_spec, _}|_Rest], _Acc) -> - ?PRV_ERROR({badconfig, "Test specs not supported"}); + ?PRV_ERROR({badconfig, "Test specs not supported. See http://www.rebar3.org/docs/running-tests#common-test"}); +ensure_opts([{cover, _}|_Rest], _Acc) -> + ?PRV_ERROR({badconfig, "Cover specs not supported. See http://www.rebar3.org/docs/running-tests#common-test"}); ensure_opts([{auto_compile, _}|_Rest], _Acc) -> ?PRV_ERROR({badconfig, "Auto compile not supported"}); ensure_opts([{suite, Suite}|Rest], Acc) when is_integer(hd(Suite)) -> @@ -669,4 +673,3 @@ help(verbose) -> "Verbose output"; help(_) -> "". - diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index a1a4408..c085ee4 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -56,14 +56,14 @@ do(State, Tests) -> %% Run eunit provider prehooks Providers = rebar_state:providers(State), Cwd = rebar_dir:get_cwd(), - rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State), + rebar_hooks:run_project_and_app_hooks(Cwd, pre, ?PROVIDER, Providers, State), case validate_tests(State, Tests) of {ok, T} -> case run_tests(State, T) of {ok, State1} -> %% Run eunit provider posthooks - rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State1), + rebar_hooks:run_project_and_app_hooks(Cwd, post, ?PROVIDER, Providers, State1), rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)), {ok, State1}; Error -> @@ -190,7 +190,7 @@ dedupe_tests({AppMods, TestMods}) -> %% in AppMods that will trigger it F = fun(Mod) -> M = filename:basename(Mod, ".erl"), - MatchesTest = fun(Dir) -> filename:basename(Dir, ".erl") ++ "_tests" == M end, + MatchesTest = fun(Dir) -> filename:basename(Dir, ".erl") ++ "_tests" == M end, case lists:any(MatchesTest, AppMods) of false -> {true, {module, list_to_atom(M)}}; true -> false @@ -457,10 +457,10 @@ eunit_opts(_State) -> [{app, undefined, "app", string, help(app)}, {application, undefined, "application", string, help(app)}, {cover, $c, "cover", boolean, help(cover)}, - {dir, undefined, "dir", string, help(dir)}, - {file, undefined, "file", string, help(file)}, - {module, undefined, "module", string, help(module)}, - {suite, undefined, "suite", string, help(module)}, + {dir, $d, "dir", string, help(dir)}, + {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}]`."; diff --git a/src/rebar_prv_state.erl b/src/rebar_prv_state.erl new file mode 100644 index 0000000..4fbcb67 --- /dev/null +++ b/src/rebar_prv_state.erl @@ -0,0 +1,44 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et + +-module(rebar_prv_state). + +-behaviour(provider). + +-export([init/1, + do/1, + format_error/1]). + +-include("rebar.hrl"). + +-define(PROVIDER, state). +-define(DEPS, []). + +%% =================================================================== +%% Public API +%% =================================================================== + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + Provider = providers:create( + [{name, ?PROVIDER}, + {module, ?MODULE}, + {bare, false}, + {deps, ?DEPS}, + {example, "rebar3 state"}, + {short_desc, "Print current configuration state"}, + {desc, "Display rebar configuration for debugging purpose"}, + {opts, []}]), + State1 = rebar_state:add_provider(State, Provider), + {ok, State1}. + +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + L = rebar_state:to_list(State), + ?CONSOLE("State:", []), + [?CONSOLE(" ~w: ~p", [K, V]) || {K,V} <- L], + {ok, State}. + +-spec format_error(any()) -> iolist(). +format_error(Reason) -> + io_lib:format("~p", [Reason]). diff --git a/src/rebar_relx.erl b/src/rebar_relx.erl index 45e1c96..125da47 100644 --- a/src/rebar_relx.erl +++ b/src/rebar_relx.erl @@ -25,7 +25,7 @@ do(Module, Command, Provider, State) -> AllOptions = string:join([Command | Options], " "), Cwd = rebar_state:dir(State), Providers = rebar_state:providers(State), - rebar_hooks:run_all_hooks(Cwd, pre, Provider, Providers, State), + rebar_hooks:run_project_and_app_hooks(Cwd, pre, Provider, Providers, State), try case rebar_state:get(State, relx, []) of [] -> @@ -37,7 +37,7 @@ do(Module, Command, Provider, State) -> ,{config, Config1} ,{caller, api} | output_dir(OutputDir, Options)], AllOptions) end, - rebar_hooks:run_all_hooks(Cwd, post, Provider, Providers, State), + rebar_hooks:run_project_and_app_hooks(Cwd, post, Provider, Providers, State), {ok, State} catch throw:T -> diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 30eff2f..a613a00 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -36,6 +36,8 @@ deps_names/1, + to_list/1, + resources/1, resources/2, add_resource/2, providers/1, providers/2, add_provider/2, allow_provider_overrides/1, allow_provider_overrides/2 @@ -418,6 +420,21 @@ create_logic_providers(ProviderModules, State0) -> throw({error, "Failed creating providers. Run with DEBUG=1 for stacktrace."}) end. +to_list(#state_t{} = State) -> + Fields = record_info(fields, state_t), + Values = tl(tuple_to_list(State)), + DictSz = tuple_size(dict:new()), + lists:zip(Fields, [reformat(I, DictSz) || I <- Values]). + +reformat({K,V}, DSz) when is_list(V) -> + {K, [reformat(I, DSz) || I <- V]}; +reformat(V, DSz) when is_tuple(V), element(1,V) =:= dict, tuple_size(V) =:= DSz -> + [reformat(I, DSz) || I <- dict:to_list(V)]; +reformat({K,V}, DSz) when is_tuple(V), element(1,V) =:= dict, tuple_size(V) =:= DSz -> + {K, [reformat(I, DSz) || I <- dict:to_list(V)]}; +reformat(Other, _DSz) -> + Other. + %% =================================================================== %% Internal functions %% =================================================================== diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl index 9532b15..73473b2 100644 --- a/test/rebar_ct_SUITE.erl +++ b/test/rebar_ct_SUITE.erl @@ -42,6 +42,7 @@ cfg_opts/1, cfg_arbitrary_opts/1, cfg_test_spec/1, + cfg_cover_spec/1, cfg_atom_suites/1, cover_compiled/1, misspecified_ct_opts/1, @@ -57,7 +58,7 @@ all() -> [{group, basic_app}, {group, ct_opts}, {group, cover}, cfg_opts, cfg_arbitrary_opts, - cfg_test_spec, + cfg_test_spec, cfg_cover_spec, cfg_atom_suites, misspecified_ct_opts, misspecified_ct_compile_opts, @@ -1050,7 +1051,24 @@ cfg_test_spec(Config) -> {error, {rebar_prv_common_test, Error}} = rebar_prv_common_test:prepare_tests(State), - {badconfig, "Test specs not supported"} = Error. + {badconfig, "Test specs not supported. See http://www.rebar3.org/docs/running-tests#common-test"} = Error. + +cfg_cover_spec(Config) -> + C = rebar_test_utils:init_rebar_state(Config, "ct_cfg_cover_spec_opts_"), + + AppDir = ?config(apps, C), + + Name = rebar_test_utils:create_random_name("ct_cfg_cover_spec_opts_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [{ct_opts, [{cover, "spec/foo.spec"}]}], + + {ok, State} = rebar_test_utils:run_and_check(C, RebarConfig, ["as", "test", "lock"], return), + + {error, {rebar_prv_common_test, Error}} = rebar_prv_common_test:prepare_tests(State), + + {badconfig, "Cover specs not supported. See http://www.rebar3.org/docs/running-tests#common-test"} = Error. cfg_atom_suites(Config) -> C = rebar_test_utils:init_rebar_state(Config, "ct_cfg_atom_suites_"), diff --git a/test/rebar_hooks_SUITE.erl b/test/rebar_hooks_SUITE.erl index 188fb34..b121dd5 100644 --- a/test/rebar_hooks_SUITE.erl +++ b/test/rebar_hooks_SUITE.erl @@ -10,6 +10,7 @@ escriptize_artifacts/1, run_hooks_once/1, run_hooks_for_plugins/1, + eunit_app_hooks/1, deps_hook_namespace/1]). -include_lib("common_test/include/ct.hrl"). @@ -33,7 +34,7 @@ end_per_testcase(_, _Config) -> all() -> [build_and_clean_app, run_hooks_once, escriptize_artifacts, - run_hooks_for_plugins, deps_hook_namespace]. + run_hooks_for_plugins, deps_hook_namespace, eunit_app_hooks]. %% Test post provider hook cleans compiled project app, leaving it invalid build_and_clean_app(Config) -> @@ -119,6 +120,25 @@ deps_hook_namespace(Config) -> {ok, [{dep, "some_dep"}]} ). +%% Checks that a hook that is defined on an app (not a top level hook of a project with subapps) is run +eunit_app_hooks(Config) -> + AppDir = ?config(apps, Config), + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RConfFile = + rebar_test_utils:create_config(AppDir, + [ + {escript_name, list_to_atom(Name)} + ,{provider_hooks, [{post, [{eunit, escriptize}]}]} + ]), + {ok, RConf} = file:consult(RConfFile), + + rebar_test_utils:run_and_check(Config, RConf, + ["eunit"], {ok, [{app, Name, valid} + ,{file, filename:join([AppDir, "_build/test/bin", Name])}]}). + run_hooks_for_plugins(Config) -> AppDir = ?config(apps, Config), |