aboutsummaryrefslogblamecommitdiffstats
path: root/lib/reltool/bin/reltool.escript
blob: 0dcd5ad1e9b5c0b2fee6e494cc367d4805a172f9 (plain) (tree)
1
2
3
4
5
6



                      
                                                   





















                                                                         
                             




                                            
                         






















                                                                        


                          

















































































































                                                                                
                    


































































                                                                              
#!/usr/bin/env escript
%% -*- erlang -*-
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2010. 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), []}.