diff options
-rw-r--r-- | src/rebar_app_discover.erl | 27 | ||||
-rw-r--r-- | src/rebar_app_info.erl | 9 | ||||
-rw-r--r-- | src/rebar_core.erl | 1 | ||||
-rw-r--r-- | src/rebar_dir.erl | 4 | ||||
-rw-r--r-- | src/rebar_hooks.erl | 10 | ||||
-rw-r--r-- | src/rebar_plugins.erl | 43 | ||||
-rw-r--r-- | src/rebar_prv_clean.erl | 9 | ||||
-rw-r--r-- | src/rebar_prv_compile.erl | 12 | ||||
-rw-r--r-- | src/rebar_prv_eunit.erl | 9 | ||||
-rw-r--r-- | src/rebar_prv_install_deps.erl | 48 | ||||
-rw-r--r-- | src/rebar_prv_shell.erl | 6 | ||||
-rw-r--r-- | src/rebar_prv_tar.erl | 2 | ||||
-rw-r--r-- | src/rebar_prv_upgrade.erl | 21 | ||||
-rw-r--r-- | src/rebar_state.erl | 11 | ||||
-rw-r--r-- | src/rebar_utils.erl | 17 | ||||
-rw-r--r-- | test/mock_pkg_resource.erl | 6 | ||||
-rw-r--r-- | test/rebar_compile_SUITE.erl | 63 | ||||
-rw-r--r-- | test/rebar_disable_app_SUITE.erl | 49 | ||||
-rw-r--r-- | test/rebar_src_dirs_SUITE.erl (renamed from test/rebar_extra_src_dirs_SUITE.erl) | 95 | ||||
-rw-r--r-- | test/rebar_test_utils.erl | 7 | ||||
-rw-r--r-- | test/rebar_upgrade_SUITE.erl | 34 |
21 files changed, 394 insertions, 89 deletions
diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl index e2ef179..332efb0 100644 --- a/src/rebar_app_discover.erl +++ b/src/rebar_app_discover.erl @@ -20,13 +20,19 @@ do(State, LibDirs) -> %% Sort apps so we get the same merged deps config everytime SortedApps = rebar_utils:sort_deps(Apps), lists:foldl(fun(AppInfo, StateAcc) -> - {AppInfo1, StateAcc1} = merge_deps(AppInfo, StateAcc), - Name = rebar_app_info:name(AppInfo), - OutDir = filename:join(DepsDir, Name), - AppInfo2 = rebar_app_info:out_dir(AppInfo1, OutDir), - ProjectDeps1 = lists:delete(Name, ProjectDeps), - rebar_state:project_apps(StateAcc1 - ,rebar_app_info:deps(AppInfo2, ProjectDeps1)) + Name = rebar_app_info:name(AppInfo), + case enable(State, AppInfo) of + true -> + {AppInfo1, StateAcc1} = merge_deps(AppInfo, StateAcc), + OutDir = filename:join(DepsDir, Name), + AppInfo2 = rebar_app_info:out_dir(AppInfo1, OutDir), + ProjectDeps1 = lists:delete(Name, ProjectDeps), + rebar_state:project_apps(StateAcc1 + ,rebar_app_info:deps(AppInfo2, ProjectDeps1)); + false -> + ?INFO("Ignoring ~s", [Name]), + StateAcc + end end, State, SortedApps). format_error({module_list, File}) -> @@ -211,3 +217,10 @@ try_handle_app_src_file(_, AppDir, [File], Validate) when Validate =:= invalid end; try_handle_app_src_file(_, _AppDir, Other, _Validate) -> throw({error, {multiple_app_files, Other}}). + +enable(State, AppInfo) -> + not lists:member(to_atom(rebar_app_info:name(AppInfo)), + rebar_state:get(State, excluded_apps, [])). + +to_atom(Bin) -> + list_to_atom(binary_to_list(Bin)). diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index 1b87e0b..9db20e7 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -34,6 +34,7 @@ source/2, state/1, state/2, + state_or_new/2, is_lock/1, is_lock/2, is_checkout/1, @@ -260,6 +261,14 @@ state(AppInfo=#app_info_t{}, State) -> state(#app_info_t{state=State}) -> State. +-spec state_or_new(rebar_state:t(), t()) -> rebar_state:t(). +state_or_new(State, AppInfo=#app_info_t{state=undefined}) -> + AppDir = dir(AppInfo), + C = rebar_config:consult(AppDir), + rebar_state:new(State, C, AppDir); +state_or_new(_State, #app_info_t{state=State}) -> + State. + -spec is_lock(t(), boolean()) -> t(). is_lock(AppInfo=#app_info_t{}, IsLock) -> AppInfo#app_info_t{is_lock=IsLock}. diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 7fe7332..c7cc45a 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -119,6 +119,7 @@ do([ProviderName | Rest], State) -> ,rebar_state:providers(State) ,rebar_state:namespace(State)) end, + case providers:do(Provider, State) of {ok, State1} -> do(Rest, State1); diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl index e810912..cb643ab 100644 --- a/src/rebar_dir.erl +++ b/src/rebar_dir.erl @@ -132,7 +132,7 @@ src_dirs(State) -> src_dirs(State, []). src_dirs(State, Default) -> ErlOpts = rebar_utils:erl_opts(State), Vs = proplists:get_all_values(src_dirs, ErlOpts), - case lists:append(Vs) of + case lists:append([rebar_state:get(State, src_dirs, []) | Vs]) of [] -> Default; Dirs -> Dirs end. @@ -144,7 +144,7 @@ extra_src_dirs(State) -> extra_src_dirs(State, []). extra_src_dirs(State, Default) -> ErlOpts = rebar_utils:erl_opts(State), Vs = proplists:get_all_values(extra_src_dirs, ErlOpts), - case lists:append(Vs) of + case lists:append([rebar_state:get(State, extra_src_dirs, []) | Vs]) of [] -> Default; Dirs -> Dirs end. diff --git a/src/rebar_hooks.erl b/src/rebar_hooks.erl index e144a8e..4ec46f7 100644 --- a/src/rebar_hooks.erl +++ b/src/rebar_hooks.erl @@ -10,11 +10,17 @@ run_all_hooks(Dir, Type, Command, Providers, State) -> run_hooks(Dir, Type, Command, State). run_provider_hooks(Dir, Type, Command, Providers, State) -> - State1 = rebar_state:providers(rebar_state:dir(State, Dir), Providers), + PluginDepsPaths = rebar_state:code_paths(State, all_plugin_deps), + code:add_pathsa(PluginDepsPaths), + Providers1 = rebar_state:providers(State), + State1 = rebar_state:providers(rebar_state:dir(State, Dir), Providers++Providers1), AllHooks = rebar_state:get(State1, provider_hooks, []), TypeHooks = proplists:get_value(Type, AllHooks, []), HookProviders = proplists:get_all_values(Command, TypeHooks), - rebar_core:do(HookProviders, State1). + + State2 = rebar_core:do(HookProviders, State1), + rebar_utils:remove_from_code_path(PluginDepsPaths), + State2. run_hooks(Dir, Type, Command, State) -> Hooks = case Type of diff --git a/src/rebar_plugins.erl b/src/rebar_plugins.erl index 6d0a4dc..c4644dc 100644 --- a/src/rebar_plugins.erl +++ b/src/rebar_plugins.erl @@ -32,31 +32,50 @@ handle_plugins(Plugins, State) -> handle_plugins(Profile, Plugins, State) -> %% Set deps dir to plugins dir so apps are installed there + Locks = rebar_state:lock(State), + DepsDir = rebar_state:get(State, deps_dir, ?DEFAULT_DEPS_DIR), State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR), - PluginProviders = lists:flatmap(fun(Plugin) -> - handle_plugin(Profile, Plugin, State1) - end, Plugins), + %% Install each plugin individually so if one fails to install it doesn't effect the others + {PluginProviders, State2} = + lists:foldl(fun(Plugin, {PluginAcc, StateAcc}) -> + {NewPlugins, NewState} = handle_plugin(Profile, Plugin, StateAcc), + {PluginAcc++NewPlugins, NewState} + end, {[], State1}, Plugins), %% reset deps dir - State2 = rebar_state:set(State1, deps_dir, ?DEFAULT_DEPS_DIR), + State3 = rebar_state:set(State2, deps_dir, DepsDir), + State4 = rebar_state:lock(State3, Locks), - rebar_state:create_logic_providers(PluginProviders, State2). + rebar_state:create_logic_providers(PluginProviders, State4). handle_plugin(Profile, Plugin, State) -> try - {ok, _, State2} = rebar_prv_install_deps:handle_deps(Profile, State, [Plugin]), + {ok, Apps, State2} = rebar_prv_install_deps:handle_deps(Profile, State, [Plugin]), + {no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps), + ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []), - Apps = rebar_state:all_deps(State2), - ToBuild = lists:dropwhile(fun rebar_app_info:valid/1, Apps), + %% Add already built plugin deps to the code path + CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps -- ToBuild], + code:add_pathsa(CodePaths), + + %% Build plugin and its deps [build_plugin(AppInfo) || AppInfo <- ToBuild], - [true = code:add_patha(filename:join(rebar_app_info:dir(AppInfo), "ebin")) || AppInfo <- Apps], - plugin_providers(Plugin) + + %% Add newly built deps and plugin to code path + State3 = rebar_state:update_all_plugin_deps(State2, Apps), + NewCodePaths = [rebar_app_info:ebin_dir(A) || A <- ToBuild], + code:add_pathsa(CodePaths), + + %% Store plugin code paths so we can remove them when compiling project apps + State4 = rebar_state:update_code_paths(State3, all_plugin_deps, CodePaths++NewCodePaths), + + {plugin_providers(Plugin), State4} catch C:T -> ?DEBUG("~p ~p ~p", [C, T, erlang:get_stacktrace()]), ?WARN("Plugin ~p not available. It will not be used.", [Plugin]), - [] + {[], State} end. build_plugin(AppInfo) -> @@ -65,6 +84,8 @@ build_plugin(AppInfo) -> S = rebar_state:new(rebar_state:new(), C, AppDir), rebar_prv_compile:compile(S, [], AppInfo). +plugin_providers({Plugin, _, _, _}) when is_atom(Plugin) -> + validate_plugin(Plugin); plugin_providers({Plugin, _, _}) when is_atom(Plugin) -> validate_plugin(Plugin); plugin_providers({Plugin, _}) when is_atom(Plugin) -> diff --git a/src/rebar_prv_clean.erl b/src/rebar_prv_clean.erl index 68acf36..e3cb84e 100644 --- a/src/rebar_prv_clean.erl +++ b/src/rebar_prv_clean.erl @@ -67,16 +67,9 @@ format_error(Reason) -> clean_apps(State, Providers, Apps) -> lists:foreach(fun(AppInfo) -> AppDir = rebar_app_info:dir(AppInfo), - S = case rebar_app_info:state(AppInfo) of - undefined -> - C = rebar_config:consult(AppDir), - rebar_state:new(State, C, AppDir); - AppState -> - AppState - end, + S = rebar_app_info:state_or_new(State, AppInfo), ?INFO("Cleaning out ~s...", [rebar_app_info:name(AppInfo)]), - %% Legacy hook support rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, S), rebar_erlc_compiler:clean(State, rebar_app_info:out_dir(AppInfo)), rebar_hooks:run_all_hooks(AppDir, post, ?PROVIDER, Providers, S) diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl index 26d658e..37dc47d 100644 --- a/src/rebar_prv_compile.erl +++ b/src/rebar_prv_compile.erl @@ -32,6 +32,8 @@ init(State) -> -spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. do(State) -> DepsPaths = rebar_state:code_paths(State, all_deps), + PluginDepsPaths = rebar_state:code_paths(State, all_plugin_deps), + rebar_utils:remove_from_code_path(PluginDepsPaths), code:add_pathsa(DepsPaths), ProjectApps = rebar_state:project_apps(State), @@ -71,17 +73,9 @@ build_apps(State, Providers, Apps) -> build_app(State, Providers, AppInfo) -> AppDir = rebar_app_info:dir(AppInfo), OutDir = rebar_app_info:out_dir(AppInfo), - copy_app_dirs(State, AppDir, OutDir), - S = case rebar_app_info:state(AppInfo) of - undefined -> - C = rebar_config:consult(AppDir), - rebar_state:new(State, C, AppDir); - AppState -> - AppState - end, - + S = rebar_app_info:state_or_new(State, AppInfo), compile(S, Providers, AppInfo). compile(State, Providers, AppInfo) -> diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl index ce93d33..28c0ed6 100644 --- a/src/rebar_prv_eunit.erl +++ b/src/rebar_prv_eunit.erl @@ -134,14 +134,7 @@ resolve_suites(State, Apps, RawOpts) -> compile_tests(State, TestApps, Suites, RawOpts) -> F = fun(AppInfo) -> - AppDir = rebar_app_info:dir(AppInfo), - S = case rebar_app_info:state(AppInfo) of - undefined -> - C = rebar_config:consult(AppDir), - rebar_state:new(State, C, AppDir); - AppState -> - AppState - end, + S = rebar_app_info:state_or_new(State, AppInfo), ok = rebar_erlc_compiler:compile(replace_src_dirs(S), ec_cnv:to_list(rebar_app_info:out_dir(AppInfo))) end, diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 3cdf784..d8b9000 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -37,7 +37,10 @@ -export([handle_deps/3, handle_deps/4, - handle_deps/5]). + handle_deps/5, + + find_cycles/1, + cull_compile/2]). -export_type([dep/0]). @@ -76,6 +79,10 @@ do(State) -> {Apps, State1} = lists:foldl(fun deps_per_profile/2, {[], State}, lists:reverse(Profiles)), + State2 = rebar_state:update_all_deps(State1, Apps), + CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps], + State3 = rebar_state:update_code_paths(State2, all_deps, CodePaths), + Source = ProjectApps ++ Apps, case find_cycles(Source) of {cycles, Cycles} -> @@ -84,7 +91,7 @@ do(State) -> {error, Error}; {no_cycle, Sorted} -> ToCompile = cull_compile(Sorted, ProjectApps), - {ok, rebar_state:deps_to_build(State1, ToCompile)} + {ok, rebar_state:deps_to_build(State3, ToCompile)} end catch %% maybe_fetch will maybe_throw an exception to break out of some loops @@ -158,11 +165,7 @@ handle_deps(Profile, State0, Deps, Upgrade, Locks) -> ,lists:ukeysort(2, SrcApps) ,lists:ukeysort(2, Solved)), - State5 = rebar_state:update_all_deps(State4, AllDeps), - CodePaths = [rebar_app_info:ebin_dir(A) || A <- AllDeps], - State6 = rebar_state:update_code_paths(State5, all_deps, CodePaths), - - {ok, AllDeps, State6}. + {ok, AllDeps, State4}. %% =================================================================== %% Internal functions @@ -224,7 +227,22 @@ handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, Locks, S Level = rebar_app_info:dep_level(AppInfo), {NewSeen, NewState} = maybe_lock(Profile, AppInfo, Seen, State, Level), {_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, NewState), - {[AppInfo1 | Fetched], NewSeen, NewState}. + + Profiles = rebar_state:current_profiles(State), + Name = rebar_app_info:name(AppInfo1), + C = rebar_config:consult(rebar_app_info:dir(AppInfo1)), + BaseDir = rebar_state:get(State, base_dir, []), + S1 = rebar_state:new(rebar_state:set(rebar_state:new(), base_dir, BaseDir), + C, rebar_app_info:dir(AppInfo1)), + S2 = rebar_state:apply_profiles(S1, Profiles), + S3 = rebar_state:apply_overrides(S2, Name), + AppInfo2 = rebar_app_info:state(AppInfo1, S3), + + %% Dep may have plugins to install. Find and install here. + S4 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), S3), + AppInfo3 = rebar_app_info:state(AppInfo2, S4), + + {[AppInfo3 | Fetched], NewSeen, NewState}. maybe_lock(Profile, AppInfo, Seen, State, Level) -> case rebar_app_info:is_checkout(AppInfo) of @@ -383,14 +401,16 @@ handle_dep(State, DepsDir, AppInfo, Locks, Level) -> AppInfo1 = rebar_app_info:state(AppInfo, S3), %% Dep may have plugins to install. Find and install here. - State1 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), State), - Deps = rebar_state:get(S3, deps, []), + S4 = rebar_plugins:handle_plugins(rebar_state:get(S3, plugins, []), S3), + AppInfo2 = rebar_app_info:state(AppInfo1, S4), + %% Upgrade lock level to be the level the dep will have in this dep tree + Deps = rebar_state:get(S4, deps, []), NewLocks = [{DepName, Source, LockLevel+Level} || - {DepName, Source, LockLevel} <- rebar_state:get(S3, {locks, default}, [])], - AppInfo2 = rebar_app_info:deps(AppInfo1, rebar_state:deps_names(Deps)), - {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S3, Locks, Level+1), - {AppInfo2, SrcDeps, PkgDeps, Locks++NewLocks, State1}. + {DepName, Source, LockLevel} <- rebar_state:get(S4, {locks, default}, [])], + AppInfo3 = rebar_app_info:deps(AppInfo2, rebar_state:deps_names(Deps)), + {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, S4, Locks, Level+1), + {AppInfo3, SrcDeps, PkgDeps, Locks++NewLocks, State}. -spec maybe_fetch(rebar_app_info:t(), atom(), boolean(), sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}. diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl index 5e87f02..bd49ee1 100644 --- a/src/rebar_prv_shell.erl +++ b/src/rebar_prv_shell.erl @@ -107,8 +107,10 @@ setup_shell() -> %% wait until user_drv and user have been registered (max 3 seconds) ok = wait_until_user_started(3000), %% set any process that had a reference to the old user's group leader to the - %% new user process - _ = [erlang:group_leader(whereis(user), Pid) || Pid <- NeedsUpdate], + %% new user process. Catch the race condition when the Pid exited after the + %% liveness check. + _ = [catch erlang:group_leader(whereis(user), Pid) || Pid <- NeedsUpdate, + is_process_alive(Pid)], %% enable error_logger's tty output ok = error_logger:swap_handler(tty), %% disable the simple error_logger (which may have been added multiple diff --git a/src/rebar_prv_tar.erl b/src/rebar_prv_tar.erl index 852ba87..84fe395 100644 --- a/src/rebar_prv_tar.erl +++ b/src/rebar_prv_tar.erl @@ -47,7 +47,7 @@ do(State) -> ,{caller, Caller}], AllOptions); Config -> relx:main([{lib_dirs, LibDirs} - ,{config, Config} + ,{config, lists:reverse(Config)} ,{output_dir, OutputDir} ,{caller, Caller}], AllOptions) end, diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl index b86cbe3..49d5674 100644 --- a/src/rebar_prv_upgrade.erl +++ b/src/rebar_prv_upgrade.erl @@ -94,10 +94,15 @@ prepare_locks([Name|Names], Deps, Locks, Unlocks) -> AtomName = binary_to_atom(Name, utf8), case lists:keyfind(Name, 1, Locks) of {_, _, 0} = Lock -> - case lists:keyfind(AtomName, 1, Deps) of - false -> + case {lists:keyfind(AtomName, 1, Deps), lists:member(AtomName, Deps)} of + {false, false} -> ?PRV_ERROR({unknown_dependency, Name}); - Dep -> + {Dep, false} -> + {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks), + prepare_locks(Names, Deps, NewLocks, + [{Name, Source, 0} | NewUnlocks ++ Unlocks]); + {false, true} -> % package as a single atom + Dep = AtomName, {Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks), prepare_locks(Names, Deps, NewLocks, [{Name, Source, 0} | NewUnlocks ++ Unlocks]) @@ -116,9 +121,13 @@ prepare_locks([Name|Names], Deps, Locks, Unlocks) -> end. prepare_lock(Dep, Lock, Locks) -> - Source = Source = case Dep of - {_, Src} -> Src; - {_, _, Src} -> Src + Source = case Dep of + {_, SrcOrVsn} -> SrcOrVsn; + {_, _, Src} -> Src; + _ when is_atom(Dep) -> + %% version-free package. Must unlock whatever matches in locks + {_, Vsn, _} = lists:keyfind(ec_cnv:to_binary(Dep), 1, Locks), + Vsn end, {NewLocks, NewUnlocks} = unlock_higher_than(0, Locks -- [Lock]), {Source, NewLocks, NewUnlocks}. diff --git a/src/rebar_state.erl b/src/rebar_state.erl index 18d6be7..96daf39 100644 --- a/src/rebar_state.erl +++ b/src/rebar_state.erl @@ -24,6 +24,7 @@ project_apps/1, project_apps/2, deps_to_build/1, deps_to_build/2, + all_plugin_deps/1, all_plugin_deps/2, update_all_plugin_deps/2, all_deps/1, all_deps/2, update_all_deps/2, namespace/1, namespace/2, @@ -55,6 +56,7 @@ project_apps = [] :: [rebar_app_info:t()], deps_to_build = [] :: [rebar_app_info:t()], + all_plugin_deps = [] :: [rebar_app_info:t()], all_deps = [] :: [rebar_app_info:t()], packages = undefined :: {rebar_dict(), rebar_digraph()} | undefined, @@ -347,6 +349,15 @@ all_deps(#state_t{all_deps=Apps}) -> all_deps(State=#state_t{}, NewApps) -> State#state_t{all_deps=NewApps}. +all_plugin_deps(#state_t{all_plugin_deps=Apps}) -> + Apps. + +all_plugin_deps(State=#state_t{}, NewApps) -> + State#state_t{all_plugin_deps=NewApps}. + +update_all_plugin_deps(State=#state_t{all_plugin_deps=Apps}, NewApps) -> + State#state_t{all_plugin_deps=Apps++NewApps}. + update_all_deps(State=#state_t{all_deps=Apps}, NewApps) -> State#state_t{all_deps=Apps++NewApps}. diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index ffa29e6..cc59ed0 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -48,6 +48,7 @@ erl_opts/1, indent/1, update_code/1, + remove_from_code_path/1, cleanup_code_path/1, args_to_tasks/1, expand_env_variable/3, @@ -581,6 +582,22 @@ update_code(Paths) -> end end, Paths). +remove_from_code_path(Paths) -> + lists:foreach(fun(Path) -> + Name = filename:basename(Path, "/ebin"), + App = list_to_atom(Name), + application:load(App), + case application:get_key(App, modules) of + undefined -> + application:unload(App), + ok; + {ok, Modules} -> + application:unload(App), + [begin code:purge(M), code:delete(M) end || M <- Modules] + end, + code:del_path(Path) + end, Paths). + cleanup_code_path(OrigPath) -> CurrentPath = code:get_path(), AddedPaths = CurrentPath -- OrigPath, diff --git a/test/mock_pkg_resource.erl b/test/mock_pkg_resource.erl index 9ed0962..eda863b 100644 --- a/test/mock_pkg_resource.erl +++ b/test/mock_pkg_resource.erl @@ -15,7 +15,7 @@ mock() -> mock([]). %% Specific config options are explained in each of the private functions. -spec mock(Opts) -> ok when Opts :: [Option], - Option :: {update, [App]} + Option :: {upgrade, [App]} | {cache_dir, string()} | {default_vsn, Vsn} | {override_vsn, [{App, Vsn}]} @@ -73,6 +73,7 @@ mock_vsn(_Opts) -> %% into a `rebar.config' file to describe dependencies. mock_download(Opts) -> Deps = proplists:get_value(pkgdeps, Opts, []), + Config = proplists:get_value(config, Opts, []), meck:expect( ?MOD, download, fun (Dir, {pkg, AppBin, Vsn}, _) -> @@ -83,7 +84,7 @@ mock_download(Opts) -> Dir, App, binary_to_list(Vsn), [kernel, stdlib] ++ [element(1,D) || D <- AppDeps] ), - rebar_test_utils:create_config(Dir, [{deps, AppDeps}]), + rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config), TarApp = App++"-"++binary_to_list(Vsn)++".tar", Tarball = filename:join([Dir, TarApp]), Contents = filename:join([Dir, "contents.tar.gz"]), @@ -120,7 +121,6 @@ mock_pkg_index(Opts) -> meck:expect(rebar_packages, get_packages, fun(_State) -> {Dict, Digraph} end). - %%%%%%%%%%%%%%% %%% Helpers %%% %%%%%%%%%%%%%%% diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index 2dc57c5..7025eef 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -20,6 +20,7 @@ checkout_priority/1, compile_plugins/1, compile_global_plugins/1, + complex_plugins/1, highest_version_of_pkg_dep/1, parse_transform_test/1]). @@ -49,7 +50,7 @@ all() -> recompile_when_opts_change, dont_recompile_when_opts_dont_change, dont_recompile_yrl_or_xrl, delete_beam_if_source_deleted, deps_in_path, checkout_priority, compile_plugins, compile_global_plugins, - highest_version_of_pkg_dep, parse_transform_test]. + complex_plugins, highest_version_of_pkg_dep, parse_transform_test]. build_basic_app(Config) -> AppDir = ?config(apps, Config), @@ -408,17 +409,20 @@ compile_plugins(Config) -> DepName = rebar_test_utils:create_random_name("dep1_"), PluginName = rebar_test_utils:create_random_name("plugin1_"), - mock_git_resource:mock([{config, [{plugins, [ - {list_to_atom(PluginName), Vsn} - ]}]}]), - mock_pkg_resource:mock([ - {pkgdeps, [{{iolist_to_binary(PluginName), iolist_to_binary(Vsn)}, []}]} - ]), + + Plugins = rebar_test_utils:expand_deps(git, [{PluginName, Vsn, []}]), + mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Plugins)}]), + + mock_pkg_resource:mock([{pkgdeps, [{{list_to_binary(DepName), list_to_binary(Vsn)}, []}]}, + {config, [{plugins, [ + {list_to_atom(PluginName), + {git, "http://site.com/user/"++PluginName++".git", + {tag, 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(DepName) ]}]), {ok, RConf} = file:consult(RConfFile), @@ -480,6 +484,49 @@ compile_global_plugins(Config) -> meck:unload(rebar_dir). +%% Tests installing of plugin with transitive deps +complex_plugins(Config) -> + AppDir = ?config(apps, Config), + + meck:new(rebar_dir, [passthrough]), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + Vsn2 = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + DepName = rebar_test_utils:create_random_name("dep1_"), + DepName2 = rebar_test_utils:create_random_name("dep2_"), + DepName3 = rebar_test_utils:create_random_name("dep3_"), + PluginName = rebar_test_utils:create_random_name("plugin1_"), + + Deps = rebar_test_utils:expand_deps(git, [{PluginName, Vsn2, [{DepName2, Vsn, + [{DepName3, Vsn, []}]}]} + ,{DepName, Vsn, []}]), + mock_git_resource:mock([{deps, rebar_test_utils:flat_deps(Deps)}]), + + RConfFile = + rebar_test_utils:create_config(AppDir, + [{deps, [ + {list_to_atom(DepName), {git, "http://site.com/user/"++DepName++".git", {tag, Vsn}}} + ]}, + {plugins, [ + {list_to_atom(PluginName), {git, "http://site.com/user/"++PluginName++".git", {tag, Vsn2}}} + ]}]), + {ok, RConf} = file:consult(RConfFile), + + %% Build with deps. + rebar_test_utils:run_and_check( + Config, RConf, ["compile"], + {ok, [{app, Name}, + {plugin, PluginName, Vsn2}, + {plugin, DepName2}, + {plugin, DepName3}, + {dep, DepName}]} + ), + + meck:unload(rebar_dir). + highest_version_of_pkg_dep(Config) -> AppDir = ?config(apps, Config), diff --git a/test/rebar_disable_app_SUITE.erl b/test/rebar_disable_app_SUITE.erl new file mode 100644 index 0000000..dd71ffb --- /dev/null +++ b/test/rebar_disable_app_SUITE.erl @@ -0,0 +1,49 @@ +-module(rebar_disable_app_SUITE). +-compile(export_all). +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-define(MOD(Name), + io_lib:format("-module(~s).~n-export([x/0]).~nx() -> ok.~n", [Name])). + +all() -> [disable_app]. + +init_per_testcase(_, Config) -> + rebar_test_utils:init_rebar_state(Config). + +end_per_testcase(_, _Config) -> + ok. + +disable_app(Config) -> + AppDir = ?config(apps, Config), + + Name1 = create_random_app(AppDir, "app1_"), + Name2 = create_random_app(AppDir, "app2_"), + + RebarConfig = [{excluded_apps, [list_to_atom(Name1)]}], + %RebarConfig = [], + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["compile"], + {ok, [{app, Name2}]}), + + App1 = filename:join([AppDir, "_build", "default", "lib", Name1, "ebin", Name1 ++ ".app"]), + ?assertEqual(filelib:is_file(App1), false), + + App2 = filename:join([AppDir, "_build", "default", "lib", Name2, "ebin", Name2 ++ ".app"]), + ?assertEqual(filelib:is_file(App2), true). + +%% +%% Utils +%% +create_random_app(AppDir, Prefix) -> + Name = rebar_test_utils:create_random_name(Prefix), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_empty_app(filename:join([AppDir, "apps", Name]), Name, Vsn, [kernel, stdlib]), + + ModName = rebar_test_utils:create_random_name("mod1_"), + Mod = filename:join([AppDir, "apps", Name, "src", ModName ++ ".erl"]), + ok = filelib:ensure_dir(Mod), + Src = ?MOD(ModName), + ok = ec_file:write(Mod, Src), + Name. diff --git a/test/rebar_extra_src_dirs_SUITE.erl b/test/rebar_src_dirs_SUITE.erl index a00bb2d..1804fbf 100644 --- a/test/rebar_extra_src_dirs_SUITE.erl +++ b/test/rebar_src_dirs_SUITE.erl @@ -1,4 +1,4 @@ --module(rebar_extra_src_dirs_SUITE). +-module(rebar_src_dirs_SUITE). -export([suite/0, init_per_suite/1, @@ -6,9 +6,15 @@ init_per_testcase/2, end_per_testcase/2, all/0, + src_dirs_at_root/1, + extra_src_dirs_at_root/1, + src_dirs_in_erl_opts/1, + extra_src_dirs_in_erl_opts/1, + src_dirs_at_root_and_in_erl_opts/1, + extra_src_dirs_at_root_and_in_erl_opts/1, build_basic_app/1, build_multi_apps/1, - src_dir_takes_precedence/1]). + src_dir_takes_precedence_over_extra/1]). -include_lib("common_test/include/ct.hrl"). @@ -27,7 +33,88 @@ init_per_testcase(_, Config) -> end_per_testcase(_, _Config) -> ok. all() -> - [build_basic_app, build_multi_apps, src_dir_takes_precedence]. + [src_dirs_at_root, extra_src_dirs_at_root, + src_dirs_in_erl_opts, extra_src_dirs_in_erl_opts, + src_dirs_at_root_and_in_erl_opts, extra_src_dirs_at_root_and_in_erl_opts, + build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra]. + +src_dirs_at_root(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]), + + RebarConfig = [{src_dirs, ["foo", "bar", "baz"]}], + + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + + ["foo", "bar", "baz"] = rebar_dir:src_dirs(State, []). + +extra_src_dirs_at_root(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]), + + RebarConfig = [{extra_src_dirs, ["foo", "bar", "baz"]}], + + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + + ["foo", "bar", "baz"] = rebar_dir:extra_src_dirs(State, []). + +src_dirs_in_erl_opts(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]), + + RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar", "baz"]}]}], + + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + + ["foo", "bar", "baz"] = rebar_dir:src_dirs(State, []). + +extra_src_dirs_in_erl_opts(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]), + + RebarConfig = [{erl_opts, [{extra_src_dirs, ["foo", "bar", "baz"]}]}], + + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + + ["foo", "bar", "baz"] = rebar_dir:extra_src_dirs(State, []). + +src_dirs_at_root_and_in_erl_opts(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]), + + RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}], + + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + + ["baz", "qux", "foo", "bar"] = rebar_dir:src_dirs(State, []). + +extra_src_dirs_at_root_and_in_erl_opts(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]), + + RebarConfig = [{erl_opts, [{extra_src_dirs, ["foo", "bar"]}]}, {extra_src_dirs, ["baz", "qux"]}], + + {ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return), + + ["baz", "qux", "foo", "bar"] = rebar_dir:extra_src_dirs(State, []). build_basic_app(Config) -> AppDir = ?config(apps, Config), @@ -118,7 +205,7 @@ build_multi_apps(Config) -> Mods2 = proplists:get_value(modules, KVs2), false = lists:member(extra2, Mods2). -src_dir_takes_precedence(Config) -> +src_dir_takes_precedence_over_extra(Config) -> AppDir = ?config(apps, Config), Name = rebar_test_utils:create_random_name("app1_"), diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl index 68e0603..f53ba20 100644 --- a/test/rebar_test_utils.erl +++ b/test/rebar_test_utils.erl @@ -70,7 +70,8 @@ run_and_check(Config, RebarConfig, Command, Expect) -> %% - src/<file>.app.src %% And returns a `rebar_app_info' object. create_app(AppDir, Name, Vsn, Deps) -> - write_src_file(AppDir, Name), + write_src_file(AppDir, Name ++ ".erl"), + write_src_file(AppDir, "not_a_real_src_" ++ Name ++ ".erl"), write_app_src_file(AppDir, Name, Vsn, Deps), rebar_app_info:new(Name, Vsn, AppDir, Deps). @@ -297,9 +298,9 @@ check_results(AppDir, Expected) -> end, Expected). write_src_file(Dir, Name) -> - Erl = filename:join([Dir, "src", "not_a_real_src_" ++ Name ++ ".erl"]), + Erl = filename:join([Dir, "src", Name]), ok = filelib:ensure_dir(Erl), - ok = ec_file:write(Erl, erl_src_file("not_a_real_src_" ++ Name ++ ".erl")). + ok = ec_file:write(Erl, erl_src_file(Name)). write_eunitized_src_file(Dir, Name) -> Erl = filename:join([Dir, "src", "not_a_real_src_" ++ Name ++ ".erl"]), diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl index 793f10a..79cf29e 100644 --- a/test/rebar_upgrade_SUITE.erl +++ b/test/rebar_upgrade_SUITE.erl @@ -3,7 +3,7 @@ -include_lib("eunit/include/eunit.hrl"). -compile(export_all). -all() -> [{group, git}, {group, pkg}]. +all() -> [{group, git}, {group, pkg}, novsn_pkg]. groups() -> [{all, [], [top_a, top_b, top_c, top_d1, top_d2, top_e, @@ -31,6 +31,26 @@ init_per_group(_, Config) -> end_per_group(_, Config) -> Config. +init_per_testcase(novsn_pkg, Config0) -> + Config = rebar_test_utils:init_rebar_state(Config0, "novsn_pkg_"), + AppDir = ?config(apps, Config), + RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [fakeapp]}]), + + Deps = [{{<<"fakeapp">>, <<"1.0.0">>}, []}], + UpDeps = [{{<<"fakeapp">>, <<"1.1.0">>}, []}], + Upgrades = ["fakeapp"], + + [{rebarconfig, RebarConf}, + {mock, fun() -> + catch mock_pkg_resource:unmock(), + mock_pkg_resource:mock([{pkgdeps, Deps}, {upgrade, []}]) + end}, + {mock_update, fun() -> + catch mock_pkg_resource:unmock(), + mock_pkg_resource:mock([{pkgdeps, UpDeps}, {upgrade, Upgrades}]) + end}, + {expected, {ok, [{dep, "fakeapp", "1.1.0"}, {lock, "fakeapp", "1.1.0"}]}} + | Config]; init_per_testcase(Case, Config) -> DepsType = ?config(deps_type, Config), {Deps, UpDeps, ToUp, Expectations} = upgrades(Case), @@ -517,6 +537,18 @@ run(Config) -> Config, NewRebarConfig, ["upgrade", App], Expectation ). +novsn_pkg(Config) -> + apply(?config(mock, Config), []), + {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), + %% Install dependencies before re-mocking for an upgrade + rebar_test_utils:run_and_check(Config, RebarConfig, ["lock"], {ok, []}), + Expectation = ?config(expected, Config), + apply(?config(mock_update, Config), []), + rebar_test_utils:run_and_check( + Config, RebarConfig, ["upgrade"], Expectation + ), + ok. + rewrite_locks({ok, Expectations}, Config) -> AppDir = ?config(apps, Config), LockFile = filename:join([AppDir, "rebar.lock"]), |