Skip to content

Instantly share code, notes, and snippets.

@uwiger
Last active December 10, 2015 14:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save uwiger/4447248 to your computer and use it in GitHub Desktop.
Save uwiger/4447248 to your computer and use it in GitHub Desktop.
A sketch for an escript that functions similarly to the now defunct erl_call.
#!/usr/bin/env escript
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% Copyright 2013 Ulf Wiger <ulf@wiger.net>
%% License: http://opensource.org/licenses/MIT
main(Args) ->
Options = check_args(Args),
start_dist(Options),
Result = rpc(Options),
io:fwrite("~w~n", [Result]),
halt(0).
check_args(["-a", Call|Args]) ->
[{call, parse_call(Call)}|check_args(Args)];
check_args(["-c", Cookie|Args]) ->
[{cookie, list_to_atom(Cookie)}|check_args(Args)];
check_args(["-h", HiddenName|Args]) ->
[{hidden_name, HiddenName}|check_args(Args)];
check_args(["-name", Name|Args]) ->
[{longnames, true},{node, Name}|check_args(Args)];
check_args(["-sname", Name|Args]) ->
[{longnames, false},{node, Name}|check_args(Args)];
check_args([_|Args]) ->
check_args(Args);
check_args([]) ->
[].
start_dist(Options) ->
UseLongNames = proplists:get_value(longnames, Options, true),
MyNodeName = case lists:keyfind(hidden_name, 1, Options) of
false ->
random_node_name();
{_, N} ->
N
end,
UseNodeName = handle_own_host(MyNodeName),
supervisor:delete_child(kernel_sup, net_sup),
supervisor:start_child(
kernel_sup, {net_sup, {erl_distribution, start_link,
[[UseNodeName, if UseLongNames -> longnames;
true -> shortnames
end]]},
permanent, infinity, supervisor, [erl_distribution]}),
case lists:keyfind(cookie, 1, Options) of
false -> ok;
{_, Cookie} ->
erlang:set_cookie(node(), Cookie)
end.
handle_own_host(Node) ->
case re:split(Node, "@", [{return, list}]) of
[Short, Host] ->
inet_db:set_hostname(Host),
list_to_atom(Short);
[_] ->
list_to_atom(Node)
end.
rpc(Options) ->
{_, Node} = lists:keyfind(node, 1, Options),
Longnames = proplists:get_value(longnames, Options, true),
FullNode = fullname(Node, Longnames),
{_, {M, F, A}} = lists:keyfind(call, 1, Options),
case net_kernel:hidden_connect_node(FullNode) of
true ->
rpc:call(FullNode, M, F, A);
false ->
{badrpc, nodedown}
end.
parse_call(Call) ->
case split(Call) of
[Mod] ->
{list_to_atom(Mod), start, []};
[Mod, Fun] ->
{list_to_atom(Mod), list_to_atom(Fun), []};
[Mod, Fun, Args] ->
{list_to_atom(Mod), list_to_atom(Fun), parse_args(Args)}
end.
random_node_name() ->
{N1,N2,N3} = erlang:now(),
random:seed(N3,N2,N1),
"ecall" ++ integer_to_list(random:uniform(10000)).
fullname(N, LongNames) ->
case re:run(N, "@", []) of
nomatch ->
if LongNames ->
Host = hostname(),
io:fwrite("Host = ~p~n", [Host]),
list_to_atom(N ++ "@" ++ Host);
true ->
Host = hd(re:split(hostname(),
"\\.", [{return, list}])),
io:fwrite("Host = ~p~n", [Host]),
list_to_atom(N ++ "@" ++ Host)
end;
{match,_} ->
list_to_atom(N)
end.
hostname() ->
case {inet_db:gethostname(),inet_db:res_option(domain)} of
{H,D} when is_list(D), is_list(H),
length(D)> 0, length(H)>0 ->
H ++ "." ++ D;
Other ->
error({hostname, Other})
end.
parse_args(Args) ->
case erl_scan:string(Args ++ ". ") of
{ok, Tokens, _} ->
case erl_parse:parse_term(Tokens) of
{ok, Term} ->
Term;
Other ->
io:fwrite("Parse error: ~p~n", [Other]),
erlang:halt(1)
end;
ScanErr ->
io:fwrite("Scan error: ~p~n", [ScanErr]),
halt(1)
end.
split(Str) ->
re:split(Str, "\\s", [{return, list}, {parts, 3}]).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment