Skip to content

Instantly share code, notes, and snippets.

@uwiger
Created April 12, 2012 07:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uwiger/2365439 to your computer and use it in GitHub Desktop.
Save uwiger/2365439 to your computer and use it in GitHub Desktop.
make_node: escript for creating a node-local start directory
#!/usr/bin/env escript
%% -*- erlang -*-
%% Copyright 2011-12 Feuerlabs Inc.
%% License: "BSD New" (http://www.opensource.org/licenses/BSD-3-Clause)
%% Author: Ulf Wiger <ulf@feuerlabs.com>
-mode(compile).
-record(state, {target, rel, vm_args = []}).
main(Args) ->
try begin
St = args(Args, #state{}),
make_node(St)
end
catch
error:E ->
rpt_error(E, erlang:get_stacktrace()),
usage(),
exit(1)
end.
rpt_error(E, Stack) ->
io:fwrite("ERROR: ~p~n"
"Stack: ~p~n", [E, Stack]).
usage() ->
io:fwrite("Usage: ~s -rel RelDir -target TargetDir [ -- VmArgs ]~n",
[escript:script_name()]),
%% allow IO time to to through
receive after 500 -> ok end.
make_node(#state{target = T, rel = R, vm_args = As}) when T=/=undefined, R=/=undefined ->
Vsn = read_start_erl_data(R),
RelDir = filename:join([R, "releases", Vsn]),
VmArgsF = filename:join(RelDir, "vm.args"),
SysConfigF = filename:join(RelDir, "sys.config"),
case file:read_file(VmArgsF) of
{ok, Bin} ->
Bin1 = substitute_args(As, Bin),
OutF = filename:join(T, "vm.args"),
ok = filelib:ensure_dir(OutF),
file:write_file(OutF, Bin1);
Error ->
error({vm_args_not_found, Error})
end,
case file:consult(SysConfigF) of
{ok, [Env]} ->
NewEnv = localize_env(T, Env),
{ok, Fd} = file:open(filename:join(T, "sys.config"), [write]),
try
io:fwrite(Fd, "~p.~n", [NewEnv])
after
file:close(Fd)
end;
{error,_} = E ->
error({could_not_consult, [SysConfigF, E]})
end.
read_start_erl_data(R) ->
case file:read_file(filename:join(R, "releases/start_erl.data")) of
{ok, B} ->
[_, V, []] = re:split(B,"\\s",[{return,list}]),
V;
_Error ->
error("start_erl.data not found")
end.
substitute_args(Args, B) ->
Lines = re:split(B, "\\n", [{return,list}]),
case lists:foldl(fun({Flag, Vs}, Acc) ->
sub(Acc, Flag, Vs)
end, Lines, Args) of
[] ->
error("empty vm_args");
[L|Ls] ->
list_to_binary([L, "\n", [[L1, "\n"] || L1 <- Ls]])
end.
sub(["-" ++ _ = L | Ls], Flag, Vs) ->
case lists:prefix(Flag, L) of
true ->
[[Flag, [[" ", V] || V <- Vs]] | Ls];
false ->
[L | sub(Ls, Flag, Vs)]
end;
sub([L | Ls], Flag, Vs) ->
[L | sub(Ls, Flag, Vs)];
sub([], Flag, Vs) ->
[[Flag, [[" ", V] || V <- Vs]]].
args(["-target", T | Args], St) ->
args(Args, St#state{target = filename:absname(T)});
args(["-rel", R | Args], St) ->
args(Args, St#state{rel = R});
args(["--" | Args], St) ->
VmArgs = vm_args(Args),
St#state{vm_args = VmArgs};
args([Other | _], _) ->
error({bad_argument, Other});
args([], St) ->
St.
vm_args(["-" ++ _ = Flag | Args]) ->
{Vals, Args1} = get_vals(Args),
[{Flag, Vals} | vm_args(Args1)];
vm_args([]) ->
[].
get_vals(Args) ->
get_vals(Args, []).
get_vals([], Vals) ->
{lists:reverse(Vals), []};
get_vals(["-" ++ _ | _] = Args, Vals) ->
{lists:reverse(Vals), Args};
get_vals([H | T], Vals) ->
get_vals(T, [H|Vals]).
localize_env(Dir, Env) ->
LogD = filename:join(Dir, "log"),
merge_env([
{sasl, [
{sasl_error_logger, {file, filename:join(LogD, "sasl-error.log")}},
{error_logger_mf_dir, filename:join(LogD, "sasl")}
]},
{setup, [
{home, Dir},
{data_dir, filename:join(Dir, "db")},
{log_dir, LogD}
]}
], Env).
merge_env([{App, Vars}|T], Env) ->
case lists:keyfind(App, 1, Env) of
{_, Vars0} ->
NewVars =
lists:foldl(
fun({K,V}, Acc) ->
lists:keystore(K, 1, Acc, {K, V})
end, Vars0, Vars),
merge_env(T, lists:keyreplace(App, 1, Env, {App, NewVars}));
false ->
merge_env(T, Env ++ [{App, Vars}])
end;
merge_env([], Env) ->
Env.
@uwiger
Copy link
Author

uwiger commented Apr 12, 2012

An example make target:

ifdef n
        ./make_node -target nodes/$(n) -rel rel/$(RELNAME) -- -name $(n)
else
        echo "no node given (e.g. n=foo make node)"
        $(error, no node given)
        exit 2
endif

@uwiger
Copy link
Author

uwiger commented Apr 12, 2012

...and a make target for starting a node:


start:
ifdef n
        (cd nodes/$(n); ../../rel/$(RELNAME)/bin/$(RELNAME) start)
else
        echo "no node given (e.g. n=foo make start)"
        $(error, no node given)
        exit 2
endif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment