diff --git a/.gitignore b/.gitignore index c594b10a3b2..039d1399325 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,8 @@ bin/ config.erl *.tar.gz *.tar.bz2 -dev/boot_node.beam +dev/*.beam +dev/devnode.* dev/lib/ dev/logs/ ebin/ diff --git a/Makefile b/Makefile index 184f9b0fbfe..873019f06fa 100644 --- a/Makefile +++ b/Makefile @@ -410,7 +410,7 @@ clean: @rm -rf src/mango/.venv @rm -f src/couch/priv/couchspawnkillable @rm -f src/couch/priv/couch_js/config.h - @rm -f dev/boot_node.beam dev/pbkdf2.pyc log/crash.log + @rm -f dev/*.beam dev/devnode.* dev/pbkdf2.pyc log/crash.log .PHONY: distclean diff --git a/dev/boot_node.erl b/dev/boot_node.erl deleted file mode 100644 index 922a5ccb6c6..00000000000 --- a/dev/boot_node.erl +++ /dev/null @@ -1,148 +0,0 @@ -% Licensed under the Apache License, Version 2.0 (the "License"); you may not -% use this file except in compliance with the License. You may obtain a copy of -% the License at -% -% http://www.apache.org/licenses/LICENSE-2.0 -% -% Unless required by applicable law or agreed to in writing, software -% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -% License for the specific language governing permissions and limitations under -% the License. - --module(boot_node). - --export([start/0]). - - -start() -> - monitor_parent(), - Apps = load_apps(), - Deps = load_deps(Apps), - start_all_apps(Deps). - - -monitor_parent() -> - {ok, [[PPid]]} = init:get_argument(parent_pid), - spawn(fun() -> monitor_parent(PPid) end). - - -monitor_parent(PPid) -> - timer:sleep(1000), - case os:type() of - {unix, _} -> - case os:cmd("kill -0 " ++ PPid) of - "" -> - monitor_parent(PPid); - _Else -> - % Assume _Else is a no such process error - init:stop() - end; - {win32, _} -> - Fmt = "tasklist /fi \"PID eq ~s\" /fo csv /nh", - Retval = os:cmd(io_lib:format(Fmt, [PPid])), - case re:run(Retval, "^\"python.exe\",*") of - {match, _} -> - monitor_parent(PPid); - nomatch -> - init:stop() - end - end. - - -load_apps() -> - {ok, [[Config]]} = init:get_argument(reltool_config), - {ok, Terms} = file:consult(Config), - load_apps(Terms). - - -load_apps([]) -> - erlang:error(failed_to_load_apps); -load_apps([{sys, Terms} | _]) -> - load_apps(Terms); -load_apps([{rel, "couchdb", _Vsn, Apps} | _]) -> - Apps; -load_apps([_ | Rest]) -> - load_apps(Rest). - - -load_deps(Apps) -> - load_deps(Apps, dict:new()). - - -load_deps([], Deps) -> - Deps; -load_deps([App | Rest], Deps) -> - load_app(App), - case application:get_key(App, applications) of - {ok, AppDeps0} -> - NewDeps = dict:store(App, AppDeps0, Deps), - Filter = fun(A) -> not dict:is_key(A, Deps) end, - AppDeps = lists:filter(Filter, AppDeps0), - load_deps(AppDeps ++ Rest, NewDeps); - _ -> - NewDeps = dict:store(App, [], Deps), - load_deps(Rest, NewDeps) - end. - - -load_app(App) -> - case application:load(App) of - ok -> - case application:get_key(App, modules) of - {ok, Modules} -> - lists:foreach(fun(Mod) -> - case load_app_module(Mod) of - ok -> ok; - E -> io:format("~p = load_app_module(~p)~n", [E, Mod]) - end - end, Modules); - undefined -> - ok - end; - {error, {already_loaded, App}} -> - ok; - Error -> - Error - end. - - -load_app_module(Mod) -> - case code:is_loaded(Mod) of - {file, _} -> - ok; - _ -> - case code:load_file(Mod) of - {module, Mod} -> - ok; - Error -> - Error - end - end. - - -start_all_apps(Deps) -> - lists:foldl(fun(App, Started) -> - start_app(App, Deps, Started) - end, [], dict:fetch_keys(Deps)). - - -start_app(App, Deps, Started) -> - case lists:member(App, Started) of - true -> - Started; - false -> - AppDeps = dict:fetch(App, Deps), - NowStarted = lists:foldl(fun(Dep, Acc) -> - start_app(Dep, Deps, Acc) - end, Started, AppDeps), - case application:start(App) of - ok -> - [App | NowStarted]; - {error, {already_started,App}} -> - % Kernel causes this - [App | NowStarted]; - Else -> - erlang:error(Else) - end - end. diff --git a/dev/make_boot_script b/dev/make_boot_script new file mode 100755 index 00000000000..549dd9a07ee --- /dev/null +++ b/dev/make_boot_script @@ -0,0 +1,9 @@ +#!/usr/bin/env escript + +main(_) -> + {ok, Server} = reltool:start_server([ + {config, "../rel/reltool.config"} + ]), + {ok, Release} = reltool:get_rel(Server, "couchdb"), + ok = file:write_file("devnode.rel", io_lib:format("~p.~n", [Release])), + ok = systools:make_script("devnode", [local]). diff --git a/dev/monitor_parent.erl b/dev/monitor_parent.erl new file mode 100644 index 00000000000..382f37e9c81 --- /dev/null +++ b/dev/monitor_parent.erl @@ -0,0 +1,43 @@ +% Licensed under the Apache License, Version 2.0 (the "License"); you may not +% use this file except in compliance with the License. You may obtain a copy of +% the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +% License for the specific language governing permissions and limitations under +% the License. + +-module(monitor_parent). + +-export([start/0]). + + +start() -> + {ok, [[PPid]]} = init:get_argument(parent_pid), + spawn(fun() -> monitor_parent(PPid) end). + + +monitor_parent(PPid) -> + timer:sleep(1000), + case os:type() of + {unix, _} -> + case os:cmd("kill -0 " ++ PPid) of + "" -> + monitor_parent(PPid); + _Else -> + % Assume _Else is a no such process error + init:stop() + end; + {win32, _} -> + Fmt = "tasklist /fi \"PID eq ~s\" /fo csv /nh", + Retval = os:cmd(io_lib:format(Fmt, [PPid])), + case re:run(Retval, "^\"python.exe\",*") of + {match, _} -> + monitor_parent(PPid); + nomatch -> + init:stop() + end + end. diff --git a/dev/run b/dev/run index 6d8bc5201d9..66d990a0936 100755 --- a/dev/run +++ b/dev/run @@ -101,6 +101,7 @@ def setup(): setup_logging(ctx) setup_dirs(ctx) check_beams(ctx) + check_boot_script(ctx) setup_configs(ctx) return ctx @@ -268,6 +269,14 @@ def check_beams(ctx): sp.check_call(["erlc", "-o", ctx["devdir"] + os.sep, fname]) +@log("Ensure Erlang boot script exists") +def check_boot_script(ctx): + if not os.path.exists(os.path.join(ctx["devdir"], "devnode.boot")): + env = os.environ.copy() + env["ERL_LIBS"] = os.path.join(ctx["rootdir"], "src") + sp.check_call(["escript", "make_boot_script"], env=env, cwd=ctx["devdir"]) + + @log("Prepare configuration files") def setup_configs(ctx): for idx, node in enumerate(ctx["nodes"]): @@ -592,10 +601,9 @@ def set_boot_env(ctx): @log("Start node {node}") def boot_node(ctx, node): - erl_libs = os.path.join(ctx["rootdir"], "src") set_boot_env(ctx) env = os.environ.copy() - env["ERL_LIBS"] = os.pathsep.join([erl_libs]) + env["ERL_LIBS"] = os.path.join(ctx["rootdir"], "src") node_etcdir = os.path.join(ctx["devdir"], "lib", node, "etc") reldir = os.path.join(ctx["rootdir"], "rel") @@ -614,11 +622,12 @@ def boot_node(ctx, node): os.path.join(reldir, "reltool.config"), "-parent_pid", str(os.getpid()), + "-boot", + os.path.join(ctx["devdir"], "devnode"), "-pa", ctx["devdir"], + "-s monitor_parent", ] - cmd += [p[:-1] for p in glob.glob(erl_libs + "/*/")] - cmd += ["-s", "boot_node"] if ctx["reset_logs"]: mode = "wb" else: