summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFred Hebert <mononcqc@ferd.ca>2015-05-26 01:07:02 +0000
committerFred Hebert <mononcqc@ferd.ca>2015-05-26 01:17:54 +0000
commit51e822e54cf862e3026d23a1f9e74797c4e7f9eb (patch)
tree059e2061d3dee620591a7bc0d592c5d41521d335
parentfb160ebf718364e8cb4edd4ead9ebf097024c037 (diff)
Add a shell agent
The shell agent allows to run rebar3 commands and autoload compiled modules when that is done.
-rw-r--r--src/r3.erl7
-rw-r--r--src/rebar_agent.erl71
-rw-r--r--src/rebar_prv_shell.erl24
3 files changed, 92 insertions, 10 deletions
diff --git a/src/r3.erl b/src/r3.erl
new file mode 100644
index 0000000..5e8b26d
--- /dev/null
+++ b/src/r3.erl
@@ -0,0 +1,7 @@
+%%% external alias for rebar_agent
+-module(r3).
+-export([do/1, do/2]).
+
+do(Command) -> rebar_agent:do(Command).
+
+do(Namespace, Command) -> rebar_agent:do(Namespace, Command).
diff --git a/src/rebar_agent.erl b/src/rebar_agent.erl
new file mode 100644
index 0000000..849e67c
--- /dev/null
+++ b/src/rebar_agent.erl
@@ -0,0 +1,71 @@
+-module(rebar_agent).
+-export([start_link/1, do/1, do/2]).
+-export([init/1,
+ handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+-record(state, {state,
+ cwd}).
+
+start_link(State) ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, State, []).
+
+do(Command) when is_atom(Command) ->
+ gen_server:call(?MODULE, {cmd, Command}, infinity).
+
+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()),
+ {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};
+handle_call(_Call, _From, State) ->
+ {noreply, State}.
+
+handle_cast(_Cast, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+refresh(RState) ->
+ ToRefresh = rebar_state:code_paths(RState, all_deps)
+ %% make sure to never reload self; halt()s the VM
+ -- [filename:dirname(code:which(?MODULE))],
+ rebar_utils:update_code(ToRefresh).
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index cf600e9..143becc 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -82,6 +82,7 @@ shell(State) ->
setup_paths(State),
ok = reread_config(State),
maybe_boot_apps(State),
+ rebar_agent:start_link(State),
setup_shell(),
%% try to read in sys.config file
%% this call never returns (until user quits shell)
@@ -134,18 +135,21 @@ maybe_boot_apps(State) ->
undefined ->
ok;
Apps ->
- ?WARN("The rebar3 shell is a development tool; to deploy "
- "applications in production, consider using releases "
- "(http://www.rebar3.org/v3.0/docs/releases)", []),
- Res = [application:ensure_all_started(App) || App <- Apps],
- _ = [?INFO("Booted ~p", [App])
- || {ok, Booted} <- Res,
- App <- Booted],
- _ = [?ERROR("Failed to boot ~p for reason ~p", [App, Reason])
- || {error, {App, Reason}} <- Res],
- ok
+ boot_apps(Apps)
end.
+boot_apps(Apps) ->
+ ?WARN("The rebar3 shell is a development tool; to deploy "
+ "applications in production, consider using releases "
+ "(http://www.rebar3.org/v3.0/docs/releases)", []),
+ Res = [application:ensure_all_started(App) || App <- Apps],
+ _ = [?INFO("Booted ~p", [App])
+ || {ok, Booted} <- Res,
+ App <- Booted],
+ _ = [?ERROR("Failed to boot ~p for reason ~p", [App, Reason])
+ || {error, {App, Reason}} <- Res],
+ ok.
+
remove_error_handler(0) ->
?WARN("Unable to remove simple error_logger handler", []);
remove_error_handler(N) ->