#!/usr/bin/env escript
%% -*- erlang -*-
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2009. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
-include_lib("reltool/src/reltool.hrl").
main(Args) ->
process_flag(trap_exit, true),
try
Tokens = scan_args(Args, [], []),
{Options, Actions} = parse_args(Tokens, []),
case invoke(Options, Actions) of
ok ->
safe_stop(0);
{error, ReasonString} ->
fatal_error(ReasonString, 2)
end
catch
throw:usage ->
usage(),
safe_stop(1);
exit:Reason ->
String = lists:flatten(io_lib:format("EXIT: ~p", [Reason])),
fatal_error(String, 3)
end.
usage() ->
Usage =
[
"[Config] [--window]",
"[Config] --create_config [-defaults] [-derived] [ConfigFile]",
"[Config] --create_rel RelName [RelFile]",
"[Config] --create_script RelName [ScriptFile]",
"[Config] --create_target TargetDir",
"[Config] --create_target_spec [SpecFile]",
"[Config] --eval_target_spec Spec TargetDir RootDir"
],
Script = script_name(),
String = lists:flatten([[Script, " ", U, "\n"] || U <- Usage]),
io:format("Erlang/OTP release management tool\n\n"
"~s\nConfig = ConfigFile | '{sys, [sys()]}'\n"
"Spec = SpecFile | '{spec, [target_spec()}']\n\n"
"See User's guide and Reference manual for more info.\n",
[String]).
safe_stop(Code) ->
init:stop(Code),
timer:sleep(infinity).
invoke(Options, Actions) ->
case Actions of
[] ->
invoke(Options, [["--window"]]);
[["--window"]] ->
start_window(Options);
[["--create_config" | OptArgs]] ->
DefArg = "-defaults",
DerivArg = "-derived",
InclDef = lists:member(DefArg, OptArgs),
InclDeriv = lists:member(DerivArg, OptArgs),
case reltool:get_config(Options, InclDef, InclDeriv) of
{ok, Config} ->
String = pretty("config", Config),
case OptArgs -- [DefArg, DerivArg] of
[] ->
format("~s", [String]);
[ConfigFile] ->
write_file(ConfigFile, String);
_ ->
throw(usage)
end;
{error, Reason} ->
{error, Reason}
end;
[["--create_rel", RelName | OptArgs]] ->
case reltool:get_rel(Options, RelName) of
{ok, Rel} ->
String = pretty("rel", Rel),
case OptArgs of
[] ->
format("~s", [String]);
[RelFile] ->
write_file(RelFile, String);
_ ->
throw(usage)
end;
{error, Reason} ->
{error, Reason}
end;
[["--create_script", RelName | OptArgs]] ->
case reltool:get_script(Options, RelName) of
{ok, Script} ->
String = pretty("script", Script),
case OptArgs of
[] ->
format("~s", [String]);
[ScriptFile] ->
write_file(ScriptFile, String);
_ ->
throw(usage)
end;
{error, Reason} ->
{error, Reason}
end;
[["--create_target", TargetDir]] ->
reltool:create_target(Options, TargetDir);
[["--create_target_spec" | OptArgs]] ->
case reltool:get_target_spec(Options) of
{ok, Script} ->
String = pretty("target_spec", Script),
case OptArgs of
[] ->
format("~s", [String]);
[SpecFile] ->
write_file(SpecFile, String);
_ ->
throw(usage)
end;
{error, Reason} ->
{error, Reason}
end;
[["--eval_target_spec", TargetSpec, TargetDir, RootDir]] ->
try
{ok, Tokens, _} = erl_scan:string(TargetSpec ++ ". "),
{ok, {spec, Spec}} = erl_parse:parse_term(Tokens),
reltool:eval_target_spec(Spec, TargetDir, RootDir)
catch
error:{badmatch, _} ->
case file:consult(TargetSpec) of
{ok, Spec2} ->
reltool:eval_target_spec(Spec2, TargetDir, RootDir);
{error, Reason} ->
Text = file:format_error(Reason),
{error, TargetSpec ++ ": " ++ Text}
end
end;
_ ->
throw(usage)
end.
start_window(Options) ->
case reltool:start_link(Options) of
{ok, WinPid} ->
receive
{'EXIT', WinPid, shutdown} ->
ok;
{'EXIT', WinPid, normal} ->
ok;
{'EXIT', WinPid, Reason} ->
exit(Reason)
end;
{error, Reason} ->
{error, Reason}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
script_name() ->
filename:basename(escript:script_name(), ".escript").
fatal_error(String, Code) ->
io:format(standard_error, "~s: ~s\n", [script_name(), String]),
safe_stop(Code).
write_file(File, IoList) ->
case file:write_file(File, IoList) of
ok ->
ok;
{error, Reason} ->
{error, file:format_error(Reason)}
end.
format(Format, Args) ->
io:format(Format, Args),
%% Wait a while for the I/O to be processed
timer:sleep(timer:seconds(1)).
pretty(Tag, Term) ->
lists:flatten(io_lib:format("%% ~s generated at ~w ~w\n~p.\n\n",
[Tag, date(), time(), Term])).
scan_args([H | T], Single, Multi) ->
case H of
"--" ++ _ when Single =:= [] ->
scan_args(T, [H], Multi);
"--" ++ _ ->
scan_args(T, [H], [lists:reverse(Single) | Multi]);
_ ->
scan_args(T, [H | Single], Multi)
end;
scan_args([], [], Multi) ->
lists:reverse(Multi);
scan_args([], Single, Multi) ->
lists:reverse([lists:reverse(Single) | Multi]).
parse_args([H | T] = Args, Options) ->
case H of
["--wx_debug" | Levels] ->
Dbg =
fun(L) ->
case catch list_to_integer(L) of
{'EXIT', _} ->
case catch list_to_atom(L) of
{'EXIT', _} ->
exit("Illegal wx debug level: " ++ L);
Atom ->
Atom
end;
Int ->
Int
end
end,
Levels2 = lists:map(Dbg, Levels),
parse_args(T, [{wx_debug, Levels2} | Options]);
["--" ++ _ | _] ->
%% No more options
{lists:reverse(Options), Args};
[Config] ->
try
{ok, Tokens, _} = erl_scan:string(Config ++ ". "),
{ok, {sys, _} = Sys} = erl_parse:parse_term(Tokens),
parse_args(T, [{config, Sys} | Options])
catch
error:{badmatch, _} ->
parse_args(T, [{config, Config} | Options]);
X:Y ->
io:format("\n\n~p\n\n", [{X, Y}])
end
end;
parse_args([], Options) ->
{lists:reverse(Options), []}.