Skip to content

Commit

Permalink
Remove shared state
Browse files Browse the repository at this point in the history
  • Loading branch information
Tuncer Ayaz committed Jul 13, 2012
1 parent 1948eb4 commit e185e86
Show file tree
Hide file tree
Showing 16 changed files with 496 additions and 430 deletions.
13 changes: 6 additions & 7 deletions src/rebar.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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],

Expand All @@ -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
Expand All @@ -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
Expand Down
95 changes: 50 additions & 45 deletions src/rebar_app_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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").

Expand Down Expand Up @@ -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) ->
Expand All @@ -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};
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/rebar_appups.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -75,7 +75,7 @@
%% Generate appup files for upgraded apps
generate_appup_files(NewVerPath, OldVerPath, UpgradeApps),

ok.
{ok, Config1}.

%% ===================================================================
%% Internal functions
Expand Down
118 changes: 82 additions & 36 deletions src/rebar_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,35 @@
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]).

%% 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()}.
Expand All @@ -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).
Expand Down Expand Up @@ -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),
Expand All @@ -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.
Expand All @@ -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().
Loading

0 comments on commit e185e86

Please sign in to comment.