Skip to content

Commit

Permalink
[reltool] Link together escript with inlined application
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sirihansen committed Mar 19, 2012
1 parent 0bc4760 commit a524046
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 53 deletions.
3 changes: 2 additions & 1 deletion lib/reltool/src/reltool.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()],
Expand Down
6 changes: 3 additions & 3 deletions lib/reltool/src/reltool_mod_win.erl
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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),
Expand Down
113 changes: 75 additions & 38 deletions lib/reltool/src/reltool_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -467,30 +467,40 @@ 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} ->
lists:keydelete(Name,#app.name,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).
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,

Expand Down Expand Up @@ -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 ->
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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],
Expand All @@ -1923,25 +1951,32 @@ escript_files_to_apps(Escript,
end;
app ->
{App, Status2} = init_escript_app(AppName,
EscriptAppName,
Dir,
ModOrInfo,
[],
Apps,
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. ",
Expand Down Expand Up @@ -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."]),
Expand Down
8 changes: 4 additions & 4 deletions lib/reltool/src/reltool_target.erl
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)}
Expand Down Expand Up @@ -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)};
Expand Down Expand Up @@ -957,7 +957,7 @@ spec_lib_files(#sys{apps = Apps} = Sys) ->
if
Name =:= ?MISSING_APP_NAME ->
false;
IsEscript ->
IsEscript =/= false ->
false;
IsIncl; IsPre ->
true;
Expand Down
Loading

0 comments on commit a524046

Please sign in to comment.