Current section
Files
Jump to
Current section
Files
src/active.erl
-module(active).
-behaviour(gen_server).
-define(SERVER, ?MODULE).
-compile(export_all).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-record(state, {last, root}).
start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) -> fs:subscribe(), erlang:process_flag(priority, low), {ok, #state{last=fresh, root=fs:path()}}.
handle_call(_Request, _From, State) -> {reply, ok, State}.
handle_cast(_Msg, State) -> {noreply, State}.
handle_info({_Pid, {fs,file_event}, {Path, Flags}}, #state{root=Root} = State) ->
Cur = path_shorten(filename:split(Root)),
P = filename:split(Path),
Result = case lists:prefix(Cur, P) of
true ->
Components = P -- Cur,
%error_logger:info_msg("event: ~p ~p", [Components, Flags]),
path_event(Components, Flags, State);
false ->
ok
end,
{noreply, State#state{last={event, Path, Flags, Result}}};
handle_info({load_ebin, Atom}, State) -> do_load_ebin(Atom), {noreply, State#state{last={do_load_ebin, Atom}}};
handle_info(Info, State) -> {noreply, State#state{last={unk, Info}}}.
terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.
path_event(C, [E|_Events], _State) when E =:= created; E =:= modified; E =:= renamed ->
case path_filter(C) of true -> otp(C); false -> ignore end;
path_event(C, [_E|Events], State) -> path_event(C, Events, State);
path_event(_, [], _State) -> done.
otp(["deps",App|Rest]) -> app(App,Rest);
otp(["apps",App|Rest]) -> app(App,Rest);
otp([Some|Path]) -> app(top(),[Some|Path]);
otp(_) -> ok.
app(App,["ebin",Module|_]) -> load_ebin(App,Module);
app(App,["priv","fdlink"++_]) -> skip;
app(App,["priv","mac"++_]) -> skip;
app(App,["priv","windows"++_]) -> skip;
app(App,["priv","linux"++_]) -> skip;
app(App,Path=["priv"|_]) -> case hd(lists:reverse(Path)) of
".#" ++ _ -> skip; % mc temp files
Else -> compile(App) end;
app(App,["include"|_]) -> compile(App);
app(App,["src"|_]) -> compile(App);
app(_,_)-> ok.
top() -> lists:last(filename:split(filename:absname(""))).
compile(_State) ->
put(mode,active),
try mad:main(["compile"]) catch E:R -> io:format("Catch: ~p:~p~n",[E,R]) end.
load_ebin(App,EName) ->
Tokens = string:tokens(EName, "."),
case Tokens of
[Name, "beam"] -> do_load_ebin(list_to_atom(Name));
[Name, "bea#"] ->
case monitor_handles_renames() of
false ->
erlang:send_after(500, ?SERVER, {load_ebin, list_to_atom(Name)}),
delayed;
true ->
ignored
end;
%[Name, Smth] -> ok;
_ ->
error_logger:warning_msg("Active: unknown BEAM file: ~p", [EName]),
ok
end.
do_load_ebin(Module) ->
{Module, Binary, Filename} = code:get_object_code(Module),
code:load_binary(Module, Filename, Binary),
io:format("Active: module loaded: ~p~n\n\r", [Module]),
reloaded.
monitor_handles_renames([renamed|_]) -> true;
monitor_handles_renames([_|Events]) -> monitor_handles_renames(Events);
monitor_handles_renames([]) -> false.
monitor_handles_renames() ->
case get(monitor_handles_renames) of
undefined ->
R = monitor_handles_renames(fs:known_events()),
put(monitor_handles_renames, R),
R;
V -> V
end.
% ["a", "b", ".."] -> ["a"]
path_shorten(Coms) -> path_shorten_r(lists:reverse(Coms), [], 0).
path_shorten_r([".."|Rest], Acc, Count) -> path_shorten_r(Rest, Acc, Count + 1);
path_shorten_r(["."|Rest], Acc, Count) -> path_shorten_r(Rest, Acc, Count);
path_shorten_r([_C|Rest], Acc, Count) when Count > 0 -> path_shorten_r(Rest, Acc, Count - 1);
path_shorten_r([C|Rest], Acc, 0) -> path_shorten_r(Rest, [C|Acc], 0);
path_shorten_r([], Acc, _) -> Acc.
%
% Filters
%
path_filter(L) ->
not lists:any(fun(E) -> not path_filter_dir(E) end, L)
andalso path_filter_file(lists:last(L))
andalso path_filter_ext(filename:extension(L)).
path_filter_dir(".git") -> false;
path_filter_dir(".hg") -> false;
path_filter_dir(".svn") -> false;
path_filter_dir("CVS") -> false;
path_filter_dir("log") -> false;
path_filter_dir(_) -> true.
path_filter_file(".rebarinfo") -> false; % new rebars
path_filter_file("LICENSE") -> false;
path_filter_file("4913 (deleted)") -> false; % vim magical file
path_filter_file("4913") -> false;
path_filter_file(_) -> true.
path_filter_ext(".jpg") -> false;
path_filter_ext(".png") -> false;
path_filter_ext(".gif") -> false;
path_filter_ext(_) -> true.