Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

247 строки
9.6 KiB

13 лет назад
13 лет назад
14 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
13 лет назад
  1. %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
  2. %% ex: ts=4 sw=4 et
  3. %% -------------------------------------------------------------------
  4. %%
  5. %% rebar: Erlang Build Tools
  6. %%
  7. %% Copyright (c) 2011 Joe Williams (joe@joetify.com)
  8. %%
  9. %% Permission is hereby granted, free of charge, to any person obtaining a copy
  10. %% of this software and associated documentation files (the "Software"), to deal
  11. %% in the Software without restriction, including without limitation the rights
  12. %% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. %% copies of the Software, and to permit persons to whom the Software is
  14. %% furnished to do so, subject to the following conditions:
  15. %%
  16. %% The above copyright notice and this permission notice shall be included in
  17. %% all copies or substantial portions of the Software.
  18. %%
  19. %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. %% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. %% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. %% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. %% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. %% THE SOFTWARE.
  26. %% -------------------------------------------------------------------
  27. -module(rebar_upgrade).
  28. -include("rebar.hrl").
  29. -include_lib("kernel/include/file.hrl").
  30. -export(['generate-upgrade'/2]).
  31. -define(TMP, "_tmp").
  32. %% ====================================================================
  33. %% Public API
  34. %% ====================================================================
  35. 'generate-upgrade'(Config0, ReltoolFile) ->
  36. %% Get the old release path
  37. {Config, ReltoolConfig} = rebar_rel_utils:load_config(Config0, ReltoolFile),
  38. TargetParentDir = rebar_rel_utils:get_target_parent_dir(Config,
  39. ReltoolConfig),
  40. TargetDir = rebar_rel_utils:get_target_dir(Config, ReltoolConfig),
  41. PrevRelPath = rebar_rel_utils:get_previous_release_path(Config),
  42. OldVerPath = filename:join([TargetParentDir, PrevRelPath]),
  43. %% Run checks to make sure that building a package is possible
  44. {NewVerPath, NewName, NewVer} = run_checks(Config, OldVerPath,
  45. ReltoolConfig),
  46. NameVer = NewName ++ "_" ++ NewVer,
  47. %% Save the code path prior to doing anything
  48. OrigPath = code:get_path(),
  49. %% Prepare the environment for building the package
  50. ok = setup(OldVerPath, NewVerPath, NewName, NewVer, NameVer),
  51. %% Build the package
  52. run_systools(NameVer, NewName),
  53. %% Boot file changes
  54. {ok, _} = boot_files(TargetDir, NewVer, NewName),
  55. %% Extract upgrade and tar it back up with changes
  56. make_tar(NameVer, NewVer, NewName),
  57. %% Clean up files that systools created
  58. ok = cleanup(NameVer),
  59. %% Restore original path
  60. true = code:set_path(OrigPath),
  61. {ok, Config}.
  62. %% ===================================================================
  63. %% Internal functions
  64. %% ==================================================================
  65. run_checks(Config, OldVerPath, ReltoolConfig) ->
  66. true = rebar_utils:prop_check(filelib:is_dir(OldVerPath),
  67. "Release directory doesn't exist (~p)~n",
  68. [OldVerPath]),
  69. {Name, Ver} = rebar_rel_utils:get_reltool_release_info(ReltoolConfig),
  70. NewVerPath =
  71. filename:join(
  72. [rebar_rel_utils:get_target_parent_dir(Config, ReltoolConfig),
  73. Name]),
  74. true = rebar_utils:prop_check(filelib:is_dir(NewVerPath),
  75. "Release directory doesn't exist (~p)~n",
  76. [NewVerPath]),
  77. {NewName, NewVer} = rebar_rel_utils:get_rel_release_info(Name, NewVerPath),
  78. {OldName, OldVer} = rebar_rel_utils:get_rel_release_info(Name, OldVerPath),
  79. true =
  80. rebar_utils:prop_check(NewName == OldName,
  81. "New and old .rel release names do not match~n",
  82. []),
  83. true =
  84. rebar_utils:prop_check(Name == NewName,
  85. "Reltool and .rel release names do not match~n",
  86. []),
  87. true =
  88. rebar_utils:prop_check(NewVer =/= OldVer,
  89. "New and old .rel contain the same version~n",
  90. []),
  91. true =
  92. rebar_utils:prop_check(Ver == NewVer,
  93. "Reltool and .rel versions do not match~n", []),
  94. {NewVerPath, NewName, NewVer}.
  95. setup(OldVerPath, NewVerPath, NewName, NewVer, NameVer) ->
  96. Src = filename:join([NewVerPath, "releases",
  97. NewVer, NewName ++ ".rel"]),
  98. Dst = filename:join([".", NameVer ++ ".rel"]),
  99. {ok, _} = file:copy(Src, Dst),
  100. ok = code:add_pathsa(
  101. lists:append([
  102. filelib:wildcard(filename:join([NewVerPath,
  103. "lib", "*", "ebin"])),
  104. filelib:wildcard(filename:join([OldVerPath,
  105. "releases", "*"])),
  106. filelib:wildcard(filename:join([OldVerPath,
  107. "lib", "*", "ebin"]))
  108. ])).
  109. run_systools(NewVer, Name) ->
  110. Opts = [silent],
  111. NameList = [Name],
  112. case systools:make_relup(NewVer, NameList, NameList, Opts) of
  113. {error, _, Msg} ->
  114. ?ABORT("Systools [systools:make_relup/4] aborted with: ~p~n",
  115. [Msg]);
  116. _ ->
  117. ?DEBUG("Relup created~n", []),
  118. case systools:make_script(NewVer, Opts) of
  119. {error, _, Msg1} ->
  120. ?ABORT("Systools [systools:make_script/2] "
  121. "aborted with: ~p~n", [Msg1]);
  122. _ ->
  123. ?DEBUG("Script created~n", []),
  124. case systools:make_tar(NewVer, Opts) of
  125. {error, _, Msg2} ->
  126. ?ABORT("Systools [systools:make_tar/2] "
  127. "aborted with: ~p~n", [Msg2]);
  128. _ ->
  129. ?DEBUG("Tarball created~n", []),
  130. ok
  131. end
  132. end
  133. end.
  134. boot_files(TargetDir, Ver, Name) ->
  135. ok = file:make_dir(filename:join([".", ?TMP])),
  136. ok = file:make_dir(filename:join([".", ?TMP, "releases"])),
  137. ok = file:make_dir(filename:join([".", ?TMP, "releases", Ver])),
  138. case os:type() of
  139. {win32,_} ->
  140. ok;
  141. _ ->
  142. ok = file:make_symlink(
  143. filename:join(["start.boot"]),
  144. filename:join([".", ?TMP, "releases", Ver, Name ++ ".boot"]))
  145. end,
  146. {ok, _} =
  147. file:copy(
  148. filename:join([TargetDir, "releases", Ver, "start_clean.boot"]),
  149. filename:join([".", ?TMP, "releases", Ver, "start_clean.boot"])),
  150. {ok, _} = file:copy(
  151. filename:join([TargetDir, "releases", Ver, "sys.config"]),
  152. filename:join([".", ?TMP, "releases", Ver, "sys.config"])),
  153. {ok, _} = file:copy(
  154. filename:join([TargetDir, "releases", Ver, "vm.args"]),
  155. filename:join([".", ?TMP, "releases", Ver, "vm.args"])).
  156. make_tar(NameVer, NewVer, NewName) ->
  157. Filename = NameVer ++ ".tar.gz",
  158. {ok, Cwd} = file:get_cwd(),
  159. Absname = filename:join([Cwd, Filename]),
  160. ok = file:set_cwd(?TMP),
  161. ok = erl_tar:extract(Absname, [compressed]),
  162. ok = file:delete(Absname),
  163. case os:type() of
  164. {win32,_} ->
  165. {ok, _} =
  166. file:copy(
  167. filename:join([".", "releases", NewVer, "start.boot"]),
  168. filename:join([".", "releases", NewVer, NewName ++ ".boot"])),
  169. ok;
  170. _ ->
  171. ok
  172. end,
  173. {ok, Tar} = erl_tar:open(Absname, [write, compressed]),
  174. ok = erl_tar:add(Tar, "lib", []),
  175. ok = erl_tar:add(Tar, "releases", []),
  176. ok = erl_tar:close(Tar),
  177. ok = file:set_cwd(Cwd),
  178. ?CONSOLE("~s upgrade package created~n", [NameVer]).
  179. cleanup(NameVer) ->
  180. ?DEBUG("Removing files needed for building the upgrade~n", []),
  181. Files = [
  182. filename:join([".", NameVer ++ ".rel"]),
  183. filename:join([".", NameVer ++ ".boot"]),
  184. filename:join([".", NameVer ++ ".script"]),
  185. filename:join([".", "relup"])
  186. ],
  187. lists:foreach(fun(F) -> ok = file:delete(F) end, Files),
  188. ok = remove_dir_tree(?TMP).
  189. %% adapted from http://www.erlang.org/doc/system_principles/create_target.html
  190. remove_dir_tree(Dir) ->
  191. remove_all_files(".", [Dir]).
  192. remove_all_files(Dir, Files) ->
  193. lists:foreach(fun(File) ->
  194. FilePath = filename:join([Dir, File]),
  195. {ok, FileInfo, Link} = file_info(FilePath),
  196. case {Link, FileInfo#file_info.type} of
  197. {false, directory} ->
  198. {ok, DirFiles} = file:list_dir(FilePath),
  199. remove_all_files(FilePath, DirFiles),
  200. file:del_dir(FilePath);
  201. _ ->
  202. file:delete(FilePath)
  203. end
  204. end, Files).
  205. file_info(Path) ->
  206. case file:read_file_info(Path) of
  207. {ok, Info} ->
  208. {ok, Info, false};
  209. {error, enoent} ->
  210. {ok, Info} = file:read_link_info(Path),
  211. {ok, Info, true};
  212. Error ->
  213. Error
  214. end.