diff options
-rw-r--r-- | rebar.config | 2 | ||||
-rw-r--r-- | rebar.lock | 4 | ||||
-rw-r--r-- | src/rebar_app_discover.erl | 50 | ||||
-rw-r--r-- | src/rebar_dir.erl | 11 | ||||
-rw-r--r-- | src/rebar_prv_app_discovery.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_edoc.erl | 5 | ||||
-rw-r--r-- | src/rebar_prv_plugins_upgrade.erl | 3 | ||||
-rw-r--r-- | src/rebar_state.erl | 22 | ||||
-rw-r--r-- | test/rebar_dir_SUITE.erl | 31 | ||||
-rw-r--r-- | test/rebar_discover_SUITE.erl | 69 | ||||
-rw-r--r-- | test/rebar_edoc_SUITE.erl | 10 | ||||
-rw-r--r-- | test/rebar_edoc_SUITE_data/foo/apps/foo/rebar.config | 1 | ||||
-rw-r--r-- | test/rebar_edoc_SUITE_data/foo/rebar.config | 1 |
13 files changed, 178 insertions, 33 deletions
diff --git a/rebar.config b/rebar.config index 1de146c..c2f00fb 100644 --- a/rebar.config +++ b/rebar.config @@ -10,7 +10,7 @@ {bbmustache, "1.6.1"}, {relx, "3.32.1"}, {cf, "0.2.2"}, - {cth_readable, "1.4.4"}, + {cth_readable, "1.4.5"}, {eunit_formatters, "0.5.0"}]}. {post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)", @@ -2,7 +2,7 @@ [{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.6.1">>},0}, {<<"certifi">>,{pkg,<<"certifi">>,<<"2.5.1">>},0}, {<<"cf">>,{pkg,<<"cf">>,<<"0.2.2">>},0}, - {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.4.4">>},0}, + {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.4.5">>},0}, {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.3.1">>},0}, {<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.5.0">>},0}, {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0}, @@ -15,7 +15,7 @@ {<<"bbmustache">>, <<"9FB63FA60BD53AFBF47F02E6D8BD6B2BEAFC068E02E20975254DC7461FD4F397">>}, {<<"certifi">>, <<"867CE347F7C7D78563450A18A6A28A8090331E77FA02380B4A21962A65D36EE5">>}, {<<"cf">>, <<"7F2913FFF90ABCABD0F489896CFEB0B0674F6C8DF6C10B17A83175448029896C">>}, - {<<"cth_readable">>, <<"6CEFD2C293F5F04A80F7DB45D1BAFF70E720681AC98E6A11B5FEF1BF5B14B9FB">>}, + {<<"cth_readable">>, <<"BE3765763F9BEA87320F03F33B578875F8B3A4E8BD970EAE198AFF8A3F1AB38F">>}, {<<"erlware_commons">>, <<"0CE192AD69BC6FD0880246D852D0ECE17631E234878011D1586E053641ED4C04">>}, {<<"eunit_formatters">>, <<"6A9133943D36A465D804C1C5B6E6839030434B8879C5600D7DDB5B3BAD4CCB59">>}, {<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}, diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl index 0c97ad7..0c15bb2 100644 --- a/src/rebar_app_discover.erl +++ b/src/rebar_app_discover.erl @@ -85,7 +85,12 @@ define_root_app(Apps, State) -> format_error({module_list, File}) -> io_lib:format("Error reading module list from ~p~n", [File]); format_error({missing_module, Module}) -> - io_lib:format("Module defined in app file missing: ~p~n", [Module]). + io_lib:format("Module defined in app file missing: ~p~n", [Module]); +format_error({cannot_read_app_file, AppFile}) -> + io_lib:format("Cannot read app file: ~p~n", [AppFile]); +format_error({bad_term_file, _File, _Reason} = Error) -> + rebar_file_utils:format_error(Error). + %% @doc merges configuration of a project app and the top level state %% some configuration like erl_opts must be merged into a subapp's opts @@ -348,24 +353,31 @@ app_dir(AppFile) -> %% app file. -spec create_app_info(rebar_app_info:t(), file:name(), file:name()) -> rebar_app_info:t(). create_app_info(AppInfo, AppDir, AppFile) -> - [{application, AppName, AppDetails}] = rebar_config:consult_app_file(AppFile), - AppVsn = proplists:get_value(vsn, AppDetails), - Applications = proplists:get_value(applications, AppDetails, []), - IncludedApplications = proplists:get_value(included_applications, AppDetails, []), - AppInfo1 = rebar_app_info:name( - rebar_app_info:original_vsn( - rebar_app_info:dir(AppInfo, AppDir), AppVsn), AppName), - AppInfo2 = rebar_app_info:applications( - rebar_app_info:app_details(AppInfo1, AppDetails), - IncludedApplications++Applications), - Valid = case rebar_app_utils:validate_application_info(AppInfo2) =:= true - andalso rebar_app_info:has_all_artifacts(AppInfo2) =:= true of - true -> - true; - _ -> - false - end, - rebar_app_info:dir(rebar_app_info:valid(AppInfo2, Valid), AppDir). + try rebar_config:consult_app_file(AppFile) of + [{application, AppName, AppDetails}] -> + AppVsn = proplists:get_value(vsn, AppDetails), + Applications = proplists:get_value(applications, AppDetails, []), + IncludedApplications = proplists:get_value(included_applications, AppDetails, []), + AppInfo1 = rebar_app_info:name( + rebar_app_info:original_vsn( + rebar_app_info:dir(AppInfo, AppDir), AppVsn), AppName), + AppInfo2 = rebar_app_info:applications( + rebar_app_info:app_details(AppInfo1, AppDetails), + IncludedApplications++Applications), + Valid = case rebar_app_utils:validate_application_info(AppInfo2) =:= true + andalso rebar_app_info:has_all_artifacts(AppInfo2) =:= true of + true -> + true; + _ -> + false + end, + rebar_app_info:dir(rebar_app_info:valid(AppInfo2, Valid), AppDir); + _Invalid -> + throw({error, {?MODULE, {cannot_read_app_file, AppFile}}}) + catch + throw:{error, {rebar_file_utils, Err = {bad_term_file, _File, _Reason}}} -> + throw({error, {?MODULE, Err}}) % wrap this + end. %% @doc Read in and parse the .app file if it is availabe. Do the same for %% the .app.src file if it exists. diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index 17bc48e..aac6210 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -107,8 +107,15 @@ home_dir() -> %% may be stored. -spec global_config_dir(rebar_state:t()) -> file:filename_all(). global_config_dir(State) -> - Home = home_dir(), - rebar_state:get(State, global_rebar_dir, filename:join([Home, ".config", "rebar3"])). + filename:join([rebar_config_dir(State), ".config", "rebar3"]). + +rebar_config_dir(State) -> + case os:getenv("REBAR_GLOBAL_CONFIG_DIR") of + false -> + rebar_state:get(State, global_rebar_dir, home_dir()); + ConfDir -> + ConfDir + end. %% @doc returns the path of the global rebar.config file -spec global_config(rebar_state:t()) -> file:filename_all(). diff --git a/src/rebar_prv_app_discovery.erl b/src/rebar_prv_app_discovery.erl index f5bab49..20b7f90 100644 --- a/src/rebar_prv_app_discovery.erl +++ b/src/rebar_prv_app_discovery.erl @@ -43,6 +43,8 @@ do(State) -> {error, {rebar_packages, Error}}; throw:{error, {rebar_app_utils, Error}} -> {error, {rebar_app_utils, Error}}; + throw:{error, {rebar_app_discover, Error}} -> + {error, {rebar_app_discover, Error}}; throw:{error, Error} -> ?PRV_ERROR(Error) end. diff --git a/src/rebar_prv_edoc.erl b/src/rebar_prv_edoc.erl index c78296a..5e563ab 100644 --- a/src/rebar_prv_edoc.erl +++ b/src/rebar_prv_edoc.erl @@ -45,7 +45,10 @@ do(State) -> AppName = rebar_utils:to_list(rebar_app_info:name(AppInfo)), ?INFO("Running edoc for ~ts", [AppName]), AppDir = rebar_app_info:dir(AppInfo), - AppRes = (catch edoc:application(list_to_atom(AppName), AppDir, EdocOptsAcc)), + AppOpts = rebar_app_info:opts(AppInfo), + %% order of the merge is important to allow app opts overrides + AppEdocOpts = rebar_opts:get(AppOpts, edoc_opts, []) ++ EdocOptsAcc, + AppRes = (catch edoc:application(list_to_atom(AppName), AppDir, AppEdocOpts)), rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, AppInfo, State), case {AppRes, ShouldAccPaths} of {ok, true} -> diff --git a/src/rebar_prv_plugins_upgrade.erl b/src/rebar_prv_plugins_upgrade.erl index 7420c83..39107c9 100644 --- a/src/rebar_prv_plugins_upgrade.erl +++ b/src/rebar_prv_plugins_upgrade.erl @@ -90,8 +90,9 @@ find_plugin(Plugin, Profiles, State) -> build_plugin(AppInfo, Apps, State) -> Providers = rebar_state:providers(State), + Resources = rebar_state:resources(State), AppDir = rebar_app_info:dir(AppInfo), C = rebar_config:consult(AppDir), S = rebar_state:new(rebar_state:all_deps(rebar_state:new(), Apps), C, AppDir), AppInfo1 = rebar_app_info:update_opts(AppInfo, rebar_app_info:opts(AppInfo), C), - rebar_prv_compile:compile(S, Providers, AppInfo1). + rebar_prv_compile:compile(rebar_state:set_resources(S, Resources), Providers, AppInfo1). diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 31d3a08..e7d772f 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -71,7 +71,7 @@ all_plugin_deps = [] :: [rebar_app_info:t()], all_deps = [] :: [rebar_app_info:t()], - compilers = [] :: [{compiler_type(), extension(), extension(), compile_fun()}], + compilers = [] :: [module()], project_builders = [] :: [{rebar_app_info:project_type(), module()}], resources = [], providers = [], @@ -81,10 +81,6 @@ -type t() :: #state_t{}. --type compiler_type() :: atom(). --type extension() :: string(). --type compile_fun() :: fun(([file:filename()], rebar_app_info:t(), list()) -> ok). - -spec new() -> t(). new() -> BaseState = base_state(dict:new()), @@ -407,15 +403,31 @@ warn_old_resource(ResourceModule) -> ?WARN("Using custom resource ~s that implements a deprecated api. " "It should be upgraded to rebar_resource_v2.", [ResourceModule]). +%% @doc get a list of all registered compiler modules, which should implement +%% the `rebar_compiler' behaviour +-spec compilers(t()) -> [module()]. compilers(#state_t{compilers=Compilers}) -> Compilers. +%% @doc register compiler modules prior to the existing ones. Each compiler +%% module should implement the `rebar_compiler' behaviour. Use this when +%% your custom compiler generates .erl files (or files of another type) and +%% that should run before other compiler modules. +-spec prepend_compilers(t(), [module()]) -> t(). prepend_compilers(State=#state_t{compilers=Compilers}, NewCompilers) -> State#state_t{compilers=NewCompilers++Compilers}. +%% @doc register compiler modules. Each compiler +%% module should implement the `rebar_compiler' behaviour. Use this when +%% your custom compiler generates binary artifacts and does not have +%% a particular need to run before any other compiler. +-spec append_compilers(t(), [module()]) -> t(). append_compilers(State=#state_t{compilers=Compilers}, NewCompilers) -> State#state_t{compilers=Compilers++NewCompilers}. +%% @private reset all compiler modules by replacing them by a list of +%% modules that implement the `rebar_compiler' behaviour. +-spec compilers(t(), [module()]) -> t(). compilers(State, Compilers) -> State#state_t{compilers=Compilers}. diff --git a/test/rebar_dir_SUITE.erl b/test/rebar_dir_SUITE.erl index 81051e6..2a5d0ca 100644 --- a/test/rebar_dir_SUITE.erl +++ b/test/rebar_dir_SUITE.erl @@ -10,6 +10,7 @@ -export([profile_src_dir_opts/1]). -export([retarget_path/1, alt_base_dir_abs/1, alt_base_dir_rel/1]). -export([global_cache_dir/1, default_global_cache_dir/1, overwrite_default_global_cache_dir/1]). +-export([default_global_config/1, overwrite_default_global_config/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -21,7 +22,8 @@ all() -> [default_src_dirs, default_extra_src_dirs, default_all_src_dirs, profile_src_dirs, profile_extra_src_dirs, profile_all_src_dirs, profile_src_dir_opts, top_src_dirs, retarget_path, alt_base_dir_abs, alt_base_dir_rel, global_cache_dir, - default_global_cache_dir, overwrite_default_global_cache_dir]. + default_global_cache_dir, overwrite_default_global_cache_dir, + default_global_config, overwrite_default_global_config]. init_per_testcase(default_global_cache_dir, Config) -> [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, _State} | Config] = rebar_test_utils:init_rebar_state(Config), @@ -34,6 +36,19 @@ init_per_testcase(overwrite_default_global_cache_dir, Config) -> NewState = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])} ,{root_dir, AppsDir}]), [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, NewState} | Config]; +init_per_testcase(default_global_config, Config) -> + [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, _State} | Config] = rebar_test_utils:init_rebar_state(Config), + NewState = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])} + ,{root_dir, AppsDir}]), + [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, NewState} | Config]; +init_per_testcase(overwrite_default_global_config, Config) -> + ConfDir = filename:join([?config(priv_dir, Config), "custom"]), + ok = file:make_dir(ConfDir), + os:putenv("REBAR_GLOBAL_CONFIG_DIR", ConfDir), + [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, _State} | Config] = rebar_test_utils:init_rebar_state(Config), + NewState = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])} + ,{root_dir, AppsDir}]), + [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, NewState} | Config]; init_per_testcase(_, Config) -> C = rebar_test_utils:init_rebar_state(Config), AppDir = ?config(apps, C), @@ -282,3 +297,17 @@ overwrite_default_global_cache_dir(Config) -> {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), Expected = ?config(priv_dir, Config), ?assertEqual(Expected, rebar_dir:global_cache_dir(rebar_state:opts(State))). + +default_global_config(Config) -> + RebarConfig = [{erl_opts, []}], + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + ConfDir = ?config(priv_dir, Config), + Expected = filename:join([ConfDir, ".config", "rebar3", "rebar.config"]), + ?assertEqual(Expected, rebar_dir:global_config(State)). + +overwrite_default_global_config(Config) -> + RebarConfig = [{erl_opts, []}], + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + Expected = filename:join([os:getenv("REBAR_GLOBAL_CONFIG_DIR"), ".config", "rebar3", "rebar.config"]), + rebar_dir:global_config(State), + ?assertEqual(Expected, rebar_dir:global_config(State)). diff --git a/test/rebar_discover_SUITE.erl b/test/rebar_discover_SUITE.erl new file mode 100644 index 0000000..3fdd34b --- /dev/null +++ b/test/rebar_discover_SUITE.erl @@ -0,0 +1,69 @@ +-module(rebar_discover_SUITE). +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +all() -> + [empty_app_src, bad_app_src, invalid_app_src]. + %% note: invalid .app files without a .app.src also present + %% has rebar3 just ignoring the directory as not OTP-related. + + +init_per_testcase(_, Config) -> + NewConfig = rebar_test_utils:init_rebar_state(Config, "discover_app_"), + AppDir = ?config(apps, NewConfig), + + 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]), + + [{app_names, [Name]}, {vsns, [Vsn]}|NewConfig]. + +end_per_testcase(_, Config) -> + Config. + +empty_app_src() -> + [{doc, "when there's an empty .app.src file, exit with a good error " + "message rather than an uncaught exception"}]. +empty_app_src(Config) -> + AppDir = ?config(apps, Config), + [Name] = ?config(app_names, Config), + AppSrc = filename:join([AppDir, "src", Name ++ ".app.src"]), + ok = file:write_file(AppSrc, ""), + ?assertEqual( + {error, {rebar_app_discover, {cannot_read_app_file, AppSrc}}}, + rebar_test_utils:run_and_check(Config, [], ["compile"], return) + ), + ok. + +bad_app_src() -> + [{doc, "when there's a syntactically invalid " + ".app.src file, exit with a good error " + "message rather than an uncaught exception"}]. +bad_app_src(Config) -> + AppDir = ?config(apps, Config), + [Name] = ?config(app_names, Config), + AppSrc = filename:join([AppDir, "src", Name ++ ".app.src"]), + ok = file:write_file(AppSrc, "bad term file :("), + ?assertMatch( + {error, {rebar_app_discover, {bad_term_file, AppSrc, _}}}, + rebar_test_utils:run_and_check(Config, [], ["compile"], return) + ), + ok. + +invalid_app_src() -> + [{doc, "when there's a syntactically valid but semantically invalid " + ".app.src file, exit with a good error " + "message rather than an uncaught exception"}]. +invalid_app_src(Config) -> + AppDir = ?config(apps, Config), + [Name] = ?config(app_names, Config), + AppSrc = filename:join([AppDir, "src", Name ++ ".app.src"]), + ok = file:write_file(AppSrc, "{applications, name_but_no_args}."), + ?assertEqual( + {error, {rebar_app_discover, {cannot_read_app_file, AppSrc}}}, + rebar_test_utils:run_and_check(Config, [], ["compile"], return) + ), + ok. + diff --git a/test/rebar_edoc_SUITE.erl b/test/rebar_edoc_SUITE.erl index 64ec0c8..2f0fad0 100644 --- a/test/rebar_edoc_SUITE.erl +++ b/test/rebar_edoc_SUITE.erl @@ -52,7 +52,15 @@ multiapp(Config) -> "barer1")), ?assert(file_content_matches( filename:join([AppsDir, "apps", "foo", "doc", "foo.html"]), - "apps/bar1/doc/bar1.html")). + "apps/bar1/doc/bar1.html")), + %% Options such from rebar.config in the app themselves are + %% respected + ?assert(file_content_matches( + filename:join([AppsDir, "apps", "foo", "doc", "overview-summary.html"]), + "foo_custom_title" + )), + ok. + error_survival(Config) -> RebarConfig = [], diff --git a/test/rebar_edoc_SUITE_data/foo/apps/foo/rebar.config b/test/rebar_edoc_SUITE_data/foo/apps/foo/rebar.config new file mode 100644 index 0000000..970d4e2 --- /dev/null +++ b/test/rebar_edoc_SUITE_data/foo/apps/foo/rebar.config @@ -0,0 +1 @@ +{edoc_opts, [{title, "foo_custom_title"}]}. diff --git a/test/rebar_edoc_SUITE_data/foo/rebar.config b/test/rebar_edoc_SUITE_data/foo/rebar.config new file mode 100644 index 0000000..b5d44fa --- /dev/null +++ b/test/rebar_edoc_SUITE_data/foo/rebar.config @@ -0,0 +1 @@ +{edoc_opts, [{title, "forced wrong title to be overridden"}]}. |