1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2011-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20%module 21-module(target_system). 22-export([create/1, create/2, install/2]). 23 24%% Note: RelFileName below is the *stem* without trailing .rel, 25%% .script etc. 26%% 27 28%% create(RelFileName) 29%% 30create(RelFileName) -> 31 create(RelFileName,[]). 32 33create(RelFileName,SystoolsOpts) -> 34 RelFile = RelFileName ++ ".rel", 35 Dir = filename:dirname(RelFileName), 36 PlainRelFileName = filename:join(Dir,"plain"), 37 PlainRelFile = PlainRelFileName ++ ".rel", 38 io:fwrite("Reading file: ~tp ...~n", [RelFile]), 39 {ok, [RelSpec]} = file:consult(RelFile), 40 io:fwrite("Creating file: ~tp from ~tp ...~n", 41 [PlainRelFile, RelFile]), 42 {release, 43 {RelName, RelVsn}, 44 {erts, ErtsVsn}, 45 AppVsns} = RelSpec, 46 PlainRelSpec = {release, 47 {RelName, RelVsn}, 48 {erts, ErtsVsn}, 49 lists:filter(fun({kernel, _}) -> 50 true; 51 ({stdlib, _}) -> 52 true; 53 (_) -> 54 false 55 end, AppVsns) 56 }, 57 {ok, Fd} = file:open(PlainRelFile, [write]), 58 io:fwrite(Fd, "~p.~n", [PlainRelSpec]), 59 file:close(Fd), 60 61 io:fwrite("Making \"~ts.script\" and \"~ts.boot\" files ...~n", 62 [PlainRelFileName,PlainRelFileName]), 63 make_script(PlainRelFileName,SystoolsOpts), 64 65 io:fwrite("Making \"~ts.script\" and \"~ts.boot\" files ...~n", 66 [RelFileName, RelFileName]), 67 make_script(RelFileName,SystoolsOpts), 68 69 TarFileName = RelFileName ++ ".tar.gz", 70 io:fwrite("Creating tar file ~tp ...~n", [TarFileName]), 71 make_tar(RelFileName,SystoolsOpts), 72 73 TmpDir = filename:join(Dir,"tmp"), 74 io:fwrite("Creating directory ~tp ...~n",[TmpDir]), 75 file:make_dir(TmpDir), 76 77 io:fwrite("Extracting ~tp into directory ~tp ...~n", [TarFileName,TmpDir]), 78 extract_tar(TarFileName, TmpDir), 79 80 TmpBinDir = filename:join([TmpDir, "bin"]), 81 ErtsBinDir = filename:join([TmpDir, "erts-" ++ ErtsVsn, "bin"]), 82 io:fwrite("Deleting \"erl\" and \"start\" in directory ~tp ...~n", 83 [ErtsBinDir]), 84 file:delete(filename:join([ErtsBinDir, "erl"])), 85 file:delete(filename:join([ErtsBinDir, "start"])), 86 87 io:fwrite("Creating temporary directory ~tp ...~n", [TmpBinDir]), 88 file:make_dir(TmpBinDir), 89 90 io:fwrite("Copying file \"~ts.boot\" to ~tp ...~n", 91 [PlainRelFileName, filename:join([TmpBinDir, "start.boot"])]), 92 copy_file(PlainRelFileName++".boot",filename:join([TmpBinDir, "start.boot"])), 93 94 io:fwrite("Copying files \"epmd\", \"run_erl\" and \"to_erl\" from \n" 95 "~tp to ~tp ...~n", 96 [ErtsBinDir, TmpBinDir]), 97 copy_file(filename:join([ErtsBinDir, "epmd"]), 98 filename:join([TmpBinDir, "epmd"]), [preserve]), 99 copy_file(filename:join([ErtsBinDir, "run_erl"]), 100 filename:join([TmpBinDir, "run_erl"]), [preserve]), 101 copy_file(filename:join([ErtsBinDir, "to_erl"]), 102 filename:join([TmpBinDir, "to_erl"]), [preserve]), 103 104 %% This is needed if 'start' script created from 'start.src' shall 105 %% be used as it points out this directory as log dir for 'run_erl' 106 TmpLogDir = filename:join([TmpDir, "log"]), 107 io:fwrite("Creating temporary directory ~tp ...~n", [TmpLogDir]), 108 ok = file:make_dir(TmpLogDir), 109 110 StartErlDataFile = filename:join([TmpDir, "releases", "start_erl.data"]), 111 io:fwrite("Creating ~tp ...~n", [StartErlDataFile]), 112 StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]), 113 write_file(StartErlDataFile, StartErlData), 114 115 io:fwrite("Recreating tar file ~tp from contents in directory ~tp ...~n", 116 [TarFileName,TmpDir]), 117 {ok, Tar} = erl_tar:open(TarFileName, [write, compressed]), 118 %% {ok, Cwd} = file:get_cwd(), 119 %% file:set_cwd("tmp"), 120 ErtsDir = "erts-"++ErtsVsn, 121 erl_tar:add(Tar, filename:join(TmpDir,"bin"), "bin", []), 122 erl_tar:add(Tar, filename:join(TmpDir,ErtsDir), ErtsDir, []), 123 erl_tar:add(Tar, filename:join(TmpDir,"releases"), "releases", []), 124 erl_tar:add(Tar, filename:join(TmpDir,"lib"), "lib", []), 125 erl_tar:add(Tar, filename:join(TmpDir,"log"), "log", []), 126 erl_tar:close(Tar), 127 %% file:set_cwd(Cwd), 128 io:fwrite("Removing directory ~tp ...~n",[TmpDir]), 129 remove_dir_tree(TmpDir), 130 ok. 131 132 133install(RelFileName, RootDir) -> 134 TarFile = RelFileName ++ ".tar.gz", 135 io:fwrite("Extracting ~tp ...~n", [TarFile]), 136 extract_tar(TarFile, RootDir), 137 StartErlDataFile = filename:join([RootDir, "releases", "start_erl.data"]), 138 {ok, StartErlData} = read_txt_file(StartErlDataFile), 139 [ErlVsn, _RelVsn| _] = string:tokens(StartErlData, " \n"), 140 ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]), 141 BinDir = filename:join([RootDir, "bin"]), 142 io:fwrite("Substituting in erl.src, start.src and start_erl.src to " 143 "form erl, start and start_erl ...\n"), 144 subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir, 145 [{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}], 146 [preserve]), 147 %%! Workaround for pre OTP 17.0: start.src and start_erl.src did 148 %%! not have correct permissions, so the above 'preserve' option did not help 149 ok = file:change_mode(filename:join(BinDir,"start"),8#0755), 150 ok = file:change_mode(filename:join(BinDir,"start_erl"),8#0755), 151 152 io:fwrite("Creating the RELEASES file ...\n"), 153 create_RELEASES(RootDir, filename:join([RootDir, "releases", 154 filename:basename(RelFileName)])). 155 156%% LOCALS 157 158%% make_script(RelFileName,Opts) 159%% 160make_script(RelFileName,Opts) -> 161 systools:make_script(RelFileName, [no_module_tests, 162 {outdir,filename:dirname(RelFileName)} 163 |Opts]). 164 165%% make_tar(RelFileName,Opts) 166%% 167make_tar(RelFileName,Opts) -> 168 RootDir = code:root_dir(), 169 systools:make_tar(RelFileName, [{erts, RootDir}, 170 {outdir,filename:dirname(RelFileName)} 171 |Opts]). 172 173%% extract_tar(TarFile, DestDir) 174%% 175extract_tar(TarFile, DestDir) -> 176 erl_tar:extract(TarFile, [{cwd, DestDir}, compressed]). 177 178create_RELEASES(DestDir, RelFileName) -> 179 release_handler:create_RELEASES(DestDir, RelFileName ++ ".rel"). 180 181subst_src_scripts(Scripts, SrcDir, DestDir, Vars, Opts) -> 182 lists:foreach(fun(Script) -> 183 subst_src_script(Script, SrcDir, DestDir, 184 Vars, Opts) 185 end, Scripts). 186 187subst_src_script(Script, SrcDir, DestDir, Vars, Opts) -> 188 subst_file(filename:join([SrcDir, Script ++ ".src"]), 189 filename:join([DestDir, Script]), 190 Vars, Opts). 191 192subst_file(Src, Dest, Vars, Opts) -> 193 {ok, Conts} = read_txt_file(Src), 194 NConts = subst(Conts, Vars), 195 write_file(Dest, NConts), 196 case lists:member(preserve, Opts) of 197 true -> 198 {ok, FileInfo} = file:read_file_info(Src), 199 file:write_file_info(Dest, FileInfo); 200 false -> 201 ok 202 end. 203 204%% subst(Str, Vars) 205%% Vars = [{Var, Val}] 206%% Var = Val = string() 207%% Substitute all occurrences of %Var% for Val in Str, using the list 208%% of variables in Vars. 209%% 210subst(Str, Vars) -> 211 subst(Str, Vars, []). 212 213subst([$%, C| Rest], Vars, Result) when $A =< C, C =< $Z -> 214 subst_var([C| Rest], Vars, Result, []); 215subst([$%, C| Rest], Vars, Result) when $a =< C, C =< $z -> 216 subst_var([C| Rest], Vars, Result, []); 217subst([$%, C| Rest], Vars, Result) when C == $_ -> 218 subst_var([C| Rest], Vars, Result, []); 219subst([C| Rest], Vars, Result) -> 220 subst(Rest, Vars, [C| Result]); 221subst([], _Vars, Result) -> 222 lists:reverse(Result). 223 224subst_var([$%| Rest], Vars, Result, VarAcc) -> 225 Key = lists:reverse(VarAcc), 226 case lists:keysearch(Key, 1, Vars) of 227 {value, {Key, Value}} -> 228 subst(Rest, Vars, lists:reverse(Value, Result)); 229 false -> 230 subst(Rest, Vars, [$%| VarAcc ++ [$%| Result]]) 231 end; 232subst_var([C| Rest], Vars, Result, VarAcc) -> 233 subst_var(Rest, Vars, Result, [C| VarAcc]); 234subst_var([], Vars, Result, VarAcc) -> 235 subst([], Vars, [VarAcc ++ [$%| Result]]). 236 237copy_file(Src, Dest) -> 238 copy_file(Src, Dest, []). 239 240copy_file(Src, Dest, Opts) -> 241 {ok,_} = file:copy(Src, Dest), 242 case lists:member(preserve, Opts) of 243 true -> 244 {ok, FileInfo} = file:read_file_info(Src), 245 file:write_file_info(Dest, FileInfo); 246 false -> 247 ok 248 end. 249 250write_file(FName, Conts) -> 251 Enc = file:native_name_encoding(), 252 {ok, Fd} = file:open(FName, [write]), 253 file:write(Fd, unicode:characters_to_binary(Conts,Enc,Enc)), 254 file:close(Fd). 255 256read_txt_file(File) -> 257 {ok, Bin} = file:read_file(File), 258 {ok, binary_to_list(Bin)}. 259 260remove_dir_tree(Dir) -> 261 remove_all_files(".", [Dir]). 262 263remove_all_files(Dir, Files) -> 264 lists:foreach(fun(File) -> 265 FilePath = filename:join([Dir, File]), 266 case filelib:is_dir(FilePath) of 267 true -> 268 {ok, DirFiles} = file:list_dir(FilePath), 269 remove_all_files(FilePath, DirFiles), 270 file:del_dir(FilePath); 271 _ -> 272 file:delete(FilePath) 273 end 274 end, Files). 275%module 276