diff options
Diffstat (limited to 'src/rebar_core.erl')
-rw-r--r-- | src/rebar_core.erl | 266 |
1 files changed, 127 insertions, 139 deletions
diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 99d3c38..9e3f9f0 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -26,97 +26,71 @@ %% ------------------------------------------------------------------- -module(rebar_core). --export([process_commands/2, - skip_dir/1, - is_skip_dir/1, - skip_dirs/0]). +-export([process_commands/2]). -include("rebar.hrl"). - -%% =================================================================== -%% Public API -%% =================================================================== - -skip_dir(Dir) -> - SkipDir = {skip_dir, Dir}, - case erlang:get(SkipDir) of - undefined -> - ?DEBUG("Adding skip dir: ~s\n", [Dir]), - erlang:put(SkipDir, true); - true -> - ok - end. - -is_skip_dir(Dir) -> - case erlang:get({skip_dir, Dir}) of - undefined -> - false; - true -> - true - end. - -skip_dirs() -> - [Dir || {{skip_dir, Dir}, true} <- erlang:get()]. - %% =================================================================== %% Internal functions %% =================================================================== -process_commands([], _ParentConfig) -> - AbortTrapped = rebar_config:get_global(abort_trapped, false), - case {erlang:get(operations), AbortTrapped} of +process_commands([], ParentConfig) -> + AbortTrapped = rebar_config:get_xconf(ParentConfig, abort_trapped, false), + case {get_operations(ParentConfig), AbortTrapped} of {0, _} -> %% None of the commands had any effect - ?ABORT; + ?FAIL; {_, true} -> %% An abort was previously trapped - ?ABORT; + ?FAIL; _ -> ok end; process_commands([Command | Rest], ParentConfig) -> - try - %% Reset skip dirs - lists:foreach(fun (D) -> erlang:erase({skip_dir, D}) end, skip_dirs()), - Operations = erlang:get(operations), - - %% Convert the code path so that all the entries are absolute paths. - %% If not, code:set_path() may choke on invalid relative paths when - %% trying to restore the code path from inside a subdirectory. - true = rebar_utils:expand_code_path(), - _ = process_dir(rebar_utils:get_cwd(), ParentConfig, - Command, sets:new()), - case erlang:get(operations) of - Operations -> - %% This command didn't do anything - ?CONSOLE("Command '~p' not understood or not applicable~n", - [Command]); - _ -> - ok - end, - %% Wipe out vsn cache to avoid invalid hits when - %% dependencies are updated - ets:delete_all_objects(rebar_vsn_cache) - catch - throw:rebar_abort -> - case rebar_config:get_global(keep_going, false) of - false -> - ?ABORT; - true -> - ?WARN("Continuing on after abort: ~p\n", [Rest]), - rebar_config:set_global(abort_trapped, true), + %% Reset skip dirs + ParentConfig1 = rebar_config:reset_skip_dirs(ParentConfig), + Operations = get_operations(ParentConfig1), + + ParentConfig4 = + try + %% Convert the code path so that all the entries are absolute paths. + %% If not, code:set_path() may choke on invalid relative paths when trying + %% to restore the code path from inside a subdirectory. + true = rebar_utils:expand_code_path(), + {ParentConfig2, _DirSet} = process_dir(rebar_utils:get_cwd(), + ParentConfig1, Command, + sets:new()), + case get_operations(ParentConfig2) of + Operations -> + %% This command didn't do anything + ?CONSOLE("Command '~p' not understood or not applicable~n", + [Command]); + _ -> ok - end - end, - process_commands(Rest, ParentConfig). - + end, + %% TODO: reconsider after config inheritance removal/redesign + ParentConfig3 = rebar_config:clean_config(ParentConfig1, ParentConfig2), + %% Wipe out vsn cache to avoid invalid hits when + %% dependencies are updated + rebar_config:set_xconf(ParentConfig3, vsn_cache, dict:new()) + catch + throw:rebar_abort -> + case rebar_config:get_xconf(ParentConfig1, keep_going, false) of + false -> + ?FAIL; + true -> + ?WARN("Continuing on after abort: ~p\n", [Rest]), + rebar_config:set_xconf(ParentConfig1, + abort_trapped, true) + end + end, + process_commands(Rest, ParentConfig4). process_dir(Dir, ParentConfig, Command, DirSet) -> case filelib:is_dir(Dir) of false -> ?WARN("Skipping non-existent sub-dir: ~p\n", [Dir]), - DirSet; + {ParentConfig, DirSet}; true -> ok = file:set_cwd(Dir), @@ -157,13 +131,13 @@ maybe_process_dir({_, ModuleSetFile}=ModuleSet, Config, CurrentCodePath, maybe_process_dir0(AppFile, ModuleSet, Config, CurrentCodePath, Dir, Command, DirSet) -> - case rebar_app_utils:is_skipped_app(AppFile) of - {true, SkippedApp} -> + case rebar_app_utils:is_skipped_app(Config, AppFile) of + {Config1, {true, SkippedApp}} -> ?DEBUG("Skipping app: ~p~n", [SkippedApp]), - increment_operations(), - DirSet; - false -> - process_dir0(Dir, Command, DirSet, Config, + Config2 = increment_operations(Config1), + {Config2, DirSet}; + {Config1, false} -> + process_dir0(Dir, Command, DirSet, Config1, CurrentCodePath, ModuleSet) end. @@ -179,64 +153,63 @@ process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath, %% Invoke 'preprocess' on the modules -- this yields a list of other %% directories that should be processed _before_ the current one. - Predirs = acc_modules(Modules, preprocess, Config0, ModuleSetFile), + {Config1, Predirs} = acc_modules(Modules, preprocess, Config0, + ModuleSetFile), SubdirAssoc = remember_cwd_subdir(Dir, Predirs), %% Get the list of plug-in modules from rebar.config. These %% modules may participate in preprocess and postprocess. - {ok, PluginModules} = plugin_modules(Config0, SubdirAssoc), + {ok, PluginModules} = plugin_modules(Config1, SubdirAssoc), - PluginPredirs = acc_modules(PluginModules, preprocess, - Config0, ModuleSetFile), + {Config2, PluginPredirs} = acc_modules(PluginModules, preprocess, + Config1, ModuleSetFile), AllPredirs = Predirs ++ PluginPredirs, ?DEBUG("Predirs: ~p\n", [AllPredirs]), - DirSet2 = process_each(AllPredirs, Command, Config0, - ModuleSetFile, DirSet), + {Config3, DirSet2} = process_each(AllPredirs, Command, Config2, + ModuleSetFile, DirSet), %% Make sure the CWD is reset properly; processing the dirs may have %% caused it to change ok = file:set_cwd(Dir), %% Check that this directory is not on the skip list - Config = case is_skip_dir(Dir) of - true -> - %% Do not execute the command on the directory, as some - %% module has requested a skip on it. - ?INFO("Skipping ~s in ~s\n", [Command, Dir]), - Config0; - - false -> - %% Check for and get command specific environments - {Config1, Env} = setup_envs(Config0, Modules), - - %% Execute any before_command plugins on this directory - execute_pre(Command, PluginModules, - Config1, ModuleSetFile, Env), - - %% Execute the current command on this directory - execute(Command, Modules ++ PluginModules, - Config1, ModuleSetFile, Env), - - %% Execute any after_command plugins on this directory - execute_post(Command, PluginModules, - Config1, ModuleSetFile, Env), - - Config1 - end, + Config7 = case rebar_config:is_skip_dir(Config3, Dir) of + true -> + %% Do not execute the command on the directory, as some + %% module has requested a skip on it. + ?INFO("Skipping ~s in ~s\n", [Command, Dir]), + Config3; + + false -> + %% Check for and get command specific environments + {Config4, Env} = setup_envs(Config3, Modules), + + %% Execute any before_command plugins on this directory + Config5 = execute_pre(Command, PluginModules, + Config4, ModuleSetFile, Env), + + %% Execute the current command on this directory + Config6 = execute(Command, Modules ++ PluginModules, + Config5, ModuleSetFile, Env), + + %% Execute any after_command plugins on this directory + execute_post(Command, PluginModules, + Config6, ModuleSetFile, Env) + end, %% Mark the current directory as processed DirSet3 = sets:add_element(Dir, DirSet2), %% Invoke 'postprocess' on the modules. This yields a list of other %% directories that should be processed _after_ the current one. - Postdirs = acc_modules(Modules ++ PluginModules, postprocess, - Config, ModuleSetFile), + {Config8, Postdirs} = acc_modules(Modules ++ PluginModules, postprocess, + Config7, ModuleSetFile), ?DEBUG("Postdirs: ~p\n", [Postdirs]), - DirSet4 = process_each(Postdirs, Command, Config, - ModuleSetFile, DirSet3), + Res = process_each(Postdirs, Command, Config8, + ModuleSetFile, DirSet3), %% Make sure the CWD is reset properly; processing the dirs may have %% caused it to change @@ -246,8 +219,8 @@ process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath, %% the parent initialized it to restore_code_path(CurrentCodePath), - %% Return the updated dirset as our result - DirSet4. + %% Return the updated {config, dirset} as result + Res. remember_cwd_subdir(Cwd, Subdirs) -> Store = fun(Dir, Dict) -> @@ -269,30 +242,32 @@ remember_cwd_subdir(Cwd, Subdirs) -> maybe_load_local_config(Dir, ParentConfig) -> %% We need to ensure we don't overwrite custom %% config when we are dealing with base_dir. - case processing_base_dir(Dir) of + case rebar_utils:processing_base_dir(ParentConfig, Dir) of true -> ParentConfig; false -> rebar_config:new(ParentConfig) end. -processing_base_dir(Dir) -> - Dir == rebar_config:get_global(base_dir, undefined). - %% %% Given a list of directories and a set of previously processed directories, %% process each one we haven't seen yet %% -process_each([], _Command, _Config, _ModuleSetFile, DirSet) -> - DirSet; +process_each([], _Command, Config, _ModuleSetFile, DirSet) -> + %% reset cached (setup_env) envs + Config1 = rebar_config:reset_envs(Config), + {Config1, DirSet}; process_each([Dir | Rest], Command, Config, ModuleSetFile, DirSet) -> case sets:is_element(Dir, DirSet) of true -> ?DEBUG("Skipping ~s; already processed!\n", [Dir]), process_each(Rest, Command, Config, ModuleSetFile, DirSet); false -> - DirSet2 = process_dir(Dir, Config, Command, DirSet), - process_each(Rest, Command, Config, ModuleSetFile, DirSet2) + {Config1, DirSet2} = process_dir(Dir, Config, Command, DirSet), + Config2 = rebar_config:clean_config(Config, Config1), + %% reset cached (setup_env) envs + Config3 = rebar_config:reset_envs(Config2), + process_each(Rest, Command, Config3, ModuleSetFile, DirSet2) end. @@ -343,24 +318,25 @@ execute(Command, Modules, Config, ModuleFile, Env) -> false -> ?WARN("'~p' command does not apply to directory ~s\n", [Command, rebar_utils:get_cwd()]) - end; + end, + Config; TargetModules -> %% Provide some info on where we are Dir = rebar_utils:get_cwd(), ?CONSOLE("==> ~s (~s)\n", [filename:basename(Dir), Command]), - increment_operations(), + Config1 = increment_operations(Config), %% Run the available modules - apply_hooks(pre_hooks, Config, Command, Env), + apply_hooks(pre_hooks, Config1, Command, Env), case catch(run_modules(TargetModules, Command, - Config, ModuleFile)) of - ok -> - apply_hooks(post_hooks, Config, Command, Env), - ok; + Config1, ModuleFile)) of + {ok, NewConfig} -> + apply_hooks(post_hooks, NewConfig, Command, Env), + NewConfig; {error, failed} -> - ?ABORT; + ?FAIL; {Module, {error, _} = Other} -> ?ABORT("~p failed while processing ~s in module ~s: ~s\n", [Command, Dir, Module, @@ -373,9 +349,12 @@ execute(Command, Modules, Config, ModuleFile, Env) -> %% Increment the count of operations, since some module %% responds to this command -increment_operations() -> - erlang:put(operations, erlang:get(operations) + 1). +increment_operations(Config) -> + Operations = get_operations(Config), + rebar_config:set_xconf(Config, operations, Operations + 1). +get_operations(Config) -> + rebar_config:get_xconf(Config, operations). update_code_path(Config) -> case rebar_config:get_local(Config, lib_dirs, []) of @@ -393,9 +372,11 @@ restore_code_path(no_change) -> restore_code_path({old, Path}) -> %% Verify that all of the paths still exist -- some dynamically %% added paths can get blown away during clean. - true = code:set_path([F || F <- Path, filelib:is_file(F)]), + true = code:set_path([F || F <- Path, erl_prim_loader_is_file(F)]), ok. +erl_prim_loader_is_file(File) -> + erl_prim_loader:read_file_info(File) =/= error. expand_lib_dirs([], _Root, Acc) -> Acc; @@ -417,12 +398,14 @@ select_modules([Module | Rest], Command, Acc) -> select_modules(Rest, Command, Acc) end. -run_modules([], _Command, _Config, _File) -> - ok; +run_modules([], _Command, Config, _File) -> + {ok, Config}; run_modules([Module | Rest], Command, Config, File) -> case Module:Command(Config, File) of ok -> run_modules(Rest, Command, Config, File); + {ok, NewConfig} -> + run_modules(Rest, Command, NewConfig, File); {error, _} = Error -> {Module, Error} end. @@ -450,7 +433,7 @@ setup_envs(Config, Modules) -> case erlang:function_exported(M, setup_env, 1) of true -> Env = M:setup_env(C), - C1 = rebar_config:set_env(C, M, Env), + C1 = rebar_config:save_env(C, M, Env), {C1, E++Env}; false -> T @@ -461,11 +444,16 @@ acc_modules(Modules, Command, Config, File) -> acc_modules(select_modules(Modules, Command, []), Command, Config, File, []). -acc_modules([], _Command, _Config, _File, Acc) -> - Acc; +acc_modules([], _Command, Config, _File, Acc) -> + {Config, Acc}; acc_modules([Module | Rest], Command, Config, File, Acc) -> - {ok, Dirs} = Module:Command(Config, File), - acc_modules(Rest, Command, Config, File, Acc ++ Dirs). + {Config1, Dirs1} = case Module:Command(Config, File) of + {ok, Dirs} -> + {Config, Dirs}; + {ok, NewConfig, Dirs} -> + {NewConfig, Dirs} + end, + acc_modules(Rest, Command, Config1, File, Acc ++ Dirs1). %% %% Return a flat list of rebar plugin modules. |