diff options
author | Tuncer Ayaz <tuncer.ayaz@gmail.com> | 2012-04-22 21:53:32 +0200 |
---|---|---|
committer | Tuncer Ayaz <tuncer.ayaz@gmail.com> | 2012-07-13 15:21:56 +0200 |
commit | e185e86bff17fa7d093f8b24fcc45069ffde55ae (patch) | |
tree | 08cbdc29922bc67d691f21be9d76d7a5c8d4c668 /src | |
parent | 1948eb4a47c1aa61aebbd046aa951f103a1f8644 (diff) |
Remove shared state
Diffstat (limited to 'src')
-rw-r--r-- | src/rebar.erl | 13 | ||||
-rw-r--r-- | src/rebar_app_utils.erl | 95 | ||||
-rw-r--r-- | src/rebar_appups.erl | 6 | ||||
-rw-r--r-- | src/rebar_config.erl | 118 | ||||
-rw-r--r-- | src/rebar_core.erl | 243 | ||||
-rw-r--r-- | src/rebar_deps.erl | 231 | ||||
-rw-r--r-- | src/rebar_edoc.erl | 7 | ||||
-rw-r--r-- | src/rebar_escripter.erl | 13 | ||||
-rw-r--r-- | src/rebar_eunit.erl | 54 | ||||
-rw-r--r-- | src/rebar_otp_app.erl | 34 | ||||
-rw-r--r-- | src/rebar_port_compiler.erl | 37 | ||||
-rw-r--r-- | src/rebar_rel_utils.erl | 29 | ||||
-rw-r--r-- | src/rebar_reltool.erl | 21 | ||||
-rw-r--r-- | src/rebar_subdirs.erl | 2 | ||||
-rw-r--r-- | src/rebar_upgrade.erl | 6 | ||||
-rw-r--r-- | src/rebar_utils.erl | 17 |
16 files changed, 496 insertions, 430 deletions
diff --git a/src/rebar.erl b/src/rebar.erl index 0b7602b..5812170 100644 --- a/src/rebar.erl +++ b/src/rebar.erl @@ -103,9 +103,6 @@ run_aux(Commands) -> %% Initialize logging system rebar_log:init(), - %% Initialize vsn cache - _VsnCacheTab = ets:new(rebar_vsn_cache,[named_table, public]), - %% Convert command strings to atoms CommandAtoms = [list_to_atom(C) || C <- Commands], @@ -118,9 +115,6 @@ run_aux(Commands) -> %% Note the top-level directory for reference rebar_config:set_global(base_dir, filename:absname(rebar_utils:get_cwd())), - %% Keep track of how many operations we do, so we can detect bad commands - erlang:put(operations, 0), - %% If $HOME/.rebar/config exists load and use as global config GlobalConfigFile = filename:join([os:getenv("HOME"), ".rebar", "config"]), GlobalConfig = case filelib:is_regular(GlobalConfigFile) of @@ -133,8 +127,13 @@ run_aux(Commands) -> end, BaseConfig = rebar_config:base_config(GlobalConfig), + %% Keep track of how many operations we do, so we can detect bad commands + BaseConfig1 = rebar_config:set_xconf(BaseConfig, operations, 0), + %% Initialize vsn cache + BaseConfig2 = rebar_config:set_xconf(BaseConfig1, vsn_cache, dict:new()), + %% Process each command, resetting any state between each one - rebar_core:process_commands(CommandAtoms, BaseConfig). + rebar_core:process_commands(CommandAtoms, BaseConfig2). %% %% print help/usage string diff --git a/src/rebar_app_utils.erl b/src/rebar_app_utils.erl index dbc2c44..1d2583a 100644 --- a/src/rebar_app_utils.erl +++ b/src/rebar_app_utils.erl @@ -29,12 +29,12 @@ -export([is_app_dir/0, is_app_dir/1, is_app_src/1, app_src_to_app/1, - app_name/1, - app_applications/1, - app_vsn/1, - is_skipped_app/1]). + app_name/2, + app_applications/2, + app_vsn/2, + is_skipped_app/2]). --export([load_app_file/1]). % TEMPORARY +-export([load_app_file/2]). % TEMPORARY -include("rebar.hrl"). @@ -77,75 +77,80 @@ is_app_src(Filename) -> app_src_to_app(Filename) -> filename:join("ebin", filename:basename(Filename, ".app.src") ++ ".app"). -app_name(AppFile) -> - case load_app_file(AppFile) of - {ok, AppName, _} -> - AppName; +app_name(Config, AppFile) -> + case load_app_file(Config, AppFile) of + {ok, NewConfig, AppName, _} -> + {NewConfig, AppName}; {error, Reason} -> ?ABORT("Failed to extract name from ~s: ~p\n", [AppFile, Reason]) end. -app_applications(AppFile) -> - case load_app_file(AppFile) of - {ok, _, AppInfo} -> - get_value(applications, AppInfo, AppFile); +app_applications(Config, AppFile) -> + case load_app_file(Config, AppFile) of + {ok, NewConfig, _, AppInfo} -> + {NewConfig, get_value(applications, AppInfo, AppFile)}; {error, Reason} -> ?ABORT("Failed to extract applications from ~s: ~p\n", [AppFile, Reason]) end. -app_vsn(AppFile) -> - case load_app_file(AppFile) of - {ok, _, AppInfo} -> +app_vsn(Config, AppFile) -> + case load_app_file(Config, AppFile) of + {ok, Config1, _, AppInfo} -> AppDir = filename:dirname(filename:dirname(AppFile)), - rebar_utils:vcs_vsn(get_value(vsn, AppInfo, AppFile), AppDir); + rebar_utils:vcs_vsn(Config1, get_value(vsn, AppInfo, AppFile), + AppDir); {error, Reason} -> ?ABORT("Failed to extract vsn from ~s: ~p\n", [AppFile, Reason]) end. -is_skipped_app(AppFile) -> - ThisApp = app_name(AppFile), +is_skipped_app(Config, AppFile) -> + {Config1, ThisApp} = app_name(Config, AppFile), %% Check for apps global parameter; this is a comma-delimited list %% of apps on which we want to run commands - case get_apps() of - undefined -> - %% No apps parameter specified, check the skip_apps list.. - case get_skip_apps() of - undefined -> - %% No skip_apps list, run everything.. - false; - SkipApps -> - TargetApps = [list_to_atom(A) || - A <- string:tokens(SkipApps, ",")], - is_skipped_app(ThisApp, TargetApps) - end; - Apps -> - %% run only selected apps - TargetApps = [list_to_atom(A) || A <- string:tokens(Apps, ",")], - is_selected_app(ThisApp, TargetApps) - end. + Skipped = + case get_apps() of + undefined -> + %% No apps parameter specified, check the skip_apps list.. + case get_skip_apps() of + undefined -> + %% No skip_apps list, run everything.. + false; + SkipApps -> + TargetApps = [list_to_atom(A) || + A <- string:tokens(SkipApps, ",")], + is_skipped(ThisApp, TargetApps) + end; + Apps -> + %% run only selected apps + TargetApps = [list_to_atom(A) || A <- string:tokens(Apps, ",")], + is_selected(ThisApp, TargetApps) + end, + {Config1, Skipped}. %% =================================================================== %% Internal functions %% =================================================================== -load_app_file(Filename) -> +load_app_file(Config, Filename) -> AppFile = {app_file, Filename}, - case erlang:get(AppFile) of - undefined -> + case rebar_config:get_xconf(Config, {appfile, AppFile}) of + error -> case file:consult(Filename) of {ok, [{application, AppName, AppData}]} -> - erlang:put(AppFile, {AppName, AppData}), - {ok, AppName, AppData}; + Config1 = rebar_config:set_xconf(Config, + {appfile, AppFile}, + {AppName, AppData}), + {ok, Config1, AppName, AppData}; {error, _} = Error -> Error; Other -> {error, {unexpected_terms, Other}} end; - {AppName, AppData} -> - {ok, AppName, AppData} + {ok, {AppName, AppData}} -> + {ok, Config, AppName, AppData} end. get_value(Key, AppInfo, AppFile) -> @@ -157,7 +162,7 @@ get_value(Key, AppInfo, AppFile) -> end. %% apps= for selecting apps -is_selected_app(ThisApp, TargetApps) -> +is_selected(ThisApp, TargetApps) -> case lists:member(ThisApp, TargetApps) of false -> {true, ThisApp}; @@ -166,7 +171,7 @@ is_selected_app(ThisApp, TargetApps) -> end. %% skip_apps= for filtering apps -is_skipped_app(ThisApp, TargetApps) -> +is_skipped(ThisApp, TargetApps) -> case lists:member(ThisApp, TargetApps) of false -> false; diff --git a/src/rebar_appups.erl b/src/rebar_appups.erl index 6271e77..88cf8d9 100644 --- a/src/rebar_appups.erl +++ b/src/rebar_appups.erl @@ -38,9 +38,9 @@ %% Public API %% ==================================================================== -'generate-appups'(_Config, ReltoolFile) -> +'generate-appups'(Config, ReltoolFile) -> %% Get the old release path - ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + {Config1, ReltoolConfig} = rebar_rel_utils:load_config(Config, ReltoolFile), TargetParentDir = rebar_rel_utils:get_target_parent_dir(ReltoolConfig), OldVerPath = filename:join([TargetParentDir, @@ -75,7 +75,7 @@ %% Generate appup files for upgraded apps generate_appup_files(NewVerPath, OldVerPath, UpgradeApps), - ok. + {ok, Config1}. %% =================================================================== %% Internal functions diff --git a/src/rebar_config.erl b/src/rebar_config.erl index 7f7d03c..c2d59b2 100644 --- a/src/rebar_config.erl +++ b/src/rebar_config.erl @@ -32,13 +32,19 @@ set/3, set_global/2, get_global/2, is_verbose/0, get_jobs/0, - set_env/3, get_env/2]). + set_env/3, get_env/2, + set_skip_dir/2, is_skip_dir/2, reset_skip_dirs/1, + clean_config/2, + set_xconf/3, get_xconf/2, erase_xconf/2, reset_xconf/1]). -include("rebar.hrl"). -record(config, { dir :: file:filename(), opts = [] :: list(), - envs = new_env() :: dict() }). + envs = new_env() :: dict(), + %% cross-directory config + skip_dirs = new_skip_dirs() :: dict(), + xconf = new_xconf() :: dict() }). %% Types that can be used from other modules -- alphabetically ordered. -export_type([config/0]). @@ -46,13 +52,15 @@ %% data types -opaque config() :: #config{}. +-define(DEFAULT_NAME, "rebar.config"). + %% =================================================================== %% Public API %% =================================================================== -base_config(#config{opts=Opts0}) -> - ConfName = rebar_config:get_global(config, "rebar.config"), - new(Opts0, ConfName). +base_config(GlobalConfig) -> + ConfName = rebar_config:get_global(config, ?DEFAULT_NAME), + new(GlobalConfig, ConfName). new() -> #config{dir = rebar_utils:get_cwd()}. @@ -65,31 +73,8 @@ new(ConfigFile) when is_list(ConfigFile) -> Other -> ?ABORT("Failed to load ~s: ~p~n", [ConfigFile, Other]) end; -new(_ParentConfig=#config{opts=Opts0})-> - new(Opts0, "rebar.config"). - -new(Opts0, ConfName) -> - %% Load terms from rebar.config, if it exists - Dir = rebar_utils:get_cwd(), - ConfigFile = filename:join([Dir, ConfName]), - Opts = case consult_file(ConfigFile) of - {ok, Terms} -> - %% Found a config file with some terms. We need to - %% be able to distinguish between local definitions - %% (i.e. from the file in the cwd) and inherited - %% definitions. To accomplish this, we use a marker - %% in the proplist (since order matters) between - %% the new and old defs. - Terms ++ [local] ++ - [Opt || Opt <- Opts0, Opt /= local]; - {error, enoent} -> - [local] ++ - [Opt || Opt <- Opts0, Opt /= local]; - Other -> - ?ABORT("Failed to load ~s: ~p\n", [ConfigFile, Other]) - end, - - #config{dir = Dir, opts = Opts}. +new(_ParentConfig=#config{opts=Opts0, skip_dirs=SkipDirs, xconf=Xconf})-> + new(#config{opts=Opts0, skip_dirs=SkipDirs, xconf=Xconf}, ?DEFAULT_NAME). get(Config, Key, Default) -> proplists:get_value(Key, Config#config.opts, Default). @@ -145,17 +130,74 @@ consult_file(File) -> end. set_env(Config, Mod, Env) -> - OldEnvs = Config#config.envs, - NewEnvs = dict:store(Mod, Env, OldEnvs), - Config#config{envs=NewEnvs}. + NewEnvs = dict:store(Mod, Env, Config#config.envs), + Config#config{envs = NewEnvs}. get_env(Config, Mod) -> dict:fetch(Mod, Config#config.envs). +set_skip_dir(Config, Dir) -> + OldSkipDirs = Config#config.skip_dirs, + NewSkipDirs = case is_skip_dir(Config, Dir) of + false -> + ?DEBUG("Adding skip dir: ~s\n", [Dir]), + dict:store(Dir, true, OldSkipDirs); + true -> + OldSkipDirs + end, + Config#config{skip_dirs = NewSkipDirs}. + +is_skip_dir(Config, Dir) -> + dict:is_key(Dir, Config#config.skip_dirs). + +reset_skip_dirs(Config) -> + Config#config{skip_dirs = new_skip_dirs()}. + +set_xconf(Config, Key, Value) -> + NewXconf = dict:store(Key, Value, Config#config.xconf), + Config#config{xconf=NewXconf}. + +get_xconf(Config, Key) -> + dict:find(Key, Config#config.xconf). + +erase_xconf(Config, Key) -> + NewXconf = dict:erase(Key, Config#config.xconf), + Config#config{xconf = NewXconf}. + +reset_xconf(Config) -> + Config#config{xconf = new_xconf()}. + +clean_config(Old, New) -> + New#config{opts=Old#config.opts}. + %% =================================================================== %% Internal functions %% =================================================================== +new(ParentConfig, ConfName) -> + %% Load terms from rebar.config, if it exists + Dir = rebar_utils:get_cwd(), + ConfigFile = filename:join([Dir, ConfName]), + Opts0 = ParentConfig#config.opts, + Opts = case consult_file(ConfigFile) of + {ok, Terms} -> + %% Found a config file with some terms. We need to + %% be able to distinguish between local definitions + %% (i.e. from the file in the cwd) and inherited + %% definitions. To accomplish this, we use a marker + %% in the proplist (since order matters) between + %% the new and old defs. + Terms ++ [local] ++ + [Opt || Opt <- Opts0, Opt /= local]; + {error, enoent} -> + [local] ++ + [Opt || Opt <- Opts0, Opt /= local]; + Other -> + ?ABORT("Failed to load ~s: ~p\n", [ConfigFile, Other]) + end, + + ParentConfig#config{dir = Dir, opts = Opts}. + consult_and_eval(File, Script) -> ?DEBUG("Evaluating config script ~p~n", [Script]), ConfigData = try_consult(File), @@ -171,7 +213,8 @@ try_consult(File) -> {ok, Terms} -> ?DEBUG("Consult config file ~p~n", [File]), Terms; - {error, enoent} -> []; + {error, enoent} -> + []; {error, Reason} -> ?ABORT("Failed to read config file ~s: ~p~n", [File, Reason]) end. @@ -188,5 +231,8 @@ local_opts([local | _Rest], Acc) -> local_opts([Item | Rest], Acc) -> local_opts(Rest, [Item | Acc]). -new_env() -> - dict:new(). +new_env() -> dict:new(). + +new_skip_dirs() -> dict:new(). + +new_xconf() -> dict:new(). diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 99d3c38..b175f50 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -26,46 +26,17 @@ %% ------------------------------------------------------------------- -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) -> +process_commands([], ParentConfig) -> AbortTrapped = rebar_config:get_global(abort_trapped, false), - case {erlang:get(operations), AbortTrapped} of + case {get_operations(ParentConfig), AbortTrapped} of {0, _} -> %% None of the commands had any effect ?ABORT; @@ -76,47 +47,49 @@ process_commands([], _ParentConfig) -> 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 = rebar_config:get_xconf(ParentConfig1, operations), + + 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, + 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_global(keep_going, false) of + false -> + ?ABORT; + true -> + ?WARN("Continuing on after abort: ~p\n", [Rest]), + rebar_config:set_global(abort_trapped, true), + ParentConfig1 + 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 +130,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 +152,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 +218,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 our result + Res. remember_cwd_subdir(Cwd, Subdirs) -> Store = fun(Dir, Dict) -> @@ -283,16 +255,17 @@ processing_base_dir(Dir) -> %% 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) -> + {Config, 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), + process_each(Rest, Command, Config2, ModuleSetFile, DirSet2) end. @@ -343,22 +316,23 @@ 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; {Module, {error, _} = Other} -> @@ -373,9 +347,13 @@ 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) -> + {ok, Operations} = rebar_config:get_xconf(Config, operations), + Operations. update_code_path(Config) -> case rebar_config:get_local(Config, lib_dirs, []) of @@ -417,12 +395,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. @@ -461,11 +441,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. diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl index dc2fe84..1abdce7 100644 --- a/src/rebar_deps.erl +++ b/src/rebar_deps.erl @@ -57,37 +57,37 @@ preprocess(Config, _) -> %% Get the list of deps for the current working directory and identify those %% deps that are available/present. Deps = rebar_config:get_local(Config, deps, []), - {AvailableDeps, MissingDeps} = find_deps(find, Deps), + {Config1, {AvailableDeps, MissingDeps}} = find_deps(Config, find, Deps), ?DEBUG("Available deps: ~p\n", [AvailableDeps]), ?DEBUG("Missing deps : ~p\n", [MissingDeps]), %% Add available deps to code path - update_deps_code_path(AvailableDeps), + Config2 = update_deps_code_path(Config1, AvailableDeps), %% If skip_deps=true, mark each dep dir as a skip_dir w/ the core so that %% the current command doesn't run on the dep dir. However, pre/postprocess %% WILL run (and we want it to) for transitivity purposes. - case rebar_config:get_global(skip_deps, false) of - "true" -> - lists:foreach(fun (#dep{dir = Dir}) -> - rebar_core:skip_dir(Dir) - end, AvailableDeps); - _ -> - ok - end, + NewConfig = case rebar_config:get_global(skip_deps, false) of + "true" -> + lists:foldl( + fun(#dep{dir = Dir}, C) -> + rebar_config:set_skip_dir(C, Dir) + end, Config2, AvailableDeps); + _ -> + Config2 + end, %% Return all the available dep directories for process - {ok, [D#dep.dir || D <- AvailableDeps]}. - + {ok, NewConfig, dep_dirs(AvailableDeps)}. -postprocess(_Config, _) -> - case erlang:get(?MODULE) of - undefined -> +postprocess(Config, _) -> + case rebar_config:get_xconf(Config, ?MODULE) of + error -> {ok, []}; - Dirs -> - erlang:erase(?MODULE), - {ok, Dirs} + {ok, Dirs} -> + NewConfig = rebar_config:erase_xconf(Config, ?MODULE), + {ok, NewConfig, Dirs} end. compile(Config, AppFile) -> @@ -114,11 +114,11 @@ setup_env(_Config) -> 'check-deps'(Config, _) -> %% Get the list of immediate (i.e. non-transitive) deps that are missing Deps = rebar_config:get_local(Config, deps, []), - case find_deps(find, Deps) of - {_, []} -> + case find_deps(Config, find, Deps) of + {Config1, {_, []}} -> %% No missing deps - ok; - {_, MissingDeps} -> + {ok, Config1}; + {_Config1, {_, MissingDeps}} -> lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) -> ?CONSOLE("Dependency not available: " "~p-~s (~p)\n", [App, Vsn, Src]) @@ -129,47 +129,52 @@ setup_env(_Config) -> 'get-deps'(Config, _) -> %% Determine what deps are available and missing Deps = rebar_config:get_local(Config, deps, []), - {_AvailableDeps, MissingDeps} = find_deps(find, Deps), + {Config1, {_AvailableDeps, MissingDeps}} = find_deps(Config, find, Deps), + MissingDeps1 = [D || D <- MissingDeps, D#dep.source =/= undefined], %% For each missing dep with a specified source, try to pull it. - PulledDeps = [use_source(D) || D <- MissingDeps, D#dep.source /= undefined], + {Config2, PulledDeps} = + lists:foldl(fun(D, {C, PulledDeps0}) -> + {C1, D1} = use_source(C, D), + {C1, [D1 | PulledDeps0]} + end, {Config1, []}, MissingDeps1), %% Add each pulled dep to our list of dirs for post-processing. This yields %% the necessary transitivity of the deps - erlang:put(?MODULE, [D#dep.dir || D <- PulledDeps]), - ok. + {ok, save_dep_dirs(Config2, lists:reverse(PulledDeps))}. 'update-deps'(Config, _) -> - %% Determine what deps are available and missing - Deps = rebar_config:get_local(Config, deps, []), - UpdatedDeps = [update_source(D) || D <- find_deps(read, Deps), - D#dep.source /= undefined], + %% Determine what deps are required + RawDeps = rebar_config:get_local(Config, deps, []), + {Config1, Deps} = find_deps(Config, read, RawDeps), + + %% Update each dep + UpdatedDeps = [update_source(D) || D <- Deps, D#dep.source =/= undefined], + %% Add each updated dep to our list of dirs for post-processing. This yields %% the necessary transitivity of the deps - erlang:put(?MODULE, [D#dep.dir || D <- UpdatedDeps]), - ok. + {ok, save_dep_dirs(Config1, UpdatedDeps)}. 'delete-deps'(Config, _) -> %% Delete all the available deps in our deps/ directory, if any {true, DepsDir} = get_deps_dir(), Deps = rebar_config:get_local(Config, deps, []), - {AvailableDeps, _} = find_deps(find, Deps), + {Config1, {AvailableDeps, _}} = find_deps(Config, find, Deps), _ = [delete_dep(D) || D <- AvailableDeps, lists:prefix(DepsDir, D#dep.dir)], - ok. + {ok, Config1}. 'list-deps'(Config, _) -> Deps = rebar_config:get_local(Config, deps, []), - case find_deps(find, Deps) of - {AvailDeps, []} -> + case find_deps(Config, find, Deps) of + {Config1, {AvailDeps, []}} -> lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps), - ok; + {ok, Config1}; {_, MissingDeps} -> ?ABORT("Missing dependencies: ~p\n", [MissingDeps]) end. - %% =================================================================== %% Internal functions %% =================================================================== @@ -191,6 +196,12 @@ get_deps_dir(App) -> DepsDir = rebar_config:get_global(deps_dir, "deps"), {true, filename:join([BaseDir, DepsDir, App])}. +dep_dirs(Deps) -> + [D#dep.dir || D <- Deps]. + +save_dep_dirs(Config, Deps) -> + rebar_config:set_xconf(Config, ?MODULE, dep_dirs(Deps)). + get_lib_dir(App) -> %% Find App amongst the reachable lib directories %% Returns either the found path or a tagged tuple with a boolean @@ -200,72 +211,77 @@ get_lib_dir(App) -> Path -> {true, Path} end. -update_deps_code_path([]) -> - ok; -update_deps_code_path([Dep | Rest]) -> - case is_app_available(Dep#dep.app, Dep#dep.vsn_regex, Dep#dep.dir) of - {true, _} -> - Dir = filename:join(Dep#dep.dir, "ebin"), - ok = filelib:ensure_dir(filename:join(Dir, "dummy")), - ?DEBUG("Adding ~s to code path~n", [Dir]), - true = code:add_patha(Dir); - {false, _} -> - true - end, - update_deps_code_path(Rest). - - -find_deps(find=Mode, Deps) -> - find_deps(Mode, Deps, {[], []}); -find_deps(read=Mode, Deps) -> - find_deps(Mode, Deps, []). - -find_deps(find, [], {Avail, Missing}) -> - {lists:reverse(Avail), lists:reverse(Missing)}; -find_deps(read, [], Deps) -> - lists:reverse(Deps); -find_deps(Mode, [App | Rest], Acc) when is_atom(App) -> - find_deps(Mode, [{App, ".*", undefined} | Rest], Acc); -find_deps(Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) -> - find_deps(Mode, [{App, VsnRegex, undefined} | Rest], Acc); -find_deps(Mode, [{App, VsnRegex, Source} | Rest], Acc) -> +update_deps_code_path(Config, []) -> + Config; +update_deps_code_path(Config, [Dep | Rest]) -> + Config2 = + case is_app_available(Config, Dep#dep.app, + Dep#dep.vsn_regex, Dep#dep.dir) of + {Config1, {true, _}} -> + Dir = filename:join(Dep#dep.dir, "ebin"), + ok = filelib:ensure_dir(filename:join(Dir, "dummy")), + ?DEBUG("Adding ~s to code path~n", [Dir]), + true = code:add_patha(Dir), + Config1; + {Config1, {false, _}} -> + Config1 + end, + update_deps_code_path(Config2, Rest). + +find_deps(Config, find=Mode, Deps) -> + find_deps(Config, Mode, Deps, {[], []}); +find_deps(Config, read=Mode, Deps) -> + find_deps(Config, Mode, Deps, []). + +find_deps(Config, find, [], {Avail, Missing}) -> + {Config, {lists:reverse(Avail), lists:reverse(Missing)}}; +find_deps(Config, read, [], Deps) -> + {Config, lists:reverse(Deps)}; +find_deps(Config, Mode, [App | Rest], Acc) when is_atom(App) -> + find_deps(Config, Mode, [{App, ".*", undefined} | Rest], Acc); +find_deps(Config, Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) -> + find_deps(Config, Mode, [{App, VsnRegex, undefined} | Rest], Acc); +find_deps(Config, Mode, [{App, VsnRegex, Source} | Rest], Acc) -> Dep = #dep { app = App, vsn_regex = VsnRegex, source = Source }, - {Availability, FoundDir} = find_dep(Dep), - find_deps(Mode, Rest, acc_deps(Mode, Availability, Dep, FoundDir, Acc)); -find_deps(_Mode, [Other | _Rest], _Acc) -> + {Config1, {Availability, FoundDir}} = find_dep(Config, Dep), + find_deps(Config1, Mode, Rest, + acc_deps(Mode, Availability, Dep, FoundDir, Acc)); +find_deps(_Config, _Mode, [Other | _Rest], _Acc) -> ?ABORT("Invalid dependency specification ~p in ~s\n", [Other, rebar_utils:get_cwd()]). -find_dep(Dep) -> +find_dep(Config, Dep) -> %% Find a dep based on its source, %% e.g. {git, "https://github.com/mochi/mochiweb.git", "HEAD"} %% Deps with a source must be found (or fetched) locally. %% Those without a source may be satisfied from lib dir (get_lib_dir). - find_dep(Dep, Dep#dep.source). + find_dep(Config, Dep, Dep#dep.source). -find_dep(Dep, undefined) -> +find_dep(Config, Dep, undefined) -> %% 'source' is undefined. If Dep is not satisfied locally, %% go ahead and find it amongst the lib_dir's. - case find_dep_in_dir(Dep, get_deps_dir(Dep#dep.app)) of - {avail, _Dir} = Avail -> Avail; - {missing, _} -> find_dep_in_dir(Dep, get_lib_dir(Dep#dep.app)) + case find_dep_in_dir(Config, Dep, get_deps_dir(Dep#dep.app)) of + {_Config1, {avail, _Dir}} = Avail -> + Avail; + {Config1, {missing, _}} -> + find_dep_in_dir(Config1, Dep, get_lib_dir(Dep#dep.app)) end; -find_dep(Dep, _Source) -> +find_dep(Config, Dep, _Source) -> %% _Source is defined. Regardless of what it is, we must find it %% locally satisfied or fetch it from the original source %% into the project's deps - find_dep_in_dir(Dep, get_deps_dir(Dep#dep.app)). + find_dep_in_dir(Config, Dep, get_deps_dir(Dep#dep.app)). -find_dep_in_dir(_Dep, {false, Dir}) -> - {missing, Dir}; -find_dep_in_dir(Dep, {true, Dir}) -> +find_dep_in_dir(Config, _Dep, {false, Dir}) -> + {Config, {missing, Dir}}; +find_dep_in_dir(Config, Dep, {true, Dir}) -> App = Dep#dep.app, VsnRegex = Dep#dep.vsn_regex, - case is_app_available(App, VsnRegex, Dir) of - {true, _AppFile} -> {avail, Dir}; - {false, _} -> {missing, Dir} + case is_app_available(Config, App, VsnRegex, Dir) of + {Config1, {true, _AppFile}} -> {Config1, {avail, Dir}}; + {Config1, {false, _}} -> {Config1, {missing, Dir}} end. acc_deps(find, avail, Dep, AppDir, {Avail, Missing}) -> @@ -288,57 +304,59 @@ require_source_engine(Source) -> true = source_engine_avail(Source), ok. -is_app_available(App, VsnRegex, Path) -> +is_app_available(Config, App, VsnRegex, Path) -> ?DEBUG("is_app_available, looking for App ~p with Path ~p~n", [App, Path]), case rebar_app_utils:is_app_dir(Path) of {true, AppFile} -> - case rebar_app_utils:app_name(AppFile) of - App -> - Vsn = rebar_app_utils:app_vsn(AppFile), + case rebar_app_utils:app_name(Config, AppFile) of + {Config1, App} -> + {Config2, Vsn} = rebar_app_utils:app_vsn(Config1, AppFile), ?INFO("Looking for ~s-~s ; found ~s-~s at ~s\n", [App, VsnRegex, App, Vsn, Path]), case re:run(Vsn, VsnRegex, [{capture, none}]) of match -> - {true, Path}; + {Config2, {true, Path}}; nomatch -> ?WARN("~s has version ~p; requested regex was ~s\n", [AppFile, Vsn, VsnRegex]), - {false, {version_mismatch, - {AppFile, - {expected, VsnRegex}, {has, Vsn}}}} + {Config2, + {false, {version_mismatch, + {AppFile, + {expected, VsnRegex}, {has, Vsn}}}}} end; - OtherApp -> + {Config1, OtherApp} -> ?WARN("~s has application id ~p; expected ~p\n", [AppFile, OtherApp, App]), - {false, {name_mismatch, - {AppFile, {expected, App}, {has, OtherApp}}}} + {Config1, + {false, {name_mismatch, + {AppFile, {expected, App}, {has, OtherApp}}}}} end; false -> ?WARN("Expected ~s to be an app dir (containing ebin/*.app), " "but no .app found.\n", [Path]), - {false, {missing_app_file, Path}} + {Config, {false, {missing_app_file, Path}}} end. -use_source(Dep) -> - use_source(Dep, 3). +use_source(Config, Dep) -> + use_source(Config, Dep, 3). -use_source(Dep, 0) -> +use_source(_Config, Dep, 0) -> ?ABORT("Failed to acquire source from ~p after 3 tries.\n", [Dep#dep.source]); -use_source(Dep, Count) -> +use_source(Config, Dep, Count) -> case filelib:is_dir(Dep#dep.dir) of true -> %% Already downloaded -- verify the versioning matches the regex - case is_app_available(Dep#dep.app, + case is_app_available(Config, Dep#dep.app, Dep#dep.vsn_regex, Dep#dep.dir) of - {true, _} -> + {Config1, {true, _}} -> Dir = filename:join(Dep#dep.dir, "ebin"), ok = filelib:ensure_dir(filename:join(Dir, "dummy")), %% Available version matches up -- we're good to go; %% add the app dir to our code path true = code:add_patha(Dir), - Dep; - {false, Reason} -> + {Config1, Dep}; + {_Config1, {false, Reason}} -> %% The app that was downloaded doesn't match up (or had %% errors or something). For the time being, abort. ?ABORT("Dependency dir ~s failed application validation " @@ -349,7 +367,7 @@ use_source(Dep, Count) -> require_source_engine(Dep#dep.source), {true, TargetDir} = get_deps_dir(Dep#dep.app), download_source(TargetDir, Dep#dep.source), - use_source(Dep#dep { dir = TargetDir }, Count-1) + use_source(Config, Dep#dep { dir = TargetDir }, Count-1) end. download_source(AppDir, {hg, Url, Rev}) -> @@ -433,9 +451,6 @@ update_source(AppDir, {bzr, _Url, Rev}) -> update_source(AppDir, {rsync, Url}) -> rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s",[Url,AppDir]),[]). - - - %% =================================================================== %% Source helper functions %% =================================================================== diff --git a/src/rebar_edoc.erl b/src/rebar_edoc.erl index 5d85146..a022913 100644 --- a/src/rebar_edoc.erl +++ b/src/rebar_edoc.erl @@ -45,15 +45,14 @@ %% Public API %% =================================================================== -%% @doc Generate Erlang program documentation. --spec doc(Config::rebar_config:config(), File::file:filename()) -> ok. doc(Config, File) -> %% Save code path CodePath = setup_code_path(), %% Get the edoc_opts and app file info EDocOpts = rebar_config:get(Config, edoc_opts, []), - {ok, AppName, _AppData} = rebar_app_utils:load_app_file(File), + {ok, Config1, AppName, _AppData} = + rebar_app_utils:load_app_file(Config, File), %% Determine the age of the summary file EDocInfoName = filename:join(proplists:get_value(dir, EDocOpts, "doc"), @@ -77,7 +76,7 @@ doc(Config, File) -> %% Restore code path true = code:set_path(CodePath), - ok. + {ok, Config1}. %% =================================================================== %% Internal functions diff --git a/src/rebar_escripter.erl b/src/rebar_escripter.erl index b51a2a5..9ff59f1 100644 --- a/src/rebar_escripter.erl +++ b/src/rebar_escripter.erl @@ -36,10 +36,10 @@ %% Public API %% =================================================================== -escriptize(Config, AppFile) -> +escriptize(Config0, AppFile) -> %% Extract the application name from the archive -- this is the default %% name of the generated script - AppName = rebar_app_utils:app_name(AppFile), + {Config, AppName} = rebar_app_utils:app_name(Config0, AppFile), %% Get the output filename for the escript -- this may include dirs Filename = rebar_config:get_local(Config, escript_name, AppName), @@ -85,16 +85,17 @@ escriptize(Config, AppFile) -> %% Finally, update executable perms for our script {ok, #file_info{mode = Mode}} = file:read_file_info(Filename), ok = file:change_mode(Filename, Mode bor 8#00111), - ok. + {ok, Config}. -clean(Config, AppFile) -> +clean(Config0, AppFile) -> %% Extract the application name from the archive -- this is the default %% name of the generated script - AppName = rebar_app_utils:app_name(AppFile), + {Config, AppName} = rebar_app_utils:app_name(Config0, AppFile), %% Get the output filename for the escript -- this may include dirs Filename = rebar_config:get_local(Config, escript_name, AppName), - rebar_file_utils:delete_each([Filename]). + rebar_file_utils:delete_each([Filename]), + {ok, Config}. %% =================================================================== %% Internal functions diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl index af14896..385bb49 100644 --- a/src/rebar_eunit.erl +++ b/src/rebar_eunit.erl @@ -64,7 +64,7 @@ %% Public API %% =================================================================== -eunit(Config, _AppFile) -> +eunit(Config0, _AppFile) -> %% Make sure ?EUNIT_DIR/ and ebin/ directory exists (append dummy module) ok = filelib:ensure_dir(filename:join(eunit_dir(), "dummy")), ok = filelib:ensure_dir(filename:join(ebin_dir(), "dummy")), @@ -85,7 +85,7 @@ eunit(Config, _AppFile) -> %% Copy source files to eunit dir for cover in case they are not directly %% in src but in a subdirectory of src. Cover only looks in cwd and ../src %% for source files. Also copy files from src_dirs. - ErlOpts = rebar_utils:erl_opts(Config), + ErlOpts = rebar_utils:erl_opts(Config0), SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), SrcErls = lists:foldl( @@ -119,8 +119,8 @@ eunit(Config, _AppFile) -> %% Compile erlang code to ?EUNIT_DIR, using a tweaked config %% with appropriate defines for eunit, and include all the test modules %% as well. - rebar_erlc_compiler:doterl_compile(eunit_config(Config), - ?EUNIT_DIR, TestErls), + Config = eunit_config(Config0), + rebar_erlc_compiler:doterl_compile(Config, ?EUNIT_DIR, TestErls), %% Build a list of all the .beams in ?EUNIT_DIR -- use this for %% cover and eunit testing. Normally you can just tell cover @@ -166,7 +166,7 @@ eunit(Config, _AppFile) -> %% Restore code path true = code:set_path(CodePath), - ok. + {ok, Config}. clean(_Config, _File) -> rebar_file_utils:rm_rf(?EUNIT_DIR). @@ -218,44 +218,48 @@ get_eunit_opts(Config) -> BaseOpts ++ rebar_config:get_list(Config, eunit_opts, []). eunit_config(Config) -> - EqcOpts = eqc_opts(), - PropErOpts = proper_opts(), + {Config1, EqcOpts} = eqc_opts(Config), + {Config2, PropErOpts} = proper_opts(Config1), - ErlOpts = rebar_config:get_list(Config, erl_opts, []), - EunitOpts = rebar_config:get_list(Config, eunit_compile_opts, []), + ErlOpts = rebar_config:get_list(Config2, erl_opts, []), + EunitOpts = rebar_config:get_list(Config2, eunit_compile_opts, []), Opts0 = [{d, 'TEST'}] ++ ErlOpts ++ EunitOpts ++ EqcOpts ++ PropErOpts, Opts = [O || O <- Opts0, O =/= no_debug_info], - Config1 = rebar_config:set(Config, erl_opts, Opts), + Config3 = rebar_config:set(Config2, erl_opts, Opts), - FirstErls = rebar_config:get_list(Config1, eunit_first_files, []), - rebar_config:set(Config1, erl_first_files, FirstErls). + FirstErls = rebar_config:get_list(Config3, eunit_first_files, []), + rebar_config:set(Config3, erl_first_files, FirstErls). -eqc_opts() -> - define_if('EQC', is_lib_avail(is_eqc_avail, eqc, - "eqc.hrl", "QuickCheck")). +eqc_opts(Config) -> + {NewConfig, IsAvail} = is_lib_avail(Config, is_eqc_avail, eqc, + "eqc.hrl", "QuickCheck"), + Opts = define_if('EQC', IsAvail), + {NewConfig, Opts}. -proper_opts() -> - define_if('PROPER', is_lib_avail(is_proper_avail, proper, - "proper.hrl", "PropEr")). +proper_opts(Config) -> + {NewConfig, IsAvail} = is_lib_avail(Config, is_proper_avail, proper, + "proper.hrl", "PropEr"), + Opts = define_if('PROPER', IsAvail), + {NewConfig, Opts}. define_if(Def, true) -> [{d, Def}]; define_if(_Def, false) -> []. -is_lib_avail(DictKey, Mod, Hrl, Name) -> - case erlang:get(DictKey) of - undefined -> +is_lib_avail(Config, DictKey, Mod, Hrl, Name) -> + case rebar_config:get_xconf(Config, DictKey) of + error -> IsAvail = case code:lib_dir(Mod, include) of {error, bad_name} -> false; Dir -> filelib:is_regular(filename:join(Dir, Hrl)) end, - erlang:put(DictKey, IsAvail), + NewConfig = rebar_config:set_xconf(Config, DictKey, IsAvail), ?DEBUG("~s availability: ~p\n", [Name, IsAvail]), - IsAvail; - IsAvail -> - IsAvail + {NewConfig, IsAvail}; + {ok, IsAvail} -> + {Config, IsAvail} end. perform_cover(Config, BeamFiles, SrcModules) -> diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl index 0b2e8be..4304600 100644 --- a/src/rebar_otp_app.erl +++ b/src/rebar_otp_app.erl @@ -39,27 +39,27 @@ compile(Config, File) -> %% If we get an .app.src file, it needs to be pre-processed and %% written out as a ebin/*.app file. That resulting file will then %% be validated as usual. - AppFile = case rebar_app_utils:is_app_src(File) of - true -> - preprocess(Config, File); - false -> - File - end, + {Config1, AppFile} = case rebar_app_utils:is_app_src(File) of + true -> + preprocess(Config, File); + false -> + {Config, File} + end, %% Load the app file and validate it. - case rebar_app_utils:load_app_file(AppFile) of - {ok, AppName, AppData} -> + case rebar_app_utils:load_app_file(Config1, AppFile) of + {ok, Config2, AppName, AppData} -> validate_name(AppName, AppFile), %% In general, the list of modules is an important thing to validate %% for compliance with OTP guidelines and upgrade procedures. %% However, some people prefer not to validate this list. - case rebar_config:get_local(Config, validate_app_modules, true) of + case rebar_config:get_local(Config1, validate_app_modules, true) of true -> - validate_modules(AppName, - proplists:get_value(modules, AppData)); + Modules = proplists:get_value(modules, AppData), + {validate_modules(AppName, Modules), Config2}; false -> - ok + {ok, Config2} end; {error, Reason} -> ?ABORT("Failed to load app file ~s: ~p\n", [AppFile, Reason]) @@ -88,17 +88,17 @@ clean(_Config, File) -> %% =================================================================== preprocess(Config, AppSrcFile) -> - case rebar_app_utils:load_app_file(AppSrcFile) of - {ok, AppName, AppData} -> + case rebar_app_utils:load_app_file(Config, AppSrcFile) of + {ok, Config1, AppName, AppData} -> %% Look for a configuration file with vars we want to %% substitute. Note that we include the list of modules available in %% ebin/ and update the app data accordingly. - AppVars = load_app_vars(Config) ++ [{modules, ebin_modules()}], + AppVars = load_app_vars(Config1) ++ [{modules, ebin_modules()}], A1 = apply_app_vars(AppVars, AppData), %% AppSrcFile may contain instructions for generating a vsn number - Vsn = rebar_app_utils:app_vsn(AppSrcFile), + {Config2, Vsn} = rebar_app_utils:app_vsn(Config1, AppSrcFile), A2 = lists:keystore(vsn, 1, A1, {vsn, Vsn}), %% Build the final spec as a string @@ -112,7 +112,7 @@ preprocess(Config, AppSrcFile) -> %% on the code path true = code:add_path(filename:absname(filename:dirname(AppFile))), - AppFile; + {Config2, AppFile}; {error, Reason} -> ?ABORT("Failed to read ~s for preprocessing: ~p\n", diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl index 0ccabc8..8f38cd2 100644 --- a/src/rebar_port_compiler.erl +++ b/src/rebar_port_compiler.erl @@ -96,14 +96,14 @@ objects = [] :: [file:filename(), ...] | [], opts = [] ::list() | []}). -compile(Config, AppFile) -> - rebar_utils:deprecated(port_sources, port_specs, Config, "soon"), - rebar_utils:deprecated(so_name, port_specs, Config, "soon"), - rebar_utils:deprecated(so_specs, port_specs, Config, "soon"), +compile(Config0, AppFile) -> + rebar_utils:deprecated(port_sources, port_specs, Config0, "soon"), + rebar_utils:deprecated(so_name, port_specs, Config0, "soon"), + rebar_utils:deprecated(so_specs, port_specs, Config0, "soon"), %% TODO: remove SpecType and OldSources make get_specs/2 %% return list(#spec{}) when removing deprecated options - {SpecType, {OldSources, Specs}} = get_specs(Config, AppFile), + {Config, {SpecType, {OldSources, Specs}}} = get_specs(Config0, AppFile), case {SpecType, OldSources, Specs} of {old, [], _} -> @@ -149,7 +149,7 @@ compile(Config, AppFile) -> clean(Config, AppFile) -> %% TODO: remove SpecType and OldSources make get_specs/2 %% return list(#spec{}) when removing deprecated options - {SpecType, {OldSources, Specs}} = get_specs(Config, AppFile), + {Config1, {SpecType, {OldSources, Specs}}} = get_specs(Config, AppFile), case {SpecType, OldSources, Specs} of {old, [], _} -> @@ -163,7 +163,8 @@ clean(Config, AppFile) -> rebar_file_utils:delete_each([Target]), rebar_file_utils:delete_each(Objects) end, Specs) - end. + end, + {ok, Config1}. setup_env(Config) -> setup_env(Config, []). @@ -264,9 +265,10 @@ get_specs(Config, AppFile) -> case rebar_config:get_local(Config, port_specs, undefined) of undefined -> %% TODO: DEPRECATED: remove support for non-port_specs syntax - {old, old_get_specs(Config, AppFile)}; + {Config1, Specs} = old_get_specs(Config, AppFile), + {Config1, {old, Specs}}; PortSpecs -> - {new, get_port_specs(Config, PortSpecs)} + {Config, {new, get_port_specs(Config, PortSpecs)}} end. get_port_specs(Config, PortSpecs) -> @@ -327,31 +329,32 @@ switch_to_dll_or_exe(Target) -> old_get_specs(Config, AppFile) -> OsType = os:type(), SourceFiles = old_get_sources(Config), - Specs = + {NewConfig, Specs} = case rebar_config:get_local(Config, so_specs, undefined) of undefined -> Objects = port_objects(SourceFiles), %% New form of so_specs is not provided. See if the old form %% of {so_name} is available instead Dir = "priv", - SoName = + {Config2, SoName} = case rebar_config:get_local(Config, so_name, undefined) of undefined -> %% Ok, neither old nor new form is %% available. Use the app name and %% generate a sensible default. - AppName = rebar_app_utils:app_name(AppFile), + {Config1, AppName} = + rebar_app_utils:app_name(Config, AppFile), DrvName = ?FMT("~s_drv.so", [AppName]), - filename:join([Dir, DrvName]); + {Config1, filename:join([Dir, DrvName])}; AName -> %% Old form is available -- use it - filename:join(Dir, AName) + {Config, filename:join(Dir, AName)} end, - [old_get_so_spec({SoName, Objects}, OsType)]; + {Config2, [old_get_so_spec({SoName, Objects}, OsType)]}; SoSpecs -> - [old_get_so_spec(S, OsType) || S <- SoSpecs] + {Config, [old_get_so_spec(S, OsType) || S <- SoSpecs]} end, - {SourceFiles, Specs}. + {NewConfig, {SourceFiles, Specs}}. old_get_sources(Config) -> RawSources = rebar_config:get_local(Config, port_sources, diff --git a/src/rebar_rel_utils.erl b/src/rebar_rel_utils.erl index e502743..3c94d97 100644 --- a/src/rebar_rel_utils.erl +++ b/src/rebar_rel_utils.erl @@ -35,7 +35,7 @@ get_rel_apps/2, get_previous_release_path/0, get_rel_file_path/2, - load_config/1, + load_config/2, get_sys_tuple/1, get_target_dir/1, get_root_dir/1, @@ -123,10 +123,10 @@ get_previous_release_path() -> %% %% Load terms from reltool.config %% -load_config(ReltoolFile) -> +load_config(Config, ReltoolFile) -> case rebar_config:consult_file(ReltoolFile) of {ok, Terms} -> - expand_version(Terms, filename:dirname(ReltoolFile)); + expand_version(Config, Terms, filename:dirname(ReltoolFile)); Other -> ?ABORT("Failed to load expected config from ~s: ~p\n", [ReltoolFile, Other]) @@ -217,16 +217,23 @@ make_proplist([H|T], Acc) -> make_proplist([], Acc) -> Acc. -expand_version(ReltoolConfig, Dir) -> +expand_version(Config, ReltoolConfig, Dir) -> case lists:keyfind(sys, 1, ReltoolConfig) of {sys, Sys} -> - ExpandedSys = {sys, [expand_rel_version(Term, Dir) || Term <- Sys]}, - lists:keyreplace(sys, 1, ReltoolConfig, ExpandedSys); + {Config1, Rels} = + lists:foldl( + fun(Term, {C, R}) -> + {C1, Rel} = expand_rel_version(C, Term, Dir), + {C1, [Rel|R]} + end, {Config, []}, Sys), + ExpandedSys = {sys, lists:reverse(Rels)}, + {Config1, lists:keyreplace(sys, 1, ReltoolConfig, ExpandedSys)}; _ -> - ReltoolConfig + {Config, ReltoolConfig} end. -expand_rel_version({rel, Name, Version, Apps}, Dir) -> - {rel, Name, rebar_utils:vcs_vsn(Version, Dir), Apps}; -expand_rel_version(Other, _Dir) -> - Other. +expand_rel_version(Config, {rel, Name, Version, Apps}, Dir) -> + {NewConfig, VsnString} = rebar_utils:vcs_vsn(Config, Version, Dir), + {NewConfig, {rel, Name, VsnString, Apps}}; +expand_rel_version(Config, Other, _Dir) -> + {Config, Other}. diff --git a/src/rebar_reltool.erl b/src/rebar_reltool.erl index 06411da..c8e8cb6 100644 --- a/src/rebar_reltool.erl +++ b/src/rebar_reltool.erl @@ -37,12 +37,12 @@ %% Public API %% =================================================================== -generate(Config, ReltoolFile) -> +generate(Config0, ReltoolFile) -> %% Make sure we have decent version of reltool available check_vsn(), %% Load the reltool configuration from the file - ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + {Config, ReltoolConfig} = rebar_rel_utils:load_config(Config0, ReltoolFile), Sys = rebar_rel_utils:get_sys_tuple(ReltoolConfig), @@ -56,7 +56,7 @@ generate(Config, ReltoolFile) -> %% Finally, run reltool case catch(run_reltool(Server, Config, ReltoolConfig)) of ok -> - ok; + {ok, Config}; {error, failed} -> ?ABORT; Other2 -> @@ -64,18 +64,17 @@ generate(Config, ReltoolFile) -> ?ABORT end. -overlay(_Config, ReltoolFile) -> +overlay(Config, ReltoolFile) -> %% Load the reltool configuration from the file - ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), - process_overlay(ReltoolConfig). + {Config1, ReltoolConfig} = rebar_rel_utils:load_config(Config, ReltoolFile), + {Config1, process_overlay(ReltoolConfig)}. -clean(_Config, ReltoolFile) -> - ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), +clean(Config, ReltoolFile) -> + {Config1, ReltoolConfig} = rebar_rel_utils:load_config(Config, ReltoolFile), TargetDir = rebar_rel_utils:get_target_dir(ReltoolConfig), rebar_file_utils:rm_rf(TargetDir), - rebar_file_utils:delete_each(["reltool.spec"]). - - + rebar_file_utils:delete_each(["reltool.spec"]), + {ok, Config1}. %% =================================================================== %% Internal functions diff --git a/src/rebar_subdirs.erl b/src/rebar_subdirs.erl index 6c33441..f444a59 100644 --- a/src/rebar_subdirs.erl +++ b/src/rebar_subdirs.erl @@ -40,7 +40,7 @@ preprocess(Config, _) -> Cwd = rebar_utils:get_cwd(), ListSubdirs = rebar_config:get_local(Config, sub_dirs, []), Subdirs0 = lists:flatmap(fun filelib:wildcard/1, ListSubdirs), - case {rebar_core:is_skip_dir(Cwd), Subdirs0} of + case {rebar_config:is_skip_dir(Config, Cwd), Subdirs0} of {true, []} -> {ok, []}; {true, _} -> diff --git a/src/rebar_upgrade.erl b/src/rebar_upgrade.erl index aaa24fd..3f7de03 100644 --- a/src/rebar_upgrade.erl +++ b/src/rebar_upgrade.erl @@ -38,9 +38,9 @@ %% Public API %% ==================================================================== -'generate-upgrade'(_Config, ReltoolFile) -> +'generate-upgrade'(Config0, ReltoolFile) -> %% Get the old release path - ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + {Config, ReltoolConfig} = rebar_rel_utils:load_config(Config0, ReltoolFile), TargetParentDir = rebar_rel_utils:get_target_parent_dir(ReltoolConfig), TargetDir = rebar_rel_utils:get_target_dir(ReltoolConfig), @@ -72,7 +72,7 @@ %% Restore original path true = code:set_path(OrigPath), - ok. + {ok, Config}. %% =================================================================== %% Internal functions diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index 36348e7..be69acc 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -42,7 +42,7 @@ prop_check/3, expand_code_path/0, expand_env_variable/3, - vcs_vsn/2, + vcs_vsn/3, deprecated/3, deprecated/4, get_deprecated_global/3, get_deprecated_global/4, get_deprecated_list/4, get_deprecated_list/5, @@ -198,14 +198,17 @@ expand_env_variable(InStr, VarName, RawVarValue) -> re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts) end. -vcs_vsn(Vcs, Dir) -> +vcs_vsn(Config, Vcs, Dir) -> Key = {Vcs, Dir}, - try ets:lookup_element(rebar_vsn_cache, Key, 2) - catch - error:badarg -> + {ok, Cache} = rebar_config:get_xconf(Config, vsn_cache), + case dict:find(Key, Cache) of + error -> VsnString = vcs_vsn_1(Vcs, Dir), - ets:insert(rebar_vsn_cache, {Key, VsnString}), - VsnString + Cache1 = dict:store(Key, VsnString, Cache), + Config1 = rebar_config:set_xconf(Config, vsn_cache, Cache1), + {Config1, VsnString}; + {ok, VsnString} -> + {Config, VsnString} end. get_deprecated_global(OldOpt, NewOpt, When) -> |