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) -> | 
