-module(rebar_state). -export([new/0, new/1, new/2, new/3, get/2, get/3, set/3, command_args/1, command_args/2, command_parsed_args/1, command_parsed_args/2, dir/1, dir/2, create_logic_providers/2, project_apps/1, project_apps/2, deps_names/1, pkg_deps/1, pkg_deps/2, src_deps/1, src_deps/2, src_apps/1, src_apps/2, prepend_hook/3, append_hook/3, hooks/2, providers/1, providers/2, add_provider/2]). -include("rebar.hrl"). -record(state_t, {dir :: file:name(), opts = [], command_args = [], command_parsed_args = [], src_deps = [], src_apps = [], pkg_deps = [] :: [rlx_depsolver:constraint()], project_apps = [], providers = []}). -export_type([t/0]). -type t() :: record(state_t). -spec new() -> t(). new() -> #state_t{dir = rebar_utils:get_cwd()}. -spec new(list()) -> t(). new(Config) when is_list(Config) -> #state_t { dir = rebar_utils:get_cwd(), opts = Config }. -spec new(t(), list()) -> t(). new(ParentState=#state_t{}, Config) -> %% Load terms from rebar.config, if it exists Dir = rebar_utils:get_cwd(), new(ParentState, Config, Dir). -spec new(t(), list(), file:name()) -> t(). new(ParentState, Config, Dir) -> Opts = ParentState#state_t.opts, LocalOpts = case rebar_config:consult_file(?LOCK_FILE) of [D] -> [{locks, D} | Config]; _ -> Config end, ProviderModules = [], create_logic_providers(ProviderModules, ParentState#state_t{dir=Dir ,opts=lists:umerge(LocalOpts, Opts)}). get(State, Key) -> proplists:get_value(Key, State#state_t.opts). get(State, Key, Default) -> proplists:get_value(Key, State#state_t.opts, Default). -spec set(t(), any(), any()) -> t(). set(State, Key, Value) -> Opts = proplists:delete(Key, State#state_t.opts), State#state_t { opts = [{Key, Value} | Opts] }. command_args(#state_t{command_args=CmdArgs}) -> CmdArgs. command_args(State, CmdArgs) -> State#state_t{command_args=CmdArgs}. command_parsed_args(#state_t{command_parsed_args=CmdArgs}) -> CmdArgs. command_parsed_args(State, CmdArgs) -> State#state_t{command_parsed_args=CmdArgs}. dir(#state_t{dir=Dir}) -> Dir. dir(State=#state_t{}, Dir) -> State#state_t{dir=filename:absname(Dir)}. deps_names(State) -> Deps = rebar_state:get(State, deps, []), lists:map(fun(Dep) when is_tuple(Dep) -> ec_cnv:to_binary(element(1, Dep)); (Dep) when is_atom(Dep) -> ec_cnv:to_binary(Dep) end, Deps). -spec pkg_deps(t()) -> [rlx_depsolver:constraint()]. pkg_deps(#state_t{pkg_deps=PkgDeps}) -> PkgDeps. pkg_deps(State=#state_t{pkg_deps=PkgDeps}, NewPkgDeps) when is_list(PkgDeps) -> State#state_t{pkg_deps=NewPkgDeps}; pkg_deps(State=#state_t{pkg_deps=PkgDeps}, PkgDep) -> State#state_t{pkg_deps=[PkgDep | PkgDeps]}. src_deps(#state_t{src_deps=SrcDeps}) -> SrcDeps. src_deps(State=#state_t{src_deps=SrcDeps}, NewSrcDeps) when is_list(SrcDeps) -> State#state_t{src_deps=NewSrcDeps}; src_deps(State=#state_t{src_deps=SrcDeps}, SrcDep) -> Name = rebar_app_info:name(SrcDep), NewSrcDeps = lists:keystore(Name, 2, SrcDeps, SrcDep), State#state_t{src_deps=NewSrcDeps}. src_apps(#state_t{src_apps=SrcApps}) -> SrcApps. src_apps(State=#state_t{src_apps=_SrcApps}, NewSrcApps) when is_list(NewSrcApps) -> State#state_t{src_apps=NewSrcApps}; src_apps(State=#state_t{src_apps=SrcApps}, NewSrcApp) -> Name = rebar_app_info:name(NewSrcApp), NewSrcApps = lists:keystore(Name, 2, SrcApps, NewSrcApp), State#state_t{src_apps=NewSrcApps}. project_apps(#state_t{project_apps=Apps}) -> Apps. project_apps(State=#state_t{}, NewApps) when is_list(NewApps) -> State#state_t{project_apps=NewApps}; project_apps(State=#state_t{project_apps=Apps}, App) -> State#state_t{project_apps=[App | Apps]}. providers(#state_t{providers=Providers}) -> Providers. providers(State, NewProviders) -> State#state_t{providers=NewProviders}. -spec add_provider(t(), providers:t()) -> t(). add_provider(State=#state_t{providers=Providers}, Provider) -> State#state_t{providers=[Provider | Providers]}. create_logic_providers(ProviderModules, State0) -> lists:foldl(fun(ProviderMod, Acc) -> case providers:new(ProviderMod, Acc) of {error, Reason} -> ?ERROR(Reason++"~n", []), Acc; {ok, State1} -> State1 end end, State0, ProviderModules). prepend_hook(State=#state_t{providers=Providers}, Target, Hook) -> State#state_t{providers=add_hook(pre, Providers, Target, Hook)}. append_hook(State=#state_t{providers=Providers}, Target, Hook) -> State#state_t{providers=add_hook(post, Providers, Target, Hook)}. -spec hooks(t(), atom()) -> {[providers:t()], [providers:t()]}. hooks(_State=#state_t{providers=Providers}, Target) -> Provider = providers:get_provider(Target, Providers), providers:hooks(Provider). %% =================================================================== %% Internal functions %% =================================================================== add_hook(Which, Providers, Target, Hook) -> Provider = providers:get_provider(Target, Providers), Hooks = providers:hooks(Provider), NewHooks = add_hook(Which, Hooks, Hook), NewProvider = providers:hooks(Provider, NewHooks), [NewProvider | lists:delete(Provider, Providers)]. add_hook(pre, {PreHooks, PostHooks}, Hook) -> {[Hook | PreHooks], PostHooks}; add_hook(post, {PreHooks, PostHooks}, Hook) -> {PreHooks, [Hook | PostHooks]}.