|
|
- -module(esScanner).
- -include("erlSync.hrl").
-
- -behaviour(gen_ipc).
-
- -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
- ]).
-
- %% gen_ipc callbacks
- -export([
- init/1,
- handleCall/4,
- handleCast/3,
- handleInfo/3,
- handleOnevent/4,
- terminate/3
- ]).
-
- -define(SERVER, ?MODULE).
-
- -type timestamp() :: file:date_time() | 0.
- -record(state, {
- modules = [] :: [module()]
- , hrlDirs = [] :: [file:filename()]
- , srcDirs = [] :: [file:filename()]
- , hrlFiles = [] :: [file:filename()]
- , srcFiles = [] :: [file:filename()]
- , beamTimes = undefined :: [{module(), timestamp()}] | undefined
- , hrlFileTimes = undefined :: [{file:filename(), timestamp()}] | undefined
- , srcFileTimes = undefined :: [{file:filename(), timestamp()}] | undefined
- , onsyncFun = undefined
- , swSyncNode = false
- }).
-
- %% ************************************ API start ***************************
- rescan() ->
- gen_ipc:cast(?SERVER, miCollMods),
- gen_ipc:cast(?SERVER, miCollSrcDirs),
- gen_ipc:cast(?SERVER, miCollSrcFiles),
- gen_ipc:cast(?SERVER, miCompareHrlFiles),
- gen_ipc:cast(?SERVER, miCompareSrcFiles),
- gen_ipc:cast(?SERVER, miCompareBeams),
- esUtils:logSuccess("start Scanning source files..."),
- ok.
-
- unpause() ->
- gen_ipc:cast(?SERVER, miUnpause),
- ok.
-
- pause() ->
- gen_ipc:cast(?SERVER, miPause),
- esUtils:logSuccess("Pausing erlSync. Call erlSync:run() to restart"),
- ok.
-
- curInfo() ->
- gen_ipc:call(?SERVER, miCurInfo).
-
- setLog(T) when ?LOG_ON(T) ->
- esUtils:setEnv(log, T),
- loadCfg(),
- esUtils:logSuccess("Console Notifications Enabled"),
- ok;
- setLog(_) ->
- esUtils:setEnv(log, none),
- loadCfg(),
- esUtils:logSuccess("Console Notifications Disabled"),
- ok.
-
- getLog() ->
- ?esCfgSync:getv(log).
-
- swSyncNode(IsSync) ->
- gen_ipc:cast(?SERVER, {miSyncNode, IsSync}),
- ok.
-
- getOnsync() ->
- gen_ipc:call(?SERVER, miGetOnsync).
-
- setOnsync(Fun) ->
- gen_ipc:call(?SERVER, {miSetOnsync, Fun}).
-
- %% ************************************ API end ***************************
-
- start_link() ->
- gen_ipc:start_link({local, ?SERVER}, ?MODULE, [], []).
-
- %% status :: running | pause
- init([]) ->
- erlang:process_flag(trap_exit, true),
- loadCfg(),
- case persistent_term:get(?esRecompileCnt, undefined) of
- undefined ->
- IndexRef = atomics:new(1, [{signed, false}]),
- persistent_term:put(?esRecompileCnt, IndexRef);
- _ ->
- ignore
- end,
- {ok, running, #state{}}.
-
- 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) ->
- keepStatusState.
-
- handleCast(miPause, _, State) ->
- {nextStatus, pause, State};
- handleCast(miUnpause, _, State) ->
- {nextStatus, running, State};
- handleCast(miCollMods, running, State) ->
- AllModules = (erlang:loaded() -- esUtils:getSystemModules()),
- LastCollMods = filterCollMods(AllModules),
- Time = ?esCfgSync:getv(?moduleTime),
- {keepStatus, State#state{modules = LastCollMods}, [?gTimeout(miCollMods, Time)]};
- handleCast(miCollSrcDirs, running, #state{modules = Modules} = State) ->
- {USortedSrcDirs, USortedHrlDirs} =
- case ?esCfgSync:getv(srcDirs) of
- undefined ->
- collSrcDirs(Modules, [], []);
- {add, DirsAndOpts} ->
- collSrcDirs(Modules, addSrcDirs(DirsAndOpts), []);
- {only, DirsAndOpts} ->
- collSrcDirs(Modules, [], addSrcDirs(DirsAndOpts))
- end,
-
- Time = ?esCfgSync:getv(?srcDirTime),
- {keepStatus, State#state{srcDirs = USortedSrcDirs, hrlDirs = USortedHrlDirs}, [?gTimeout(miCollSrcDirs, Time)]};
- handleCast(miCollSrcFiles, running, #state{hrlDirs = HrlDirs, srcDirs = SrcDirs} = State) ->
- FSrc =
- fun(Dir, Acc) ->
- esUtils:wildcard(Dir, ".*\\.(erl|dtl|lfe|ex)$") ++ Acc
- end,
- SrcFiles = lists:usort(lists:foldl(FSrc, [], SrcDirs)),
- FHrl =
- fun(Dir, Acc) ->
- esUtils:wildcard(Dir, ".*\\.hrl$") ++ Acc
- end,
- HrlFiles = lists:usort(lists:foldl(FHrl, [], HrlDirs)),
- Time = ?esCfgSync:getv(?srcFileTime),
- {keepStatus, State#state{srcFiles = SrcFiles, hrlFiles = HrlFiles}, [?gTimeout(miCollSrcFiles, Time)]};
- handleCast(miCompareBeams, running, #state{modules = Modules, beamTimes = BeamTimes, onsyncFun = OnsyncFun, swSyncNode = SwSyncNode} = State) ->
- BeamTimeList = [{Mod, LastMod} || Mod <- Modules, LastMod <- [modLastmod(Mod)], LastMod =/= 0],
- NewBeamLastMod = lists:usort(BeamTimeList),
- reloadChangedMod(BeamTimes, NewBeamLastMod, SwSyncNode, OnsyncFun, []),
- Time = ?esCfgSync:getv(?compareBeamTime),
- {keepStatus, State#state{beamTimes = NewBeamLastMod}, [?gTimeout(miCompareBeams, Time)]};
- handleCast(miCompareSrcFiles, running, #state{srcFiles = SrcFiles, srcFileTimes = SrcFileTimes, swSyncNode = SwSyncNode} = State) ->
- atomics:put(persistent_term:get(?esRecompileCnt), 1, 0),
- %% Create a list of file lastmod times...
- SrcFileTimeList = [{Src, LastMod} || Src <- SrcFiles, LastMod <- [filelib:last_modified(Src)], LastMod =/= 0],
- %% NewSrcFileLastMod = lists:usort(SrcFileTimeList),
- %% Compare to previous results, if there are changes, then recompile the file...
- recompileChangeSrcFile(SrcFileTimes, SrcFileTimeList, SwSyncNode),
- case atomics:get(persistent_term:get(?esRecompileCnt), 1) > 0 of
- true ->
- gen_ipc:cast(?SERVER, miCompareBeams);
- _ ->
- ignore
- end,
- Time = ?esCfgSync:getv(?compareSrcFileTime),
- {keepStatus, State#state{srcFileTimes = SrcFileTimeList}, [?gTimeout(miCompareSrcFiles, Time)]};
- handleCast(miCompareHrlFiles, running, #state{hrlFiles = HrlFiles, srcFiles = SrcFiles, hrlFileTimes = HrlFileTimes, swSyncNode = SwSyncNode} = State) ->
- atomics:put(persistent_term:get(?esRecompileCnt), 1, 0),
- %% Create a list of file lastmod times...
- HrlFileTimeList = [{Hrl, LastMod} || Hrl <- HrlFiles, LastMod <- [filelib:last_modified(Hrl)], LastMod =/= 0],
- %% NewHrlFileLastMod = lists:usort(HrlFileTimeList),
- %% Compare to previous results, if there are changes, then recompile src files that depends
- recompileChangeHrlFile(HrlFileTimes, HrlFileTimeList, SrcFiles, SwSyncNode),
- case atomics:get(persistent_term:get(?esRecompileCnt), 1) > 0 of
- true ->
- gen_ipc:cast(?SERVER, miCompareBeams);
- _ ->
- ignore
- end,
- Time = ?esCfgSync:getv(?compareSrcFileTime),
- {keepStatus, State#state{hrlFileTimes = HrlFileTimeList}, [?gTimeout(miCompareHrlFiles, Time)]};
- handleCast({miSyncNode, IsSync}, _, State) ->
- case IsSync of
- true ->
- {keepStatus, State#state{swSyncNode = true}};
- _ ->
- {keepStatus, State#state{swSyncNode = false}}
- end;
- handleCast(_Msg, _, _State) ->
- keepStatusState.
-
- handleInfo(_Msg, _, _State) ->
- keepStatusState.
-
- handleOnevent({gTimeout, _}, Msg, Status, State) ->
- handleCast(Msg, Status, State);
- handleOnevent(_EventType, _EventContent, _Status, _State) ->
- keepStatusState.
-
- terminate(_Reason, _Status, _State) ->
- ok.
-
- %% ***********************************PRIVATE FUNCTIONS start *******************************************
-
- addSrcDirs(DirsAndOpts) ->
- [
- begin
- %% ensure module out path exists & in our code path list
- case proplists:get_value(outdir, Opts) of
- undefined ->
- true;
- Path ->
- ok = filelib:ensure_dir(Path),
- true = code:add_pathz(Path)
- end,
- setOptions(Dir, Opts),
- Dir
- end || {Dir, Opts} <- DirsAndOpts
- ].
-
- reloadChangedMod([{Module, LastMod} | T1], [{Module, LastMod} | T2], SwSyncNode, OnsyncFun, Acc) ->
- reloadChangedMod(T1, T2, SwSyncNode, OnsyncFun, Acc);
- reloadChangedMod([{Module, _} | T1], [{Module, _} | T2], 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(T1, T2, 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(T1, T2, SwSyncNode, OnsyncFun, [Module | Acc])
- end;
- reloadChangedMod([{Module1, _LastMod1} | T1] = OldLastMods, [{Module2, _LastMod2} | T2] = NewLastMods, SwSyncNode, OnsyncFun, Acc) ->
- %% Lists are different, advance the smaller one...
- case Module1 < Module2 of
- true ->
- reloadChangedMod(T1, NewLastMods, SwSyncNode, OnsyncFun, Acc);
- false ->
- reloadChangedMod(OldLastMods, T2, SwSyncNode, OnsyncFun, Acc)
- end;
- reloadChangedMod(A, B, _SwSyncNode, OnsyncFun, Acc) when A =:= []; B =:= [] ->
- fireOnsync(OnsyncFun, Acc),
- ok;
- reloadChangedMod(undefined, _Other, _, _, _) ->
- ok.
-
- 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).
-
- 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([{File, LastMod} | T1], [{File, LastMod} | T2], SwSyncNode) ->
- recompileChangeSrcFile(T1, T2, SwSyncNode);
- recompileChangeSrcFile([{File, _} | T1], [{File, _} | T2], SwSyncNode) ->
- recompileSrcFile(File, SwSyncNode),
- recompileChangeSrcFile(T1, T2, SwSyncNode);
- recompileChangeSrcFile([{File1, _LastMod1} | T1] = OldSrcFiles, [{File2, LastMod2} | T2] = NewSrcFiles, SwSyncNode) ->
- %% Lists are different...
- case File1 < File2 of
- true ->
- %% File was removed, do nothing...
- recompileChangeSrcFile(T1, NewSrcFiles, SwSyncNode);
- false ->
- maybeRecompileSrcFile(File2, LastMod2, SwSyncNode),
- recompileChangeSrcFile(OldSrcFiles, T2, SwSyncNode)
- end;
- recompileChangeSrcFile([], [{File, LastMod} | T2], SwSyncNode) ->
- maybeRecompileSrcFile(File, LastMod, SwSyncNode),
- recompileChangeSrcFile([], T2, SwSyncNode);
- recompileChangeSrcFile(_A, [], _) ->
- %% All remaining files, if any, were removed.
- ok;
- recompileChangeSrcFile(undefined, _Other, _) ->
- ok.
-
- erlydtlCompile(SrcFile, Options) ->
- F =
- fun({outdir, OutDir}, Acc) -> [{out_dir, OutDir} | Acc];
- (OtherOption, Acc) -> [OtherOption | Acc]
- end,
- DtlOptions = lists:foldl(F, [], Options),
- Module = list_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([list_to_binary(SrcFile)], list_to_binary(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).
-
- maybeRecompileSrcFile(File, LastMod, SwSyncNode) ->
- Module = list_to_atom(filename:basename(File, ".erl")),
- case code:which(Module) of
- BeamFile when is_list(BeamFile) ->
- %% check with beam file
- case filelib:last_modified(BeamFile) of
- BeamLastMod when LastMod > BeamLastMod ->
- recompileSrcFile(File, SwSyncNode);
- _ ->
- ok
- end;
- _ ->
- %% File is new, recompile...
- recompileSrcFile(File, SwSyncNode)
- end.
-
- getCompileFunAndModuleName(SrcFile) ->
- case esUtils:getFileType(SrcFile) of
- erl ->
- {fun compile:file/2, list_to_atom(filename:basename(SrcFile, ".erl"))};
- dtl ->
- {fun erlydtlCompile/2, list_to_atom(lists:flatten(filename:basename(SrcFile, ".dtl") ++ "_dtl"))};
- lfe ->
- {fun lfe_compile/2, list_to_atom(filename:basename(SrcFile, ".lfe"))};
- elixir ->
- {fun elixir_compile/2, list_to_atom(filename:basename(SrcFile, ".ex"))}
- end.
-
- getObjectCode(Module) ->
- case code:get_object_code(Module) of
- {Module, B, _Filename} -> B;
- _ -> undefined
- end.
-
- reloadIfNecessary(_CompileFun, _SrcFile, _Module, Binary, Binary, _Options) ->
- ok;
- reloadIfNecessary(CompileFun, SrcFile, Module, _OldBinary, _Binary, Options) ->
- %% Compiling changed the beam code. Compile and reload.
- CompileFun(SrcFile, Options),
- %% Try to load the module...
- case code:ensure_loaded(Module) of
- {module, Module} -> ok;
- {error, nofile} -> errorNoFile(Module);
- {error, embedded} ->
- case code:load_file(Module) of %% Module is not yet loaded, load it.
- {module, Module} -> ok;
- {error, nofile} -> errorNoFile(Module)
- end
- end,
- atomics:add(persistent_term:get(?esRecompileCnt), 1, 1).
-
- errorNoFile(Module) ->
- Msg = io_lib:format("~p Couldn't load module: nofile", [Module]),
- esUtils:logWarnings([Msg]).
-
- recompileSrcFile(SrcFile, SwSyncNode) ->
- %% Get the module, src dir, and options...
- case esUtils:getSrcDir(SrcFile) of
- {ok, SrcDir} ->
- {CompileFun, Module} = getCompileFunAndModuleName(SrcFile),
- OldBinary = getObjectCode(Module),
- case getOptions(SrcDir) of
- {ok, Options} ->
- case CompileFun(SrcFile, [binary, return | Options]) of
- {ok, Module, Binary, Warnings} ->
- reloadIfNecessary(CompileFun, SrcFile, Module, OldBinary, Binary, Options),
- printResults(Module, SrcFile, [], Warnings),
- {ok, [], Warnings};
- {ok, [{ok, Module, Binary, Warnings}], Warnings2} ->
- reloadIfNecessary(CompileFun, SrcFile, Module, OldBinary, Binary, Options),
- printResults(Module, SrcFile, [], Warnings ++ Warnings2),
- {ok, [], Warnings ++ Warnings2};
- {ok, multiple, Results, Warnings} ->
- [reloadIfNecessary(CompileFun, SrcFile, CompiledModule, OldBinary, Binary, Options) || {CompiledModule, Binary} <- Results],
- printResults(Module, SrcFile, [], Warnings),
- {ok, [], Warnings};
- {ok, OtherModule, _Binary, Warnings} ->
- Desc = io_lib:format("Module definition (~p) differs from expected (~s)", [OtherModule, filename:rootname(filename:basename(SrcFile))]),
- Errors = [{SrcFile, {0, Module, Desc}}],
- printResults(Module, SrcFile, Errors, Warnings),
- {ok, Errors, Warnings};
- {error, Errors, Warnings} ->
- printResults(Module, SrcFile, Errors, Warnings),
- {ok, Errors, Warnings}
- end;
- undefined ->
- case esUtils:tryGetModOptions(Module) of
- {ok, Options} ->
- setOptions(SrcDir, Options),
- recompileSrcFile(SrcFile, SwSyncNode);
- _ ->
- Msg = io_lib:format("Unable to determine options for ~s", [SrcFile]),
- esUtils:logErrors(Msg)
- end
- end;
- _ ->
- Msg = io_lib:format("not find the file ~s", [SrcFile]),
- esUtils:logErrors(Msg)
- end.
-
- printResults(_Module, SrcFile, [], []) ->
- Msg = io_lib:format("~s Recompiled", [SrcFile]),
- esUtils:logSuccess(lists:flatten(Msg));
- printResults(_Module, SrcFile, [], Warnings) ->
- Msg = [formatErrors(SrcFile, [], Warnings), io_lib:format("~s Recompiled with ~p warnings", [SrcFile, length(Warnings)])],
- esUtils:logWarnings(Msg);
- printResults(_Module, SrcFile, Errors, Warnings) ->
- Msg = [formatErrors(SrcFile, Errors, Warnings)],
- esUtils:logErrors(Msg).
-
-
- %% @private Print error messages in a pretty and user readable way.
- formatErrors(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),
- io_lib:format("~s:~p: ~s: ~s", [File, Line, Prefix, Msg])
- end,
- [FPck(X) || X <- Everything].
-
- formatError(Module, ErrorDescription) ->
- case erlang:function_exported(Module, format_error, 1) of
- true -> Module:format_error(ErrorDescription);
- false -> io_lib:format("~s", [ErrorDescription])
- end.
-
- recompileChangeHrlFile([{File, LastMod} | T1], [{File, LastMod} | T2], SrcFiles, SwSyncNode) ->
- recompileChangeHrlFile(T1, T2, SrcFiles, SwSyncNode);
- recompileChangeHrlFile([{File, _} | T1], [{File, _} | T2], SrcFiles, SwSyncNode) ->
- WhoInclude = whoInclude(File, SrcFiles),
- [recompileSrcFile(SrcFile, SwSyncNode) || SrcFile <- WhoInclude],
- recompileChangeHrlFile(T1, T2, SrcFiles, SwSyncNode);
- recompileChangeHrlFile([{File1, _LastMod1} | T1] = OldHrlFiles, [{File2, LastMod2} | T2] = NewHrlFiles, SrcFiles, SwSyncNode) ->
- %% Lists are different...
- case File1 < File2 of
- true ->
- %% File was removed, do nothing...
- warnDelHrlFiles(File1, SrcFiles),
- recompileChangeHrlFile(T1, NewHrlFiles, SrcFiles, SwSyncNode);
- false ->
- %% File is new, look for src that include it
- WhoInclude = whoInclude(File2, SrcFiles),
- [maybeRecompileSrcFile(SrcFile, LastMod2, SwSyncNode) || SrcFile <- WhoInclude],
- recompileChangeHrlFile(OldHrlFiles, T2, SrcFiles, SwSyncNode)
- end;
- recompileChangeHrlFile([], [{File, LastMod} | T2], SrcFiles, SwSyncNode) ->
- WhoInclude = whoInclude(File, SrcFiles),
- [maybeRecompileSrcFile(SrcFile, LastMod, SwSyncNode) || SrcFile <- WhoInclude],
- recompileChangeHrlFile([], T2, SrcFiles, SwSyncNode);
- recompileChangeHrlFile([{File1, _LastMod1} | T1], [], SrcFiles, SwSyncNode) ->
- warnDelHrlFiles(File1, SrcFiles),
- recompileChangeHrlFile(T1, [], SrcFiles, SwSyncNode);
- recompileChangeHrlFile([], [], _, _) ->
- %% Done
- ok;
- recompileChangeHrlFile(undefined, _Other, _, _) ->
- %% First load, do nothing
- ok.
-
- warnDelHrlFiles(HrlFile, SrcFiles) ->
- WhoInclude = whoInclude(HrlFile, SrcFiles),
- case WhoInclude of
- [] -> ok;
- _ ->
- Msg = io_lib:format("Warning. Deleted ~p file included in existing src files: ~p", [filename:basename(HrlFile), lists:map(fun(File) ->
- filename:basename(File) end, WhoInclude)]),
- esUtils:logSuccess(lists:flatten(Msg))
- end.
-
- whoInclude(HrlFile, SrcFiles) ->
- HrlFileBaseName = filename:basename(HrlFile),
- Pred =
- fun(SrcFile) ->
- {ok, Forms} = epp_dodger:parse_file(SrcFile),
- isInclude(HrlFileBaseName, Forms)
- end,
- lists: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).
-
- filterCollMods(Modules) ->
- excludeMods(onlyMods(Modules)).
-
- onlyMods(Modules) ->
- case ?esCfgSync:getv(?onlyMods) of
- [] ->
- Modules;
- OnlyMods ->
- [Mod || Mod <- Modules, checkModIsMatch(OnlyMods, Mod) == true]
- end.
-
- excludeMods(Modules) ->
- case ?esCfgSync:getv(?excludedMods) of
- [] ->
- Modules;
- ExcludedModules ->
- [Mod || Mod <- Modules, checkModIsMatch(ExcludedModules, Mod) == false]
- end.
-
- checkModIsMatch([], _Module) ->
- false;
- checkModIsMatch([ModOrPattern | T], Module) ->
- case ModOrPattern of
- Module ->
- true;
- _ when is_list(ModOrPattern) ->
- case re:run(atom_to_list(Module), ModOrPattern) of
- {match, _} ->
- true;
- nomatch ->
- checkModIsMatch(T, Module)
- end;
- _ ->
- checkModIsMatch(T, Module)
- end.
-
- collSrcDirs(Modules, AddDirs, OnlyDirs) ->
- FColl =
- fun
- (Mod, {SrcAcc, HrlAcc} = Acc) ->
- case esUtils:getModSrcDir(Mod) of
- {ok, SrcDir} ->
- case isOnlyDir(OnlyDirs, SrcDir) of
- true ->
- {ok, Options} = esUtils:getModOptions(Mod),
- HrlDir = proplists:get_all_values(i, Options),
- setOptions(SrcDir, Options),
- {[SrcDir | SrcAcc], HrlDir ++ HrlAcc};
- _ ->
- Acc
- end;
- undefined ->
- Acc
- end
- end,
- {SrcDirs, HrlDirs} = lists:foldl(FColl, {AddDirs, []}, Modules),
- USortedSrcDirs = lists:usort(SrcDirs),
- USortedHrlDirs = lists:usort(HrlDirs),
- {USortedSrcDirs, USortedHrlDirs}.
-
- isOnlyDir([], _) ->
- true;
- isOnlyDir(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.
-
- modLastmod(Mod) ->
- case code:which(Mod) of
- Beam when is_list(Beam) ->
- filelib:last_modified(Beam);
- _Other ->
- 0 %% non_existing | cover_compiled | preloaded
- end.
-
- 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).
- %% ***********************************PRIVATE FUNCTIONS end *********************************************
-
|