From b72c19c12cfaa3cfae335a63372c252c819548e1 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Tue, 8 Sep 2015 00:04:52 +0900 Subject: Add rebar_set/0 type --- src/rebar.hrl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rebar.hrl b/src/rebar.hrl index 961b8ea..8ad0faa 100644 --- a/src/rebar.hrl +++ b/src/rebar.hrl @@ -43,6 +43,12 @@ -type rebar_digraph() :: digraph(). -endif. +-ifdef(namespaced_types). +-type rebar_set() :: sets:set(). +-else. +-type rebar_set() :: set(). +-endif. + -define(GRAPH_VSN, 2). -type v() :: {digraph:vertex(), term()} | 'false'. -type e() :: {digraph:vertex(), digraph:vertex()}. -- cgit v1.1 From fa462e9dba1e3e94f6d74e36c99e25b80d4f524a Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Tue, 8 Sep 2015 03:43:13 +0900 Subject: Add `plt_include_all_deps` dialyzer config option --- rebar.config.sample | 1 + src/rebar_prv_dialyzer.erl | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/rebar.config.sample b/rebar.config.sample index 8621b44..5dcd7de 100644 --- a/rebar.config.sample +++ b/rebar.config.sample @@ -100,6 +100,7 @@ {warnings, [underspecs, no_return]}, {get_warnings, true}, {plt_extra_apps, []}, + {plt_include_all_deps, false}, {plt_location, local}, % local | "/my/file/name" {plt_prefix, "rebar3"}, {base_plt_apps, [stdlib, kernel, crypto]}, diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index 1cf7b71..68cc63a 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -45,6 +45,9 @@ desc() -> "`warnings` - a list of dialyzer warnings\n" "`get_warnings` - display warnings when altering a PLT file (boolean)\n" "`plt_extra_apps` - a list of applications to include in the PLT file*\n" + "`plt_include_all_deps` - in addition to the first level dependencies, " + "include all nested dependent applications in the PLT file (boolean), " + "default to `false`\n" "`plt_location` - the location of the PLT file, `local` to store in the " "profile's base directory (default) or a custom directory.\n" "`plt_prefix` - the prefix to the PLT file, defaults to \"rebar3\"**\n" @@ -178,7 +181,12 @@ proj_plt_files(State) -> PltApps = get_config(State, plt_extra_apps, []), Apps = rebar_state:project_apps(State), DepApps = lists:flatmap(fun rebar_app_info:applications/1, Apps), - get_plt_files(BasePltApps ++ PltApps ++ DepApps, Apps). + DepApps1 = + case get_config(State, plt_include_all_deps, false) of + false -> DepApps; + true -> collect_nested_dependent_apps(DepApps) + end, + get_plt_files(BasePltApps ++ PltApps ++ DepApps1, Apps). default_plt_apps() -> [erts, @@ -442,3 +450,30 @@ no_warnings() -> get_config(State, Key, Default) -> Config = rebar_state:get(State, dialyzer, []), proplists:get_value(Key, Config, Default). + +-spec collect_nested_dependent_apps([atom()]) -> [atom()]. +collect_nested_dependent_apps(RootApps) -> + Deps = lists:foldl(fun collect_nested_dependent_apps/2, sets:new(), RootApps), + sets:to_list(Deps). + +-spec collect_nested_dependent_apps(atom(), rebar_set()) -> rebar_set(). +collect_nested_dependent_apps(App, Seen) -> + case sets:is_element(App, Seen) of + true -> + Seen; + false -> + Seen1 = sets:add_element(App, Seen), + case code:lib_dir(App) of + {error, _} -> + Seen1; + AppDir -> + case rebar_app_discover:find_app(AppDir, all) of + false -> + Seen1; + {true, AppInfo} -> + lists:foldl(fun collect_nested_dependent_apps/2, + Seen1, + rebar_app_info:applications(AppInfo)) + end + end + end. -- cgit v1.1 From 4ff78b4d7785e567f682a9642772620043af788e Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Tue, 8 Sep 2015 04:07:30 +0900 Subject: Add rebar_localfs_resource module for testing purposes --- test/rebar_localfs_resource.erl | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 test/rebar_localfs_resource.erl diff --git a/test/rebar_localfs_resource.erl b/test/rebar_localfs_resource.erl new file mode 100644 index 0000000..d60421e --- /dev/null +++ b/test/rebar_localfs_resource.erl @@ -0,0 +1,38 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et +%% +%% @doc A localfs custom resource (for testing purposes only) +%% +%% ``` +%% {deps, [ +%% %% Application files are copied from "/path/to/app_name" +%% {app_name, {localfs, "/path/to/app_name", undefined}} +%% ]}. +%% ''' +-module(rebar_localfs_resource). + +-behaviour(rebar_resource). + +-export([lock/2 + ,download/3 + ,needs_update/2 + ,make_vsn/1]). + +-include_lib("eunit/include/eunit.hrl"). + +lock(AppDir, {localfs, Path, _Ref}) -> + lock(AppDir, {localfs, Path}); +lock(_AppDir, {localfs, Path}) -> + {localfs, Path, undefined}. + +needs_update(_AppDir, _Resource) -> + false. + +download(AppDir, {localfs, Path, _Ref}, State) -> + download(AppDir, {localfs, Path}, State); +download(AppDir, {localfs, Path}, _State) -> + ok = rebar_file_utils:cp_r(filelib:wildcard(Path ++ "/*"), AppDir), + {ok, undefined}. + +make_vsn(_AppDir) -> + {plain, "undefined"}. -- cgit v1.1 From 902dd59d23335c35300b4e5520f128648f501a9f Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Tue, 8 Sep 2015 04:29:15 +0900 Subject: Add a testcase for 'plt_include_all_deps' dialyzer option --- test/rebar_dialyzer_SUITE.erl | 71 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/test/rebar_dialyzer_SUITE.erl b/test/rebar_dialyzer_SUITE.erl index 3158e8f..99d1024 100644 --- a/test/rebar_dialyzer_SUITE.erl +++ b/test/rebar_dialyzer_SUITE.erl @@ -7,7 +7,8 @@ all/0, update_base_plt/1, update_app_plt/1, - build_release_plt/1]). + build_release_plt/1, + plt_include_all_deps_option/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -38,7 +39,7 @@ init_per_testcase(Testcase, Config) -> rebar_test_utils:init_rebar_state(Config)]. all() -> - [update_base_plt, update_app_plt, build_release_plt]. + [update_base_plt, update_app_plt, build_release_plt, plt_include_all_deps_option]. update_base_plt(Config) -> AppDir = ?config(apps, Config), @@ -130,6 +131,56 @@ build_release_plt(Config) -> {ok, PltFiles} = plt_files(Plt), ?assertEqual(ErtsFiles, PltFiles). +plt_include_all_deps_option(Config) -> + AppDir = ?config(apps, Config), + RebarConfig = ?config(rebar_config, Config), + Plt = ?config(plt, Config), + State = ?config(state, Config), + + %% Create applications + Name1 = rebar_test_utils:create_random_name("app1_"), + Vsn1 = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(filename:join([AppDir,"deps",Name1]), Name1, Vsn1, + [erts]), + App1 = ec_cnv:to_atom(Name1), + + Name2 = rebar_test_utils:create_random_name("app2_"), + Vsn2 = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(filename:join([AppDir,"deps",Name2]), Name2, Vsn2, + [erts, App1]), % App2 depends on App1 + App2 = ec_cnv:to_atom(Name2), + + Name3 = rebar_test_utils:create_random_name("app3_"), % the project application + Vsn3 = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name3, Vsn3, + [erts, App2]), % App3 depends on App2 + + %% Dependencies settings + State1 = rebar_state:add_resource(State, {localfs, rebar_localfs_resource}), + Config1 = [{state, State1} | Config], + RebarConfig1 = merge_config( + [{deps, + [ + {App1, {localfs, filename:join([AppDir,"deps",Name1])}}, + {App2, {localfs, filename:join([AppDir,"deps",Name2])}} + ]}], + RebarConfig), + + %% Dialyzer: plt_include_all_deps = false (default) + rebar_test_utils:run_and_check(Config1, RebarConfig1, ["dialyzer"], + {ok, [{app, Name3}]}), + {ok, PltFiles1} = plt_files(Plt), + ?assertEqual([App2, erts], get_apps_from_beam_files(PltFiles1)), + + %% Dialyzer: plt_include_all_deps = true + RebarConfig2 = merge_config([{dialyzer, [{plt_include_all_deps, true}]}], + RebarConfig1), + rebar_test_utils:run_and_check(Config1, RebarConfig2, ["dialyzer"], + {ok, [{app, Name3}]}), + + {ok, PltFiles2} = plt_files(Plt), + ?assertEqual([App1, App2, erts], get_apps_from_beam_files(PltFiles2)). + %% Helpers erts_files() -> @@ -157,3 +208,19 @@ alter_plt(Plt) -> {init_plt, Plt}, {files, [code:which(dialyzer)]}]), ok. + +-spec merge_config(Config, Config) -> Config when + Config :: [{term(), term()}]. +merge_config(NewConfig, OldConfig) -> + dict:to_list( + rebar_opts:merge_opts(dict:from_list(NewConfig), + dict:from_list(OldConfig))). + +-spec get_apps_from_beam_files(string()) -> [atom()]. +get_apps_from_beam_files(BeamFiles) -> + lists:usort( + [begin + AppNameVsn = filename:basename(filename:dirname(filename:dirname(File))), + [AppName | _] = string:tokens(AppNameVsn ++ "-", "-"), + ec_cnv:to_atom(AppName) + end || File <- BeamFiles]). -- cgit v1.1 From 4891912790c9c3bdae450bf95e0155231210e416 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Sat, 12 Sep 2015 15:24:50 +0900 Subject: Fix error handlings for unknown applications --- src/rebar_prv_dialyzer.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index 68cc63a..2a20707 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -465,11 +465,11 @@ collect_nested_dependent_apps(App, Seen) -> Seen1 = sets:add_element(App, Seen), case code:lib_dir(App) of {error, _} -> - Seen1; + throw({unknown_application, App}); AppDir -> case rebar_app_discover:find_app(AppDir, all) of false -> - Seen1; + throw({unknown_application, App}); {true, AppInfo} -> lists:foldl(fun collect_nested_dependent_apps/2, Seen1, -- cgit v1.1 From f5d413e90fcf2830f9d8138ce0464e97c25a1424 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Sat, 12 Sep 2015 18:48:06 +0900 Subject: Change option name from "plt_include_all_deps" to "plt_apps" --- rebar.config.sample | 2 +- src/rebar_prv_dialyzer.erl | 33 +++++++++++++++++---------------- test/rebar_dialyzer_SUITE.erl | 12 ++++++------ 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/rebar.config.sample b/rebar.config.sample index 5dcd7de..37f641f 100644 --- a/rebar.config.sample +++ b/rebar.config.sample @@ -99,8 +99,8 @@ {dialyzer, [ {warnings, [underspecs, no_return]}, {get_warnings, true}, + {plt_apps, top_level_deps}, % top_level_deps | all_deps {plt_extra_apps, []}, - {plt_include_all_deps, false}, {plt_location, local}, % local | "/my/file/name" {plt_prefix, "rebar3"}, {base_plt_apps, [stdlib, kernel, crypto]}, diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl index 2a20707..0fc1d7d 100644 --- a/src/rebar_prv_dialyzer.erl +++ b/src/rebar_prv_dialyzer.erl @@ -44,28 +44,29 @@ desc() -> "options `dialyzer` in rebar.config:\n" "`warnings` - a list of dialyzer warnings\n" "`get_warnings` - display warnings when altering a PLT file (boolean)\n" - "`plt_extra_apps` - a list of applications to include in the PLT file*\n" - "`plt_include_all_deps` - in addition to the first level dependencies, " - "include all nested dependent applications in the PLT file (boolean), " - "default to `false`\n" + "`plt_apps` - the strategy for determining the applications which included " + "in the PLT file, `top_level_deps` to include just the direct dependencies " + "or `all_deps` to include all nested dependencies*\n" + "`plt_extra_apps` - a list of applications to include in the PLT file**\n" "`plt_location` - the location of the PLT file, `local` to store in the " "profile's base directory (default) or a custom directory.\n" - "`plt_prefix` - the prefix to the PLT file, defaults to \"rebar3\"**\n" + "`plt_prefix` - the prefix to the PLT file, defaults to \"rebar3\"***\n" "`base_plt_apps` - a list of applications to include in the base " - "PLT file***\n" + "PLT file****\n" "`base_plt_location` - the location of base PLT file, `global` to store in " - "$HOME/.cache/rebar3 (default) or a custom directory***\n" + "$HOME/.cache/rebar3 (default) or a custom directory****\n" "`base_plt_prefix` - the prefix to the base PLT file, defaults to " - "\"rebar3\"** ***\n" + "\"rebar3\"*** ****\n" "\n" "For example, to warn on unmatched returns: \n" "{dialyzer, [{warnings, [unmatched_returns]}]}.\n" "\n" - "*The applications in `dialyzer_base_plt_apps` and any `applications` and " - "`included_applications` listed in their .app files will be added to the " - "list.\n" - "**PLT files are named \"__plt\".\n" - "***The base PLT is a PLT containing the core applications often required " + "*The direct dependent applications are listed in `applications` and " + "`included_applications` of their .app files.\n" + "**The applications in `base_plt_apps` will be added to the " + "list. \n" + "***PLT files are named \"__plt\".\n" + "****The base PLT is a PLT containing the core applications often required " "for a project's PLT. One base PLT is created per OTP version and " "stored in `base_plt_location`. A base PLT is used to build project PLTs." "\n". @@ -182,9 +183,9 @@ proj_plt_files(State) -> Apps = rebar_state:project_apps(State), DepApps = lists:flatmap(fun rebar_app_info:applications/1, Apps), DepApps1 = - case get_config(State, plt_include_all_deps, false) of - false -> DepApps; - true -> collect_nested_dependent_apps(DepApps) + case get_config(State, plt_apps, top_level_deps) of + top_level_deps -> DepApps; + all_deps -> collect_nested_dependent_apps(DepApps) end, get_plt_files(BasePltApps ++ PltApps ++ DepApps1, Apps). diff --git a/test/rebar_dialyzer_SUITE.erl b/test/rebar_dialyzer_SUITE.erl index 99d1024..bbdaaff 100644 --- a/test/rebar_dialyzer_SUITE.erl +++ b/test/rebar_dialyzer_SUITE.erl @@ -8,7 +8,7 @@ update_base_plt/1, update_app_plt/1, build_release_plt/1, - plt_include_all_deps_option/1]). + plt_apps_option/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -39,7 +39,7 @@ init_per_testcase(Testcase, Config) -> rebar_test_utils:init_rebar_state(Config)]. all() -> - [update_base_plt, update_app_plt, build_release_plt, plt_include_all_deps_option]. + [update_base_plt, update_app_plt, build_release_plt, plt_apps_option]. update_base_plt(Config) -> AppDir = ?config(apps, Config), @@ -131,7 +131,7 @@ build_release_plt(Config) -> {ok, PltFiles} = plt_files(Plt), ?assertEqual(ErtsFiles, PltFiles). -plt_include_all_deps_option(Config) -> +plt_apps_option(Config) -> AppDir = ?config(apps, Config), RebarConfig = ?config(rebar_config, Config), Plt = ?config(plt, Config), @@ -166,14 +166,14 @@ plt_include_all_deps_option(Config) -> ]}], RebarConfig), - %% Dialyzer: plt_include_all_deps = false (default) + %% Dialyzer: plt_apps = top_level_deps (default) rebar_test_utils:run_and_check(Config1, RebarConfig1, ["dialyzer"], {ok, [{app, Name3}]}), {ok, PltFiles1} = plt_files(Plt), ?assertEqual([App2, erts], get_apps_from_beam_files(PltFiles1)), - %% Dialyzer: plt_include_all_deps = true - RebarConfig2 = merge_config([{dialyzer, [{plt_include_all_deps, true}]}], + %% Dialyzer: plt_apps = all_deps + RebarConfig2 = merge_config([{dialyzer, [{plt_apps, all_deps}]}], RebarConfig1), rebar_test_utils:run_and_check(Config1, RebarConfig2, ["dialyzer"], {ok, [{app, Name3}]}), -- cgit v1.1 From db2a53b3d92aee1373dbdc1a6a3d285434a3d461 Mon Sep 17 00:00:00 2001 From: Takeru Ohta Date: Sat, 12 Sep 2015 19:15:24 +0900 Subject: Fix for R15B03 --- test/rebar_dialyzer_SUITE.erl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/rebar_dialyzer_SUITE.erl b/test/rebar_dialyzer_SUITE.erl index bbdaaff..31e02d9 100644 --- a/test/rebar_dialyzer_SUITE.erl +++ b/test/rebar_dialyzer_SUITE.erl @@ -141,19 +141,19 @@ plt_apps_option(Config) -> Name1 = rebar_test_utils:create_random_name("app1_"), Vsn1 = rebar_test_utils:create_random_vsn(), rebar_test_utils:create_app(filename:join([AppDir,"deps",Name1]), Name1, Vsn1, - [erts]), + []), App1 = ec_cnv:to_atom(Name1), Name2 = rebar_test_utils:create_random_name("app2_"), Vsn2 = rebar_test_utils:create_random_vsn(), rebar_test_utils:create_app(filename:join([AppDir,"deps",Name2]), Name2, Vsn2, - [erts, App1]), % App2 depends on App1 + [App1]), % App2 depends on App1 App2 = ec_cnv:to_atom(Name2), Name3 = rebar_test_utils:create_random_name("app3_"), % the project application Vsn3 = rebar_test_utils:create_random_vsn(), rebar_test_utils:create_app(AppDir, Name3, Vsn3, - [erts, App2]), % App3 depends on App2 + [App2]), % App3 depends on App2 %% Dependencies settings State1 = rebar_state:add_resource(State, {localfs, rebar_localfs_resource}), @@ -169,6 +169,8 @@ plt_apps_option(Config) -> %% Dialyzer: plt_apps = top_level_deps (default) rebar_test_utils:run_and_check(Config1, RebarConfig1, ["dialyzer"], {ok, [{app, Name3}]}), + + %% NOTE: `erts` is included in `base_plt_apps` {ok, PltFiles1} = plt_files(Plt), ?assertEqual([App2, erts], get_apps_from_beam_files(PltFiles1)), -- cgit v1.1