Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

365 righe
16 KiB

15 anni fa
15 anni fa
14 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message
6 anni fa
  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) 2009 Dave Smith (dizzyd@dizzyd.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_app_utils).
  28. -export([find/2,
  29. find/3,
  30. is_app_src/1,
  31. app_src_to_app/2,
  32. validate_application_info/1,
  33. validate_application_info/2,
  34. parse_deps/5,
  35. parse_deps/6,
  36. parse_dep/6,
  37. expand_deps_sources/2,
  38. dep_to_app/7,
  39. lint_app_info/1,
  40. format_error/1]).
  41. -include("rebar.hrl").
  42. -include_lib("providers/include/providers.hrl").
  43. %% ===================================================================
  44. %% Public API
  45. %% ===================================================================
  46. %% @doc finds the proper app info record for a given app name in a list of
  47. %% such records.
  48. -spec find(binary(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
  49. find(Name, Apps) ->
  50. ec_lists:find(fun(App) -> rebar_app_info:name(App) =:= Name end, Apps).
  51. %% @doc finds the proper app info record for a given app name at a given version
  52. %% in a list of such records.
  53. -spec find(binary(), binary(), [rebar_app_info:t()]) -> {ok, rebar_app_info:t()} | error.
  54. find(Name, Vsn, Apps) ->
  55. ec_lists:find(fun(App) ->
  56. rebar_app_info:name(App) =:= Name
  57. andalso rebar_app_info:original_vsn(App) =:= Vsn
  58. end, Apps).
  59. %% @doc checks if a given file is .app.src file
  60. is_app_src(Filename) ->
  61. %% If removing the extension .app.src yields a shorter name,
  62. %% this is an .app.src file.
  63. Filename =/= filename:rootname(Filename, ".app.src").
  64. %% @doc translates the name of the .app.src[.script] file to where
  65. %% its .app counterpart should be stored.
  66. -spec app_src_to_app(OutDir, SrcFilename) -> OutFilename when
  67. OutDir :: file:filename(),
  68. SrcFilename :: file:filename(),
  69. OutFilename :: file:filename().
  70. app_src_to_app(OutDir, Filename) ->
  71. AppFile =
  72. case lists:suffix(".app.src", Filename) of
  73. true ->
  74. filename:join([OutDir, "ebin", filename:basename(Filename, ".app.src") ++ ".app"]);
  75. false ->
  76. filename:join([OutDir, "ebin", filename:basename(Filename,
  77. ".app.src.script") ++ ".app"])
  78. end,
  79. filelib:ensure_dir(AppFile),
  80. AppFile.
  81. %% @doc checks whether the .app file has all the required data to be valid,
  82. %% and cross-references it with compiled modules on disk
  83. -spec validate_application_info(rebar_app_info:t()) -> boolean().
  84. validate_application_info(AppInfo) ->
  85. validate_application_info(AppInfo, rebar_app_info:app_details(AppInfo)).
  86. %% @doc checks whether the .app file has all the required data to be valid
  87. %% and cross-references it with compiled modules on disk.
  88. %% The app info is passed explicitly as a second argument.
  89. -spec validate_application_info(rebar_app_info:t(), list()) -> boolean().
  90. validate_application_info(AppInfo, AppDetail) ->
  91. EbinDir = rebar_app_info:ebin_dir(AppInfo),
  92. case rebar_app_info:app_file(AppInfo) of
  93. undefined ->
  94. false;
  95. AppFile ->
  96. case proplists:get_value(modules, AppDetail) of
  97. undefined ->
  98. ?PRV_ERROR({module_list, AppFile});
  99. List ->
  100. has_all_beams(EbinDir, List)
  101. end
  102. end.
  103. lint_app_info(AppInfo) ->
  104. AppDetails = rebar_app_info:app_details(AppInfo),
  105. AppFile = rebar_app_info:app_file(AppInfo),
  106. lint_detail(AppDetails, AppFile).
  107. -spec lint_detail(list(), file:filename_all()) -> ok.
  108. lint_detail(AppDetail, AppFile) ->
  109. lint_description(AppDetail, AppFile),
  110. lint_applications(AppDetail, AppFile).
  111. -spec lint_description(list(), file:filename_all()) -> ok.
  112. lint_description(AppDetail, AppFile) ->
  113. case proplists:get_value(description, AppDetail, "") of
  114. "" -> ?WARN("~p is missing description entry", [AppFile]);
  115. _ -> ok
  116. end.
  117. -spec lint_applications(list(), file:filename_all()) -> ok.
  118. lint_applications(AppDetail, AppFile) ->
  119. case proplists:get_value(applications, AppDetail) of
  120. undefined -> ?WARN("~p is missing applications entry", [AppFile]);
  121. AppList when is_list(AppList) ->
  122. case lists:member(kernel, AppList) of
  123. false ->
  124. ?WARN("~p is missing kernel from applications list", [AppFile]);
  125. true -> ok
  126. end,
  127. case lists:member(stdlib, AppList) of
  128. false ->
  129. ?WARN("~p is missing stdlib from applications list", [AppFile]);
  130. true -> ok
  131. end;
  132. _ -> ?WARN("~p requires a list for applications value", [AppFile])
  133. end.
  134. %% @doc parses all dependencies from the root of the project
  135. -spec parse_deps(Dir, Deps, State, Locks, Level) -> [rebar_app_info:t()] when
  136. Dir :: file:filename(),
  137. Deps :: [tuple() | atom() | binary()], % TODO: meta to source() | lock()
  138. State :: rebar_state:t(),
  139. Locks :: [tuple()], % TODO: meta to [lock()]
  140. Level :: non_neg_integer().
  141. parse_deps(DepsDir, Deps, State, Locks, Level) ->
  142. parse_deps(root, DepsDir, Deps, State, Locks, Level).
  143. %% @doc runs `parse_dep/6' for a set of dependencies.
  144. -spec parse_deps(Parent, Dir, Deps, State, Locks, Level) -> [rebar_app_info:t()] when
  145. Parent :: root | binary(),
  146. Dir :: file:filename(),
  147. Deps :: [tuple() | atom() | binary()], % TODO: meta to source() | lock()
  148. State :: rebar_state:t(),
  149. Locks :: [tuple()], % TODO: meta to [lock()]
  150. Level :: non_neg_integer().
  151. parse_deps(Parent, DepsDir, Deps, State, Locks, Level) ->
  152. [parse_dep(Dep, Parent, DepsDir, State, Locks, Level) || Dep <- Deps].
  153. %% @doc for a given dep, return its app info record. The function
  154. %% also has to choose whether to define the dep from its immediate spec
  155. %% (if it is a newer thing) or from the locks specified in the lockfile.
  156. -spec parse_dep(Dep, Parent, Dir, State, Locks, Level) -> rebar_app_info:t() when
  157. Dep :: tuple() | atom() | binary(), % TODO: meta to source() | lock()
  158. Parent :: root | binary(),
  159. Dir :: file:filename(),
  160. State :: rebar_state:t(),
  161. Locks :: [tuple()], % TODO: meta to [lock()]
  162. Level :: non_neg_integer().
  163. parse_dep(Dep, Parent, DepsDir, State, Locks, Level) ->
  164. Name = case Dep of
  165. Dep when is_tuple(Dep) ->
  166. element(1, Dep);
  167. Dep ->
  168. Dep
  169. end,
  170. case lists:keyfind(rebar_utils:to_binary(Name), 1, Locks) of
  171. false ->
  172. parse_dep(Parent, Dep, DepsDir, false, State);
  173. LockedDep ->
  174. LockedLevel = element(3, LockedDep),
  175. case LockedLevel > Level of
  176. true ->
  177. parse_dep(Parent, Dep, DepsDir, false, State);
  178. false ->
  179. parse_dep(Parent, LockedDep, DepsDir, true, State)
  180. end
  181. end.
  182. %% @doc converts a dependency definition and a location for it on disk
  183. %% into an app info tuple representing it.
  184. -spec parse_dep(Parent, Dep, Dir, IsLock, State) -> rebar_app_info:t() when
  185. Parent :: root | binary(),
  186. Dep :: tuple() | atom() | binary(), % TODO: meta to source() | lock()
  187. Dir :: file:filename(),
  188. IsLock :: boolean(),
  189. State :: rebar_state:t().
  190. parse_dep(Parent, {Name, Vsn, {pkg, PkgName}}, DepsDir, IsLock, State) ->
  191. {PkgName1, PkgVsn} = {rebar_utils:to_binary(PkgName),
  192. rebar_utils:to_binary(Vsn)},
  193. dep_to_app(Parent, DepsDir, Name, PkgVsn, {pkg, PkgName1, PkgVsn, undefined}, IsLock, State);
  194. parse_dep(Parent, {Name, {pkg, PkgName}}, DepsDir, IsLock, State) ->
  195. %% Package dependency with different package name from app name
  196. dep_to_app(Parent, DepsDir, Name, undefined, {pkg, rebar_utils:to_binary(PkgName), undefined, undefined}, IsLock, State);
  197. parse_dep(Parent, {Name, Vsn}, DepsDir, IsLock, State) when is_list(Vsn); is_binary(Vsn) ->
  198. %% Versioned Package dependency
  199. {PkgName, PkgVsn} = {rebar_utils:to_binary(Name),
  200. rebar_utils:to_binary(Vsn)},
  201. dep_to_app(Parent, DepsDir, PkgName, PkgVsn, {pkg, PkgName, PkgVsn, undefined}, IsLock, State);
  202. parse_dep(Parent, Name, DepsDir, IsLock, State) when is_atom(Name); is_binary(Name) ->
  203. %% Unversioned package dependency
  204. dep_to_app(Parent, DepsDir, rebar_utils:to_binary(Name), undefined, {pkg, rebar_utils:to_binary(Name), undefined, undefined}, IsLock, State);
  205. parse_dep(Parent, {Name, Source}, DepsDir, IsLock, State) when is_tuple(Source) ->
  206. dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
  207. parse_dep(Parent, {Name, _Vsn, Source}, DepsDir, IsLock, State) when is_tuple(Source) ->
  208. dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
  209. parse_dep(Parent, {Name, _Vsn, Source, Opts}, DepsDir, IsLock, State) when is_tuple(Source),
  210. is_list(Opts) ->
  211. ?WARN("Dependency option list ~p in ~p is not supported and will be ignored", [Opts, Name]),
  212. dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
  213. parse_dep(Parent, {Name, Source, Opts}, DepsDir, IsLock, State) when is_tuple(Source),
  214. is_list(Opts) ->
  215. ?WARN("Dependency option list ~p in ~p is not supported and will be ignored", [Opts, Name]),
  216. dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
  217. parse_dep(Parent, {Name, {pkg, PkgName, Vsn}, Level}, DepsDir, IsLock, State) when is_integer(Level) ->
  218. dep_to_app(Parent, DepsDir, Name, Vsn, {pkg, PkgName, Vsn, undefined}, IsLock, State);
  219. parse_dep(Parent, {Name, {pkg, PkgName, Vsn, Hash}, Level}, DepsDir, IsLock, State) when is_integer(Level) ->
  220. dep_to_app(Parent, DepsDir, Name, Vsn, {pkg, PkgName, Vsn, Hash}, IsLock, State);
  221. parse_dep(Parent, {Name, Source, Level}, DepsDir, IsLock, State) when is_tuple(Source)
  222. , is_integer(Level) ->
  223. dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
  224. parse_dep(_, Dep, _, _, _) ->
  225. throw(?PRV_ERROR({parse_dep, Dep})).
  226. %% @doc convert a dependency that has just been fetched into
  227. %% an app info record related to it
  228. -spec dep_to_app(Parent, Dir, Name, Vsn, Source, IsLock, State) -> rebar_app_info:t() when
  229. Parent :: root | binary(),
  230. Dir :: file:filename(),
  231. Name :: binary(),
  232. Vsn :: iodata() | undefined,
  233. Source :: tuple(),
  234. IsLock :: boolean(),
  235. State :: rebar_state:t().
  236. dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State) ->
  237. CheckoutsDir = rebar_utils:to_list(rebar_dir:checkouts_dir(State, Name)),
  238. AppInfo = case rebar_app_info:discover(CheckoutsDir) of
  239. {ok, App} ->
  240. rebar_app_info:source(rebar_app_info:is_checkout(App, true), checkout);
  241. not_found ->
  242. Dir = rebar_utils:to_list(filename:join(DepsDir, Name)),
  243. {ok, AppInfo0} =
  244. case rebar_app_info:discover(Dir) of
  245. {ok, App} ->
  246. App1 = rebar_app_info:name(App, Name),
  247. {ok, rebar_app_info:is_available(rebar_app_info:parent(App1, Parent),
  248. true)};
  249. not_found ->
  250. rebar_app_info:new(Parent, Name, Vsn, Dir, [])
  251. end,
  252. rebar_app_info:source(AppInfo0, Source)
  253. end,
  254. Overrides = rebar_app_info:get(AppInfo, overrides, []) ++ rebar_state:get(State, overrides, []),
  255. AppInfo2 = rebar_app_info:set(AppInfo, overrides, Overrides),
  256. AppInfo5 = rebar_app_info:profiles(AppInfo2, [default]),
  257. rebar_app_info:is_lock(AppInfo5, IsLock).
  258. %% @doc Takes a given application app_info record along with the project.
  259. %% If the app is a package, resolve and expand the package definition.
  260. -spec expand_deps_sources(rebar_app_info:t(), rebar_state:t()) ->
  261. rebar_app_info:t().
  262. expand_deps_sources(Dep, State) ->
  263. update_source(Dep, rebar_app_info:source(Dep), State).
  264. %% @doc sets the source for a given dependency or app along with metadata
  265. %% around version if required.
  266. -spec update_source(rebar_app_info:t(), Source, rebar_state:t()) ->
  267. rebar_app_info:t() when
  268. Source :: rebar_resource_v2:source().
  269. update_source(AppInfo, {pkg, PkgName, PkgVsn, Hash}, State) ->
  270. case rebar_packages:resolve_version(PkgName, PkgVsn, Hash,
  271. ?PACKAGE_TABLE, State) of
  272. {ok, Package, RepoConfig} ->
  273. #package{key={_, PkgVsn1, _},
  274. checksum=Hash1,
  275. dependencies=Deps,
  276. retired=Retired} = Package,
  277. maybe_warn_retired(PkgName, PkgVsn1, Hash, Retired),
  278. PkgVsn2 = list_to_binary(lists:flatten(ec_semver:format(PkgVsn1))),
  279. AppInfo1 = rebar_app_info:source(AppInfo, {pkg, PkgName, PkgVsn2, Hash1, RepoConfig}),
  280. rebar_app_info:update_opts_deps(AppInfo1, Deps);
  281. not_found ->
  282. throw(?PRV_ERROR({missing_package, PkgName, PkgVsn}));
  283. {error, {invalid_vsn, InvalidVsn}} ->
  284. throw(?PRV_ERROR({invalid_vsn, PkgName, InvalidVsn}))
  285. end;
  286. update_source(AppInfo, Source, _State) ->
  287. rebar_app_info:source(AppInfo, Source).
  288. %% @doc convert a given exception's payload into an io description.
  289. -spec format_error(any()) -> iolist().
  290. format_error({missing_package, Name, undefined}) ->
  291. io_lib:format("Package not found in any repo: ~ts", [rebar_utils:to_binary(Name)]);
  292. format_error({missing_package, Name, Constraint}) ->
  293. io_lib:format("Package not found in any repo: ~ts ~ts", [Name, Constraint]);
  294. format_error({parse_dep, Dep}) ->
  295. io_lib:format("Failed parsing dep ~p", [Dep]);
  296. format_error({invalid_vsn, Dep, InvalidVsn}) ->
  297. io_lib:format("Dep ~ts has invalid version ~ts", [Dep, InvalidVsn]);
  298. format_error(Error) ->
  299. io_lib:format("~p", [Error]).
  300. %% ===================================================================
  301. %% Internal functions
  302. %% ===================================================================
  303. maybe_warn_retired(_, _, _, false) ->
  304. ok;
  305. maybe_warn_retired(_, _, Hash, _) when is_binary(Hash) ->
  306. %% don't warn if this is a lock
  307. ok;
  308. maybe_warn_retired(Name, Vsn, _, R=#{reason := Reason}) ->
  309. Message = maps:get(message, R, ""),
  310. ?WARN("Warning: package ~s-~s is retired: (~s) ~s",
  311. [Name, ec_semver:format(Vsn), retire_reason(Reason), Message]);
  312. maybe_warn_retired(_, _, _, _) ->
  313. ok.
  314. %% TODO: move to hex_core
  315. retire_reason('RETIRED_OTHER') ->
  316. "other";
  317. retire_reason('RETIRED_INVALID') ->
  318. "invalid";
  319. retire_reason('RETIRED_SECURITY') ->
  320. "security";
  321. retire_reason('RETIRED_DEPRECATED') ->
  322. "deprecated";
  323. retire_reason('RETIRED_RENAMED') ->
  324. "renamed";
  325. retire_reason(_Other) ->
  326. "other".
  327. %% @private checks that all the beam files have been properly
  328. %% created.
  329. -spec has_all_beams(file:filename_all(), [module()]) ->
  330. true | ?PRV_ERROR({missing_module, module()}).
  331. has_all_beams(EbinDir, [Module | ModuleList]) ->
  332. BeamFile = filename:join([EbinDir, rebar_utils:to_list(Module) ++ ".beam"]),
  333. case filelib:is_file(BeamFile) of
  334. true ->
  335. has_all_beams(EbinDir, ModuleList);
  336. false ->
  337. ?PRV_ERROR({missing_module, Module})
  338. end;
  339. has_all_beams(_, []) ->
  340. true.