erlang自动编译与加载
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

1323 satır
50 KiB

3 yıl önce
3 yıl önce
3 yıl önce
1 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
3 yıl önce
5 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
5 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
5 yıl önce
5 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
5 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
1 yıl önce
3 yıl önce
1 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
1 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
3 yıl önce
2 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
2 yıl önce
3 yıl önce
5 yıl önce
3 yıl önce
  1. -module(eSync).
  2. -behaviour(es_gen_ipc).
  3. -include_lib("kernel/include/file.hrl").
  4. -compile(inline).
  5. -compile({inline_size, 128}).
  6. -define(CASE(Cond, Ret1, Ret2), (case Cond of true -> Ret1; _ -> Ret2 end)).
  7. -define(LOG_ON(Val), Val == true; Val == all; Val == skip_success; is_list(Val), Val =/= []).
  8. -define(Log, log).
  9. -define(baseDir, baseDir).
  10. -define(monitorExt, monitorExt).
  11. -define(compileCmd, compileCmd).
  12. -define(extraDirs, extraDirs).
  13. -define(descendant, descendant).
  14. -define(onMSyncFun, onMSyncFun).
  15. -define(onCSyncFun, onCSyncFun).
  16. -define(swSyncNode, swSyncNode).
  17. -define(isJustMem, isJustMem).
  18. -define(debugInfoKeyFun, debugInfoKeyFun).
  19. -define(ExtList, [".hrl", ".erl", ".beam", ".dtl", ".lfe", ".ex", ".config"]).
  20. -define(DefCfgList, [{?Log, all}, {?baseDir, "./"}, {?monitorExt, ?ExtList}, {?compileCmd, undefined}, {?extraDirs, undefined}, {?descendant, fix}, {?onMSyncFun, undefined}, {?onCSyncFun, undefined}, {?swSyncNode, false}, {?isJustMem, false}, {?debugInfoKeyFun, undefined}]).
  21. -define(esCfgSync, esCfgSync).
  22. -define(rootSrcDir, <<"src">>).
  23. -define(logSuccess(Format), canLog(success) andalso error_logger:info_msg("eSync[~p:~p|~p] " ++ Format, [?MODULE, ?FUNCTION_NAME, ?LINE])).
  24. -define(logSuccess(Format, Args), canLog(success) andalso error_logger:info_msg("eSync[~p:~p|~p] " ++ Format, [?MODULE, ?FUNCTION_NAME, ?LINE] ++ Args)).
  25. -define(logErrors(Format), canLog(errors) andalso error_logger:info_msg("eSync[~p:~p|~p] " ++ Format, [?MODULE, ?FUNCTION_NAME, ?LINE])).
  26. -define(logErrors(Format, Args), canLog(errors) andalso error_logger:info_msg("eSync[~p:~p|~p] " ++ Format, [?MODULE, ?FUNCTION_NAME, ?LINE] ++ Args)).
  27. -define(logWarnings(Format), canLog(warnings) andalso error_logger:info_msg("eSync[~p:~p|~p] " ++ Format, [?MODULE, ?FUNCTION_NAME, ?LINE])).
  28. -define(logWarnings(Format, Args), canLog(warnings) andalso error_logger:info_msg("eSync[~p:~p|~p] " ++ Format, [?MODULE, ?FUNCTION_NAME, ?LINE] ++ Args)).
  29. -export([
  30. start/2,
  31. start/0,
  32. stop/0,
  33. run/0
  34. ]).
  35. %% API
  36. -export([
  37. start_link/0,
  38. rescan/0,
  39. pause/0,
  40. unpause/0,
  41. setLog/1,
  42. getLog/0,
  43. curInfo/0,
  44. getOnMSync/0,
  45. setOnMSync/1,
  46. getOnCSync/0,
  47. setOnCSync/1,
  48. swSyncNode/1
  49. ]).
  50. %% es_gen_ipc callbacks
  51. -export([
  52. init/1,
  53. handleCall/4,
  54. handleAfter/3,
  55. handleCast/3,
  56. handleInfo/3,
  57. handleOnevent/4,
  58. terminate/3
  59. ]).
  60. start(_StartType, _StartArgs) ->
  61. start_link().
  62. start() ->
  63. application:ensure_all_started(eSync).
  64. stop() ->
  65. application:stop(eSync).
  66. run() ->
  67. case start() of
  68. {ok, _Started} ->
  69. unpause(),
  70. ok;
  71. {error, Reason} ->
  72. ?logErrors("start eSync error:~p~n", [Reason])
  73. end.
  74. -define(SERVER, ?MODULE).
  75. -define(None, 0).
  76. -record(state, {
  77. port = undefined
  78. , onMSyncFun = undefined
  79. , onCSyncFun = undefined
  80. , swSyncNode = false
  81. , srcFiles = #{} :: map()
  82. , hrlFiles = #{} :: map()
  83. , configs = #{} :: map()
  84. , beams = #{} :: map()
  85. }).
  86. %% ************************************ API start ***************************
  87. rescan() ->
  88. es_gen_ipc:cast(?SERVER, miRescan),
  89. ?logSuccess("start rescaning source files..."),
  90. ok.
  91. unpause() ->
  92. es_gen_ipc:cast(?SERVER, miUnpause),
  93. ok.
  94. pause() ->
  95. es_gen_ipc:cast(?SERVER, miPause),
  96. ?logSuccess("Pausing eSync. Call eSync:run() to restart"),
  97. ok.
  98. curInfo() ->
  99. es_gen_ipc:call(?SERVER, miCurInfo).
  100. setLog(T) when ?LOG_ON(T) ->
  101. setEnv(log, T),
  102. loadCfg(),
  103. ?logSuccess("Console Notifications Enabled"),
  104. ok;
  105. setLog(_) ->
  106. setEnv(log, none),
  107. loadCfg(),
  108. ?logSuccess("Console Notifications Disabled"),
  109. ok.
  110. getLog() ->
  111. ?esCfgSync:getv(log).
  112. swSyncNode(IsSync) ->
  113. es_gen_ipc:cast(?SERVER, {miSyncNode, IsSync}),
  114. ok.
  115. getOnMSync() ->
  116. es_gen_ipc:call(?SERVER, miGetOnMSync).
  117. setOnMSync(Fun) ->
  118. es_gen_ipc:call(?SERVER, {miSetOnMSync, Fun}).
  119. getOnCSync() ->
  120. es_gen_ipc:call(?SERVER, miGetOnCSync).
  121. setOnCSync(Fun) ->
  122. es_gen_ipc:call(?SERVER, {miSetOnCSync, Fun}).
  123. %% ************************************ API end ***************************
  124. start_link() ->
  125. es_gen_ipc:start_link({local, ?SERVER}, ?MODULE, ?None, []).
  126. %% status :: waiting | running | pause
  127. init(_Args) ->
  128. erlang:process_flag(trap_exit, true),
  129. loadCfg(),
  130. {ok, waiting, #state{onMSyncFun = ?esCfgSync:getv(?onMSyncFun), onCSyncFun = ?esCfgSync:getv(?onCSyncFun), swSyncNode = ?esCfgSync:getv(?swSyncNode)}, {doAfter, ?None}}.
  131. handleAfter(?None, waiting, State) ->
  132. %% 启动port 发送监听目录信息
  133. {AddExtraSrcDirs, AddOnlySrcDirs, OnlySrcDirs, DelSrcDirs} = mergeExtraDirs(false),
  134. AddExtraStr = string:join([filename:nativename(OneDir) || OneDir <- AddExtraSrcDirs], "|"),
  135. AddOnlyStr = string:join([filename:nativename(OneDir) || OneDir <- AddOnlySrcDirs], "|"),
  136. OnlyStr = string:join([filename:nativename(OneDir) || OneDir <- OnlySrcDirs], "|"),
  137. DelStr = string:join([filename:nativename(OneDir) || OneDir <- DelSrcDirs], "|"),
  138. AllStr = string:join([AddExtraStr, AddOnlyStr, OnlyStr, DelStr], "\r\n"),
  139. BaseDirStr = filename:nativename(?esCfgSync:getv(?baseDir)),
  140. MonitorExtStr = string:join(?esCfgSync:getv(?monitorExt), "|"),
  141. Opts = [{packet, 4}, binary, exit_status, use_stdio, {args, [BaseDirStr, MonitorExtStr, AllStr]}],
  142. PortName = fileSyncPath("fileSync"),
  143. Port = erlang:open_port({spawn_executable, PortName}, Opts),
  144. {kpS, State#state{port = Port}, {sTimeout, 4000, waitConnOver}}.
  145. handleCall(miGetOnMSync, _, #state{onMSyncFun = OnMSyncFun} = State, _From) ->
  146. {reply, OnMSyncFun, State};
  147. handleCall({miSetOnMSync, Fun}, _, State, _From) ->
  148. {reply, ok, State#state{onMSyncFun = Fun}};
  149. handleCall(miGetOnCSync, _, #state{onCSyncFun = OnCSyncFun} = State, _From) ->
  150. {reply, OnCSyncFun, State};
  151. handleCall({miSetOnCSync, Fun}, _, State, _From) ->
  152. {reply, ok, State#state{onCSyncFun = Fun}};
  153. handleCall(miCurInfo, Status, State, _Form) ->
  154. {reply, {Status, erlang:get(), State}, State};
  155. handleCall(_Request, _, _State, _From) ->
  156. kpS_S.
  157. handleCast(miPause, running, State) ->
  158. {nextS, pause, State};
  159. handleCast(miUnpause, pause, State) ->
  160. {nextS, running, State};
  161. handleCast({miSyncNode, IsSync}, _, State) ->
  162. case IsSync of
  163. true ->
  164. {kpS, State#state{swSyncNode = true}};
  165. _ ->
  166. {kpS, State#state{swSyncNode = false}}
  167. end;
  168. handleCast(miRescan, _, State) ->
  169. {Srcs, Hrls, Configs, Beams} = collSrcFiles(false),
  170. {noreply, State#state{srcFiles = Srcs, hrlFiles = Hrls, configs = Configs, beams = Beams}, hibernate};
  171. handleCast(_Msg, _, _State) ->
  172. kpS_S.
  173. handleInfo({_Port, {data, Data}}, Status, #state{srcFiles = Srcs, hrlFiles = Hrls, configs = Configs, beams = Beams, onMSyncFun = OnMSyncFun, onCSyncFun = OnCSyncFun, swSyncNode = SwSyncNode} = State) ->
  174. case Status of
  175. running ->
  176. FileList = binary:split(Data, <<"\r\n">>, [global]),
  177. %% 收集改动了beam hrl src 文件 然后执行相应的逻辑
  178. {CBeams, CConfigs, CHrls, CSrcs, NewSrcs, NewHrls, NewConfigs, NewBeams} = classifyChangeFile(FileList, [], [], #{}, #{}, Srcs, Hrls, Configs, Beams),
  179. fireOnSync(OnCSyncFun, CConfigs),
  180. reloadChangedMod(CBeams, SwSyncNode, OnMSyncFun, []),
  181. case ?esCfgSync:getv(?compileCmd) of
  182. undefined ->
  183. LastCHrls = collIncludeCHrls(maps:keys(CHrls), NewHrls, CHrls, #{}),
  184. NReSrcs = collIncludeCErls(maps:keys(LastCHrls), NewSrcs, CSrcs, #{}),
  185. recompileChangeSrcFile(maps:iterator(NReSrcs), SwSyncNode),
  186. {kpS, State#state{srcFiles = NewSrcs, hrlFiles = NewHrls, configs = NewConfigs, beams = NewBeams}};
  187. CmdStr ->
  188. case maps:size(CSrcs) > 0 orelse CHrls =/= [] of
  189. true ->
  190. RetStr = os:cmd(CmdStr),
  191. RetList = string:split(RetStr, "\n", all),
  192. ?logSuccess("compile cmd:~p ~n", [CmdStr]),
  193. ?logSuccess("the result: ~n ", []),
  194. [
  195. begin
  196. ?logSuccess("~p ~n", [OneRet])
  197. end || OneRet <- RetList, OneRet =/= []
  198. ],
  199. ok;
  200. _ ->
  201. ignore
  202. end,
  203. kpS_S
  204. end;
  205. _ ->
  206. case Data of
  207. <<"init">> ->
  208. %% 然后收集一下监听目录下的src文件
  209. {BSrcs, BHrls, BConfigs, BBeams} = collSrcFiles(true),
  210. ?logSuccess("eSync connect fileSync success and coll src files over..."),
  211. {nextS, running, State#state{srcFiles = BSrcs, hrlFiles = BHrls, configs = BConfigs, beams = BBeams}, {isHib, true}};
  212. _ ->
  213. ?logErrors("error, receive unexpect port msg ~p~n", [Data]),
  214. kpS_S
  215. end
  216. end;
  217. handleInfo({Port, closed}, running, #state{port = Port} = _State) ->
  218. ?logErrors("receive port closed ~n"),
  219. {nextS, port_close, _State};
  220. handleInfo({'EXIT', Port, Reason}, running, #state{port = Port} = _State) ->
  221. ?logErrors("receive port exit Reason:~p ~n", [Reason]),
  222. {nextS, {port_EXIT, Reason}, _State};
  223. handleInfo({Port, {exit_status, Status}}, running, #state{port = Port} = _State) ->
  224. ?logErrors("receive port exit_status Status:~p ~p ~n", [Status, Port]),
  225. {nextS, {port_exit_status, Status}, _State};
  226. handleInfo({'EXIT', _Pid, _Reason}, running, _State) ->
  227. kpS_S;
  228. handleInfo(_Msg, _, _State) ->
  229. ?logErrors("receive unexpect msg:~p ~n", [_Msg]),
  230. kpS_S.
  231. handleOnevent(sTimeout, waitConnOver, Status, State) ->
  232. ?logErrors("failed to connect the fileSync to stop stauts:~p state:~p ~n", [Status, State]),
  233. stop;
  234. handleOnevent(_EventType, _EventContent, _Status, _State) ->
  235. kpS_S.
  236. terminate(_Reason, _Status, _State) ->
  237. ok.
  238. %% ************************************************* utils start *******************************************************
  239. getModSrcDir(Module) ->
  240. case code:is_loaded(Module) of
  241. {file, _} ->
  242. try
  243. %% Get some module info...
  244. Props = Module:module_info(compile),
  245. Source = proplists:get_value(source, Props, ""),
  246. %% Ensure that the file exists, is a decendent of the tree, and how to deal with that
  247. IsFile = filelib:is_regular(Source),
  248. IsDescendant = isDescendent(Source),
  249. Descendant = ?esCfgSync:getv(?descendant),
  250. LastSource =
  251. case {IsFile, IsDescendant, Descendant} of
  252. %% is file and descendant, we're good to go
  253. {true, true, _} -> Source;
  254. %% is not a descendant, but we allow them, so good to go
  255. {true, false, allow} -> Source;
  256. %% is not a descendant, and we fix non-descendants, so let's fix it
  257. {_, false, fix} -> fixDescendantSource(Source, IsFile);
  258. %% Anything else, and we don't know what to do, so let's just bail.
  259. _ -> undefined
  260. end,
  261. case LastSource of
  262. undefined ->
  263. undefined;
  264. _ ->
  265. %% Get the source dir...
  266. Dir = filename:dirname(LastSource),
  267. getSrcDir(Dir)
  268. end
  269. catch _ : _ ->
  270. undefined
  271. end;
  272. _ ->
  273. undefined
  274. end.
  275. getModOpts(Module) ->
  276. case code:is_loaded(Module) of
  277. {file, _} ->
  278. try
  279. Props = Module:module_info(compile),
  280. BeamDir = filename:dirname(code:which(Module)),
  281. Options1 = proplists:get_value(options, Props, []),
  282. %% transform `outdir'
  283. Options2 = transformOutdir(BeamDir, Options1),
  284. Options3 = ensureInclude(Options2),
  285. %% transform the include directories
  286. Options4 = transformAllIncludes(Module, BeamDir, Options3),
  287. %% maybe_add_compile_info
  288. Options5 = maybeAddCompileInfo(Options4),
  289. %% add filetype to options (DTL, LFE, erl, etc)
  290. Options6 = addFileType(Module, Options5),
  291. Options7 = lists:keyreplace(debug_info_key, 1, Options6, debugInfoKeyFun()),
  292. {ok, Options7}
  293. catch ExType:Error ->
  294. ?logWarnings("~p:0: ~p looking for options: ~p. ~n", [Module, ExType, Error]),
  295. undefined
  296. end;
  297. _ ->
  298. undefined
  299. end.
  300. tryGetModOpts(Module) ->
  301. try
  302. Props = Module:module_info(compile),
  303. BeamDir = filename:dirname(code:which(Module)),
  304. Options1 = proplists:get_value(options, Props, []),
  305. %% transform `outdir'
  306. Options2 = transformOutdir(BeamDir, Options1),
  307. Options3 = ensureInclude(Options2),
  308. %% transform the include directories
  309. Options4 = transformAllIncludes(Module, BeamDir, Options3),
  310. %% maybe_add_compile_info
  311. Options5 = maybeAddCompileInfo(Options4),
  312. %% add filetype to options (DTL, LFE, erl, etc)
  313. Options6 = addFileType(Module, Options5),
  314. Options7 = lists:keyreplace(debug_info_key, 1, Options6, debugInfoKeyFun()),
  315. {ok, Options7}
  316. catch _ExType:_Error ->
  317. undefined
  318. end.
  319. tryGetSrcOpts(SrcDir) ->
  320. %% Then we dig back through the parent directories until we find our include directory
  321. NewDirName = filename:dirname(SrcDir),
  322. case getOptions(NewDirName) of
  323. {ok, _Options} = Opts ->
  324. Opts;
  325. _ ->
  326. BaseName = filename:basename(SrcDir),
  327. IsBaseSrcDir = BaseName == ?rootSrcDir,
  328. case NewDirName =/= SrcDir andalso not IsBaseSrcDir of
  329. true ->
  330. tryGetSrcOpts(NewDirName);
  331. _ when IsBaseSrcDir ->
  332. try filelib:fold_files(SrcDir, ".*\\.(erl|dtl|lfe|ex)$", true,
  333. fun(OneFile, Acc) ->
  334. Mod = binary_to_atom(filename:basename(OneFile, filename:extension(OneFile))),
  335. case tryGetModOpts(Mod) of
  336. {ok, _Options} = Opts ->
  337. throw(Opts);
  338. _ ->
  339. Acc
  340. end
  341. end, undefined)
  342. catch
  343. {ok, _Options} = Opts ->
  344. Opts;
  345. _ExType:_Error ->
  346. ?logWarnings("looking src options error ~p:~p. ~n", [_ExType, _Error]),
  347. undefined
  348. end;
  349. _ ->
  350. undefined
  351. end
  352. end.
  353. transformOutdir(BeamDir, Options) ->
  354. [{outdir, BeamDir} | proplists:delete(outdir, Options)].
  355. ensureInclude(Options) ->
  356. case proplists:get_value(i, Options) of
  357. undefined -> [{i, "include"} | Options];
  358. _ -> Options
  359. end.
  360. transformAllIncludes(Module, BeamDir, Options) ->
  361. [begin
  362. case Opt of
  363. {i, IncludeDir} ->
  364. {ok, SrcDir} = getModSrcDir(Module),
  365. {ok, IncludeDir2} = determineIncludeDir(IncludeDir, BeamDir, SrcDir),
  366. {i, IncludeDir2};
  367. _ ->
  368. Opt
  369. end
  370. end || Opt <- Options].
  371. maybeAddCompileInfo(Options) ->
  372. case lists:member(compile_info, Options) of
  373. true -> Options;
  374. false -> addCompileInfo(Options)
  375. end.
  376. addCompileInfo(Options) ->
  377. CompInfo = [{K, V} || {K, V} <- Options, lists:member(K, [outdir, i])],
  378. [{compile_info, CompInfo} | Options].
  379. addFileType(Module, Options) ->
  380. Type = getFileType(Module),
  381. [{type, Type} | Options].
  382. %% This will check if the given module or source file is an ErlyDTL template.
  383. %% Currently, this is done by checking if its reported source path ends with
  384. %% ".dtl.erl".
  385. getFileType(Module) when is_atom(Module) ->
  386. Props = Module:module_info(compile),
  387. Source = proplists:get_value(source, Props, ""),
  388. getFileType(Source);
  389. getFileType(Source) ->
  390. Ext = filename:extension(Source),
  391. Root = filename:rootname(Source),
  392. SecondExt = filename:extension(Root),
  393. case Ext of
  394. <<".erl">> when SecondExt =:= <<".dtl">> -> dtl;
  395. <<".dtl">> -> dtl;
  396. <<".erl">> -> erl;
  397. <<".lfe">> -> lfe;
  398. <<".ex">> -> elixir;
  399. ".erl" when SecondExt =:= ".dtl" -> dtl;
  400. ".dtl" -> dtl;
  401. ".erl" -> erl;
  402. ".lfe" -> lfe;
  403. ".ex" -> elixir
  404. end.
  405. %% This will search back to find an appropriate include directory, by
  406. %% searching further back than "..". Instead, it will extract the basename
  407. %% (probably "include" from the include pathfile, and then search backwards in
  408. %% the directory tree until it finds a directory with the same basename found
  409. %% above.
  410. determineIncludeDir(IncludeDir, BeamDir, SrcDir) ->
  411. IncludeBase = filename:basename(IncludeDir),
  412. case determineIncludeDirFromBeamDir(IncludeBase, IncludeDir, BeamDir) of
  413. {ok, _Dir} = RetD -> RetD;
  414. undefined ->
  415. {ok, Cwd} = file:get_cwd(),
  416. % Cwd2 = normalizeCaseWindowsDir(Cwd),
  417. % SrcDir2 = normalizeCaseWindowsDir(SrcDir),
  418. % IncludeBase2 = normalizeCaseWindowsDir(IncludeBase),
  419. case findIncludeDirFromAncestors(SrcDir, Cwd, IncludeBase) of
  420. {ok, _Dir} = RetD -> RetD;
  421. undefined -> {ok, IncludeDir} %% Failed, just stick with original
  422. end
  423. end.
  424. %% First try to see if we have an include file alongside our ebin directory, which is typically the case
  425. determineIncludeDirFromBeamDir(IncludeBase, IncludeDir, BeamDir) ->
  426. BeamBasedIncDir = filename:join(filename:dirname(BeamDir), IncludeBase),
  427. case filelib:is_dir(BeamBasedIncDir) of
  428. true -> {ok, BeamBasedIncDir};
  429. false ->
  430. BeamBasedIncDir2 = filename:join(filename:dirname(BeamDir), IncludeDir),
  431. case filelib:is_dir(BeamBasedIncDir2) of
  432. true -> {ok, BeamBasedIncDir2};
  433. _ ->
  434. undefined
  435. end
  436. end.
  437. %% get the src dir
  438. getRootSrcDirFromSrcDir(SrcDir) ->
  439. NewDirName = filename:dirname(SrcDir),
  440. BaseName = filename:basename(SrcDir),
  441. case BaseName of
  442. ?rootSrcDir ->
  443. NewDirName;
  444. _ ->
  445. case NewDirName =/= SrcDir of
  446. true ->
  447. getRootSrcDirFromSrcDir(NewDirName);
  448. _ ->
  449. undefined
  450. end
  451. end.
  452. %% Then we dig back through the parent directories until we find our include directory
  453. findIncludeDirFromAncestors(Cwd, Cwd, _) -> undefined;
  454. findIncludeDirFromAncestors("/", _, _) -> undefined;
  455. findIncludeDirFromAncestors(".", _, _) -> undefined;
  456. findIncludeDirFromAncestors("", _, _) -> undefined;
  457. findIncludeDirFromAncestors(Dir, Cwd, IncludeBase) ->
  458. NewDirName = filename:dirname(Dir),
  459. AttemptDir = filename:join(NewDirName, IncludeBase),
  460. case filelib:is_dir(AttemptDir) of
  461. true ->
  462. {ok, AttemptDir};
  463. false ->
  464. case NewDirName =/= Dir of
  465. true ->
  466. findIncludeDirFromAncestors(NewDirName, Cwd, IncludeBase);
  467. _ ->
  468. undefined
  469. end
  470. end.
  471. % normalizeCaseWindowsDir(Dir) ->
  472. % case os:type() of
  473. % {win32, _} -> Dir; %string:to_lower(Dir);
  474. % {unix, _} -> Dir
  475. % end.
  476. %% This is an attempt to intelligently fix paths in modules when a
  477. %% release is moved. Essentially, it takes a module name and its original path
  478. %% from Module:module_info(compile), say
  479. %% "/some/original/path/site/src/pages/somepage.erl", and then breaks down the
  480. %% path one by one prefixing it with the current working directory until it
  481. %% either finds a match, or fails. If it succeeds, it returns the Path to the
  482. %% new Source file.
  483. fixDescendantSource([], _IsFile) ->
  484. undefined;
  485. fixDescendantSource(Path, IsFile) ->
  486. {ok, Cwd} = file:get_cwd(),
  487. PathParts = filename:split(Path),
  488. case makeDescendantSource(PathParts, Cwd) of
  489. undefined -> case IsFile of true -> Path; _ -> undefined end;
  490. FoundPath -> FoundPath
  491. end.
  492. makeDescendantSource([], _Cwd) ->
  493. undefined;
  494. makeDescendantSource([_ | T], Cwd) ->
  495. PathAttempt = filename:join([Cwd | T]),
  496. case filelib:is_regular(PathAttempt) of
  497. true -> PathAttempt;
  498. false -> makeDescendantSource(T, Cwd)
  499. end.
  500. isDescendent(Path) ->
  501. {ok, Cwd} = file:get_cwd(),
  502. lists:sublist(Path, length(Cwd)) == Cwd.
  503. %% @private Find the src directory for the specified Directory; max 15 iterations
  504. getSrcDir(Dir) ->
  505. getSrcDir(Dir, 15).
  506. getSrcDir(_Dir, 0) ->
  507. undefined;
  508. getSrcDir(Dir, Ctr) ->
  509. HasCode = filelib:wildcard("*.{erl,hrl,ex,dtl,lfe}", Dir) /= [],
  510. if
  511. HasCode -> {ok, Dir};
  512. true -> getSrcDir(filename:dirname(Dir), Ctr - 1)
  513. end.
  514. mergeExtraDirs(IsAddPath) ->
  515. case ?esCfgSync:getv(?extraDirs) of
  516. undefined ->
  517. {[], [], [], []};
  518. ExtraList ->
  519. FunMerge =
  520. fun(OneExtra, {AddExtraDirs, AddOnlyDirs, OnlyDirs, DelDirs} = AllAcc) ->
  521. case OneExtra of
  522. {addExtra, DirsAndOpts} ->
  523. Adds =
  524. [
  525. begin
  526. case IsAddPath of
  527. true ->
  528. case proplists:get_value(outdir, Opts) of
  529. undefined ->
  530. true;
  531. Path ->
  532. ok = filelib:ensure_dir(Path),
  533. true = code:add_pathz(Path)
  534. end;
  535. _ ->
  536. ignore
  537. end,
  538. filename:absname(Dir)
  539. end || {Dir, Opts} <- DirsAndOpts
  540. ],
  541. setelement(1, AllAcc, Adds ++ AddExtraDirs);
  542. {addOnly, DirsAndOpts} ->
  543. Adds =
  544. [
  545. begin
  546. case IsAddPath of
  547. true ->
  548. case proplists:get_value(outdir, Opts) of
  549. undefined ->
  550. true;
  551. Path ->
  552. ok = filelib:ensure_dir(Path),
  553. true = code:add_pathz(Path)
  554. end;
  555. _ ->
  556. ignore
  557. end,
  558. filename:absname(Dir)
  559. end || {Dir, Opts} <- DirsAndOpts
  560. ],
  561. setelement(2, AllAcc, Adds ++ AddOnlyDirs);
  562. {only, DirsAndOpts} ->
  563. Onlys =
  564. [
  565. begin
  566. case IsAddPath of
  567. true ->
  568. case proplists:get_value(outdir, Opts) of
  569. undefined ->
  570. true;
  571. Path ->
  572. ok = filelib:ensure_dir(Path),
  573. true = code:add_pathz(Path)
  574. end;
  575. _ ->
  576. ignore
  577. end,
  578. filename:absname(Dir)
  579. end || {Dir, Opts} <- DirsAndOpts
  580. ],
  581. setelement(3, AllAcc, Onlys ++ OnlyDirs);
  582. {del, DirsAndOpts} ->
  583. Dels =
  584. [
  585. begin
  586. filename:absname(Dir)
  587. end || {Dir, _Opts} <- DirsAndOpts
  588. ],
  589. setelement(4, AllAcc, Dels ++ DelDirs)
  590. end
  591. end,
  592. lists:foldl(FunMerge, {[], [], [], []}, ExtraList)
  593. end.
  594. toBinary(Value) when is_list(Value) -> list_to_binary(Value);
  595. toBinary(Value) when is_binary(Value) -> Value.
  596. regExp() ->
  597. % <<".*\\.(erl|hrl|beam|config|dtl|lfe|ex)$">>
  598. <<_Del:8, RegExpStr/binary>> = << <<"|", (toBinary(Tail))/binary>> || [_Dot | Tail] <- ?esCfgSync:getv(?monitorExt)>>,
  599. <<".*\\.(", RegExpStr/binary, ")$">>.
  600. -define(RegExp, regExp()).
  601. collSrcFiles(IsAddPath) ->
  602. {AddExtraSrcDirs, AddOnlySrcDirs, OnlySrcDirs, DelSrcDirs} = mergeExtraDirs(IsAddPath),
  603. CollFiles = filelib:fold_files(filename:absname(toBinary(?esCfgSync:getv(?baseDir))), ?RegExp, true,
  604. fun(OneFile, {Srcs, Hrls, Configs, Beams} = Acc) ->
  605. case isOnlyDir(OnlySrcDirs, OneFile) andalso (not isDelDir(DelSrcDirs, OneFile)) of
  606. true ->
  607. MTimeSec = case file:read_file_info(OneFile, [raw]) of
  608. {ok, FileInfo} ->
  609. dateTimeToSec(FileInfo#file_info.mtime);
  610. _ ->
  611. 0
  612. end,
  613. %MTimeSec = dateTimeToSec(filelib:last_modified(OneFile)),
  614. case filename:extension(OneFile) of
  615. <<".beam">> ->
  616. BeamMod = binary_to_atom(filename:basename(OneFile, <<".beam">>)),
  617. setelement(4, Acc, Beams#{BeamMod => MTimeSec});
  618. <<".config">> ->
  619. setelement(3, Acc, Configs#{OneFile => MTimeSec});
  620. <<".hrl">> ->
  621. setelement(2, Acc, Hrls#{OneFile => MTimeSec});
  622. <<>> ->
  623. Acc;
  624. _ ->
  625. RootSrcDir =
  626. case getRootSrcDirFromSrcDir(OneFile) of
  627. undefined ->
  628. filename:dirname(OneFile);
  629. RetSrcDir ->
  630. RetSrcDir
  631. end,
  632. case getOptions(RootSrcDir) of
  633. undefined ->
  634. Mod = binary_to_atom(filename:basename(OneFile, filename:extension(OneFile))),
  635. case getModOpts(Mod) of
  636. {ok, Options} ->
  637. setOptions(RootSrcDir, Options);
  638. _ ->
  639. ignore
  640. end;
  641. _ ->
  642. ignore
  643. end,
  644. setelement(1, Acc, Srcs#{OneFile => MTimeSec})
  645. end;
  646. _ ->
  647. Acc
  648. end
  649. end, {#{}, #{}, #{}, #{}}),
  650. FunCollAddExtra =
  651. fun(OneDir, FilesAcc) ->
  652. filelib:fold_files(?CASE(is_list(OneDir), list_to_binary(OneDir), OneDir), ?RegExp, true,
  653. fun(OneFile, {Srcs, Hrls, Configs, Beams} = Acc) ->
  654. MTimeSec = dateTimeToSec(filelib:last_modified(OneFile)),
  655. case filename:extension(OneFile) of
  656. <<".beam">> ->
  657. BeamMod = binary_to_atom(filename:basename(OneFile, <<".beam">>)),
  658. setelement(4, Acc, Beams#{BeamMod => MTimeSec});
  659. <<".config">> ->
  660. setelement(3, Acc, Configs#{OneFile => MTimeSec});
  661. <<".hrl">> ->
  662. setelement(2, Acc, Hrls#{OneFile => MTimeSec});
  663. <<>> ->
  664. Acc;
  665. _ ->
  666. setelement(1, Acc, Srcs#{OneFile => MTimeSec})
  667. end
  668. end, FilesAcc)
  669. end,
  670. AddExtraCollFiles = lists:foldl(FunCollAddExtra, CollFiles, AddExtraSrcDirs),
  671. FunCollAddOnly =
  672. fun(OneDir, FilesAcc) ->
  673. filelib:fold_files(?CASE(is_list(OneDir), list_to_binary(OneDir), OneDir), ?RegExp, false,
  674. fun(OneFile, {Srcs, Hrls, Configs, Beams} = Acc) ->
  675. MTimeSec = dateTimeToSec(filelib:last_modified(OneFile)),
  676. case filename:extension(OneFile) of
  677. <<".beam">> ->
  678. BeamMod = binary_to_atom(filename:basename(OneFile, <<".beam">>)),
  679. setelement(4, Acc, Beams#{BeamMod => MTimeSec});
  680. <<".config">> ->
  681. setelement(3, Acc, Configs#{OneFile => MTimeSec});
  682. <<".hrl">> ->
  683. setelement(2, Acc, Hrls#{OneFile => MTimeSec});
  684. <<>> ->
  685. Acc;
  686. _ ->
  687. setelement(1, Acc, Srcs#{OneFile => MTimeSec})
  688. end
  689. end, FilesAcc)
  690. end,
  691. lists:foldl(FunCollAddOnly, AddExtraCollFiles, AddOnlySrcDirs).
  692. isOnlyDir([], _) ->
  693. true;
  694. isOnlyDir(ReplaceDirs, SrcDir) ->
  695. isMatchDir(ReplaceDirs, SrcDir).
  696. isDelDir([], _) ->
  697. false;
  698. isDelDir(ReplaceDirs, SrcDir) ->
  699. isMatchDir(ReplaceDirs, SrcDir).
  700. isMatchDir([], _SrcDir) ->
  701. false;
  702. isMatchDir([SrcDir | _ReplaceDirs], SrcDir) ->
  703. true;
  704. isMatchDir([OneDir | ReplaceDirs], SrcDir) ->
  705. case re:run(SrcDir, OneDir) of
  706. nomatch -> isMatchDir(ReplaceDirs, SrcDir);
  707. _ -> true
  708. end.
  709. getEnv(Var, Default) ->
  710. case application:get_env(eSync, Var) of
  711. {ok, Value} ->
  712. Value;
  713. _ ->
  714. Default
  715. end.
  716. setEnv(Var, Val) ->
  717. ok = application:set_env(eSync, Var, Val).
  718. canLog(MsgType) ->
  719. case eSync:getLog() of
  720. true -> true;
  721. all -> true;
  722. none -> false;
  723. false -> false;
  724. skip_success -> MsgType == errors orelse MsgType == warnings;
  725. L when is_list(L) -> lists:member(MsgType, L);
  726. _ -> false
  727. end.
  728. %% 注意 map类型的数据不能当做key
  729. -type key() :: atom() | binary() | bitstring() | float() | integer() | list() | tuple().
  730. -type value() :: atom() | binary() | bitstring() | float() | integer() | list() | tuple() | map().
  731. -spec load(term(), [{key(), value()}]) -> ok.
  732. load(Module, KVs) ->
  733. Forms = forms(Module, KVs),
  734. {ok, Module, Bin} = compile:forms(Forms),
  735. code:soft_purge(Module),
  736. {module, Module} = code:load_binary(Module, atom_to_list(Module), Bin),
  737. ok.
  738. forms(Module, KVs) ->
  739. %% -module(Module).
  740. Mod = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
  741. %% -export([getv/0]).
  742. ExportList = [erl_syntax:arity_qualifier(erl_syntax:atom(getv), erl_syntax:integer(1))],
  743. Export = erl_syntax:attribute(erl_syntax:atom(export), [erl_syntax:list(ExportList)]),
  744. %% getv(K) -> V
  745. Function = erl_syntax:function(erl_syntax:atom(getv), lookup_clauses(KVs, [])),
  746. [erl_syntax:revert(X) || X <- [Mod, Export, Function]].
  747. lookup_clause(Key, Value) ->
  748. Var = erl_syntax:abstract(Key),
  749. Body = erl_syntax:abstract(Value),
  750. erl_syntax:clause([Var], [], [Body]).
  751. lookup_clause_anon() ->
  752. Var = erl_syntax:variable("_"),
  753. Body = erl_syntax:atom(undefined),
  754. erl_syntax:clause([Var], [], [Body]).
  755. lookup_clauses([], Acc) ->
  756. lists:reverse(lists:flatten([lookup_clause_anon() | Acc]));
  757. lookup_clauses([{Key, Value} | T], Acc) ->
  758. lookup_clauses(T, [lookup_clause(Key, Value) | Acc]).
  759. getOptions(SrcDir) ->
  760. case erlang:get(SrcDir) of
  761. undefined ->
  762. undefined;
  763. Options ->
  764. {ok, Options}
  765. end.
  766. setOptions(SrcDir, Options) ->
  767. case erlang:get(SrcDir) of
  768. undefined ->
  769. erlang:put(SrcDir, Options);
  770. OldOptions ->
  771. NewOptions =
  772. case lists:keytake(compile_info, 1, Options) of
  773. {value, {compile_info, ValList1}, Options1} ->
  774. case lists:keytake(compile_info, 1, OldOptions) of
  775. {value, {compile_info, ValList2}, Options2} ->
  776. [{compile_info, lists:usort(ValList1 ++ ValList2)} | lists:usort(Options1 ++ Options2)];
  777. _ ->
  778. lists:usort(Options ++ OldOptions)
  779. end;
  780. _ ->
  781. lists:usort(Options ++ OldOptions)
  782. end,
  783. erlang:put(SrcDir, NewOptions)
  784. end.
  785. loadCfg() ->
  786. KVs = [{Key, getEnv(Key, DefVal)} || {Key, DefVal} <- ?DefCfgList],
  787. load(?esCfgSync, KVs).
  788. %% ******************************* 加载与编译相关 **********************************************************************
  789. printResults(_Module, SrcFile, [], []) ->
  790. ?logSuccess("~s Recompiled", [SrcFile]);
  791. printResults(_Module, SrcFile, [], Warnings) ->
  792. formatErrors(logWarnings, SrcFile, [], Warnings);
  793. printResults(_Module, SrcFile, Errors, Warnings) ->
  794. formatErrors(logErrors, SrcFile, Errors, Warnings).
  795. %% @private Print error messages in a pretty and user readable way.
  796. formatErrors(LogFun, File, Errors, Warnings) ->
  797. AllErrors1 = lists:sort(lists:flatten([X || {_, X} <- Errors])),
  798. AllErrors2 = [{Line, "Error", Module, Description} || {Line, Module, Description} <- AllErrors1],
  799. AllWarnings1 = lists:sort(lists:flatten([X || {_, X} <- Warnings])),
  800. AllWarnings2 = [{Line, "Warning", Module, Description} || {Line, Module, Description} <- AllWarnings1],
  801. Everything = lists:sort(AllErrors2 ++ AllWarnings2),
  802. FPck =
  803. fun({Line, Prefix, Module, ErrorDescription}) ->
  804. Msg = formatError(Module, ErrorDescription),
  805. case LogFun of
  806. logWarnings ->
  807. ?logWarnings("~s: ~p: ~s: ~s", [File, Line, Prefix, Msg]);
  808. logErrors ->
  809. ?logErrors("~s: ~p: ~s: ~s", [File, Line, Prefix, Msg])
  810. end
  811. end,
  812. [FPck(X) || X <- Everything],
  813. ok.
  814. formatError(Module, ErrorDescription) ->
  815. case erlang:function_exported(Module, format_error, 1) of
  816. true -> Module:format_error(ErrorDescription);
  817. false -> io_lib:format("~s", [ErrorDescription])
  818. end.
  819. fireOnSync(OnSyncFun, Modules) ->
  820. case OnSyncFun of
  821. undefined -> ok;
  822. Funs when is_list(Funs) -> onSyncApplyList(Funs, Modules);
  823. Fun -> onSyncApply(Fun, Modules)
  824. end.
  825. onSyncApplyList(Funs, Modules) ->
  826. [onSyncApply(Fun, Modules) || Fun <- Funs].
  827. onSyncApply({M, F}, Modules) ->
  828. try erlang:apply(M, F, [Modules])
  829. catch
  830. C:R:S ->
  831. ?logErrors("apply sync fun ~p:~p(~p) error ~p", [M, F, Modules, {C, R, S}])
  832. end;
  833. onSyncApply(Fun, Modules) when is_function(Fun) ->
  834. try Fun(Modules)
  835. catch
  836. C:R:S ->
  837. ?logErrors("apply sync fun ~p(~p) error ~p", [Fun, Modules, {C, R, S}])
  838. end.
  839. reloadChangedMod([], _SwSyncNode, OnSyncFun, Acc) ->
  840. fireOnSync(OnSyncFun, Acc);
  841. reloadChangedMod([Module | LeftMod], SwSyncNode, OnSyncFun, Acc) ->
  842. case Module == es_gen_ipc orelse code:get_object_code(Module) of
  843. true ->
  844. ignore;
  845. error ->
  846. ?logErrors("Error loading object code for ~p", [Module]),
  847. reloadChangedMod(LeftMod, SwSyncNode, OnSyncFun, Acc);
  848. {Module, Binary, Filename} ->
  849. case code:load_binary(Module, Filename, Binary) of
  850. {module, Module} ->
  851. ?logSuccess("Reloaded(Beam changed) Mod: ~s Success", [Module]),
  852. syncLoadModOnAllNodes(SwSyncNode, Module, Binary, changed);
  853. {error, What} ->
  854. ?logErrors("Reloaded(Beam changed) Mod: ~s Errors Reason:~p", [Module, What])
  855. end,
  856. reloadChangedMod(LeftMod, SwSyncNode, OnSyncFun, [Module | Acc])
  857. end.
  858. getNodes() ->
  859. lists:usort(lists:flatten(nodes() ++ [erpc:call(X, erlang, nodes, []) || X <- nodes()])) -- [node()].
  860. syncLoadModOnAllNodes(false, _Module, _Binary, _Reason) ->
  861. ignore;
  862. syncLoadModOnAllNodes(true, Module, Binary, Reason) ->
  863. %% Get a list of nodes known by this node, plus all attached nodes.
  864. Nodes = getNodes(),
  865. NumNodes = length(Nodes),
  866. [
  867. begin
  868. ?logSuccess("Do Reloading '~s' on ~p", [Module, Node]),
  869. erpc:call(Node, code, ensure_loaded, [Module]),
  870. case erpc:call(Node, code, which, [Module]) of
  871. Filename when is_binary(Filename) orelse is_list(Filename) ->
  872. %% File exists, overwrite and load into VM.
  873. ok = erpc:call(Node, file, write_file, [Filename, Binary]),
  874. erpc:call(Node, code, purge, [Module]),
  875. case erpc:call(Node, code, load_file, [Module]) of
  876. {module, Module} ->
  877. ?logSuccess("Reloaded(Beam ~p) Mod:~s and write Success on node:~p", [Reason, Module, Node]);
  878. {error, What} ->
  879. ?logErrors("Reloaded(Beam ~p) Mod:~s and write Errors on node:~p Reason:~p", [Module, Node, What])
  880. end;
  881. _ ->
  882. %% File doesn't exist, just load into VM.
  883. case erpc:call(Node, code, load_binary, [Module, undefined, Binary]) of
  884. {module, Module} ->
  885. ?logSuccess("Reloaded(Beam ~p) Mod:~s Success on node:~p", [Reason, Module, Node]);
  886. {error, What} ->
  887. ?logErrors("Reloaded(Beam ~p) Mod:~s Errors on node:~p Reason:~p", [Reason, Module, Node, What])
  888. end
  889. end
  890. end || Node <- Nodes
  891. ],
  892. ?logSuccess("Reloaded(Beam changed) Mod: ~s on ~p nodes:~p", [Module, NumNodes, Nodes]).
  893. recompileChangeSrcFile(Iterator, SwSyncNode) ->
  894. case maps:next(Iterator) of
  895. {File, _V, NextIterator} ->
  896. recompileSrcFile(File, SwSyncNode),
  897. recompileChangeSrcFile(NextIterator, SwSyncNode);
  898. _ ->
  899. ok
  900. end.
  901. erlydtlCompile(SrcFile, Options) ->
  902. F =
  903. fun({outdir, OutDir}, Acc) -> [{out_dir, OutDir} | Acc];
  904. (OtherOption, Acc) -> [OtherOption | Acc]
  905. end,
  906. DtlOptions = lists:foldl(F, [], Options),
  907. Module = binary_to_atom(lists:flatten(filename:basename(SrcFile, ".dtl") ++ "_dtl")),
  908. Compiler = erlydtl,
  909. Compiler:compile(SrcFile, Module, DtlOptions).
  910. elixir_compile(SrcFile, Options) ->
  911. Outdir = proplists:get_value(outdir, Options),
  912. Compiler = ':Elixir.Kernel.ParallelCompiler',
  913. Modules = Compiler:files_to_path([SrcFile], Outdir),
  914. Loader =
  915. fun(Module) ->
  916. Outfile = code:which(Module),
  917. Binary = file:read_file(Outfile),
  918. {Module, Binary}
  919. end,
  920. Results = lists:map(Loader, Modules),
  921. {ok, multiple, Results, []}.
  922. lfe_compile(SrcFile, Options) ->
  923. Compiler = lfe_comp,
  924. Compiler:file(SrcFile, Options).
  925. getCompileFunAndModuleName(SrcFile) ->
  926. case getFileType(SrcFile) of
  927. erl ->
  928. {fun compile:file/2, binary_to_atom(filename:basename(SrcFile, <<".erl">>))};
  929. dtl ->
  930. {fun erlydtlCompile/2, list_to_atom(lists:flatten(binary_to_list(filename:basename(SrcFile, <<".dtl">>)) ++ "_dtl"))};
  931. lfe ->
  932. {fun lfe_compile/2, binary_to_atom(filename:basename(SrcFile, <<".lfe">>))};
  933. elixir ->
  934. {fun elixir_compile/2, binary_to_atom(filename:basename(SrcFile, <<".ex">>))}
  935. end.
  936. getObjectCode(Module) ->
  937. case code:get_object_code(Module) of
  938. {Module, B, Filename} -> {B, Filename};
  939. _ -> {undefined, undefined}
  940. end.
  941. reloadIfNecessary(Module, OldBinary, Binary, Filename, SwSyncNode) ->
  942. case Binary =/= OldBinary of
  943. true ->
  944. %% Try to load the module...
  945. case code:ensure_loaded(Module) of
  946. {module, Module} ->
  947. case code:load_binary(Module, Filename, Binary) of
  948. {module, Module} ->
  949. ?logSuccess("Reloaded(Beam recompiled) Mod:~s Success", [Module]),
  950. syncLoadModOnAllNodes(SwSyncNode, Module, Binary, recompiled);
  951. {error, What} ->
  952. ?logErrors("Reloaded(Beam recompiled) Mod:~s Errors Reason:~p", [Module, What])
  953. end;
  954. {error, nofile} ->
  955. case code:load_binary(Module, Filename, Binary) of
  956. {module, Module} ->
  957. ?logSuccess("Reloaded(Beam recompiled) Mod:~s Success", [Module]),
  958. syncLoadModOnAllNodes(SwSyncNode, Module, Binary, recompiled);
  959. {error, What} ->
  960. ?logErrors("Reloaded(Beam recompiled) Mod:~s Errors Reason:~p", [Module, What])
  961. end;
  962. {error, embedded} ->
  963. case code:load_file(Module) of %% Module is not yet loaded, load it.
  964. {module, Module} -> ok;
  965. {error, nofile} ->
  966. case code:load_binary(Module, Filename, Binary) of
  967. {module, Module} ->
  968. ?logSuccess("Reloaded(Beam recompiled) Mod:~s Success", [Module]),
  969. syncLoadModOnAllNodes(SwSyncNode, Module, Binary, recompiled);
  970. {error, What} ->
  971. ?logErrors("Reloaded(Beam recompiled) Mod:~s Errors Reason:~p", [Module, What])
  972. end
  973. end
  974. end;
  975. _ ->
  976. ignore
  977. end.
  978. recompileSrcFile(SrcFile, SwSyncNode) ->
  979. %% Get the module, src dir, and options...
  980. RootSrcDir =
  981. case getRootSrcDirFromSrcDir(SrcFile) of
  982. undefined ->
  983. filename:dirname(SrcFile);
  984. RetSrcDir ->
  985. RetSrcDir
  986. end,
  987. CurSrcDir = filename:dirname(SrcFile),
  988. {CompileFun, Module} = getCompileFunAndModuleName(SrcFile),
  989. {OldBinary, Filename} = getObjectCode(Module),
  990. case Module == es_gen_ipc orelse getOptions(RootSrcDir) of
  991. true ->
  992. ignore;
  993. {ok, Options} ->
  994. RightFileDir = binary_to_list(filename:join(CurSrcDir, filename:basename(SrcFile))),
  995. LastOptions = ?CASE(?esCfgSync:getv(?isJustMem), [binary, return | Options], [return | Options]),
  996. case CompileFun(RightFileDir, LastOptions) of
  997. {ok, Module, Binary, Warnings} ->
  998. printResults(Module, RightFileDir, [], Warnings),
  999. reloadIfNecessary(Module, OldBinary, Binary, Filename, SwSyncNode),
  1000. {ok, [], Warnings};
  1001. {ok, [{ok, Module, Binary, Warnings}], Warnings2} ->
  1002. printResults(Module, RightFileDir, [], Warnings ++ Warnings2),
  1003. reloadIfNecessary(Module, OldBinary, Binary, Filename, SwSyncNode),
  1004. {ok, [], Warnings ++ Warnings2};
  1005. {ok, multiple, Results, Warnings} ->
  1006. printResults(Module, RightFileDir, [], Warnings),
  1007. [reloadIfNecessary(CompiledModule, OldBinary, Binary, Filename, SwSyncNode) || {CompiledModule, Binary} <- Results],
  1008. {ok, [], Warnings};
  1009. {ok, OtherModule, _Binary, Warnings} ->
  1010. Desc = io_lib:format("Module definition (~p) differs from expected (~s)", [OtherModule, filename:rootname(filename:basename(RightFileDir))]),
  1011. Errors = [{RightFileDir, {0, Module, Desc}}],
  1012. printResults(Module, RightFileDir, Errors, Warnings),
  1013. {ok, Errors, Warnings};
  1014. {error, Errors, Warnings} ->
  1015. printResults(Module, RightFileDir, Errors, Warnings),
  1016. {ok, Errors, Warnings};
  1017. {ok, Module, Warnings} ->
  1018. printResults(Module, RightFileDir, [], Warnings),
  1019. {ok, [], Warnings};
  1020. _Err ->
  1021. ?logErrors("compile Mod:~s Errors Reason:~p", [Module, _Err])
  1022. end;
  1023. undefined ->
  1024. case tryGetModOpts(Module) of
  1025. {ok, Options} ->
  1026. setOptions(RootSrcDir, Options),
  1027. recompileSrcFile(SrcFile, SwSyncNode);
  1028. _ ->
  1029. case tryGetSrcOpts(CurSrcDir) of
  1030. {ok, Options} ->
  1031. setOptions(RootSrcDir, Options),
  1032. recompileSrcFile(SrcFile, SwSyncNode);
  1033. _ ->
  1034. ?logErrors("Unable to determine options for ~s", [SrcFile])
  1035. end
  1036. end
  1037. end.
  1038. collIncludeCHrls([], AllHrls, CHrls, NewAddMap) ->
  1039. case maps:size(NewAddMap) > 0 of
  1040. true ->
  1041. collIncludeCHrls(maps:keys(NewAddMap), AllHrls, CHrls, #{});
  1042. _ ->
  1043. CHrls
  1044. end;
  1045. collIncludeCHrls([OneHrl | LeftCHrls], AllHrls, CHrls, NewAddMap) ->
  1046. {NewCHrls, NNewAddMap} = whoInclude(OneHrl, AllHrls, CHrls, NewAddMap),
  1047. collIncludeCHrls(LeftCHrls, AllHrls, NewCHrls, NNewAddMap).
  1048. collIncludeCErls([], _SrcFiles, CSrcs, _NewAddMap) ->
  1049. CSrcs;
  1050. collIncludeCErls([Hrl | LeftHrl], SrcFiles, CSrcs, NewAddMap) ->
  1051. {NewCSrcs, NNewAddMap} = whoInclude(Hrl, SrcFiles, CSrcs, NewAddMap),
  1052. collIncludeCErls(LeftHrl, SrcFiles, NewCSrcs, NNewAddMap).
  1053. whoInclude(HrlFile, AllFiles, CFiles, NewAddMap) ->
  1054. HrlFileBaseName = filename:basename(HrlFile),
  1055. doMathEveryFile(maps:iterator(AllFiles), HrlFileBaseName, CFiles, NewAddMap).
  1056. doMathEveryFile(Iterator, HrlFileBaseName, CFiles, NewAddMap) ->
  1057. case maps:next(Iterator) of
  1058. {OneFile, _V, NextIterator} ->
  1059. case file:open(OneFile, [read, binary]) of
  1060. {ok, IoDevice} ->
  1061. IsInclude = doMathEveryLine(IoDevice, HrlFileBaseName),
  1062. file:close(IoDevice),
  1063. case IsInclude of
  1064. true ->
  1065. case maps:is_key(OneFile, CFiles) of
  1066. true ->
  1067. doMathEveryFile(NextIterator, HrlFileBaseName, CFiles, NewAddMap);
  1068. _ ->
  1069. doMathEveryFile(NextIterator, HrlFileBaseName, CFiles#{OneFile => 1}, NewAddMap#{OneFile => 1})
  1070. end;
  1071. _ ->
  1072. doMathEveryFile(NextIterator, HrlFileBaseName, CFiles, NewAddMap)
  1073. end;
  1074. _ ->
  1075. doMathEveryFile(NextIterator, HrlFileBaseName, CFiles, NewAddMap)
  1076. end;
  1077. _ ->
  1078. {CFiles, NewAddMap}
  1079. end.
  1080. %% 注释
  1081. %% whoInclude(HrlFile, SrcFiles) ->
  1082. %% HrlFileBaseName = filename:basename(HrlFile),
  1083. %% Pred =
  1084. %% fun(SrcFile, _) ->
  1085. %% {ok, Forms} = epp_dodger:parse_file(SrcFile),
  1086. %% isInclude(binary_to_list(HrlFileBaseName), Forms)
  1087. %% end,
  1088. %% maps:filter(Pred, SrcFiles).
  1089. %% isInclude(_HrlFile, []) ->
  1090. %% false;
  1091. %% isInclude(HrlFile, [{tree, attribute, _, {attribute, _, [{_, _, IncludeFile}]}} | Forms]) when is_list(IncludeFile) ->
  1092. %% IncludeFileBaseName = filename:basename(IncludeFile),
  1093. %% case IncludeFileBaseName of
  1094. %% HrlFile -> true;
  1095. %% _ -> isInclude(HrlFile, Forms)
  1096. %% end;
  1097. %% isInclude(HrlFile, [_SomeForm | Forms]) ->
  1098. %% isInclude(HrlFile, Forms).
  1099. doMathEveryLine(IoDevice, HrlFileBaseName) ->
  1100. case file:read_line(IoDevice) of
  1101. {ok, Data} ->
  1102. case re:run(Data, HrlFileBaseName) of
  1103. nomatch ->
  1104. case re:run(Data, <<"->">>) of
  1105. nomatch ->
  1106. doMathEveryLine(IoDevice, HrlFileBaseName);
  1107. _ ->
  1108. false
  1109. end;
  1110. {match, [{Start, _Len} | _]} ->
  1111. case binary:at(Data, max(Start - 1, 0)) of
  1112. 47 -> %% /
  1113. true;
  1114. 34 -> %% "
  1115. true;
  1116. _ ->
  1117. false
  1118. end
  1119. end;
  1120. _ ->
  1121. false
  1122. end.
  1123. classifyChangeFile([], Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams) ->
  1124. {Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams};
  1125. classifyChangeFile([OneFile | LeftFile], Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams) ->
  1126. CurMTimeSec = dateTimeToSec(filelib:last_modified(OneFile)),
  1127. case filename:extension(OneFile) of
  1128. <<".beam">> ->
  1129. BinMod = binary_to_atom(filename:basename(OneFile, <<".beam">>)),
  1130. case ColBeams of
  1131. #{BinMod := OldMTimeSec} ->
  1132. case CurMTimeSec =/= OldMTimeSec andalso CurMTimeSec =/= 0 of
  1133. true ->
  1134. classifyChangeFile(LeftFile, [BinMod | Beams], Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams#{BinMod := CurMTimeSec});
  1135. _ ->
  1136. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams)
  1137. end;
  1138. _ ->
  1139. classifyChangeFile(LeftFile, [BinMod | Beams], Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams#{BinMod => CurMTimeSec})
  1140. end;
  1141. <<".config">> ->
  1142. AbsFile = filename:absname(OneFile),
  1143. case ColConfigs of
  1144. #{AbsFile := OldMTimeSec} ->
  1145. case CurMTimeSec =/= OldMTimeSec andalso CurMTimeSec =/= 0 of
  1146. true ->
  1147. CfgMod = erlang:binary_to_atom(filename:basename(AbsFile, <<".config">>), utf8),
  1148. classifyChangeFile(LeftFile, Beams, [CfgMod | Configs], Hrls, Srcs, ColSrcs, ColHrls, ColConfigs#{AbsFile := CurMTimeSec}, ColBeams);
  1149. _ ->
  1150. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams)
  1151. end;
  1152. _ ->
  1153. CfgMod = erlang:binary_to_atom(filename:basename(AbsFile, <<".config">>), utf8),
  1154. classifyChangeFile(LeftFile, Beams, [CfgMod | Configs], Hrls, Srcs, ColSrcs, ColHrls, ColConfigs#{AbsFile => CurMTimeSec}, ColBeams)
  1155. end;
  1156. <<".hrl">> ->
  1157. AbsFile = filename:absname(OneFile),
  1158. case ColHrls of
  1159. #{AbsFile := OldMTimeSec} ->
  1160. case CurMTimeSec =/= OldMTimeSec andalso CurMTimeSec =/= 0 of
  1161. true ->
  1162. classifyChangeFile(LeftFile, Beams, Configs, Hrls#{AbsFile => 1}, Srcs, ColSrcs, ColHrls#{AbsFile := CurMTimeSec}, ColConfigs, ColBeams);
  1163. _ ->
  1164. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams)
  1165. end;
  1166. _ ->
  1167. classifyChangeFile(LeftFile, Beams, Configs, Hrls#{AbsFile => 1}, Srcs, ColSrcs, ColHrls#{AbsFile => CurMTimeSec}, ColConfigs, ColBeams)
  1168. end;
  1169. <<>> ->
  1170. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams);
  1171. _ ->
  1172. AbsFile = filename:absname(OneFile),
  1173. case ColSrcs of
  1174. #{AbsFile := OldMTimeSec} ->
  1175. case CurMTimeSec =/= OldMTimeSec andalso CurMTimeSec =/= 0 of
  1176. true ->
  1177. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs#{AbsFile => 1}, ColSrcs#{AbsFile := CurMTimeSec}, ColHrls, ColConfigs, ColBeams);
  1178. _ ->
  1179. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs, ColSrcs, ColHrls, ColConfigs, ColBeams)
  1180. end;
  1181. _ ->
  1182. classifyChangeFile(LeftFile, Beams, Configs, Hrls, Srcs#{AbsFile => 1}, ColSrcs#{AbsFile => CurMTimeSec}, ColHrls, ColConfigs, ColBeams)
  1183. end
  1184. end.
  1185. fileSyncPath(ExecName) ->
  1186. case code:priv_dir(?MODULE) of
  1187. {error, _} ->
  1188. case code:which(?MODULE) of
  1189. Filename when is_list(Filename) ->
  1190. filename:join([filename:dirname(filename:dirname(Filename)), "priv", ExecName]);
  1191. _ ->
  1192. filename:join("../priv", ExecName)
  1193. end;
  1194. Dir ->
  1195. filename:join(Dir, ExecName)
  1196. end.
  1197. dateTimeToSec(DateTime) ->
  1198. if
  1199. DateTime == 0 ->
  1200. 0;
  1201. true ->
  1202. erlang:universaltime_to_posixtime(DateTime)
  1203. end.
  1204. debugInfoKeyFun() ->
  1205. case ?esCfgSync:getv(?debugInfoKeyFun) of
  1206. undefined ->
  1207. {debug_info_key, undefined};
  1208. {Mod, Fun} ->
  1209. Mod:Fun()
  1210. end.
  1211. %% ************************************************* utils end *******************************************************