共通のコミットはありません。 'erlang+tcp版本' と 'master' の履歴はすべて異なっています。

13個のファイルの変更1497行の追加1355行の削除
分割表示
  1. +17
    -4
      README.md
  2. +32
    -6
      eSync.sample.config
  3. +0
    -21
      include/eSync.hrl
  4. バイナリ
      priv/fileSync
  5. バイナリ
      priv/fileSync.exe
  6. +1
    -1
      rebar.config
  7. +2
    -2
      src/eSync.app.src
  8. +1301
    -37
      src/eSync.erl
  9. +0
    -10
      src/eSync_app.erl
  10. +0
    -27
      src/eSync_sup.erl
  11. +144
    -103
      src/es_gen_ipc.erl
  12. +0
    -242
      src/sync/esSyncSrv.erl
  13. +0
    -902
      src/sync/esUtils.erl

+ 17
- 4
README.md ファイルの表示

@ -1,17 +1,23 @@
# eSync
otp21.2+
Erlang即时重新编译和重新加载!
## 基于 [fsnotify](https://github.com/fsnotify/fsnotify) 跨平台文件系统通知。
## 改造自 [sync](https://github.com/rustyio/sync)
## 封装的监听文件项目[fileSync](https://github.com/SisMaker/fileSync) 如果要自己构建执行文件, 拉取监听文件项目, 然后 go build 复制执行文件到该工程的 priv 目录即可
# 特点
本项目实现了自带编译与加载功能,另外支持额外的编译命令,但是执行额外的编译命令是通过os:cmd(),会阻塞VM不是很建议使用.
启动后,eSync会收集监听目录下的源文件和编译选项等的信息。
不仅适用于开发模式,也可以在生产环境中运行。
注意:linux下拉取项目后 需要给priv目录下的执行文件添加执行权限
# 使用
启动自动编译与加载
eSync:run().
暂停自动编译与加载
@ -23,9 +29,11 @@
设置编译与加载日志提示
eSync:setLog(Val).
设置加载后的钩子函数(支持匿名函数, {Mod, Fun}(Fun函数只有一个参数)格式, 以及他们的列表组合)
eSync:setOnsync(FunOrFuns).
eSync:setOnMSync(FunOrFuns).
eSync:setOnCSync(FunOrFuns).
# 配置说明
参见eSync.sample.config
默认配置为
[
@ -34,7 +42,12 @@
{compileCmd, undefined},
{extraDirs, undefined}
{log, all},
{descendant, fix}
{descendant, fix},
{onMSyncFun, undefined},
{onCSyncFun, undefined},
{swSyncNode, false},
{isJustMem, false},
{debugInfoKeyFun, undefined}
]
}
]

+ 32
- 6
eSync.sample.config ファイルの表示

@ -9,15 +9,25 @@
%% 默认值: all
{log, all},
%% base dir
%% 默认值: "./"
{baseDir, "./"},
%% monitor file ext 监听文件的后缀名列表
%% 默认值: [".hrl", ".erl", ".beam", ".dtl", ".lfe", ".ex", ".config"]
{monitorExt, [".hrl", ".erl", ".beam", ".dtl", ".lfe", ".ex", ".config"]},
%% 这个参数用于设置特殊目录下的文件检查编译与加载
%% 格式:{extraDirs, [{strategy(), [srcDirDescr()]}} | {srcDirs, undefined]}
%% -type strategy() :: add | only | del.
%% 如果 strategy() when add, 会无条件监听添加的指定目录及其子目录同步编译与加载.
%% 格式:{extraDirs, [{strategy(), [srcDirDescr()]}] | undefined}
%% -type strategy() :: only | del | addExtra | addOnly.
%% 如果 strategy() when addExtra, 会无条件监听添加的指定目录及其子目录同步编译与加载.
%% 如果 strategy() when addOnly, 会无条件监听添加的指定目录(不含子目录)同步编译与加载.
%% 如果 strategy() when only, 仅仅监听指定目录及其子目录下的文件编译与加载.
%% 如果 strategy() when del, 则不会监听该目录及其子目录下的文件.
%% -type srcDirDescr() :: { Dir :: file:filename(), [Options :: compile_option()]}.
%% 默认值:undefined 根据当前工作目录 和 已经加载的模块做来得出需要扫描的目录
%%示例: {extraDirs, [{add, [{"./_build/default/lib/erlGbh", []}]}, {only, [{"./", []}]}, {del, [{"./_build", []}]}]}.
%%示例: {extraDirs, [{addExtra, [{"./_build/default/lib/erlGbh", []}]}, {only, [{"./", []}]}, {del, [{"./_build", []}]}]}.
%%{extraDirs, [{add, [{"./_build/default/lib/erlGbh", []}, {"./_build/default/lib/eSync/ebin", []}]}, {only, [{"./", []}]}, {del, [{"./_build", []}]}]}
{extraDirs, [{strategy(), [srcDirDescr()]}]},
@ -27,8 +37,24 @@
%% * allow = 不要做任何特别的事情,使用beam源文件原始路径查找该文件
%% * ignore = 而忽略对其源路径的任何更改
%% 默认值: fix
{descendant, fix}
]}
{descendant, fix},
%% Beam更新回调函数 格式: undefined | {Mondule, Fun} | [{Mondule, Fun}, ...], Fun函数只有一个参数
{onMSyncFun, undefined},
%% config更新回调函数 格式: undefined | {Mondule, Fun} | [{Mondule, Fun}, ...], Fun函数只有一个参数
{onCSyncFun, undefined},
%% 是否开启集群同步加载
{swSyncNode, false},
%% 仅仅内存编译还是编译写入到磁盘去
{isJustMem, false},
%% 如果存在debug_info_key 需要用户提供获取debug_info_key的函数 格式: undefined | {Mondule, Fun}
%% this fun need return: {debug_info_key, xxx}
{debugInfoKeyFun, undefined}
]}
].

+ 0
- 21
include/eSync.hrl ファイルの表示

@ -1,21 +0,0 @@
-define(LOG_ON(Val), Val == true; Val == all; Val == skip_success; is_list(Val), Val =/= []).
-define(TCP_DEFAULT_OPTIONS, [
binary
, {packet, 4}
, {active, true}
, {reuseaddr, true}
, {nodelay, false}
, {delay_send, true}
, {send_timeout, 15000}
, {keepalive, true}
, {exit_on_close, true}]).
-define(Log, log).
-define(compileCmd, compileCmd).
-define(extraDirs, extraDirs).
-define(descendant, descendant).
-define(CfgList, [{?Log, all}, {?compileCmd, undefined}, {?extraDirs, undefined}, {?descendant, fix}]).
-define(esCfgSync, esCfgSync).
-define(rootSrcDir, <<"src">>).

バイナリ
priv/fileSync ファイルの表示


バイナリ
priv/fileSync.exe ファイルの表示


+ 1
- 1
rebar.config ファイルの表示

@ -1,4 +1,4 @@
{erl_opts, [no_debug_info]}.
{erl_opts, [no_debug_info, deterministic]}.
{deps, []}.
{shell, [

+ 2
- 2
src/eSync.app.src ファイルの表示

@ -2,10 +2,10 @@
[{description, "erlang code auto compile and loader"},
{vsn, "0.1.0"},
{registered, []},
{mod, {eSync_app, []}},
{mod, {eSync, []}},
{applications, [kernel, stdlib, syntax_tools, compiler]},
{env, []},
{modules, []},
{licenses, ["MIT License"]},
{licenses, ["MIT"]},
{links, []}
]}.

+ 1301
- 37
src/eSync.erl
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 0
- 10
src/eSync_app.erl ファイルの表示

@ -1,10 +0,0 @@
-module(eSync_app).
-behaviour(application).
-export([start/2, stop/1]).
start(_StartType, _StartArgs) ->
eSync_sup:start_link().
stop(_State) ->
ok.

+ 0
- 27
src/eSync_sup.erl ファイルの表示

@ -1,27 +0,0 @@
-module(eSync_sup).
-behaviour(supervisor).
-export([
start_link/0
, init/1
]).
-define(SERVER, ?MODULE).
-define(ChildSpec(I, Type), #{id => I, start => {I, start_link, []}, restart => permanent, shutdown => 5000, type => Type, modules => [I]}).
start_link() ->
supervisor:start_link({local, ?SERVER}, ?MODULE, []).
%% sup_flags() = #{strategy => strategy(), % optional
%% intensity => non_neg_integer(), % optional
%% period => pos_integer()} % optional
%% child_spec() = #{id => child_id(), % mandatory
%% start => mfargs(), % mandatory
%% restart => restart(), % optional
%% shutdown => shutdown(), % optional
%% type => worker(), % optional
%% modules => modules()} % optional
init([]) ->
SupFlags = #{strategy => one_for_one, intensity => 5, period => 10},
ChildSpecs = [?ChildSpec(esSyncSrv, worker)],
{ok, {SupFlags, ChildSpecs}}.

src/sync/es_gen_ipc.erl → src/es_gen_ipc.erl ファイルの表示

@ -13,7 +13,7 @@
, cast/2, send/2
, abcast/2, abcast/3
, call/2, call/3
, send_request/2, wait_response/1, wait_response/2, check_response/2
, send_request/2, wait_response/1, wait_response/2, receive_response/1, receive_response/2, check_response/2
, multi_call/2, multi_call/3, multi_call/4
, enter_loop/4, enter_loop/5, enter_loop/6
, reply/1, reply/2
@ -176,9 +176,9 @@
{'reply', Reply :: term(), NewState :: term()} | % gen_server模式时快速响应进入消息接收
{'sreply', Reply :: term(), NextStatus :: term(), NewState :: term()} | % gen_ipc模式便捷式返回reply reply放在actions列表中
{'noreply', NewState :: term()} | % gen_server模式时快速响应进入消息接收
{'reply', Reply :: term(), NewState :: term(), Options :: hibernate | {doAfter, Args}} | % gen_server模式时快速响应进入消息接收
{'reply', Reply :: term(), NewState :: term(), Options :: hibernate | {doAfter, Args :: term()}} | % gen_server模式时快速响应进入消息接收
{'sreply', Reply :: term(), NextStatus :: term(), NewState :: term(), Actions :: actions(eventAction())} | % gen_ipc模式便捷式返回reply reply放在actions列表中
{'noreply', NewState :: term(), Options :: hibernate | {doAfter, Args}} | % gen_server模式时快速响应进入循环
{'noreply', NewState :: term(), Options :: hibernate | {doAfter, Args :: term()}} | % gen_server模式时快速响应进入循环
{'nextS', NextStatus :: term(), NewState :: term()} | % {next_status,NextS,NewData,[]}
{'nextS', NextStatus :: term(), NewState :: term(), Actions :: actions(eventAction())} | % Status transition, maybe to the same status
commonCallbackResult(eventAction()).
@ -365,7 +365,7 @@ doModuleInit(Module, Args) ->
Module:init(Args)
catch
throw:Ret -> Ret;
Class:Reason -> {'EXIT', Class, Reason, ?STACKTRACE()}
Class:Reason:Stacktrace -> {'EXIT', Class, Reason, Stacktrace}
end.
init_it(Starter, self, ServerRef, Module, Args, Opts) ->
@ -685,6 +685,14 @@ wait_response(RequestId) ->
wait_response(RequestId, Timeout) ->
gen:wait_response(RequestId, Timeout).
-spec receive_response(RequestId::serverRef()) -> {reply, Reply::term()} | {error, {term(), serverRef()}}.
receive_response(RequestId) ->
gen:receive_response(RequestId, infinity).
-spec receive_response(RequestId::requestId(), timeout()) -> {reply, Reply::term()} | 'timeout' | {error, {term(), serverRef()}}.
receive_response(RequestId, Timeout) ->
gen:receive_response(RequestId, Timeout).
-spec check_response(Msg :: term(), RequestId :: requestId()) ->
{reply, Reply :: term()} | 'no_reply' | {error, {term(), serverRef()}}.
check_response(Msg, RequestId) ->
@ -732,7 +740,7 @@ rec_nodes(Tag, [N | Tail], Name, BadNodes, Replies, Time, TimerId) ->
monitor_node(N, false),
rec_nodes_rest(Tag, Tail, Name, [N | BadNodes], Replies)
after Time ->
case rpc:call(N, erlang, whereis, [Name]) of
case erpc:call(N, erlang, whereis, [Name]) of
Pid when is_pid(Pid) ->
rec_nodes(Tag, [N | Tail], Name, BadNodes,
Replies, infinity, TimerId);
@ -820,6 +828,9 @@ reply(Replies) when is_list(Replies) ->
ok.
-spec reply(From :: from(), Reply :: term()) -> ok.
reply({_To, [alias|Alias] = Tag}, Reply) ->
Alias ! {Tag, Reply},
ok;
reply({To, Tag}, Reply) ->
try To ! {Tag, Reply},
ok
@ -827,6 +838,15 @@ reply({To, Tag}, Reply) ->
ok
end.
try_reply(false, _Msg) ->
ignore;
try_reply({To, Ref}, Msg) ->
try To ! {Ref, Msg},
ok
catch _:_ ->
ok
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% API helpers end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_event start %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
epmRequest({global, Name}, Msg) ->
@ -885,11 +905,11 @@ add_epm(EpmSrv, EpmHandler, Args) ->
-spec add_sup_epm(serverRef(), epmHandler(), term()) -> term().
add_sup_epm(EpmSrv, EpmHandler, Args) ->
epmRpc(EpmSrv, {'$addSupEpm', EpmHandler, Args}).
epmRpc(EpmSrv, {'$addSupEpm', EpmHandler, Args, self()}).
-spec del_epm(serverRef(), epmHandler(), term()) -> term().
del_epm(EpmSrv, EpmHandler, Args) ->
epmRpc(EpmSrv, {'$deleteEpm', EpmHandler, Args}).
epmRpc(EpmSrv, {'$delEpm', EpmHandler, Args}).
-spec swap_epm(serverRef(), {epmHandler(), term()}, {epmHandler(), term()}) -> 'ok' | {'error', term()}.
swap_epm(EpmSrv, {H1, A1}, {H2, A2}) ->
@ -928,8 +948,8 @@ doAddEpm(EpmHers, {Module, _SubId} = EpmId, Args, EpmSup) ->
catch
throw:Ret ->
addNewEpm(Ret, EpmHers, Module, EpmId, EpmSup);
C:R ->
{{error, {C, R, ?STACKTRACE()}}, EpmHers, false}
C:R:S ->
{{error, {C, R, S}}, EpmHers, false}
end
end;
doAddEpm(EpmHers, Module, Args, EpmSup) ->
@ -943,8 +963,8 @@ doAddEpm(EpmHers, Module, Args, EpmSup) ->
catch
throw:Ret ->
addNewEpm(Ret, EpmHers, Module, Module, EpmSup);
C:R ->
{{error, {C, R, ?STACKTRACE()}}, EpmHers, false}
C:R:S ->
{{error, {C, R, S}}, EpmHers, false}
end
end.
@ -973,7 +993,7 @@ doSwapEpm(EpmHers, EpmId1, Args1, EpmMId, Args2) ->
end.
doSwapSupEpm(EpmHers, EpmId1, Args1, EpmMId, Args2, EpmSup) ->
case EpmHers(EpmId1) of
case EpmHers of
#{EpmId1 := EpmHer} ->
State2 = epmTerminate(EpmHer, Args1, swapped, {swapped, EpmMId, EpmSup}),
NewEpmHers = maps:remove(EpmId1, EpmHers),
@ -982,13 +1002,17 @@ doSwapSupEpm(EpmHers, EpmId1, Args1, EpmMId, Args2, EpmSup) ->
doAddSupEpm(EpmHers, EpmMId, {Args2, undefined}, EpmSup)
end.
doNotify(EpmHers, Event, Func, _Form) ->
FunFor =
fun(K, _V, {TemEpmHers, IsHib}) ->
{NewEpmHers, NewIsHib} = doEpmHandle(TemEpmHers, K, Func, Event, false),
{NewEpmHers, NewIsHib orelse IsHib}
end,
maps:fold(FunFor, {EpmHers, false}, EpmHers).
doNotify(EpmHers, Func, Event, _Form) ->
allNotify(maps:iterator(EpmHers), Func, Event, false, EpmHers, false).
allNotify(Iterator, Func, Event, From, TemEpmHers, IsHib) ->
case maps:next(Iterator) of
{K, _V, NextIterator} ->
{NewEpmHers, NewIsHib} = doEpmHandle(TemEpmHers, K, Func, Event, From),
allNotify(NextIterator, Func, Event, From, NewEpmHers, IsHib orelse NewIsHib);
_ ->
{TemEpmHers, IsHib}
end.
doEpmHandle(EpmHers, EpmHandler, Func, Event, From) ->
case EpmHers of
@ -999,16 +1023,17 @@ doEpmHandle(EpmHers, EpmHandler, Func, Event, From) ->
catch
throw:Ret ->
handleEpmCR(Ret, EpmHers, EpmHer, Event, From);
C:R ->
epmTerminate(EpmHer, {error, {C, R, ?STACKTRACE()}}, Event, crash),
NewEpmHers = maps:remove(EpmHandler, EpmHer),
C:R:S ->
epmTerminate(EpmHer, {error, {C, R, S}}, Event, crash),
NewEpmHers = maps:remove(EpmHandler, EpmHers),
{NewEpmHers, false}
end;
_ ->
try_reply(From, {error, bad_module}),
{EpmHers, false}
end.
doDeleteEpm(EpmHers, EpmHandler, Args) ->
doDelEpm(EpmHers, EpmHandler, Args) ->
case EpmHers of
#{EpmHandler := EpmHer} ->
epmTerminate(EpmHer, Args, delete, normal),
@ -1054,7 +1079,7 @@ report_error(#epmHer{epmId = EpmId, epmM = EpmM}, Reason, State, LastIn) ->
handler => {EpmId, EpmM},
name => undefined,
last_message => LastIn,
state=> State,
state => State,
reason => Reason
},
#{
@ -1093,30 +1118,39 @@ epm_log(#{label := {es_gen_ipc, no_handle_info}, module := Module, message := Ms
"** Unhandled message: ~tp~n", [Module, Msg]}.
epmStopAll(EpmHers) ->
FunFor =
fun(_K, V, _Ok) ->
allStop(maps:iterator(EpmHers)).
allStop(Iterator) ->
case maps:next(Iterator) of
{_K, V, NextIterator} ->
epmTerminate(V, stop, 'receive', shutdown),
case element(#epmHer.epmSup, V) of
undefined ->
ignore;
EpmSup ->
unlink(EpmSup)
end
end,
maps:fold(FunFor, ok, EpmHers).
end,
allStop(NextIterator);
none ->
ok
end.
epmStopOne(ExitEmpSup, EpmHers) ->
FunFor =
fun(K, V, TemEpmHers) ->
forStopOne(maps:iterator(EpmHers), ExitEmpSup, EpmHers).
forStopOne(Iterator, ExitEmpSup, TemEpmHers) ->
case maps:next(Iterator) of
{K, V, NextIterator} ->
case element(#epmHer.epmSup, V) =:= ExitEmpSup of
true ->
epmTerminate(V, stop, 'receive', shutdown),
maps:remove(K, TemEpmHers);
forStopOne(NextIterator, ExitEmpSup, maps:remove(K, TemEpmHers));
_ ->
EpmHers
end
end,
maps:fold(FunFor, EpmHers, EpmHers).
forStopOne(NextIterator, ExitEmpSup, TemEpmHers)
end;
none ->
TemEpmHers
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gen_event end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listify(Item) when is_list(Item) ->
@ -1188,8 +1222,8 @@ matchCallMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Post
catch
throw:Result ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent], Result, ?CB_FORM_EVENT, From);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
end.
matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Cast) ->
@ -1201,8 +1235,8 @@ matchCastMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Post
catch
throw:Result ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent], Result, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
end.
matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, Msg) ->
@ -1214,8 +1248,8 @@ matchInfoMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Post
catch
throw:Result ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent], Result, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
end.
matchTimeoutMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, TimeoutType, TimeoutMsg) ->
@ -1227,8 +1261,8 @@ matchTimeoutMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, P
catch
throw:Result ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent], Result, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [CurEvent])
end.
matchEpmCallMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, From, Request) ->
@ -1244,8 +1278,8 @@ matchEpmCallMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, P
{Reply, NewEpmHers, IsHib} = doAddSupEpm(EpmHers, EpmHandler, Args, EpmSup),
reply(From, Reply),
reLoopEntry(Parent, Name, Module, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, IsHib);
{'$deleteEpm', EpmHandler, Args} ->
{Reply, NewEpmHers} = doDeleteEpm(EpmHers, EpmHandler, Args),
{'$delEpm', EpmHandler, Args} ->
{Reply, NewEpmHers} = doDelEpm(EpmHers, EpmHandler, Args),
reply(From, Reply),
receiveIng(Parent, Name, Module, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, false);
{'$swapEpm', EpmId1, Args1, EpmId2, Args2} ->
@ -1257,7 +1291,7 @@ matchEpmCallMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, P
reply(From, Reply),
reLoopEntry(Parent, Name, Module, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, IsHib);
{'$syncNotify', Event} ->
{NewEpmHers, IsHib} = doNotify(EpmHers, Event, handleEvent, false),
{NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false),
reply(From, ok),
startEpmCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, handleEpmEvent, Request, IsHib);
{'$epmCall', EpmHandler, Query} ->
@ -1269,10 +1303,10 @@ matchEpmInfoMsg(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, P
NewDebug = ?SYS_DEBUG(Debug, Name, {in, {CmdOrEmpHandler, Event}, CurStatus}),
case CmdOrEmpHandler of
'$infoNotify' ->
{NewEpmHers, IsHib} = doNotify(EpmHers, Event, handleEvent, false),
{NewEpmHers, IsHib} = doNotify(EpmHers, handleEvent, Event, false),
startEpmCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, handleEpmEvent, Event, IsHib);
EpmHandler ->
{NewEpmHers, IsHib} = doEpmHandle(EpmHers, EpmHandler, Event, handleInfo, false),
{NewEpmHers, IsHib} = doEpmHandle(EpmHers, EpmHandler, handleInfo, Event, false),
startEpmCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, NewEpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, handleEpmInfo, Event, IsHib)
end.
@ -1286,8 +1320,8 @@ startEpmCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Post
catch
throw:Ret ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [Event], Ret, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [Event])
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, NewDebug, [Event])
end;
_ ->
receiveIng(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, IsHib)
@ -1300,8 +1334,8 @@ startEnterCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Po
catch
throw:Result ->
handleEnterCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, PrevStatus, CurState, CurStatus, Debug, LeftEvents, NextEs, IsPos, IsHib, DoAfter, Result);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
end.
startAfterCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Args) ->
@ -1311,8 +1345,8 @@ startAfterCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Po
catch
throw:Result ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Result, ?CB_FORM_AFTER, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
end.
startEventCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, {Type, Content}) ->
@ -1324,8 +1358,8 @@ startEventCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Po
catch
throw:Ret ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
end;
'info' ->
try Module:handleInfo(Content, CurStatus, CurState) of
@ -1334,8 +1368,8 @@ startEventCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Po
catch
throw:Ret ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
end;
{'call', From} ->
try Module:handleCall(Content, CurStatus, CurState, From) of
@ -1344,8 +1378,8 @@ startEventCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Po
catch
throw:Ret ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, From);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
end;
_ ->
try Module:handleOnevent(Type, Content, CurStatus, CurState) of
@ -1354,15 +1388,15 @@ startEventCall(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Po
catch
throw:Ret ->
handleEventCR(Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents, Ret, ?CB_FORM_EVENT, false);
Class:Reason ->
terminate(Class, Reason, ?STACKTRACE(), Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
Class:Reason:Strace ->
terminate(Class, Reason, Strace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents)
end
end.
%% handleEpmCallbackRet
handleEpmCR(Result, EpmHers, #epmHer{epmId = EpmId} = EpmHer, Event, From) ->
case Result of
ok ->
kpS ->
{EpmHers, false};
{ok, NewEpmS} ->
MewEpmHer = setelement(#epmHer.epmS, EpmHer, NewEpmS),
@ -1996,13 +2030,16 @@ cancelTimer(TimeoutType, TimerRef, Timers) ->
%% Return a list of all pending timeouts
listTimeouts(Timers) ->
{
maps:size(Timers),
maps:fold(
fun(TimeoutType, {_TimerRef, TimeoutMsg}, Acc) ->
[{TimeoutType, TimeoutMsg} | Acc]
end, [], Timers)
}.
{maps:size(Timers), allTimer(maps:iterator(Timers), [])}.
allTimer(Iterator, Acc) ->
case maps:next(Iterator) of
{TimeoutType, {_TimerRef, TimeoutMsg}, NextIterator} ->
allTimer(NextIterator, [{TimeoutType, TimeoutMsg} | Acc]);
none ->
Acc
end.
%%---------------------------------------------------------------------------
terminate(Class, Reason, Stacktrace, Parent, Name, Module, HibernateAfterTimeout, IsEnter, EpmHers, Postponed, Timers, CurStatus, CurState, Debug, LeftEvents) ->
@ -2099,15 +2136,17 @@ format_log(Report) ->
limit_report(Report, unlimited) ->
Report;
limit_report(
#{label:={es_gen_ipc, terminate},
queue:=Q,
postponed:=Postponed,
module:=Module,
status:=FmtData,
timeouts:=Timeouts,
log:=Log,
reason:={Class, Reason, Stacktrace},
client_info:=ClientInfo} = Report,
#{
label := {es_gen_ipc, terminate},
queue := Q,
postponed := Postponed,
module := Module,
status := FmtData,
timeouts := Timeouts,
log := Log,
reason := {Class, Reason, Stacktrace},
client_info := ClientInfo
} = Report,
Depth) ->
Report#{
queue =>
@ -2156,25 +2195,26 @@ format_log(Report, FormatOpts0) ->
FormatOpts = maps:merge(Default, FormatOpts0),
IoOpts =
case FormatOpts of
#{ chars_limit:=unlimited} -> [];
#{ chars_limit:=Limit} -> [{chars_limit, Limit}]
#{chars_limit := unlimited} -> [];
#{chars_limit := Limit} -> [{chars_limit, Limit}]
end,
{Format, Args} = format_log_single(Report, FormatOpts),
io_lib:format(Format, Args, IoOpts).
format_log_single(
#{
label:={es_gen_ipc, terminate},
name:=Name,
queue:=Q,
label := {es_gen_ipc, terminate},
name := Name,
queue := Q,
%% postponed
%% isEnter
status:=FmtData,
status := FmtData,
%% timeouts
log:=Log,
reason:={Class, Reason, Stacktrace},
client_info:=ClientInfo},
#{single_line:=true, depth:=Depth} = FormatOpts) ->
log := Log,
reason := {Class, Reason, Stacktrace},
client_info := ClientInfo
},
#{single_line := true, depth := Depth} = FormatOpts) ->
P = p(FormatOpts),
{FixedReason, FixedStacktrace} = fix_reason(Class, Reason, Stacktrace),
{ClientFmt, ClientArgs} = format_client_log_single(ClientInfo, P, Depth),
@ -2224,18 +2264,19 @@ format_log_single(Report, FormatOpts) ->
format_log_multi(
#{
label:={es_gen_ipc, terminate},
name:=Name,
queue:=Q,
postponed:=Postponed,
module:=Module,
isEnter:=StateEnter,
status:=FmtData,
timeouts:=Timeouts,
log:=Log,
reason:={Class, Reason, Stacktrace},
client_info:=ClientInfo},
#{depth:=Depth} = FormatOpts) ->
label := {es_gen_ipc, terminate},
name := Name,
queue := Q,
postponed := Postponed,
module := Module,
isEnter := StateEnter,
status := FmtData,
timeouts := Timeouts,
log := Log,
reason := {Class, Reason, Stacktrace},
client_info := ClientInfo
},
#{depth := Depth} = FormatOpts) ->
P = p(FormatOpts),
{FixedReason, FixedStacktrace} = fix_reason(Class, Reason, Stacktrace),
{ClientFmt, ClientArgs} = format_client_log(ClientInfo, P, Depth),
@ -2378,7 +2419,7 @@ format_client_log({_Pid, {Name, Stacktrace}}, P, Depth) ->
end,
{Format, Args}.
p(#{ single_line:=Single, depth:=Depth, encoding:=Enc}) ->
p(#{single_line := Single, depth := Depth, encoding := Enc}) ->
"~" ++ single(Single) ++ mod(Enc) ++ p(Depth);
p(unlimited) ->
"p";

+ 0
- 242
src/sync/esSyncSrv.erl ファイルの表示

@ -1,242 +0,0 @@
-module(esSyncSrv).
-behaviour(es_gen_ipc).
-include("eSync.hrl").
-compile(inline).
-compile({inline_size, 128}).
%% API
-export([
start_link/0,
rescan/0,
pause/0,
unpause/0,
setLog/1,
getLog/0,
curInfo/0,
getOnsync/0,
setOnsync/1,
swSyncNode/1
]).
%% es_gen_ipc callbacks
-export([
init/1,
handleCall/4,
handleAfter/3,
handleCast/3,
handleInfo/3,
handleOnevent/4,
terminate/3
]).
-define(SERVER, ?MODULE).
-define(None, 0).
-record(state, {
srcFiles = #{} :: map()
, onsyncFun = undefined
, swSyncNode = false
, sockMod = undefined
, sock = undefined
}).
%% ************************************ API start ***************************
rescan() ->
es_gen_ipc:cast(?SERVER, miRescan),
esUtils:logSuccess("start rescaning source files..."),
ok.
unpause() ->
es_gen_ipc:cast(?SERVER, miUnpause),
ok.
pause() ->
es_gen_ipc:cast(?SERVER, miPause),
esUtils:logSuccess("Pausing eSync. Call eSync:run() to restart"),
ok.
curInfo() ->
es_gen_ipc:call(?SERVER, miCurInfo).
setLog(T) when ?LOG_ON(T) ->
esUtils:setEnv(log, T),
esUtils:loadCfg(),
esUtils:logSuccess("Console Notifications Enabled"),
ok;
setLog(_) ->
esUtils:setEnv(log, none),
esUtils:loadCfg(),
esUtils:logSuccess("Console Notifications Disabled"),
ok.
getLog() ->
?esCfgSync:getv(log).
swSyncNode(IsSync) ->
es_gen_ipc:cast(?SERVER, {miSyncNode, IsSync}),
ok.
getOnsync() ->
es_gen_ipc:call(?SERVER, miGetOnsync).
setOnsync(Fun) ->
es_gen_ipc:call(?SERVER, {miSetOnsync, Fun}).
%% ************************************ API end ***************************
start_link() ->
es_gen_ipc:start_link({local, ?SERVER}, ?MODULE, ?None, []).
%% status :: waiting | running | pause
init(_Args) ->
erlang:process_flag(trap_exit, true),
esUtils:loadCfg(),
{ok, waiting, #state{}, {doAfter, ?None}}.
handleAfter(?None, waiting, State) ->
%% tcp
case gen_tcp:listen(0, ?TCP_DEFAULT_OPTIONS) of
{ok, LSock} ->
{ok, ListenPort} = inet:port(LSock),
case prim_inet:async_accept(LSock, -1) of
{ok, _Ref} ->
{ok, SockMod} = inet_db:lookup_socket(LSock),
spawn(fun() ->
case os:type() of
{win32, _Osname} ->
CmtStr = "start " ++ esUtils:fileSyncPath("fileSync.exe") ++ " ./ " ++ integer_to_list(ListenPort),
CmdRet = os:cmd(CmtStr),
RetMsg = io_lib:format("the os:cmd start fileSync CmtStr:~p ret:~p ~n ", [CmtStr, CmdRet]),
esUtils:logErrors(RetMsg);
_ ->
CmtStr = esUtils:fileSyncPath("fileSync") ++ " ./ " ++ integer_to_list(ListenPort),
CmdRet = os:cmd(CmtStr),
RetMsg = io_lib:format("the os:cmd start fileSync CmtStr:~p ret:~p ~n ", [CmtStr, CmdRet]),
esUtils:logErrors(RetMsg)
end end),
{kpS, State#state{sockMod = SockMod}, {sTimeout, 4000, waitConnOver}};
{error, Reason} ->
Msg = io_lib:format("init prim_inet:async_accept error ~p~n", [Reason]),
esUtils:logErrors(Msg),
{kpS, State, {sTimeout, 2000, waitConnOver}}
end;
{error, Reason} ->
Msg = io_lib:format("failed to listen ~p (~s) ~n", [Reason, inet:format_error(Reason)]),
esUtils:logErrors(Msg),
{kpS, State, {sTimeout, 2000, waitConnOver}}
end.
handleCall(miGetOnsync, _, #state{onsyncFun = OnSync} = State, _From) ->
{reply, OnSync, State};
handleCall({miSetOnsync, Fun}, _, State, _From) ->
{reply, ok, State#state{onsyncFun = Fun}};
handleCall(miCurInfo, _, State, _Form) ->
{reply, {erlang:get(), State}, State};
handleCall(_Request, _, _State, _From) ->
kpS_S.
handleCast(miPause, running, State) ->
{nextS, pause, State};
handleCast(miUnpause, pause, State) ->
{nextS, running, State};
handleCast({miSyncNode, IsSync}, _, State) ->
case IsSync of
true ->
{kpS, State#state{swSyncNode = true}};
_ ->
{kpS, State#state{swSyncNode = false}}
end;
handleCast(miRescan, _, State) ->
SrcFiles = esUtils:collSrcFiles(false),
{kpS_S, State#state{srcFiles = SrcFiles}};
handleCast(_Msg, _, _State) ->
kpS_S.
handleInfo({tcp, _Socket, Data}, running, #state{srcFiles = SrcFiles, onsyncFun = OnsyncFun, swSyncNode = SwSyncNode} = State) ->
FileList = binary:split(Data, <<"\r\n">>, [global]),
%% beam hrl src
{Beams, Hrls, Srcs} = esUtils:classifyChangeFile(FileList, [], [], []),
esUtils:reloadChangedMod(Beams, SwSyncNode, OnsyncFun, []),
case ?esCfgSync:getv(?compileCmd) of
undefined ->
esUtils:recompileChangeHrlFile(Hrls, SrcFiles, SwSyncNode),
esUtils:recompileChangeSrcFile(Srcs, SwSyncNode),
NewSrcFiles = esUtils:addNewFile(Srcs, SrcFiles),
{kpS, State#state{srcFiles = NewSrcFiles}};
CmdStr ->
case Srcs =/= [] orelse Hrls =/= [] of
true ->
RetStr = os:cmd(CmdStr),
RetList = string:split(RetStr, "\n", all),
CmdMsg = io_lib:format("compile cmd:~p ~n", [CmdStr]),
esUtils:logSuccess(CmdMsg),
RetMsg = io_lib:format("the result: ~n ", []),
esUtils:logSuccess(RetMsg),
[
begin
OneMsg = io_lib:format("~p ~n", [OneRet]),
esUtils:logSuccess(OneMsg)
end || OneRet <- RetList, OneRet =/= []
],
ok;
_ ->
ignore
end,
kpS_S
end;
handleInfo({inet_async, LSock, _Ref, Msg}, _, #state{sockMod = SockMod} = State) ->
case Msg of
{ok, Sock} ->
%% make it look like gen_tcp:accept
inet_db:register_socket(Sock, SockMod),
inet:setopts(Sock, [{active, true}]),
prim_inet:async_accept(LSock, -1),
%%
{AddSrcDirs, OnlySrcDirs, DelSrcDirs} = esUtils:mergeExtraDirs(false),
AddStr = string:join([filename:nativename(OneDir) || OneDir <- AddSrcDirs], "|"),
OnlyStr = string:join([filename:nativename(OneDir) || OneDir <- OnlySrcDirs], "|"),
DelStr = string:join([filename:nativename(OneDir) || OneDir <- DelSrcDirs], "|"),
AllStr = string:join([AddStr, OnlyStr, DelStr], "\r\n"),
gen_tcp:send(Sock, AllStr),
esUtils:logSuccess("eSync connect fileSync success..."),
case ?esCfgSync:getv(?compileCmd) of
undefined ->
%% src文件
SrcFiles = esUtils:collSrcFiles(true),
{nextS, running, State#state{sock = Sock, srcFiles = SrcFiles}};
_ ->
{nextS, running, State}
end;
{error, closed} ->
Msg = io_lib:format("error, closed listen sock error ~p~n", [closed]),
esUtils:logErrors(Msg),
{stop, normal};
{error, Reason} ->
Msg = io_lib:format("listen sock error ~p~n", [Reason]),
esUtils:logErrors(Msg),
{stop, {lsock, Reason}}
end;
handleInfo({tcp_closed, _Socket}, running, _State) ->
Msg = io_lib:format("esSyncSrv receive tcp_closed ~n", []),
esUtils:logErrors(Msg),
kpS_S;
handleInfo({tcp_error, _Socket, Reason}, running, _State) ->
Msg = io_lib:format("esSyncSrv receive tcp_error Reason:~p ~n", [Reason]),
esUtils:logErrors(Msg),
kpS_S;
handleInfo(_Msg, _, _State) ->
Msg = io_lib:format("esSyncSrv receive unexpect msg:~p ~n", [_Msg]),
esUtils:logErrors(Msg),
kpS_S.
handleOnevent(sTimeout, waitConnOver, Status, State) ->
Msg = io_lib:format("failed to connect the fileSync to stop stauts:~p state:~p ~n", [Status, State]),
esUtils:logErrors(Msg),
stop;
handleOnevent(_EventType, _EventContent, _Status, _State) ->
kpS_S.
terminate(_Reason, _Status, _State) ->
ok.

+ 0
- 902
src/sync/esUtils.erl ファイルの表示

@ -1,902 +0,0 @@
-module(esUtils).
-include("eSync.hrl").
-compile(inline).
-compile({inline_size, 128}).
-compile([export_all, nowarn_export_all]).
getModSrcDir(Module) ->
case code:is_loaded(Module) of
{file, _} ->
try
%% Get some module info...
Props = Module:module_info(compile),
Source = proplists:get_value(source, Props, ""),
%% Ensure that the file exists, is a decendent of the tree, and how to deal with that
IsFile = filelib:is_regular(Source),
IsDescendant = isDescendent(Source),
Descendant = ?esCfgSync:getv(?descendant),
LastSource =
case {IsFile, IsDescendant, Descendant} of
%% is file and descendant, we're good to go
{true, true, _} -> Source;
%% is not a descendant, but we allow them, so good to go
{true, false, allow} -> Source;
%% is not a descendant, and we fix non-descendants, so let's fix it
{_, false, fix} -> fixDescendantSource(Source, IsFile);
%% Anything else, and we don't know what to do, so let's just bail.
_ -> undefined
end,
case LastSource of
undefined ->
undefined;
_ ->
%% Get the source dir...
Dir = filename:dirname(LastSource),
getSrcDir(Dir)
end
catch _ : _ ->
undefined
end;
_ ->
undefined
end.
getModOptions(Module) ->
case code:is_loaded(Module) of
{file, _} ->
try
Props = Module:module_info(compile),
BeamDir = filename:dirname(code:which(Module)),
Options1 = proplists:get_value(options, Props, []),
%% transform `outdir'
Options2 = transformOutdir(BeamDir, Options1),
Options3 = ensureInclude(Options2),
%% transform the include directories
Options4 = transformAllIncludes(Module, BeamDir, Options3),
%% maybe_add_compile_info
Options5 = maybeAddCompileInfo(Options4),
%% add filetype to options (DTL, LFE, erl, etc)
Options6 = addFileType(Module, Options5),
{ok, Options6}
catch ExType:Error ->
Msg = [io_lib:format("~p:0: ~p looking for options: ~p. ~n", [Module, ExType, Error])],
logWarnings(Msg),
undefined
end;
_ ->
undefined
end.
tryGetModOptions(Module) ->
try
Props = Module:module_info(compile),
BeamDir = filename:dirname(code:which(Module)),
Options1 = proplists:get_value(options, Props, []),
%% transform `outdir'
Options2 = transformOutdir(BeamDir, Options1),
Options3 = ensureInclude(Options2),
%% transform the include directories
Options4 = transformAllIncludes(Module, BeamDir, Options3),
%% maybe_add_compile_info
Options5 = maybeAddCompileInfo(Options4),
%% add filetype to options (DTL, LFE, erl, etc)
Options6 = addFileType(Module, Options5),
{ok, Options6}
catch _ExType:_Error ->
undefiend
end.
tryGetSrcOptions(SrcDir) ->
%% Then we dig back through the parent directories until we find our include directory
NewDirName = filename:dirname(SrcDir),
case getOptions(NewDirName) of
{ok, _Options} = Opts ->
Opts;
_ ->
BaseName = filename:basename(SrcDir),
IsBaseSrcDir = BaseName == ?rootSrcDir,
case NewDirName =/= SrcDir andalso not IsBaseSrcDir of
true ->
tryGetSrcOptions(NewDirName);
_ when IsBaseSrcDir ->
try filelib:fold_files(SrcDir, ".*\\.(erl|dtl|lfe|ex)$", true,
fun(OneFiles, Acc) ->
Mod = binary_to_atom(filename:basename(OneFiles, filename:extension(OneFiles))),
case tryGetModOptions(Mod) of
{ok, _Options} = Opts ->
throw(Opts);
_ ->
Acc
end
end, undefined)
catch
{ok, _Options} = Opts ->
Opts;
_ExType:_Error ->
Msg = [io_lib:format("looking src options error ~p:~p. ~n", [_ExType, _Error])],
logWarnings(Msg),
undefined
end;
_ ->
undefined
end
end.
transformOutdir(BeamDir, Options) ->
[{outdir, BeamDir} | proplists:delete(outdir, Options)].
ensureInclude(Options) ->
case proplists:get_value(i, Options) of
undefined -> [{i, "include"} | Options];
_ -> Options
end.
transformAllIncludes(Module, BeamDir, Options) ->
[begin
case Opt of
{i, IncludeDir} ->
{ok, SrcDir} = getModSrcDir(Module),
{ok, IncludeDir2} = determineIncludeDir(IncludeDir, BeamDir, SrcDir),
{i, IncludeDir2};
_ ->
Opt
end
end || Opt <- Options].
maybeAddCompileInfo(Options) ->
case lists:member(compile_info, Options) of
true -> Options;
false -> addCompileInfo(Options)
end.
addCompileInfo(Options) ->
CompInfo = [{K, V} || {K, V} <- Options, lists:member(K, [outdir, i])],
[{compile_info, CompInfo} | Options].
addFileType(Module, Options) ->
Type = getFileType(Module),
[{type, Type} | Options].
%% This will check if the given module or source file is an ErlyDTL template.
%% Currently, this is done by checking if its reported source path ends with
%% ".dtl.erl".
getFileType(Module) when is_atom(Module) ->
Props = Module:module_info(compile),
Source = proplists:get_value(source, Props, ""),
getFileType(Source);
getFileType(Source) ->
Ext = filename:extension(Source),
Root = filename:rootname(Source),
SecondExt = filename:extension(Root),
case Ext of
<<".erl">> when SecondExt =:= <<".dtl">> -> dtl;
<<".dtl">> -> dtl;
<<".erl">> -> erl;
<<".lfe">> -> lfe;
<<".ex">> -> elixir;
".erl" when SecondExt =:= ".dtl" -> dtl;
".dtl" -> dtl;
".erl" -> erl;
".lfe" -> lfe;
".ex" -> elixir
end.
%% This will search back to find an appropriate include directory, by
%% searching further back than "..". Instead, it will extract the basename
%% (probably "include" from the include pathfile, and then search backwards in
%% the directory tree until it finds a directory with the same basename found
%% above.
determineIncludeDir(IncludeDir, BeamDir, SrcDir) ->
IncludeBase = filename:basename(IncludeDir),
case determineIncludeDirFromBeamDir(IncludeBase, IncludeDir, BeamDir) of
{ok, _Dir} = RetD -> RetD;
undefined ->
{ok, Cwd} = file:get_cwd(),
% Cwd2 = normalizeCaseWindowsDir(Cwd),
% SrcDir2 = normalizeCaseWindowsDir(SrcDir),
% IncludeBase2 = normalizeCaseWindowsDir(IncludeBase),
case findIncludeDirFromAncestors(SrcDir, Cwd, IncludeBase) of
{ok, _Dir} = RetD -> RetD;
undefined -> {ok, IncludeDir} %% Failed, just stick with original
end
end.
%% First try to see if we have an include file alongside our ebin directory, which is typically the case
determineIncludeDirFromBeamDir(IncludeBase, IncludeDir, BeamDir) ->
BeamBasedIncDir = filename:join(filename:dirname(BeamDir), IncludeBase),
case filelib:is_dir(BeamBasedIncDir) of
true -> {ok, BeamBasedIncDir};
false ->
BeamBasedIncDir2 = filename:join(filename:dirname(BeamDir), IncludeDir),
case filelib:is_dir(BeamBasedIncDir2) of
true -> {ok, BeamBasedIncDir2};
_ ->
undefined
end
end.
%% get the src dir
getRootSrcDirFromSrcDir(SrcDir) ->
NewDirName = filename:dirname(SrcDir),
BaseName = filename:basename(SrcDir),
case BaseName of
?rootSrcDir ->
NewDirName;
_ ->
case NewDirName =/= SrcDir of
true ->
getRootSrcDirFromSrcDir(NewDirName);
_ ->
undefined
end
end.
%% Then we dig back through the parent directories until we find our include directory
findIncludeDirFromAncestors(Cwd, Cwd, _) -> undefined;
findIncludeDirFromAncestors("/", _, _) -> undefined;
findIncludeDirFromAncestors(".", _, _) -> undefined;
findIncludeDirFromAncestors("", _, _) -> undefined;
findIncludeDirFromAncestors(Dir, Cwd, IncludeBase) ->
NewDirName = filename:dirname(Dir),
AttemptDir = filename:join(NewDirName, IncludeBase),
case filelib:is_dir(AttemptDir) of
true ->
{ok, AttemptDir};
false ->
case NewDirName =/= Dir of
true ->
findIncludeDirFromAncestors(NewDirName, Cwd, IncludeBase);
_ ->
undefined
end
end.
% normalizeCaseWindowsDir(Dir) ->
% case os:type() of
% {win32, _} -> Dir; %string:to_lower(Dir);
% {unix, _} -> Dir
% end.
%% This is an attempt to intelligently fix paths in modules when a
%% release is moved. Essentially, it takes a module name and its original path
%% from Module:module_info(compile), say
%% "/some/original/path/site/src/pages/somepage.erl", and then breaks down the
%% path one by one prefixing it with the current working directory until it
%% either finds a match, or fails. If it succeeds, it returns the Path to the
%% new Source file.
fixDescendantSource([], _IsFile) ->
undefined;
fixDescendantSource(Path, IsFile) ->
{ok, Cwd} = file:get_cwd(),
PathParts = filename:split(Path),
case makeDescendantSource(PathParts, Cwd) of
undefined -> case IsFile of true -> Path; _ -> undefined end;
FoundPath -> FoundPath
end.
makeDescendantSource([], _Cwd) ->
undefined;
makeDescendantSource([_ | T], Cwd) ->
PathAttempt = filename:join([Cwd | T]),
case filelib:is_regular(PathAttempt) of
true -> PathAttempt;
false -> makeDescendantSource(T, Cwd)
end.
isDescendent(Path) ->
{ok, Cwd} = file:get_cwd(),
lists:sublist(Path, length(Cwd)) == Cwd.
%% @private Find the src directory for the specified Directory; max 15 iterations
getSrcDir(Dir) ->
getSrcDir(Dir, 15).
getSrcDir(_Dir, 0) ->
undefined;
getSrcDir(Dir, Ctr) ->
HasCode = filelib:wildcard("*.erl", Dir) /= [] orelse
filelib:wildcard("*.hrl", Dir) /= [] orelse
filelib:wildcard("*.dtl", Dir) /= [] orelse
filelib:wildcard("*.lfe", Dir) /= [] orelse
filelib:wildcard("*.ex", Dir) /= [],
if
HasCode -> {ok, Dir};
true -> getSrcDir(filename:dirname(Dir), Ctr - 1)
end.
mergeExtraDirs(IsAddPath) ->
case ?esCfgSync:getv(?extraDirs) of
undefined ->
{[], [], []};
ExtraList ->
FunMerge =
fun(OneExtra, {AddDirs, OnlyDirs, DelDirs} = AllAcc) ->
case OneExtra of
{add, DirsAndOpts} ->
Adds =
[
begin
case IsAddPath of
true ->
case proplists:get_value(outdir, Opts) of
undefined ->
true;
Path ->
ok = filelib:ensure_dir(Path),
true = code:add_pathz(Path)
end;
_ ->
ignore
end,
filename:absname(Dir)
end || {Dir, Opts} <- DirsAndOpts
],
setelement(1, AllAcc, Adds ++ AddDirs);
{only, DirsAndOpts} ->
Onlys =
[
begin
case IsAddPath of
true ->
case proplists:get_value(outdir, Opts) of
undefined ->
true;
Path ->
ok = filelib:ensure_dir(Path),
true = code:add_pathz(Path)
end;
_ ->
ignore
end,
filename:absname(Dir)
end || {Dir, Opts} <- DirsAndOpts
],
setelement(2, AllAcc, Onlys ++ OnlyDirs);
{del, DirsAndOpts} ->
Dels =
[
begin
filename:absname(Dir)
end || {Dir, _Opts} <- DirsAndOpts
],
setelement(3, AllAcc, Dels ++ DelDirs)
end
end,
lists:foldl(FunMerge, {[], [], []}, ExtraList)
end.
collSrcFiles(IsAddPath) ->
{AddSrcDirs, OnlySrcDirs, DelSrcDirs} = mergeExtraDirs(IsAddPath),
CollFiles = filelib:fold_files(filename:absname(<<"./">>), ".*\\.(erl|dtl|lfe|ex)$", true,
fun(OneFiles, Acc) ->
case isOnlyDir(OnlySrcDirs, OneFiles) of
true ->
case isDelDir(DelSrcDirs, OneFiles) of
false ->
RootSrcDir =
case getRootSrcDirFromSrcDir(OneFiles) of
undefined ->
filename:dirname(OneFiles);
RetSrcDir ->
RetSrcDir
end,
case getOptions(RootSrcDir) of
undefined ->
Mod = binary_to_atom(filename:basename(OneFiles, filename:extension(OneFiles))),
case getModOptions(Mod) of
{ok, Options} ->
setOptions(RootSrcDir, Options);
_ ->
ignore
end;
_ ->
ignore
end,
Acc#{OneFiles => 1};
_ ->
Acc
end;
_ ->
Acc
end
end, #{}),
FunCollAdds =
fun(OneDir, FilesAcc) ->
filelib:fold_files(case is_list(OneDir) of true -> list_to_binary(OneDir); _ ->
OneDir end, ".*\\.(erl|dtl|lfe|ex)$", true, fun(OneFiles, Acc) ->
Acc#{OneFiles => 1} end, FilesAcc)
end,
lists:foldl(FunCollAdds, CollFiles, AddSrcDirs).
isOnlyDir([], _) ->
true;
isOnlyDir(ReplaceDirs, SrcDir) ->
isMatchDir(ReplaceDirs, SrcDir).
isDelDir([], _) ->
false;
isDelDir(ReplaceDirs, SrcDir) ->
isMatchDir(ReplaceDirs, SrcDir).
isMatchDir([], _SrcDir) ->
false;
isMatchDir([SrcDir | _ReplaceDirs], SrcDir) ->
true;
isMatchDir([OneDir | ReplaceDirs], SrcDir) ->
case re:run(SrcDir, OneDir) of
nomatch -> isMatchDir(ReplaceDirs, SrcDir);
_ -> true
end.
getEnv(Var, Default) ->
case application:get_env(eSync, Var) of
{ok, Value} ->
Value;
_ ->
Default
end.
setEnv(Var, Val) ->
ok = application:set_env(eSync, Var, Val).
logSuccess(Message) ->
canLog(success) andalso error_logger:info_msg(lists:flatten(Message)).
logErrors(Message) ->
canLog(errors) andalso error_logger:error_msg(lists:flatten(Message)).
logWarnings(Message) ->
canLog(warnings) andalso error_logger:warning_msg(lists:flatten(Message)).
canLog(MsgType) ->
case esSyncSrv:getLog() of
true -> true;
all -> true;
none -> false;
false -> false;
skip_success -> MsgType == errors orelse MsgType == warnings;
L when is_list(L) -> lists:member(MsgType, L);
_ -> false
end.
%% map类型的数据不能当做key
-type key() :: atom() | binary() | bitstring() | float() | integer() | list() | tuple().
-type value() :: atom() | binary() | bitstring() | float() | integer() | list() | tuple() | map().
-spec load(term(), [{key(), value()}]) -> ok.
load(Module, KVs) ->
Forms = forms(Module, KVs),
{ok, Module, Bin} = compile:forms(Forms),
code:soft_purge(Module),
{module, Module} = code:load_binary(Module, atom_to_list(Module), Bin),
ok.
forms(Module, KVs) ->
%% -module(Module).
Mod = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
%% -export([getv/0]).
ExportList = [erl_syntax:arity_qualifier(erl_syntax:atom(getv), erl_syntax:integer(1))],
Export = erl_syntax:attribute(erl_syntax:atom(export), [erl_syntax:list(ExportList)]),
%% getv(K) -> V
Function = erl_syntax:function(erl_syntax:atom(getv), lookup_clauses(KVs, [])),
[erl_syntax:revert(X) || X <- [Mod, Export, Function]].
lookup_clause(Key, Value) ->
Var = erl_syntax:abstract(Key),
Body = erl_syntax:abstract(Value),
erl_syntax:clause([Var], [], [Body]).
lookup_clause_anon() ->
Var = erl_syntax:variable("_"),
Body = erl_syntax:atom(undefined),
erl_syntax:clause([Var], [], [Body]).
lookup_clauses([], Acc) ->
lists:reverse(lists:flatten([lookup_clause_anon() | Acc]));
lookup_clauses([{Key, Value} | T], Acc) ->
lookup_clauses(T, [lookup_clause(Key, Value) | Acc]).
getOptions(SrcDir) ->
case erlang:get(SrcDir) of
undefined ->
undefined;
Options ->
{ok, Options}
end.
setOptions(SrcDir, Options) ->
case erlang:get(SrcDir) of
undefined ->
erlang:put(SrcDir, Options);
OldOptions ->
NewOptions =
case lists:keytake(compile_info, 1, Options) of
{value, {compile_info, ValList1}, Options1} ->
case lists:keytake(compile_info, 1, OldOptions) of
{value, {compile_info, ValList2}, Options2} ->
[{compile_info, lists:usort(ValList1 ++ ValList2)} | lists:usort(Options1 ++ Options2)];
_ ->
lists:usort(Options ++ OldOptions)
end;
_ ->
lists:usort(Options ++ OldOptions)
end,
erlang:put(SrcDir, NewOptions)
end.
loadCfg() ->
KVs = [{Key, esUtils:getEnv(Key, DefVal)} || {Key, DefVal} <- ?CfgList],
esUtils:load(?esCfgSync, KVs).
%% ******************************* **********************************************************************
errorNoFile(Module) ->
Msg = io_lib:format("~p Couldn't load module: nofile", [Module]),
esUtils:logWarnings([Msg]).
printResults(_Module, SrcFile, [], []) ->
Msg = io_lib:format("~s Recompiled", [SrcFile]),
esUtils:logSuccess(lists:flatten(Msg));
printResults(_Module, SrcFile, [], Warnings) ->
formatErrors(fun esUtils:logWarnings/1, SrcFile, [], Warnings), io_lib:format("~s Recompiled with ~p warnings", [SrcFile, length(Warnings)]);
printResults(_Module, SrcFile, Errors, Warnings) ->
formatErrors(fun esUtils:logErrors/1, SrcFile, Errors, Warnings).
%% @private Print error messages in a pretty and user readable way.
formatErrors(LogFun, File, Errors, Warnings) ->
AllErrors1 = lists:sort(lists:flatten([X || {_, X} <- Errors])),
AllErrors2 = [{Line, "Error", Module, Description} || {Line, Module, Description} <- AllErrors1],
AllWarnings1 = lists:sort(lists:flatten([X || {_, X} <- Warnings])),
AllWarnings2 = [{Line, "Warning", Module, Description} || {Line, Module, Description} <- AllWarnings1],
Everything = lists:sort(AllErrors2 ++ AllWarnings2),
FPck =
fun({Line, Prefix, Module, ErrorDescription}) ->
Msg = formatError(Module, ErrorDescription),
LogMsg = io_lib:format("~s: ~p: ~s: ~s", [File, Line, Prefix, Msg]),
LogFun(LogMsg)
end,
[FPck(X) || X <- Everything],
ok.
formatError(Module, ErrorDescription) ->
case erlang:function_exported(Module, format_error, 1) of
true -> Module:format_error(ErrorDescription);
false -> io_lib:format("~s", [ErrorDescription])
end.
fireOnsync(OnsyncFun, Modules) ->
case OnsyncFun of
undefined -> ok;
Funs when is_list(Funs) -> onsyncApplyList(Funs, Modules);
Fun -> onsyncApply(Fun, Modules)
end.
onsyncApplyList(Funs, Modules) ->
[onsyncApply(Fun, Modules) || Fun <- Funs].
onsyncApply({M, F}, Modules) ->
erlang:apply(M, F, [Modules]);
onsyncApply(Fun, Modules) when is_function(Fun) ->
Fun(Modules).
reloadChangedMod([], _SwSyncNode, OnsyncFun, Acc) ->
fireOnsync(OnsyncFun, Acc);
reloadChangedMod([Module | LeftMod], SwSyncNode, OnsyncFun, Acc) ->
case code:get_object_code(Module) of
error ->
Msg = io_lib:format("Error loading object code for ~p", [Module]),
esUtils:logErrors(Msg),
reloadChangedMod(LeftMod, SwSyncNode, OnsyncFun, Acc);
{Module, Binary, Filename} ->
case code:load_binary(Module, Filename, Binary) of
{module, Module} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod: ~s Success", [Module]),
esUtils:logSuccess(Msg);
{error, What} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod: ~s Errors Reason:~p", [Module, What]),
esUtils:logErrors(Msg)
end,
case SwSyncNode of
true ->
{ok, NumNodes, Nodes} = syncLoadModOnAllNodes(Module),
MsgNodes = io_lib:format("Reloaded(Beam changed) Mod: ~s on ~p nodes:~p", [Module, NumNodes, Nodes]),
esUtils:logSuccess(MsgNodes);
false ->
ignore
end,
reloadChangedMod(LeftMod, SwSyncNode, OnsyncFun, [Module | Acc])
end.
getNodes() ->
lists:usort(lists:flatten(nodes() ++ [rpc:call(X, erlang, nodes, []) || X <- nodes()])) -- [node()].
syncLoadModOnAllNodes(Module) ->
%% Get a list of nodes known by this node, plus all attached nodes.
Nodes = getNodes(),
NumNodes = length(Nodes),
{Module, Binary, _} = code:get_object_code(Module),
FSync =
fun(Node) ->
MsgNode = io_lib:format("Reloading '~s' on ~p", [Module, Node]),
esUtils:logSuccess(MsgNode),
rpc:call(Node, code, ensure_loaded, [Module]),
case rpc:call(Node, code, which, [Module]) of
Filename when is_binary(Filename) orelse is_list(Filename) ->
%% File exists, overwrite and load into VM.
ok = rpc:call(Node, file, write_file, [Filename, Binary]),
rpc:call(Node, code, purge, [Module]),
case rpc:call(Node, code, load_file, [Module]) of
{module, Module} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s and write Success on node:~p", [Module, Node]),
esUtils:logSuccess(Msg);
{error, What} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s and write Errors on node:~p Reason:~p", [Module, Node, What]),
esUtils:logErrors(Msg)
end;
_ ->
%% File doesn't exist, just load into VM.
case rpc:call(Node, code, load_binary, [Module, undefined, Binary]) of
{module, Module} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Success on node:~p", [Module, Node]),
esUtils:logSuccess(Msg);
{error, What} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Errors on node:~p Reason:~p", [Module, Node, What]),
esUtils:logErrors(Msg)
end
end
end,
[FSync(X) || X <- Nodes],
{ok, NumNodes, Nodes}.
recompileChangeSrcFile([], _SwSyncNode) ->
ok;
recompileChangeSrcFile([File | LeftFile], SwSyncNode) ->
recompileSrcFile(File, SwSyncNode),
recompileChangeSrcFile(LeftFile, SwSyncNode).
erlydtlCompile(SrcFile, Options) ->
F =
fun({outdir, OutDir}, Acc) -> [{out_dir, OutDir} | Acc];
(OtherOption, Acc) -> [OtherOption | Acc]
end,
DtlOptions = lists:foldl(F, [], Options),
Module = binary_to_atom(lists:flatten(filename:basename(SrcFile, ".dtl") ++ "_dtl")),
Compiler = erlydtl,
Compiler:compile(SrcFile, Module, DtlOptions).
elixir_compile(SrcFile, Options) ->
Outdir = proplists:get_value(outdir, Options),
Compiler = ':Elixir.Kernel.ParallelCompiler',
Modules = Compiler:files_to_path([SrcFile], Outdir),
Loader =
fun(Module) ->
Outfile = code:which(Module),
Binary = file:read_file(Outfile),
{Module, Binary}
end,
Results = lists:map(Loader, Modules),
{ok, multiple, Results, []}.
lfe_compile(SrcFile, Options) ->
Compiler = lfe_comp,
Compiler:file(SrcFile, Options).
getCompileFunAndModuleName(SrcFile) ->
case esUtils:getFileType(SrcFile) of
erl ->
{fun compile:file/2, binary_to_atom(filename:basename(SrcFile, <<".erl">>))};
dtl ->
{fun erlydtlCompile/2, list_to_atom(lists:flatten(binary_to_list(filename:basename(SrcFile, <<".dtl">>)) ++ "_dtl"))};
lfe ->
{fun lfe_compile/2, binary_to_atom(filename:basename(SrcFile, <<".lfe">>))};
elixir ->
{fun elixir_compile/2, binary_to_atom(filename:basename(SrcFile, <<".ex">>))}
end.
getObjectCode(Module) ->
case code:get_object_code(Module) of
{Module, B, Filename} -> {B, Filename};
_ -> {undefined, undefined}
end.
reloadIfNecessary(Module, OldBinary, Binary, Filename) ->
case Binary =/= OldBinary of
true ->
%% Try to load the module...
case code:ensure_loaded(Module) of
{module, Module} ->
case code:load_binary(Module, Filename, Binary) of
{module, Module} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Success", [Module]),
esUtils:logSuccess(Msg);
{error, What} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Errors Reason:~p", [Module, What]),
esUtils:logErrors(Msg)
end;
{error, nofile} ->
case code:load_binary(Module, Filename, Binary) of
{module, Module} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Success", [Module]),
esUtils:logSuccess(Msg);
{error, What} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Errors Reason:~p", [Module, What]),
esUtils:logErrors(Msg)
end;
{error, embedded} ->
case code:load_file(Module) of %% Module is not yet loaded, load it.
{module, Module} -> ok;
{error, nofile} ->
case code:load_binary(Module, Filename, Binary) of
{module, Module} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Success", [Module]),
esUtils:logSuccess(Msg);
{error, What} ->
Msg = io_lib:format("Reloaded(Beam changed) Mod:~s Errors Reason:~p", [Module, What]),
esUtils:logErrors(Msg)
end
end
end;
_ ->
ignore
end.
recompileSrcFile(SrcFile, SwSyncNode) ->
%% Get the module, src dir, and options...
RootSrcDir =
case getRootSrcDirFromSrcDir(SrcFile) of
undefined ->
filename:dirname(SrcFile);
RetSrcDir ->
RetSrcDir
end,
CurSrcDir = filename:dirname(SrcFile),
{CompileFun, Module} = getCompileFunAndModuleName(SrcFile),
{OldBinary, Filename} = getObjectCode(Module),
case getOptions(RootSrcDir) of
{ok, Options} ->
RightFileDir = binary_to_list(filename:join(CurSrcDir, filename:basename(SrcFile))),
case CompileFun(RightFileDir, [binary, return | Options]) of
{ok, Module, Binary, Warnings} ->
printResults(Module, RightFileDir, [], Warnings),
reloadIfNecessary(Module, OldBinary, Binary, Filename),
{ok, [], Warnings};
{ok, [{ok, Module, Binary, Warnings}], Warnings2} ->
printResults(Module, RightFileDir, [], Warnings ++ Warnings2),
reloadIfNecessary(Module, OldBinary, Binary, Filename),
{ok, [], Warnings ++ Warnings2};
{ok, multiple, Results, Warnings} ->
printResults(Module, RightFileDir, [], Warnings),
[reloadIfNecessary(CompiledModule, OldBinary, Binary, Filename) || {CompiledModule, Binary} <- Results],
{ok, [], Warnings};
{ok, OtherModule, _Binary, Warnings} ->
Desc = io_lib:format("Module definition (~p) differs from expected (~s)", [OtherModule, filename:rootname(filename:basename(RightFileDir))]),
Errors = [{RightFileDir, {0, Module, Desc}}],
printResults(Module, RightFileDir, Errors, Warnings),
{ok, Errors, Warnings};
{error, Errors, Warnings} ->
printResults(Module, RightFileDir, Errors, Warnings),
{ok, Errors, Warnings};
_Err ->
Msg = io_lib:format("compile Mod:~s Errors Reason:~p", [Module, _Err]),
esUtils:logErrors(Msg)
end;
undefined ->
case esUtils:tryGetModOptions(Module) of
{ok, Options} ->
setOptions(RootSrcDir, Options),
recompileSrcFile(SrcFile, SwSyncNode);
_ ->
case esUtils:tryGetSrcOptions(CurSrcDir) of
{ok, Options} ->
setOptions(RootSrcDir, Options),
recompileSrcFile(SrcFile, SwSyncNode);
_ ->
Msg = io_lib:format("Unable to determine options for ~s", [SrcFile]),
esUtils:logErrors(Msg)
end
end
end.
recompileChangeHrlFile([], _SrcFiles, _SwSyncNode) ->
ok;
recompileChangeHrlFile([Hrl | LeftHrl], SrcFiles, SwSyncNode) ->
WhoInclude = whoInclude(Hrl, SrcFiles),
[recompileSrcFile(SrcFile, SwSyncNode) || {SrcFile, _} <- maps:to_list(WhoInclude)],
recompileChangeHrlFile(LeftHrl, SrcFiles, SwSyncNode).
%%
%% whoInclude(HrlFile, SrcFiles) ->
%% HrlFileBaseName = filename:basename(HrlFile),
%% Pred =
%% fun(SrcFile, _) ->
%% {ok, Forms} = epp_dodger:parse_file(SrcFile),
%% isInclude(binary_to_list(HrlFileBaseName), Forms)
%% end,
%% maps:filter(Pred, SrcFiles).
%% isInclude(_HrlFile, []) ->
%% false;
%% isInclude(HrlFile, [{tree, attribute, _, {attribute, _, [{_, _, IncludeFile}]}} | Forms]) when is_list(IncludeFile) ->
%% IncludeFileBaseName = filename:basename(IncludeFile),
%% case IncludeFileBaseName of
%% HrlFile -> true;
%% _ -> isInclude(HrlFile, Forms)
%% end;
%% isInclude(HrlFile, [_SomeForm | Forms]) ->
%% isInclude(HrlFile, Forms).
whoInclude(HrlFile, SrcFiles) ->
HrlFileBaseName = filename:basename(HrlFile),
Pred =
fun(SrcFile, _) ->
case file:open(SrcFile, [read, binary]) of
{ok, IoDevice} ->
IsInclude = doMathEveryLine(IoDevice, HrlFileBaseName),
file:close(IoDevice),
IsInclude;
_ ->
false
end
end,
maps:filter(Pred, SrcFiles).
doMathEveryLine(IoDevice, HrlFileBaseName) ->
case file:read_line(IoDevice) of
{ok, Data} ->
case re:run(Data, HrlFileBaseName) of
nomatch ->
case re:run(Data, <<"->">>) of
nomatch ->
doMathEveryLine(IoDevice, HrlFileBaseName);
_ ->
false
end;
_ ->
true
end;
_ ->
false
end.
classifyChangeFile([], Beams, Hrls, Srcs) ->
{Beams, Hrls, Srcs};
classifyChangeFile([OneFile | LeftFile], Beams, Hrls, Srcs) ->
case filename:extension(OneFile) of
<<".beam">> ->
Module = binary_to_atom(filename:basename(OneFile, <<".beam">>)),
classifyChangeFile(LeftFile, [Module | Beams], Hrls, Srcs);
<<".hrl">> ->
classifyChangeFile(LeftFile, Beams, [OneFile | Hrls], Srcs);
<<>> ->
classifyChangeFile(LeftFile, Beams, Hrls, Srcs);
_ ->
classifyChangeFile(LeftFile, Beams, Hrls, [OneFile | Srcs])
end.
addNewFile([], SrcFiles) ->
SrcFiles;
addNewFile([OneFile | LeftFile], SrcFiles) ->
case SrcFiles of
#{OneFile := _value} ->
addNewFile(LeftFile, SrcFiles);
_ ->
addNewFile(LeftFile, SrcFiles#{OneFile => 1})
end.
fileSyncPath(ExecName) ->
case code:priv_dir(?MODULE) of
{error, _} ->
case code:which(?MODULE) of
Filename when is_list(Filename) ->
filename:join([filename:dirname(filename:dirname(Filename)), "priv", ExecName]);
_ ->
filename:join("../priv", ExecName)
end;
Dir ->
filename:join(Dir, ExecName)
end.

読み込み中…
キャンセル
保存