From a20eb61c2fdd027a89acd249eea4f452e4accfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Mattsson?= Date: Mon, 1 Mar 2010 19:53:48 +0100 Subject: Add function zip:foldl/3 to iterate over zip archives This is the public interface of prim_zip:open/3, which has been used in earlier releases by both erl_prim_loader and escript. The new function can be used as a replacement for the undocumented function escript:foldl/3 that is likely to be removed without further notice. The error handling of prim_zip:open/3 (and prim_zip:foldl/3) has been improved in order to better suite a public interface. For example it could happen that a file or a zlib port could be left open in some errors cases. The documentation of the FileSpec parameter to zip:create/3 has been updated to show that file info can be explicitly specified. A FileSpec may contain {Filename, binary(), #file_info{}} elements. The function zip:create/3 was already prepared to partly support this, but now after a few minor fixes it is fully supported. --- erts/preloaded/ebin/erl_prim_loader.beam | Bin 50808 -> 50816 bytes erts/preloaded/ebin/erlang.beam | Bin 23800 -> 23808 bytes erts/preloaded/ebin/init.beam | Bin 44488 -> 44500 bytes erts/preloaded/ebin/otp_ring0.beam | Bin 1436 -> 1448 bytes erts/preloaded/ebin/prim_file.beam | Bin 29480 -> 29496 bytes erts/preloaded/ebin/prim_inet.beam | Bin 57308 -> 57320 bytes erts/preloaded/ebin/prim_zip.beam | Bin 21756 -> 22600 bytes erts/preloaded/ebin/zlib.beam | Bin 10612 -> 10620 bytes erts/preloaded/src/prim_zip.erl | 89 ++++++++++++++++++++---------- lib/stdlib/doc/src/zip.xml | 90 +++++++++++++++++++++++++------ lib/stdlib/src/zip.erl | 80 ++++++++++++++++++--------- lib/stdlib/test/zip_SUITE.erl | 78 +++++++++++++++++++-------- 12 files changed, 246 insertions(+), 91 deletions(-) diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam index 304ac41dce..afd8a90b3f 100644 Binary files a/erts/preloaded/ebin/erl_prim_loader.beam and b/erts/preloaded/ebin/erl_prim_loader.beam differ diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam index 21e5525b2f..4ec84948d8 100644 Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam index 8ccc553c13..c3e746f3ee 100644 Binary files a/erts/preloaded/ebin/init.beam and b/erts/preloaded/ebin/init.beam differ diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam index 8ae73ea9a7..4b2d8bb2de 100644 Binary files a/erts/preloaded/ebin/otp_ring0.beam and b/erts/preloaded/ebin/otp_ring0.beam differ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index 3acda843fd..2916baaa77 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index 9457b6d360..46912e2bea 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam index 6837cb4661..ccf8aff6f6 100644 Binary files a/erts/preloaded/ebin/prim_zip.beam and b/erts/preloaded/ebin/prim_zip.beam differ diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam index 4e4f85d312..ccd597ba68 100644 Binary files a/erts/preloaded/ebin/zlib.beam and b/erts/preloaded/ebin/zlib.beam differ diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index 3f5a5b9721..6a9856fdad 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -65,34 +65,55 @@ filter_fun() -> open(F) -> open(filter_fun(), undefined, F). -open(FilterFun, FilterAcc, F) -> - case ?CATCH do_open(FilterFun, FilterAcc, F) of - {ok, PrimZip, Acc} -> - {ok, PrimZip, Acc}; - Error -> - {error, Error} - end. +open(FilterFun, FilterAcc, F) when is_function(FilterFun, 2) -> + try + do_open(FilterFun, FilterAcc, F) + catch + throw:{filter_fun_throw, Reason} -> + throw(Reason); + throw:InternalReason -> + {error, InternalReason}; + Class:Reason -> + erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) + end; +open(_, _, _) -> + {error, einval}. do_open(FilterFun, FilterAcc, F) -> Input = get_zip_input(F), In0 = Input({open, F, [read, binary, raw]}, []), Z = zlib:open(), PrimZip = #primzip{files = [], zlib = Z, in = In0, input = Input}, - {PrimZip2, FilterAcc2} = get_central_dir(PrimZip, FilterFun, FilterAcc), - {ok, PrimZip2, FilterAcc2}. + try + {PrimZip2, FilterAcc2} = get_central_dir(PrimZip, FilterFun, FilterAcc), + {ok, PrimZip2, FilterAcc2} + catch + Class:Reason -> + close(PrimZip), + erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) + end. %% iterate over all files in a zip archive -foldl(FilterFun, FilterAcc, #primzip{files = Files} = PrimZip) -> - case ?CATCH do_foldl(FilterFun, FilterAcc, Files, [], PrimZip, PrimZip) of - {ok, FilterAcc2, PrimZip2} -> {ok, PrimZip2, FilterAcc2}; - Error -> {error, Error} +foldl(FilterFun, FilterAcc, #primzip{files = Files} = PrimZip) + when is_function(FilterFun, 2) -> + try + {ok, FilterAcc2, PrimZip2} = + do_foldl(FilterFun, FilterAcc, Files, [], PrimZip, PrimZip), + {ok, PrimZip2, FilterAcc2} + catch + throw:{filter_fun_throw, Reason} -> + throw(Reason); + throw:InternalReason -> + {error, InternalReason}; + Class:Reason -> + erlang:error(erlang:raise(Class, Reason, erlang:get_stacktrace())) end; foldl(_, _, _) -> {error, einval}. do_foldl(FilterFun, FilterAcc, [PF | Tail], Acc0, PrimZip, PrimZipOrig) -> #primzip_file{name = F, get_info = GetInfo, get_bin = GetBin} = PF, - case FilterFun({F, GetInfo, GetBin}, FilterAcc) of + try FilterFun({F, GetInfo, GetBin}, FilterAcc) of {Continue, Include, FilterAcc2} -> Acc1 = include_acc(Include, PF, Acc0), case Continue of @@ -103,6 +124,9 @@ do_foldl(FilterFun, FilterAcc, [PF | Tail], Acc0, PrimZip, PrimZipOrig) -> end; FilterRes -> throw({illegal_filter, FilterRes}) + catch + throw:Reason -> + throw({filter_fun_throw, Reason}) end; do_foldl(_FilterFun, FilterAcc, [], Acc, PrimZip, _PrimZipOrig) -> {ok, FilterAcc, PrimZip#primzip{files = reverse(Acc)}}. @@ -121,12 +145,14 @@ include_acc(Include, PF, Acc) -> List when is_list(List) -> %% Add new entries Fun = fun(I, A) -> include_acc(I, PF, A) end, - lists_foldl(Fun, Acc, List) + lists_foldl(Fun, Acc, List); + Bad -> + throw({illegal_filter, Bad}) end. lists_foldl(F, Accu, [Hd|Tail]) -> lists_foldl(F, F(Hd, Accu), Tail); -lists_foldl(F, Accu, []) when is_function(F, 2) -> +lists_foldl(F, Accu, []) when is_function(F, 2) -> Accu. %% close a zip archive @@ -139,7 +165,9 @@ close(_) -> get_zip_input({F, B}) when is_binary(B), is_list(F) -> fun binary_io/2; get_zip_input(F) when is_list(F) -> - fun prim_file_io/2. + fun prim_file_io/2; +get_zip_input(_) -> + throw(einval). %% get a file from the archive get_z_file(F, Offset, ChunkSize, #primzip{zlib = Z, in = In0, input = Input}) -> @@ -218,15 +246,15 @@ get_cd_loop(N, BCD, Acc0, PrimZip, FileName, Offset, CFH, EndOffset, FilterFun, GetInfo = fun() -> cd_file_header_to_file_info(FileName, CFH, <<>>) end, GetBin = fun() -> get_z_file(FileName, Offset, Size, PrimZip) end, PF = #primzip_file{name = FileName, get_info = GetInfo, get_bin = GetBin}, - case FilterFun({FileName, GetInfo, GetBin}, FilterAcc) of + try FilterFun({FileName, GetInfo, GetBin}, FilterAcc) of {Continue, Include, FilterAcc2} -> Acc1 = case Include of - false -> + false -> Acc0; true -> [PF | Acc0]; - {true, Nick} -> + {true, Nick} -> [PF#primzip_file{name = Nick} | Acc0]; {true, Nick, GI, GB} -> PF2 = #primzip_file{name = Nick, get_info = GI, get_bin = GB}, @@ -247,13 +275,16 @@ get_cd_loop(N, BCD, Acc0, PrimZip, FileName, Offset, CFH, EndOffset, FilterFun, end; FilterRes -> throw({illegal_filter, FilterRes}) + catch + throw:Reason -> + throw({filter_fun_throw, Reason}) end. get_file_header(BCD) -> BCFH = case BCD of <> -> B; _ -> @@ -266,11 +297,11 @@ get_file_header(BCD) -> ToGet = FileNameLen + ExtraLen + CommentLen, {B2, BCDRest} = case BCD of - <<_:?CENTRAL_FILE_HEADER_SZ/binary, + <<_:?CENTRAL_FILE_HEADER_SZ/binary, G:ToGet/binary, - Rest/binary>> -> + Rest/binary>> -> {G, Rest}; - _ -> + _ -> throw(bad_central_directory) end, FileName = get_filename_from_b2(B2, FileNameLen, ExtraLen, CommentLen), @@ -319,9 +350,9 @@ prim_file_io({file_info, F}, _) -> end; prim_file_io({open, FN, Opts}, _) -> case ?CATCH prim_file:open(FN, Opts++[binary]) of - {ok, H} -> + {ok, H} -> H; - {error, E} -> + {error, E} -> throw(E) end; prim_file_io({read, N}, H) -> @@ -476,7 +507,7 @@ cd_file_header_to_file_info(FileName, %% FI; % not yet supported, and not widely used add_extra_info(FI, _) -> FI. -%% +%% %% unix_extra_field_and_var_from_bin(< <> = <>, <> = <>, {{YearFrom1980+1980, Month, Day}, - {Hour, Min, Sec}}. + {Hour, Min, Sec}}. cd_file_header_from_bin(< reverse([H|T], Y) -> reverse(T, [H|Y]); -reverse([], X) -> +reverse([], X) -> X. last([E|Es]) -> last(E, Es). diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml index af407f1925..4d98a20206 100644 --- a/lib/stdlib/doc/src/zip.xml +++ b/lib/stdlib/doc/src/zip.xml @@ -42,16 +42,18 @@

By convention, the name of a zip file should end in ".zip". To abide to the convention, you'll need to add ".zip" yourself to the name.

-

Zip archives are created with the - zip/2 or the +

Zip archives are created with the + zip/2 or the zip/3 function. (They are also available as create, to resemble the erl_tar module.)

-

To extract files from a zip archive, use the - unzip/1 or the +

To extract files from a zip archive, use the + unzip/1 or the unzip/2 function. (They are also available as extract.)

-

To return a list of the files in a zip archive, use the +

To fold a function over all files in a zip archive, use the + foldl_3.

+

To return a list of the files in a zip archive, use the list_dir/1 or the list_dir/2 function. (They are also available as table.)

@@ -132,7 +134,7 @@ zip_file() Name = filename() FileList = [FileSpec] - FileSpec = filename() | {filename(), binary()} + FileSpec = filename() | {filename(), binary()} | {filename(), binary(), #file_info{}} Options = [Option] Option = memory | cooked | verbose | {comment, Comment} | {cwd, CWD} | {compress, What} | {uncompress, What} What = all | [Extension] | {add, [Extension]} | {del, [Extension]} @@ -212,16 +214,16 @@ zip_file() all

means that all files will be compressed (as long - as they pass the uncompress condition).

+ as they pass the uncompress condition).

[Extension]

means that only files with exactly these extensions - will be compressed.

+ will be compressed.

{add,[Extension]}

adds these extensions to the list of compress - extensions.

+ extensions.

{del,[Extension]}

deletes these extensions from the list of compress - extensions.

+ extensions.

{uncompress, What} @@ -231,16 +233,16 @@ zip_file() The following values of What are allowed:

all -

means that no files will be compressed.

+

means that no files will be compressed.

[Extension]

means that files with these extensions will be - uncompressed.

+ uncompressed.

{add,[Extension]}

adds these extensions to the list of uncompress - extensions.

+ extensions.

{del,[Extension]}

deletes these extensions from the list of uncompress - extensions.

+ extensions.

@@ -283,7 +285,7 @@ zip_file() the unzip/2 function will only extract the files whose names are included in FileList. The full paths, including the names of all sub directories within - the zip archive, must be specified.

+ the zip archive, must be specified.

cooked @@ -326,6 +328,64 @@ zip_file() + + foldl(Fun, Acc0, Archive) -> {ok, Acc1} | {error, Reason} + Fold a function over all files in a zip archive + + Fun = fun(FileInArchive, GetInfo, GetBin, AccIn) -> AccOut + FileInArchive = filename() + GetInfo = fun() -> #file_info{} + GetBin = fun() -> binary() + Acc0 = Acc1 = AccIn = AccOut = term() + Archive = filename() | {filename(), binary()} + + +

The foldl/3 function + calls Fun(FileInArchive, GetInfo, GetBin, AccIn) on + successive files in the Archive, starting with AccIn + == Acc0. FileInArchive is the name that the file + has in the archive. GetInfo is a fun that returns info + about the the file. GetBin returns the contents of the + file. Both GetInfo and GetBin must be called + within the Fun. Their behavior is undefined if they are + called outside the context of the Fun. The Fun + must return a new accumulator which is passed to the next + call. foldl/3 returns the final value of the + accumulator. Acc0 is returned if the archive is + empty. It is not necessary to iterate over all files in the + archive. The iteration may be ended prematurely in a + controlled manner by throwing an exception.

+ +

For example:

+
+> Name = "dummy.zip".
+"dummy.zip"
+> {ok, {Name, Bin}} = zip:create(Name, [{"foo", <<"FOO">>}, {"bar", <<"BAR">>}], [memory]).
+{ok,{"dummy.zip",
+     <<80,75,3,4,20,0,0,0,0,0,74,152,97,60,171,39,212,26,3,0,
+       0,0,3,0,0,...>>}}
+> {ok, FileSpec} = zip:foldl(fun(N, I, B, Acc) -> [{N, B(), I()} | Acc] end, [], {Name, Bin}).
+{ok,[{"bar",<<"BAR">>,
+      {file_info,3,regular,read_write,
+                 {{2010,3,1},{19,2,10}},
+                 {{2010,3,1},{19,2,10}},
+                 {{2010,3,1},{19,2,10}},
+                 54,1,0,0,0,0,0}},
+     {"foo",<<"FOO">>,
+      {file_info,3,regular,read_write,
+                 {{2010,3,1},{19,2,10}},
+                 {{2010,3,1},{19,2,10}},
+                 {{2010,3,1},{19,2,10}},
+                 54,1,0,0,0,0,0}}]}
+> {ok, {Name, Bin}} = zip:create(Name, lists:reverse(FileSpec), [memory]).
+{ok,{"dummy.zip",
+     <<80,75,3,4,20,0,0,0,0,0,74,152,97,60,171,39,212,26,3,0,
+       0,0,3,0,0,...>>}}
+> catch zip:foldl(fun("foo", _, B, _) -> throw(B()); (_, _, _, Acc) -> Acc end, [], {Name, Bin}). 
+<<"FOO">>
+
+
+
list_dir(Archive) -> RetValue list_dir(Archive, Options) diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl index e76d588cb5..d41aeefa59 100644 --- a/lib/stdlib/src/zip.erl +++ b/lib/stdlib/src/zip.erl @@ -20,7 +20,7 @@ %% Basic api -export([unzip/1, unzip/2, extract/1, extract/2, - zip/2, zip/3, create/2, create/3, + zip/2, zip/3, create/2, create/3, foldl/3, list_dir/1, list_dir/2, table/1, table/2, t/1, tt/1]). @@ -38,7 +38,7 @@ zip_t/1, zip_tt/1, zip_list_dir/1, zip_list_dir/2, zip_close/1]). - + %% just for debugging zip server, not documented, not tested, not to be used -export([zip_get_state/1]). @@ -82,7 +82,7 @@ -record(openzip_opts, { output, % output object (fun) open_opts, % file:open options - cwd % directory to relate paths to + cwd % directory to relate paths to }). % openzip record, state for an open zip-file @@ -93,10 +93,10 @@ input, % archive io object (fun) output, % output io object (fun) zlib, % handle to open zlib - cwd % directory to relate paths to + cwd % directory to relate paths to }). -% Things that I would like to add to the public record #zip_file, +% Things that I would like to add to the public record #zip_file, % but can't as it would make things fail at upgrade. % Instead we use {#zip_file,#zip_file_extra} internally. -record(zip_file_extra, { @@ -278,7 +278,7 @@ file_name_search(Name,Files) -> [ZFile|_] -> ZFile; [] -> false end. - + %% %% add a file to an open archive %% openzip_add(File, OpenZip) -> %% case ?CATCH do_openzip_add(File, OpenZip) of @@ -344,6 +344,25 @@ do_unzip(F, Options) -> Input(close, In1), {ok, Files}. +%% Iterate over all files in a zip archive +foldl(Fun, Acc0, Archive) when is_function(Fun, 4) -> + ZipFun = + fun({Name, GetInfo, GetBin}, A) -> + A2 = Fun(Name, GetInfo, GetBin, A), + {true, false, A2} + end, + case prim_zip:open(ZipFun, Acc0, Archive) of + {ok, PrimZip, Acc1} -> + ok = prim_zip:close(PrimZip), + {ok, Acc1}; + {error, bad_eocd} -> + {error, "Not an archive file"}; + {error, Reason} -> + {error, Reason} + end; +foldl(_,_, _) -> + {error, einval}. + %% Create zip archive name F from Files or binaries %% %% Accepted options: @@ -383,7 +402,7 @@ list_dir(F, Options) -> do_list_dir(F, Options) -> Opts = get_list_dir_options(F, Options), - #list_dir_opts{input = Input, open_opts = OpO, + #list_dir_opts{input = Input, open_opts = OpO, raw_iterator = RawIterator} = Opts, In0 = Input({open, F, OpO}, []), {Info, In1} = get_central_dir(In0, RawIterator, Input), @@ -417,7 +436,7 @@ tt(F) when is_record(F, openzip) -> openzip_tt(F); tt(F) -> t(F, fun raw_long_print_info_etc/5). -%% option utils +%% option utils get_unzip_opt([], Opts) -> Opts; get_unzip_opt([verbose | Rest], Opts) -> @@ -470,7 +489,7 @@ get_zip_opt([{cwd, CWD} | Rest], Opts) -> get_zip_opt([{comment, C} | Rest], Opts) -> get_zip_opt(Rest, Opts#zip_opts{comment = C}); get_zip_opt([{compress, Which} = O| Rest], Opts) -> - Which2 = + Which2 = case Which of all -> all; @@ -485,7 +504,7 @@ get_zip_opt([{compress, Which} = O| Rest], Opts) -> end, get_zip_opt(Rest, Opts#zip_opts{compress = Which2}); get_zip_opt([{uncompress, Which} = O| Rest], Opts) -> - Which2 = + Which2 = case Which of all -> all; @@ -560,16 +579,24 @@ get_openzip_options(Options) -> get_input(F) when is_binary(F) -> fun binary_io/2; get_input(F) when is_list(F) -> - fun file_io/2. + fun file_io/2; +get_input(_) -> + throw(einval). get_zip_input({F, B}) when is_binary(B), is_list(F) -> fun binary_io/2; +get_zip_input({F, B, #file_info{}}) when is_binary(B), is_list(F) -> + fun binary_io/2; +get_zip_input({F, #file_info{}, B}) when is_binary(B), is_list(F) -> + fun binary_io/2; get_zip_input(F) when is_list(F) -> fun file_io/2; get_zip_input({files, []}) -> fun binary_io/2; get_zip_input({files, [File | _]}) -> - get_zip_input(File). + get_zip_input(File); +get_zip_input(_) -> + throw(einval). get_list_dir_options(F, Options) -> Opts = #list_dir_opts{raw_iterator = fun raw_file_info_public/5, @@ -620,6 +647,8 @@ put_eocd(N, Pos, Sz, Comment, Output, Out0) -> get_filename({Name, _}, Type) -> get_filename(Name, Type); +get_filename({Name, _, _}, Type) -> + get_filename(Name, Type); get_filename(Name, regular) -> Name; get_filename(Name, directory) -> @@ -895,7 +924,7 @@ local_file_header_to_bin( CompSize:32/little, UncompSize:32/little, FileNameLength:16/little, - ExtraFieldLength:16/little>>. + ExtraFieldLength:16/little>>. eocd_to_bin(#eocd{disk_num = DiskNum, start_disk_num = StartDiskNum, @@ -912,7 +941,7 @@ eocd_to_bin(#eocd{disk_num = DiskNum, Offset:32/little, ZipCommentLength:16/little>>. -%% put together a local file header +%% put together a local file header local_file_header_from_info_method_name(#file_info{mtime = MTime}, UncompSize, CompMethod, Name) -> @@ -939,7 +968,7 @@ server_loop(OpenZip) -> server_loop(NewOpenZip); Error -> From ! {self(), Error} - end; + end; {From, close} -> From ! {self(), openzip_close(OpenZip)}; {From, get} -> @@ -1024,7 +1053,7 @@ lists_foreach(F, [Hd|Tl]) -> F(Hd), lists_foreach(F, Tl). -%% option utils +%% option utils get_openzip_opt([], Opts) -> Opts; get_openzip_opt([cooked | Rest], #openzip_opts{open_opts = OO} = Opts) -> @@ -1121,7 +1150,7 @@ raw_file_info_public(CD, FileName, FileComment, BExtraField, Acc0) -> Other -> Other end, [H2|T]. - + %% make a file_info from a central directory header cd_file_header_to_file_info(FileName, @@ -1213,8 +1242,8 @@ get_z_file(In0, Z, Input, Output, OpO, FB, CWD, {ZipFile,Extra}) -> {dir, In3}; _ -> %% FileInfo = local_file_header_to_file_info(LH) - %%{Out, In4, CRC, UncompSize} = - {Out, In4, CRC, _UncompSize} = + %%{Out, In4, CRC, UncompSize} = + {Out, In4, CRC, _UncompSize} = get_z_data(CompMethod, In3, FileName1, CompSize, Input, Output, OpO, Z), In5 = skip_z_data_descriptor(GPFlag, Input, In4), @@ -1280,7 +1309,7 @@ get_z_data_loop(CompSize, UncompSize, In0, Out0, Input, Output, Z) -> Out1 = Output({write, Uncompressed}, Out0), get_z_data_loop(CompSize-N, UncompSize + iolist_size(Uncompressed), In1, Out1, Input, Output, Z) - end. + end. %% skip data descriptor if any @@ -1298,7 +1327,7 @@ dos_date_time_to_datetime(DosDate, DosTime) -> <> = <>, <> = <>, {{YearFrom1980+1980, Month, Day}, - {Hour, Min, Sec}}. + {Hour, Min, Sec}}. dos_date_time_from_datetime({{Year, Month, Day}, {Hour, Min, Sec}}) -> YearFrom1980 = Year-1980, @@ -1319,7 +1348,6 @@ unix_extra_field_and_var_from_bin(< throw(bad_unix_extra_field). - %% A pwrite-like function for iolists (used by memory-option) @@ -1478,6 +1506,8 @@ local_file_header_from_bin(_) -> %% io functions binary_io({file_info, {_Filename, _B, #file_info{} = FI}}, _A) -> FI; +binary_io({file_info, {_Filename, #file_info{} = FI, _B}}, _A) -> + FI; binary_io({file_info, {_Filename, B}}, A) -> binary_io({file_info, B}, A); binary_io({file_info, B}, _) -> @@ -1493,9 +1523,11 @@ binary_io({file_info, B}, _) -> links = 1, major_device = 0, minor_device = 0, inode = 0, uid = 0, gid = 0}; -binary_io({open, {_Filename, B, _FI}, _Opts}, _) -> +binary_io({open, {_Filename, B, _FI}, _Opts}, _) when is_binary(B) -> + {0, B}; +binary_io({open, {_Filename, _FI, B}, _Opts}, _) when is_binary(B) -> {0, B}; -binary_io({open, {_Filename, B}, _Opts}, _) -> +binary_io({open, {_Filename, B}, _Opts}, _) when is_binary(B) -> {0, B}; binary_io({open, B, _Opts}, _) when is_binary(B) -> {0, B}; diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl index 12ca655000..48b14396c1 100644 --- a/lib/stdlib/test/zip_SUITE.erl +++ b/lib/stdlib/test/zip_SUITE.erl @@ -18,12 +18,13 @@ %% -module(zip_SUITE). --export([all/1, borderline/1, atomic/1, +-export([all/1, borderline/1, atomic/1, bad_zip/1, unzip_from_binary/1, unzip_to_binary/1, zip_to_binary/1, unzip_options/1, zip_options/1, list_dir_options/1, aliases/1, openzip_api/1, zip_api/1, unzip_jar/1, - compress_control/1]). + compress_control/1, + foldl/1]). -include("test_server.hrl"). -include("test_server_line.hrl"). @@ -35,7 +36,8 @@ all(suite) -> [borderline, atomic, bad_zip, zip_to_binary, unzip_options, zip_options, list_dir_options, aliases, openzip_api, zip_api, unzip_jar, - compress_control]. + compress_control, + foldl]. borderline(doc) -> ["Test creating, listing and extracting one file from an archive " @@ -110,17 +112,17 @@ get_data(Port, Expect) -> {Port, {data, Bytes}} -> get_data(Port, match_output(Bytes, Expect, Port)); {Port, eof} -> - Port ! {self(), close}, + Port ! {self(), close}, receive {Port, closed} -> true - end, + end, receive - {'EXIT', Port, _} -> + {'EXIT', Port, _} -> ok after 1 -> % force context switch ok - end, + end, match_output(eof, Expect, Port) end. @@ -290,7 +292,7 @@ unzip_options(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), Long = filename:join(DataDir, "abc.zip"), - + %% create a temp directory Subdir = filename:join(PrivDir, "t"), ok = file:make_dir(Subdir), @@ -303,7 +305,7 @@ unzip_options(Config) when is_list(Config) -> %% Verify. ?line true = (length(FList) =:= length(RetList)), - ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)), + ?line lists:foreach(fun(F)-> {ok,B} = file:read_file(filename:join(DataDir, F)), {ok,B} = file:read_file(filename:join(Subdir, F)) end, FList), ?line lists:foreach(fun(F)-> ok = file:delete(F) end, @@ -321,7 +323,7 @@ unzip_jar(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), JarFile = filename:join(DataDir, "test.jar"), - + %% create a temp directory Subdir = filename:join(PrivDir, "jartest"), ok = file:make_dir(Subdir), @@ -479,7 +481,7 @@ unzip_to_binary(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), PrivDir = ?config(priv_dir, Config), - delete_all_in(PrivDir), + delete_all_in(PrivDir), file:set_cwd(PrivDir), Long = filename:join(DataDir, "abc.zip"), @@ -595,17 +597,17 @@ do_delete_files([],Cnt) -> Cnt; do_delete_files([Item|Rest], Cnt) -> case file:delete(Item) of - ok -> + ok -> DelCnt = 1; {error,eperm} -> file:change_mode(Item, 8#777), DelCnt = delete_files(filelib:wildcard(filename:join(Item, "*"))), - file:del_dir(Item); + file:del_dir(Item); {error,eacces} -> %% We'll see about that! file:change_mode(Item, 8#777), case file:delete(Item) of - ok -> + ok -> DelCnt = 1; {error,_} -> erlang:yield(), @@ -643,22 +645,22 @@ compress_control(Config) when is_list(Config) -> ], test_compress_control(Dir, - Files, + Files, [{compress, []}], []), test_compress_control(Dir, - Files, + Files, [{uncompress, all}], []), test_compress_control(Dir, - Files, + Files, [{uncompress, []}], [".txt", ".exe", ".zip", ".lzh", ".arj"]), test_compress_control(Dir, - Files, + Files, [], [".txt", ".exe"]), @@ -686,7 +688,7 @@ test_compress_control(Dir, Files, ZipOptions, Expected) -> create_files(Files), {ok, Zip} = zip:create(Zip, [Dir], ZipOptions), - + {ok, OpenZip} = zip:openzip_open(Zip, [memory]), {ok,[#zip_comment{comment = ""} | ZipList]} = zip:openzip_list_dir(OpenZip), io:format("compress_control: -> ~p -> ~p\n -> ~pn", [Expected, ZipOptions, ZipList]), @@ -698,19 +700,19 @@ test_compress_control(Dir, Files, ZipOptions, Expected) -> delete_files(lists:reverse(Names)), % Remove plain files before directories ok. - + verify_compression([{Name, Kind, _Filler} | Files], ZipList, OpenZip, ZipOptions, Expected) -> {Name2, BinSz} = case Kind of - dir -> + dir -> {Name ++ "/", 0}; - _ -> + _ -> {ok, {Name, Bin}} = zip:openzip_get(Name, OpenZip), {Name, size(Bin)} end, {Name2, {value, ZipFile}} = {Name2, lists:keysearch(Name2, #zip_file.name, ZipList)}, #zip_file{info = #file_info{size = InfoSz, type = InfoType}, comp_size = InfoCompSz} = ZipFile, - + Ext = filename:extension(Name), IsComp = is_compressed(Ext, Kind, ZipOptions), ExpComp = lists:member(Ext, Expected), @@ -757,3 +759,33 @@ extensions([H | T], Old) -> extensions([], Old) -> Old. +foldl(Config) -> + PrivDir = ?config(priv_dir, Config), + File = filename:join([PrivDir, "foldl.zip"]), + + FooBin = <<"FOO">>, + BarBin = <<"BAR">>, + Files = [{"foo", FooBin}, {"bar", BarBin}], + ?line {ok, {File, Bin}} = zip:create(File, Files, [memory]), + ZipFun = fun(N, I, B, Acc) -> [{N, B(), I()} | Acc] end, + ?line {ok, FileSpec} = zip:foldl(ZipFun, [], {File, Bin}), + ?line [{"bar", BarBin, #file_info{}}, {"foo", FooBin, #file_info{}}] = FileSpec, + ?line {ok, {File, Bin}} = zip:create(File, lists:reverse(FileSpec), [memory]), + ?line {foo_bin, FooBin} = + try + zip:foldl(fun("foo", _, B, _) -> throw(B()); (_, _, _, Acc) -> Acc end, [], {File, Bin}) + catch + throw:FooBin -> + {foo_bin, FooBin} + end, + ?line ok = file:write_file(File, Bin), + ?line {ok, FileSpec} = zip:foldl(ZipFun, [], File), + + ?line {error, einval} = zip:foldl(fun() -> ok end, [], File), + ?line {error, einval} = zip:foldl(ZipFun, [], 42), + ?line {error, einval} = zip:foldl(ZipFun, [], {File, 42}), + + ?line ok = file:delete(File), + ?line {error, enoent} = zip:foldl(ZipFun, [], File), + + ok. -- cgit v1.2.3 From 31b790bdf8442a7eee22bfad0887d42278ffc18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Mattsson?= Date: Mon, 1 Mar 2010 16:22:39 +0100 Subject: Add functions to create and extract escripts Both reltool and rebar needs to parse escripts. They are currently using an undocumented function called escript:foldl/3. It folds a function over all files in the body of an escript. If the body contains source code the function compiles it and the gives debug compiled beam code to the fold fun. If the body is an archive the fun is applied for all files in the archive. Instead of making the undocumented function public, the new functions escript:create/2 and escript:extract/2 has been introduced. Together with the new zip:foldl/3 function they have the same functionality as escript:foldl/3 in a more flexible and generic way. escript:foldl/3 should be removed as soon as reltool and rebar has been adopted to use the new functions. The simplest way for reltool and rebar to do this is to just copy the code from escript_SUITE:escript_foldl/3, which happens to provide a future compatible implementation of an emulated escript:foldl/3 function. I was quite hesitant when I introduced the compile_source option. It feels that it does not belong there but the alternative felt worse. The rationale for the compile_source option is that it is a bit cumbersome to compile the source code, as the source in most cases is partial. In order to do compile the source you need to know about some internals in escript. Without compile_source I think that these internals should be documented. Further you need to duplicate parts of the code. Without the compile_source option you need to first parse the source to forms, using an undocumented function in epp with an extended format of predefined macros which also is undocumented. Then you need to investigate the forms to see if you need to add an export form for main. When that is done you can run the rest of the compiler passes as usual. It is not so much code (60 lines or so) to write, but I do not want to urge people to write it. I actually wrote the code (see escript_SUITE:escript_foldl/3) before I decided to introduce the compile_source option. --- erts/doc/src/escript.xml | 217 ++++++++++++++++++--- lib/stdlib/src/escript.erl | 401 ++++++++++++++++++++++++++++++-------- lib/stdlib/test/escript_SUITE.erl | 396 ++++++++++++++++++++++++++++++------- 3 files changed, 845 insertions(+), 169 deletions(-) diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml index a89449df23..44c9a5ac68 100644 --- a/erts/doc/src/escript.xml +++ b/erts/doc/src/escript.xml @@ -31,7 +31,7 @@ escript Erlang scripting support -

provides support for running short Erlang programs +

escript provides support for running short Erlang programs without having to compile them first and an easy way to retrieve the command line arguments.

@@ -41,10 +41,10 @@ escript escript-flags script-name script-arg1 script-arg2... Run a script written in Erlang -

runs a script written in Erlang.

+

escript runs a script written in Erlang.

Here follows an example.

-$ cat factorial        
+$ cat factorial
 #!/usr/bin/env escript
 %% -*- erlang -*-
 %%! -smp enable -sname factorial -mnesia debug verbose
@@ -59,11 +59,11 @@ main([String]) ->
     end;
 main(_) ->
     usage().
-        
+
 usage() ->
     io:format("usage: factorial integer\n"),
     halt(1).
-        
+
 fac(0) -> 1;
 fac(N) -> N * fac(N-1).
 $ factorial 5
@@ -74,9 +74,8 @@ $ factorial five
 usage: factorial integer        

The header of the Erlang script in the example differs from a normal Erlang module. The first line is intended to be the - interpreter line, which invokes - . However if you invoke the - like this

+ interpreter line, which invokes escript. However if you + invoke the escript like this

 $ escript factorial 5        

the contents of the first line does not matter, but it @@ -93,13 +92,13 @@ $ escript factorial 5 %%! -smp enable -sname factorial -mnesia debug verbose

Such an argument line must start with %%! and the rest of the line will interpreted as arguments to the emulator.

-

If you know the location of the executable, the first - line can directly give the path to . For instance:

+

If you know the location of the escript executable, the first + line can directly give the path to escript. For instance:

 #!/usr/local/bin/escript        

As any other kind of scripts, Erlang scripts will not work on Unix platforms if the execution bit for the script file is not set. - (Use to turn on the execution bit.) + (Use chmod +x script-name to turn on the execution bit.)

The rest of the Erlang script file may either contain @@ -108,33 +107,33 @@ $ escript factorial 5

An Erlang script file must always contain the function main/1. When the script is run, the - function will be called with a list + main/1 function will be called with a list of strings representing the arguments given to the script (not changed or interpreted in any way).

-

If the function in the script returns successfully, +

If the main/1 function in the script returns successfully, the exit status for the script will be 0. If an exception is generated during execution, a short message will be printed and the script terminated with exit status 127.

-

To return your own non-zero exit code, call ; +

To return your own non-zero exit code, call halt(ExitCode); for instance:

 halt(1).
-

Call from your to - script to retrieve the pathname of the script (the pathname - is usually, but not always, absolute).

+

Call escript:script_name() + from your to script to retrieve the pathname of the script + (the pathname is usually, but not always, absolute).

If the file contains source code (as in the example above), it will be processed by the preprocessor epp. This means that you for example may use pre-defined macros (such as - ) as well as include directives like - the directive. For instance, use

+ ?MODULE) as well as include directives like + the -include_lib directive. For instance, use

--include_lib("kernel/include/file.hrl").        
+-include_lib("kernel/include/file.hrl").

to include the record definitions for the records used by the - function.

+ file:read_link_info/1 function.

The script will be checked for syntactic and semantic correctness before being run. If there are warnings (such as @@ -144,7 +143,7 @@ halt(1). 127.

Both the module declaration and the export declaration of - the function are optional.

+ the main/1 function are optional.

By default, the script will be interpreted. You can force it to be compiled by including the following line somewhere @@ -198,6 +197,180 @@ factorial 5 = 120 + + escript:create(FileOrBin, Sections) -> ok | {ok, binary()} | {error, term()} + Create an escript + + FileOrBin = filename() | 'binary' + Sections = [Header] Body | Body + Header = shebang | {shebang, Shebang} + | comment | {comment, Comment} + | {emu_args, EmuArgs} + Shebang = string() | 'default' | 'undefined' + Comment = string() | 'default' | 'undefined' + EmuArgs = string() | 'undefined' + Body = {source, SourceCode} + | {beam, BeamCode} + | {archive, ZipArchive} + SourceCode = BeamCode = ZipArchive = binary() + + +

The create/2 + function creates an escript from a list of sections. The + sections can be given in any order. An escript begins with an + optional Header followed by a mandatory Body. If + the header is present, it does always begin with a + shebang, possibly followed by a comment and + emu_args. The shebang defaults to + "/usr/bin/env escript". The comment defaults to + "This is an -*- erlang -*- file". The created escript + can either be returned as a binary or written to file.

+ +

As an example of how the function can be used, we create an + interpreted escript which uses emu_args to set some emulator + flag. In this case it happens to disable the smp_support. We + do also extract the different sections from the newly created + script:

+
+> Source = "%% Demo\nmain(_Args) ->\n    io:format(erlang:system_info(smp_support)).\n".
+"%% Demo\nmain(_Args) ->\n    io:format(erlang:system_info(smp_support)).\n"
+> io:format("~s\n", [Source]).
+%% Demo
+main(_Args) ->
+    io:format(erlang:system_info(smp_support)).
+
+ok
+> {ok, Bin} = escript:create(binary, [shebang, comment, {emu_args, "-smp disable"},
+                                      {source, list_to_binary(Source)}]).
+{ok,<<"#!/usr/bin/env escript\n%% This is an -*- erlang -*- file\n%%!-smp disabl"...>>}
+> file:write_file("demo.escript", Bin).
+ok
+> os:cmd("escript demo.escript").
+"false"
+> escript:extract("demo.escript", []).
+{ok,[{shebang,default}, {comment,default}, {emu_args,"-smp disable"},
+     {source,<<"%% Demo\nmain(_Args) ->\n    io:format(erlang:system_info(smp_su"...>>}]}
+	
+ +

An escript without header can be created like this:

+
+> file:write_file("demo.erl",
+                  ["%% demo.erl\n-module(demo).\n-export([main/1]).\n\n", Source]).
+ok
+> {ok, _, BeamCode} = compile:file("demo.erl", [binary, debug_info]).
+{ok,demo,
+    <<70,79,82,49,0,0,2,208,66,69,65,77,65,116,111,109,0,0,0,
+      79,0,0,0,9,4,100,...>>}
+> escript:create("demo.beam", [{beam, BeamCode}]).
+ok
+> escript:extract("demo.beam", []).
+{ok,[{shebang,undefined}, {comment,undefined}, {emu_args,undefined},
+     {beam,<<70,79,82,49,0,0,3,68,66,69,65,77,65,116,
+             111,109,0,0,0,83,0,0,0,9,...>>}]}
+> os:cmd("escript demo.beam").
+"true"
+
+

Here we create an archive script containing both Erlang + code as well as beam code. Then we iterate over all files in + the archive and collect their contents and some info about + them. +

+
+> {ok, SourceCode} = file:read_file("demo.erl").
+{ok,<<"%% demo.erl\n-module(demo).\n-export([main/1]).\n\n%% Demo\nmain(_Arg"...>>}
+> escript:create("demo.escript",
+                 [shebang,
+                  {archive, [{"demo.erl", SourceCode},
+                             {"demo.beam", BeamCode}], []}]).
+ok
+> {ok, [{shebang,default}, {comment,undefined}, {emu_args,undefined},
+     {archive, ArchiveBin}]} = escript:extract("demo.escript", []).
+{ok,[{shebang,default}, {comment,undefined}, {emu_args,undefined},
+     {{archive,<<80,75,3,4,20,0,0,0,8,0,118,7,98,60,105,
+                152,61,93,107,0,0,0,118,0,...>>}]}
+> file:write_file("demo.zip", ArchiveBin).
+ok
+> zip:foldl(fun(N, I, B, A) -> [{N, I(), B()} | A] end, [], "demo.zip").
+{ok,[{"demo.beam",
+      {file_info,748,regular,read_write,
+                 {{2010,3,2},{0,59,22}},
+                 {{2010,3,2},{0,59,22}},
+                 {{2010,3,2},{0,59,22}},
+                 54,1,0,0,0,0,0},
+      <<70,79,82,49,0,0,2,228,66,69,65,77,65,116,111,109,0,0,0,
+        83,0,0,...>>},
+     {"demo.erl",
+      {file_info,118,regular,read_write,
+                 {{2010,3,2},{0,59,22}},
+                 {{2010,3,2},{0,59,22}},
+                 {{2010,3,2},{0,59,22}},
+                 54,1,0,0,0,0,0},
+      <<"%% demo.erl\n-module(demo).\n-export([main/1]).\n\n%% Demo\nmain(_Arg"...>>}]}
+
+
+ + escript:extract(File, Options) -> {ok, Sections} | {error, term()} + Parses an escript and extracts its sections + + File = filename() + Options = [] | [compile_source] + Sections = Headers Body + Headers = {shebang, Shebang} + {comment, Comment} + {emu_args, EmuArgs} + Shebang = string() | 'default' | 'undefined' + Comment = string() | 'default' | 'undefined' + EmuArgs = string() | 'undefined' + Body = {source, SourceCode} + | {source, BeamCode} + | {beam, BeamCode} + | {archive, ZipArchive} + SourceCode = BeamCode = ZipArchive = binary() + + +

The extract/2 + function parses an escript and extracts its sections. This is + the reverse of create/2.

+ +

All sections are returned even if they do not exist in the + escript. If a particular section happens to have the same + value as the default value, the extracted value is set to the + atom default. If a section is missing, the extracted + value is set to the atom undefined.

+ +

The compile_source option only affects the result if + the escript contains source code. In that case the + Erlang code is automatically compiled and {source, + BeamCode} is returned instead of {source, + SourceCode}.

+ +
+> escript:create("demo.escript",
+                 [shebang, {archive, [{"demo.erl", SourceCode},
+                                      {"demo.beam", BeamCode}], []}]).
+ok
+> {ok, [{shebang,default}, {comment,undefined}, {emu_args,undefined},
+     {archive, ArchiveBin}]} =
+              escript:extract("demo.escript", []).
+{ok,[{{archive,<<80,75,3,4,20,0,0,0,8,0,118,7,98,60,105,
+                152,61,93,107,0,0,0,118,0,...>>}
+     {emu_args,undefined}]}
+	
+
+
+ + escript:script_name() -> File + Returns the name of an escript + + File = filename() + + +

The + script_name/0 function returns the name of the escript + being executed. If the function is invoked outside the context + of an escript, the behavior is undefined.

+
+
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index 5958a58d7c..bf32e15209 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -19,11 +19,17 @@ -module(escript). %% Useful functions that can be called from scripts. --export([script_name/0, foldl/3]). +-export([script_name/0, create/2, extract/2]). +-export([foldl/3]). % Undocumented function that will be removed %% Internal API. -export([start/0, start/1]). +-include_lib("kernel/include/file.hrl"). + +-define(SHEBANG, "/usr/bin/env escript"). +-define(COMMENT, "This is an -*- erlang -*- file"). + -record(state, {file, module, forms_or_bin, @@ -32,46 +38,247 @@ mode, exports_main, has_records}). - +-record(sections, {type, + shebang, + comment, + emu_args, + body}). +-record(extract_options, {compile_source}). + +-type shebang() :: string(). +-type comment() :: string(). +-type emu_args() :: string(). +-type escript_filename() :: string(). +-type filename() :: string(). +-type zip_file() :: + filename() + | {filename(), binary()} + | {filename(), binary(), #file_info{}}. +-type zip_create_option() :: term(). +-type section() :: + shebang + | {shebang, shebang()} + | comment + | {comment, comment()} + | {emu_args, emu_args()} + | {source, filename() | binary()} + | {beam, filename() | binary()} + | {archive, filename() | binary()} + | {archive, [zip_file()], [zip_create_option()]}. + +%% Create a complete escript file with both header and body +-spec create(escript_filename() | binary, [section()]) -> + ok | {ok, binary()} | {error, term()}. + +create(File, Options) when is_list(Options) -> + try + S = prepare(Options, #sections{}), + BinList = + [Section || Section <- [S#sections.shebang, + S#sections.comment, + S#sections.emu_args, + S#sections.body], + Section =/= undefined], + case File of + binary -> + {ok, list_to_binary(BinList)}; + _ -> + case file:write_file(File, BinList) of + ok -> + ok; + {error, Reason} -> + {error, {Reason, File}} + end + end + catch + throw:PrepareReason -> + {error, PrepareReason} + end. + +prepare([H | T], S) -> + case H of + {shebang, undefined} -> + prepare(T, S); + shebang -> + prepare(T, S#sections{shebang = "#!" ++ ?SHEBANG ++ "\n"}); + {shebang, default} -> + prepare(T, S#sections{shebang = "#!" ++ ?SHEBANG ++ "\n"}); + {shebang, Shebang} when is_list(Shebang) -> + prepare(T, S#sections{shebang = "#!" ++ Shebang ++ "\n"}); + {comment, undefined} -> + prepare(T, S); + comment -> + prepare(T, S#sections{comment = "%% " ++ ?COMMENT ++ "\n"}); + {comment, default} -> + prepare(T, S#sections{comment = "%% " ++ ?COMMENT ++ "\n"}); + {comment, Comment} when is_list(Comment) -> + prepare(T, S#sections{comment = "%% " ++ Comment ++ "\n"}); + {emu_args, undefined} -> + prepare(T, S); + {emu_args, Args} when is_list(Args) -> + prepare(T, S#sections{emu_args = "%%!" ++ Args ++ "\n"}); + {Type, File} when is_list(File) -> + case file:read_file(File) of + {ok, Bin} -> + prepare(T, S#sections{type = Type, body = Bin}); + {error, Reason} -> + throw({Reason, H}) + end; + {Type, Bin} when is_binary(Bin) -> + prepare(T, S#sections{type = Type, body = Bin}); + {archive = Type, ZipFiles, ZipOptions} + when is_list(ZipFiles), is_list(ZipOptions) -> + File = "dummy.zip", + case zip:create(File, ZipFiles, ZipOptions ++ [memory]) of + {ok, {File, ZipBin}} -> + prepare(T, S#sections{type = Type, body = ZipBin}); + {error, Reason} -> + throw({Reason, H}) + end; + _ -> + throw({badarg, H}) + end; +prepare([], #sections{body = undefined}) -> + throw(missing_body); +prepare([], #sections{type = Type} = S) + when Type =:= source; Type =:= beam; Type =:= archive -> + S; +prepare([], #sections{type = Type}) -> + throw({illegal_type, Type}); +prepare(BadOptions, _) -> + throw({badarg, BadOptions}). + +-type section_name() :: shebang | comment | emu_args | body . +-type extract_option() :: compile_source | {section, [section_name()]}. +-spec extract(filename(), [extract_option()]) -> {ok, [section()]} | {error, term()}. +extract(File, Options) when is_list(File), is_list(Options) -> + try + EO = parse_extract_options(Options, + #extract_options{compile_source = false}), + {HeaderSz, NextLineNo, Fd, Sections} = + parse_header(File, not EO#extract_options.compile_source), + Type = Sections#sections.type, + case {Type, EO#extract_options.compile_source} of + {source, true} -> + Bin = compile_source(Type, File, Fd, NextLineNo, HeaderSz); + {_, _} -> + ok = file:close(Fd), + case file:read_file(File) of + {ok, <<_Header:HeaderSz/binary, Bin/binary>>} -> + ok; + {error, ReadReason} -> + Bin = get_rid_of_compiler_warning, + throw(ReadReason) + end + end, + return_sections(Sections, Bin) + catch + throw:Reason -> + {error, Reason} + end. + +parse_extract_options([H | T], EO) -> + case H of + compile_source -> + EO2 = EO#extract_options{compile_source = true}, + parse_extract_options(T, EO2); + _ -> + throw({badarg, H}) + end; +parse_extract_options([], EO) -> + EO. + +compile_source(Type, File, Fd, NextLineNo, HeaderSz) -> + {text, _Module, Forms, _HasRecs, _Mode} = + do_parse_file(Type, File, Fd, NextLineNo, HeaderSz, false), + ok = file:close(Fd), + case compile:forms(Forms, [return_errors, debug_info]) of + {ok, _, BeamBin} -> + BeamBin; + {error, Errors, Warnings} -> + throw({compile, [{errors, format_errors(Errors)}, + {warnings, format_errors(Warnings)}]}) + end. + +format_errors(CompileErrors) -> + [lists:flatten([File, ":", integer_to_list(LineNo), ": ", + Mod:format_error(Error)]) || + {File, FileErrors} <- CompileErrors, + {LineNo, Mod, Error} <- FileErrors]. + +return_sections(S, Bin) -> + {ok, [normalize_section(shebang, S#sections.shebang), + normalize_section(comment, S#sections.comment), + normalize_section(emu_args, S#sections.emu_args), + normalize_section(S#sections.type, Bin)]}. + +normalize_section(Name, undefined) -> + {Name, undefined}; +normalize_section(shebang, "#!" ++ Chars) -> + Chopped = string:strip(Chars, right, $\n), + Stripped = string:strip(Chopped, both), + if + Stripped =:= ?SHEBANG -> + {shebang, default}; + true -> + {shebang, Stripped} + end; +normalize_section(comment, Chars) -> + Chopped = string:strip(Chars, right, $\n), + Stripped = string:strip(string:strip(Chopped, left, $%), both), + if + Stripped =:= ?COMMENT -> + {comment, default}; + true -> + {comment, Stripped} + end; +normalize_section(emu_args, "%%!" ++ Chars) -> + Chopped = string:strip(Chars, right, $\n), + Stripped = string:strip(Chopped, both), + {emu_args, Stripped}; +normalize_section(Name, Chars) -> + {Name, Chars}. + +-spec script_name() -> string(). script_name() -> [ScriptName|_] = init:get_plain_arguments(), ScriptName. %% Apply Fun(Name, GetInfo, GetBin, Acc) for each file in the escript. -%% +%% %% Fun/2 must return a new accumulator which is passed to the next call. %% The function returns the final value of the accumulator. Acc0 is %% returned if the escript contain an empty archive. -%% +%% %% GetInfo/0 is a fun that returns a #file_info{} record for the file. %% GetBin/0 is a fun that returns a the contents of the file as a binary. %% %% An escript may contain erlang code, beam code or an archive: %% -%% archive - the Fun/2 will be applied for each file in the archive -%% beam - the Fun/2 will be applied once and GetInfo/0 returns the file +%% archive - the Fun/4 will be applied for each file in the archive +%% beam - the Fun/4 will be applied once and GetInfo/0 returns the file %% info for the (entire) escript file -%% erl - the Fun/2 will be applied once, GetInfo/0 returns the file +%% erl - the Fun/4 will be applied once, GetInfo/0 returns the file %% info for the (entire) escript file and the GetBin returns %% the compiled beam code -%%-spec foldl(fun((string(), -%% fun(() -> #file_info()), -%% fun(() -> binary() -> term()), -%% term()) -> term()), -%% term(), -%% string()). +-spec foldl(fun((string(), + fun(() -> #file_info{}), + fun(() -> binary()), + term()) -> term()), + term(), + string()) -> {ok, term()} | {error, term()}. foldl(Fun, Acc0, File) when is_function(Fun, 4) -> case parse_file(File, false) of {text, _, Forms, _HasRecs, _Mode} when is_list(Forms) -> - GetInfo = fun() -> file:read_file_info(File) end, + GetInfo = fun() -> {ok, FI} = file:read_file_info(File), FI end, GetBin = fun() -> case compile:forms(Forms, [return_errors, debug_info]) of {ok, _, BeamBin} -> BeamBin; {error, _Errors, _Warnings} -> - fatal("There were compilation errors.") + throw("There were compilation errors.") end end, try @@ -81,7 +288,7 @@ foldl(Fun, Acc0, File) when is_function(Fun, 4) -> {error, Reason} end; {beam, _, BeamBin, _HasRecs, _Mode} when is_binary(BeamBin) -> - GetInfo = fun() -> file:read_file_info(File) end, + GetInfo = fun() -> {ok, FI} = file:read_file_info(File), FI end, GetBin = fun() -> BeamBin end, try {ok, Fun(".", GetInfo, GetBin, Acc0)} @@ -110,11 +317,13 @@ foldl(Fun, Acc0, File) when is_function(Fun, 4) -> %% Internal API. %% +-spec start() -> no_return(). start() -> start([]). +-spec start([string()]) -> no_return(). start(EscriptOptions) -> - try + try %% Commands run using -run or -s are run in a process %% trap_exit set to false. Because this behaviour is %% surprising for users of escript, make sure to reset @@ -143,11 +352,11 @@ parse_and_run(File, Args, Options) -> parse_file(File, CheckOnly), Mode2 = case lists:member("d", Options) of - true -> + true -> debug; false -> case lists:member("c", Options) of - true -> + true -> compile; false -> case lists:member("i", Options) of @@ -177,7 +386,7 @@ parse_and_run(File, Args, Options) -> _Other -> fatal("There were compilation errors.") end - end; + end; is_binary(FormsOrBin) -> case Source of archive -> @@ -190,11 +399,13 @@ parse_and_run(File, Args, Options) -> true -> my_halt(0); false -> - Text = lists:concat(["Function ", Module, ":main/1 is not exported"]), + Text = lists:concat(["Function ", Module, + ":main/1 is not exported"]), fatal(Text) end; _ -> - Text = lists:concat(["Cannot load module ", Module, " from archive"]), + Text = lists:concat(["Cannot load module ", Module, + " from archive"]), fatal(Text) end; ok -> @@ -212,7 +423,7 @@ parse_and_run(File, Args, Options) -> run -> {module, Module} = code:load_binary(Module, File, FormsOrBin), run(Module, Args); - debug -> + debug -> [Base | Rest] = lists:reverse(filename:split(File)), Base2 = filename:basename(Base, code:objfile_extension()), Rest2 = @@ -222,8 +433,8 @@ parse_and_run(File, Args, Options) -> end, SrcFile = filename:join(lists:reverse([Base2 ++ ".erl" | Rest2])), debug(Module, {Module, SrcFile, File, FormsOrBin}, Args) - end - end + end + end end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -231,25 +442,19 @@ parse_and_run(File, Args, Options) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% parse_file(File, CheckOnly) -> - S = #state{file = File, - n_errors = 0, - mode = interpret, - exports_main = false, - has_records = false}, - {ok, Fd} = - case file:open(File, [read]) of - {ok, Fd0} -> - {ok, Fd0}; - {error, R} -> - fatal(lists:concat([file:format_error(R), ": '", File, "'"])) - end, - {HeaderSz, StartLine, ScriptType} = skip_header(Fd, 1), + {HeaderSz, NextLineNo, Fd, Sections} = + parse_header(File, false), + do_parse_file(Sections#sections.type, + File, Fd, NextLineNo, HeaderSz, CheckOnly). + +do_parse_file(Type, File, Fd, NextLineNo, HeaderSz, CheckOnly) -> + S = initial_state(File), #state{mode = Mode, source = Source, module = Module, forms_or_bin = FormsOrBin, has_records = HasRecs} = - case ScriptType of + case Type of archive -> %% Archive file ok = file:close(Fd), @@ -260,51 +465,93 @@ parse_file(File, CheckOnly) -> parse_beam(S, File, HeaderSz, CheckOnly); source -> %% Source code - parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) + parse_source(S, File, Fd, NextLineNo, HeaderSz, CheckOnly) end, {Source, Module, FormsOrBin, HasRecs, Mode}. +initial_state(File) -> + #state{file = File, + n_errors = 0, + mode = interpret, + exports_main = false, + has_records = false}. + %% Skip header and make a heuristic guess about the script type -skip_header(P, LineNo) -> +parse_header(File, KeepFirst) -> + LineNo = 1, + {ok, Fd} = + case file:open(File, [read]) of + {ok, Fd0} -> + {ok, Fd0}; + {error, R} -> + fatal(lists:concat([file:format_error(R), ": '", File, "'"])) + end, + %% Skip shebang on first line - {ok, HeaderSz0} = file:position(P, cur), - Line1 = get_line(P), + {ok, HeaderSz0} = file:position(Fd, cur), + Line1 = get_line(Fd), case classify_line(Line1) of shebang -> - find_first_body_line(P, LineNo); + find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, + #sections{shebang = Line1}); archive -> - {HeaderSz0, LineNo, archive}; + {HeaderSz0, LineNo, Fd, + #sections{type = archive}}; beam -> - {HeaderSz0, LineNo, beam}; + {HeaderSz0, LineNo, Fd, + #sections{type = beam}}; _ -> - find_first_body_line(P, LineNo) + find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, + #sections{}) end. -find_first_body_line(P, LineNo) -> - {ok, HeaderSz1} = file:position(P, cur), +find_first_body_line(Fd, HeaderSz0, LineNo, KeepFirst, Sections) -> + {ok, HeaderSz1} = file:position(Fd, cur), %% Look for special comment on second line - Line2 = get_line(P), - {ok, HeaderSz2} = file:position(P, cur), + Line2 = get_line(Fd), + {ok, HeaderSz2} = file:position(Fd, cur), case classify_line(Line2) of emu_args -> %% Skip special comment on second line - Line3 = get_line(P), - {HeaderSz2, LineNo + 2, guess_type(Line3)}; - _ -> + Line3 = get_line(Fd), + {HeaderSz2, LineNo + 2, Fd, + Sections#sections{type = guess_type(Line3), + comment = undefined, + emu_args = Line2}}; + Line2Type -> %% Look for special comment on third line - Line3 = get_line(P), - {ok, HeaderSz3} = file:position(P, cur), - case classify_line(Line3) of - emu_args -> + Line3 = get_line(Fd), + {ok, HeaderSz3} = file:position(Fd, cur), + Line3Type = classify_line(Line3), + if + Line3Type =:= emu_args -> %% Skip special comment on third line - Line4 = get_line(P), - {HeaderSz3, LineNo + 3, guess_type(Line4)}; - _ -> + Line4 = get_line(Fd), + {HeaderSz3, LineNo + 3, Fd, + Sections#sections{type = guess_type(Line4), + comment = Line2, + emu_args = Line3}}; + Sections#sections.shebang =:= undefined, + KeepFirst =:= true -> + %% No shebang. Use the entire file + {HeaderSz0, LineNo, Fd, + Sections#sections{type = guess_type(Line2)}}; + Sections#sections.shebang =:= undefined -> + %% No shebang. Skip the first line + {HeaderSz1, LineNo, Fd, + Sections#sections{type = guess_type(Line2)}}; + Line2Type =:= comment -> + %% Skip shebang on first line and comment on second + {HeaderSz2, LineNo + 2, Fd, + Sections#sections{type = guess_type(Line3), + comment = Line2}}; + true -> %% Just skip shebang on first line - {HeaderSz1, LineNo + 1, guess_type(Line2)} + {HeaderSz1, LineNo + 1, Fd, + Sections#sections{type = guess_type(Line2)}} end end. - + classify_line(Line) -> case Line of [$\#, $\! | _] -> @@ -313,8 +560,10 @@ classify_line(Line) -> archive; [$F, $O, $R, $1 | _] -> beam; - [$\%, $\%, $\! | _] -> + [$%, $%, $\! | _] -> emu_args; + [$% | _] -> + comment; _ -> undefined end. @@ -336,8 +585,8 @@ get_line(P) -> parse_archive(S, File, HeaderSz) -> case file:read_file(File) of - {ok, <<_FirstLine:HeaderSz/binary, Bin/binary>>} -> - Mod = + {ok, <<_Header:HeaderSz/binary, Bin/binary>>} -> + Mod = case init:get_argument(escript) of {ok, [["main", M]]} -> %% Use explicit module name @@ -345,14 +594,14 @@ parse_archive(S, File, HeaderSz) -> _ -> %% Use escript name without extension as module name RevBase = lists:reverse(filename:basename(File)), - RevBase2 = + RevBase2 = case lists:dropwhile(fun(X) -> X =/= $. end, RevBase) of [$. | Rest] -> Rest; [] -> RevBase end, list_to_atom(lists:reverse(RevBase2)) end, - + S#state{source = archive, mode = run, module = Mod, @@ -365,7 +614,7 @@ parse_archive(S, File, HeaderSz) -> parse_beam(S, File, HeaderSz, CheckOnly) -> - {ok, <<_FirstLine:HeaderSz/binary, Bin/binary>>} = + {ok, <<_Header:HeaderSz/binary, Bin/binary>>} = file:read_file(File), case beam_lib:chunks(Bin, [exports]) of {ok, {Module, [{exports, Exports}]}} -> @@ -399,7 +648,7 @@ parse_source(S, File, Fd, StartLine, HeaderSz, CheckOnly) -> {ok, FileForm} = epp:parse_erl_form(Epp), OptModRes = epp:parse_erl_form(Epp), S2 = S#state{source = text, module = Module}, - S3 = + S3 = case OptModRes of {ok, {attribute,_, module, M} = Form} -> epp_parse_file(Epp, S2#state{module = M}, [Form, FileForm]); @@ -448,12 +697,12 @@ check_source(S, CheckOnly) -> pre_def_macros(File) -> {MegaSecs, Secs, MicroSecs} = erlang:now(), - Replace = fun(Char) -> + Replace = fun(Char) -> case Char of $\. -> $\_; _ -> Char end - end, + end, CleanBase = lists:map(Replace, filename:basename(File)), ModuleStr = CleanBase ++ "__" ++ @@ -642,8 +891,8 @@ eval_exprs([E|Es], Bs0, Lf, Ef, RBs) -> eval_exprs(Es, Bs, Lf, Ef, RBs). format_exception(Class, Reason) -> - PF = fun(Term, I) -> - io_lib:format("~." ++ integer_to_list(I) ++ "P", [Term, 50]) + PF = fun(Term, I) -> + io_lib:format("~." ++ integer_to_list(I) ++ "P", [Term, 50]) end, StackTrace = erlang:get_stacktrace(), StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end, @@ -651,7 +900,7 @@ format_exception(Class, Reason) -> fatal(Str) -> throw(Str). - + my_halt(Reason) -> case process_info(group_leader(), status) of {_,waiting} -> @@ -675,7 +924,7 @@ hidden_apply(App, M, F, Args) -> Arity = length(Args), Text = io_lib:format("Call to ~w:~w/~w in application ~w failed.\n", [M, F, Arity, App]), - fatal(Text); + fatal(Text); Stk -> erlang:raise(error, undef, Stk) end diff --git a/lib/stdlib/test/escript_SUITE.erl b/lib/stdlib/test/escript_SUITE.erl index f36ae34633..77fd190e45 100644 --- a/lib/stdlib/test/escript_SUITE.erl +++ b/lib/stdlib/test/escript_SUITE.erl @@ -22,16 +22,20 @@ init_per_testcase/2, fin_per_testcase/2, basic/1, - errors/1, + errors/1, strange_name/1, emulator_flags/1, module_script/1, beam_script/1, archive_script/1, - epp/1 + epp/1, + create_and_extract/1, + foldl/1, + verify_sections/3 ]). -include("test_server.hrl"). +-include_lib("kernel/include/file.hrl"). all(suite) -> [ @@ -42,7 +46,9 @@ all(suite) -> module_script, beam_script, archive_script, - epp + epp, + create_and_extract, + foldl ]. init_per_testcase(_Case, Config) -> @@ -68,11 +74,11 @@ basic(Config) when is_list(Config) -> ?line run(Dir, "factorial_warning 20", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\n" "factorial 20 = 2432902008176640000\nExitCode:0">>]), - ?line run(Dir, "-s", "factorial_warning", + ?line run_with_opts(Dir, "-s", "factorial_warning", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]), - ?line run(Dir, "-s -i", "factorial_warning", + ?line run_with_opts(Dir, "-s -i", "factorial_warning", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]), - ?line run(Dir, "-c -s", "factorial_warning", + ?line run_with_opts(Dir, "-c -s", "factorial_warning", [data_dir,<<"factorial_warning:12: Warning: function bar/0 is unused\nExitCode:0">>]), ?line run(Dir, "filesize "++filename:join(?config(data_dir, Config),"filesize"), [data_dir,<<"filesize:11: Warning: function id/1 is unused\n324\nExitCode:0">>]), @@ -100,7 +106,7 @@ errors(Config) when is_list(Config) -> [data_dir,<<"lint_error:6: function main/1 already defined\n">>, data_dir,"lint_error:8: variable 'ExitCode' is unbound\n", <<"escript: There were compilation errors.\nExitCode:127">>]), - ?line run(Dir, "-s", "lint_error", + ?line run_with_opts(Dir, "-s", "lint_error", [data_dir,<<"lint_error:6: function main/1 already defined\n">>, data_dir,"lint_error:8: variable 'ExitCode' is unbound\n", <<"escript: There were compilation errors.\nExitCode:127">>]), @@ -140,31 +146,31 @@ module_script(Config) when is_list(Config) -> OrigFile = filename:join([Data,"emulator_flags"]), {ok, OrigBin} = file:read_file(OrigFile), ?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"), - ?line {ok, OrigFI} = file:read_file_info(OrigFile), + ?line {ok, OrigFI} = file:read_file_info(OrigFile), %% Write source file Priv = ?config(priv_dir, Config), Dir = filename:absname(Priv), % Get rid of trailing slash. Base = "module_script", ErlFile = filename:join([Priv, Base ++ ".erl"]), - ErlCode = ["-module(", Base, ").\n", + ErlCode = ["\n-module(", Base, ").\n", "-export([main/1]).\n\n", string:join(Source, "\n"), "\n"], ?line ok = file:write_file(ErlFile, ErlCode), - + %%%%%%% %% Create and run scripts without emulator flags %% With shebang NoArgsBase = Base ++ "_no_args_with_shebang", NoArgsFile = filename:join([Priv, NoArgsBase]), - ?line ok = file:write_file(NoArgsFile, + ?line ok = file:write_file(NoArgsFile, [Shebang, "\n", ErlCode]), ?line ok = file:write_file_info(NoArgsFile, OrigFI), - - ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3", + + ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -172,7 +178,7 @@ module_script(Config) when is_list(Config) -> "unknown:[]\n" "ExitCode:0">>]), - ?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -183,33 +189,33 @@ module_script(Config) when is_list(Config) -> %% Without shebang NoArgsBase2 = Base ++ "_no_args_without_shebang", NoArgsFile2 = filename:join([Priv, NoArgsBase2]), - ?line ok = file:write_file(NoArgsFile2, + ?line ok = file:write_file(NoArgsFile2, ["Something else than shebang!!!", "\n", ErlCode]), ?line ok = file:write_file_info(NoArgsFile2, OrigFI), - - ?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", + + ?line run_with_opts(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" "ERL_FLAGS=false\n" "unknown:[]\n" "ExitCode:0">>]), - + %% Plain module without header NoArgsBase3 = Base ++ "_no_args_without_header", NoArgsFile3 = filename:join([Priv, NoArgsBase3]), ?line ok = file:write_file(NoArgsFile3, [ErlCode]), ?line ok = file:write_file_info(NoArgsFile3, OrigFI), - - ?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", + + ?line run_with_opts(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" "ERL_FLAGS=false\n" "unknown:[]\n" "ExitCode:0">>]), - + %%%%%%% %% Create and run scripts with emulator flags @@ -217,12 +223,12 @@ module_script(Config) when is_list(Config) -> ArgsBase = Base ++ "_args_with_shebang", ArgsFile = filename:join([Priv, ArgsBase]), ?line ok = file:write_file(ArgsFile, - [Shebang, "\n", + [Shebang, "\n", Mode, "\n", Flags, "\n", ErlCode]), - ?line ok = file:write_file_info(ArgsFile, OrigFI), - + ?line ok = file:write_file_info(ArgsFile, OrigFI), + ?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[{nostick,[]}]\n" @@ -242,32 +248,32 @@ beam_script(Config) when is_list(Config) -> OrigFile = filename:join([Data,"emulator_flags"]), {ok, OrigBin} = file:read_file(OrigFile), ?line [Shebang, Mode, Flags | Source] = string:tokens(binary_to_list(OrigBin), "\n"), - ?line {ok, OrigFI} = file:read_file_info(OrigFile), + ?line {ok, OrigFI} = file:read_file_info(OrigFile), %% Write source file Priv = ?config(priv_dir, Config), Dir = filename:absname(Priv), % Get rid of trailing slash. Base = "beam_script", ErlFile = filename:join([Priv, Base ++ ".erl"]), - ?line ok = file:write_file(ErlFile, - ["-module(", Base, ").\n", + ?line ok = file:write_file(ErlFile, + ["\n-module(", Base, ").\n", "-export([main/1]).\n\n", string:join(Source, "\n"), "\n"]), %% Compile the code ?line {ok, _Mod, BeamCode} = compile:file(ErlFile, [binary]), - + %%%%%%% %% Create and run scripts without emulator flags %% With shebang NoArgsBase = Base ++ "_no_args_with_shebang", NoArgsFile = filename:join([Priv, NoArgsBase]), - ?line ok = file:write_file(NoArgsFile, + ?line ok = file:write_file(NoArgsFile, [Shebang, "\n", BeamCode]), - ?line ok = file:write_file_info(NoArgsFile, OrigFI), + ?line ok = file:write_file_info(NoArgsFile, OrigFI), ?line run(Dir, NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" @@ -277,7 +283,7 @@ beam_script(Config) when is_list(Config) -> "unknown:[]\n" "ExitCode:0">>]), - ?line run(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -288,12 +294,12 @@ beam_script(Config) when is_list(Config) -> %% Without shebang NoArgsBase2 = Base ++ "_no_args_without_shebang", NoArgsFile2 = filename:join([Priv, NoArgsBase2]), - ?line ok = file:write_file(NoArgsFile2, + ?line ok = file:write_file(NoArgsFile2, ["Something else than shebang!!!", "\n", BeamCode]), - ?line ok = file:write_file_info(NoArgsFile2, OrigFI), + ?line ok = file:write_file_info(NoArgsFile2, OrigFI), - ?line run(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase2 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -305,9 +311,9 @@ beam_script(Config) when is_list(Config) -> NoArgsBase3 = Base ++ "_no_args_without_header", NoArgsFile3 = filename:join([Priv, NoArgsBase3]), ?line ok = file:write_file(NoArgsFile3, [BeamCode]), - ?line ok = file:write_file_info(NoArgsFile3, OrigFI), + ?line ok = file:write_file_info(NoArgsFile3, OrigFI), - ?line run(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", + ?line run_with_opts(Dir, "", NoArgsBase3 ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[]\n" "mnesia:[]\n" @@ -322,12 +328,12 @@ beam_script(Config) when is_list(Config) -> ArgsBase = Base ++ "_args", ArgsFile = filename:join([Priv, ArgsBase]), ?line ok = file:write_file(ArgsFile, - [Shebang, "\n", + [Shebang, "\n", Mode, "\n", Flags, "\n", BeamCode]), - ?line ok = file:write_file_info(ArgsFile, OrigFI), - + ?line ok = file:write_file_info(ArgsFile, OrigFI), + ?line run(Dir, ArgsBase ++ " -arg1 arg2 arg3", [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "nostick:[{nostick,[]}]\n" @@ -356,13 +362,13 @@ archive_script(Config) when is_list(Config) -> ?line ok = compile_app(TopDir, "archive_script_dict"), ?line ok = compile_app(TopDir, "archive_script_dummy"), ?line {ok, MainFiles} = file:list_dir(TopDir), - ?line ok = compile_files(MainFiles, TopDir, TopDir), - + ?line ok = compile_files(MainFiles, TopDir, TopDir), + %% Create the archive {ok, TopFiles} = file:list_dir(TopDir), ?line {ok, {_, ArchiveBin}} = zip:create(Archive, TopFiles, [memory, {compress, []}, {cwd, TopDir}]), - + %% Read the source script OrigFile = filename:join([DataDir, "emulator_flags"]), {ok, OrigBin} = file:read_file(OrigFile), @@ -371,73 +377,73 @@ archive_script(Config) when is_list(Config) -> Flags = "%%! -archive_script_dict foo bar" " -archive_script_dict foo" " -archive_script_dummy bar", - ?line {ok, OrigFI} = file:read_file_info(OrigFile), - + ?line {ok, OrigFI} = file:read_file_info(OrigFile), + %%%%%%% %% Create and run scripts without emulator flags - MainBase = "archive_script_main", - MainScript = filename:join([PrivDir, MainBase]), + MainBase = "archive_script_main", + MainScript = filename:join([PrivDir, MainBase]), %% With shebang - ?line ok = file:write_file(MainScript, + ?line ok = file:write_file(MainScript, [Shebang, "\n", Flags, "\n", ArchiveBin]), - ?line ok = file:write_file_info(MainScript, OrigFI), - + ?line ok = file:write_file_info(MainScript, OrigFI), + ?line run(PrivDir, MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n" "dummy:[{archive_script_dummy,[\"bar\"]}]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), - ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + ?line run_with_opts(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[{archive_script_dict,[\"foo\",\"bar\"]},{archive_script_dict,[\"foo\"]}]\n" "dummy:[{archive_script_dummy,[\"bar\"]}]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), - + ?line ok = file:rename(MainScript, MainScript ++ "_with_shebang"), %% Without shebang (no flags) - ?line ok = file:write_file(MainScript, + ?line ok = file:write_file(MainScript, ["Something else than shebang!!!", "\n", ArchiveBin]), - ?line ok = file:write_file_info(MainScript, OrigFI), - - ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + ?line ok = file:write_file_info(MainScript, OrigFI), + + ?line run_with_opts(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[]\n" "dummy:[]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), ?line ok = file:rename(MainScript, MainScript ++ "_without_shebang"), - + %% Plain archive without header (no flags) - + ?line ok = file:write_file(MainScript, [ArchiveBin]), - ?line ok = file:write_file_info(MainScript, OrigFI), - - ?line run(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", - [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" + ?line ok = file:write_file_info(MainScript, OrigFI), + + ?line run_with_opts(PrivDir, "", MainBase ++ " -arg1 arg2 arg3", + [<<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n" "dict:[]\n" "dummy:[]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), ?line ok = file:rename(MainScript, MainScript ++ "_without_header"), - + %%%%%%% %% Create and run scripts with emulator flags AltBase = "archive_script_alternate_main", AltScript = filename:join([PrivDir, AltBase]), - ?line ok = file:write_file(AltScript, + ?line ok = file:write_file(AltScript, [Shebang, "\n", Mode, "\n", Flags, " -escript main archive_script_main2\n", ArchiveBin]), - ?line ok = file:write_file_info(AltScript, OrigFI), + ?line ok = file:write_file_info(AltScript, OrigFI), ?line run(PrivDir, AltBase ++ " -arg1 arg2 arg3", [<<"main2:[\"-arg1\",\"arg2\",\"arg3\"]\n" @@ -445,7 +451,7 @@ archive_script(Config) when is_list(Config) -> "dummy:[{archive_script_dummy,[\"bar\"]}]\n" "priv:{ok,<<\"Some private data...\\n\">>}\n" "ExitCode:0">>]), - + ok. compile_app(TopDir, AppName) -> @@ -482,6 +488,254 @@ epp(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +create_and_extract(Config) when is_list(Config) -> + {NewFile, FileInfo, + EmuArg, Source, + _ErlBase, ErlCode, + _BeamBase, BeamCode, + ArchiveBin} = + prepare_creation("create_and_extract", Config), + + Bodies = + [[{source, ErlCode}], + [{beam, BeamCode}], + [{archive, ArchiveBin}]], + + %% Verify all combinations of scripts with shebangs + [verify_sections(NewFile, FileInfo, S ++ C ++ E ++ B) || + S <- [[{shebang, default}], + [{shebang, "/usr/bin/env escript"}]], + C <- [[], + [{comment, undefined}], + [{comment, default}], + [{comment, "This is a nonsense comment"}]], + E <- [[], + [{emu_args, undefined}], + [{emu_args, EmuArg}]], + B <- [[{source, Source}] | Bodies]], + + %% Verify all combinations of scripts without shebangs + [verify_sections(NewFile, FileInfo, S ++ C ++ E ++ B) || + S <- [[], [{shebang, undefined}]], + C <- [[], [{comment, undefined}]], + E <- [[], [{emu_args, undefined}]], + B <- Bodies], + + %% Verify the compile_source option + file:delete(NewFile), + ?line ok = escript:create(NewFile, [{source, Source}]), + ?line {ok, [_, _, _, {source, Source}]} = escript:extract(NewFile, []), + ?line {ok, [_, _, _, {source, BeamCode2}]} = + escript:extract(NewFile, [compile_source]), + verify_sections(NewFile, FileInfo, + [{shebang, default}, + {comment, default}, + {beam, BeamCode2}]), + + file:delete(NewFile), + ok. + +prepare_creation(Base, Config) -> + %% Read the source + PrivDir = ?config(priv_dir, Config), + DataDir = ?config(data_dir, Config), + OrigFile = filename:join([DataDir,"emulator_flags"]), + ?line {ok, FileInfo} = file:read_file_info(OrigFile), + NewFile = filename:join([PrivDir, Base]), + ?line {ok, [{shebang, default}, + {comment, _}, + {emu_args, EmuArg}, + {source, Source}]} = + escript:extract(OrigFile, []), + + %% Compile the code + ErlFile = NewFile ++ ".erl", + ErlCode = list_to_binary(["\n-module(", Base, ").\n", + "-export([main/1]).\n\n", + Source, "\n\n"]), + ?line ok = file:write_file(ErlFile, ErlCode), + + %% Compile the code + ?line {ok, _Mod, BeamCode} = + compile:file(ErlFile, [binary, debug_info]), + + %% Create an archive + ?line {ok, {_, ArchiveBin}} = + zip:create("dummy_archive_name", + [{Base ++ ".erl", ErlCode}, + {Base ++ ".beam", BeamCode}], + [{compress, []}, memory]), + {NewFile, FileInfo, + EmuArg, Source, + Base ++ ".erl", ErlCode, + Base ++ ".beam", BeamCode, + ArchiveBin}. + +verify_sections(File, FileInfo, Sections) -> + io:format("~p:verify_sections(\n\t~p,\n\t~p,\n\t~p).\n", + [?MODULE, File, FileInfo, Sections]), + + %% Create + file:delete(File), + ?line ok = escript:create(File, Sections), + ?line ok = file:write_file_info(File, FileInfo), + + %% Run + Dir = filename:absname(filename:dirname(File)), + Base = filename:basename(File), + + HasArg = fun(Tag) -> + case lists:keysearch(Tag, 1, Sections) of + false -> false; + {value, {_, undefined}} -> false; + {value, _} -> true + end + end, + ExpectedMain = <<"main:[\"-arg1\",\"arg2\",\"arg3\"]\n">>, + ExpectedOutput = + case HasArg(emu_args) of + true -> + <<"nostick:[{nostick,[]}]\n" + "mnesia:[{mnesia,[\"dir\",\"a/directory\"]},{mnesia,[\"debug\",\"verbose\"]}]\n" + "ERL_FLAGS=false\n" + "unknown:[]\n" + "ExitCode:0">>; + false -> + <<"nostick:[]\nmnesia:[]\nERL_FLAGS=false\nunknown:[]\nExitCode:0">> + end, + + InputArgs = Base ++ " -arg1 arg2 arg3", + Expected = <>, + case HasArg(shebang) of + true -> + ?line run(Dir, InputArgs, [Expected]); + false -> + ?line run_with_opts(Dir, [], InputArgs, [Expected]) + end, + + %% Verify + ?line {ok, Bin} = escript:create(binary, Sections), + ?line {ok, Read} = file:read_file(File), + ?line Bin = Read, % Assert + + Normalized = normalize_sections(Sections), + ?line {ok, Extracted} = escript:extract(File, []), + io:format("Normalized; ~p\n", [Normalized]), + io:format("Extracted ; ~p\n", [Extracted]), + ?line Normalized = Extracted, % Assert + ok. + +normalize_sections(Sections) -> + AtomToTuple = + fun(Val) -> + if + is_atom(Val) -> {Val, default}; + true -> Val + end + end, + case lists:map(AtomToTuple, [{K, V} || {K, V} <- Sections, V =/= undefined]) of + [{shebang, Shebang} | Rest] -> + [{shebang, Shebang} | + case Rest of + [{comment, Comment} | Rest2] -> + [{comment, Comment} | + case Rest2 of + [{emu_args, EmuArgs}, Body] -> + [{emu_args, EmuArgs}, Body]; + [Body] -> + [{emu_args, undefined}, Body] + end + ]; + [{emu_args, EmuArgs}, Body] -> + [{comment, undefined}, {emu_args, EmuArgs}, Body]; + [Body] -> + [{comment, undefined}, {emu_args, undefined}, Body] + end + ]; + [Body] -> + [{shebang, undefined}, {comment, undefined}, {emu_args, undefined}, Body] + end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +foldl(Config) when is_list(Config) -> + {NewFile, _FileInfo, + _EmuArg, _Source, + ErlBase, ErlCode, + BeamBase, _BeamCode, + ArchiveBin} = + prepare_creation("foldl", Config), + + Collect = fun(Name, GetInfo, GetBin, Acc) -> + [{Name, GetInfo(), GetBin()} | Acc] + end, + + %% Get line numbers and the file attribute right + SourceFile = NewFile ++ ".erl", + <<_:1/binary, ErlCode2/binary>> = ErlCode, + ?line ok = file:write_file(SourceFile, ErlCode2), + ?line {ok, _Mod, BeamCode} = + compile:file(SourceFile, [binary, debug_info]), + + %% Verify source script + ?line ok = escript:create(SourceFile, [{source, ErlCode}]), + ?line {ok, [{".", _, BeamCode2}]} + = escript_foldl(Collect, [], SourceFile), + + ?line {ok, Abstr} = beam_lib:chunks(BeamCode, [abstract_code]), + ?line {ok, Abstr2} = beam_lib:chunks(BeamCode2, [abstract_code]), + %% io:format("abstr1=~p\n", [Abstr]), + %% io:format("abstr2=~p\n", [Abstr2]), + ?line Abstr = Abstr2, % Assert + + %% Verify beam script + ?line ok = escript:create(NewFile, [{beam, BeamCode}]), + ?line {ok, [{".", _, BeamCode}]} + = escript_foldl(Collect, [], NewFile), + + %% Verify archive scripts + ?line ok = escript:create(NewFile, [{archive, ArchiveBin}]), + ?line {ok, [{BeamBase, #file_info{}, _}, + {ErlBase, #file_info{}, _}]} + = escript_foldl(Collect, [], NewFile), + + ArchiveFiles = [{ErlBase, ErlCode}, {BeamBase, BeamCode}], + ?line ok = escript:create(NewFile, [{archive, ArchiveFiles, []}]), + ?line {ok, [{BeamBase, _, _}, + {ErlBase, _, _}]} + = escript_foldl(Collect, [], NewFile), + + ok. + +escript_foldl(Fun, Acc, File) -> + code:ensure_loaded(zip), + case erlang:function_exported(zip, foldl, 3) of + true -> + emulate_escript_foldl(Fun, Acc, File); + false -> + escript:foldl(Fun, Acc, File) + end. + +emulate_escript_foldl(Fun, Acc, File) -> + case escript:extract(File, [compile_source]) of + {ok, [_Shebang, _Comment, _EmuArgs, Body]} -> + case Body of + {source, BeamCode} -> + GetInfo = fun() -> file:read_file_info(File) end, + GetBin = fun() -> BeamCode end, + {ok, Fun(".", GetInfo, GetBin, Acc)}; + {beam, BeamCode} -> + GetInfo = fun() -> file:read_file_info(File) end, + GetBin = fun() -> BeamCode end, + {ok, Fun(".", GetInfo, GetBin, Acc)}; + {archive, ArchiveBin} -> + zip:foldl(Fun, Acc, {File, ArchiveBin}) + end; + {error, Reason} -> + {error, Reason} + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + run(Dir, Cmd0, Expected0) -> Expected = iolist_to_binary(expected_output(Expected0, Dir)), Cmd = case os:type() of @@ -490,7 +744,7 @@ run(Dir, Cmd0, Expected0) -> end, do_run(Dir, Cmd, Expected). -run(Dir, Opts, Cmd0, Expected) -> +run_with_opts(Dir, Opts, Cmd0, Expected) -> Cmd = case os:type() of {win32,_} -> "escript " ++ Opts ++ " " ++ filename:nativename(Dir) ++ "\\" ++ Cmd0; _ -> "escript " ++ Opts ++ " " ++ Dir ++ "/" ++ Cmd0 @@ -533,8 +787,8 @@ expected_output([data_dir|T], Data) -> [filename:nativename(Data)++Slash|expected_output(T, Data)]; expected_output([H|T], Data) -> [H|expected_output(T, Data)]; -expected_output([], _) -> +expected_output([], _) -> []; -expected_output(Bin, _) when is_binary(Bin) -> +expected_output(Bin, _) when is_binary(Bin) -> Bin. -- cgit v1.2.3 From 26d609d3193c0adb371e27317fa0de7cda203061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Mattsson?= Date: Fri, 5 Mar 2010 14:33:00 +0100 Subject: Make reltool independent of the function escript:foldl/3 The function is undocumented and is removed. The new implementation uses the newly introduced functions escript:extract/2 and zip:foldl/3. These new functions are documented (which implies that they are a part of the public API). --- lib/reltool/src/reltool_mod_win.erl | 2 +- lib/reltool/src/reltool_server.erl | 27 +++++++++++++++------------ lib/reltool/src/reltool_utils.erl | 21 +++++++++++++++++++++ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl index c05f73cde8..754f6a0e8a 100644 --- a/lib/reltool/src/reltool_mod_win.erl +++ b/lib/reltool/src/reltool_mod_win.erl @@ -379,7 +379,7 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) -> filename:dirname(ActiveDir)} end, try - case escript:foldl(Fun, NotFound, Escript) of + case reltool_utils:escript_foldl(Fun, NotFound, Escript) of {ok, {text, Bin}} -> Bin; {ok, {obj, Bin}} -> diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 8d4530131f..11839e6a0e 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -1412,18 +1412,21 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) -> {FileAcc, StatusAcc} end end, - try - case escript:foldl(Fun, {[], Status}, Escript) of - {ok, {Files, Status2}} -> - {Apps2, Status3} = files_to_apps(Escript, lists:sort(Files), Apps, Apps, OldApps, Status2), - escripts_to_apps(Escripts, Apps2, OldApps, Status3); - {error, Reason} -> - Text = lists:flatten(io_lib:format("~p", [Reason])), - {[], reltool_utils:return_first_error(Status, "Illegal escript " ++ Escript ++ ": " ++ Text)} - end - catch - throw:Reason2 when is_list(Reason2) -> - {[], reltool_utils:return_first_error(Status, "Illegal escript " ++ Escript ++ ": " ++ Reason2)} + case reltool_utils:escript_foldl(Fun, {[], Status}, Escript) of + {ok, {Files, Status2}} -> + {Apps2, Status3} = + files_to_apps(Escript, + lists:sort(Files), + Apps, + Apps, + OldApps, + Status2), + escripts_to_apps(Escripts, Apps2, OldApps, Status3); + {error, Reason} -> + Text = lists:flatten(io_lib:format("~p", [Reason])), + {[], reltool_utils:return_first_error(Status, + "Illegal escript " ++ + Escript ++ ": " ++ Text)} end; escripts_to_apps([], Apps, _OldApps, Status) -> {Apps, Status}. diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl index 8d52ade9be..4de98317b5 100644 --- a/lib/reltool/src/reltool_utils.erl +++ b/lib/reltool/src/reltool_utils.erl @@ -532,6 +532,27 @@ default_val(Val, Default) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +escript_foldl(Fun, Acc, File) -> + case escript:extract(File, [compile_source]) of + {ok, [_Shebang, _Comment, _EmuArgs, Body]} -> + case Body of + {source, BeamCode} -> + GetInfo = fun() -> file:read_file_info(File) end, + GetBin = fun() -> BeamCode end, + {ok, Fun(".", GetInfo, GetBin, Acc)}; + {beam, BeamCode} -> + GetInfo = fun() -> file:read_file_info(File) end, + GetBin = fun() -> BeamCode end, + {ok, Fun(".", GetInfo, GetBin, Acc)}; + {archive, ArchiveBin} -> + zip:foldl(Fun, Acc, {File, ArchiveBin}) + end; + {error, Reason} -> + {error, Reason} + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + call(Name, Msg) when is_atom(Name) -> call(whereis(Name), Msg); call(Pid, Msg) when is_pid(Pid) -> -- cgit v1.2.3 From e774e560dfcb01f4ff16d6f4e64b1c1ed75de5d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Mattsson?= Date: Fri, 5 Mar 2010 17:48:27 +0100 Subject: Remove the undocumented function escript:foldl/3 It is possible to obtain the same effect with the functions escript:extract/2 and zip:fold/3. See escript_SUITE:escript_foldl/3 for a complete emulation of the old escript:foldl/3 function. --- lib/stdlib/src/escript.erl | 70 ---------------------------------------------- 1 file changed, 70 deletions(-) diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index bf32e15209..d26443f277 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -20,7 +20,6 @@ %% Useful functions that can be called from scripts. -export([script_name/0, create/2, extract/2]). --export([foldl/3]). % Undocumented function that will be removed %% Internal API. -export([start/0, start/1]). @@ -244,75 +243,6 @@ script_name() -> [ScriptName|_] = init:get_plain_arguments(), ScriptName. -%% Apply Fun(Name, GetInfo, GetBin, Acc) for each file in the escript. -%% -%% Fun/2 must return a new accumulator which is passed to the next call. -%% The function returns the final value of the accumulator. Acc0 is -%% returned if the escript contain an empty archive. -%% -%% GetInfo/0 is a fun that returns a #file_info{} record for the file. -%% GetBin/0 is a fun that returns a the contents of the file as a binary. -%% -%% An escript may contain erlang code, beam code or an archive: -%% -%% archive - the Fun/4 will be applied for each file in the archive -%% beam - the Fun/4 will be applied once and GetInfo/0 returns the file -%% info for the (entire) escript file -%% erl - the Fun/4 will be applied once, GetInfo/0 returns the file -%% info for the (entire) escript file and the GetBin returns -%% the compiled beam code - --spec foldl(fun((string(), - fun(() -> #file_info{}), - fun(() -> binary()), - term()) -> term()), - term(), - string()) -> {ok, term()} | {error, term()}. -foldl(Fun, Acc0, File) when is_function(Fun, 4) -> - case parse_file(File, false) of - {text, _, Forms, _HasRecs, _Mode} when is_list(Forms) -> - GetInfo = fun() -> {ok, FI} = file:read_file_info(File), FI end, - GetBin = - fun() -> - case compile:forms(Forms, [return_errors, debug_info]) of - {ok, _, BeamBin} -> - BeamBin; - {error, _Errors, _Warnings} -> - throw("There were compilation errors.") - end - end, - try - {ok, Fun(".", GetInfo, GetBin, Acc0)} - catch - throw:Reason -> - {error, Reason} - end; - {beam, _, BeamBin, _HasRecs, _Mode} when is_binary(BeamBin) -> - GetInfo = fun() -> {ok, FI} = file:read_file_info(File), FI end, - GetBin = fun() -> BeamBin end, - try - {ok, Fun(".", GetInfo, GetBin, Acc0)} - catch - throw:Reason -> - {error, Reason} - end; - {archive, _, ArchiveBin, _HasRecs, _Mode} when is_binary(ArchiveBin) -> - ZipFun = - fun({Name, GetInfo, GetBin}, A) -> - A2 = Fun(Name, GetInfo, GetBin, A), - {true, false, A2} - end, - case prim_zip:open(ZipFun, Acc0, {File, ArchiveBin}) of - {ok, PrimZip, Res} -> - ok = prim_zip:close(PrimZip), - {ok, Res}; - {error, bad_eocd} -> - {error, "Not an archive file"}; - {error, Reason} -> - {error, Reason} - end - end. - %% %% Internal API. %% -- cgit v1.2.3 From d09c73a475ecc29b2715b92fe39bd234b3283e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kan=20Mattsson?= Date: Fri, 5 Mar 2010 15:36:30 +0100 Subject: Add type info for record fields While at it, adapt the source files to fit within 80 chars and remove trailing whitespace. --- lib/reltool/src/Makefile | 2 +- lib/reltool/src/reltool.erl | 144 ++---- lib/reltool/src/reltool.hrl | 335 +++++++++----- lib/reltool/src/reltool_app_win.erl | 238 +++++++--- lib/reltool/src/reltool_fgraph.erl | 24 +- lib/reltool/src/reltool_fgraph_win.erl | 267 +++++++----- lib/reltool/src/reltool_mod_win.erl | 227 ++++++---- lib/reltool/src/reltool_server.erl | 772 ++++++++++++++++++++++----------- lib/reltool/src/reltool_sys_win.erl | 379 ++++++++++------ lib/reltool/src/reltool_target.erl | 423 +++++++++++------- lib/reltool/src/reltool_utils.erl | 30 +- 11 files changed, 1833 insertions(+), 1008 deletions(-) diff --git a/lib/reltool/src/Makefile b/lib/reltool/src/Makefile index fa24efbb8c..12baf5b571 100644 --- a/lib/reltool/src/Makefile +++ b/lib/reltool/src/Makefile @@ -85,7 +85,7 @@ $(TARGET_FILES): $(HRL_FILES) $(INTERNAL_HRL_FILES) # ---------------------------------------------------- # Release Target -# ---------------------------------------------------- +# ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl index e6548bfe68..01365c6317 100644 --- a/lib/reltool/src/reltool.erl +++ b/lib/reltool/src/reltool.erl @@ -24,106 +24,16 @@ start/0, start/1, start_link/1, debug/0, % GUI start_server/1, get_server/1, stop/1, get_config/1, get_config/3, get_rel/2, get_script/2, - create_target/2, get_target_spec/1, eval_target_spec/3, + create_target/2, get_target_spec/1, eval_target_spec/3, install/2 ]). --type file() :: string(). --type dir() :: string(). --type mod_cond() :: all | app | ebin | derived | none. --type incl_cond() :: include | exclude | derived. --type debug_info() :: keep | strip. --type app_file() :: keep | strip | all. --type re_regexp() :: string(). --type regexps() :: [re_regexp()] | {add, [re_regexp()]} | {del, [re_regexp()]} . --type incl_sys_filters() :: regexps(). --type excl_sys_filters() :: regexps(). --type incl_app_filters() :: regexps(). --type excl_app_filters() :: regexps(). --type incl_archive_filters() :: regexps(). --type excl_archive_filters() :: regexps(). --type archive_opt() :: term(). --type root_dir() :: dir(). --type lib_dir() :: dir(). --type profile() :: development | embedded | standalone. --type relocatable() :: boolean(). --type escript_file() :: file(). --type mod_name() :: atom(). --type app_name() :: atom(). --type app_vsn() :: string(). --type app_type() :: permanent | transient | temporary | load | none. --type incl_app() :: app_name(). --type rel_name() :: string(). --type rel_vsn() :: string(). --type boot_rel() :: rel_name(). --type rel_app() :: app_name() - | {app_name(), app_type()} - | {app_name(), [incl_app()]} - | {app_name(), app_type(), [incl_app()]}. --type mod() :: {incl_cond, incl_cond()} - | {debug_info, debug_info()}. --type app() :: {vsn, app_vsn()} - | {mod, mod_name(), mod()} - | {mod_cond, mod_cond()} - | {incl_cond, incl_cond()} - | {app_file, app_file()} - | {debug_info, debug_info()} - | {incl_app_filters, incl_app_filters()} - | {excl_app_filters, excl_app_filters()} - | {incl_archive_filters, incl_archive_filters()} - | {excl_archive_filters, excl_archive_filters()}. --type escript() :: {incl_cond, incl_cond()}. --type sys() :: {mod_cond, mod_cond()} - | {incl_cond, incl_cond()} - | {debug_info, debug_info()} - | {app_file, app_file()} - | {profile, profile()} - | {incl_sys_filters, incl_sys_filters()} - | {excl_sys_filters, excl_sys_filters()} - | {incl_app_filters, incl_app_filters()} - | {excl_app_filters, excl_app_filters()} - | {incl_archive_filters, incl_archive_filters()} - | {excl_archive_filters, excl_archive_filters()} - | {archive_opts, [archive_opt()]} - | {root_dir, root_dir()} - | {lib_dirs, [lib_dir()]} - | {boot_rel, boot_rel()} - | {rel, rel_name(), rel_vsn(), [rel_app()]} - | {relocatable, relocatable()} - | {erts, app()} - | {escript, escript_file(), [escript()]} - | {app, app_name(), [app()]}. --type config() :: {sys, [sys()]}. --type option() :: {wx_debug, term()} | {trap_exit, boolean()} | config() | {config, config() | file()}. --type options() :: [option()]. --type server_pid() :: pid(). --type window_pid() :: pid(). --type server() :: server_pid() | options(). --type rel_file() :: term(). --type script_file() :: term(). --type reason() :: string(). --type escript_arg() :: string(). -%%-type base_dir() :: dir(). -%%-type base_file() :: file(). -%%-type top_dir() :: file(). -%%-type top_file() :: file(). -%%-type target_spec() :: [target_spec()] -%% | {create_dir, base_dir(), [target_spec()]} -%% | {create_dir, base_dir(), top_dir(), [target_spec()]} -%% | {archive, base_file(), [archive_opt()], [target_spec()]} -%% | {copy_file, base_file()} -%% | {copy_file, base_file(), top_file()} -%% | {write_file, base_file(), iolist()} -%% | {strip_beam_file, base_file()}. --type target_spec() :: term(). --type target_dir() :: dir(). --type incl_defaults() :: boolean(). --type incl_derived() :: boolean(). +-include("reltool.hrl"). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Main function for escript --spec main([escript_arg()]) -> ok. +-spec main([escript_arg()]) -> ok. main(_) -> process_flag(trap_exit, true), {ok, WinPid} = start_link([]), @@ -164,7 +74,7 @@ start_link(Options) when is_list(Options) -> {ok, WinPid}; {error, Reason} -> {error, lists:flatten(io_lib:format("~p", [Reason]))} - end. + end. %% Start server process with options -spec start_server(options()) -> {ok, server_pid()} | {error, reason()}. @@ -200,7 +110,8 @@ stop(Pid) when is_pid(Pid) -> end. %% Internal library function --spec eval_server(server(), fun((server_pid()) -> term())) -> {ok, server_pid()} | {error, reason()}. +-spec eval_server(server(), fun((server_pid()) -> term())) -> + {ok, server_pid()} | {error, reason()}. eval_server(Pid, Fun) when is_pid(Pid) -> Fun(Pid); eval_server(Options, Fun) when is_list(Options), is_function(Fun, 1) -> @@ -212,39 +123,54 @@ eval_server(Options, Fun) when is_list(Options), is_function(Fun, 1) -> {error, Reason} -> {error, Reason} end. - + %% Get reltool configuration -spec get_config(server()) -> {ok, config()} | {error, reason()}. get_config(PidOrOption) -> get_config(PidOrOption, false, false). --spec get_config(server(), incl_defaults(), incl_derived()) -> {ok, config()} | {error, reason()}. -get_config(PidOrOptions, InclDefaults, InclDerived) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, fun(Pid) -> reltool_server:get_config(Pid, InclDefaults, InclDerived) end). +-spec get_config(server(), incl_defaults(), incl_derived()) -> + {ok, config()} | {error, reason()}. +get_config(PidOrOptions, InclDef, InclDeriv) + when is_pid(PidOrOptions); is_list(PidOrOptions) -> + eval_server(PidOrOptions, + fun(Pid) -> + reltool_server:get_config(Pid, InclDef, InclDeriv) + end). %% Get contents of release file -spec get_rel(server(), rel_name()) -> {ok, rel_file()} | {error, reason()}. -get_rel(PidOrOptions, RelName) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, fun(Pid) -> reltool_server:get_rel(Pid, RelName) end). +get_rel(PidOrOptions, RelName) + when is_pid(PidOrOptions); is_list(PidOrOptions) -> + eval_server(PidOrOptions, + fun(Pid) -> reltool_server:get_rel(Pid, RelName) end). %% Get contents of boot script file --spec get_script(server(), rel_name()) -> {ok, script_file()} | {error, reason()}. -get_script(PidOrOptions, RelName) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, fun(Pid) -> reltool_server:get_script(Pid, RelName) end). +-spec get_script(server(), rel_name()) -> + {ok, script_file()} | {error, reason()}. +get_script(PidOrOptions, RelName) + when is_pid(PidOrOptions); is_list(PidOrOptions) -> + eval_server(PidOrOptions, + fun(Pid) -> reltool_server:get_script(Pid, RelName) end). %% Generate a target system -spec create_target(server(), target_dir()) -> ok | {error, reason()}. -create_target(PidOrOptions, TargetDir) when is_pid(PidOrOptions); is_list(PidOrOptions) -> - eval_server(PidOrOptions, fun(Pid) -> reltool_server:gen_target(Pid, TargetDir) end). +create_target(PidOrOptions, TargetDir) + when is_pid(PidOrOptions); is_list(PidOrOptions) -> + eval_server(PidOrOptions, + fun(Pid) -> reltool_server:gen_target(Pid, TargetDir) end). %% Generate a target system -spec get_target_spec(server()) -> {ok, target_spec()} | {error, reason()}. -get_target_spec(PidOrOptions) when is_pid(PidOrOptions); is_list(PidOrOptions) -> +get_target_spec(PidOrOptions) + when is_pid(PidOrOptions); is_list(PidOrOptions) -> eval_server(PidOrOptions, fun(Pid) -> reltool_server:gen_spec(Pid) end). %% Generate a target system --spec eval_target_spec(target_spec(), root_dir(), target_dir()) -> ok | {error, reason()}. -eval_target_spec(Spec, SourceDir, TargetDir) when is_list(SourceDir), is_list(TargetDir) -> +-spec eval_target_spec(target_spec(), root_dir(), target_dir()) -> + ok | {error, reason()}. +eval_target_spec(Spec, SourceDir, TargetDir) + when is_list(SourceDir), is_list(TargetDir) -> reltool_target:eval_spec(Spec, SourceDir, TargetDir). %% Install a target system diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl index e7d84f97db..8a6a2142fd 100644 --- a/lib/reltool/src/reltool.hrl +++ b/lib/reltool/src/reltool.hrl @@ -16,119 +16,144 @@ %% %% %CopyrightEnd% --define(APPLICATION, reltool). +-define(APPLICATION, reltool). -define(MISSING_APP, '*MISSING*'). -define(MISSING_APP_TEXT, "*MISSING*"). --record(common, - { - sys_debug, % term() - wx_debug, % term() - trap_exit, % bool() - app_tab, % ets_tab() - mod_tab, % ets_tab() - mod_used_by_tab % ets_tab() - }). - --record(sys, - { - %% Sources - root_dir, % directory() - lib_dirs, % [directory()] - escripts, % [file()] - mod_cond, % all | app | ebin | derived | none - incl_cond, % include | exclude | derived - apps, % [#app{}] - - %% Target cond - boot_rel, % string() - rels, % [#rel{}] - emu_name, % string() - profile, % standalone | development | embedded - incl_sys_filters, % [regexp()] - excl_sys_filters, % [regexp()] - incl_app_filters, % [regexp()] - excl_app_filters, % [regexp()] - incl_archive_filters, % [regexp()] - excl_archive_filters, % [regexp()] - archive_opts, % [zip:create()] - relocatable, % bool() - app_type, % permanent | transient | temporary | load | none - app_file, % keep | strip | all - debug_info % keep | strip - }). - --record(rel, - { - name, % string() - vsn, % string() - rel_apps % [#rel_app{}] - }). +-type file() :: string(). +-type dir() :: string(). +%% app - Include all modules in app file +%% ebin - Include all modules on ebin directory +%% derived - Include only those modules that others are dependent on +-type mod_cond() :: all | app | ebin | derived | none. +-type incl_cond() :: include | exclude | derived. +-type debug_info() :: keep | strip. +-type app_file() :: keep | strip | all. +-type re_regexp() :: string(). % re:regexp() +-type regexps() :: [re_regexp()] | + {add, [re_regexp()]} | + {del, [re_regexp()]} . +-type incl_sys_filters() :: regexps(). +-type excl_sys_filters() :: regexps(). +-type incl_app_filters() :: regexps(). +-type excl_app_filters() :: regexps(). +-type incl_archive_filters() :: regexps(). +-type excl_archive_filters() :: regexps(). +-type archive_opt() :: term(). % zip:create() +-type root_dir() :: dir(). +-type lib_dir() :: dir(). +-type profile() :: development | embedded | standalone. +-type relocatable() :: boolean(). +-type escript_file() :: file(). +-type mod_name() :: atom(). +-type app_name() :: atom(). +-type app_vsn() :: string(). % e.g. "4.7" +-type app_label() :: string().% e.g. "mnesia" or "mnesia-4.7" +-type app_type() :: permanent | transient | temporary | load | none. +-type incl_app() :: app_name(). +-type emu_name() :: string(). +-type rel_name() :: string(). +-type rel_vsn() :: string(). +-type boot_rel() :: rel_name(). +-type rel_app() :: app_name() + | {app_name(), app_type()} + | {app_name(), [incl_app()]} + | {app_name(), app_type(), [incl_app()]}. +-type mod() :: {incl_cond, incl_cond()} + | {debug_info, debug_info()}. +-type app() :: {vsn, app_vsn()} + | {mod, mod_name(), mod()} + | {mod_cond, mod_cond()} + | {incl_cond, incl_cond()} + | {app_file, app_file()} + | {debug_info, debug_info()} + | {incl_app_filters, incl_app_filters()} + | {excl_app_filters, excl_app_filters()} + | {incl_archive_filters, incl_archive_filters()} + | {excl_archive_filters, excl_archive_filters()}. +-type escript() :: {incl_cond, incl_cond()}. +-type sys() :: {mod_cond, mod_cond()} + | {incl_cond, incl_cond()} + | {debug_info, debug_info()} + | {app_file, app_file()} + | {profile, profile()} + | {incl_sys_filters, incl_sys_filters()} + | {excl_sys_filters, excl_sys_filters()} + | {incl_app_filters, incl_app_filters()} + | {excl_app_filters, excl_app_filters()} + | {incl_archive_filters, incl_archive_filters()} + | {excl_archive_filters, excl_archive_filters()} + | {archive_opts, [archive_opt()]} + | {root_dir, root_dir()} + | {lib_dirs, [lib_dir()]} + | {boot_rel, boot_rel()} + | {rel, rel_name(), rel_vsn(), [rel_app()]} + | {relocatable, relocatable()} + | {erts, app()} + | {escript, escript_file(), [escript()]} + | {app, app_name(), [app()]}. +-type config() :: {sys, [sys()]}. +-type option() :: {wx_debug, term()} | + {trap_exit, boolean()} | + config() | + {config, config() | file()}. +-type options() :: [option()]. +-type server_pid() :: pid(). +-type window_pid() :: pid(). +-type server() :: server_pid() | options(). +-type rel_file() :: term(). +-type script_file() :: term(). +-type reason() :: string(). +-type escript_arg() :: string(). +-type base_dir() :: dir(). +-type base_file() :: file(). +-type top_dir() :: file(). +-type top_file() :: file(). +-type target_spec() :: [target_spec()] + | {create_dir, base_dir(), [target_spec()]} + | {create_dir, base_dir(), top_dir(), [target_spec()]} + | {archive, + base_file(), + [archive_opt()], + [target_spec()]} + | {copy_file, base_file()} + | {copy_file, base_file(), top_file()} + | {write_file, base_file(), iolist()} + | {strip_beam_file, base_file()}. +-type target_dir() :: dir(). +-type incl_defaults() :: boolean(). +-type incl_derived() :: boolean(). +-type ets_tab() :: term(). +-type status() :: missing | ok. --record(rel_app, +-record(common, { - name, % atom() - app_type, % permanent | transient | temporary | load | none - incl_apps % [atom()] + sys_debug :: term(), + wx_debug :: term(), + trap_exit :: boolean(), + app_tab :: ets_tab(), + mod_tab :: ets_tab(), + mod_used_by_tab :: ets_tab() }). --record(app, - {%% Static info - name, % atom() - is_escript, % bool() - use_selected_vsn,% bool() | undefined - active_dir, % dir_name() - sorted_dirs, % [dir_name()] - vsn, % string() e.g. "4.7" - label, % string() e.g. "mnesia" or "mnesia-4.7" - info, % #app_info{} | undefined - mods, % [#mod{}] - - %% Static source cond - mod_cond, % all | app | ebin | derived | none | undefined - incl_cond, % include | exclude | derived | undefined - - %% Static target cond - debug_info, % keep | strip | undefined - app_file, % keep | strip | all | undefined - app_type, % permanent | transient | temporary | load | none - incl_app_filters, % [regexp()] - excl_app_filters, % [regexp()] - incl_archive_filters, % [regexp()] - excl_archive_filters, % [regexp()] - archive_opts, % [zip_create_opt()] - - %% Dynamic - status, % missing | ok - uses_mods, % [atom()] - used_by_mods, % [atom()] - uses_apps, % [atom()] - used_by_apps, % [atom()] - is_pre_included, % bool() - is_included % bool() - }). -record(mod, {%% Static - name, % atom() - app_name, % atom() - incl_cond, % include | exclude | derived | undefined - debug_info, % keep | strip | undefined - is_app_mod, % bool(), - is_ebin_mod, % bool(), - uses_mods, % [module()] - exists, % bool() + name :: mod_name(), + app_name :: app_name(), + incl_cond :: incl_cond() | undefined, + debug_info :: debug_info() | undefined, + is_app_mod :: boolean(), + is_ebin_mod :: boolean(), + uses_mods :: [mod_name()], + exists :: boolean(), %% Dynamic - status, % missing | ok - used_by_mods, % [atom()] - is_pre_included, % bool() | undefined - is_included % bool() | undefined + status :: status(), + used_by_mods :: [mod_name()], + is_pre_included :: boolean() | undefined, + is_included :: boolean() | undefined }). -%% app - Include all modules in app file -%% ebin - Include all modules on ebin directory -%% derived - Include only those modules that others are dependent on - -record(app_info, { description = "", @@ -145,8 +170,86 @@ start_phases = undefined }). +-record(app, + {%% Static info + name :: app_name(), + is_escript :: boolean(), + use_selected_vsn :: boolean() | undefined, + active_dir :: dir(), + sorted_dirs :: [dir()], + vsn :: app_vsn(), + label :: app_label(), + info :: #app_info{} | undefined, + mods :: [#mod{}], + + %% Static source cond + mod_cond :: mod_cond() | undefined, + incl_cond :: incl_cond() | undefined, + + %% Static target cond + debug_info :: debug_info() | undefined, + app_file :: app_file() | undefined, + app_type :: app_type(), + incl_app_filters :: incl_app_filters(), + excl_app_filters :: excl_app_filters(), + incl_archive_filters :: incl_archive_filters(), + excl_archive_filters :: excl_archive_filters(), + archive_opts :: [archive_opt()], + + %% Dynamic + status :: status(), + uses_mods :: [mod_name()], + used_by_mods :: [mod_name()], + uses_apps :: [app_name()], + used_by_apps :: [app_name()], + is_pre_included :: boolean(), + is_included :: boolean() + }). + +-record(rel_app, + { + name :: app_name(), + app_type :: app_type(), + incl_apps :: [incl_app()] + }). + +-record(rel, + { + name :: rel_name(), + vsn :: rel_vsn(), + rel_apps :: [#rel_app{}] + }). + +-record(sys, + { + %% Sources + root_dir :: dir(), + lib_dirs :: [dir()], + escripts :: [file()], + mod_cond :: mod_cond(), + incl_cond :: incl_cond(), + apps :: [#app{}], + + %% Target cond + boot_rel :: boot_rel(), + rels :: [#rel{}], + emu_name :: emu_name(), + profile :: profile(), + incl_sys_filters :: incl_sys_filters(), + excl_sys_filters :: excl_sys_filters(), + incl_app_filters :: incl_app_filters(), + excl_app_filters :: excl_app_filters(), + incl_archive_filters :: incl_archive_filters(), + excl_archive_filters :: excl_archive_filters(), + archive_opts :: [archive_opt()], + relocatable :: boolean(), + app_type :: app_type(), + app_file :: app_file(), + debug_info :: debug_info() + }). + -record(regexp, {source, compiled}). - + -define(ERR_IMAGE, 0). -define(WARN_IMAGE, 1). -define(QUEST_IMAGE, 2). @@ -170,7 +273,7 @@ -define(DEFAULT_DEBUG_INFO, keep). -define(DEFAULT_INCL_ARCHIVE_FILTERS, [".*"]). --define(DEFAULT_EXCL_ARCHIVE_FILTERS, ["^include$", "^priv$"]). +-define(DEFAULT_EXCL_ARCHIVE_FILTERS, ["^include\$", "^priv\$"]). -define(DEFAULT_ARCHIVE_OPTS, []). -define(DEFAULT_INCL_SYS_FILTERS, [".*"]). @@ -178,25 +281,27 @@ -define(DEFAULT_INCL_APP_FILTERS, [".*"]). -define(DEFAULT_EXCL_APP_FILTERS, []). --define(EMBEDDED_INCL_SYS_FILTERS, ["^bin", +-define(EMBEDDED_INCL_SYS_FILTERS, ["^bin", "^erts", "^lib", "^releases"]). --define(EMBEDDED_EXCL_SYS_FILTERS, ["^bin/(erlc|dialyzer|typer)(|\\.exe)$", - "^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)$", - "^erts.*/bin/.*(debug|pdb)"]). +-define(EMBEDDED_EXCL_SYS_FILTERS, + ["^bin/(erlc|dialyzer|typer)(|\\.exe)\$", + "^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$", + "^erts.*/bin/.*(debug|pdb)"]). -define(EMBEDDED_INCL_APP_FILTERS, ["^ebin", - "^priv", + "^priv", "^include"]). -define(EMBEDDED_EXCL_APP_FILTERS, []). --define(STANDALONE_INCL_SYS_FILTERS, ["^bin/(erl|epmd)(|\\.exe|\\.ini)$", - "^bin/start(|_clean).boot$", +-define(STANDALONE_INCL_SYS_FILTERS, ["^bin/(erl|epmd)(|\\.exe|\\.ini)\$", + "^bin/start(|_clean).boot\$", "^erts.*/bin", - "^lib$"]). --define(STANDALONE_EXCL_SYS_FILTERS, ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)$", - "^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)$", - "^erts.*/bin/.*(debug|pdb)"]). --define(STANDALONE_INCL_APP_FILTERS, ["^ebin", + "^lib\$"]). +-define(STANDALONE_EXCL_SYS_FILTERS, + ["^erts.*/bin/(erlc|dialyzer|typer)(|\\.exe)\$", + "^erts.*/bin/(start|escript|to_erl|run_erl)(|\\.exe)\$", + "^erts.*/bin/.*(debug|pdb)"]). +-define(STANDALONE_INCL_APP_FILTERS, ["^ebin", "^priv"]). --define(STANDALONE_EXCL_APP_FILTERS, ["^ebin/.*\\.appup$"]). +-define(STANDALONE_EXCL_APP_FILTERS, ["^ebin/.*\\.appup\$"]). diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl index 6083493c02..d7280f1607 100644 --- a/lib/reltool/src/reltool_app_win.erl +++ b/lib/reltool/src/reltool_app_win.erl @@ -34,7 +34,7 @@ -include_lib("wx/include/wx.hrl"). -include("reltool.hrl"). --record(state, +-record(state, {parent_pid, xref_pid, mod_wins, @@ -63,7 +63,7 @@ %% -define(APPS_APP_COL_WIDTH, 250). -define(CLOSE_ITEM, ?wxID_EXIT). %% Use OS specific version if available --define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific +-define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific -define(CONTENTS_ITEM, 300). -define(MODS_MOD_COL, 0). @@ -79,7 +79,11 @@ %% Client start_link(WxEnv, Xref, Common, AppName) -> - proc_lib:start_link(?MODULE, init, [self(), WxEnv, Xref, Common, AppName], infinity, []). + proc_lib:start_link(?MODULE, + init, + [self(), WxEnv, Xref, Common, AppName], + infinity, + []). raise(Pid) -> reltool_utils:cast(Pid, raise). @@ -121,7 +125,12 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) -> receive {system, From, Msg} -> Dbg = C#common.sys_debug, - sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, Dbg, S); + sys:handle_system_msg(Msg, + From, + S#state.parent_pid, + ?MODULE, + Dbg, + S); {cast, _From, raise} -> wxFrame:raise(S#state.frame), wxFrame:setFocus(S#state.frame), @@ -131,7 +140,8 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) -> {ok, App2} -> {ok, Sys} = reltool_server:get_sys(Xref), S2 = redraw_window(S#state{sys = Sys, app = App2}), - [ok = reltool_mod_win:refresh(MW#mod_win.pid) || MW <- S2#state.mod_wins], + [ok = reltool_mod_win:refresh(MW#mod_win.pid) || + MW <- S2#state.mod_wins], ?MODULE:loop(S2); {error, _Reason} -> wxFrame:destroy(S#state.frame), @@ -139,7 +149,8 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) -> end; {call, ReplyTo, Ref, {open_mod, ModName}} -> S2 = create_mod_window(S, ModName), - {value, #mod_win{pid = ModPid}} = lists:keysearch(ModName, #mod_win.name, S2#state.mod_wins), + {value, #mod_win{pid = ModPid}} = + lists:keysearch(ModName, #mod_win.name, S2#state.mod_wins), reltool_utils:reply(ReplyTo, Ref, {ok, ModPid}), ?MODULE:loop(S2); #wx{event = #wxSize{}} = Wx -> @@ -157,7 +168,9 @@ loop(#state{xref_pid = Xref, common = C, app = App} = S) -> exit(Reason); {'EXIT', Pid, _Reason} = Exit -> exit_warning(Exit), - S2 = S#state{mod_wins = lists:keydelete(Pid, #mod_win.pid, S#state.mod_wins)}, + S2 = S#state{mod_wins = lists:keydelete(Pid, + #mod_win.pid, + S#state.mod_wins)}, ?MODULE:loop(S2); Msg -> error_logger:format("~p~p got unexpected message:\n\t~p\n", @@ -179,7 +192,7 @@ create_window(#state{app = App} = S) -> StatusBar = wxFrame:createStatusBar(Frame,[]), Book = wxNotebook:new(Panel, ?wxID_ANY, []), - + S2 = S#state{frame = Frame, panel = Panel, book = Book, @@ -210,12 +223,16 @@ create_apps_page(S, Derived) -> Lower = wxBoxSizer:new(?wxHORIZONTAL), UsedByCtrl = create_apps_list_ctrl(Panel, Upper, "Used by"), - wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), - + wxSizer:add(Upper, + wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + RequiredCtrl = create_apps_list_ctrl(Panel, Upper, "Required"), - wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), InclCtrl = create_apps_list_ctrl(Panel, Upper, "Included"), - wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + wxSizer:add(Upper, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), UsesCtrl = create_apps_list_ctrl(Panel, Upper, "Uses"), S2 = S#state{app_required_ctrl = RequiredCtrl, app_used_by_ctrl = UsedByCtrl, @@ -262,8 +279,10 @@ create_apps_list_ctrl(Panel, Sizer, Text) -> [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}, {proportion, 1}]), - wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, apps_list_ctrl}]), - wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_app}]), + wxEvtHandler:connect(ListCtrl, size, + [{skip, true}, {userData, apps_list_ctrl}]), + wxListCtrl:connect(ListCtrl, command_list_item_activated, + [{userData, open_app}]), wxWindow:connect(ListCtrl, enter_window), ListCtrl. @@ -271,9 +290,20 @@ create_deps_page(S, Derived) -> Panel = wxPanel:new(S#state.book, []), Main = wxBoxSizer:new(?wxHORIZONTAL), - UsedByCtrl = create_mods_list_ctrl(Panel, Main, "Modules used by others", " and their applications", undefined, undefined), - wxSizer:add(Main, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), - UsesCtrl = create_mods_list_ctrl(Panel, Main, "Used modules", " and their applications", undefined, undefined), + UsedByCtrl = create_mods_list_ctrl(Panel, + Main, + "Modules used by others", + " and their applications", + undefined, + undefined), + wxSizer:add(Main, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + UsesCtrl = create_mods_list_ctrl(Panel, + Main, + "Used modules", + " and their applications", + undefined, + undefined), S2 = S#state{deps_used_by_ctrl = UsedByCtrl, deps_uses_ctrl = UsesCtrl}, redraw_mods(S2, Derived), @@ -285,13 +315,36 @@ create_mods_page(S, Derived) -> Panel = wxPanel:new(S#state.book, []), MainSz = wxBoxSizer:new(?wxHORIZONTAL), - SourceCtrl = create_mods_list_ctrl(Panel, MainSz, ?source, "", whitelist_add, blacklist_add), - wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), - WhiteCtrl = create_mods_list_ctrl(Panel, MainSz, ?whitelist, "", whitelist_del, blacklist_add), - wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), - BlackCtrl = create_mods_list_ctrl(Panel, MainSz, ?blacklist, "", whitelist_add, blacklist_del), - wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), - DerivedCtrl = create_mods_list_ctrl(Panel, MainSz, ?derived, "", whitelist_add, blacklist_add), + SourceCtrl = create_mods_list_ctrl(Panel, + MainSz, + ?source, + "", + whitelist_add, + blacklist_add), + wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + WhiteCtrl = create_mods_list_ctrl(Panel, + MainSz, + ?whitelist, + "", + whitelist_del, + blacklist_add), + wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + BlackCtrl = create_mods_list_ctrl(Panel, + MainSz, + ?blacklist, + "", + whitelist_add, + blacklist_del), + wxSizer:add(MainSz, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), + [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), + DerivedCtrl = create_mods_list_ctrl(Panel, + MainSz, + ?derived, + "", + whitelist_add, + blacklist_add), S2 = S#state{mods_source_ctrl = SourceCtrl, mods_white_ctrl = WhiteCtrl, mods_black_ctrl = BlackCtrl, @@ -309,7 +362,8 @@ create_mods_list_ctrl(Panel, OuterSz, Title, AppText, Tick, Cross) -> %% ?wxLC_SINGLE_SEL bor ?wxHSCROLL bor ?wxVSCROLL}]), - ToolTip = "Select module(s) or open separate module window with a double click.", + ToolTip = "Select module(s) or open separate module " + "window with a double click.", wxListCtrl:setToolTip(ListCtrl, ToolTip), %% Prep images @@ -326,7 +380,8 @@ create_mods_list_ctrl(Panel, OuterSz, Title, AppText, Tick, Cross) -> true -> wxListItem:setText(ListItem, AppText), wxListCtrl:insertColumn(ListCtrl, ?MODS_APP_COL, ListItem), - %% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, ?MODS_APP_COL_WIDTH), + %% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, + %% ?MODS_APP_COL_WIDTH), 2; false -> 1 @@ -336,9 +391,11 @@ create_mods_list_ctrl(Panel, OuterSz, Title, AppText, Tick, Cross) -> ButtonSz = wxBoxSizer:new(?wxHORIZONTAL), create_button(Panel, ButtonSz, ListCtrl, Title, "wxART_TICK_MARK", Tick), create_button(Panel, ButtonSz, ListCtrl, Title, "wxART_CROSS_MARK", Cross), - wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, mods_list_ctrl}]), - wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_mod}]), - wxWindow:connect(ListCtrl, enter_window), + wxEvtHandler:connect(ListCtrl, size, + [{skip, true}, {userData, mods_list_ctrl}]), + wxListCtrl:connect(ListCtrl, command_list_item_activated, + [{userData, open_mod}]), + wxWindow:connect(ListCtrl, enter_window), InnerSz = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(InnerSz, ListCtrl, [{border, 2}, @@ -377,7 +434,7 @@ action_to_tool_tip(Label, Action) -> "Remove selected module(s)from whitelist."; blacklist_add when Label =:= ?blacklist -> "Remove selected module(s) from blacklist."; - blacklist_add -> + blacklist_add -> "Add selected module(s) to blacklist."; blacklist_del -> "Remove selected module(s) from blacklist." @@ -444,8 +501,8 @@ create_config_page(#state{app = App} = S) -> wxNotebook:addPage(S2#state.book, Panel, "Application settings", []), S2. -create_double_box(Panel, Sizer, TopLabel, - OuterText, OuterData, +create_double_box(Panel, Sizer, TopLabel, + OuterText, OuterData, InnerText, InnerData, InternalLabel, InternalChoices, InternalChoiceData) -> TopSizer = wxStaticBoxSizer:new(?wxVERTICAL, Panel, @@ -457,10 +514,10 @@ create_double_box(Panel, Sizer, TopLabel, [{userData, OuterData}]), InnerRadio = wxRadioButton:new(Panel, ?wxID_ANY, InnerText), wxEvtHandler:connect(InnerRadio, command_radiobutton_selected, - [{userData, InnerData}]), - InnerBox = wxRadioBox:new(Panel, + [{userData, InnerData}]), + InnerBox = wxRadioBox:new(Panel, ?wxID_ANY, - InternalLabel, + InternalLabel, ?wxDefaultPosition, ?wxDefaultSize, InternalChoices, @@ -487,29 +544,38 @@ handle_event(#state{sys = Sys, app = App} = S, Wx) -> #wx{obj = ObjRef, event = #wxMouse{type = enter_window}} -> wxWindow:setFocus(ObjRef), S; - #wx{obj= ListCtrl, userData = mods_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} -> + #wx{obj= ListCtrl, + userData = mods_list_ctrl, + event = #wxSize{type = size, size = {W, _H}}} -> HasApps = (wxListCtrl:getColumnCount(ListCtrl) > 1), case HasApps of false -> wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, W); true -> - wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, (2 * W) div 3), + wxListCtrl:setColumnWidth(ListCtrl, + ?MODS_MOD_COL, + (2 * W) div 3), wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, W div 3) end, S; - #wx{obj= ListCtrl, userData = apps_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} -> + #wx{obj = ListCtrl, + userData = apps_list_ctrl, + event = #wxSize{type = size, size = {W, _H}}} -> wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, W), S; #wx{userData = open_app, obj = ListCtrl, - event = #wxList{type = command_list_item_activated, itemIndex = Pos}} -> + event = #wxList{type = command_list_item_activated, + itemIndex = Pos}} -> AppBase = wxListCtrl:getItemText(ListCtrl, Pos), {AppName, _AppVsn} = reltool_utils:split_app_name(AppBase), - {ok, _AppPid} = reltool_sys_win:open_app(S#state.parent_pid, AppName), + {ok, _AppPid} = reltool_sys_win:open_app(S#state.parent_pid, + AppName), S; #wx{userData = open_mod, obj = ListCtrl, - event = #wxList{type = command_list_item_activated, itemIndex = Pos}} -> + event = #wxList{type = command_list_item_activated, + itemIndex = Pos}} -> ModName = list_to_atom(wxListCtrl:getItemText(ListCtrl, Pos)), create_mod_window(S, ModName); #wx{userData = global_incl_cond} -> @@ -560,16 +626,19 @@ handle_event(#state{sys = Sys, app = App} = S, Wx) -> Items = reltool_utils:get_items(ListCtrl), handle_mod_button(S, Items, Action); _ -> - error_logger:format("~p~p got unexpected app event from wx:\n\t~p\n", + error_logger:format("~p~p got unexpected app event from " + "wx:\n\t~p\n", [?MODULE, self(), Wx]), S end. -create_mod_window(#state{parent_pid = RelPid, xref_pid = Xref, common = C} = S, ModName) -> +create_mod_window(#state{parent_pid = RelPid, xref_pid = Xref, common = C} = S, + ModName) -> case lists:keysearch(ModName, #mod_win.name, S#state.mod_wins) of false -> WxEnv = wx:get_env(), - {ok, Pid} = reltool_mod_win:start_link(WxEnv, Xref, RelPid, C, ModName), + {ok, Pid} = + reltool_mod_win:start_link(WxEnv, Xref, RelPid, C, ModName), MW = #mod_win{name = ModName, pid = Pid}, S#state{mod_wins = [MW | S#state.mod_wins]}; {value, MW} -> @@ -578,7 +647,9 @@ create_mod_window(#state{parent_pid = RelPid, xref_pid = Xref, common = C} = S, end. handle_mod_button(#state{app = App} = S, Items, Action) -> - App2 = lists:foldl(fun(Item, A) -> move_mod(A, Item, Action) end, App, Items), + App2 = lists:foldl(fun(Item, A) -> move_mod(A, Item, Action) end, + App, + Items), {ok, App3} = reltool_sys_win:set_app(S#state.parent_pid, App2), S2 = S#state{app = App3}, redraw_window(S2). @@ -587,7 +658,7 @@ move_mod(App, {_ItemNo, ModStr}, Action) -> ModName = list_to_atom(ModStr), Mods = App#app.mods, {value, M} = lists:keysearch(ModName, #mod.name, Mods), - AppCond = + AppCond = case Action of whitelist_add -> case M#mod.incl_cond of @@ -597,12 +668,13 @@ move_mod(App, {_ItemNo, ModStr}, Action) -> end; whitelist_del -> undefined; - blacklist_add -> + blacklist_add -> exclude; blacklist_del -> undefined; _ -> - error_logger:format("~p~p got unexpected mod button event: ~p\n\t ~p\n", + error_logger:format("~p~p got unexpected mod " + "button event: ~p\n\t ~p\n", [?MODULE, self(), ModName, Action]), M#mod.incl_cond end, @@ -623,7 +695,10 @@ change_mod_cond(S, App, NewModCond) -> redraw_window(S2). change_version(S, App, NewDir) -> - App2 = App#app{active_dir = NewDir, label = undefined, vsn = undefined, info = undefined}, + App2 = App#app{active_dir = NewDir, + label = undefined, + vsn = undefined, + info = undefined}, {ok, App3} = reltool_sys_win:set_app(S#state.parent_pid, App2), Title = app_title(App3), wxFrame:setTitle(S#state.frame, Title), @@ -635,8 +710,14 @@ redraw_apps(#state{app = #app{info = AppInfo}, app_incl_ctrl = InclCtrl, app_uses_ctrl = UsesCtrl, xref_pid = Xref}, - {_SourceMods, _WhiteMods, _BlackMods, _DerivedMods, UsedByMods, UsesMods}) -> - UsedByApps = lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsedByMods]), + {_SourceMods, + _WhiteMods, + _BlackMods, + _DerivedMods, + UsedByMods, + UsesMods}) -> + UsedByApps = + lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsedByMods]), Select = fun(AppName) -> {ok, App} = reltool_server:get_app(Xref, AppName), @@ -647,7 +728,8 @@ redraw_apps(#state{app = #app{info = AppInfo}, end, RequiredApps = lists:sort(lists:map(Select, AppInfo#app_info.applications)), InclApps = lists:map(Select, AppInfo#app_info.incl_apps), - UsesApps = lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsesMods]), + UsesApps = + lists:usort([{M#mod.app_name, Image} || {Image, _, M} <- UsesMods]), do_redraw_apps(UsedByCtrl, UsedByApps), do_redraw_apps(RequiredCtrl, RequiredApps), do_redraw_apps(InclCtrl, InclApps), @@ -656,19 +738,26 @@ redraw_apps(#state{app = #app{info = AppInfo}, do_redraw_apps(ListCtrl, []) -> wxListCtrl:deleteAllItems(ListCtrl); - %% wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, ?wxLIST_AUTOSIZE_USEHEADER); + %% wxListCtrl:setColumnWidth(ListCtrl, ?APPS_APP_COL, +%% ?wxLIST_AUTOSIZE_USEHEADER); do_redraw_apps(ListCtrl, AppImages) -> wxListCtrl:deleteAllItems(ListCtrl), Add = fun({AppName, ImageId}, {Row, Prev}) when AppName =/= Prev -> - wxListCtrl:insertItem(ListCtrl, Row, ""), - if (Row rem 2) =:= 0 -> - wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255}); + wxListCtrl:insertItem(ListCtrl, Row, ""), + if (Row rem 2) =:= 0 -> + wxListCtrl:setItemBackgroundColour(ListCtrl, + Row, + {240,240,255}); true -> ignore end, Str = atom_to_list(AppName), - wxListCtrl:setItem(ListCtrl, Row, ?APPS_APP_COL, Str, [{imageId, ImageId}]), + wxListCtrl:setItem(ListCtrl, + Row, + ?APPS_APP_COL, + Str, + [{imageId, ImageId}]), {Row + 1, AppName}; ({_, _}, Acc) -> Acc @@ -688,8 +777,13 @@ redraw_mods(#state{mods_source_ctrl = SourceCtrl, deps_uses_ctrl = UsesCtrl, app = #app{is_pre_included = IsPre, is_included = IsIncl}, status_bar = Bar}, - {SourceMods, WhiteMods, BlackMods, DerivedMods, UsedByMods, UsesMods}) -> - InclStatus = + {SourceMods, + WhiteMods, + BlackMods, + DerivedMods, + UsedByMods, + UsesMods}) -> + InclStatus = case IsIncl of true when IsPre =:= true -> "Whitelist - "; true -> "Derived - "; @@ -711,7 +805,7 @@ app_to_mods(#state{xref_pid = Xref, app = App}) -> SourceMods = [M || M <- App#app.mods, M#mod.is_included =/= true, M#mod.is_pre_included =/= false], - WhiteMods = [M || M <- App#app.mods, + WhiteMods = [M || M <- App#app.mods, M#mod.is_pre_included =:= true], BlackMods = [M || M <- App#app.mods, M#mod.is_pre_included =:= false], @@ -722,7 +816,8 @@ app_to_mods(#state{xref_pid = Xref, app = App}) -> fun(ModName) when is_atom(ModName) -> {ok, M} = reltool_server:get_mod(Xref, ModName), if - M#mod.app_name =:= App#app.name, M#mod.is_included =:= true -> + M#mod.app_name =:= App#app.name, + M#mod.is_included =:= true -> false; true -> {true, M} @@ -780,20 +875,26 @@ opt_redraw_mods(undefined, _ImageMods) -> opt_redraw_mods(ListCtrl, ImageMods) -> HasApps = (wxListCtrl:getColumnCount(ListCtrl) > 1), do_redraw_mods(ListCtrl, ImageMods, HasApps). - + do_redraw_mods(ListCtrl, [], _HasApps) -> wxListCtrl:deleteAllItems(ListCtrl); do_redraw_mods(ListCtrl, ImageMods, HasApps) -> wxListCtrl:deleteAllItems(ListCtrl), Add = fun({ImageId, AppName, #mod{name = ModName}}, Row) -> - wxListCtrl:insertItem(ListCtrl, Row, ""), - if (Row rem 2) =:= 0 -> - wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255}); + wxListCtrl:insertItem(ListCtrl, Row, ""), + if (Row rem 2) =:= 0 -> + wxListCtrl:setItemBackgroundColour(ListCtrl, + Row, + {240,240,255}); true -> ignore end, - wxListCtrl:setItem(ListCtrl, Row, ?MODS_MOD_COL, atom_to_list(ModName), [{imageId, ImageId}]), + wxListCtrl:setItem(ListCtrl, + Row, + ?MODS_MOD_COL, + atom_to_list(ModName), + [{imageId, ImageId}]), case HasApps of false -> ok; @@ -842,13 +943,14 @@ redraw_config(#state{sys = #sys{incl_cond = GlobalIncl, SelectedRadio, SourceBox, fun(true) -> - reltool_utils:elem_to_index(ActiveDir, SortedDirs) - 1; + reltool_utils:elem_to_index(ActiveDir, + SortedDirs) - 1; (false) -> 0 end). redraw_double_box(Global, Local, GlobalRadio, LocalRadio, LocalBox, GetChoice) -> - AppCond = + AppCond = case Local of undefined -> wxRadioButton:setValue(GlobalRadio, true), diff --git a/lib/reltool/src/reltool_fgraph.erl b/lib/reltool/src/reltool_fgraph.erl index 09c4f8c8ce..d17992b3e7 100644 --- a/lib/reltool/src/reltool_fgraph.erl +++ b/lib/reltool/src/reltool_fgraph.erl @@ -80,7 +80,7 @@ foreach(Fun, Fg) -> end, Fg), Fg. -map(Fun, Fg) -> +map(Fun, Fg) -> lists:foreach(fun (Key) -> put(Key,Fun(get(Key))) end, Fg), @@ -105,7 +105,9 @@ step(Vs, Es) -> step(Vs, Es, {0,0}). step(Vs, Es, Pa) -> ?MODULE:map(fun (Node = {_, #fg_v{ type = static }}) -> Node; - ({Key, Value = #fg_v{ p = {Px, Py}, v = {Vx, Vy}, type = dynamic}}) when is_float(Px), is_float(Py), is_float(Vx), is_float(Vy) -> + ({Key, Value = #fg_v{ p = {Px, Py}, v = {Vx, Vy}, type = dynamic}}) + when is_float(Px), is_float(Py), + is_float(Vx), is_float(Vy) -> F0 = {0.0,0.0}, F1 = coulomb_repulsion(Key, Value, Vs, F0), F2 = hooke_attraction(Key, Value, Vs, Es, F1), @@ -115,7 +117,7 @@ step(Vs, Es, Pa) -> Vx1 = (Vx + ?fg_th*Fx)*?fg_damp, Vy1 = (Vy + ?fg_th*Fy)*?fg_damp, - + Px1 = Px + ?fg_th*Vx1, Py1 = Py + ?fg_th*Vy1, @@ -123,14 +125,16 @@ step(Vs, Es, Pa) -> (Node) -> Node end, Vs). -point_attraction(_, #fg_v{ p = P0 }, Pa, {Fx, Fy}) when is_float(Fx), is_float(Fy) -> +point_attraction(_, #fg_v{ p = P0 }, Pa, {Fx, Fy}) + when is_float(Fx), is_float(Fy) -> K = 20, L = 150, {R, {Cx,Cy}} = composition(P0, Pa), F = -K*?fg_stretch*(R - L), {Fx + Cx*F, Fy + Cy*F}. - -coulomb_repulsion(K0, #fg_v{ p = P0, q = Q0}, Vs, {Fx0, Fy0}) when is_float(Fx0), is_float(Fy0) -> + +coulomb_repulsion(K0, #fg_v{ p = P0, q = Q0}, Vs, {Fx0, Fy0}) + when is_float(Fx0), is_float(Fy0) -> ?MODULE:foldl(fun ({K1, _}, F) when K1 == K0 -> F; ({_, #fg_v{ p = P1, q = Q1}}, {Fx, Fy}) -> @@ -140,7 +144,8 @@ coulomb_repulsion(K0, #fg_v{ p = P0, q = Q0}, Vs, {Fx0, Fy0}) when is_float(Fx0) (_, F) -> F end, {Fx0, Fy0}, Vs). -hooke_attraction(Key0, #fg_v{ p = P0 }, Vs, Es, {Fx0, Fy0}) when is_float(Fx0), is_float(Fy0) -> +hooke_attraction(Key0, #fg_v{ p = P0 }, Vs, Es, {Fx0, Fy0}) + when is_float(Fx0), is_float(Fy0) -> ?MODULE:foldl(fun ({{Key1,Key1}, _}, F) -> F; ({{Key1,Key2}, #fg_e{ l = L, k = K}}, {Fx, Fy}) when Key1 =:= Key0-> @@ -153,10 +158,11 @@ hooke_attraction(Key0, #fg_v{ p = P0 }, Vs, Es, {Fx0, Fy0}) when is_float(Fx0), {R, {Cx,Cy}} = composition(P0, P1), F = -K*?fg_stretch*(R - L), {Fx + Cx*F, Fy + Cy*F}; - (_, F) -> F + (_, F) -> F end, {Fx0, Fy0}, Es). -composition({Px1, Py1}, {Px0, Py0}) when is_float(Px1), is_float(Py1), is_float(Px0), is_float(Py0) -> +composition({Px1, Py1}, {Px0, Py0}) + when is_float(Px1), is_float(Py1), is_float(Px0), is_float(Py0) -> Dx = Px1 - Px0, Dy = Py1 - Py0, R = math:sqrt(Dx*Dx + Dy*Dy + 0.001), diff --git a/lib/reltool/src/reltool_fgraph_win.erl b/lib/reltool/src/reltool_fgraph_win.erl index b063fb94ba..c2054cc865 100644 --- a/lib/reltool/src/reltool_fgraph_win.erl +++ b/lib/reltool/src/reltool_fgraph_win.erl @@ -95,7 +95,7 @@ change_node(Pid, Key, Color) -> Pid ! {change_node, Key, Color}. add_link(Pid, {FromKey, ToKey}) -> Pid ! {add_link, {FromKey, ToKey}}. del_link(Pid, {FromKey, ToKey}) -> Pid ! {del_link, {FromKey, ToKey}}. -stop(Pid, Reason) -> +stop(Pid, Reason) -> Ref = erlang:monitor(process, Pid), Pid ! {stop, Reason}, receive @@ -110,21 +110,24 @@ new(Parent, Options) -> Me = self(), Pid = spawn_link(fun() -> init([Parent, Me, Env, Options]) end), receive {Pid, {?MODULE, Panel}} -> {Pid,Panel} end. - + init([ParentWin, Pid, Env, Options]) -> wx:set_env(Env), - + BReset = wxButton:new(ParentWin, ?reset, [{label,"Reset"}]), BFreeze = wxButton:new(ParentWin, ?freeze, [{label,"Freeze"}]), BLock = wxButton:new(ParentWin, ?lock, [{label,"Lock"}]), BUnlock = wxButton:new(ParentWin, ?unlock, [{label,"Unlock"}]), BDelete = wxButton:new(ParentWin, ?delete, [{label,"Delete"}]), - SQ = wxSlider:new(ParentWin, ?q_slider, ?default_q, 1, 500, [{style, ?wxVERTICAL}]), - SL = wxSlider:new(ParentWin, ?l_slider, ?default_l, 1, 500, [{style, ?wxVERTICAL}]), - SK = wxSlider:new(ParentWin, ?k_slider, ?default_k, 1, 500, [{style, ?wxVERTICAL}]), + SQ = wxSlider:new(ParentWin, ?q_slider, ?default_q, 1, 500, + [{style, ?wxVERTICAL}]), + SL = wxSlider:new(ParentWin, ?l_slider, ?default_l, 1, 500, + [{style, ?wxVERTICAL}]), + SK = wxSlider:new(ParentWin, ?k_slider, ?default_k, 1, 500, + [{style, ?wxVERTICAL}]), Win = wxWindow:new(ParentWin, ?wxID_ANY, Options), - + ButtonSizer = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(ButtonSizer, BReset), wxSizer:add(ButtonSizer, BFreeze), @@ -141,31 +144,34 @@ init([ParentWin, Pid, Env, Options]) -> WindowSizer = wxBoxSizer:new(?wxHORIZONTAL), wxSizer:add(WindowSizer, ButtonSizer, [{flag, ?wxEXPAND}, {proportion, 0}]), wxSizer:add(WindowSizer, Win, [{flag, ?wxEXPAND}, {proportion, 1}]), - + wxButton:setToolTip(BReset, "Remove selection and unlock all nodes."), wxButton:setToolTip(BFreeze, "Start/stop redraw of screen."), wxButton:setToolTip(BLock, "Lock all selected nodes."), wxButton:setToolTip(BUnlock, "Unlock all selected nodes."), wxButton:setToolTip(BDelete, "Delete all selected nodes."), - wxButton:setToolTip(SQ, "Control repulsive force. This can also be controlled with the mouse wheel on the canvas."), + wxButton:setToolTip(SQ, "Control repulsive force. This can also be" + " controlled with the mouse wheel on the canvas."), wxButton:setToolTip(SL, "Control link length."), wxButton:setToolTip(SK, "Control attractive force. Use with care."), - wxButton:setToolTip(Win, - "Drag mouse while left mouse button is pressed to perform various operations. " - "Combine with control key to select. Combine with shift key to lock single node."), + wxButton:setToolTip(Win, + "Drag mouse while left mouse button is pressed " + "to perform various operations. " + "Combine with control key to select. Combine " + "with shift key to lock single node."), wxButton:connect(BReset, command_button_clicked), wxButton:connect(BFreeze, command_button_clicked), wxButton:connect(BLock, command_button_clicked), wxButton:connect(BUnlock, command_button_clicked), wxButton:connect(BDelete, command_button_clicked), - + wxWindow:connect(SQ, command_slider_updated), wxWindow:connect(SL, command_slider_updated), wxWindow:connect(SK, command_slider_updated), - - wxWindow:connect(Win, enter_window), + + wxWindow:connect(Win, enter_window), wxWindow:connect(Win, move), wxWindow:connect(Win, motion), wxWindow:connect(Win, mousewheel), @@ -174,7 +180,7 @@ init([ParentWin, Pid, Env, Options]) -> wxWindow:connect(Win, left_up), wxWindow:connect(Win, right_down), wxWindow:connect(Win, paint, [{skip, true}]), - + Pen = wxPen:new({0,0,0}, [{width, 3}]), Font = wxFont:new(12, ?wxSWISS, ?wxNORMAL, ?wxNORMAL,[]), Brush = wxBrush:new({0,0,0}), @@ -182,13 +188,13 @@ init([ParentWin, Pid, Env, Options]) -> Pid ! {self(), {?MODULE, WindowSizer}}, wxWindow:setFocus(Win), %% Get keyboard focus - + Vs = reltool_fgraph:new(), Es = reltool_fgraph:new(), Me = self(), Ticker = spawn_link(fun() -> ticker_init(Me) end), - + loop( #state{ parent_pid = Pid, q_slider = SQ, l_slider = SL, @@ -215,14 +221,17 @@ graph_add_node(Key, Color, G = #graph{ vs = Vs}) -> M = 0.5, % mass P = {float(450 + random:uniform(100)), float(450 + random:uniform(100))}, - G#graph{ vs = reltool_fgraph:add(Key, #fg_v{ p = P, m = M, q = Q, color = Color}, Vs)}. + G#graph{ vs = reltool_fgraph:add(Key, + #fg_v{ p = P, m = M, q = Q, color = Color}, + Vs)}. graph_change_node(Key, Color, G) -> case reltool_fgraph:get(Key, G#graph.vs) of - undefined -> + undefined -> G; V -> - G#graph{ vs = reltool_fgraph:set(Key, V#fg_v{ color = Color }, G#graph.vs)} + G#graph{ vs = reltool_fgraph:set(Key, V#fg_v{ color = Color }, + G#graph.vs)} end. graph_del_node(Key, G = #graph{ vs = Vs0, es = Es0}) -> @@ -231,7 +240,7 @@ graph_del_node(Key, G = #graph{ vs = Vs0, es = Es0}) -> G#graph{ vs = Vs, es = Es }. graph_add_link(Key0, Key1, G = #graph{ es = Es}) -> - K = 60.0, % attractive force + K = 60.0, % attractive force L = 5.0, % spring length G#graph{ es = reltool_fgraph:add({Key0, Key1}, #fg_e{ k = K, l = L}, Es) }. @@ -249,15 +258,17 @@ ticker_loop(Pid, Time) -> D = timer:now_diff(T1, T0)/1000, case round(40 - D) of Ms when Ms < 0 -> - %io:format("ticker: wait is 0 ms [fg ~7s ms] [fps ~7s]~n", [s(D), s(1000/D)]), + %io:format("ticker: wait is 0 ms [fg ~7s ms] [fps ~7s]~n", + % [s(D), s(1000/D)]), ticker_loop(Pid, 0); Ms -> - %io:format("ticker: wait is ~3s ms [fg ~7s ms] [fps ~7s]~n", [s(Ms), s(D), s(1000/40)]), + %io:format("ticker: wait is ~3s ms [fg ~7s ms] [fps ~7s]~n", + % [s(Ms), s(D), s(1000/40)]), ticker_loop(Pid, Ms) end end. -delete_edges(Es, []) -> +delete_edges(Es, []) -> Es; delete_edges(Es, [Key|Keys]) -> Edges = reltool_fgraph:foldl(fun @@ -269,7 +280,7 @@ delete_edges(Es, [Key|Keys]) -> (K, Esi) -> reltool_fgraph:del(K, Esi) end, Es, Edges), delete_edges(Es1, Keys). - + set_charge(Q, Vs) -> % Repulsive force F = fun({Key, Value}) -> {Key, Value#fg_v{ q = Q}} end, @@ -295,36 +306,47 @@ loop(S, G) -> wxSlider:setValue(S#state.k_slider, K), Es = set_length(L, G#graph.es), Es2 = set_spring(K, Es), - - Vs2 = reltool_fgraph:map(fun({Key, V}) -> - {Key, V#fg_v{selected = false, type = dynamic, q = Q}} - end, - G#graph.vs), - - {Xs, Ys} = reltool_fgraph:foldl(fun({_Key, #fg_v{p = {X, Y}}}, {Xs, Ys}) -> - {[X| Xs], [Y | Ys]} - end, - {[], []}, - Vs2), + + Vs2 = + reltool_fgraph:map(fun({Key, V}) -> + {Key, V#fg_v{selected = false, + type = dynamic, + q = Q}} + end, + G#graph.vs), + + {Xs, Ys} = + reltool_fgraph:foldl(fun({_Key, + #fg_v{p = {X, Y}}}, {Xs, Ys}) -> + {[X| Xs], [Y | Ys]} + end, + {[], []}, + Vs2), %% io:format("Before: ~p\n", [G#graph.offset]), Offset = case length(Xs) of 0 -> {0, 0}; N -> - MeanX = (lists:sum(Xs) / N), + MeanX = (lists:sum(Xs) / N), MeanY = (lists:sum(Ys) / N), {SizeX, SizeY} = wxWindow:getSize(S#state.window), - %% io:format("Min: ~p\n", [{lists:min(Xs), lists:min(Ys)}]), - %% io:format("Mean: ~p\n", [{MeanX, MeanY}]), - %% io:format("Max: ~p\n", [{lists:max(Xs), lists:max(Ys)}]), + %% io:format("Min: ~p\n", + %% [{lists:min(Xs), lists:min(Ys)}]), + %% io:format("Mean: ~p\n", + %% [{MeanX, MeanY}]), + %% io:format("Max: ~p\n", + %% [{lists:max(Xs), lists:max(Ys)}]), %% io:format("Size: ~p\n", [{SizeX, SizeY}]), %% {XM - (XS / 2), YM - (YS / 2)} %% {0 - lists:min(Xs) + 20, 0 - lists:min(Ys) + 20} {0 - MeanX + (SizeX / 2), 0 - MeanY + (SizeY / 2)} end, %% io:format("After: ~p\n", [Offset]), - loop(S, G#graph{vs = Vs2, es = Es2, offset = Offset, offset_state = false}); + loop(S, G#graph{vs = Vs2, + es = Es2, + offset = Offset, + offset_state = false}); #wx{id = ?freeze, event = #wxCommand{type=command_button_clicked}} -> %% Start/stop redraw of screen IsFrozen = @@ -354,10 +376,15 @@ loop(S, G) -> loop(S, G#graph{ vs = Vs }); #wx{id = ?delete, event = #wxCommand{type=command_button_clicked}} -> %% Delete all selected nodes - {Vs1, Keys} = reltool_fgraph:foldl(fun - ({Key, #fg_v{ selected = true}}, {Vs, Ks}) -> - {reltool_fgraph:del(Key,Vs), [Key|Ks]}; - (_, {Vs, Ks}) -> {Vs, Ks} + {Vs1, Keys} = + reltool_fgraph:foldl(fun + ({Key, + #fg_v{ selected = true}}, + {Vs, Ks}) -> + {reltool_fgraph:del(Key,Vs), + [Key|Ks]}; + (_, {Vs, Ks}) -> + {Vs, Ks} end, {G#graph.vs,[]}, G#graph.vs), Es = delete_edges(G#graph.es, Keys), loop(S, G#graph{ vs = Vs1, es = Es}); @@ -368,20 +395,26 @@ loop(S, G) -> #wx{id = ?move, event = #wxCommand{type=command_button_clicked}} -> loop(S#state{ mouse_act = ?move }, G); - #wx{id = ?q_slider, event = #wxCommand{type=command_slider_updated, commandInt = Q}} -> + #wx{id = ?q_slider, event = #wxCommand{type=command_slider_updated, + commandInt = Q}} -> loop(S, G#graph{ vs = set_charge(Q, G#graph.vs)}); - #wx{id = ?l_slider, event = #wxCommand{type=command_slider_updated, commandInt = L}} -> + #wx{id = ?l_slider, event = #wxCommand{type=command_slider_updated, + commandInt = L}} -> loop(S, G#graph{ es = set_length(L, G#graph.es)}); - #wx{id = ?k_slider, event = #wxCommand{type=command_slider_updated, commandInt = K}} -> + #wx{id = ?k_slider, event = #wxCommand{type=command_slider_updated, + commandInt = K}} -> loop(S, G#graph{ es = set_spring(K, G#graph.es)}); #wx{event=#wxKey{type=key_up, keyCode = 127}} -> % delete {Vs1, Keys} = - reltool_fgraph:foldl(fun({Key, #fg_v{ selected = true}}, {Vs, Ks}) -> - {reltool_fgraph:del(Key,Vs), [Key|Ks]}; - (_, {Vs, Ks}) -> - {Vs, Ks} - end, - {G#graph.vs,[]}, G#graph.vs), + reltool_fgraph:foldl(fun({Key, + #fg_v{ selected = true}}, + {Vs, Ks}) -> + {reltool_fgraph:del(Key,Vs), + [Key|Ks]}; + (_, {Vs, Ks}) -> + {Vs, Ks} + end, + {G#graph.vs,[]}, G#graph.vs), Es = delete_edges(G#graph.es, Keys), loop(S, G#graph{ vs = Vs1, es = Es}); #wx{event=#wxKey{type=key_up}} -> @@ -390,7 +423,11 @@ loop(S, G) -> loop(S, G); %% mouse - #wx{event=#wxMouse{type=left_down, shiftDown=Shift, controlDown=Ctrl, x=X, y=Y}} -> + #wx{event=#wxMouse{type=left_down, + shiftDown=Shift, + controlDown=Ctrl, + x=X, + y=Y}} -> if Shift -> loop(S, mouse_left_down_move(G, {X,Y})); @@ -401,7 +438,11 @@ loop(S, G) -> S#state.mouse_act =:= ?select -> loop(S, mouse_left_down_select(G, {X,Y})) end; - #wx{event=#wxMouse{type=motion, shiftDown=Shift, controlDown=Ctrl, x=X, y=Y}} -> + #wx{event=#wxMouse{type=motion, + shiftDown=Shift, + controlDown=Ctrl, + x=X, + y=Y}} -> if Shift -> loop(S, mouse_motion_move(G, {X,Y})); @@ -412,7 +453,9 @@ loop(S, G) -> S#state.mouse_act =:= ?select -> loop(S, mouse_motion_select(G, {X,Y})) end; - #wx{event=#wxMouse{type=left_up, shiftDown=Shift, controlDown=Ctrl, x=X, y=Y}} -> + #wx{event=#wxMouse{type=left_up, + shiftDown=Shift, + controlDown=Ctrl, x=X, y=Y}} -> if Shift -> loop(S, mouse_left_up_move(G, {X,Y}, Shift)); @@ -424,7 +467,7 @@ loop(S, G) -> loop(S, mouse_left_up_select(G, {X,Y})) end; - #wx{event=#wxMouse{type=right_down,x=_X,y=_Y}} -> + #wx{event=#wxMouse{type=right_down,x=_X,y=_Y}} -> loop(S, G); %% mouse wheel #wx{event=#wxMouse{type=mousewheel, wheelRotation=Rotation}} -> @@ -436,7 +479,7 @@ loop(S, G) -> Rotation < 0 -> wxSlider:setValue(S#state.q_slider, Q + 4), loop(S, G#graph{ vs = set_charge(Q + 4, G#graph.vs) }); - true -> + true -> loop(S, G) end; @@ -448,7 +491,7 @@ loop(S, G) -> redraw(S, G), loop(S, G); #wx{obj=Win,event=#wxMouse{type=enter_window}} -> - wxWindow:setFocus(Win), + wxWindow:setFocus(Win), loop(S, G); %% Graph manipulation @@ -465,9 +508,11 @@ loop(S, G) -> {Req, redraw} -> {SizeX, SizeY} = wxWindow:getSize(S#state.window), - Vs = reltool_fgraph:step(G#graph.vs, G#graph.es, {SizeX/2.0 - 20.0, SizeY/2.0}), + Vs = reltool_fgraph:step(G#graph.vs, + G#graph.es, + {SizeX/2.0 - 20.0, SizeY/2.0}), case S#state.is_frozen of - false -> + false -> Req ! {self(), ok}; true -> ignore @@ -481,7 +526,7 @@ loop(S, G) -> Other -> error_logger:format("~p~p got unexpected message:\n\t~p\n", - [?MODULE, self(), Other]), + [?MODULE, self(), Other]), loop(S, G) end. @@ -494,17 +539,22 @@ mouse_left_down_move(#graph{vs = Vs} = G, {X, Y}) -> false -> G#graph{ offset_state = {X,Y}}; {true, Key} -> - V = #fg_v{ type = Type} = reltool_fgraph:get(Key, Vs), - G#graph{ vs = reltool_fgraph:set(Key, V#fg_v{ type = moving}, Vs), select = {node, Key, Type, X, Y} } + V = #fg_v{ type = Type} = reltool_fgraph:get(Key, Vs), + G#graph{ vs = reltool_fgraph:set(Key, + V#fg_v{ type = moving}, Vs), + select = {node, Key, Type, X, Y} } end. coord_to_key(#graph{vs = Vs, offset = {Xo, Yo}}, {X, Y}) -> Xr = X - Xo, Yr = Y - Yo, - reltool_fgraph:foldl(fun({Key, #fg_v{ p = {Px, Py}}}, _) when abs(Px - Xr) < 10, - abs(Py - Yr) < 10 -> {true, Key}; - (_, Out) -> Out - end, false, Vs). + reltool_fgraph:foldl(fun({Key, #fg_v{ p = {Px, Py}}}, _) + when abs(Px - Xr) < 10, + abs(Py - Yr) < 10 -> + {true, Key}; + (_, Out) -> + Out + end, false, Vs). mouse_left_up_select(G, {_X,_Y}) -> case G#graph.select of @@ -524,7 +574,7 @@ mouse_left_up_select(G, {_X,_Y}) -> _ -> G#graph{ select = none} end. - + mouse_left_up_move(G = #graph{ select = Select, vs = Vs} = G, {X,Y}, Shift) -> case Select of {node, Key, _, X, Y} -> @@ -543,7 +593,7 @@ mouse_left_up_move(G = #graph{ select = Select, vs = Vs} = G, {X,Y}, Shift) -> _ -> G#graph{ select = none, offset_state = false } end. - + mouse_motion_select(G, {X,Y}) -> case G#graph.select of {P0, _P1} -> G#graph{ select = {P0, {X,Y}}}; @@ -557,11 +607,11 @@ mouse_motion_move(G = #graph{ select = {node, Key, _, _, _}, vs = Vs}, {X,Y}) -> G#graph{ vs = reltool_fgraph:set(Key, V2, Vs) }; mouse_motion_move(G, {X,Y}) -> case G#graph.offset_state of - {X1,Y1} -> + {X1,Y1} -> {X0, Y0} = G#graph.offset, G#graph{ offset_state = {X,Y}, offset = {X0 - (X1 - X), Y0 - (Y1 - Y)} }; - _ -> + _ -> G end. @@ -574,9 +624,9 @@ redraw(#state{window=Win}, G) -> wxClientDC:destroy(DC0), ok. -redraw(DC, _Size, G) -> - wx:batch(fun() -> - +redraw(DC, _Size, G) -> + wx:batch(fun() -> + Pen = G#graph.pen, Font = G#graph.font, Brush = G#graph.brush, @@ -587,7 +637,7 @@ redraw(DC, _Size, G) -> wxPen:setWidth(Pen, 1), wxDC:clear(DC), - % draw vertices and edges + % draw vertices and edges wxPen:setColour(Pen, ?color_fg), wxDC:setPen(DC,Pen), @@ -602,7 +652,9 @@ redraw(DC, _Size, G) -> % draw information text wxFont:setWeight(Font,?wxNORMAL), - draw_text(DC, reltool_fgraph:size(G#graph.vs), reltool_fgraph:size(G#graph.es), G#graph.ke), + draw_text(DC, + reltool_fgraph:'size'(G#graph.vs), + reltool_fgraph:'size'(G#graph.es), G#graph.ke), ok end). @@ -612,14 +664,14 @@ draw_select_box(DC, {{X0,Y0}, {X1,Y1}}) -> draw_line(DC, {X1,Y1}, {X0,Y1}, {0,0}), draw_line(DC, {X0,Y0}, {X0,Y1}, {0,0}), ok; -draw_select_box(_DC, _) -> +draw_select_box(_DC, _) -> ok. draw_es(DC, Vs, Es, Po, Pen, Brush) -> reltool_fgraph:foreach(fun ({{K1, K2}, _}) -> - #fg_v{ p = P1} = reltool_fgraph:get(K1, Vs), - #fg_v{ p = P2} = reltool_fgraph:get(K2, Vs), + #fg_v{ p = P1} = reltool_fgraph:'get'(K1, Vs), + #fg_v{ p = P2} = reltool_fgraph:'get'(K2, Vs), draw_arrow(DC, P1, P2, Po, Pen, Brush) end, Es). @@ -650,10 +702,15 @@ draw_arrow(DC, {X0,Y0}, {X1, Y1}, {X, Y}, Pen, Brush) -> wxDC:drawPolygon(DC, Points, []). draw_line(DC, {X0,Y0}, {X1, Y1}, {X, Y}) -> - wxDC:drawLine(DC, {round(X0 + X), round(Y0 + Y)}, {round(X1 + X), round(Y1 + Y)}). - + wxDC:drawLine(DC, + {round(X0 + X), round(Y0 + Y)}, + {round(X1 + X), round(Y1 + Y)}). + draw_vs(DC, Vs, {Xo, Yo}, Pen, Brush) -> - reltool_fgraph:foreach(fun({Key, #fg_v{ p ={X, Y}, color = Color, selected = Sel}}) -> + reltool_fgraph:foreach(fun({Key, + #fg_v{p ={X, Y}, + color = Color, + selected = Sel}}) -> String = s(Key), case Sel of true -> @@ -661,35 +718,49 @@ draw_vs(DC, Vs, {Xo, Yo}, Pen, Brush) -> wxBrush:setColour(Brush, ?color_bg), wxDC:setPen(DC,Pen), wxDC:setBrush(DC, Brush), - SelProps = {round(X-12 + Xo), round(Y-12 + Yo), 24, 24}, - wxDC:drawRoundedRectangle(DC, SelProps, float(?ARC_R)), + SelProps = {round(X-12 + Xo), + round(Y-12 + Yo), + 24, + 24}, + wxDC:drawRoundedRectangle(DC, + SelProps, + float(?ARC_R)), ok; false -> ok end, case Color of - default -> + default -> wxPen:setColour(Pen, ?color_default), - wxBrush:setColour(Brush, ?color_default_bg); - alternate -> - wxPen:setColour(Pen, ?color_alternate), - wxBrush:setColour(Brush, ?color_alternate_bg); + wxBrush:setColour(Brush, + ?color_default_bg); + alternate -> + wxPen:setColour(Pen, + ?color_alternate), + wxBrush:setColour(Brush, + ?color_alternate_bg); {FgColor, BgColor} -> wxPen:setColour(Pen, FgColor), - wxBrush:setColour(Brush, BgColor); + wxBrush:setColour(Brush, BgColor); Color -> wxPen:setColour(Pen, Color), wxBrush:setColour(Brush, Color) end, wxDC:setPen(DC,Pen), wxDC:setBrush(DC, Brush), - NodeProps = {round(X-8 + Xo),round(Y-8 + Yo),17,17}, - wxDC:drawRoundedRectangle(DC, NodeProps, float(?ARC_R)), - wxDC:drawText(DC, String, {round(X + Xo), round(Y + Yo)}), + NodeProps = {round(X-8 + Xo), + round(Y-8 + Yo),17,17}, + wxDC:drawRoundedRectangle(DC, + NodeProps, + float(?ARC_R)), + wxDC:drawText(DC, + String, + {round(X + Xo), + round(Y + Yo)}), ok; (_) -> ok - end, + end, Vs). draw_text(DC, Nvs, Nes, _KE) -> @@ -720,7 +791,7 @@ calc_point({X, Y}, Length, Radians) -> %% %% Convert from an angle in radians to degrees %% radians_to_degrees(Radians) -> %% Radians * 180 / math:pi(). -%% +%% %% %% Convert from an angle in degrees to radians %% degrees_to_radians(Degrees) -> %% Degrees * math:pi() / 180. diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl index 754f6a0e8a..dd8e44eefe 100644 --- a/lib/reltool/src/reltool_mod_win.erl +++ b/lib/reltool/src/reltool_mod_win.erl @@ -34,7 +34,7 @@ -include_lib("wx/include/wx.hrl"). -include("reltool.hrl"). --record(state, +-record(state, {parent_pid, xref_pid, rel_pid, @@ -73,7 +73,7 @@ -define(WIN_HEIGHT, 600). -define(CLOSE_ITEM, ?wxID_EXIT). %% Use OS specific version if available --define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific +-define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific -define(CONTENTS_ITEM, 300). -define(SEARCH_ENTRY, 413). -define(GOTO_ENTRY, 414). @@ -87,7 +87,11 @@ %% Client start_link(WxEnv, Xref, RelPid, Common, ModName) -> - proc_lib:start_link(?MODULE, init, [self(), WxEnv, Xref, RelPid, Common, ModName], infinity, []). + proc_lib:start_link(?MODULE, + init, + [self(), WxEnv, Xref, RelPid, Common, ModName], + infinity, + []). raise(Pid) -> reltool_utils:cast(Pid, raise). @@ -127,10 +131,15 @@ loop(#state{xref_pid = Xref, common = C, mod = Mod} = S) -> receive Msg -> %% io:format("~s~p -> ~p\n", [S#state.name, self(), Msg]), - case Msg of + case Msg of {system, From, SysMsg} -> Dbg = C#common.sys_debug, - sys:handle_system_msg(SysMsg, From, S#state.parent_pid, ?MODULE, Dbg, S); + sys:handle_system_msg(SysMsg, + From, + S#state.parent_pid, + ?MODULE, + Dbg, + S); {cast, _From, raise} -> wxFrame:raise(S#state.frame), wxFrame:setFocus(S#state.frame), @@ -169,7 +178,7 @@ loop(#state{xref_pid = Xref, common = C, mod = Mod} = S) -> create_window(#state{mod = Mod, name = ModStr} = S) -> Title = atom_to_list(?APPLICATION) ++ " - " ++ - atom_to_list(Mod#mod.app_name) ++ " - " ++ + atom_to_list(Mod#mod.app_name) ++ " - " ++ ModStr ++ ".erl", Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, []), %% wxFrame:setSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}), @@ -177,7 +186,7 @@ create_window(#state{mod = Mod, name = ModStr} = S) -> StatusBar = wxFrame:createStatusBar(Frame,[]), Book = wxNotebook:new(Panel, ?wxID_ANY, []), - + S2 = S#state{frame = Frame, panel = Panel, book = Book, @@ -204,11 +213,17 @@ create_deps_page(S) -> Panel = wxPanel:new(S#state.book, []), Main = wxBoxSizer:new(?wxHORIZONTAL), - UsedByCtrl = create_mods_list_ctrl(Panel, Main, "Modules used by others", " and their applications"), + UsedByCtrl = create_mods_list_ctrl(Panel, + Main, + "Modules used by others", + " and their applications"), wxSizer:add(Main, wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]), [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]), - UsesCtrl = create_mods_list_ctrl(Panel, Main, "Used modules", " and their applications"), + UsesCtrl = create_mods_list_ctrl(Panel, + Main, + "Used modules", + " and their applications"), S2 = S#state{deps_used_by_ctrl = UsedByCtrl, deps_uses_ctrl = UsesCtrl}, redraw_mods(S2), @@ -242,8 +257,10 @@ create_mods_list_ctrl(Panel, Sizer, ModText, AppText) -> %% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, ?MODS_APP_COL_WIDTH), wxListItem:destroy(ListItem), - wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, mods_list_ctrl}]), - wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_app}]), + wxEvtHandler:connect(ListCtrl, size, + [{skip, true}, {userData, mods_list_ctrl}]), + wxListCtrl:connect(ListCtrl, command_list_item_activated, + [{userData, open_app}]), wxWindow:connect(ListCtrl, enter_window), wxSizer:add(Sizer, ListCtrl, @@ -252,7 +269,8 @@ create_mods_list_ctrl(Panel, Sizer, ModText, AppText) -> {proportion, 1}]), ListCtrl. -create_code_page(#state{book = Book, code_pages = Pages, name = ModStr} = S, PageName) -> +create_code_page(#state{book = Book, code_pages = Pages, name = ModStr} = S, + PageName) -> case find_page(S, PageName) of not_found -> Page = do_create_code_page(S, PageName), @@ -260,7 +278,7 @@ create_code_page(#state{book = Book, code_pages = Pages, name = ModStr} = S, Pag Pos = length(Pages2), wxNotebook:setSelection(Book, Pos), case find_page(S, ?INITIAL_CODE_PAGE_NAME) of - not_found -> + not_found -> ignore; {found, _, CodePos} -> %% Rename initial code page @@ -288,25 +306,29 @@ find_page([], _PageName, _Pos) -> do_create_code_page(#state{xref_pid = Xref, mod = M} = S, PageName) -> Panel = wxPanel:new(S#state.book, []), Editor = create_editor(Panel), - ToolTip = "Double click on a function call to search the function definition.", + ToolTip = "Double click on a function call to " + "search the function definition.", wxBitmapButton:setToolTip(Editor, ToolTip), {Objs, Data, SearchSz} = create_search_area(Panel), {ok, App} = reltool_server:get_app(Xref, M#mod.app_name), - ErlBin = + ErlBin = case App#app.is_escript of true -> find_escript_bin(App, M); false -> find_regular_bin(App, M) end, - + load_code(Editor, ErlBin), - + Sizer = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(Sizer, Editor, [{flag, ?wxEXPAND}, {proportion, 1}]), wxSizer:add(Sizer, SearchSz, [{flag, ?wxEXPAND}]), wxPanel:setSizer(Panel, Sizer), wxNotebook:addPage(S#state.book, Panel, PageName, []), - #code_page{name = PageName, editor = Editor, find_objs = Objs, find_data = Data}. + #code_page{name = PageName, + editor = Editor, + find_objs = Objs, + find_data = Data}. find_regular_bin(App, Mod) -> ActiveDir = App#app.active_dir, @@ -322,9 +344,11 @@ find_regular_bin(App, Mod) -> BeamFile = filename:join([ActiveDir, "ebin", ModStr ++ ".beam"]), case beam_lib:chunks(BeamFile, [abstract_code]) of {ok,{_,[{abstract_code,{_,AC}}]}} -> - list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC))); + IoList = erl_prettypr:format(erl_syntax:form_list(AC)), + list_to_binary(IoList); _ -> - list_to_binary(["%% Bad luck, cannot find any debug info in the file \"", BeamFile]) + list_to_binary(["%% Bad luck, cannot find any " + "debug info in the file \"", BeamFile]) end end. @@ -340,10 +364,17 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) -> [_] -> Bin = GetBin(), case beam_lib:version(Bin) of - {ok,{M, _}} when M =:= ModName; FullName =:= "." -> - case beam_lib:chunks(Bin, [abstract_code]) of + {ok,{M, _}} when M =:= ModName; + FullName =:= "." -> + case beam_lib:chunks(Bin, + [abstract_code]) of {ok,{_,[{abstract_code,{_,AC}}]}} -> - {obj, list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)))}; + Form = + erl_syntax:form_list(AC), + IoList = + erl_prettypr:format(Form), + {obj, + list_to_binary(IoList)}; _ -> Acc end; @@ -363,10 +394,14 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) -> {fun(FullName, _GetInfo, GetBin, Acc) -> io:format("", []), case filename:split(FullName) of - [_AppName, "ebin", F] when F =:= ObjFile, Acc =:= NotFound -> - case beam_lib:chunks(GetBin(), [abstract_code]) of + [_AppName, "ebin", F] + when F =:= ObjFile, Acc =:= NotFound -> + case beam_lib:chunks(GetBin(), + [abstract_code]) of {ok,{_,[{abstract_code,{_,AC}}]}} -> - {obj, list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)))}; + Form = erl_syntax:form_list(AC), + IoList = erl_prettypr:format(Form), + {obj, list_to_binary(IoList)}; _ -> Acc end; @@ -385,11 +420,13 @@ find_escript_bin(#app{active_dir = ActiveDir}, Mod) -> {ok, {obj, Bin}} -> Bin; _ -> - list_to_binary(["%% Bad luck, cannot find the code in the escript ", Escript, "."]) + list_to_binary(["%% Bad luck, cannot find the " + "code in the escript ", Escript, "."]) end - catch + catch throw:Reason when is_list(Reason) -> - list_to_binary(["%% Bad luck, cannot find the code in the escript ", Escript, ": ", Reason]) + list_to_binary(["%% Bad luck, cannot find the code " + "in the escript ", Escript, ": ", Reason]) end. create_config_page(S) -> @@ -400,13 +437,16 @@ create_config_page(S) -> handle_event(#state{xref_pid = Xref} = S, Wx) -> %% io:format("wx: ~p\n", [Wx]), case Wx of - #wx{obj= ListCtrl, userData = mods_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} -> + #wx{obj= ListCtrl, + userData = mods_list_ctrl, + event = #wxSize{type = size, size = {W, _H}}} -> wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, (2 * W) div 3), wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, W div 3), S; #wx{userData = open_app, obj = ListCtrl, - event = #wxList{type = command_list_item_activated, itemIndex = Pos}} -> + event = #wxList{type = command_list_item_activated, + itemIndex = Pos}} -> ModStr = wxListCtrl:getItemText(ListCtrl, Pos), ModName = list_to_atom(ModStr), {ok, Mod} = reltool_server:get_mod(Xref, ModName), @@ -431,13 +471,15 @@ handle_event(#state{xref_pid = Xref} = S, Wx) -> Page = lists:nth(N, S#state.code_pages), S#state{active_page = Page} end; - #wx{event = #wxCommand{type = command_button_clicked}, userData = history_back} -> + #wx{event = #wxCommand{type = command_button_clicked}, + userData = history_back} -> goto_back(S); #wx{obj = ObjRef, event = #wxMouse{type = enter_window}} -> wxWindow:setFocus(ObjRef), S; _ -> - error_logger:format("~p~p got unexpected mod event from wx:\n\t~p\n", + error_logger:format("~p~p got unexpected mod event from " + "wx:\n\t~p\n", [?MODULE, self(), Wx]), S end. @@ -450,7 +492,7 @@ redraw_mods(#state{xref_pid = Xref, uses_mods = UsesModNames, used_by_mods = UsedByModNames}, status_bar = Bar}) -> - InclStatus = + InclStatus = case IsIncl of true when IsPre =:= true -> "Whitelist - "; true -> "Derived - "; @@ -458,8 +500,10 @@ redraw_mods(#state{xref_pid = Xref, undefined -> "Source - " end, Status = lists:concat([InclStatus, - " uses ", length(UsesModNames), " modules and ", - " is used by ", length(UsedByModNames), " modules."]), + " uses ", length(UsesModNames), + " modules and ", + " is used by ", length(UsedByModNames), + " modules."]), wxStatusBar:setStatusText(Bar, Status), UsesMods = [select_image(Xref, M) || M <- UsesModNames], UsedByMods = [select_image(Xref, M) || M <- UsedByModNames], @@ -483,9 +527,11 @@ redraw_mods(ListCtrl, ImageMods) -> wxListCtrl:deleteAllItems(ListCtrl), Add = fun({ImageId, AppName, #mod{name = ModName}}, Row) -> - wxListCtrl:insertItem(ListCtrl, Row, ""), - if (Row rem 2) =:= 0 -> - wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255}); + wxListCtrl:insertItem(ListCtrl, Row, ""), + if (Row rem 2) =:= 0 -> + wxListCtrl:setItemBackgroundColour(ListCtrl, + Row, + {240,240,255}); true -> ignore end, @@ -515,16 +561,16 @@ goto_line(#state{active_page = P} = S, LineNo) when is_integer(LineNo) -> wxStyledTextCtrl:setSelection(Editor, Left, Right), S; goto_line(#state{active_page = P} =S, Str) when is_list(Str) -> - try + try LineNo = list_to_integer(Str), CurrentPos = wxStyledTextCtrl:getCurrentPos(P#code_page.editor), S2 = add_pos_to_history(S, CurrentPos), goto_line(S2, LineNo - 1) - catch + catch _:_ -> wxStatusBar:setStatusText(S#state.status_bar, "Not a line number"), S - end. + end. find_string(S, Str) -> find_string(S, Str, 0). @@ -535,19 +581,20 @@ find_regexp_forward(S, Str) -> wxTextCtrl:setValue(TextCtrl, Str), S2. -find_string(#state{active_page = #code_page{editor = Editor, - find_objs = #find_objs{radio={NextO,_,CaseO}}, - find_data = #find_data{found = Found} = Data} = P} = S, +find_string(#state{active_page = + #code_page{editor = Editor, + find_objs = #find_objs{radio={NextO,_,CaseO}}, + find_data = #find_data{found = Found} = Data} = P} = S, Str, Flag) -> wxStyledTextCtrl:hideSelection(Editor, true), Dir = wxRadioButton:getValue(NextO) xor wx_misc:getKeyState(?WXK_SHIFT), Case = wxCheckBox:getValue(CaseO), Pos = - if + if Found, Dir -> %% Forward Continuation wxStyledTextCtrl:getAnchor(Editor); - Found -> %% Backward Continuation + Found -> %% Backward Continuation wxStyledTextCtrl:getCurrentPos(Editor); Dir -> %% Forward wrap 0; @@ -556,18 +603,18 @@ find_string(#state{active_page = #code_page{editor = Editor, end, wxStyledTextCtrl:gotoPos(Editor,Pos), wxStyledTextCtrl:searchAnchor(Editor), - Flag2 = + Flag2 = if Case -> Flag bor ?wxSTC_FIND_MATCHCASE; true -> Flag end, - Res = - if + Res = + if Dir -> wxStyledTextCtrl:searchNext(Editor, Flag2, Str); true -> wxStyledTextCtrl:searchPrev(Editor, Flag2, Str) end, - Found2 = + Found2 = case Res >= 0 of - true -> + true -> wxStyledTextCtrl:hideSelection(Editor, false), %% io:format("Found ~p ~n",[Res]), LineNo = wxStyledTextCtrl:lineFromPosition(Editor,Res), @@ -576,11 +623,15 @@ find_string(#state{active_page = #code_page{editor = Editor, true; false -> wxStatusBar:setStatusText(S#state.status_bar, - "Not found (Hit Enter to wrap search)"), + "Not found (Hit Enter to " + "wrap search)"), false - end, + end, P2 = P#code_page{find_data = Data#find_data{found = Found2}}, - Pages = lists:keystore(P#code_page.name, #code_page.name, S#state.code_pages, P2), + Pages = lists:keystore(P#code_page.name, + #code_page.name, + S#state.code_pages, + P2), S#state{active_page = P2, code_pages = Pages}. goto_function(S, Editor) -> @@ -589,14 +640,14 @@ goto_function(S, Editor) -> Left = wxStyledTextCtrl:wordStartPosition(Editor, CurrentPos, true), Right = wxStyledTextCtrl:wordEndPosition(Editor, CurrentPos, true), ColonPos = Left - 1, - Left2 = + Left2 = case wxStyledTextCtrl:getCharAt(Editor, ColonPos) of $: -> wxStyledTextCtrl:wordStartPosition(Editor, ColonPos, true); _ -> Left end, - Right2 = + Right2 = case wxStyledTextCtrl:getCharAt(Editor, Right) of $: -> wxStyledTextCtrl:wordEndPosition(Editor, Right + 1, true); @@ -627,29 +678,37 @@ do_goto_function(S, [ModStr, FunStr]) -> S2 = create_code_page(S#state{mod = Mod}, ModStr), find_regexp_forward(S2, "^" ++ FunStr ++ "("); {ok, _} -> - wxStatusBar:setStatusText(S#state.status_bar, "No such module: " ++ ModStr), + wxStatusBar:setStatusText(S#state.status_bar, + "No such module: " ++ ModStr), S end. -goto_back(#state{active_page = #code_page{editor = Editor, find_data = Data} = Page, +goto_back(#state{active_page = + #code_page{editor = Editor, find_data = Data} = Page, code_pages = Pages} = S) -> case Data#find_data.history of [PrevPos | History] -> LineNo = wxStyledTextCtrl:lineFromPosition(Editor, PrevPos), Data2 = Data#find_data{history = History}, Page2 = Page#code_page{find_data = Data2}, - Pages2 = lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2), - goto_line(S#state{active_page = Page2, code_pages = Pages2}, LineNo); + Pages2 = lists:keystore(Page2#code_page.name, + #code_page.name, + Pages, + Page2), + goto_line(S#state{active_page = Page2, code_pages = Pages2}, + LineNo); [] -> wxStatusBar:setStatusText(S#state.status_bar, "No history"), S end. -add_pos_to_history(#state{active_page = Page, code_pages = Pages} = S, CurrentPos) -> +add_pos_to_history(#state{active_page = Page, code_pages = Pages} = S, + CurrentPos) -> Data = Page#code_page.find_data, Data2 = Data#find_data{history = [CurrentPos | Data#find_data.history]}, Page2 = Page#code_page{find_data = Data2}, - Pages2 = lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2), + Pages2 = + lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2), S#state{active_page = Page2, code_pages = Pages2}. create_editor(Parent) -> @@ -690,19 +749,26 @@ create_editor(Parent) -> %% Margins Markers %% Breakpoint Should be a pixmap? - wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, [{foreground, {170,20,20}}]), - wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, [{background, {200,120,120}}]), - %% Disabled Breakpoint - wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, [{foreground, {20,20,170}}]), - wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, [{background, {120,120,200}}]), - + wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, + [{foreground, {170,20,20}}]), + wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, + [{background, {200,120,120}}]), + %% Disabled Breakpoint + wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, + [{foreground, {20,20,170}}]), + wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, + [{background, {120,120,200}}]), + %% Current Line - wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, [{foreground, {20,170,20}}]), - wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, [{background, {200,255,200}}]), - wxStyledTextCtrl:markerDefine(Ed, 3, ?wxSTC_MARK_BACKGROUND, [{background, {200,255,200}}]), + wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, + [{foreground, {20,170,20}}]), + wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, + [{background, {200,255,200}}]), + wxStyledTextCtrl:markerDefine(Ed, 3, ?wxSTC_MARK_BACKGROUND, + [{background, {200,255,200}}]), %% Scrolling - Policy = ?wxSTC_CARET_SLOP bor ?wxSTC_CARET_JUMPS bor ?wxSTC_CARET_EVEN, + Policy = ?wxSTC_CARET_SLOP bor ?wxSTC_CARET_JUMPS bor ?wxSTC_CARET_EVEN, wxStyledTextCtrl:setYCaretPolicy(Ed, Policy, 3), wxStyledTextCtrl:setVisiblePolicy(Ed, Policy, 3), @@ -714,9 +780,9 @@ create_editor(Parent) -> create_search_area(Parent) -> Sizer = wxBoxSizer:new(?wxHORIZONTAL), - wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Find:"), + wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Find:"), [{flag,?wxALIGN_CENTER_VERTICAL}]), - TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), + TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), wxSizer:add(Sizer, TC1, [{proportion,3}, {flag, ?wxEXPAND}]), Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"), wxRadioButton:setValue(Nbtn, true), @@ -726,14 +792,15 @@ create_search_area(Parent) -> Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"), wxSizer:add(Sizer,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]), wxSizer:add(Sizer, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]), - wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"), + wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"), [{flag,?wxALIGN_CENTER_VERTICAL}]), - TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), + TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]), wxSizer:add(Sizer, TC2, [{proportion,0}, {flag, ?wxEXPAND}]), Button = wxButton:new(Parent, ?wxID_ANY, [{label, "Back"}]), wxSizer:add(Sizer, Button, []), - wxEvtHandler:connect(Button, command_button_clicked, [{userData, history_back}]), + wxEvtHandler:connect(Button, command_button_clicked, + [{userData, history_back}]), %% wxTextCtrl:connect(TC1, command_text_updated), wxTextCtrl:connect(TC1, command_text_enter), %% wxTextCtrl:connect(TC1, kill_focus), @@ -748,7 +815,9 @@ load_code(Ed, Code) when is_binary(Code) -> wxStyledTextCtrl:setTextRaw(Ed, <>), Lines = wxStyledTextCtrl:getLineCount(Ed), Sz = trunc(math:log10(Lines))+1, - LW = wxStyledTextCtrl:textWidth(Ed, ?wxSTC_STYLE_LINENUMBER, lists:duplicate(Sz, $9)), + LW = wxStyledTextCtrl:textWidth(Ed, + ?wxSTC_STYLE_LINENUMBER, + lists:duplicate(Sz, $9)), %%io:format("~p ~p ~p~n", [Lines, Sz, LW]), wxStyledTextCtrl:setMarginWidth(Ed, 0, LW+5), wxStyledTextCtrl:setReadOnly(Ed, true), diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl index 11839e6a0e..c8364285b8 100644 --- a/lib/reltool/src/reltool_server.erl +++ b/lib/reltool/src/reltool_server.erl @@ -44,7 +44,7 @@ -include("reltool.hrl"). --record(state, +-record(state, {options, parent_pid, common, @@ -60,16 +60,20 @@ start_link() -> start_link([]). start_link(Options) -> - proc_lib:start_link(?MODULE, init, [[{parent, self()} | Options]], infinity, []). + proc_lib:start_link(?MODULE, + init, + [[{parent, self()} | Options]], + infinity, + []). -get_config(Pid, InclDefaults, InclDerivates) -> - reltool_utils:call(Pid, {get_config, InclDefaults, InclDerivates}). +get_config(Pid, InclDef, InclDeriv) -> + reltool_utils:call(Pid, {get_config, InclDef, InclDeriv}). load_config(Pid, FilenameOrConfig) -> reltool_utils:call(Pid, {load_config, FilenameOrConfig}). -save_config(Pid, Filename, InclDefaults, InclDerivates) -> - reltool_utils:call(Pid, {save_config, Filename, InclDefaults, InclDerivates}). +save_config(Pid, Filename, InclDef, InclDeriv) -> + reltool_utils:call(Pid, {save_config, Filename, InclDef, InclDeriv}). reset_config(Pid) -> reltool_utils:call(Pid, reset_config). @@ -131,7 +135,8 @@ do_init(Options) -> case parse_options(Options) of {#state{parent_pid = ParentPid, common = C, sys = Sys} = S, Status} -> %% process_flag(trap_exit, (S#state.common)#common.trap_exit), - proc_lib:init_ack(ParentPid, {ok, self(), C, Sys#sys{apps = undefined}}), + proc_lib:init_ack(ParentPid, + {ok, self(), C, Sys#sys{apps = undefined}}), {S2, Status2} = refresh(S, true, Status), {S3, Status3} = analyse(S2#state{old_sys = S2#state.sys}, Status2), case Status3 of @@ -156,15 +161,33 @@ parse_options(Opts) -> rels = reltool_utils:default_rels(), emu_name = ?DEFAULT_EMU_NAME, profile = ?DEFAULT_PROFILE, - incl_sys_filters = reltool_utils:decode_regexps(incl_sys_filters, ?DEFAULT_INCL_SYS_FILTERS, []), - excl_sys_filters = reltool_utils:decode_regexps(excl_sys_filters, ?DEFAULT_EXCL_SYS_FILTERS, []), - incl_app_filters = reltool_utils:decode_regexps(incl_app_filters, ?DEFAULT_INCL_APP_FILTERS, []), - excl_app_filters = reltool_utils:decode_regexps(excl_app_filters, ?DEFAULT_EXCL_APP_FILTERS, []), + incl_sys_filters = + reltool_utils:decode_regexps(incl_sys_filters, + ?DEFAULT_INCL_SYS_FILTERS, + []), + excl_sys_filters = + reltool_utils:decode_regexps(excl_sys_filters, + ?DEFAULT_EXCL_SYS_FILTERS, + []), + incl_app_filters = + reltool_utils:decode_regexps(incl_app_filters, + ?DEFAULT_INCL_APP_FILTERS, + []), + excl_app_filters = + reltool_utils:decode_regexps(excl_app_filters, + ?DEFAULT_EXCL_APP_FILTERS, + []), relocatable = ?DEFAULT_RELOCATABLE, app_type = ?DEFAULT_APP_TYPE, app_file = ?DEFAULT_APP_FILE, - incl_archive_filters = reltool_utils:decode_regexps(incl_archive_filters, ?DEFAULT_INCL_ARCHIVE_FILTERS, []), - excl_archive_filters = reltool_utils:decode_regexps(excl_archive_filters, ?DEFAULT_EXCL_ARCHIVE_FILTERS, []), + incl_archive_filters = + reltool_utils:decode_regexps(incl_archive_filters, + ?DEFAULT_INCL_ARCHIVE_FILTERS, + []), + excl_archive_filters = + reltool_utils:decode_regexps(excl_archive_filters, + ?DEFAULT_EXCL_ARCHIVE_FILTERS, + []), archive_opts = ?DEFAULT_ARCHIVE_OPTS, debug_info = ?DEFAULT_DEBUG_INFO}, C2 = #common{sys_debug = [], @@ -194,30 +217,38 @@ parse_options([{Key, Val} | KeyVals], S, C, Sys, Status) -> parse_options(KeyVals, S, C, Sys2, Status2); _ -> Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - Status2 = reltool_utils:return_first_error(Status, "Illegal option: " ++ Text), + Status2 = + reltool_utils:return_first_error(Status, + "Illegal option: " ++ Text), parse_options(KeyVals, S, C, Sys, Status2) end; parse_options([], S, C, Sys, Status) -> {S#state{common = C, sys = Sys}, Status}; parse_options(KeyVals, S, C, Sys, Status) -> Text = lists:flatten(io_lib:format("~p", [KeyVals])), - Status2 = reltool_utils:return_first_error(Status, "Illegal options: " ++ Text), + Status2 = reltool_utils:return_first_error(Status, + "Illegal options: " ++ Text), {S#state{common = C, sys = Sys}, Status2}. loop(#state{common = C, sys = Sys} = S) -> receive {system, From, Msg} -> - sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, C#common.sys_debug, S); - {call, ReplyTo, Ref, {get_config, InclDefaults, InclDerivates}} -> - Reply = do_get_config(S, InclDefaults, InclDerivates), + sys:handle_system_msg(Msg, + From, + S#state.parent_pid, + ?MODULE, + C#common.sys_debug, + S); + {call, ReplyTo, Ref, {get_config, InclDef, InclDeriv}} -> + Reply = do_get_config(S, InclDef, InclDeriv), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, {load_config, SysConfig}} -> {S2, Reply} = do_load_config(S, SysConfig), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S2); - {call, ReplyTo, Ref, {save_config, Filename, InclDefaults, InclDerivates}} -> - Reply = do_save_config(S, Filename, InclDefaults, InclDerivates), + {call, ReplyTo, Ref, {save_config, Filename, InclDef, InclDeriv}} -> + Reply = do_save_config(S, Filename, InclDef, InclDeriv), reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, reset_config} -> @@ -225,7 +256,7 @@ loop(#state{common = C, sys = Sys} = S) -> S3 = shrink_sys(S2), {S4, Status2} = refresh(S3, true, Status), {S5, Status3} = analyse(S4#state{old_sys = S4#state.sys}, Status2), - S6 = + S6 = case Status3 of {ok, _Warnings} -> S5#state{status = Status3, old_status = S#state.status}; @@ -236,14 +267,14 @@ loop(#state{common = C, sys = Sys} = S) -> ?MODULE:loop(S6); {call, ReplyTo, Ref, undo_config} -> reltool_utils:reply(ReplyTo, Ref, ok), - S2 = S#state{sys = S#state.old_sys, + S2 = S#state{sys = S#state.old_sys, old_sys = S#state.sys, status = S#state.old_status, old_status = S#state.status}, ?MODULE:loop(S2); {call, ReplyTo, Ref, {get_rel, RelName}} -> Sys = S#state.sys, - Reply = + Reply = case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of {value, Rel} -> {ok, reltool_target:gen_rel(Rel, Sys)}; @@ -254,12 +285,12 @@ loop(#state{common = C, sys = Sys} = S) -> ?MODULE:loop(S); {call, ReplyTo, Ref, {get_script, RelName}} -> Sys = S#state.sys, - Reply = + Reply = case lists:keysearch(RelName, #rel.name, Sys#sys.rels) of {value, Rel} -> PathFlag = true, - Variables = [], - reltool_target:gen_script(Rel, Sys, PathFlag, Variables); + Vars = [], + reltool_target:gen_script(Rel, Sys, PathFlag, Vars); false -> {error, "No such release"} end, @@ -276,7 +307,7 @@ loop(#state{common = C, sys = Sys} = S) -> reltool_utils:reply(ReplyTo, Ref, Reply), ?MODULE:loop(S); {call, ReplyTo, Ref, {get_app, AppName}} when is_atom(AppName) -> - Reply = + Reply = case lists:keysearch(AppName, #app.name, Sys#sys.apps) of {value, App} -> {ok, App}; @@ -302,15 +333,15 @@ loop(#state{common = C, sys = Sys} = S) -> {call, ReplyTo, Ref, {get_apps, Kind}} -> AppNames = case Kind of - whitelist -> + whitelist -> [A || A <- Sys#sys.apps, A#app.is_pre_included =:= true]; - blacklist -> + blacklist -> [A || A <- Sys#sys.apps, A#app.is_pre_included =:= false]; - source -> + source -> [A || A <- Sys#sys.apps, A#app.is_included =/= true, @@ -324,9 +355,10 @@ loop(#state{common = C, sys = Sys} = S) -> reltool_utils:reply(ReplyTo, Ref, {ok, AppNames}), ?MODULE:loop(S); {call, ReplyTo, Ref, {set_apps, Apps}} -> - {S2, Status} = lists:foldl(fun(A, {X, Y}) -> do_set_app(X, A, Y) end, - {S, {ok, []}}, - Apps), + {S2, Status} = + lists:foldl(fun(A, {X, Y}) -> do_set_app(X, A, Y) end, + {S, {ok, []}}, + Apps), {S3, Status2} = analyse(S2, Status), reltool_utils:reply(ReplyTo, Ref, Status2), ?MODULE:loop(S3); @@ -335,13 +367,13 @@ loop(#state{common = C, sys = Sys} = S) -> ?MODULE:loop(S); {call, ReplyTo, Ref, {set_sys, Sys2}} -> S2 = S#state{sys = Sys2#sys{apps = Sys#sys.apps}}, - Force = + Force = (Sys2#sys.root_dir =/= Sys#sys.root_dir) orelse (Sys2#sys.lib_dirs =/= Sys#sys.lib_dirs) orelse (Sys2#sys.escripts =/= Sys#sys.escripts), {S3, Status} = refresh(S2, Force, {ok, []}), {S4, Status2} = analyse(S3#state{old_sys = S#state.sys}, Status), - S6 = + S6 = case Status2 of {ok, _Warnings} -> S4#state{status = Status2, old_status = S#state.status}; @@ -354,7 +386,7 @@ loop(#state{common = C, sys = Sys} = S) -> reltool_utils:reply(ReplyTo, Ref, S#state.status), ?MODULE:loop(S); {call, ReplyTo, Ref, {gen_rel_files, Dir}} -> - Status = + Status = case reltool_target:gen_rel_files(S#state.sys, Dir) of ok -> {ok, []}; @@ -404,7 +436,7 @@ analyse(#state{common = C, sys = #sys{apps = Apps0} = Sys} = S, Status) -> ets:insert(C#common.app_tab, MissingApp), Apps2 = lists:map(fun(App) -> app_init_is_included(C, Sys, App) end, Apps), - Apps3 = + Apps3 = case app_propagate_is_included(C, Sys, Apps2, []) of [] -> Apps2; @@ -412,14 +444,15 @@ analyse(#state{common = C, sys = #sys{apps = Apps0} = Sys} = S, Status) -> %% io:format("Missing mods: ~p\n", [MissingMods]), MissingApp2 = MissingApp#app{label = ?MISSING_APP_TEXT, info = missing_app_info(""), - mods = MissingMods, + mods = MissingMods, status = missing, uses_mods = []}, [MissingApp2 | Apps2] end, app_propagate_is_used_by(C, Apps3), Apps4 = read_apps(C, Sys, Apps3, []), - %% io:format("Missing app: ~p\n", [lists:keysearch(?MISSING_APP, #app.name, Apps4)]), + %% io:format("Missing app: ~p\n", + %% [lists:keysearch(?MISSING_APP, #app.name, Apps4)]), Sys2 = Sys#sys{apps = Apps4}, try Status2 = verify_config(Sys2, Status), @@ -430,7 +463,7 @@ analyse(#state{common = C, sys = #sys{apps = Apps0} = Sys} = S, Status) -> end. app_init_is_included(C, Sys, #app{mods = Mods} = A) -> - AppCond = + AppCond = case A#app.incl_cond of undefined -> Sys#sys.incl_cond; _ -> A#app.incl_cond @@ -448,7 +481,14 @@ app_init_is_included(C, Sys, #app{mods = Mods} = A) -> end, A2 = A#app{is_pre_included = IsIncl, is_included = IsIncl}, ets:insert(C#common.app_tab, A2), - lists:foreach(fun(Mod) -> mod_init_is_included(C, Mod, ModCond, AppCond, undefined) end, Mods), + lists:foreach(fun(Mod) -> + mod_init_is_included(C, + Mod, + ModCond, + AppCond, + undefined) + end, + Mods), %%app_mod_init_is_included(C, AppName, Info, ModCond, AppCond), A2. @@ -463,7 +503,8 @@ mod_init_is_included(C, M, ModCond, AppCond, Default) -> exclude -> false; undefined -> - %% print(M#mod.name, hipe, "mod_cond -> ~p\n", [ModCond]), + %% print(M#mod.name, hipe, "mod_cond -> ~p\n", + %% [ModCond]), case ModCond of all -> true; app -> false_to_undefined(M#mod.is_app_mod); @@ -493,7 +534,7 @@ false_to_undefined(Bool) -> false -> undefined; _ -> Bool end. - + app_propagate_is_included(C, Sys, [#app{mods = Mods} = A | Apps], Acc) -> Acc2 = mod_propagate_is_included(C, Sys, A, Mods, Acc), app_propagate_is_included(C, Sys, Apps, Acc2); @@ -502,9 +543,11 @@ app_propagate_is_included(_C, _Sys, [], Acc) -> mod_propagate_is_included(C, Sys, A, [#mod{name = ModName} | Mods], Acc) -> [M2] = ets:lookup(C#common.mod_tab, ModName), - %% print(ModName, file, "Maybe Prop ~p -> ~p\n", [M2, M2#mod.is_included]), - %% print(ModName, filename, "Maybe Prop ~p -> ~p\n", [M2, M2#mod.is_included]), - Acc2 = + %% print(ModName, file, "Maybe Prop ~p -> ~p\n", + %% [M2, M2#mod.is_included]), + %% print(ModName, filename, "Maybe Prop ~p -> ~p\n", + %% [M2, M2#mod.is_included]), + Acc2 = case M2#mod.is_included of true -> %% Propagate include mark @@ -519,11 +562,13 @@ mod_propagate_is_included(_C, _Sys, _A, [], Acc) -> Acc. mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> - Acc3 = + Acc3 = case ets:lookup(C#common.mod_tab, ModName) of - [M] -> - %% print(UsedByName, file, "Maybe Mark ~p -> ~p\n", [M, M#mod.is_included]), - %% print(UsedByName, filename, "Maybe Mark ~p -> ~p\n", [M, M#mod.is_included]), + [M] -> + %% print(UsedByName, file, "Maybe Mark ~p -> ~p\n", + %% [M, M#mod.is_included]), + %% print(UsedByName, filename, "Maybe Mark ~p -> ~p\n", + %% [M, M#mod.is_included]), case M#mod.is_included of true -> %% Already marked @@ -533,19 +578,22 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> Acc; undefined -> %% Mark and propagate - M2 = + M2 = case M#mod.incl_cond of include -> - M#mod{is_pre_included = true, is_included = true}; + M#mod{is_pre_included = true, + is_included = true}; exclude -> - M#mod{is_pre_included = true, is_included = true}; + M#mod{is_pre_included = true, + is_included = true}; undefined -> M#mod{is_included = true} end, ets:insert(C#common.mod_tab, M2), - %% io:format("Propagate mod: ~p -> ~p (~p)\n", [UsedByName, ModName, M#mod.incl_cond]), + %% io:format("Propagate mod: ~p -> ~p (~p)\n", + %% [UsedByName, ModName, M#mod.incl_cond]), [A] = ets:lookup(C#common.app_tab, M2#mod.app_name), - Acc2 = + Acc2 = case A#app.is_included of true -> Acc; @@ -557,7 +605,7 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> undefined -> Sys#sys.mod_cond; _ -> A#app.mod_cond end, - Filter = + Filter = fun(M3) -> case ModCond of all -> true; @@ -569,12 +617,22 @@ mod_mark_is_included(C, Sys, UsedByName, [ModName | ModNames], Acc) -> end, Mods = lists:filter(Filter, A#app.mods), %% io:format("Propagate app: ~p ~p -> ~p\n", - %% [UsedByName, A#app.name, [M3#mod.name || M3 <- Mods]]), + %% [UsedByName, A#app.name, + %% [M3#mod.name || M3 <- Mods]]), A2 = A#app{is_included = true}, - ets:insert(C#common.app_tab, A2), - mod_mark_is_included(C, Sys, ModName, [M3#mod.name || M3 <- Mods], Acc) + ets:insert(C#common.app_tab, A2), + mod_mark_is_included(C, + Sys, + ModName, + [M3#mod.name || + M3 <- Mods], + Acc) end, - mod_mark_is_included(C, Sys, ModName, M2#mod.uses_mods, Acc2) + mod_mark_is_included(C, + Sys, + ModName, + M2#mod.uses_mods, + Acc2) end; [] -> M = missing_mod(ModName, ?MISSING_APP), @@ -614,21 +672,24 @@ mod_propagate_is_used_by(_C, []) -> read_apps(C, Sys, [#app{mods = Mods, is_included = IsIncl} = A | Apps], Acc) -> {Mods2, IsIncl2} = read_apps(C, Sys, A, Mods, [], IsIncl), - %% reltool_utils:print(A#app.name, stdlib, "Mods2: ~p\n", [[M#mod.status || M <- Mods2]]), - Status = + %% reltool_utils:print(A#app.name, stdlib, "Mods2: ~p\n", + %% [[M#mod.status || M <- Mods2]]), + Status = case lists:keysearch(missing, #mod.status, Mods2) of {value, _} -> missing; false -> ok end, UsesMods = [M#mod.uses_mods || M <- Mods2, M#mod.is_included =:= true], UsesMods2 = lists:usort(lists:flatten(UsesMods)), - UsesApps = [M#mod.app_name || ModName <- UsesMods2, M <- ets:lookup(C#common.mod_tab, ModName)], + UsesApps = [M#mod.app_name || ModName <- UsesMods2, + M <- ets:lookup(C#common.mod_tab, ModName)], UsesApps2 = lists:usort(UsesApps), UsedByMods = [M#mod.used_by_mods || M <- Mods2, M#mod.is_included =:= true], UsedByMods2 = lists:usort(lists:flatten(UsedByMods)), - UsedByApps = [M#mod.app_name || ModName <- UsedByMods2, M <- ets:lookup(C#common.mod_tab, ModName)], + UsedByApps = [M#mod.app_name || ModName <- UsedByMods2, + M <- ets:lookup(C#common.mod_tab, ModName)], UsedByApps2 = lists:usort(UsedByApps), - + A2 = A#app{mods = Mods2, status = Status, uses_mods = UsesMods2, @@ -644,12 +705,14 @@ read_apps(C, Sys, A, [#mod{name = ModName} | Mods], Acc, IsIncl) -> [M2] = ets:lookup(C#common.mod_tab, ModName), Status = do_get_status(M2), %% print(M2#mod.name, hipe, "status -> ~p\n", [Status]), - {IsIncl2, M3} = + {IsIncl2, M3} = case M2#mod.is_included of true -> - UsedByMods = [N || {_, N} <- ets:lookup(C#common.mod_used_by_tab, ModName)], + UsedByMods = + [N || {_, N} <- ets:lookup(C#common.mod_used_by_tab, + ModName)], {true, M2#mod{status = Status, used_by_mods = UsedByMods}}; - _ -> + _ -> {IsIncl, M2#mod{status = Status, used_by_mods = []}} end, ets:insert(C#common.mod_tab, M3), @@ -669,14 +732,14 @@ shrink_sys(#state{sys = #sys{apps = Apps} = Sys} = S) -> Apps2 = lists:zf(fun filter_app/1, Apps), S#state{sys = Sys#sys{apps = Apps2}}. -filter_app(A) -> +filter_app(A) -> Mods = [M#mod{is_app_mod = undefined, is_ebin_mod = undefined, uses_mods = undefined, exists = false, is_pre_included = undefined, is_included = undefined} || - M <- A#app.mods, + M <- A#app.mods, M#mod.incl_cond =/= undefined], if A#app.is_escript -> @@ -692,9 +755,9 @@ filter_app(A) -> A#app.use_selected_vsn =:= undefined -> false; true -> - {Dir, Dirs} = + {Dir, Dirs} = case A#app.use_selected_vsn of - undefined -> + undefined -> {shrinked, []}; false -> {shrinked, []}; @@ -730,37 +793,45 @@ refresh_app(#app{name = AppName, Status) -> if Force; OptLabel =:= undefined -> - {AppInfo, EbinMods, Status3} = + {AppInfo, EbinMods, Status3} = case IsEscript of false -> - + %% Add info from .app file Base = get_base(AppName, ActiveDir), {_, DefaultVsn} = reltool_utils:split_app_name(Base), Ebin = filename:join([ActiveDir, "ebin"]), - AppFile = filename:join([Ebin, atom_to_list(AppName) ++ ".app"]), - {AI, Status2} = read_app_info(AppFile, AppFile, AppName, DefaultVsn, Status), + AppFile = + filename:join([Ebin, + atom_to_list(AppName) ++ ".app"]), + {AI, Status2} = + read_app_info(AppFile, + AppFile, + AppName, + DefaultVsn, + Status), {AI, read_ebin_mods(Ebin, AppName), Status2}; true -> {App#app.info, Mods, Status} end, - + %% Add non-existing modules AppModNames = case AppInfo#app_info.mod of {StartModName, _} -> - case lists:member(StartModName, AppInfo#app_info.modules) of + case lists:member(StartModName, + AppInfo#app_info.modules) of true -> AppInfo#app_info.modules; false -> [StartModName | AppInfo#app_info.modules] end; - undefined -> + undefined -> AppInfo#app_info.modules end, MissingMods = add_missing_mods(AppName, EbinMods, AppModNames), - + %% Add optional user config for each module Mods2 = add_mod_config(MissingMods ++ EbinMods, Mods), - + %% Set app flag for each module in app file Mods3 = set_mod_flags(Mods2, AppModNames), AppVsn = AppInfo#app_info.vsn, @@ -770,7 +841,7 @@ refresh_app(#app{name = AppName, _ -> atom_to_list(AppName) ++ "-" ++ AppVsn end, App2 = App#app{vsn = AppVsn, - label = AppLabel, + label = AppLabel, info = AppInfo, mods = lists:keysort(#mod.name, Mods3)}, {App2, Status3}; @@ -790,30 +861,55 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) -> AI = #app_info{vsn = DefaultVsn}, parse_app_info(AppFile, Info, AI, Status); {ok, _BadApp} -> - Text = lists:concat([AppName, ": Illegal contents in app file ", AppFile]), - {missing_app_info(DefaultVsn), reltool_utils:add_warning(Status, Text)}; + Text = lists:concat([AppName, + ": Illegal contents in app file ", AppFile]), + {missing_app_info(DefaultVsn), + reltool_utils:add_warning(Status, Text)}; {error, Text} when Text =:= EnoentText-> {missing_app_info(DefaultVsn), Status}; {error, Text} -> - Text2 = lists:concat([AppName, ": Cannot parse app file ", AppFile, " (", Text, ")."]), - {missing_app_info(DefaultVsn), reltool_utils:add_warning(Status, Text2)} + Text2 = lists:concat([AppName, + ": Cannot parse app file ", + AppFile, " (", Text, ")."]), + {missing_app_info(DefaultVsn), + reltool_utils:add_warning(Status, Text2)} end. parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) -> case Key of - description -> parse_app_info(File, KeyVals, AI#app_info{description = Val}, Status); - id -> parse_app_info(File, KeyVals, AI#app_info{id = Val}, Status); - vsn -> parse_app_info(File, KeyVals, AI#app_info{vsn = Val}, Status); - modules -> parse_app_info(File, KeyVals, AI#app_info{modules = Val}, Status); - maxP -> parse_app_info(File, KeyVals, AI#app_info{maxP = Val}, Status); - maxT -> parse_app_info(File, KeyVals, AI#app_info{maxT = Val}, Status); - registered -> parse_app_info(File, KeyVals, AI#app_info{registered = Val}, Status); - included_applications -> parse_app_info(File, KeyVals, AI#app_info{incl_apps = Val}, Status); - applications -> parse_app_info(File, KeyVals, AI#app_info{applications = Val}, Status); - env -> parse_app_info(File, KeyVals, AI#app_info{env = Val}, Status); - mod -> parse_app_info(File, KeyVals, AI#app_info{mod = Val}, Status); - start_phases -> parse_app_info(File, KeyVals, AI#app_info{start_phases = Val}, Status); - _ -> parse_app_info(File, KeyVals, AI, reltool_utils:add_warning(Status, lists:concat(["Unexpected item ", Key, "in app file ", File]))) + description -> + parse_app_info(File, KeyVals, AI#app_info{description = Val}, + Status); + id -> + parse_app_info(File, KeyVals, AI#app_info{id = Val}, Status); + vsn -> + parse_app_info(File, KeyVals, AI#app_info{vsn = Val}, Status); + modules -> + parse_app_info(File, KeyVals, AI#app_info{modules = Val}, Status); + maxP -> + parse_app_info(File, KeyVals, AI#app_info{maxP = Val}, Status); + maxT -> + parse_app_info(File, KeyVals, AI#app_info{maxT = Val}, Status); + registered -> + parse_app_info(File, KeyVals, AI#app_info{registered = Val}, + Status); + included_applications -> + parse_app_info(File, KeyVals, AI#app_info{incl_apps = Val}, Status); + applications -> + parse_app_info(File, KeyVals, AI#app_info{applications = Val}, + Status); + env -> + parse_app_info(File, KeyVals, AI#app_info{env = Val}, Status); + mod -> + parse_app_info(File, KeyVals, AI#app_info{mod = Val}, Status); + start_phases -> + parse_app_info(File, KeyVals, AI#app_info{start_phases = Val}, + Status); + _ -> + String = lists:concat(["Unexpected item ", + Key, "in app file ", File]), + parse_app_info(File, KeyVals, AI, + reltool_utils:add_warning(Status, String)) end; parse_app_info(_, [], AI, Status) -> {AI, Status}. @@ -824,7 +920,7 @@ read_ebin_mods(Ebin, AppName) -> Ext = code:objfile_extension(), InitMod = fun(F) -> File = filename:join([Ebin, F]), - init_mod(AppName, File, File, Ext) + init_mod(AppName, File, File, Ext) end, Files2 = [F || F <- Files, filename:extension(F) =:= Ext], pmap(InitMod, Files2); @@ -839,7 +935,7 @@ pmap(Fun, List) -> %% -record(pmap_res, {count, ref, res}). %% -record(pmap_wait, {count, ref, pid}). -%% +%% %% pmap(Fun, [H | T], N, Max, Count, WaitFor, Results) when N < Max -> %% Ref = make_ref(), %% Parent = self(), @@ -943,16 +1039,16 @@ set_mod_flags(Mods, AppModNames) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -do_get_config(S, InclDefaults, InclDerivates) -> +do_get_config(S, InclDef, InclDeriv) -> S2 = - case InclDerivates of + case InclDeriv of false -> shrink_sys(S); true -> S end, - {ok, reltool_target:gen_config(S2#state.sys, InclDefaults)}. + {ok, reltool_target:gen_config(S2#state.sys, InclDef)}. -do_save_config(S, Filename, InclDefaults, InclDerivates) -> - {ok, Config} = do_get_config(S, InclDefaults, InclDerivates), +do_save_config(S, Filename, InclDef, InclDeriv) -> + {ok, Config} = do_get_config(S, InclDef, InclDeriv), IoList = io_lib:format("%% config generated at ~w ~w\n~p.\n\n", [date(), time(), Config]), file:write_file(Filename, IoList). @@ -963,13 +1059,15 @@ do_load_config(S, SysConfig) -> OldSys = S#state.sys, S2 = shrink_sys(S), ShrinkedSys = S2#state.sys, - {NewSys, Status} = read_config(ShrinkedSys#sys{apps = []}, SysConfig, {ok, []}), + {NewSys, Status} = + read_config(ShrinkedSys#sys{apps = []}, SysConfig, {ok, []}), case Status of {ok, _Warnings} -> Force = false, {MergedSys, Status2} = merge_config(OldSys, NewSys, Force, Status), - {S3, Status3} = analyse(S2#state{sys = MergedSys, old_sys = OldSys}, Status2), - S4 = + {S3, Status3} = + analyse(S2#state{sys = MergedSys, old_sys = OldSys}, Status2), + S4 = case Status3 of {ok, _Warnings2} -> S3#state{status = Status3, old_status = S#state.status}; @@ -988,10 +1086,15 @@ read_config(OldSys, Filename, Status) when is_list(Filename) -> read_config(OldSys, SysConfig, Status); {ok, Content} -> Text = lists:flatten(io_lib:format("~p", [Content])), - {OldSys, reltool_utils:return_first_error(Status, "Illegal file content: " ++ Text)}; + {OldSys, + reltool_utils:return_first_error(Status, + "Illegal file content: " ++ + Text)}; {error, Reason} -> Text = file:format_error(Reason), - {OldSys, reltool_utils:return_first_error(Status, "File access: " ++ Text)} + {OldSys, + reltool_utils:return_first_error(Status, "File access: " ++ + Text)} end; read_config(OldSys, {sys, KeyVals}, Status) -> {NewSys, Status2} = @@ -1006,7 +1109,7 @@ read_config(OldSys, {sys, KeyVals}, Status) -> [] -> Rels = reltool_utils:default_rels(); Rels -> ok end, - NewSys2 = NewSys#sys{apps = lists:sort(Apps), rels = lists:sort(Rels)}, + NewSys2 = NewSys#sys{apps = lists:sort(Apps), rels = lists:sort(Rels)}, case lists:keysearch(NewSys2#sys.boot_rel, #rel.name, NewSys2#sys.rels) of {value, _} -> {NewSys2, Status2}; @@ -1016,9 +1119,11 @@ read_config(OldSys, {sys, KeyVals}, Status) -> end; read_config(OldSys, BadConfig, Status) -> Text = lists:flatten(io_lib:format("~p", [BadConfig])), - {OldSys, reltool_utils:return_first_error(Status, "Illegal content: " ++ Text)}. + {OldSys, + reltool_utils:return_first_error(Status, "Illegal content: " ++ Text)}. -decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals], Status) +decode(#sys{apps = Apps} = Sys, [{erts = Name, AppKeyVals} | SysKeyVals], + Status) when is_atom(Name), is_list(AppKeyVals) -> App = default_app(Name), {App2, Status2} = decode(App, AppKeyVals, Status), @@ -1028,7 +1133,8 @@ decode(#sys{apps = Apps} = Sys, [{app, Name, AppKeyVals} | SysKeyVals], Status) App = default_app(Name), {App2, Status2} = decode(App, AppKeyVals, Status), decode(Sys#sys{apps = [App2 | Apps]}, SysKeyVals, Status2); -decode(#sys{apps = Apps, escripts = Escripts} = Sys, [{escript, File, AppKeyVals} | SysKeyVals], Status) +decode(#sys{apps = Apps, escripts = Escripts} = Sys, + [{escript, File, AppKeyVals} | SysKeyVals], Status) when is_list(File), is_list(AppKeyVals) -> {Name, Label} = split_escript_name(File), App = default_app(Name, File), @@ -1038,14 +1144,17 @@ decode(#sys{apps = Apps, escripts = Escripts} = Sys, [{escript, File, AppKeyVals active_dir = File, sorted_dirs = [File]}, {App3, Status2} = decode(App2, AppKeyVals, Status), - decode(Sys#sys{apps = [App3 | Apps], escripts = [File | Escripts]}, SysKeyVals, Status2); -decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals], Status) + decode(Sys#sys{apps = [App3 | Apps], escripts = [File | Escripts]}, + SysKeyVals, + Status2); +decode(#sys{rels = Rels} = Sys, [{rel, Name, Vsn, RelApps} | SysKeyVals], + Status) when is_list(Name), is_list(Vsn), is_list(RelApps) -> Rel = #rel{name = Name, vsn = Vsn, rel_apps = []}, {Rel2, Status2} = decode(Rel, RelApps, Status), decode(Sys#sys{rels = [Rel2 | Rels]}, SysKeyVals, Status2); decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> - {Sys3, Status3} = + {Sys3, Status3} = case Key of root_dir when is_list(Val) -> {Sys#sys{root_dir = Val}, Status}; @@ -1053,10 +1162,10 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> {Sys#sys{lib_dirs = Val}, Status}; mod_cond when Val =:= all; Val =:= app; Val =:= ebin; Val =:= derived; - Val =:= none -> + Val =:= none -> {Sys#sys{mod_cond = Val}, Status}; incl_cond when Val =:= include; Val =:= exclude; - Val =:= derived -> + Val =:= derived -> {Sys#sys{incl_cond = Val}, Status}; boot_rel when is_list(Val) -> {Sys#sys{boot_rel = Val}, Status}; @@ -1065,122 +1174,194 @@ decode(#sys{} = Sys, [{Key, Val} | KeyVals], Status) -> profile when Val =:= development -> Val = ?DEFAULT_PROFILE, % assert, {Sys#sys{profile = Val, - incl_sys_filters = reltool_utils:decode_regexps(incl_sys_filters, - ?DEFAULT_INCL_SYS_FILTERS, - Sys#sys.incl_sys_filters), - excl_sys_filters = reltool_utils:decode_regexps(excl_sys_filters, - ?DEFAULT_EXCL_SYS_FILTERS, - Sys#sys.excl_sys_filters), - incl_app_filters = reltool_utils:decode_regexps(incl_app_filters, - ?DEFAULT_INCL_APP_FILTERS, - Sys#sys.incl_app_filters), - excl_app_filters = reltool_utils:decode_regexps(excl_app_filters, - ?DEFAULT_EXCL_APP_FILTERS, - Sys#sys.excl_app_filters)}, + incl_sys_filters = + reltool_utils:decode_regexps(incl_sys_filters, + ?DEFAULT_INCL_SYS_FILTERS, + Sys#sys.incl_sys_filters), + excl_sys_filters = + reltool_utils:decode_regexps(excl_sys_filters, + ?DEFAULT_EXCL_SYS_FILTERS, + Sys#sys.excl_sys_filters), + incl_app_filters = + reltool_utils:decode_regexps(incl_app_filters, + ?DEFAULT_INCL_APP_FILTERS, + Sys#sys.incl_app_filters), + excl_app_filters = + reltool_utils:decode_regexps(excl_app_filters, + ?DEFAULT_EXCL_APP_FILTERS, + Sys#sys.excl_app_filters)}, Status}; profile when Val =:= embedded -> {Sys#sys{profile = Val, - incl_sys_filters = reltool_utils:decode_regexps(incl_sys_filters, - ?EMBEDDED_INCL_SYS_FILTERS, - Sys#sys.incl_sys_filters), - excl_sys_filters = reltool_utils:decode_regexps(excl_sys_filters, - ?EMBEDDED_EXCL_SYS_FILTERS, - Sys#sys.excl_sys_filters), - incl_app_filters = reltool_utils:decode_regexps(incl_app_filters, - ?EMBEDDED_INCL_APP_FILTERS, - Sys#sys.incl_app_filters), - excl_app_filters = reltool_utils:decode_regexps(excl_app_filters, - ?EMBEDDED_EXCL_APP_FILTERS, - Sys#sys.excl_app_filters)}, + incl_sys_filters = + reltool_utils:decode_regexps(incl_sys_filters, + ?EMBEDDED_INCL_SYS_FILTERS, + Sys#sys.incl_sys_filters), + excl_sys_filters = + reltool_utils:decode_regexps(excl_sys_filters, + ?EMBEDDED_EXCL_SYS_FILTERS, + Sys#sys.excl_sys_filters), + incl_app_filters = + reltool_utils:decode_regexps(incl_app_filters, + ?EMBEDDED_INCL_APP_FILTERS, + Sys#sys.incl_app_filters), + excl_app_filters = + reltool_utils:decode_regexps(excl_app_filters, + ?EMBEDDED_EXCL_APP_FILTERS, + Sys#sys.excl_app_filters)}, Status}; profile when Val =:= standalone -> {Sys#sys{profile = Val, - incl_sys_filters = reltool_utils:decode_regexps(incl_sys_filters, - ?STANDALONE_INCL_SYS_FILTERS, - Sys#sys.incl_sys_filters), - excl_sys_filters = reltool_utils:decode_regexps(excl_sys_filters, - ?STANDALONE_EXCL_SYS_FILTERS, - Sys#sys.excl_sys_filters), - incl_app_filters = reltool_utils:decode_regexps(incl_app_filters, - ?STANDALONE_INCL_APP_FILTERS, - Sys#sys.incl_app_filters), - excl_app_filters = reltool_utils:decode_regexps(excl_app_filters, - ?STANDALONE_EXCL_APP_FILTERS, - Sys#sys.excl_app_filters)}, + incl_sys_filters = + reltool_utils:decode_regexps(incl_sys_filters, + ?STANDALONE_INCL_SYS_FILTERS, + Sys#sys.incl_sys_filters), + excl_sys_filters = + reltool_utils:decode_regexps(excl_sys_filters, + ?STANDALONE_EXCL_SYS_FILTERS, + Sys#sys.excl_sys_filters), + incl_app_filters = + reltool_utils:decode_regexps(incl_app_filters, + ?STANDALONE_INCL_APP_FILTERS, + Sys#sys.incl_app_filters), + excl_app_filters = + reltool_utils:decode_regexps(excl_app_filters, + ?STANDALONE_EXCL_APP_FILTERS, + Sys#sys.excl_app_filters)}, Status}; incl_sys_filters -> - {Sys#sys{incl_sys_filters = reltool_utils:decode_regexps(Key, Val, Sys#sys.incl_sys_filters)}, Status}; + {Sys#sys{incl_sys_filters = + reltool_utils:decode_regexps(Key, + Val, + Sys#sys.incl_sys_filters)}, + Status}; excl_sys_filters -> - {Sys#sys{excl_sys_filters = reltool_utils:decode_regexps(Key, Val, Sys#sys.excl_sys_filters)}, Status}; + {Sys#sys{excl_sys_filters = + reltool_utils:decode_regexps(Key, + Val, + Sys#sys.excl_sys_filters)}, + Status}; incl_app_filters -> - {Sys#sys{incl_app_filters = reltool_utils:decode_regexps(Key, Val, Sys#sys.incl_app_filters)}, Status}; + {Sys#sys{incl_app_filters = + reltool_utils:decode_regexps(Key, + Val, + Sys#sys.incl_app_filters)}, + Status}; excl_app_filters -> - {Sys#sys{excl_app_filters = reltool_utils:decode_regexps(Key, Val, Sys#sys.excl_app_filters)}, Status}; + {Sys#sys{excl_app_filters = + reltool_utils:decode_regexps(Key, + Val, + Sys#sys.excl_app_filters)}, + Status}; incl_archive_filters -> - {Sys#sys{incl_archive_filters = reltool_utils:decode_regexps(Key, Val, Sys#sys.incl_archive_filters)}, Status}; + {Sys#sys{incl_archive_filters = + reltool_utils:decode_regexps(Key, + Val, + Sys#sys.incl_archive_filters)}, + Status}; excl_archive_filters -> - {Sys#sys{excl_archive_filters = reltool_utils:decode_regexps(Key, Val, Sys#sys.excl_archive_filters)}, Status}; + {Sys#sys{excl_archive_filters = + reltool_utils:decode_regexps(Key, + Val, + Sys#sys.excl_archive_filters)}, + Status}; archive_opts when is_list(Val) -> {Sys#sys{archive_opts = Val}, Status}; relocatable when Val =:= true; Val =:= false -> {Sys#sys{relocatable = Val}, Status}; - app_type when Val =:= permanent; Val =:= transient; Val =:= temporary; - Val =:= load; Val =:= none -> + app_type when Val =:= permanent; + Val =:= transient; + Val =:= temporary; + Val =:= load; Val =:= none -> {Sys#sys{app_type = Val}, Status}; - app_file when Val =:= keep; Val =:= strip, Val =:= all -> + app_file when Val =:= keep; Val =:= strip, Val =:= all -> {Sys#sys{app_file = Val}, Status}; - debug_info when Val =:= keep; Val =:= strip -> + debug_info when Val =:= keep; Val =:= strip -> {Sys#sys{debug_info = Val}, Status}; _ -> Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - {Sys, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)} + {Sys, reltool_utils:return_first_error(Status, + "Illegal option: " ++ + Text)} end, decode(Sys3, KeyVals, Status3); decode(#app{} = App, [{Key, Val} | KeyVals], Status) -> - {App2, Status2} = + {App2, Status2} = case Key of - mod_cond when Val =:= all; Val =:= app; Val =:= ebin; Val =:= derived; Val =:= none -> + mod_cond when Val =:= all; + Val =:= app; + Val =:= ebin; + Val =:= derived; + Val =:= none -> {App#app{mod_cond = Val}, Status}; - incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> + incl_cond when Val =:= include; + Val =:= exclude; + Val =:= derived -> {App#app{incl_cond = Val}, Status}; - debug_info when Val =:= keep; Val =:= strip -> + debug_info when Val =:= keep; + Val =:= strip -> {App#app{debug_info = Val}, Status}; - app_file when Val =:= keep; Val =:= strip, Val =:= all -> + app_file when Val =:= keep; + Val =:= strip, + Val =:= all -> {App#app{app_file = Val}, Status}; - app_type when Val =:= permanent; Val =:= transient; Val =:= temporary; - Val =:= load; Val =:= none -> + app_type when Val =:= permanent; + Val =:= transient; + Val =:= temporary; + Val =:= load; + Val =:= none -> {App#app{app_type = Val}, Status}; incl_app_filters -> - {App#app{incl_app_filters = reltool_utils:decode_regexps(Key, Val, App#app.incl_app_filters)}, Status}; + {App#app{incl_app_filters = + reltool_utils:decode_regexps(Key, + Val, + App#app.incl_app_filters)}, + Status}; excl_app_filters -> - {App#app{excl_app_filters = reltool_utils:decode_regexps(Key, Val, App#app.excl_app_filters)}, Status}; + {App#app{excl_app_filters = + reltool_utils:decode_regexps(Key, + Val, + App#app.excl_app_filters)}, + Status}; incl_archive_filters -> - {App#app{incl_archive_filters = reltool_utils:decode_regexps(Key, Val, App#app.incl_archive_filters)}, Status}; + {App#app{incl_archive_filters = + reltool_utils:decode_regexps(Key, + Val, + App#app.incl_archive_filters)}, + Status}; excl_archive_filters -> - {App#app{excl_archive_filters = reltool_utils:decode_regexps(Key, Val, App#app.excl_archive_filters)}, Status}; + {App#app{excl_archive_filters = + reltool_utils:decode_regexps(Key, + Val, + App#app.excl_archive_filters)}, + Status}; archive_opts when is_list(Val) -> {App#app{archive_opts = Val}, Status}; - vsn when is_list(Val) -> + vsn when is_list(Val) -> {App#app{use_selected_vsn = true, vsn = Val}, Status}; _ -> Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - {App, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)} + {App, reltool_utils:return_first_error(Status, + "Illegal option: " ++ Text)} end, decode(App2, KeyVals, Status2); -decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals], Status) -> +decode(#app{mods = Mods} = App, [{mod, Name, ModKeyVals} | AppKeyVals], + Status) -> {Mod, Status2} = decode(#mod{name = Name}, ModKeyVals, Status), decode(App#app{mods = [Mod | Mods]}, AppKeyVals, Status2); decode(#mod{} = Mod, [{Key, Val} | KeyVals], Status) -> - {Mod2, Status2} = + {Mod2, Status2} = case Key of - incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> + incl_cond when Val =:= include; Val =:= exclude; Val =:= derived -> {Mod#mod{incl_cond = Val}, Status}; - debug_info when Val =:= keep; Val =:= strip -> + debug_info when Val =:= keep; Val =:= strip -> {Mod#mod{debug_info = Val}, Status}; _ -> Text = lists:flatten(io_lib:format("~p", [{Key, Val}])), - {Mod, reltool_utils:return_first_error(Status, "Illegal option: " ++ Text)} + {Mod, + reltool_utils:return_first_error(Status, + "Illegal option: " ++ Text)} end, decode(Mod2, KeyVals, Status2); decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) -> @@ -1191,7 +1372,9 @@ decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) -> {Name, Type} when is_atom(Name) -> #rel_app{name = Name, app_type = Type, incl_apps = []}; {Name, InclApps} when is_atom(Name), is_list(InclApps) -> - #rel_app{name = Name, app_type = undefined, incl_apps = InclApps}; + #rel_app{name = Name, + app_type = undefined, + incl_apps = InclApps}; {Name, Type, InclApps} when is_atom(Name), is_list(InclApps) -> #rel_app{name = Name, app_type = Type, incl_apps = InclApps}; _ -> @@ -1204,7 +1387,9 @@ decode(#rel{rel_apps = RelApps} = Rel, [RelApp | KeyVals], Status) -> decode(Rel#rel{rel_apps = RelApps ++ [RA]}, KeyVals, Status); true -> Text = lists:flatten(io_lib:format("~p", [RelApp])), - Status2 = reltool_utils:return_first_error(Status, "Illegal option: " ++ Text), + Status2 = + reltool_utils:return_first_error(Status, + "Illegal option: " ++ Text), decode(Rel, KeyVals, Status2) end; decode(Acc, [], Status) -> @@ -1227,7 +1412,7 @@ is_type(Type) -> split_escript_name(File) when is_list(File) -> Label = filename:basename(File, ".escript"), {list_to_atom("*escript* " ++ Label), Label}. - + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% refresh(#state{sys = Sys} = S, Force, Status) -> @@ -1245,7 +1430,8 @@ merge_config(OldSys, NewSys, Force, Status) -> escripts_to_apps(Escripts, MergedApps, OldSys#sys.apps, Status2), {RefreshedApps, Status4} = refresh_apps(OldSys#sys.apps, AllApps, [], Force, Status3), - {PatchedApps, Status5} = patch_erts_version(RootDir, RefreshedApps, Status4), + {PatchedApps, Status5} = + patch_erts_version(RootDir, RefreshedApps, Status4), Escripts2 = [A#app.active_dir || A <- PatchedApps, A#app.is_escript], NewSys2 = NewSys#sys{root_dir = RootDir, lib_dirs = LibDirs, @@ -1255,8 +1441,9 @@ merge_config(OldSys, NewSys, Force, Status) -> verify_config(Sys, Status) -> case lists:keymember(Sys#sys.boot_rel, #rel.name, Sys#sys.rels) of - true -> - lists:foreach(fun(Rel)-> check_rel(Rel, Sys, Status) end, Sys#sys.rels), + true -> + lists:foreach(fun(Rel)-> check_rel(Rel, Sys, Status) end, + Sys#sys.rels), Status; false -> Text = lists:concat([Sys#sys.boot_rel, ": release is mandatory"]), @@ -1264,15 +1451,19 @@ verify_config(Sys, Status) -> throw({error, Status2}) end. -check_rel(#rel{name = RelName, rel_apps = RelApps}, #sys{apps = Apps}, Status) -> +check_rel(#rel{name = RelName, rel_apps = RelApps}, + #sys{apps = Apps}, + Status) -> EnsureApp = fun(AppName) -> case lists:keymember(AppName, #rel_app.name, RelApps) of true -> ok; false -> - Text = lists:concat([RelName, ": ", AppName, " is not included."]), - Status2 = reltool_utils:return_first_error(Status, Text), + Text = lists:concat([RelName, ": ", AppName, + " is not included."]), + Status2 = + reltool_utils:return_first_error(Status, Text), throw({error, Status2}) end end, @@ -1286,9 +1477,11 @@ check_rel(#rel{name = RelName, rel_apps = RelApps}, #sys{apps = Apps}, Status) - {value, App} when App#app.is_included -> ok; _ -> - Text = lists:concat([RelName, ": uses application ", - AppName, " that not is included."]), - Status2 = reltool_utils:return_first_error(Status, Text), + Text = + lists:concat([RelName, ": uses application ", + AppName, " that not is included."]), + Status2 = + reltool_utils:return_first_error(Status, Text), %% throw BUGBUG: add throw ({error, Status2}) end @@ -1308,13 +1501,14 @@ patch_erts_version(RootDir, Apps, Status) -> Apps2 = lists:keystore(AppName, #app.name, Apps, Erts2), {Apps2, Status}; Vsn =:= "" -> - {Apps, reltool_utils:add_warning(Status, "erts has no version")}; + {Apps, reltool_utils:add_warning(Status, + "erts has no version")}; true -> {Apps, Status} end; false -> Text = "erts cannnot be found in the root directory " ++ RootDir, - Status2 = reltool_utils:return_first_error(Status, Text), + Status2 = reltool_utils:return_first_error(Status, Text), {Apps, Status2} end. @@ -1327,21 +1521,31 @@ libs_to_dirs(RootDir, LibDirs, Status) -> [] -> Fun = fun(Base) -> AppDir = filename:join([RootLibDir, Base]), - case filelib:is_dir(filename:join([AppDir, "ebin"]), erl_prim_loader) of + case filelib:is_dir(filename:join([AppDir, + "ebin"]), + erl_prim_loader) of true -> AppDir; false -> - filename:join([RootDir, Base, "preloaded"]) + filename:join([RootDir, + Base, + "preloaded"]) end end, - ErtsFiles = [{erts, Fun(F)} || F <- RootFiles, lists:prefix("erts", F)], + ErtsFiles = [{erts, Fun(F)} || F <- RootFiles, + lists:prefix("erts", F)], app_dirs2(AllLibDirs, [ErtsFiles], Status); [Duplicate | _] -> - {[], reltool_utils:return_first_error(Status, "Duplicate library: " ++ Duplicate)} + {[], + reltool_utils:return_first_error(Status, + "Duplicate library: " ++ + Duplicate)} end; {error, Reason} -> Text = file:format_error(Reason), - {[], reltool_utils:return_first_error(Status, "Missing root library " ++ RootDir ++ ": " ++ Text)} + {[], reltool_utils:return_first_error(Status, + "Missing root library " ++ + RootDir ++ ": " ++ Text)} end. app_dirs2([Lib | Libs], Acc, Status) -> @@ -1352,8 +1556,9 @@ app_dirs2([Lib | Libs], Acc, Status) -> AppDir = filename:join([Lib, Base]), EbinDir = filename:join([AppDir, "ebin"]), case filelib:is_dir(EbinDir, erl_prim_loader) of - true -> - {Name, _Vsn} = reltool_utils:split_app_name(Base), + true -> + {Name, _Vsn} = + reltool_utils:split_app_name(Base), case Name of erts -> false; _ -> {true, {Name, AppDir}} @@ -1366,7 +1571,9 @@ app_dirs2([Lib | Libs], Acc, Status) -> app_dirs2(Libs, [Files2 | Acc], Status); {error, Reason} -> Text = file:format_error(Reason), - {[], reltool_utils:return_first_error(Status, "Illegal library " ++ Lib ++ ": " ++ Text)} + {[], reltool_utils:return_first_error(Status, + "Illegal library " ++ + Lib ++ ": " ++ Text)} end; app_dirs2([], Acc, Status) -> {lists:sort(lists:append(Acc)), Status}. @@ -1380,17 +1587,29 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) -> [AppLabel, "ebin", File] -> case filename:extension(File) of ".app" -> - {AppName, DefaultVsn} = reltool_utils:split_app_name(AppLabel), - AppFileName = filename:join([Escript, FullName]), + {AppName, DefaultVsn} = + reltool_utils:split_app_name(AppLabel), + AppFileName = + filename:join([Escript, FullName]), {Info, StatusAcc2} = - read_app_info(GetBin(), AppFileName, AppName, DefaultVsn, Status), + read_app_info(GetBin(), + AppFileName, + AppName, + DefaultVsn, + Status), Dir = filename:join([Escript, AppName]), - {[{AppName, app, Dir, Info} | FileAcc], StatusAcc2}; + {[{AppName, app, Dir, Info} | FileAcc], + StatusAcc2}; E when E =:= Ext -> - {AppName, _} = reltool_utils:split_app_name(AppLabel), - Mod = init_mod(AppName, File, {File, GetBin()}, Ext), + {AppName, _} = + reltool_utils:split_app_name(AppLabel), + Mod = init_mod(AppName, + File, + {File, GetBin()}, + Ext), Dir = filename:join([Escript, AppName]), - {[{AppName, mod, Dir, Mod} | FileAcc], StatusAcc}; + {[{AppName, mod, Dir, Mod} | FileAcc], + StatusAcc}; _ -> {FileAcc, StatusAcc} end; @@ -1398,13 +1617,21 @@ escripts_to_apps([Escript | Escripts], Apps, OldApps, Status) -> Bin = GetBin(), {ok, {ModName, _}} = beam_lib:version(Bin), ModStr = atom_to_list(ModName) ++ Ext, - Mod = init_mod(EscriptAppName, ModStr, {ModStr, GetBin()}, Ext), - {[{EscriptAppName, mod, Escript, Mod} | FileAcc], StatusAcc}; + Mod = init_mod(EscriptAppName, + ModStr, + {ModStr, GetBin()}, + Ext), + {[{EscriptAppName, mod, Escript, Mod} | FileAcc], + StatusAcc}; [File] -> case filename:extension(File) of E when E =:= Ext -> - Mod = init_mod(EscriptAppName, File, {File, GetBin()}, Ext), - {[{EscriptAppName, mod, File, Mod} | FileAcc], StatusAcc}; + Mod = init_mod(EscriptAppName, + File, + {File, GetBin()}, + Ext), + {[{EscriptAppName, mod, File, Mod} | FileAcc], + StatusAcc}; _ -> {FileAcc, StatusAcc} end; @@ -1433,25 +1660,61 @@ escripts_to_apps([], Apps, _OldApps, Status) -> %% Assume that all files for an app are in consecutive order %% Assume the app info is before the mods -files_to_apps(Escript, [{AppName, Type, Dir, ModOrInfo} | Files] = AllFiles, Acc, Apps, OldApps, Status) -> +files_to_apps(Escript, + [{AppName, Type, Dir, ModOrInfo} | Files] = AllFiles, + Acc, + Apps, + OldApps, + Status) -> case Type of mod -> case Acc of [] -> Info = missing_app_info(""), - {NewApp, Status2} = merge_escript_app(AppName, Dir, Info, [ModOrInfo], Apps, OldApps, Status), - files_to_apps(Escript, AllFiles, [NewApp | Acc], Apps, OldApps, Status2); + {NewApp, Status2} = + merge_escript_app(AppName, + Dir, + Info, + [ModOrInfo], + Apps, + OldApps, + Status), + files_to_apps(Escript, + AllFiles, + [NewApp | Acc], + Apps, + OldApps, Status2); [App | Acc2] when App#app.name =:= ModOrInfo#mod.app_name -> App2 = App#app{mods = [ModOrInfo | App#app.mods]}, - files_to_apps(Escript, Files, [App2 | Acc2], Apps, OldApps, Status); + files_to_apps(Escript, + Files, + [App2 | Acc2], + Apps, + OldApps, + Status); [App | Acc2] -> - PrevApp = App#app{mods = lists:keysort(#mod.name, App#app.mods)}, + PrevApp = App#app{mods = lists:keysort(#mod.name, + App#app.mods)}, Info = missing_app_info(""), - {NewApp, Status2} = merge_escript_app(AppName, Dir, Info, [ModOrInfo], Apps, OldApps, Status), - files_to_apps(Escript, Files, [NewApp, PrevApp | Acc2], Apps, OldApps, Status2) + {NewApp, Status2} = + merge_escript_app(AppName, + Dir, + Info, + [ModOrInfo], + Apps, + OldApps, + Status), + files_to_apps(Escript, + Files, + [NewApp, PrevApp | Acc2], + Apps, + OldApps, + Status2) end; app -> - {App, Status2} = merge_escript_app(AppName, Dir, ModOrInfo, [], Apps, OldApps, Status), + {App, Status2} = + merge_escript_app(AppName, Dir, ModOrInfo, [], Apps, OldApps, + Status), files_to_apps(Escript, Files, [App | Acc], Apps, OldApps, Status2) end; files_to_apps(_Escript, [], Acc, _Apps, _OldApps, Status) -> @@ -1473,13 +1736,14 @@ merge_escript_app(AppName, Dir, Info, Mods, Apps, OldApps, Status) -> case lists:keysearch(AppName, #app.name, Apps) of {value, _} -> Error = lists:concat([AppName, ": Application name clash. ", - "Escript ", Dir," contains application ", AppName, "."]), + "Escript ", Dir," contains application ", + AppName, "."]), {App2, reltool_utils:return_first_error(Status, Error)}; false -> {App2, Status} end. -merge_app_dirs([{Name, Dir} | Rest], [App | Apps], OldApps) +merge_app_dirs([{Name, Dir} | Rest], [App | Apps], OldApps) when App#app.name =:= Name -> %% Add new dir to app App2 = App#app{sorted_dirs = [Dir | App#app.sorted_dirs]}, @@ -1494,10 +1758,11 @@ merge_app_dirs([{Name, Dir} | Rest], Apps, OldApps) -> {value, OldApp} when OldApp#app.active_dir =:= Dir -> [OldApp | Apps2]; {value, OldApp} -> - App = + App = case filter_app(OldApp) of {true, NewApp} -> - NewApp#app{active_dir = Dir, sorted_dirs = [Dir]}; + NewApp#app{active_dir = Dir, + sorted_dirs = [Dir]}; false -> default_app(Name, Dir) end, @@ -1550,10 +1815,11 @@ default_app(Name) -> is_pre_included = undefined, is_included = undefined}. -%% Assume that the application are sorted -refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) when New#app.name =:= Old#app.name -> +%% Assume that the application are sorted +refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) + when New#app.name =:= Old#app.name -> {Info, ActiveDir, Status2} = ensure_app_info(New, Status), - OptLabel = + OptLabel = case Info#app_info.vsn =:= New#app.vsn of true -> New#app.label; false -> undefined % Cause refresh @@ -1562,23 +1828,28 @@ refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) when New#app. refresh_app(New#app{label = OptLabel, active_dir = ActiveDir, vsn = Info#app_info.vsn, - info = Info}, + info = Info}, Force, Status2), refresh_apps(OldApps, NewApps, [Refreshed | Acc], Force, Status3); -refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) when New#app.name < Old#app.name -> +refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) + when New#app.name < Old#app.name -> %% No old app version exists. Use new as is. %% BUGBUG: Issue warning if the active_dir is not defined {New2, Status2} = refresh_app(New, Force, Status), refresh_apps([Old | OldApps], NewApps, [New2 | Acc], Force, Status2); -refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) when New#app.name > Old#app.name -> +refresh_apps([Old | OldApps], [New | NewApps], Acc, Force, Status) + when New#app.name > Old#app.name -> %% No new version. Remove the old. Status2 = case Old#app.name =:= ?MISSING_APP of true -> Status; false -> - Warning = lists:concat([Old#app.name, ": The source dirs does not contain the application anymore."]), + Warning = + lists:concat([Old#app.name, + ": The source dirs does not ", + "contain the application anymore."]), reltool_utils:add_warning(Status, Warning) end, refresh_apps(OldApps, [New | NewApps], Acc, Force, Status2); @@ -1593,21 +1864,28 @@ refresh_apps([Old | OldApps], [], Acc, Force, Status) -> true -> Status; false -> - Warning = lists:concat([Old#app.name, ": The source dirs ", - "does not contain the application anymore."]), + Warning = + lists:concat([Old#app.name, + ": The source dirs does not " + "contain the application anymore."]), reltool_utils:add_warning(Status, Warning) end, refresh_apps(OldApps, [], Acc, Force, Status2); refresh_apps([], [], 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 = true, active_dir = Dir, info = Info}, + Status) -> {Info, Dir, Status}; ensure_app_info(#app{name = Name, sorted_dirs = []}, Status) -> Error = lists:concat([Name, ": Missing application directory."]), Status2 = reltool_utils:return_first_error(Status, Error), {missing_app_info(""), undefined, Status2}; -ensure_app_info(#app{name = Name, vsn = Vsn, sorted_dirs = Dirs, info = undefined}, Status) -> +ensure_app_info(#app{name = Name, + vsn = Vsn, + sorted_dirs = Dirs, + info = undefined}, + Status) -> ReadInfo = fun(Dir, StatusAcc) -> Base = get_base(Name, Dir), @@ -1624,8 +1902,10 @@ ensure_app_info(#app{name = Name, vsn = Vsn, sorted_dirs = Dirs, info = undefine %% No redundant info Status2; [BadVsn | _] -> - Error2 = lists:concat([Name, ": Application version clash. ", - "Multiple directories contains version \"", BadVsn, "\"."]), + Error2 = + lists:concat([Name, ": Application version clash. ", + "Multiple directories contains version \"", + BadVsn, "\"."]), reltool_utils:return_first_error(Status2, Error2) end, FirstInfo = hd(AllInfo), @@ -1640,7 +1920,11 @@ ensure_app_info(#app{name = Name, vsn = Vsn, sorted_dirs = Dirs, info = undefine {Info, VsnDir} -> {Info, VsnDir, Status3}; false -> - Error3 = lists:concat([Name, ": No application directory contains selected version \"", Vsn, "\"."]), + Error3 = + lists:concat([Name, + ": No application directory contains ", + "selected version \"", + Vsn, "\"."]), Status4 = reltool_utils:return_first_error(Status3, Error3), {FirstInfo, FirstDir, Status4} end diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl index ea80ab7e85..e71534d2d3 100644 --- a/lib/reltool/src/reltool_sys_win.erl +++ b/lib/reltool/src/reltool_sys_win.erl @@ -34,7 +34,7 @@ -include_lib("wx/include/wx.hrl"). -include("reltool.hrl"). --record(state, +-record(state, {parent_pid, server_pid, app_wins, @@ -61,7 +61,7 @@ -define(WIN_HEIGHT, 600). -define(CLOSE_ITEM, ?wxID_EXIT). %% Use OS specific version if available --define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific +-define(ABOUT_ITEM, ?wxID_ABOUT). %% Use OS specific -define(CONTENTS_ITEM, 300). -define(APP_GRAPH_ITEM, 301). -define(MOD_GRAPH_ITEM, 302). @@ -100,7 +100,11 @@ %% Client start_link(Opts) -> - proc_lib:start_link(?MODULE, init, [[{parent, self()} | Opts]], infinity, []). + proc_lib:start_link(?MODULE, + init, + [[{parent, self()} | Opts]], + infinity, + []). get_server(Pid) -> reltool_utils:call(Pid, get_server). @@ -146,9 +150,13 @@ do_init([{parent, Parent} | Options]) -> S3 = S2#state{sys = Sys2}, S5 = wx:batch(fun() -> Title = atom_to_list(?APPLICATION), - wxFrame:setTitle(S3#state.frame, Title), - %% wxFrame:setMinSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}), - wxStatusBar:setStatusText(S3#state.status_bar, "Done."), + wxFrame:setTitle(S3#state.frame, + Title), + %% wxFrame:setMinSize(Frame, + %% {?WIN_WIDTH, ?WIN_HEIGHT}), + wxStatusBar:setStatusText( + S3#state.status_bar, + "Done."), S4 = redraw_apps(S3), redraw_libs(S4) end), @@ -182,7 +190,12 @@ loop(S) -> receive {system, From, Msg} -> Common = S#state.common, - sys:handle_system_msg(Msg, From, S#state.parent_pid, ?MODULE, Common#common.sys_debug, S); + sys:handle_system_msg(Msg, + From, + S#state.parent_pid, + ?MODULE, + Common#common.sys_debug, + S); #wx{obj = ObjRef, event = #wxClose{type = close_window}} = Msg -> if @@ -193,17 +206,22 @@ loop(S) -> FWs = S#state.fgraph_wins, case lists:keysearch(ObjRef, #fgraph_win.frame, FWs) of {value, FW} -> - reltool_fgraph_win:stop(FW#fgraph_win.pid, shutdown), + reltool_fgraph_win:stop(FW#fgraph_win.pid, + shutdown), wxFrame:destroy(ObjRef), - FWs2 = lists:keydelete(ObjRef, #fgraph_win.frame, FWs), + FWs2 = + lists:keydelete(ObjRef, #fgraph_win.frame, FWs), ?MODULE:loop(S#state{fgraph_wins = FWs2}); false -> - error_logger:format("~p~p got unexpected message:\n\t~p\n", - [?MODULE, self(), Msg]), + error_logger:format("~p~p got unexpected " + "message:\n\t~p\n", + [?MODULE, self(), Msg]), ?MODULE:loop(S) end end; - #wx{id = ?CLOSE_ITEM, event = #wxCommand{type = command_menu_selected}, userData = main_window} -> + #wx{id = ?CLOSE_ITEM, + event = #wxCommand{type = command_menu_selected}, + userData = main_window} -> wxFrame:destroy(S#state.frame), exit(shutdown); #wx{event = #wxSize{}} = Wx -> @@ -222,14 +240,18 @@ loop(S) -> ?MODULE:loop(S2); {call, ReplyTo, Ref, {open_app, AppName}} -> S2 = do_open_app(S, AppName), - {value, #app_win{pid = AppPid}} = lists:keysearch(AppName, #app_win.name, S2#state.app_wins), + {value, #app_win{pid = AppPid}} = + lists:keysearch(AppName, #app_win.name, S2#state.app_wins), reltool_utils:reply(ReplyTo, Ref, {ok, AppPid}), ?MODULE:loop(S2); {'EXIT', Pid, Reason} when Pid =:= S#state.parent_pid -> - [reltool_fgraph_win:stop(FW#fgraph_win.pid, Reason) || FW <- S#state.fgraph_wins], + [reltool_fgraph_win:stop(FW#fgraph_win.pid, Reason) || + FW <- S#state.fgraph_wins], exit(Reason); {'EXIT', _Pid, _Reason} = Exit -> - {FWs, AWs} = handle_child_exit(Exit, S#state.fgraph_wins, S#state.app_wins), + {FWs, AWs} = handle_child_exit(Exit, + S#state.fgraph_wins, + S#state.app_wins), ?MODULE:loop(S#state{fgraph_wins = FWs, app_wins = AWs}); Msg -> error_logger:format("~p~p got unexpected message:\n\t~p\n", @@ -261,7 +283,8 @@ msg_warning(Exit, Type) -> create_window(S) -> Title = lists:concat([?APPLICATION, " - starting up"]), - Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, [{size, {?WIN_WIDTH, ?WIN_HEIGHT}}]), + Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, + [{size, {?WIN_WIDTH, ?WIN_HEIGHT}}]), %%wxFrame:setSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}), %% wxFrame:setMinSize(Frame, {?WIN_WIDTH, ?WIN_HEIGHT}), Bar = wxFrame:createStatusBar(Frame,[]), @@ -306,21 +329,29 @@ create_menubar(Frame) -> File = wxMenu:new([]), Help = wxMenu:new([]), wxMenuBar:append(MenuBar, File, "File" ), - wxMenu:append(File, ?APP_GRAPH_ITEM, "Display application dependency graph" ), - wxMenu:append(File, ?MOD_GRAPH_ITEM, "Display module dependency graph" ), + wxMenu:append(File, ?APP_GRAPH_ITEM, + "Display application dependency graph" ), + wxMenu:append(File, ?MOD_GRAPH_ITEM, + "Display module dependency graph" ), wxMenu:appendSeparator(File), wxMenu:append(File, ?RESET_CONFIG_ITEM, "Reset configuration to default" ), wxMenu:append(File, ?UNDO_CONFIG_ITEM, "Undo configuration (toggle)" ), wxMenu:append(File, ?LOAD_CONFIG_ITEM, "Load configuration" ), Save = wxMenu:new(), - wxMenu:append(Save, ?SAVE_CONFIG_NODEF_NODER_ITEM, "Save explicit configuration (neither defaults nor derivates)"), - wxMenu:append(Save, ?SAVE_CONFIG_DEF_NODER_ITEM , "Save configuration defaults (defaults only)"), - wxMenu:append(Save, ?SAVE_CONFIG_NODEF_DER_ITEM, "Save configuration derivates (derivates only))"), - wxMenu:append(Save, ?SAVE_CONFIG_DEF_DER_ITEM, "Save extended configuration (both defaults and derivates)"), + wxMenu:append(Save, ?SAVE_CONFIG_NODEF_NODER_ITEM, + "Save explicit configuration " + "(neither defaults nor derivates)"), + wxMenu:append(Save, ?SAVE_CONFIG_DEF_NODER_ITEM, + "Save configuration defaults (defaults only)"), + wxMenu:append(Save, ?SAVE_CONFIG_NODEF_DER_ITEM, + "Save configuration derivates (derivates only))"), + wxMenu:append(Save, ?SAVE_CONFIG_DEF_DER_ITEM, + "Save extended configuration (both defaults and derivates)"), wxMenu:append(File, ?wxID_ANY, "Save configuration", Save), wxMenu:appendSeparator(File), - wxMenu:append(File, ?GEN_REL_FILES_ITEM, "Generate rel, script and boot files" ), + wxMenu:append(File, ?GEN_REL_FILES_ITEM, + "Generate rel, script and boot files" ), wxMenu:append(File, ?GEN_TARGET_ITEM, "Generate target system" ), wxMenu:appendSeparator(File), wxMenu:append(File, ?CLOSE_ITEM, "Close" ), @@ -375,12 +406,13 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) -> %% ?wxLC_SINGLE_SEL bor ?wxVSCROLL}, {size, {Width, Height}}]), - ToolTip = "Select application(s) or open separate application window with a double click.", + ToolTip = "Select application(s) or open separate " + "application window with a double click.", wxListCtrl:setToolTip(ListCtrl, ToolTip), %% Prep images reltool_utils:assign_image_list(ListCtrl), - + %% Prep column label ListItem = wxListItem:new(), wxListItem:setAlign(ListItem, ?wxLIST_FORMAT_LEFT), @@ -395,7 +427,7 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) -> InnerSz = wxBoxSizer:new(?wxVERTICAL), - wxSizer:add(InnerSz, + wxSizer:add(InnerSz, ListCtrl, [{border, 2}, {flag, ?wxALL bor ?wxEXPAND}, @@ -408,9 +440,10 @@ create_app_list_ctrl(Panel, OuterSz, Title, Tick, Cross) -> [{flag, ?wxEXPAND}, {proportion, 1}]), %% Subscribe on events - wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, app_list_ctrl}]), + wxEvtHandler:connect(ListCtrl, size, + [{skip, true}, {userData, app_list_ctrl}]), wxEvtHandler:connect(ListCtrl, command_list_item_activated), - wxWindow:connect(ListCtrl, enter_window), + wxWindow:connect(ListCtrl, enter_window), ListCtrl. @@ -423,7 +456,7 @@ create_button(Panel, Sizer, ListCtrl, Title, BitMapName, Action) -> wxBitmapButton:setToolTip(Button, ToolTip), Options = [{userData, {app_button, Action, ListCtrl}}], wxEvtHandler:connect(Button, command_button_clicked, Options), - wxSizer:add(Sizer, + wxSizer:add(Sizer, Button, [{border, 2}, {flag, ?wxALL}, @@ -439,7 +472,7 @@ action_to_tool_tip(Label, Action) -> "Remove selected application(s)from whitelist."; blacklist_add when Label =:= ?blacklist -> "Remove selected application(s) from blacklist."; - blacklist_add -> + blacklist_add -> "Add selected application(s) to blacklist."; blacklist_del -> "Remove selected application(s) from blacklist." @@ -448,8 +481,9 @@ action_to_tool_tip(Label, Action) -> create_lib_page(#state{book = Book} = S) -> Panel = wxPanel:new(Book, []), Sizer = wxBoxSizer:new(?wxHORIZONTAL), - - Tree = wxTreeCtrl:new(Panel, [{style , ?wxTR_HAS_BUTTONS bor ?wxTR_HIDE_ROOT}]), + + Tree = wxTreeCtrl:new(Panel, + [{style , ?wxTR_HAS_BUTTONS bor ?wxTR_HIDE_ROOT}]), ToolTip = "Edit application sources.", wxBitmapButton:setToolTip(Tree, ToolTip), @@ -478,7 +512,9 @@ redraw_libs(#state{lib_tree = Tree, sys = Sys} = S) -> [append_lib(Tree, LibItem, Dir) || Dir <- Sys#sys.lib_dirs], EscriptItem = append_item(Tree, Top, "Escript files", undefined), - EscriptData = #escript_data{file = undefined, tree = Tree, item = EscriptItem}, + EscriptData = #escript_data{file = undefined, + tree = Tree, + item = EscriptItem}, wxTreeCtrl:setItemData(Tree,EscriptItem, EscriptData), [append_escript(Tree, EscriptItem, File) || File <- Sys#sys.escripts], wxTreeCtrl:expand(Tree, LibItem), @@ -529,9 +565,9 @@ create_config_page(#state{sys = Sys, book = Book} = S) -> Panel = wxPanel:new(Book, []), Sizer = wxBoxSizer:new(?wxHORIZONTAL), AppConds = reltool_utils:incl_conds(), - AppBox = wxRadioBox:new(Panel, + AppBox = wxRadioBox:new(Panel, ?wxID_ANY, - "Application inclusion policy", + "Application inclusion policy", ?wxDefaultPosition, ?wxDefaultSize, AppConds, @@ -543,9 +579,9 @@ create_config_page(#state{sys = Sys, book = Book} = S) -> wxEvtHandler:connect(AppBox, command_radiobox_selected, [{userData, config_incl_cond}]), ModConds = reltool_utils:mod_conds(), - ModBox = wxRadioBox:new(Panel, + ModBox = wxRadioBox:new(Panel, ?wxID_ANY, - "Module inclusion policy", + "Module inclusion policy", ?wxDefaultPosition, ?wxDefaultSize, ModConds, @@ -582,19 +618,19 @@ create_main_release_page(#state{book = Book} = S) -> wxButton:setToolTip(Create, "Create a new release."), wxButton:connect(Create, command_button_clicked, [{userData, create_rel}]), wxSizer:add(ButtonSizer, Create), - + Delete = wxButton:new(Panel, ?wxID_ANY, [{label, "Delete"}]), wxButton:setToolTip(Delete, "Delete a release."), wxButton:connect(Delete, command_button_clicked, [{userData, delete_rel}]), wxSizer:add(ButtonSizer, Delete), - + View = wxButton:new(Panel, ?wxID_ANY, [{label, "View script"}]), wxButton:setToolTip(View, "View generated script file."), wxButton:connect(View, command_button_clicked, [{userData, view_script}]), wxSizer:add(ButtonSizer, View), [add_release_page(RelBook, Rel) || Rel <- (S#state.sys)#sys.rels], - + wxSizer:add(Sizer, RelBook, [{flag, ?wxEXPAND}, {proportion, 1}]), wxSizer:add(Sizer, ButtonSizer, [{flag, ?wxEXPAND}]), wxPanel:setSizer(Panel, Sizer), @@ -604,16 +640,18 @@ create_main_release_page(#state{book = Book} = S) -> add_release_page(Book, #rel{name = RelName, rel_apps = RelApps}) -> Panel = wxPanel:new(Book, []), Sizer = wxBoxSizer:new(?wxHORIZONTAL), - RelBox = wxRadioBox:new(Panel, + RelBox = wxRadioBox:new(Panel, ?wxID_ANY, - "Applications included in the release " ++ RelName, + "Applications included in the release " ++ RelName, ?wxDefaultPosition, ?wxDefaultSize, [atom_to_list(RA#rel_app.name) || RA <- RelApps], []), %% wxRadioBox:setSelection(RelBox, 2), % mandatory - wxEvtHandler:connect(RelBox, command_radiobox_selected, [{userData, {config_rel_cond, RelName}}]), - RelToolTip = "Choose which applications that shall be included in the release resource file.", + wxEvtHandler:connect(RelBox, command_radiobox_selected, + [{userData, {config_rel_cond, RelName}}]), + RelToolTip = "Choose which applications that shall " + "be included in the release resource file.", wxBitmapButton:setToolTip(RelBox, RelToolTip), wxSizer:add(Sizer, @@ -629,11 +667,14 @@ do_open_app(S, AppBase) when is_list(AppBase) -> do_open_app(S, AppName); do_open_app(S, '') -> S; -do_open_app(#state{server_pid = ServerPid, common = C, app_wins = AppWins} = S, AppName) when is_atom(AppName) -> +do_open_app(#state{server_pid = ServerPid, common = C, app_wins = AppWins} = S, + AppName) + when is_atom(AppName) -> case lists:keysearch(AppName, #app_win.name, AppWins) of false -> WxEnv = wx:get_env(), - {ok, Pid} = reltool_app_win:start_link(WxEnv, ServerPid, C, AppName), + {ok, Pid} = + reltool_app_win:start_link(WxEnv, ServerPid, C, AppName), AW = #app_win{name = AppName, pid = Pid}, S#state{app_wins = [AW | AppWins]}; {value, AW} -> @@ -651,7 +692,10 @@ root_popup(S, Root, Tree, Item) -> wxEvtHandler:connect(PopupMenu, menu_close), wxWindow:popupMenu(S#state.frame, PopupMenu), - Popup = #root_popup{dir = Root, choices = Choices, tree = Tree, item = Item}, + Popup = #root_popup{dir = Root, + choices = Choices, + tree = Tree, + item = Item}, S#state{popup_menu = Popup}. lib_popup(S, Lib, Tree, Item) -> @@ -693,7 +737,10 @@ escript_popup(S, File, Tree, Item) -> wxEvtHandler:connect(PopupMenu, menu_close), wxWindow:popupMenu(S#state.frame, PopupMenu), - Popup = #escript_popup{file = File, choices = Choices, tree = Tree, item = Item}, + Popup = #escript_popup{file = File, + choices = Choices, + tree = Tree, + item = Item}, S#state{popup_menu = Popup}. @@ -705,29 +752,40 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = #wxSize{type = size, size = {W, _H}} when UserData =:= app_list_ctrl -> wxListCtrl:setColumnWidth(ObjRef, ?APPS_APP_COL, W), S; - #wxCommand{type = command_menu_selected} when Id =:= ?APP_GRAPH_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?APP_GRAPH_ITEM -> update_app_graph(S); - #wxCommand{type = command_menu_selected} when Id =:= ?MOD_GRAPH_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?MOD_GRAPH_ITEM -> update_mod_graph(S); - #wxCommand{type = command_menu_selected} when Id =:= ?RESET_CONFIG_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?RESET_CONFIG_ITEM -> reset_config(S); - #wxCommand{type = command_menu_selected} when Id =:= ?UNDO_CONFIG_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?UNDO_CONFIG_ITEM -> undo_config(S); - #wxCommand{type = command_menu_selected} when Id =:= ?LOAD_CONFIG_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?LOAD_CONFIG_ITEM -> load_config(S); - #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_NODEF_NODER_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?SAVE_CONFIG_NODEF_NODER_ITEM -> save_config(S, false, false); - #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_NODEF_DER_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?SAVE_CONFIG_NODEF_DER_ITEM -> save_config(S, false, true); #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_DEF_NODER_ITEM -> save_config(S, true, false); - #wxCommand{type = command_menu_selected} when Id =:= ?SAVE_CONFIG_DEF_DER_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?SAVE_CONFIG_DEF_DER_ITEM -> save_config(S, true, true); - #wxCommand{type = command_menu_selected} when Id =:= ?GEN_REL_FILES_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?GEN_REL_FILES_ITEM -> gen_rel_files(S); - #wxCommand{type = command_menu_selected} when Id =:= ?GEN_TARGET_ITEM -> + #wxCommand{type = command_menu_selected} + when Id =:= ?GEN_TARGET_ITEM -> gen_target(S); - #wxCommand{type = command_menu_selected} when UserData =:= main_window, Id =:= ?CONTENTS_ITEM -> + #wxCommand{type = command_menu_selected} + when UserData =:= main_window, Id =:= ?CONTENTS_ITEM -> {file, BeamFile} = code:is_loaded(?MODULE), EbinDir = filename:dirname(BeamFile), AppDir = filename:dirname(EbinDir), @@ -735,16 +793,17 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = Url = "file://" ++ filename:absname(HelpFile), wx_misc:launchDefaultBrowser(Url), S; - #wxCommand{type = command_menu_selected} when UserData =:= main_window, Id =:= ?ABOUT_ITEM -> - AboutStr = "Reltool is a release management tool. It analyses a given" - " Erlang/OTP installation and determines various dependencies" - " between applications. The graphical frontend depicts the" - " dependencies and enables interactive customization of a" - " target system. The backend provides a batch interface" - " for generation of customized target systems.", - MD = wxMessageDialog:new(S#state.frame, + #wxCommand{type = command_menu_selected} + when UserData =:= main_window, Id =:= ?ABOUT_ITEM -> + AboutStr = "Reltool is a release management tool. It analyses a " + " given Erlang/OTP installation and determines various " + " dependencies between applications. The graphical frontend " + " depicts the dependencies and enables interactive " + " customization of a target system. The backend provides a " + " batch interface for generation of customized target systems.", + MD = wxMessageDialog:new(S#state.frame, AboutStr, - [{style, ?wxOK bor ?wxICON_INFORMATION}, + [{style, ?wxOK bor ?wxICON_INFORMATION}, {caption, "About Reltool"}]), wxMessageDialog:showModal(MD), wxMessageDialog:destroy(MD), @@ -758,7 +817,8 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = wxWindow:setFocus(ObjRef), S; _ -> - case wxNotebook:getPageText(S#state.book, wxNotebook:getSelection(S#state.book)) of + case wxNotebook:getPageText(S#state.book, + wxNotebook:getSelection(S#state.book)) of ?APP_PAGE -> handle_app_event(S, Event, ObjRef, UserData); ?LIB_PAGE -> handle_source_event(S, Event, ObjRef, UserData); ?SYS_PAGE -> handle_system_event(S, Event, ObjRef, UserData); @@ -768,13 +828,17 @@ handle_event(S, #wx{id = Id, obj= ObjRef, userData = UserData, event = Event} = handle_popup_event(S, _Type, 0, _ObjRef, _UserData, _Str) -> S#state{popup_menu = undefined}; -handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir, choices = Choices}, +handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir, + choices = Choices}, sys = Sys} = S, _Type, Pos, _ObjRef, _UserData, _Str) -> case lists:nth(Pos, Choices) of edit -> Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST, - case select_dir(S#state.frame, "Change root directory", OldDir, Style) of + case select_dir(S#state.frame, + "Change root directory", + OldDir, + Style) of {ok, NewDir} when NewDir =:= OldDir -> %% Same dir.Ignore. S#state{popup_menu = undefined}; @@ -785,7 +849,8 @@ handle_popup_event(#state{popup_menu = #root_popup{dir = OldDir, choices = Choic S#state{popup_menu = undefined} end end; -handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choices}, +handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, + choices = Choices}, sys = Sys} = S, _Type, Pos, _ObjRef, _UserData, _Str) -> case lists:nth(Pos, Choices) of @@ -801,14 +866,18 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choice false -> LibDirs = Sys#sys.lib_dirs ++ [NewDir], Sys2 = Sys#sys{lib_dirs = LibDirs}, - do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) + do_set_sys(S#state{popup_menu = undefined, + sys = Sys2}) end; cancel -> S#state{popup_menu = undefined} end; edit -> Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST, - case select_dir(S#state.frame, "Change library directory", OldDir, Style) of + case select_dir(S#state.frame, + "Change library directory", + OldDir, + Style) of {ok, NewDir} -> case lists:member(NewDir, Sys#sys.lib_dirs) of true -> @@ -820,7 +889,8 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choice lists:splitwith(Pred, Sys#sys.lib_dirs), LibDirs2 = Before ++ [NewDir | After], Sys2 = Sys#sys{lib_dirs = LibDirs2}, - do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) + do_set_sys(S#state{popup_menu = undefined, + sys = Sys2}) end; cancel -> S#state{popup_menu = undefined} @@ -828,14 +898,15 @@ handle_popup_event(#state{popup_menu = #lib_popup{dir = OldDir, choices = Choice delete -> LibDirs = Sys#sys.lib_dirs -- [OldDir], Sys2 = Sys#sys{lib_dirs = LibDirs}, - do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) + do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) end; -handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices = Choices}, +handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, + choices = Choices}, sys = Sys} = S, _Type, Pos, _ObjRef, _UserData, _Str) -> case lists:nth(Pos, Choices) of add -> - OldFile2 = + OldFile2 = case OldFile of undefined -> {ok, Cwd} = file:get_cwd(), @@ -844,7 +915,10 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices = OldFile end, Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST, - case select_file(S#state.frame, "Select an escript file to add", OldFile2, Style) of + case select_file(S#state.frame, + "Select an escript file to add", + OldFile2, + Style) of {ok, NewFile} -> case lists:member(NewFile, Sys#sys.escripts) of true -> @@ -860,7 +934,10 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices = end; edit -> Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST, - case select_file(S#state.frame, "Change escript file name", OldFile, Style) of + case select_file(S#state.frame, + "Change escript file name", + OldFile, + Style) of {ok, NewFile} -> case lists:member(NewFile, Sys#sys.escripts) of true -> @@ -868,10 +945,12 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices = S#state{popup_menu = undefined}; false -> Pred = fun(E) -> E =/= OldFile end, - {Before, [_| After]} = lists:splitwith(Pred, Sys#sys.escripts), + {Before, [_| After]} = + lists:splitwith(Pred, Sys#sys.escripts), Escripts2 = Before ++ [NewFile | After], Sys2 = Sys#sys{escripts = Escripts2}, - do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) + do_set_sys(S#state{popup_menu = undefined, + sys = Sys2}) end; cancel -> S#state{popup_menu = undefined} @@ -879,25 +958,28 @@ handle_popup_event(#state{popup_menu = #escript_popup{file = OldFile, choices = delete -> Escripts = Sys#sys.escripts -- [OldFile], Sys2 = Sys#sys{escripts = Escripts}, - do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) + do_set_sys(S#state{popup_menu = undefined, sys = Sys2}) end. handle_system_event(#state{sys = Sys} = S, - #wxCommand{type = command_radiobox_selected, cmdString = Choice}, + #wxCommand{type = command_radiobox_selected, + cmdString = Choice}, _ObjRef, config_mod_cond) -> ModCond = reltool_utils:list_to_mod_cond(Choice), Sys2 = Sys#sys{mod_cond = ModCond}, do_set_sys(S#state{sys = Sys2}); handle_system_event(#state{sys = Sys} = S, - #wxCommand{type = command_radiobox_selected, cmdString = Choice}, + #wxCommand{type = command_radiobox_selected, + cmdString = Choice}, _ObjRef, config_incl_cond) -> AppCond = reltool_utils:list_to_incl_cond(Choice), Sys2 = Sys#sys{incl_cond = AppCond}, do_set_sys(S#state{sys = Sys2}); handle_system_event(S, Event, ObjRef, UserData) -> - error_logger:format("~p~p got unexpected wx sys event to ~p with user data: ~p\n\t ~p\n", + error_logger:format("~p~p got unexpected wx sys event to ~p " + "with user data: ~p\n\t ~p\n", [?MODULE, self(), ObjRef, UserData, Event]), S. @@ -905,7 +987,11 @@ handle_release_event(S, _Event, _ObjRef, UserData) -> io:format("Release data: ~p\n", [UserData]), S. -handle_source_event(S, #wxTree{type = command_tree_item_activated, item = Item}, ObjRef, _UserData) -> +handle_source_event(S, + #wxTree{type = command_tree_item_activated, + item = Item}, + ObjRef, + _UserData) -> case wxTreeCtrl:getItemData(ObjRef, Item) of #root_data{dir = _Dir} -> %% io:format("Root dialog: ~p\n", [Dir]), @@ -921,7 +1007,11 @@ handle_source_event(S, #wxTree{type = command_tree_item_activated, item = Item}, undefined -> S end; -handle_source_event(S, #wxTree{type = command_tree_item_right_click, item = Item}, Tree, _UserData) -> +handle_source_event(S, + #wxTree{type = command_tree_item_right_click, + item = Item}, + Tree, + _UserData) -> case wxTreeCtrl:getItemData(Tree, Item) of #root_data{dir = Dir} -> wx:batch(fun() -> root_popup(S, Dir, Tree, Item) end); @@ -936,18 +1026,28 @@ handle_source_event(S, #wxTree{type = command_tree_item_right_click, item = Item S end. -handle_app_event(S, #wxList{type = command_list_item_activated, itemIndex = Pos}, ListCtrl, _UserData) -> +handle_app_event(S, + #wxList{type = command_list_item_activated, + itemIndex = Pos}, + ListCtrl, + _UserData) -> AppName = wxListCtrl:getItemText(ListCtrl, Pos), do_open_app(S, AppName); -handle_app_event(S, #wxCommand{type = command_button_clicked}, _ObjRef, {app_button, Action, ListCtrl}) -> +handle_app_event(S, + #wxCommand{type = command_button_clicked}, + _ObjRef, + {app_button, Action, ListCtrl}) -> Items = reltool_utils:get_items(ListCtrl), handle_app_button(S, Items, Action); handle_app_event(S, Event, ObjRef, UserData) -> - error_logger:format("~p~p got unexpected wx app event to ~p with user data: ~p\n\t ~p\n", + error_logger:format("~p~p got unexpected wx app event to " + "~p with user data: ~p\n\t ~p\n", [?MODULE, self(), ObjRef, UserData, Event]), S. -handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S, Items, Action) -> +handle_app_button(#state{server_pid = ServerPid, app_wins = AppWins} = S, + Items, + Action) -> NewApps = [move_app(S, Item, Action) || Item <- Items], case reltool_server:set_apps(ServerPid, NewApps) of {ok, []} -> @@ -967,9 +1067,9 @@ do_set_sys(#state{sys = Sys, server_pid = ServerPid, status_bar = Bar} = S) -> check_and_refresh(S, Status). move_app(S, {_ItemNo, AppBase}, Action) -> - {AppName, _Vsn} = reltool_utils:split_app_name(AppBase), + {AppName, _Vsn} = reltool_utils:split_app_name(AppBase), {ok, OldApp} = reltool_server:get_app(S#state.server_pid, AppName), - AppCond = + AppCond = case Action of whitelist_add -> case OldApp#app.incl_cond of @@ -979,12 +1079,13 @@ move_app(S, {_ItemNo, AppBase}, Action) -> end; whitelist_del -> undefined; - blacklist_add -> + blacklist_add -> exclude; blacklist_del -> undefined; _ -> - error_logger:format("~p~p got unexpected app button event: ~p ~p\n", + error_logger:format("~p~p got unexpected app " + "button event: ~p ~p\n", [?MODULE, self(), Action, AppBase]), OldApp#app.incl_cond end, @@ -1047,14 +1148,21 @@ do_redraw_apps(ListCtrl, Apps, OkImage, ErrImage) -> ImageApps = lists:map(AddImage, Apps), Show = fun({ImageId, Text, App}, {Row, ModCount, Items}) -> - wxListCtrl:insertItem(ListCtrl, Row, ""), - if (Row rem 2) =:= 0 -> - wxListCtrl:setItemBackgroundColour(ListCtrl, Row, {240,240,255}); + wxListCtrl:insertItem(ListCtrl, Row, ""), + if (Row rem 2) =:= 0 -> + wxListCtrl:setItemBackgroundColour(ListCtrl, + Row, + {240,240,255}); true -> ignore end, - wxListCtrl:setItem(ListCtrl, Row, ?APPS_APP_COL, Text, [{imageId, ImageId}]), - N = length([M || M <- App#app.mods, M#mod.is_included =:= true]), + wxListCtrl:setItem(ListCtrl, + Row, + ?APPS_APP_COL, + Text, + [{imageId, ImageId}]), + N = length([M || M <- App#app.mods, + M#mod.is_included =:= true]), {Row + 1, ModCount + N, [{Row, Text} | Items]} end, {_, N, NewItems} = wx:foldl(Show, {0, 0, []}, lists:sort(ImageApps)), @@ -1068,8 +1176,10 @@ update_app_graph(S) -> WhiteNames = [A#app.name || A <- WhiteApps], DerivedNames = [A#app.name || A <- DerivedApps], Nodes = WhiteNames ++ DerivedNames, - %% WhiteUses = [N || A <- WhiteApps, N <- A#app.uses_apps, lists:member(N, Nodes)], - %% DerivedUses = [N || A <- DerivedApps, N <- A#app.uses_apps, lists:member(N, Nodes)], + %% WhiteUses = [N || A <- WhiteApps, + %% N <- A#app.uses_apps, lists:member(N, Nodes)], + %% DerivedUses = [N || A <- DerivedApps, + %% N <- A#app.uses_apps, lists:member(N, Nodes)], WhiteLinks = [[A#app.name, U] || A <- WhiteApps, U <- A#app.uses_apps, @@ -1078,7 +1188,7 @@ update_app_graph(S) -> DerivedLinks = [[A#app.name, U] || A <- DerivedApps, U <- A#app.uses_apps, U =/= A#app.name, - lists:member(U, Nodes)], + lists:member(U, Nodes)], Links = lists:usort(WhiteLinks ++ DerivedLinks), %% io:format("Links: ~p\n", [Links]), Title = lists:concat([?APPLICATION, " - application graph"]), @@ -1087,8 +1197,12 @@ update_app_graph(S) -> update_mod_graph(S) -> {ok, WhiteApps} = reltool_server:get_apps(S#state.server_pid, whitelist), {ok, DerivedApps} = reltool_server:get_apps(S#state.server_pid, derived), - WhiteMods = lists:usort([M || A <- WhiteApps, M <- A#app.mods, M#mod.is_included =:= true]), - DerivedMods = lists:usort([M || A <- DerivedApps, M <- A#app.mods, M#mod.is_included =:= true]), + WhiteMods = lists:usort([M || A <- WhiteApps, + M <- A#app.mods, + M#mod.is_included =:= true]), + DerivedMods = lists:usort([M || A <- DerivedApps, + M <- A#app.mods, + M#mod.is_included =:= true]), WhiteNames = [M#mod.name || M <- WhiteMods], DerivedNames = [M#mod.name || M <- DerivedMods], @@ -1141,7 +1255,10 @@ undo_config(#state{status_bar = Bar} = S) -> load_config(#state{status_bar = Bar, config_file = OldFile} = S) -> Style = ?wxFD_OPEN bor ?wxFD_FILE_MUST_EXIST, - case select_file(S#state.frame, "Select a file to load the configuration from", OldFile, Style) of + case select_file(S#state.frame, + "Select a file to load the configuration from", + OldFile, + Style) of {ok, NewFile} -> wxStatusBar:setStatusText(Bar, "Processing libraries..."), Status = reltool_server:load_config(S#state.server_pid, NewFile), @@ -1151,18 +1268,27 @@ load_config(#state{status_bar = Bar, config_file = OldFile} = S) -> end. save_config(#state{config_file = OldFile} = S, InclDefaults, InclDerivates) -> - Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, - case select_file(S#state.frame, "Select a file to save the configuration to", OldFile, Style) of + Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, + case select_file(S#state.frame, + "Select a file to save the configuration to", + OldFile, + Style) of {ok, NewFile} -> - Status = reltool_server:save_config(S#state.server_pid, NewFile, InclDefaults, InclDerivates), + Status = reltool_server:save_config(S#state.server_pid, + NewFile, + InclDefaults, + InclDerivates), check_and_refresh(S#state{config_file = NewFile}, Status); cancel -> S end. gen_rel_files(#state{target_dir = OldDir} = S) -> - Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, - case select_dir(S#state.frame, "Select a directory to generate rel, script and boot files to", OldDir, Style) of + Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, + case select_dir(S#state.frame, + "Select a directory to generate rel, script and boot files to", + OldDir, + Style) of {ok, NewDir} -> Status = reltool_server:gen_rel_files(S#state.server_pid, NewDir), check_and_refresh(S, Status); @@ -1171,8 +1297,11 @@ gen_rel_files(#state{target_dir = OldDir} = S) -> end. gen_target(#state{target_dir = OldDir} = S) -> - Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, - case select_dir(S#state.frame, "Select a directory to generate a target system to", OldDir, Style) of + Style = ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT, + case select_dir(S#state.frame, + "Select a directory to generate a target system to", + OldDir, + Style) of {ok, NewDir} -> Status = reltool_server:gen_target(S#state.server_pid, NewDir), check_and_refresh(S#state{target_dir = NewDir}, Status); @@ -1186,7 +1315,7 @@ select_file(Frame, Message, DefaultFile, Style) -> {defaultDir, filename:dirname(DefaultFile)}, {defaultFile, filename:basename(DefaultFile)}, {style, Style}]), - Choice = + Choice = case wxMessageDialog:showModal(Dialog) of ?wxID_CANCEL -> cancel; ?wxID_OK -> {ok, wxFileDialog:getPath(Dialog)} @@ -1199,7 +1328,7 @@ select_dir(Frame, Message, DefaultDir, Style) -> [{title, Message}, {defaultPath, DefaultDir}, {style, Style}]), - Choice = + Choice = case wxMessageDialog:showModal(Dialog) of ?wxID_CANCEL -> cancel; ?wxID_OK -> {ok, wxDirDialog:getPath(Dialog)} @@ -1229,28 +1358,34 @@ refresh(S) -> S2 = S#state{sys = Sys}, S3 = redraw_libs(S2), redraw_apps(S3). - + question_dialog(Question, Details) -> %% Parent = S#state.frame, Parent = wx:typeCast(wx:null(), wxWindow), %% [{style, ?wxYES_NO bor ?wxICON_ERROR bor ?wx}]), DialogStyle = ?wxRESIZE_BORDER bor ?wxCAPTION bor ?wxSYSTEM_MENU bor ?wxMINIMIZE_BOX bor ?wxMAXIMIZE_BOX bor ?wxCLOSE_BOX, - Dialog = wxDialog:new(Parent, ?wxID_ANY, "Undo dialog", [{style, DialogStyle}]), + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Undo dialog", + [{style, DialogStyle}]), Color = wxWindow:getBackgroundColour(Dialog), TextStyle = ?wxTE_READONLY bor ?wxTE_MULTILINE bor ?wxHSCROLL, - Text1 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{style, ?wxTE_READONLY bor ?wxBORDER_NONE}]), + Text1 = wxTextCtrl:new(Dialog, ?wxID_ANY, + [{style, ?wxTE_READONLY bor ?wxBORDER_NONE}]), wxWindow:setBackgroundColour(Text1, Color), wxTextCtrl:appendText(Text1, Question), - Text2 = wxTextCtrl:new(Dialog, ?wxID_ANY, [{size, {600, 400}}, {style, TextStyle}]), + Text2 = wxTextCtrl:new(Dialog, ?wxID_ANY, + [{size, {600, 400}}, {style, TextStyle}]), wxWindow:setBackgroundColour(Text2, Color), wxTextCtrl:appendText(Text2, Details), %% wxDialog:setAffirmativeId(Dialog, ?wxID_YES), %% wxDialog:setEscapeId(Dialog, ?wxID_NO), Sizer = wxBoxSizer:new(?wxVERTICAL), wxSizer:add(Sizer, Text1, [{border, 2}, {flag, ?wxEXPAND}]), - wxSizer:add(Sizer, Text2, [{border, 2}, {flag, ?wxEXPAND}, {proportion, 1}]), - ButtSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxOK bor ?wxCANCEL), + wxSizer:add(Sizer, Text2, [{border, 2}, + {flag, ?wxEXPAND}, + {proportion, 1}]), + ButtSizer = wxDialog:createStdDialogButtonSizer(Dialog, + ?wxOK bor ?wxCANCEL), wxSizer:add(Sizer, ButtSizer, [{border, 2}, {flag, ?wxEXPAND}]), wxPanel:setSizer(Dialog, Sizer), wxSizer:fit(Sizer, Dialog), diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl index 6d85a98d9f..e079a02f3c 100644 --- a/lib/reltool/src/reltool_target.erl +++ b/lib/reltool/src/reltool_target.erl @@ -22,7 +22,7 @@ -export([ gen_config/2, gen_app/1, - gen_rel/2, + gen_rel/2, gen_rel_files/2, gen_boot/1, gen_script/4, @@ -55,7 +55,9 @@ kernel_processes(KernelApp) -> [ {kernelProcess, heart, {heart, start, []}}, {kernelProcess, error_logger , {error_logger, start_link, []}}, - {kernelProcess, application_controller, {application_controller, start, [KernelApp]}} + {kernelProcess, + application_controller, + {application_controller, start, [KernelApp]}} ]. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -82,120 +84,126 @@ gen_config(#sys{root_dir = RootDir, app_type = AppType, app_file = AppFile, debug_info = DebugInfo}, - InclDefaults) -> - ErtsItems = + InclDefs) -> + ErtsItems = case lists:keysearch(erts, #app.name, Apps) of {value, Erts} -> - [{erts, gen_config(Erts, InclDefaults)}]; + [{erts, gen_config(Erts, InclDefs)}]; false -> [] end, AppsItems = - [{app, A#app.name, gen_config(A, InclDefaults)} - || A <- Apps, + [{app, A#app.name, gen_config(A, InclDefs)} + || A <- Apps, A#app.name =/= ?MISSING_APP, A#app.name =/= erts, A#app.is_included =:= true, A#app.is_escript =/= true], - EscriptItems = [{escript, A#app.active_dir, emit(incl_cond, A#app.incl_cond, undefined, InclDefaults)} + EscriptItems = [{escript, + A#app.active_dir, + emit(incl_cond, A#app.incl_cond, undefined, InclDefs)} || A <- Apps, A#app.is_escript], DefaultRels = reltool_utils:default_rels(), RelsItems = - case {[{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefaults)} || R <- Rels], - [{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefaults)} || R <- DefaultRels]} of + case {[{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefs)} || + R <- Rels], + [{rel, R#rel.name, R#rel.vsn, gen_config(R, InclDefs)} || + R <- DefaultRels]} of {RI, RI} -> []; {RI, _} -> RI end, X = fun(List) -> [Re || #regexp{source = Re} <- List] end, {sys, - emit(root_dir, RootDir, code:root_dir(), InclDefaults) ++ - emit(lib_dirs, LibDirs, ?DEFAULT_LIBS, InclDefaults) ++ + emit(root_dir, RootDir, code:root_dir(), InclDefs) ++ + emit(lib_dirs, LibDirs, ?DEFAULT_LIBS, InclDefs) ++ EscriptItems ++ - emit(mod_cond, ModCond, ?DEFAULT_MOD_COND, InclDefaults) ++ - emit(incl_cond, AppCond, ?DEFAULT_INCL_COND, InclDefaults) ++ + emit(mod_cond, ModCond, ?DEFAULT_MOD_COND, InclDefs) ++ + emit(incl_cond, AppCond, ?DEFAULT_INCL_COND, InclDefs) ++ ErtsItems ++ AppsItems ++ - emit(boot_rel, BootRel, ?DEFAULT_REL_NAME, InclDefaults) ++ + emit(boot_rel, BootRel, ?DEFAULT_REL_NAME, InclDefs) ++ RelsItems ++ - emit(emu_name, EmuName, ?DEFAULT_EMU_NAME, InclDefaults) ++ - emit(relocatable, Relocatable, ?DEFAULT_RELOCATABLE, InclDefaults) ++ - emit(profile, Profile, ?DEFAULT_PROFILE, InclDefaults) ++ - emit(incl_sys_filters, X(InclSysFiles), ?DEFAULT_INCL_SYS_FILTERS, InclDefaults) ++ - emit(excl_sys_filters, X(ExclSysFiles), ?DEFAULT_EXCL_SYS_FILTERS, InclDefaults) ++ - emit(incl_app_filters, X(InclAppFiles), ?DEFAULT_INCL_APP_FILTERS, InclDefaults) ++ - emit(excl_app_filters, X(ExclAppFiles), ?DEFAULT_EXCL_APP_FILTERS, InclDefaults) ++ - emit(incl_archive_filters, X(InclArchiveDirs), ?DEFAULT_INCL_ARCHIVE_FILTERS, InclDefaults) ++ - emit(excl_archive_filters, X(ExclArchiveDirs), ?DEFAULT_EXCL_ARCHIVE_FILTERS, InclDefaults) ++ - emit(archive_opts, ArchiveOpts, ?DEFAULT_ARCHIVE_OPTS, InclDefaults) ++ - emit(app_type, AppType, ?DEFAULT_APP_TYPE, InclDefaults) ++ - emit(app_file, AppFile, ?DEFAULT_APP_FILE, InclDefaults) ++ - emit(debug_info, DebugInfo, ?DEFAULT_DEBUG_INFO, InclDefaults)}; -gen_config(#app{name = _Name, - mod_cond = ModCond, - incl_cond = AppCond, - debug_info = DebugInfo, - app_file = AppFile, - incl_app_filters = InclAppFiles, - excl_app_filters = ExclAppFiles, + emit(emu_name, EmuName, ?DEFAULT_EMU_NAME, InclDefs) ++ + emit(relocatable, Relocatable, ?DEFAULT_RELOCATABLE, InclDefs) ++ + emit(profile, Profile, ?DEFAULT_PROFILE, InclDefs) ++ + emit(incl_sys_filters, X(InclSysFiles), ?DEFAULT_INCL_SYS_FILTERS, InclDefs) ++ + emit(excl_sys_filters, X(ExclSysFiles), ?DEFAULT_EXCL_SYS_FILTERS, InclDefs) ++ + emit(incl_app_filters, X(InclAppFiles), ?DEFAULT_INCL_APP_FILTERS, InclDefs) ++ + emit(excl_app_filters, X(ExclAppFiles), ?DEFAULT_EXCL_APP_FILTERS, InclDefs) ++ + emit(incl_archive_filters, X(InclArchiveDirs), ?DEFAULT_INCL_ARCHIVE_FILTERS, InclDefs) ++ + emit(excl_archive_filters, X(ExclArchiveDirs), ?DEFAULT_EXCL_ARCHIVE_FILTERS, InclDefs) ++ + emit(archive_opts, ArchiveOpts, ?DEFAULT_ARCHIVE_OPTS, InclDefs) ++ + emit(app_type, AppType, ?DEFAULT_APP_TYPE, InclDefs) ++ + emit(app_file, AppFile, ?DEFAULT_APP_FILE, InclDefs) ++ + emit(debug_info, DebugInfo, ?DEFAULT_DEBUG_INFO, InclDefs)}; +gen_config(#app{name = _Name, + mod_cond = ModCond, + incl_cond = AppCond, + debug_info = DebugInfo, + app_file = AppFile, + incl_app_filters = InclAppFiles, + excl_app_filters = ExclAppFiles, incl_archive_filters = InclArchiveDirs, excl_archive_filters = ExclArchiveDirs, - archive_opts = ArchiveOpts, + archive_opts = ArchiveOpts, use_selected_vsn = UseSelected, vsn = Vsn, mods = Mods}, - InclDefaults) -> - emit(mod_cond, ModCond, undefined, InclDefaults) ++ - emit(incl_cond, AppCond, undefined, InclDefaults) ++ - emit(debug_info, DebugInfo, undefined, InclDefaults) ++ - emit(app_file, AppFile, undefined, InclDefaults) ++ - emit(incl_app_filters, InclAppFiles, undefined, InclDefaults) ++ - emit(excl_app_filters, ExclAppFiles, undefined, InclDefaults) ++ - emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefaults) ++ - emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefaults) ++ - emit(archive_opts, ArchiveOpts, undefined, InclDefaults) ++ - emit(vsn, Vsn, undefined, InclDefaults orelse UseSelected =/= true) ++ - [{mod, M#mod.name, gen_config(M, InclDefaults)} || M <- Mods, M#mod.is_included =:= true]; + InclDefs) -> + emit(mod_cond, ModCond, undefined, InclDefs) ++ + emit(incl_cond, AppCond, undefined, InclDefs) ++ + emit(debug_info, DebugInfo, undefined, InclDefs) ++ + emit(app_file, AppFile, undefined, InclDefs) ++ + emit(incl_app_filters, InclAppFiles, undefined, InclDefs) ++ + emit(excl_app_filters, ExclAppFiles, undefined, InclDefs) ++ + emit(incl_archive_filters, InclArchiveDirs, undefined, InclDefs) ++ + emit(excl_archive_filters, ExclArchiveDirs, undefined, InclDefs) ++ + emit(archive_opts, ArchiveOpts, undefined, InclDefs) ++ + emit(vsn, Vsn, undefined, InclDefs orelse UseSelected =/= true) ++ + [{mod, M#mod.name, gen_config(M, InclDefs)} || + M <- Mods, + M#mod.is_included =:= true]; gen_config(#mod{name = _Name, incl_cond = AppCond, debug_info = DebugInfo}, - InclDefaults) -> - emit(incl_cond, AppCond, undefined, InclDefaults) ++ - emit(debug_info, DebugInfo, undefined, InclDefaults); + InclDefs) -> + emit(incl_cond, AppCond, undefined, InclDefs) ++ + emit(debug_info, DebugInfo, undefined, InclDefs); gen_config(#rel{name = _Name, vsn = _Vsn, rel_apps = RelApps}, - InclDefaults) -> - [gen_config(RA, InclDefaults) || RA <- RelApps]; + InclDefs) -> + [gen_config(RA, InclDefs) || RA <- RelApps]; gen_config(#rel_app{name = Name, app_type = Type, incl_apps = InclApps}, - _InclDefaults) -> + _InclDefs) -> case {Type, InclApps} of {undefined, []} -> Name; {undefined, _} -> {Name, InclApps}; {_, []} -> {Name, Type}; {_, _} -> {Name, Type, InclApps} end; -gen_config({Tag, Val}, InclDefaults) -> - emit(Tag, Val, undefined, InclDefaults); -gen_config([], _InclDefaults) -> +gen_config({Tag, Val}, InclDefs) -> + emit(Tag, Val, undefined, InclDefs); +gen_config([], _InclDefs) -> []; -gen_config([H | T], InclDefaults) -> - lists:flatten([gen_config(H, InclDefaults), gen_config(T, InclDefaults)]). +gen_config([H | T], InclDefs) -> + lists:flatten([gen_config(H, InclDefs), gen_config(T, InclDefs)]). -emit(Tag, Val, Default, InclDefaults) -> +emit(Tag, Val, Default, InclDefs) -> if Val == undefined -> []; - InclDefaults -> [{Tag, Val}]; + InclDefs -> [{Tag, Val}]; Val =/= Default -> [{Tag, Val}]; true -> [] - end. + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate the contents of an app file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -gen_app(#app{name = Name, +gen_app(#app{name = Name, info = #app_info{description = Desc, id = Id, vsn = Vsn, @@ -234,19 +242,20 @@ gen_app(#app{name = Name, gen_rel(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, #sys{apps = Apps}) -> {value, Erts} = lists:keysearch(erts, #app.name, Apps), - {release, + {release, {RelName, RelVsn}, {erts, Erts#app.vsn}, [app_to_rel(RA, Apps ) || RA <- RelApps]}. -app_to_rel(#rel_app{name = Name, app_type = Type, incl_apps = InclApps}, Apps) -> +app_to_rel(#rel_app{name = Name, app_type = Type, incl_apps = InclApps}, + Apps) -> {value, #app{vsn = Vsn}} = lists:keysearch(Name, #app.name, Apps), case {Type, InclApps} of {undefined, []} -> {Name, Vsn}; {undefined, _} -> {Name, Vsn, InclApps}; {_, []} -> {Name, Vsn, Type}; {_, _} -> {Name, Vsn, Type, InclApps} - end. + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Generate the contents of a boot file @@ -262,7 +271,7 @@ gen_boot({script, {_, _}, _} = Script) -> gen_script(Rel, Sys, PathFlag, Variables) -> try do_gen_script(Rel, Sys, PathFlag, Variables) - catch + catch throw:{error, Text} -> {error, Text} end. @@ -279,7 +288,9 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, SortedApps = sort_apps(MergedApps), {value, KernelApp} = lists:keysearch(kernel, #app.name, SortedApps), - InclApps = lists:append([I || #app{info = #app_info{incl_apps = I}} <- SortedApps]), + InclApps = + lists:append([I || + #app{info = #app_info{incl_apps = I}} <- SortedApps]), %% Create the script DeepList = @@ -312,9 +323,9 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, %% Start applications [{apply, {application, start_boot, [Name, Type]}} || - #app{name = Name, app_type = Type} <- SortedApps, - Type =/= none, - Type =/= load, + #app{name = Name, app_type = Type} <- SortedApps, + Type =/= none, + Type =/= load, not lists:member(Name, InclApps)], %% Apply user specific customizations @@ -323,7 +334,9 @@ do_gen_script(#rel{name = RelName, vsn = RelVsn, rel_apps = RelApps}, ], {ok, {script, {RelName, RelVsn}, lists:flatten(DeepList)}}. -merge_app(#rel_app{name = Name, app_type = Type, incl_apps = RelIncl}, Apps, DefaultType) -> +merge_app(#rel_app{name = Name, app_type = Type, incl_apps = RelIncl}, + Apps, + DefaultType) -> {value, App} = lists:keysearch(Name, #app.name, Apps), Type2 = case {Type, App#app.app_type} of @@ -334,10 +347,12 @@ merge_app(#rel_app{name = Name, app_type = Type, incl_apps = RelIncl}, Apps, Def Info = App#app.info, case RelIncl -- Info#app_info.incl_apps of [] -> - App#app{app_type = Type2, info = Info#app_info{incl_apps = RelIncl}}; + App#app{app_type = Type2, + info = Info#app_info{incl_apps = RelIncl}}; BadIncl -> - reltool_utils:throw_error("~p: These applications are missing as " - "included_applications in the app file: ~p\n", + reltool_utils:throw_error("~p: These applications are " + "missing as included_applications " + "in the app file: ~p\n", [Name, BadIncl]) end. @@ -359,7 +374,7 @@ load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) -> Subs -> [{Subs, [M]}|[{Last,Acc}|Rest]] end - end, + end, [{[], []}], PartNames), @@ -381,17 +396,26 @@ load_app_mods(#app{mods = Mods} = App, Mand, PathFlag, Variables) -> %% Mod. by mbj %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -sort_apps(Apps) -> +sort_apps(Apps) -> sort_apps(Apps, [], [], []). -sort_apps([#app{name = Name, info = Info} = App | Apps], Missing, Circular, Visited) -> - {Uses, Apps1, NotFnd1} = find_all(Name, Info#app_info.applications, Apps, Visited, [], []), - {Incs, Apps2, NotFnd2} = find_all(Name, lists:reverse(Info#app_info.incl_apps), - Apps1, Visited, [], []), - +sort_apps([#app{name = Name, info = Info} = App | Apps], + Missing, + Circular, + Visited) -> + {Uses, Apps1, NotFnd1} = + find_all(Name, Info#app_info.applications, Apps, Visited, [], []), + {Incs, Apps2, NotFnd2} = + find_all(Name, + lists:reverse(Info#app_info.incl_apps), + Apps1, + Visited, + [], + []), + Missing1 = NotFnd1 ++ NotFnd2 ++ Missing, case Uses ++ Incs of - [] -> + [] -> %% No more app that must be started before this one is %% found; they are all already taken care of (and present %% in Visited list) @@ -401,8 +425,8 @@ sort_apps([#app{name = Name, info = Info} = App | Apps], Missing, Circular, Visi %% Check if we have already taken care of some app in L, %% in that case we have a circular dependency. NewCircular = [N1 || N1 <- L, N2 <- Visited, N1 =:= N2], - Circular1 = case NewCircular of - [] -> Circular; + Circular1 = case NewCircular of + [] -> Circular; _ -> [Name | NewCircular] ++ Circular end, %% L must be started before N, try again, with all apps @@ -414,9 +438,11 @@ sort_apps([], [], [], _) -> []; sort_apps([], Missing, [], _) -> %% this has already been checked before, but as we have the info... - reltool_utils:throw_error("Undefined applications: ~p\n", [make_set(Missing)]); + reltool_utils:throw_error("Undefined applications: ~p\n", + [make_set(Missing)]); sort_apps([], [], Circular, _) -> - reltool_utils:throw_error("Circular dependencies: ~p\n", [make_set(Circular)]); + reltool_utils:throw_error("Circular dependencies: ~p\n", + [make_set(Circular)]); sort_apps([], Missing, Circular, _) -> reltool_utils:throw_error("Circular dependencies: ~p\n" "Undefined applications: ~p\n", @@ -431,24 +457,49 @@ find_all(CheckingApp, [Name | Names], Apps, Visited, Found, NotFound) -> true -> case lists:member(Name, Visited) of true -> - find_all(CheckingApp, Names, Apps, Visited, Found, NotFound); + find_all(CheckingApp, + Names, + Apps, + Visited, + Found, + NotFound); false -> - find_all(CheckingApp, Names, Apps, Visited, Found, [Name | NotFound]) + find_all(CheckingApp, + Names, + Apps, + Visited, + Found, + [Name | NotFound]) end; false -> - find_all(CheckingApp, Names, Apps -- [App], Visited, [App|Found], NotFound) + find_all(CheckingApp, + Names, + Apps -- [App], + Visited, + [App|Found], + NotFound) end; false -> case lists:member(Name, Visited) of true -> - find_all(CheckingApp, Names, Apps, Visited, Found, NotFound); + find_all(CheckingApp, + Names, + Apps, + Visited, + Found, + NotFound); false -> - find_all(CheckingApp, Names, Apps, Visited, Found, [Name|NotFound]) + find_all(CheckingApp, + Names, + Apps, + Visited, + Found, + [Name|NotFound]) end end; find_all(_CheckingApp, [], Apps, _Visited, Found, NotFound) -> {Found, Apps, NotFound}. - + del_apps([Name | Names], Apps) -> del_apps(Names, lists:keydelete(Name, #app.name, Apps)); del_apps([], Apps) -> @@ -470,7 +521,9 @@ create_path(Apps, PathFlag, Variables) -> %% (The otp_build flag is only used for OTP internal system make) cr_path(#app{label = Label}, true, []) -> filename:join(["$ROOT", "lib", Label, "ebin"]); -cr_path(#app{name = Name, vsn = Vsn, label = Label, active_dir = Dir}, true, Variables) -> +cr_path(#app{name = Name, vsn = Vsn, label = Label, active_dir = Dir}, + true, + Variables) -> Tail = [Label, "ebin"], case variable_dir(Dir, atom_to_list(Name), Vsn, Variables) of {ok, VarDir} -> @@ -542,7 +595,7 @@ gen_rel_files(Sys, TargetDir) -> try Spec = spec_rel_files(Sys), eval_spec(Spec, Sys#sys.root_dir, TargetDir) - catch + catch throw:{error, Text} -> {error, Text} end. @@ -579,15 +632,15 @@ gen_target(Sys, TargetDir) -> try Spec = do_gen_spec(Sys), eval_spec(Spec, Sys#sys.root_dir, TargetDir) - catch + catch throw:{error, Text} -> {error, Text} end. - + gen_spec(Sys) -> try {ok, do_gen_spec(Sys)} - catch + catch throw:{error, Text} -> {error, Text} end. @@ -598,14 +651,16 @@ do_gen_spec(#sys{root_dir = RootDir, relocatable = Relocatable, apps = Apps} = Sys) -> {create_dir, _, SysFiles} = spec_dir(RootDir), - {ExclRegexps2, SysFiles2} = strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps), + {ExclRegexps2, SysFiles2} = + strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps), RelFiles = spec_rel_files(Sys), - {InclRegexps2, BinFiles} = spec_bin_files(Sys, SysFiles, SysFiles2, RelFiles, InclRegexps), + {InclRegexps2, BinFiles} = + spec_bin_files(Sys, SysFiles, SysFiles2, RelFiles, InclRegexps), LibFiles = spec_lib_files(Sys), {BootVsn, StartFile} = spec_start_file(Sys), SysFiles3 = [ - {create_dir, "releases", + {create_dir, "releases", [StartFile, {create_dir,BootVsn, RelFiles}]}, {create_dir, "bin", BinFiles} @@ -621,14 +676,15 @@ strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps) -> ExclRegexps2 = case Relocatable of true -> - ExtraExcl = ["^erts.*/bin/.*src$"], - reltool_utils:decode_regexps(excl_sys_filters, {add, ExtraExcl}, ExclRegexps); + ExtraExcl = ["^erts.*/bin/.*src\$"], + reltool_utils:decode_regexps(excl_sys_filters, + {add, ExtraExcl}, ExclRegexps); false -> ExclRegexps end, {value, Erts} = lists:keysearch(erts, #app.name, Apps), FilterErts = - fun(Spec) -> + fun(Spec) -> File = element(2, Spec), case lists:prefix("erts", File) of true -> @@ -636,7 +692,7 @@ strip_sys_files(Relocatable, SysFiles, Apps, ExclRegexps) -> File =:= Erts#app.label -> replace_dyn_erl(Relocatable, Spec); true -> - false + false end; false -> true @@ -660,7 +716,11 @@ replace_dyn_erl(true, {create_dir, ErtsDir, ErtsFiles}) -> [{copy_file, ErlIni}] -> %% Remove Windows .ini file BinFiles2 = lists:keydelete(ErlIni, 2, BinFiles), - ErtsFiles2 = lists:keyreplace("bin", 2, ErtsFiles, {create_dir, "bin", BinFiles2}), + ErtsFiles2 = + lists:keyreplace("bin", + 2, + ErtsFiles, + {create_dir, "bin", BinFiles2}), {true, {create_dir, ErtsDir, ErtsFiles2}} end; [{copy_file, DynErlExe}] -> @@ -668,33 +728,42 @@ replace_dyn_erl(true, {create_dir, ErtsDir, ErtsFiles}) -> ErlExe = "erl" ++ filename:extension(DynErlExe), BinFiles2 = lists:keydelete(DynErlExe, 2, BinFiles), DynErlExe2 = filename:join([ErtsDir, "bin", DynErlExe]), - BinFiles3 = lists:keyreplace(ErlExe, 2, BinFiles2, {copy_file, ErlExe, DynErlExe2}), - ErtsFiles2 = lists:keyreplace("bin", 2, ErtsFiles, {create_dir, "bin", BinFiles3}), + BinFiles3 = lists:keyreplace(ErlExe, + 2, + BinFiles2, + {copy_file, ErlExe, DynErlExe2}), + ErtsFiles2 = lists:keyreplace("bin", + 2, + ErtsFiles, + {create_dir, "bin", BinFiles3}), {true, {create_dir, ErtsDir, ErtsFiles2}} end. spec_bin_files(Sys, AllSysFiles, StrippedSysFiles, RelFiles, InclRegexps) -> - [{create_dir, ErtsLabel, ErtsFiles}] = safe_lookup_spec("erts", StrippedSysFiles), + [{create_dir, ErtsLabel, ErtsFiles}] = + safe_lookup_spec("erts", StrippedSysFiles), [{create_dir, _, BinFiles}] = safe_lookup_spec("bin", ErtsFiles), ErtsBin = filename:join([ErtsLabel, "bin"]), Escripts = spec_escripts(Sys, ErtsBin, BinFiles), Map = fun({copy_file, File}) -> {copy_file, File, filename:join([ErtsBin, File])}; ({copy_file, NewFile, OldFile}) -> - {_, OldFile2} = abs_to_rel_path(ErtsBin, filename:join([ErtsBin, OldFile])), + {_, OldFile2} = + abs_to_rel_path(ErtsBin, + filename:join([ErtsBin, OldFile])), {copy_file, NewFile, OldFile2} end, %% Do only copy those bin files from erts/bin that also exists in bin [{create_dir, _, OldBinFiles}] = safe_lookup_spec("bin", AllSysFiles), GoodNames = [F || {copy_file, F} <- OldBinFiles, - not lists:suffix(".boot", F), + not lists:suffix(".boot", F), not lists:suffix(".script", F)], BinFiles2 = [Map(S) || S <- BinFiles, lists:member(element(2, S), GoodNames)], BootFiles = [F || F <- RelFiles, lists:suffix(".boot", element(2, F))], [{write_file, _, BootRel}] = safe_lookup_spec(Sys#sys.boot_rel ++ ".boot", BootFiles), BootFiles2 = lists:keystore("start.boot", 2, BootFiles, {write_file, "start.boot", BootRel}), - MakeRegexp = fun(File) -> "^bin/" ++ element(2, File) ++ "(|.escript)$" end, + MakeRegexp = fun(File) -> "^bin/" ++ element(2, File) ++ "(|.escript)\$" end, ExtraIncl = lists:map(MakeRegexp, Escripts), InclRegexps2 = reltool_utils:decode_regexps(incl_sys_filters, {add, ExtraIncl}, InclRegexps), {InclRegexps2, Escripts ++ BinFiles2 ++ BootFiles2}. @@ -722,7 +791,7 @@ do_spec_escript(File, ErtsBin, BinFiles) -> ExeExt = filename:extension(EscriptExe), [{copy_file, Base ++ EscriptExt, File}, {copy_file, Base ++ ExeExt, filename:join([ErtsBin, EscriptExe])}]. - + check_sys(Mandatory, SysFiles) -> lists:foreach(fun(M) -> do_check_sys(M, SysFiles) end, Mandatory). @@ -730,7 +799,8 @@ do_check_sys(Prefix, Specs) -> %%io:format("Prefix: ~p\n", [Prefix]), case lookup_spec(Prefix, Specs) of [] -> - reltool_utils:throw_error("Mandatory system directory ~s is not included", + reltool_utils:throw_error("Mandatory system directory ~s " + "is not included", [Prefix]); _ -> ok @@ -750,7 +820,8 @@ lookup_spec(Prefix, Specs) -> safe_lookup_spec(Prefix, Specs) -> case lookup_spec(Prefix, Specs) of [] -> - reltool_utils:throw_error("Mandatory system file ~s is not included", [Prefix]); + reltool_utils:throw_error("Mandatory system file ~s is " + "not included", [Prefix]); Match -> Match end. @@ -780,7 +851,8 @@ spec_lib_files(#sys{apps = Apps} = Sys) -> check_apps([Mandatory | Names], Apps) -> case lists:keymember(Mandatory, #app.name, Apps) of false -> - reltool_utils:throw_error("Mandatory application ~p is not included in ~p", + reltool_utils:throw_error("Mandatory application ~p is " + "not included in ~p", [Mandatory, Apps]); true -> check_apps(Names, Apps) @@ -804,8 +876,12 @@ spec_app(#app{name = Name, EbinDir = filename:join([SourceDir, "ebin"]), OptAppUpFileSpec = spec_opt_copy_file(EbinDir, AppUpFilename), OptAppFileSpec = spec_app_file(App, Sys, EbinDir), - ModSpecs = [spec_mod(M, SysDebugInfo) || M <- Mods, M#mod.is_included, M#mod.exists], - NewEbin = {create_dir, "ebin", OptAppUpFileSpec ++ OptAppFileSpec ++ ModSpecs}, + ModSpecs = [spec_mod(M, SysDebugInfo) || M <- Mods, + M#mod.is_included, + M#mod.exists], + NewEbin = {create_dir, + "ebin", + OptAppUpFileSpec ++ OptAppFileSpec ++ ModSpecs}, AppFiles2 = lists:keystore("ebin", 2, AppFiles, NewEbin), %% Apply file filter @@ -826,24 +902,32 @@ spec_archive(#app{label = Label, excl_archive_filters = SysExclArchiveDirs, archive_opts = SysArchiveOpts}, Files) -> - InclArchiveDirs = reltool_utils:default_val(AppInclArchiveDirs, SysInclArchiveDirs), - ExclArchiveDirs = reltool_utils:default_val(AppExclArchiveDirs, SysExclArchiveDirs), - ArchiveOpts = reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts), + InclArchiveDirs = + reltool_utils:default_val(AppInclArchiveDirs, SysInclArchiveDirs), + ExclArchiveDirs = + reltool_utils:default_val(AppExclArchiveDirs, SysExclArchiveDirs), + ArchiveOpts = + reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts), Match = fun(F) -> match(element(2, F), InclArchiveDirs, ExclArchiveDirs) end, case lists:filter(Match, Files) of [] -> %% Nothing to archive [spec_create_dir(RootDir, SourceDir, Label, Files)]; ArchiveFiles -> - OptDir = + OptDir = case Files -- ArchiveFiles of [] -> []; ExternalFiles -> - [spec_create_dir(RootDir, SourceDir, Label, ExternalFiles)] + [spec_create_dir(RootDir, + SourceDir, + Label, + ExternalFiles)] end, - ArchiveOpts = reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts), - ArchiveDir = spec_create_dir(RootDir, SourceDir, Label, ArchiveFiles), + ArchiveOpts = + reltool_utils:default_val(AppArchiveOpts, SysArchiveOpts), + ArchiveDir = + spec_create_dir(RootDir, SourceDir, Label, ArchiveFiles), [{archive, Label ++ ".ez", ArchiveOpts, [ArchiveDir]} | OptDir] end. @@ -854,7 +938,9 @@ spec_dir(Dir) -> case erl_prim_loader:list_dir(Dir) of {ok, Files} -> %% Directory - {create_dir, Base, [spec_dir(filename:join([Dir, F])) || F <- Files]}; + {create_dir, + Base, + [spec_dir(filename:join([Dir, F])) || F <- Files]}; error -> reltool_utils:throw_error("list dir ~s failed\n", [Dir]) end; @@ -895,7 +981,7 @@ spec_app_file(#app{name = Name, App2 = App#app{info = Info#app_info{modules = ModNames}}, Contents = gen_app(App2), AppIoList = io_lib:format("%% app generated at ~w ~w\n~p.\n\n", - [date(), time(), Contents]), + [date(), time(), Contents]), [{write_file, AppFilename, AppIoList}]; all -> %% Include all included modules @@ -904,13 +990,14 @@ spec_app_file(#app{name = Name, App2 = App#app{info = Info#app_info{modules = ModNames}}, Contents = gen_app(App2), AppIoList = io_lib:format("%% app generated at ~w ~w\n~p.\n\n", - [date(), time(), Contents]), + [date(), time(), Contents]), [{write_file, AppFilename, AppIoList}] - + end. spec_opt_copy_file(DirName, BaseName) -> - case filelib:is_regular(filename:join([DirName, BaseName]), erl_prim_loader) of + case filelib:is_regular(filename:join([DirName, BaseName]), + erl_prim_loader) of true -> [{copy_file, BaseName}]; false -> [] end. @@ -949,14 +1036,17 @@ eval_spec(Spec, SourceDir, TargetDir) -> false -> {error, TargetDir2 ++ ": " ++ file:format_error(enoent)} end - catch + catch throw:{error, Text} -> cleanup_spec(Spec, TargetDir2), {error, Text} end. do_eval_spec(List, OrigSourceDir, SourceDir, TargetDir) when is_list(List) -> - lists:foreach(fun(F) -> do_eval_spec(F, OrigSourceDir, SourceDir, TargetDir) end, List); + lists:foreach(fun(F) -> + do_eval_spec(F, OrigSourceDir, SourceDir, TargetDir) + end, + List); %% do_eval_spec({source_dir, SourceDir2, Spec}, OrigSourceDir, _SourceDir, TargetDir) -> %% %% Source dir is absolute or relative the original source dir %% SourceDir3 = filename:join([OrigSourceDir, SourceDir2]), @@ -966,12 +1056,18 @@ do_eval_spec({create_dir, Dir, Files}, OrigSourceDir, SourceDir, TargetDir) -> TargetDir2 = filename:join([TargetDir, Dir]), reltool_utils:create_dir(TargetDir2), do_eval_spec(Files, OrigSourceDir, SourceDir2, TargetDir2); -do_eval_spec({create_dir, Dir, OldDir, Files}, OrigSourceDir, _SourceDir, TargetDir) -> +do_eval_spec({create_dir, Dir, OldDir, Files}, + OrigSourceDir, + _SourceDir, + TargetDir) -> SourceDir2 = filename:join([OrigSourceDir, OldDir]), TargetDir2 = filename:join([TargetDir, Dir]), reltool_utils:create_dir(TargetDir2), do_eval_spec(Files, SourceDir2, SourceDir2, TargetDir2); -do_eval_spec({archive, Archive, Options, Files}, OrigSourceDir, SourceDir, TargetDir) -> +do_eval_spec({archive, Archive, Options, Files}, + OrigSourceDir, + SourceDir, + TargetDir) -> TmpSpec = {create_dir, "tmp", Files}, TmpDir = filename:join([TargetDir, "tmp"]), reltool_utils:create_dir(TmpDir), @@ -986,17 +1082,24 @@ do_eval_spec({archive, Archive, Options, Files}, OrigSourceDir, SourceDir, Targe {ok, _} -> ok; {error, Reason} -> - reltool_utils:throw_error("create archive ~s: ~p\n", [ArchiveFile, Reason]) + reltool_utils:throw_error("create archive ~s: ~p\n", + [ArchiveFile, Reason]) end; do_eval_spec({copy_file, File}, _OrigSourceDir, SourceDir, TargetDir) -> SourceFile = filename:join([SourceDir, File]), TargetFile = filename:join([TargetDir, File]), reltool_utils:copy_file(SourceFile, TargetFile); -do_eval_spec({copy_file, File, OldFile}, OrigSourceDir, _SourceDir, TargetDir) -> +do_eval_spec({copy_file, File, OldFile}, + OrigSourceDir, + _SourceDir, + TargetDir) -> SourceFile = filename:join([OrigSourceDir, OldFile]), TargetFile = filename:join([TargetDir, File]), reltool_utils:copy_file(SourceFile, TargetFile); -do_eval_spec({write_file, File, IoList}, _OrigSourceDir, _SourceDir, TargetDir) -> +do_eval_spec({write_file, File, IoList}, + _OrigSourceDir, + _SourceDir, + TargetDir) -> TargetFile = filename:join([TargetDir, File]), reltool_utils:write_file(TargetFile, IoList); do_eval_spec({strip_beam, File}, _OrigSourceDir, SourceDir, TargetDir) -> @@ -1039,9 +1142,12 @@ cleanup_spec({strip_beam, File}, TargetDir) -> filter_spec(List, InclRegexps, ExclRegexps) -> do_filter_spec("", List, InclRegexps, ExclRegexps). - + do_filter_spec(Path, List, InclRegexps, ExclRegexps) when is_list(List) -> - lists:zf(fun(File) -> do_filter_spec(Path, File, InclRegexps, ExclRegexps) end, List); + lists:zf(fun(File) -> + do_filter_spec(Path, File, InclRegexps, ExclRegexps) + end, + List); %% do_filter_spec(Path, {source_dir, _SourceDir, Spec}, InclRegexps, ExclRegexps) -> %% do_filter_spec(Path, Spec, InclRegexps, ExclRegexps); do_filter_spec(Path, {create_dir, Dir, Files}, InclRegexps, ExclRegexps) -> @@ -1057,7 +1163,10 @@ do_filter_spec(Path, {create_dir, Dir, Files}, InclRegexps, ExclRegexps) -> Files2 when is_list(Files2) -> {true, {create_dir, Dir, Files2}} end; -do_filter_spec(Path, {create_dir, NewDir, OldDir, Files}, InclRegexps, ExclRegexps) -> +do_filter_spec(Path, + {create_dir, NewDir, OldDir, Files}, + InclRegexps, + ExclRegexps) -> Path2 = opt_join(Path, NewDir), case do_filter_spec(Path2, Files, InclRegexps, ExclRegexps) of [] -> @@ -1070,7 +1179,10 @@ do_filter_spec(Path, {create_dir, NewDir, OldDir, Files}, InclRegexps, ExclRegex Files2 when is_list(Files2) -> {true, {create_dir, NewDir, OldDir, Files2}} end; -do_filter_spec(Path, {archive, Archive, Options, Files}, InclRegexps, ExclRegexps) -> +do_filter_spec(Path, + {archive, Archive, Options, Files}, + InclRegexps, + ExclRegexps) -> case do_filter_spec(Path, Files, InclRegexps, ExclRegexps) of [] -> case match(Path, InclRegexps, ExclRegexps) of @@ -1085,7 +1197,10 @@ do_filter_spec(Path, {archive, Archive, Options, Files}, InclRegexps, ExclRegexp do_filter_spec(Path, {copy_file, File}, InclRegexps, ExclRegexps) -> Path2 = opt_join(Path, File), match(Path2, InclRegexps, ExclRegexps); -do_filter_spec(Path, {copy_file, NewFile, _OldFile}, InclRegexps, ExclRegexps) -> +do_filter_spec(Path, + {copy_file, NewFile, _OldFile}, + InclRegexps, + ExclRegexps) -> Path2 = opt_join(Path, NewFile), match(Path2, InclRegexps, ExclRegexps); do_filter_spec(Path, {write_file, File, _IoList}, InclRegexps, ExclRegexps) -> @@ -1101,7 +1216,7 @@ opt_join(Path, File) -> filename:join([Path, File]). match(String, InclRegexps, ExclRegexps) -> - %%case + %%case match(String, InclRegexps) andalso not match(String, ExclRegexps). %% of %% true -> @@ -1109,7 +1224,7 @@ match(String, InclRegexps, ExclRegexps) -> %% false -> %% io:format("no match: ~p\n" %% " incl: ~p\n" -%% " excl: ~p\n", +%% " excl: ~p\n", %% [String, InclRegexps, ExclRegexps]), %% false %% end. @@ -1131,7 +1246,7 @@ match(String, [#regexp{source = _, compiled = MP} | Regexps]) -> install(RelName, TargetDir) -> try do_install(RelName, TargetDir) - catch + catch throw:{error, Text} -> {error, Text} end. @@ -1148,7 +1263,8 @@ do_install(RelName, TargetDir) -> case os:type() of {win32, _} -> NativeRootDir = filename:nativename(TargetDir2), - %% NativeBinDir = filename:nativename(filename:join([BinDir, "win32"])), + %% NativeBinDir = + %% filename:nativename(filename:join([BinDir, "win32"])), NativeBinDir = filename:nativename(BinDir), IniData = ["[erlang]\r\n", "Bindir=", NativeBinDir, "\r\n", @@ -1157,8 +1273,11 @@ do_install(RelName, TargetDir) -> IniFile = filename:join([BinDir, "erl.ini"]), ok = file:write_file(IniFile, IniData); _ -> - subst_src_scripts(start_scripts(), ErtsBinDir, BinDir, - [{"FINAL_ROOTDIR", TargetDir2}, {"EMU", "beam"}], + subst_src_scripts(start_scripts(), + ErtsBinDir, + BinDir, + [{"FINAL_ROOTDIR", TargetDir2}, + {"EMU", "beam"}], [preserve]) end, RelFile = filename:join([RelDir, RelVsn, RelName ++ ".rel"]), @@ -1169,13 +1288,15 @@ do_install(RelName, TargetDir) -> end. subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> - Fun = fun(Script) -> subst_src_script(Script, SrcDir, DestDir, Vars, Opts) end, + Fun = fun(Script) -> + subst_src_script(Script, SrcDir, DestDir, Vars, Opts) + end, lists:foreach(Fun, Scripts). -subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> +subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> subst_file(filename:join([SrcDir, Script ++ ".src"]), filename:join([DestDir, Script]), - Vars, + Vars, Opts). subst_file(Src, Dest, Vars, Opts) -> diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl index 4de98317b5..906f1570c3 100644 --- a/lib/reltool/src/reltool_utils.erl +++ b/lib/reltool/src/reltool_utils.erl @@ -30,11 +30,11 @@ root_dir() -> erl_libs() -> case os:getenv("ERL_LIBS") of - false -> + false -> []; LibStr -> string:tokens(LibStr, ":;") - end. + end. lib_dirs(Dir) -> case erl_prim_loader:list_dir(Dir) of @@ -42,7 +42,7 @@ lib_dirs(Dir) -> [F || F <- Files, filelib:is_dir(filename:join([Dir, F]), erl_prim_loader)]; - error -> + error -> [] end. @@ -55,7 +55,7 @@ split_app_name(Name) -> Elem >= $0, Elem =< $9 -> true; true -> false end - end, + end, case lists:splitwith(Pred, lists:reverse(Name)) of {Vsn, [$- | App]} -> {list_to_atom(lists:reverse(App)), lists:reverse(Vsn)}; @@ -119,7 +119,7 @@ default_rels() -> assign_image_list(ListCtrl) -> Art = wxImageList:new(16,16), - [wxImageList:add(Art, wxArtProvider:getBitmap(Image, [{size, {16,16}}])) + [wxImageList:add(Art, wxArtProvider:getBitmap(Image, [{size, {16,16}}])) || Image <- ["wxART_ERROR", "wxART_WARNING", "wxART_QUESTION", @@ -206,7 +206,7 @@ split_app_dir(Dir) -> ParentDir = filename:dirname(Dir), Base = filename:basename(Dir), {Name, Vsn} = split_app_name(Base), - Vsn2 = + Vsn2 = try [list_to_integer(N) || N <- string:tokens(Vsn, ".")] catch @@ -276,7 +276,9 @@ get_selected_items(ListCtrl, PrevItem, Acc) -> ItemNo -> case wxListCtrl:getItemText(ListCtrl, ItemNo) of Text when Text =/= ?MISSING_APP_TEXT -> - get_selected_items(ListCtrl, ItemNo, [{ItemNo, Text} | Acc]); + get_selected_items(ListCtrl, + ItemNo, + [{ItemNo, Text} | Acc]); _Text -> get_selected_items(ListCtrl, ItemNo, Acc) end @@ -306,7 +308,8 @@ select_items(ListCtrl, OldItems, NewItems) -> select_item(ListCtrl, NewItems); ValidItems -> %% Some old selections are still valid. Select them again. - lists:foreach(fun(Item) -> select_item(ListCtrl, [Item]) end, ValidItems) + lists:foreach(fun(Item) -> select_item(ListCtrl, [Item]) end, + ValidItems) end. select_item(ListCtrl, [{ItemNo, Text} | Items]) -> @@ -339,7 +342,7 @@ print(_, _, _, _) -> ok. %% -define(SAFE(M,F,A), safe(M, F, A, ?MODULE, ?LINE)). -%% +%% %% safe(M, F, A, Mod, Line) -> %% case catch apply(M, F, A) of %% {'EXIT', Reason} -> @@ -356,7 +359,7 @@ return_first_error(Status, NewError) when is_list(NewError) -> {error, OldError} -> {error, OldError} end. - + add_warning(Status, Warning) -> case Status of {ok, Warnings} -> @@ -429,7 +432,8 @@ recursive_delete(Dir) -> true -> case file:list_dir(Dir) of {ok, Files} -> - Fun = fun(F) -> recursive_delete(filename:join([Dir, F])) end, + Fun = + fun(F) -> recursive_delete(filename:join([Dir, F])) end, lists:foreach(Fun, Files), delete(Dir, directory); {error, enoent} -> @@ -514,7 +518,9 @@ decode_regexps(Key, Regexps, _Old) when is_list(Regexps) -> do_decode_regexps(Key, [Regexp | Regexps], Acc) -> case catch re:compile(Regexp, []) of {ok, MP} -> - do_decode_regexps(Key, Regexps, [#regexp{source = Regexp, compiled = MP} | Acc]); + do_decode_regexps(Key, + Regexps, + [#regexp{source = Regexp, compiled = MP} | Acc]); _ -> Text = lists:flatten(io_lib:format("~p", [{Key, Regexp}])), throw({error, "Illegal option: " ++ Text}) -- cgit v1.2.3