From 2311bc5cbe06dcf2cb03d9b0a93392e1d9095bbb Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 12 Sep 2012 16:27:41 -0500 Subject: support OTP App discovery in the system --- src/rcl_state.erl | 120 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 16 deletions(-) (limited to 'src/rcl_state.erl') diff --git a/src/rcl_state.erl b/src/rcl_state.erl index 1b25ce3..c399b42 100644 --- a/src/rcl_state.erl +++ b/src/rcl_state.erl @@ -29,24 +29,47 @@ lib_dirs/1, goals/1, config_files/1, + providers/1, + providers/2, + add_release/2, + get_release/3, + releases/1, + default_release/1, + default_release/3, + available_apps/1, + available_apps/2, format/1, format/2]). + -export_type([t/0, + app_descriptor/0, + releases/0, cmd_args/0]). --record(?MODULE, {log :: rcl_log:t(), +-record(state_t, {log :: rcl_log:t(), output_dir :: file:name(), lib_dirs=[] :: [file:name()], config_files=[] :: [file:filename()], - goals=[] :: [depsolver:constraint()]}). + goals=[] :: [depsolver:constraint()], + providers = [] :: [rcl_provider:t()], + available_apps = [] :: [app_descriptor()], + default_release :: {rcl_release:name(), rcl_release:vsn()}, + releases :: ec_dictionary:dictionary({ReleaseName::atom(), + ReleaseVsn::string()}, + rcl_release:t())}). %%============================================================================ %% types %%============================================================================ +-type app_descriptor() :: {rcl_release:app_name(), rcl_release:app_vsn(), file:name()}. + +-type releases() :: ec_dictionary:dictionary({rcl_release:name(), + rcl_release:vsn()}, + rcl_release:t()). -type cmd_args() :: proplists:proplist(). --opaque t() :: record(?MODULE). +-opaque t() :: record(state_t). %%============================================================================ %% API @@ -54,40 +77,84 @@ %% @doc Create a new 'log level' for the system -spec new(proplists:proplist(), [file:filename()]) -> t(). new(PropList, Targets) when erlang:is_list(PropList) -> - #?MODULE{log = proplists:get_value(log, PropList, rcl_log:new(error)), - output_dir=proplists:get_value(output_dir, PropList, ""), - lib_dirs=proplists:get_value(lib_dirs, PropList, []), - config_files=Targets, - goals=proplists:get_value(goals, PropList, [])}. + State0 = + #state_t{log = proplists:get_value(log, PropList, rcl_log:new(error)), + output_dir=proplists:get_value(output_dir, PropList, ""), + lib_dirs=get_lib_dirs(proplists:get_value(lib_dirs, PropList, [])), + config_files=Targets, + goals=proplists:get_value(goals, PropList, []), + providers = [], + releases=ec_dictionary:new(ec_dict)}, + create_logic_providers(State0). %% @doc get the current log state for the system -spec log(t()) -> rcl_log:t(). -log(#?MODULE{log=LogState}) -> +log(#state_t{log=LogState}) -> LogState. -spec output_dir(t()) -> file:name(). -output_dir(#?MODULE{output_dir=OutDir}) -> +output_dir(#state_t{output_dir=OutDir}) -> OutDir. -spec lib_dirs(t()) -> [file:name()]. -lib_dirs(#?MODULE{lib_dirs=LibDir}) -> +lib_dirs(#state_t{lib_dirs=LibDir}) -> LibDir. -spec goals(t()) -> [depsolver:constraints()]. -goals(#?MODULE{goals=TS}) -> +goals(#state_t{goals=TS}) -> TS. -spec config_files(t()) -> [file:filename()]. -config_files(#?MODULE{config_files=ConfigFiles}) -> +config_files(#state_t{config_files=ConfigFiles}) -> ConfigFiles. +-spec providers(t()) -> [rcl_provider:t()]. +providers(#state_t{providers=Providers}) -> + Providers. + +-spec providers(t(), [rcl_provider:t()]) -> t(). +providers(M, NewProviders) -> + M#state_t{providers=NewProviders}. + +-spec add_release(t(), rcl_release:t()) -> t(). +add_release(M=#state_t{releases=Releases}, Release) -> + M#state_t{releases=ec_dictionary:add({rcl_release:name(Release), + rcl_release:vsn(Release)}, + Release, + Releases)}. + +-spec get_release(t(), rcl_release:name(), rcl_release:vsn()) -> rcl_release:t(). +get_release(#state_t{releases=Releases}, Name, Vsn) -> + ec_dictionary:get({Name, Vsn}, Releases). + +-spec releases(t()) -> releases(). +releases(#state_t{releases=Releases}) -> + Releases. + +-spec default_release(t()) -> {rcl_release:name(), rcl_release:vsn()}. +default_release(#state_t{default_release=Def}) -> + Def. + +-spec default_release(t(), rcl_release:name(), rcl_release:vsn()) -> t(). +default_release(M, Name, Vsn) -> + M#state_t{default_release={Name, Vsn}}. + +-spec available_apps(t()) -> [app_descriptor()]. +available_apps(#state_t{available_apps=Apps}) -> + Apps. + +-spec available_apps(t(), [app_descriptor()]) -> t(). +available_apps(M, NewApps) -> + M#state_t{available_apps=NewApps}. + -spec format(t()) -> iolist(). format(Mod) -> format(Mod, 0). -spec format(t(), non_neg_integer()) -> iolist(). -format(#?MODULE{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, - goals=Goals, config_files=ConfigFiles}, +format(#state_t{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, + goals=Goals, config_files=ConfigFiles, + providers=Providers}, Indent) -> [rcl_util:indent(Indent), <<"state:\n">>, @@ -98,7 +165,28 @@ format(#?MODULE{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, [[rcl_util:indent(Indent + 2), depsolver:format_constraint(Goal), ",\n"] || Goal <- Goals], rcl_util:indent(Indent + 1), "output_dir: ", OutDir, "\n", rcl_util:indent(Indent + 1), "lib_dirs: \n", - [[rcl_util:indent(Indent + 2), LibDir, ",\n"] || LibDir <- LibDirs]]. + [[rcl_util:indent(Indent + 2), LibDir, ",\n"] || LibDir <- LibDirs], + rcl_util:indent(Indent + 1), "providers: \n", + [[rcl_util:indent(Indent + 2), rcl_provider:format(Provider), ",\n"] || Provider <- Providers]]. + +%%%=================================================================== +%%% Internal Functions +%%%=================================================================== +-spec get_lib_dirs([file:name()]) -> [file:name()]. +get_lib_dirs(CmdDirs) -> + case os:getenv("ERL_LIBS") of + false -> + CmdDirs; + EnvString -> + [Lib || Lib <- re:split(EnvString, ":|;"), + filelib:is_dir(Lib)] ++ CmdDirs + end. + +-spec create_logic_providers(t()) -> t(). +create_logic_providers(State0) -> + {ConfigProvider, {ok, State1}} = rcl_provider:new(rcl_prv_config, State0), + {DiscoveryProvider, {ok, State2}} = rcl_provider:new(rcl_prv_discover, State1), + State2#state_t{providers=[ConfigProvider, DiscoveryProvider]}. %%%=================================================================== %%% Test Functions -- cgit v1.2.3