mad_repl.erl 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. -module(mad_repl).
  2. -copyright('Maxim Sokhatsky').
  3. -compile(export_all).
  4. disabled() -> [].
  5. system() -> [compiler,syntax_tools,sasl,tools,mnesia,reltool,xmerl,crypto,kernel,stdlib,ssh,eldap,
  6. wx,webtool,ssl,runtime_tools,public_key,observer,inets,asn1,et,eunit,hipe,os_mon,parsetools,odbc].
  7. local_app() ->
  8. case filename:basename(filelib:wildcard("ebin/*.app"),".app") of
  9. [] -> [];
  10. A -> list_to_atom(A) end.
  11. applist() ->
  12. Name = ".applist",
  13. case file:read_file(Name) of
  14. {ok,Binary} -> parse_applist(Binary);
  15. {error,_} ->
  16. case mad_repl:load_file(Name) of
  17. {error,_} -> mad_resolve:main([]);
  18. {ok,Plan} -> parse_applist(Plan) end end.
  19. wildcards(List) -> lists:concat([filelib:wildcard(X)||X<-List]).
  20. parse_applist(AppList) ->
  21. Res = string:tokens(string:strip(string:strip(binary_to_list(AppList),right,$]),left,$[),","),
  22. [ list_to_atom(R) || R <-Res ] -- disabled().
  23. load_config() ->
  24. Config = wildcards(["sys.config",lists:concat(["etc/",mad:host(),"/sys.config"])]),
  25. Apps = case Config of
  26. [] -> case mad_repl:load_file("sys.config") of
  27. {error,_} -> [];
  28. {ok,Bin} -> parse(unicode:characters_to_list(Bin)) end;
  29. File -> case file:consult(hd(File)) of
  30. {error,_} -> [];
  31. {ok,[A]} -> A end end,
  32. load_config(Apps, []).
  33. load_config([H|T], Apps2) ->
  34. App2 = case H of
  35. {App,Cfg} -> [application:set_env(App,K,V) || {K,V} <- Cfg], [H];
  36. File when is_list(File) ->
  37. Apps = case file:consult(File) of
  38. {error,_} -> [];
  39. {ok,[A]} -> A end,
  40. load_config(Apps, []);
  41. _ -> []
  42. end,
  43. load_config(T, Apps2 ++ App2);
  44. load_config([], Apps2) ->
  45. Apps2.
  46. acc_start(A,Acc) ->
  47. case application:start(A) of
  48. {error,{already_started,_}} -> Acc;
  49. {error,{_,{{M,_F,_},_Ret}}} -> [M|Acc];
  50. {error,{_Reason,Name}} when is_atom(_Reason) -> [Name|Acc];
  51. ok -> Acc;
  52. _ -> Acc end.
  53. load_apps([],_,_Acc) ->
  54. Res = lists:foldl(fun(A,Acc) -> case lists:member(A,system()) of
  55. true -> acc_start(A,Acc);
  56. _ -> case load_config(A) of
  57. [] -> acc_start(A,Acc);
  58. _E -> acc_start(_E,Acc) end end end,[], applist()),
  59. case Res of
  60. [] -> ok;
  61. _ -> mad:info("~nApps couldn't be loaded: ~p~n",[Res]) end;
  62. load_apps(["applist"],Config,Acc) -> load_apps([],Config,Acc);
  63. load_apps(Params,_,_Acc) -> [ application:ensure_all_started(list_to_atom(A))||A<-Params].
  64. cwd() -> case file:get_cwd() of {ok, Cwd} -> Cwd; _ -> "." end.
  65. sh(Params) ->
  66. { _Cwd,_ConfigFileName,_Config } = mad_utils:configs(),
  67. SystemPath = filelib:wildcard(code:root_dir() ++ "/lib/{"
  68. ++ string:join([atom_to_list(X)||X<-mad_repl:system()],",") ++ "}-*/ebin"),
  69. UserPath = wildcards(["{apps,deps}/*/ebin","ebin"]),
  70. code:set_path(SystemPath++UserPath),
  71. code:add_path(filename:join([cwd(),filename:basename(escript:script_name())])),
  72. load(),
  73. Config = load_config(),
  74. Driver = mad_utils:get_value(shell_driver,_Config,user_drv),
  75. repl_intro(),
  76. case os:type() of
  77. {win32,nt} -> os:cmd("chcp 65001"), shell:start();
  78. _ -> O = whereis(user),
  79. supervisor:terminate_child(kernel_sup, user),
  80. Driver:start(),
  81. wait(3000),
  82. rewrite_leaders(O,whereis(user)) end,
  83. load_apps(Params,Config,[]),
  84. case Params of
  85. ["applist"] -> skip;
  86. _ -> timer:sleep(infinity) end.
  87. remove(0) -> skip;
  88. remove(N) -> case gen_event:delete_handler(error_logger, error_logger, []) of
  89. {error, module_not_found} -> ok;
  90. {error_logger, _} -> remove(N-1) end.
  91. wait(0) -> erlang:error(timeout);
  92. wait(Timeout) -> case whereis(user) of undefined -> timer:sleep(100), wait(Timeout - 100); _ -> ok end.
  93. rewrite_leaders(OldUser, NewUser) ->
  94. _ = [catch erlang:group_leader(NewUser, Pid)
  95. || Pid <- erlang:processes(),
  96. proplists:get_value(group_leader, erlang:process_info(Pid)) == OldUser,
  97. is_process_alive(Pid)],
  98. OldMasters = [Pid
  99. || Pid <- erlang:processes(),
  100. Pid < NewUser, % only change old masters
  101. {_,Dict} <- [erlang:process_info(Pid, dictionary)],
  102. {application_master,init,4} == proplists:get_value('$initial_call', Dict)],
  103. _ = [catch erlang:group_leader(NewUser, Pid)
  104. || Pid <- erlang:processes(),
  105. lists:member(proplists:get_value(group_leader, erlang:process_info(Pid)),
  106. OldMasters)],
  107. try error_logger:swap_handler(tty),
  108. remove(3)
  109. catch E:R -> hope_for_best end.
  110. load() ->
  111. ets_created(),
  112. {ok,Sections} = escript:extract(escript:script_name(),[]),
  113. [Bin] = [B||{archive,B}<-Sections],
  114. unfold_zips(Bin).
  115. unfold_zips(Bin) ->
  116. {ok,Unzip} = zip:unzip(Bin,[memory]),
  117. [ begin
  118. try
  119. ets:insert(filesystem,{unicode:characters_to_list(base64:decode(list_to_binary(U))),FileBin})
  120. catch _:_ ->
  121. ets:insert(filesystem,{U,FileBin})
  122. end,
  123. case U of
  124. "static.gz" -> unfold_zips(FileBin);
  125. _ -> skip end
  126. end || {U,FileBin} <- Unzip].
  127. ets_created() ->
  128. case ets:info(filesystem) of
  129. undefined -> ets:new(filesystem,[set,named_table,{keypos,1},public]);
  130. _ -> skip end.
  131. load_file(Name) ->
  132. ets_created(),
  133. case ets:lookup(filesystem,Name) of
  134. [{Name,Bin}] -> {ok,Bin};
  135. _ -> {error,etsfs} end.
  136. load_config(A) when is_atom(A) -> load_config(atom_to_list(A));
  137. load_config(A) when is_list(A) ->
  138. AppFile = A ++".app",
  139. Name = wildcards(["{apps,deps}/*/ebin/"++AppFile,"ebin/"++AppFile]),
  140. case file:read_file(Name) of
  141. {ok,Bin} -> parse(binary_to_list(Bin));
  142. {error,_} -> case ets:lookup(filesystem,AppFile) of
  143. [{Name,Bin}] -> parse(binary_to_list(Bin));
  144. _ -> [] end end.
  145. parse(String) ->
  146. {ok,Tokens,_EndLine} = erl_scan:string(String),
  147. {ok,AbsForm} = erl_parse:parse_exprs(Tokens),
  148. {value,Value,_Bs} = erl_eval:exprs(AbsForm, erl_eval:new_bindings()),
  149. Value.
  150. repl_intro() ->
  151. io:format("Configuration: ~p~n", [load_config()]),
  152. io:format("Applications: ~p~n", [applist()]).