📄 release_handler.erl
字号:
[Script],[NewAppl],[OldAppl]) of {ok, LowLevelScript} -> {ok, NewVsn, LowLevelScript}; {error, _SystoolsRC, Reason} -> throw(Reason) end.downgrade_script(App, OldVsn, OldDir) -> NewVsn = ensure_running(App), NewDir = code:lib_dir(App), {NewVsn, Script} = find_script(App, NewDir, OldVsn, down), OldAppl = read_app(App, OldVsn, OldDir), NewAppl = read_app(App, NewVsn, NewDir), case systools_rc:translate_scripts(dn, [Script],[OldAppl],[NewAppl]) of {ok, LowLevelScript} -> {ok, LowLevelScript}; {error, _SystoolsRC, Reason} -> throw(Reason) end.eval_appup_script(App, ToVsn, ToDir, Script) -> EnvBefore = application_controller:prep_config_change(), AppSpecL = read_appspec(App, ToDir), Res = release_handler_1:eval_script(Script, [], % [AppSpec] [{App, ToVsn, ToDir}], []), % [Opt] case Res of {ok, _Unpurged} -> application_controller:change_application_data(AppSpecL,[]), application_controller:config_change(EnvBefore); _Res -> ignore end, Res.ensure_running(App) -> case lists:keysearch(App, 1, application:which_applications()) of {value, {_App, _Descr, Vsn}} -> Vsn; false -> throw({app_not_running, App}) end.find_script(App, Dir, OldVsn, UpOrDown) -> Appup = filename:join([Dir, "ebin", atom_to_list(App)++".appup"]), case file:consult(Appup) of {ok, [{NewVsn, UpFromScripts, DownToScripts}]} -> Scripts = case UpOrDown of up -> UpFromScripts; down -> DownToScripts end, case lists:keysearch(OldVsn, 1, Scripts) of {value, {_OldVsn, Script}} -> {NewVsn, Script}; false -> throw({version_not_in_appup, OldVsn}) end; {error, enoent} -> throw(no_appup_found); {error, Reason} -> throw(Reason) end.read_app(App, Vsn, Dir) -> AppS = atom_to_list(App), Path = [filename:join(Dir, "ebin")], case systools_make:read_application(AppS, Vsn, Path, []) of {ok, Appl} -> Appl; {error, {not_found, _AppFile}} -> throw({no_app_found, Vsn, Dir}); {error, Reason} -> throw(Reason) end.read_appspec(App, Dir) -> AppS = atom_to_list(App), Path = [filename:join(Dir, "ebin")], case file:path_consult(Path, AppS++".app") of {ok, AppSpecL, _File} -> AppSpecL; {error, Reason} -> throw(Reason) end. %%-----------------------------------------------------------------%% Call-back functions from gen_server%%-----------------------------------------------------------------init([]) -> {ok, [[Root]]} = init:get_argument(root), {CliDir, Masters} = is_client(), ReleaseDir = case application:get_env(sasl, releases_dir) of undefined -> case os:getenv("RELDIR") of false -> if CliDir == false -> filename:join([Root, "releases"]); true -> filename:join([CliDir, "releases"]) end; RELDIR -> RELDIR end; {ok, Dir} -> Dir end, Releases = case consult(filename:join(ReleaseDir, "RELEASES"), Masters) of {ok, [Term]} -> transform_release(ReleaseDir, Term, Masters); _ -> {Name, Vsn} = init:script_id(), [#release{name = Name, vsn = Vsn, status = permanent}] end, StartPrg = case application:get_env(start_prg) of {ok, Found2} when is_list(Found2) -> {do_check, Found2}; _ -> {no_check, filename:join([Root, "bin", "start"])} end, Static = case application:get_env(static_emulator) of {ok, SFlag} when is_atom(SFlag) -> SFlag; _ -> false end, {ok, #state{root = Root, rel_dir = ReleaseDir, releases = Releases, start_prg = StartPrg, masters = Masters, client_dir = CliDir, static_emulator = Static}}.handle_call({unpack_release, ReleaseName}, _From, S) when S#state.masters == false -> RelDir = S#state.rel_dir, case catch do_unpack_release(S#state.root, RelDir, ReleaseName, S#state.releases) of {ok, NewReleases, Vsn} -> clean_release(RelDir, ReleaseName), {reply, {ok, Vsn}, S#state{releases = NewReleases}}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({unpack_release, _ReleaseName}, _From, S) -> {reply, {error, client_node}, S};handle_call({check_install_release, Vsn}, _From, S) -> case catch do_check_install_release(S#state.rel_dir, Vsn, S#state.releases, S#state.masters) of {ok, CurrentVsn, Descr} -> {reply, {ok, CurrentVsn, Descr}, S}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) -> NS = resend_sync_nodes(S), case catch do_install_release(S, Vsn, Opts) of {ok, NewReleases, CurrentVsn, Descr} -> {reply, {ok, CurrentVsn, Descr}, NS#state{releases=NewReleases}}; {ok, NewReleases, Unpurged, CurrentVsn, Descr} -> Timer = case S#state.timer of undefined -> {ok, Ref} = timer:send_interval(?timeout, timeout), Ref; Ref -> Ref end, NewS = NS#state{releases = NewReleases, unpurged = Unpurged, timer = Timer}, {reply, {ok, CurrentVsn, Descr}, NewS}; {error, Reason} -> {reply, {error, Reason}, NS}; {restart_new_emulator, CurrentVsn, Descr} -> gen_server:reply(From, {ok, CurrentVsn, Descr}), init:reboot(), {noreply, NS}; {'EXIT', Reason} -> io:format("release_handler:" "install_release(Vsn=~p Opts=~p) failed, " "Reason=~p~n", [Vsn, Opts, Reason]), gen_server:reply(From, {error, Reason}), case ErrorAction of restart -> init:restart(); reboot -> init:reboot() end, {noreply, NS} end;handle_call({make_permanent, Vsn}, _From, S) -> case catch do_make_permanent(S, Vsn) of {ok, Releases, Unpurged} -> {reply, ok, S#state{releases = Releases, unpurged = Unpurged}}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({reboot_old_release, Vsn}, From, S) -> case catch do_reboot_old_release(S, Vsn) of ok -> gen_server:reply(From, ok), init:reboot(), {noreply, S}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({remove_release, Vsn}, _From, S) when S#state.masters == false -> case catch do_remove_release(S#state.root, S#state.rel_dir, Vsn, S#state.releases) of {ok, NewReleases} -> {reply, ok, S#state{releases = NewReleases}}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({remove_release, _Vsn}, _From, S) -> {reply, {error, client_node}, S};handle_call({set_unpacked, RelFile, LibDirs}, _From, S) -> Root = S#state.root, case catch do_set_unpacked(Root, S#state.rel_dir, RelFile, LibDirs, S#state.releases, S#state.masters) of {ok, NewReleases, Vsn} -> {reply, {ok, Vsn}, S#state{releases = NewReleases}}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({set_removed, Vsn}, _From, S) -> case catch do_set_removed(S#state.rel_dir, Vsn, S#state.releases, S#state.masters) of {ok, NewReleases} -> {reply, ok, S#state{releases = NewReleases}}; {error, Reason} -> {reply, {error, Reason}, S}; {'EXIT', Reason} -> {reply, {error, Reason}, S} end;handle_call({install_file, File, Vsn}, _From, S) -> Reply = case lists:keysearch(Vsn, #release.vsn, S#state.releases) of {value, _} -> Dir = filename:join([S#state.rel_dir, Vsn]), catch copy_file(File, Dir, S#state.masters); _ -> {error, {no_such_release, Vsn}} end, {reply, Reply, S};handle_call(which_releases, _From, S) -> Reply = lists:map(fun(#release{name = Name, vsn = Vsn, libs = Libs, status = Status}) -> {Name, Vsn, mk_lib_name(Libs), Status} end, S#state.releases), {reply, Reply, S}.mk_lib_name([{LibName, Vsn, _Dir} | T]) -> [lists:concat([LibName, "-", Vsn]) | mk_lib_name(T)];mk_lib_name([]) -> [].handle_info(timeout, S) -> case soft_purge(S#state.unpurged) of [] -> timer:cancel(S#state.timer), {noreply, S#state{unpurged = [], timer = undefined}}; Unpurged -> {noreply, S#state{unpurged = Unpurged}} end;handle_info({sync_nodes, Id, Node}, S) -> PSN = S#state.pre_sync_nodes, {noreply, S#state{pre_sync_nodes = [{sync_nodes, Id, Node} | PSN]}};handle_info(Msg, State) -> error_logger:info_msg("release_handler: got unknown message: ~p~n", [Msg]), {noreply, State}.terminate(_Reason, _State) -> ok.handle_cast(_Msg, State) -> {noreply, State}.code_change(_OldVsn, State, _Extra) -> {ok, State}.%%%-----------------------------------------------------------------%%% Internal functions%%%-----------------------------------------------------------------is_client() -> case application:get_env(masters) of {ok, Masters} -> Alive = is_alive(), case atom_list(Masters) of true when Alive == true -> case application:get_env(client_directory) of {ok, ClientDir} -> case int_list(ClientDir) of true -> {ClientDir, Masters}; _ -> exit({bad_parameter, client_directory, ClientDir}) end; _ -> {false, false} end; _ -> exit({bad_parameter, masters, Masters}) end; _ -> {false, false} end.atom_list([A|T]) when is_atom(A) -> atom_list(T);atom_list([]) -> true;atom_list(_) -> false.int_list([I|T]) when is_integer(I) -> int_list(T);int_list([]) -> true;int_list(_) -> false.resend_sync_nodes(S) -> lists:foreach(fun(Msg) -> self() ! Msg end, S#state.pre_sync_nodes), S#state{pre_sync_nodes = []}.soft_purge(Unpurged) -> lists:filter(fun({Mod, _PostPurgeMethod}) -> case code:soft_purge(Mod) of true -> false; % No proc left, don't remember Mod false -> true % Still proc left, remember it end end, Unpurged).brutal_purge(Unpurged) -> lists:filter(fun({Mod, brutal_purge}) -> code:purge(Mod), false; (_) -> true end, Unpurged).%%-----------------------------------------------------------------%% The release package is a RelName.tar.Z (.tar on non unix) file%% with the following contents:%% - RelName.rel == {release, {Name, Vsn}, {erts, EVsn}, [lib()]}%% - <files> according to [lib()]%% - lib() = {LibName, LibVsn}%% In the Dir, there exists a file called RELEASES, which contains%% a [{Vsn, {erts, EVsn}, {libs, [{LibName, LibVsn, LibDir}]}}].%% Note that RelDir is an absolute directory name !%% Note that this function is not executed by a client%% release_handler.%%-----------------------------------------------------------------do_unpack_release(Root, RelDir, ReleaseName, Releases) ->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -