From 936c8b1ba9d8d0b16bbdf8f78e6bb435f6956079 Mon Sep 17 00:00:00 2001 From: Fred Hebert Date: Thu, 24 Oct 2019 10:20:28 -0400 Subject: [PATCH] Allow cleaning specific apps or deps only This will allow project with larger dependencies sets to clean only the apps they want to when testing or changing small things, rather than forcing a rebuild of the whole dep set. Also allows cleaning up apps, not just deps. --- src/rebar_prv_clean.erl | 43 +++++++++++++++++++++++++----------- test/rebar_compile_SUITE.erl | 34 +++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/rebar_prv_clean.erl b/src/rebar_prv_clean.erl index 3c8a0c3f..5d0d0a50 100644 --- a/src/rebar_prv_clean.erl +++ b/src/rebar_prv_clean.erl @@ -28,28 +28,32 @@ init(State) -> {short_desc, "Remove compiled beam files from apps."}, {desc, "Remove compiled beam files from apps."}, {opts, [{all, $a, "all", undefined, "Clean all apps include deps"}, + {apps, undefined, "apps", string, "Clean a specific list of apps or dependencies"}, {profile, $p, "profile", string, "Clean under profile. Equivalent to `rebar3 as clean`"}]}])), {ok, State1}. -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> Providers = rebar_state:providers(State), - {All, Profiles} = handle_args(State), + {All, Profiles, Specific} = handle_args(State), State1 = rebar_state:apply_profiles(State, [list_to_atom(X) || X <- Profiles]), Cwd = rebar_dir:get_cwd(), rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State1), - case All of - true -> - DepsDir = rebar_dir:deps_dir(State1), - DepsDirs = filelib:wildcard(filename:join(DepsDir, "*")), - AllApps = rebar_app_discover:find_apps(DepsDirs, all), - clean_apps(State1, Providers, AllApps); - false -> - ProjectApps = rebar_state:project_apps(State1), - clean_apps(State1, Providers, ProjectApps) + if All; Specific =/= [] -> + DepsDir = rebar_dir:deps_dir(State1), + DepsDirs = filelib:wildcard(filename:join(DepsDir, "*")), + AllApps = rebar_app_discover:find_apps(DepsDirs, all), + Filter = case All of + true -> fun(_) -> true end; + false -> fun(AppInfo) -> filter_name(AppInfo, Specific) end + end, + clean_apps(State1, Providers, AllApps, Filter); + true -> + ProjectApps = rebar_state:project_apps(State1), + clean_apps(State1, Providers, ProjectApps, fun(_) -> true end) end, clean_extras(State1), @@ -66,7 +70,7 @@ format_error(Reason) -> %% Internal functions %% =================================================================== -clean_apps(State, Providers, Apps) -> +clean_apps(State, Providers, Apps, Filter) -> Compilers = rebar_state:compilers(State), [begin ?INFO("Cleaning out ~ts...", [rebar_app_info:name(AppInfo)]), @@ -74,7 +78,7 @@ clean_apps(State, Providers, Apps) -> AppInfo1 = rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, AppInfo, State), rebar_compiler:clean(Compilers, AppInfo1), rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, AppInfo1, State) - end || AppInfo <- Apps]. + end || AppInfo <- Apps, Filter(AppInfo)]. clean_extras(State) -> BaseDir = rebar_dir:base_dir(State), @@ -84,4 +88,17 @@ handle_args(State) -> {Args, _} = rebar_state:command_parsed_args(State), All = proplists:get_value(all, Args, false), Profiles = proplists:get_all_values(profile, Args), - {All, Profiles}. + DepsRaw = proplists:get_value(apps, Args), + Deps = parse_deps(DepsRaw), + {All, Profiles, Deps}. + +parse_deps(undefined) -> []; +parse_deps(Bin) -> + case lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode])) of + [<<"">>] -> []; % nothing submitted + Other -> Other + end. + +filter_name(AppInfo, Names) -> + Name = rebar_app_info:name(AppInfo), + lists:member(Name, Names). diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index 30523678..bb7f9e8b 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -24,7 +24,7 @@ all() -> deps_in_path, checkout_priority, highest_version_of_pkg_dep, parse_transform_test, erl_first_files_test, mib_test, umbrella_mib_first_test, only_default_transitive_deps, clean_all, - profile_deps, deps_build_in_prod, only_deps, + clean_specific, profile_deps, deps_build_in_prod, only_deps, override_deps, override_add_deps, override_del_deps, override_opts, override_add_opts, override_del_opts, apply_overrides_exactly_once, override_only_deps, @@ -1351,6 +1351,38 @@ clean_all(Config) -> {app, DepName, invalid}, {app, PkgName, invalid}]}). +clean_specific(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]), + + DepName = rebar_test_utils:create_random_name("dep1_"), + PkgName = rebar_test_utils:create_random_name("pkg1_"), + mock_git_resource:mock([]), + mock_pkg_resource:mock([ + {pkgdeps, [{{iolist_to_binary(PkgName), iolist_to_binary(Vsn)}, []}]} + ]), + + RConfFile = rebar_test_utils:create_config(AppDir, [{deps, [ + {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}}, + {list_to_atom(PkgName), Vsn} + ]}]), + {ok, RConf} = file:consult(RConfFile), + + %% Build things + rebar_test_utils:run_and_check( + Config, RConf, ["compile"], + {ok, [{app, Name}, {app, DepName}, {app, PkgName}]} + ), + + %% Clean all + rebar_test_utils:run_and_check(Config, [], ["clean", "--apps="++DepName++","++Name], + {ok, [{app, Name, invalid}, + {app, DepName, invalid}, + {app, PkgName, valid}]}). + override_deps(Config) -> Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), TopDeps = rebar_test_utils:top_level_deps(Deps),