summaryrefslogtreecommitdiff
path: root/src/rebar_agent.erl
diff options
context:
space:
mode:
authorFred Hebert <mononcqc@ferd.ca>2015-05-28 02:21:07 +0000
committerFred Hebert <mononcqc@ferd.ca>2015-05-28 02:21:07 +0000
commit3de325aa497e2b05ada5c84ea75d980d58aba645 (patch)
treea367ae1850bb24bff9b648ae64b22e424f69b3ab /src/rebar_agent.erl
parent2fabfe1ee824e3d1d0764e2770309c242ae771d9 (diff)
Rebar agent reloads the config file on every run
This allows proper checking of new configurations, deps, or plugins, and makes sure they are detected during an active shell session.
Diffstat (limited to 'src/rebar_agent.erl')
-rw-r--r--src/rebar_agent.erl101
1 files changed, 67 insertions, 34 deletions
diff --git a/src/rebar_agent.erl b/src/rebar_agent.erl
index 849e67c..f04afe3 100644
--- a/src/rebar_agent.erl
+++ b/src/rebar_agent.erl
@@ -4,6 +4,8 @@
handle_call/3, handle_cast/2, handle_info/2,
code_change/3, terminate/2]).
+-include("rebar.hrl").
+
-record(state, {state,
cwd}).
@@ -16,39 +18,16 @@ do(Command) when is_atom(Command) ->
do(Namespace, Command) when is_atom(Namespace), is_atom(Command) ->
gen_server:call(?MODULE, {cmd, Namespace, Command}, infinity).
-init(State0) ->
- Cwd = file:get_cwd(),
- State = rebar_state:update_code_paths(State0, default, code:get_path()),
+init(State) ->
+ {ok, Cwd} = file:get_cwd(),
{ok, #state{state=State, cwd=Cwd}}.
handle_call({cmd, Command}, _From, State=#state{state=RState, cwd=Cwd}) ->
- Res = try
- case file:get_cwd() of
- Cwd ->
- case rebar_core:process_command(RState, Command) of
- {ok, _} ->
- refresh(RState),
- ok;
- {error, Err} when is_list(Err) ->
- refresh(RState),
- {error, lists:flatten(Err)};
- {error, Err} ->
- refresh(RState),
- {error, Err}
- end;
- _ ->
- {error, cwd_changed}
- end
- catch
- Type:Reason ->
- {error, {Type, Reason}}
- end,
- {reply, Res, State};
-handle_call({cmd, Namespace, Command}, From, State = #state{state=RState}) ->
- {reply, Res, _} = handle_call({cmd, Command}, From, State#state{
- state = rebar_state:namespace(RState, Namespace)
- }),
- {reply, Res, State};
+ {Res, NewRState} = run(default, Command, RState, Cwd),
+ {reply, Res, State#state{state=NewRState}};
+handle_call({cmd, Namespace, Command}, _From, State = #state{state=RState, cwd=Cwd}) ->
+ {Res, NewRState} = run(Namespace, Command, RState, Cwd),
+ {reply, Res, State#state{state=NewRState}};
handle_call(_Call, _From, State) ->
{noreply, State}.
@@ -64,8 +43,62 @@ code_change(_OldVsn, State, _Extra) ->
terminate(_Reason, _State) ->
ok.
-refresh(RState) ->
- ToRefresh = rebar_state:code_paths(RState, all_deps)
+run(Namespace, Command, RState, Cwd) ->
+ try
+ case file:get_cwd() of
+ {ok, Cwd} ->
+ Args = [atom_to_list(Namespace), atom_to_list(Command)],
+ CmdState0 = refresh_state(RState, Cwd),
+ CmdState1 = rebar_state:set(CmdState0, task, atom_to_list(Command)),
+ CmdState = rebar_state:set(CmdState1, caller, api),
+ case rebar3:run(CmdState, Args) of
+ {ok, TmpState} ->
+ refresh_paths(TmpState),
+ {ok, CmdState};
+ {error, Err} when is_list(Err) ->
+ refresh_paths(CmdState),
+ {{error, lists:flatten(Err)}, CmdState};
+ {error, Err} ->
+ refresh_paths(CmdState),
+ {{error, Err}, CmdState}
+ end;
+ _ ->
+ {{error, cwd_changed}, RState}
+ end
+ catch
+ Type:Reason ->
+ ?DEBUG("Agent Stacktrace: ~p", [erlang:get_stacktrace()]),
+ {{error, {Type, Reason}}, RState}
+ end.
+
+refresh_paths(RState) ->
+ ToRefresh = (rebar_state:code_paths(RState, all_deps)
+ %% TODO: add plugin paths here when the other change is merged
+ ++ [filename:join([rebar_app_info:out_dir(App), "test"])
+ || App <- rebar_state:project_apps(RState)]
%% make sure to never reload self; halt()s the VM
- -- [filename:dirname(code:which(?MODULE))],
- rebar_utils:update_code(ToRefresh).
+ ) -- [filename:dirname(code:which(?MODULE))],
+ %% Similar to rebar_utils:update_code/1, but also forces a reload
+ %% of used modules.
+ lists:foreach(fun(Path) ->
+ Name = filename:basename(Path, "/ebin"),
+ App = list_to_atom(Name),
+ application:load(App),
+ case application:get_key(App, modules) of
+ undefined ->
+ code:add_patha(Path),
+ ok;
+ {ok, Modules} ->
+ ?DEBUG("reloading ~p from ~s", [Modules, Path]),
+ code:replace_path(Name, Path),
+ [begin code:purge(M), code:delete(M), code:load_file(M) end
+ || M <- Modules]
+ end
+ end, ToRefresh).
+
+refresh_state(RState, _Dir) ->
+ lists:foldl(
+ fun(F, State) -> F(State) end,
+ rebar3:init_config(),
+ [fun(S) -> rebar_state:current_profiles(S, rebar_state:current_profiles(RState)) end]
+ ).