⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 release_handler.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 5 页
字号:
	    lists:foreach(fun({_Lib, _LVsn, LDir}) ->				  remove_file(LDir)			  end, RemoveThese),	    remove_file(filename:join([RelDir, Vsn])),	    case lists:keysearch(EVsn, #release.erts_vsn, NewReleases) of		{value, _} -> ok;		false -> % Remove erts library, no more references to it		    remove_file(filename:join(Root, "erts-" ++ EVsn))	    end,	    write_releases(RelDir, NewReleases, false),	    {ok, NewReleases};	false ->	    {error, {no_such_release, Vsn}}    end.do_set_unpacked(Root, RelDir, RelFile, LibDirs, Releases, Masters) ->    Release = check_rel(Root, RelFile, LibDirs, Masters),    #release{vsn = Vsn} = Release,    case lists:keysearch(Vsn, #release.vsn, Releases) of	{value, _} -> throw({error, {existing_release, Vsn}});	false -> ok    end,    NewReleases = [Release#release{status = unpacked} | Releases],    VsnDir = filename:join([RelDir, Vsn]),    make_dir(VsnDir, Masters),    write_releases(RelDir, NewReleases, Masters),    {ok, NewReleases, Vsn}.do_set_removed(RelDir, Vsn, Releases, Masters) ->    case lists:keysearch(Vsn, #release.vsn, Releases) of	{value, #release{status = permanent}} ->	    {error, {permanent, Vsn}};	{value, _} ->	    NewReleases = lists:keydelete(Vsn, #release.vsn, Releases),	    write_releases(RelDir, NewReleases, Masters),	    {ok, NewReleases};	false ->	    {error, {no_such_release, Vsn}}    end.%%-----------------------------------------------------------------%% A relup file consists of:%%   {Vsn, [{FromVsn, Descr, RhScript}], [{ToVsn, Descr, RhScript}]}.%% It describes how to get to this release from previous releases,%% and how to get from this release to previous releases.%% We can get from a FromVsn that's a substring of CurrentVsn (e.g.%% 1.1 is a substring of 1.1.1, but not 1.2), but when we get to%% ToVsn, we must have an exact match.%%%% We do not put any semantics into the version strings, i.e. we%% don't know if going from Vsn1 to Vsn2 represents a upgrade or%% a downgrade.  For both upgrades and downgrades, the relup file%% is located in the directory of the latest version.  Since we%% do not which version is latest, we first suppose that ToVsn > %% CurrentVsn, i.e. we perform an upgrade.  If we don't find the%% corresponding relup instructions, we check if it's possible to%% downgrade from CurrentVsn to ToVsn.%%-----------------------------------------------------------------get_rh_script(#release{vsn = CurrentVsn},	      #release{vsn = Vsn},	      RelDir,	      Masters) ->    Relup = filename:join([RelDir, Vsn, "relup"]),    case try_upgrade(Vsn, CurrentVsn, Relup, Masters) of	{ok, RhScript} ->	    {ok, RhScript};	_ ->	    Relup2 = filename:join([RelDir, CurrentVsn,"relup"]),	    case try_downgrade(Vsn, CurrentVsn, Relup2, Masters) of		{ok, RhScript} ->		    {ok, RhScript};		_ ->		    throw({error, {no_matching_relup, Vsn, CurrentVsn}})	    end    end.try_upgrade(ToVsn, CurrentVsn, Relup, Masters) ->    case consult(Relup, Masters) of	{ok, [{ToVsn, ListOfRhScripts, _}]} ->	    case lists:keysearch(CurrentVsn, 1, ListOfRhScripts) of		{value, RhScript} -> 		    {ok, RhScript};		_ -> 		    error	    end;	{ok, _} ->	    throw({error, {bad_relup_file, Relup}});	{error, Reason} when is_tuple(Reason) ->	    throw({error, {bad_relup_file, Relup}});	{error, enoent} ->	    error;	{error, FileError} -> % FileError is posix atom | no_master	    throw({error, {FileError, Relup}})    end.try_downgrade(ToVsn, CurrentVsn, Relup, Masters) ->    case consult(Relup, Masters) of	{ok, [{CurrentVsn, _, ListOfRhScripts}]} ->	    case lists:keysearch(ToVsn, 1, ListOfRhScripts) of		{value, RhScript} ->		    {ok, RhScript};		_ ->		    error	    end;	{ok, _} ->	    throw({error, {bad_relup_file, Relup}});	{error, Reason} when is_tuple(Reason) ->	    throw({error, {bad_relup_file, Relup}});	{error, FileError} -> % FileError is posix atom | no_master	    throw({error, {FileError, Relup}})    end.%% Status = current | tmp_current | permanentset_status(Vsn, Status, Releases) ->    lists:zf(fun(Release) when Release#release.vsn == Vsn,		               Release#release.status == permanent ->		     %% If a permanent rel is installed, it keeps its		     %% permanent status (not changed to current).		     %% The current becomes old though.		     true;		(Release) when Release#release.vsn == Vsn ->			     {true, Release#release{status = Status}};			(Release) when Release#release.status == Status ->		     {true, Release#release{status = old}};		(_) ->		     true	     end, Releases).get_latest_release(Releases) ->    case lists:keysearch(current, #release.status, Releases) of	{value, Release} ->	    Release;	false ->	    {value, Release} = 		lists:keysearch(permanent, #release.status, Releases),	    Release    end.%% Returns: [{Lib, Vsn, Dir}] to be removeddiff_dir([H | T], L) ->    case memlib(H, L) of	true -> diff_dir(T, L);	false -> [H | diff_dir(T, L)]    end;diff_dir([], _) -> [].memlib({Lib, Vsn, _Dir}, [{Lib, Vsn, _Dir2} | _T]) -> true;memlib(Lib, [_H | T]) -> memlib(Lib, T);memlib(_Lib, []) -> false.			 %% recursively remove file or directoryremove_file(File) ->    case file:read_file_info(File) of	{ok, Info} when Info#file_info.type==directory ->	    case file:list_dir(File) of		{ok, Files} ->		    lists:foreach(fun(File2) ->					 remove_file(filename:join(File,File2))				  end, Files),		    case file:del_dir(File) of			ok -> ok;			{error, Reason} -> throw({error, Reason})		    end;		{error, Reason} ->		    throw({error, Reason})	    end;	{ok, _Info} ->	    case file:delete(File) of		ok -> ok;		{error, Reason} -> throw({error, Reason})	    end;	{error, _Reason} ->	    throw({error, {no_such_file, File}})    end.do_write_file(File, Str) ->    case file:open(File, write) of	{ok, Fd} ->	    io:put_chars(Fd, Str),	    file:close(Fd),	    ok;	{error, Reason} ->	    {error, {Reason, File}}    end.%%-----------------------------------------------------------------%% Change current applications (specifically, update their version,%% description and env.)%%-----------------------------------------------------------------change_appl_data(RelDir, #release{vsn = Vsn}, Masters) ->    Dir = filename:join([RelDir, Vsn]),    BootFile = filename:join(Dir, "start.boot"),    case read_file(BootFile, Masters) of	{ok, Bin} ->	    Config = case consult(filename:join(Dir, "sys.config"), Masters) of			 {ok, [Conf]} -> Conf;			 _ -> []		     end,	    Appls = get_appls(binary_to_term(Bin)),	    case application_controller:change_application_data(Appls,Config) of		ok -> Appls;		{error, Reason} -> exit({change_appl_data, Reason})	    end;	{error, _Reason} ->	    throw({error, {no_such_file, BootFile}})    end.%%-----------------------------------------------------------------%% This function is dependent on the application functions and%% the start script syntax.%%-----------------------------------------------------------------get_appls({script, _, Script}) -> get_appls(Script, []).%% kernel is taken care of separatelyget_appls([{kernelProcess, application_controller, 	    {application_controller, start, [App]}} |T], Res) ->    get_appls(T, [App | Res]);%% other applications but kernelget_appls([{apply, {application, load, [App]}} |T], Res) ->    get_appls(T, [App | Res]);get_appls([_ | T], Res) ->    get_appls(T, Res);get_appls([], Res) ->    Res.mon_nodes(true) ->    net_kernel:monitor_nodes(true);mon_nodes(false) ->    net_kernel:monitor_nodes(false),    flush().flush() ->    receive	{nodedown, _} -> flush();	{nodeup, _} -> flush()    after	0 -> ok    end.prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn},		   #release{erts_vsn = PermEVsn, vsn = PermVsn},		   DataFileName) ->    CurrentServiceName = hd(string:tokens(atom_to_list(node()),"@")) 	++ "_" ++ PermVsn,    FutureServiceName = hd(string:tokens(atom_to_list(node()),"@")) 	++ "_" ++ Vsn,    CurrentService = case erlsrv:get_service(PermEVsn,CurrentServiceName) of			 {error, Reason} ->			     throw({error, Reason});			 CS ->			     CS		     end,    FutureService =  erlsrv:new_service(FutureServiceName,					CurrentService,					filename:nativename(DataFileName),					%% This is rather icky... On a					%% non permanent service, the 					%% ERLSRV_SERVICE_NAME is 					%% actually that of an old service,					%% to make heart commands work...					CurrentServiceName),        case erlsrv:store_service(EVsn, FutureService) of	{error, Rison} ->	    throw({error,Rison});	_ ->	    erlsrv:disable_service(EVsn, FutureServiceName),	    ErlSrv = filename:nativename(erlsrv:erlsrv(EVsn)),	    case heart:set_cmd(ErlSrv ++ " enable " ++ FutureServiceName ++			       " & " ++ ErlSrv ++ " start " ++ 			       FutureServiceName ++			       " & " ++ ErlSrv ++ " disable " ++ 			       FutureServiceName) of		ok ->		    ok;		Error ->		    throw({error, {'heart:set_cmd() error', Error}})	    end    end.    %%-----------------------------------------------------------------%% Set things up for restarting the new emulator.  The actual%% restart is performed by calling init:reboot() higher up.%%-----------------------------------------------------------------prepare_restart_new_emulator(StartPrg, RelDir,			     Release, PRelease,			     Masters) ->    #release{erts_vsn = EVsn, vsn = Vsn} = Release,    Data = EVsn ++ " " ++ Vsn,    DataFile = write_new_start_erl(Data, RelDir, Masters),    %% Tell heart to use DataFile instead of start_erl.data    case os:type() of	{win32,nt} ->	    prepare_restart_nt(Release,PRelease,DataFile); 	{unix,_} ->	    StartP = check_start_prg(StartPrg, Masters),	    case heart:set_cmd(StartP ++ " " ++ DataFile) of		ok ->		    ok;		Error ->		    throw({error, {'heart:set_cmd() error', Error}})	    end    end.check_start_prg({do_check, StartPrg}, Masters) ->    check_file(StartPrg, regular, Masters),    StartPrg;check_start_prg({_, StartPrg}, _) ->    StartPrg.write_new_start_erl(Data, RelDir, false) ->    DataFile = filename:join([RelDir, "new_start_erl.data"]),    case do_write_file(DataFile, Data) of	ok    -> DataFile;	Error -> throw(Error)    end;write_new_start_erl(Data, RelDir, Masters) ->    DataFile = filename:join([RelDir, "new_start_erl.data"]),    case at_all_masters(Masters, ?MODULE, do_write_file,			[DataFile, Data]) of	ok    -> DataFile;	Error -> throw(Error)    end.%%-----------------------------------------------------------------%% When a new emulator shall be restarted, the current release%% is written with status tmp_current.  When the new emulator%% is started, this function is called.  The tmp_current release%% gets status unpacked on disk, and current in memory.  If a reboot%% is made (due to a crash), the release is just unpacked.  If a crash%% occurs before a call to transform_release is made, the old emulator%% is started, and transform_release is called for it.  The tmp_current%% release is changed to unpacked.%% If the release is made permanent, this is written to disk.%%-----------------------------------------------------------------transform_release(ReleaseDir, Releases, Masters) ->    F = fun(Release) when Release#release.status == tmp_current ->		Release#release{status = unpacked};	   (Release) -> Release	end,    case lists:map(F, Releases) of	Releases ->	    Releases;	DReleases ->	    write_releases(ReleaseDir, DReleases, Masters),	    F1 = fun(Release) when Release#release.status == tmp_current ->			 case init:script_id() of			     {_Name, Vsn} when Release#release.vsn == Vsn ->				 Release#release{status = current};			     _ ->				 Release#release{status = unpacked}			 end;		    (Release) -> Release		 end,	    lists:map(F1, Releases)    end.%%-----------------------------------------------------------------%% Functions handling files, RELEASES, start_erl.data etc.%% This functions consider if the release_handler is a client and%% in that case performs the operations at all master nodes or at%% none (in case of failure).%%-----------------------------------------------------------------check_opt_file(FileName, Type, Masters) ->    case catch check_file(FileName, Type, Masters) of	ok ->	    true;	_Error ->	    io:format("Warning: ~p missing (optional)~n", [FileName]),	    false    end.check_file(FileName, Type, false) ->    do_check_file(FileName, Type);check_file(FileName, Type, Masters) ->    check_file_masters(FileName, Type, Masters).

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -