aboutsummaryrefslogtreecommitdiffstats
path: root/lib/reltool
diff options
context:
space:
mode:
authorSiri Hansen <[email protected]>2012-02-16 14:58:57 +0100
committerSiri Hansen <[email protected]>2012-03-19 09:48:54 +0100
commita5240467ac0b5428063360fc4a3d67ab9ffa1413 (patch)
tree38acda36f4e798399b5ce6223de7cbd48798b9ea /lib/reltool
parent0bc47607cad0c9ad475a7c0a8e7aa5633d00ceb5 (diff)
downloadotp-a5240467ac0b5428063360fc4a3d67ab9ffa1413.tar.gz
otp-a5240467ac0b5428063360fc4a3d67ab9ffa1413.tar.bz2
otp-a5240467ac0b5428063360fc4a3d67ab9ffa1413.zip
[reltool] Link together escript with inlined application
OTP-9968 Make sure that inlined applications in an escript is included/excluded as the escript itself, and forbid explicit configuration of the inlined application.
Diffstat (limited to 'lib/reltool')
-rw-r--r--lib/reltool/src/reltool.hrl3
-rw-r--r--lib/reltool/src/reltool_mod_win.erl6
-rw-r--r--lib/reltool/src/reltool_server.erl113
-rw-r--r--lib/reltool/src/reltool_target.erl8
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl116
5 files changed, 193 insertions, 53 deletions
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index 8e80c80e10..0a90c42ce2 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -45,6 +45,7 @@
-type profile() :: development | embedded | standalone.
-type relocatable() :: boolean().
-type escript_file() :: file().
+-type escript_app_name() :: app_name().
-type mod_name() :: atom().
-type app_name() :: atom().
-type app_vsn() :: string(). % e.g. "4.7"
@@ -170,7 +171,7 @@
-record(app,
{ %% Static info
name :: app_name(),
- is_escript :: boolean(),
+ is_escript :: boolean() | {inlined, escript_app_name()},
use_selected_vsn :: boolean() | undefined,
active_dir :: dir(),
sorted_dirs :: [dir()],
diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl
index e1c2fa5100..8cf175547b 100644
--- a/lib/reltool/src/reltool_mod_win.erl
+++ b/lib/reltool/src/reltool_mod_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. 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
@@ -314,8 +314,8 @@ do_create_code_page(#state{xref_pid = Xref, mod = M} = S, PageName) ->
{ok, App} = reltool_server:get_app(Xref, M#mod.app_name),
ErlBin =
case App#app.is_escript of
- true -> find_escript_bin(App, M);
- false -> find_regular_bin(App, M)
+ false -> find_regular_bin(App, M);
+ _ -> find_escript_bin(App, M)
end,
load_code(Editor, ErlBin),
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index da15d91581..f5abaf0957 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -467,20 +467,30 @@ loop(#state{common = C, sys = Sys} = S) ->
do_set_apps(#state{sys = Sys} = S, ChangedApps, Status) ->
%% Create new list of configured applications
- Sys2 = Sys#sys{apps = app_update_config(ChangedApps, Sys#sys.apps)},
+ {SysApps,Status2} = app_update_config(ChangedApps, Sys#sys.apps, Status),
+ Sys2 = Sys#sys{apps = SysApps},
- %% Refresh and analyse
- {S2, Apps, Status2} = refresh(S#state{sys = Sys2}, true, Status),
- Status3 = analyse(S2, Apps, Status2),
+ %% Refresh from filesystem and analyse dependencies
+ {S2, Apps, Status3} = refresh(S#state{sys = Sys2}, true, Status2),
+ Status4 = analyse(S2, Apps, Status3),
- {S2, Status3}.
+ {S2, Status4}.
%% Re-create the #sys.apps list by
%% 1) taking configurable fields from the changed #app records and
%% create new default records
%% 2) removing #app records if no configurable fields are set
%% 3) keeping #app records that are not changed
-app_update_config([Config|Configs],SysApps) ->
+app_update_config([#app{name=Name,is_escript={inlined,Escript}}|Configs],
+ SysApps,Status) ->
+ Text =
+ lists:flatten(
+ io_lib:format("Application ~p is inlined in ~p. Can not change "
+ "configuration for an inlined application.",
+ [Name,Escript])),
+ Status2 = reltool_utils:return_first_error(Status, Text),
+ app_update_config(Configs,SysApps,Status2);
+app_update_config([Config|Configs],SysApps,Status) ->
NewSysApps =
case app_set_config_only(Config) of
{delete,Name} ->
@@ -488,9 +498,9 @@ app_update_config([Config|Configs],SysApps) ->
New ->
lists:ukeymerge(#app.name,[New],SysApps)
end,
- app_update_config(Configs,NewSysApps);
-app_update_config([],SysApps) ->
- SysApps.
+ app_update_config(Configs,NewSysApps,Status);
+app_update_config([],SysApps,Status) ->
+ {SysApps,Status}.
app_set_config_only(#app{mods=ConfigMods} = Config) ->
app_set_config_only(mod_set_config_only(ConfigMods),Config).
@@ -506,13 +516,13 @@ app_set_config_only([],#app{name = Name,
excl_app_filters = undefined,
incl_archive_filters = undefined,
excl_archive_filters = undefined,
- archive_opts = undefined}) ->
+ archive_opts = undefined,
+ is_escript = false})->
{delete,Name};
app_set_config_only(Mods,#app{name = Name,
incl_cond = InclCond,
mod_cond = ModCond,
use_selected_vsn = UseSelectedVsn,
- active_dir = ActiveDir,
debug_info = DebugInfo,
app_file = AppFile,
app_type = AppType,
@@ -521,21 +531,38 @@ app_set_config_only(Mods,#app{name = Name,
incl_archive_filters = InclArchiveFilters,
excl_archive_filters = ExclArchiveFilters,
archive_opts = ArchiveOpts,
- vsn = Vsn}) ->
- (default_app(Name))#app{incl_cond = InclCond,
- mod_cond = ModCond,
- use_selected_vsn = UseSelectedVsn,
- active_dir = ActiveDir,
- debug_info = DebugInfo,
- app_file = AppFile,
- app_type = AppType,
- incl_app_filters = InclAppFilters,
- excl_app_filters = ExclAppFilters,
- incl_archive_filters = InclArchiveFilters,
- excl_archive_filters = ExclArchiveFilters,
- archive_opts = ArchiveOpts,
- vsn = Vsn,
- mods = Mods}.
+ vsn = Vsn,
+ is_escript = IsEscript,
+ label = Label,
+ info = Info,
+ active_dir = ActiveDir,
+ sorted_dirs = SortedDirs}) ->
+ App = (default_app(Name))#app{incl_cond = InclCond,
+ mod_cond = ModCond,
+ use_selected_vsn = UseSelectedVsn,
+ debug_info = DebugInfo,
+ app_file = AppFile,
+ app_type = AppType,
+ incl_app_filters = InclAppFilters,
+ excl_app_filters = ExclAppFilters,
+ incl_archive_filters = InclArchiveFilters,
+ excl_archive_filters = ExclArchiveFilters,
+ archive_opts = ArchiveOpts,
+ vsn = Vsn,
+ mods = Mods},
+
+ %% Some fields shall only be set if it is an escript, e.g. label
+ %% must never be set for any other applications since that will
+ %% prevent refreshing.
+ if IsEscript ->
+ App#app{is_escript = IsEscript,
+ active_dir = ActiveDir,
+ sorted_dirs = SortedDirs,
+ label = Label,
+ info = Info};
+ true ->
+ App
+ end.
mod_set_config_only(ConfigMods) ->
[#mod{name = Name,
@@ -1044,7 +1071,7 @@ refresh_app(#app{name = AppName,
%% And read all modules from ebin and create
%% #mod record with dependencies (uses_mods).
{AI, read_ebin_mods(Ebin, AppName), Status2};
- true ->
+ _ ->
{App#app.info, Mods, Status}
end,
@@ -1316,7 +1343,7 @@ shrink_app(A) ->
info = undefined,
mods = [],
uses_mods = undefined};
- true ->
+ true ->
{Dir, Dirs, OptVsn} =
case A#app.use_selected_vsn of
undefined ->
@@ -1881,7 +1908,7 @@ escripts_to_apps([Escript | Escripts], Apps, Status) ->
EA -> EA
end,
{Apps2, Status3} =
- escript_files_to_apps(Escript,
+ escript_files_to_apps(EscriptAppName,
lists:sort(Files),
[EscriptApp],
Apps,
@@ -1898,7 +1925,7 @@ escripts_to_apps([], Apps, Status) ->
%% Assume that all files for an app are in consecutive order
%% Assume the app info is before the mods
-escript_files_to_apps(Escript,
+escript_files_to_apps(EscriptAppName,
[{AppName, Type, Dir, ModOrInfo} | Files],
Acc,
Apps,
@@ -1914,6 +1941,7 @@ escript_files_to_apps(Escript,
{[App#app{mods = Mods} | Acc2], Status};
Acc ->
{NewApp, Status2} = init_escript_app(AppName,
+ EscriptAppName,
Dir,
missing_app_info(""),
[ModOrInfo],
@@ -1923,6 +1951,7 @@ escript_files_to_apps(Escript,
end;
app ->
{App, Status2} = init_escript_app(AppName,
+ EscriptAppName,
Dir,
ModOrInfo,
[],
@@ -1930,18 +1959,24 @@ escript_files_to_apps(Escript,
Status),
{[App | Acc], Status2}
end,
- escript_files_to_apps(Escript, Files, NewAcc, Apps, Status3);
-escript_files_to_apps(_Escript, [], Acc, Apps, Status) ->
- {lists:ukeymerge(#app.name, Acc, Apps), Status}.
+ escript_files_to_apps(EscriptAppName, Files, NewAcc, Apps, Status3);
+escript_files_to_apps(_EscriptAppName, [], Acc, Apps, Status) ->
+ {lists:ukeymerge(#app.name, lists:reverse(Acc), Apps), Status}.
-init_escript_app(AppName, Dir, Info, Mods, Apps, Status) ->
+init_escript_app(AppName, EscriptAppName, Dir, Info, Mods, Apps, Status) ->
App1 = default_app(AppName, Dir),
- App2 = App1#app{is_escript = true,
+ IsEscript =
+ if AppName=:=EscriptAppName -> true;
+ true -> {inlined, EscriptAppName}
+ end,
+ InclCond = (lists:keyfind(EscriptAppName,#app.name,Apps))#app.incl_cond,
+ App2 = App1#app{is_escript = IsEscript,
label = filename:basename(Dir, ".escript"),
info = Info,
mods = Mods,
active_dir = Dir,
- sorted_dirs = [Dir]},
+ sorted_dirs = [Dir],
+ incl_cond = InclCond},% inlined apps inherit incl from escript
case lists:keymember(AppName, #app.name, Apps) of
true ->
Error = lists:concat([AppName, ": Application name clash. ",
@@ -2022,8 +2057,10 @@ refresh_apps(_ConfigApps, [], Acc, _Force, Status) ->
{lists:reverse(Acc), Status}.
-ensure_app_info(#app{is_escript = true, active_dir = Dir, info = Info},
- Status) ->
+ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info},
+ Status)
+ when IsEscript=/=false ->
+ %% Escript or application which is inlined in an escript
{Info, Dir, Status};
ensure_app_info(#app{name = Name, sorted_dirs = []}, Status) ->
Error = lists:concat([Name, ": Missing application directory."]),
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 0fcf89a360..40d1009733 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2012. 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
@@ -101,7 +101,7 @@ do_gen_config(#sys{root_dir = RootDir,
|| A <- Apps,
A#app.name =/= ?MISSING_APP_NAME,
A#app.name =/= erts,
- not A#app.is_escript],
+ A#app.is_escript =/= true],
EscriptItems = [{escript,
A#app.active_dir,
emit(incl_cond, A#app.incl_cond, undefined, InclDefs)}
@@ -895,7 +895,7 @@ spec_escripts(#sys{apps = Apps}, ErtsBin, BinFiles) ->
if
Name =:= ?MISSING_APP_NAME ->
false;
- not IsEscript ->
+ IsEscript =/= true ->
false;
IsIncl; IsPre ->
{true, do_spec_escript(File, ErtsBin, BinFiles)};
@@ -957,7 +957,7 @@ spec_lib_files(#sys{apps = Apps} = Sys) ->
if
Name =:= ?MISSING_APP_NAME ->
false;
- IsEscript ->
+ IsEscript =/= false ->
false;
IsIncl; IsPre ->
true;
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index f2b63f78f0..e279be82a8 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -64,6 +64,7 @@ all() ->
create_standalone,
create_standalone_beam,
create_standalone_app,
+ create_standalone_app_clash,
create_multiple_standalone,
create_old_target,
eval_target_spec,
@@ -75,6 +76,7 @@ all() ->
get_sys,
set_app_and_undo,
set_apps_and_undo,
+ set_apps_inlined,
set_sys_and_undo,
load_config_and_undo,
load_config_escript_path,
@@ -798,13 +800,6 @@ create_standalone_beam(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with inlined archived application
-%% BUG: see OTP-9792, 25)
-%% Problem related to change of #app.name from "*escript* someapp" to
-%% just "someapp", since there is a someapp.app in the
-%% archive. "someapp" does not have an incl_cond=include statement,
-%% and it is not derived so the it is not included in the target
-%% system.
-create_standalone_app(_Config) -> {skip, "Known bug: escript with inlined archive is not handled correctly by reltool"};
create_standalone_app(Config) ->
%% Create archive
DataDir = ?config(data_dir,Config),
@@ -855,6 +850,43 @@ create_standalone_app(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Generate standalone system with inlined archived application
+%% Check that the inlined app can not be explicitly configured
+
+create_standalone_app_clash(Config) ->
+ %% Create archive
+ DataDir = ?config(data_dir,Config),
+ EscriptDir = filename:join(DataDir,escript),
+ {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
+ [memory,
+ {cwd,EscriptDir},
+ {compress,all},
+ {uncompress,[".beam",".app"]}]),
+
+ %% Create the escript
+ EscriptName = "someapp.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,
+ {emu_args,"-escript main mymod"},
+ {archive,Bin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {lib_dirs, []},
+ {escript, Escript, [{incl_cond, include}]},
+ {profile, standalone},
+ {app, someapp, [{incl_cond,include}]}
+ ]},
+
+ ?msym({error,"someapp: Application name clash. Escript "++_},
+ reltool:get_target_spec([{config,Sys}])),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with multiple escripts
create_multiple_standalone(Config) ->
@@ -1267,6 +1299,76 @@ set_apps_and_undo(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that escript can be configured, but not its inlined applications
+set_apps_inlined(Config) ->
+ %% Create archive
+ DataDir = ?config(data_dir,Config),
+ EscriptDir = filename:join(DataDir,escript),
+ {ok,{_Archive,Bin}} = zip:create("someapp-1.0.ez",["someapp-1.0"],
+ [memory,
+ {cwd,EscriptDir},
+ {compress,all},
+ {uncompress,[".beam",".app"]}]),
+
+ %% Create the escript
+ EscriptName = "someapp.escript",
+ Escript = filename:join(?WORK_DIR,EscriptName),
+ ok = escript:create(Escript,[shebang,
+ {emu_args,"-escript main mymod"},
+ {archive,Bin}]),
+ ok = file:change_mode(Escript,8#00744),
+
+ %% Configure the server
+ Sys = {sys,[{incl_cond, exclude},
+ {escript,Escript,[]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]}]},
+ {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])),
+ ?msym({ok,[]},reltool_server:get_status(Pid)),
+
+ %% Get app and mod
+ {ok,EApp} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')),
+ {ok,Someapp} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
+ ?m(undefined, EApp#app.incl_cond),
+ ?m(undefined, Someapp#app.incl_cond),
+ ?m(false, Someapp#app.is_included),
+ ?m(false, Someapp#app.is_pre_included),
+
+ %% Include escript
+ EApp1 = EApp#app{incl_cond=include},
+ ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp1])),
+ ExpectedEApp = EApp1#app{is_included=true,is_pre_included=true},
+ ?m({ok,ExpectedEApp}, reltool_server:get_app(Pid,'*escript* someapp')),
+ {ok,Someapp1} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
+ ?m(include, Someapp1#app.incl_cond),
+ ?m(true, Someapp1#app.is_included),
+ ?m(true, Someapp1#app.is_pre_included),
+
+ %% Check that inlined app can not be configured
+ Someapp2 = Someapp1#app{incl_cond=exclude},
+ ?msym({error,
+ "Application someapp is inlined in '*escript* someapp'. "
+ "Can not change configuration for an inlined application."},
+ reltool_server:set_apps(Pid,[Someapp2])),
+ ?m({ok,Someapp1}, reltool_server:get_app(Pid,someapp)),
+
+ %% Exclude escript
+ {ok,EApp2} = ?msym({ok,_}, reltool_server:get_app(Pid,'*escript* someapp')),
+ EApp3 = EApp2#app{incl_cond=exclude},
+ ?m({ok,[]}, reltool_server:set_apps(Pid,[EApp3])),
+ ExpectedEApp3 = EApp3#app{is_included=false,is_pre_included=false},
+ ?m({ok,ExpectedEApp3}, reltool_server:get_app(Pid,'*escript* someapp')),
+ {ok,Someapp3} = ?msym({ok,_}, reltool_server:get_app(Pid,someapp)),
+ ?m(exclude, Someapp3#app.incl_cond),
+ ?m(false, Someapp3#app.is_included),
+ ?m(false, Someapp3#app.is_pre_included),
+
+ ?m(ok, reltool:stop(Pid)),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
set_sys_and_undo(Config) ->
Sys1 = {sys,[{incl_cond, exclude},
{app,kernel,[{incl_cond,include}]},