No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

725 líneas
26 KiB

hace 10 años
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
hace 6 años
hace 10 años
hace 10 años
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
hace 6 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
hace 10 años
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
hace 6 años
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
hace 6 años
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
hace 6 años
hace 10 años
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
hace 6 años
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
hace 6 años
hace 10 años
hace 10 años
hace 10 años
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
hace 6 años
hace 10 años
hace 10 años
hace 10 años
  1. -module(rebar_app_info).
  2. -export([new/0,
  3. new/1,
  4. new/2,
  5. new/3,
  6. new/4,
  7. new/5,
  8. app_to_map/1,
  9. update_opts/3,
  10. update_opts/2,
  11. update_opts_deps/2,
  12. discover/1,
  13. name/1,
  14. name/2,
  15. app_file_src/1,
  16. app_file_src/2,
  17. app_file_src_script/1,
  18. app_file_src_script/2,
  19. app_file/1,
  20. app_file/2,
  21. app_details/1,
  22. app_details/2,
  23. parent/1,
  24. parent/2,
  25. original_vsn/1,
  26. original_vsn/2,
  27. vsn/1,
  28. vsn/2,
  29. priv_dir/1,
  30. applications/1,
  31. applications/2,
  32. included_applications/1,
  33. included_applications/2,
  34. profiles/1,
  35. profiles/2,
  36. deps/1,
  37. deps/2,
  38. dep_level/1,
  39. dep_level/2,
  40. fetch_dir/1,
  41. fetch_dir/2,
  42. dir/1,
  43. dir/2,
  44. out_dir/1,
  45. out_dir/2,
  46. ebin_dir/1,
  47. ebin_dir/2,
  48. default/1,
  49. default/2,
  50. opts/1,
  51. opts/2,
  52. get/2,
  53. get/3,
  54. set/3,
  55. source/1,
  56. source/2,
  57. project_type/1,
  58. project_type/2,
  59. is_lock/1,
  60. is_lock/2,
  61. is_checkout/1,
  62. is_checkout/2,
  63. valid/1,
  64. valid/2,
  65. is_available/1,
  66. is_available/2,
  67. verify_otp_vsn/1,
  68. has_all_artifacts/1,
  69. apply_overrides/2,
  70. add_to_profile/3,
  71. apply_profiles/2,
  72. deduplicate/1,
  73. do_deduplicate/2]).
  74. -include("rebar.hrl").
  75. -include_lib("providers/include/providers.hrl").
  76. -export_type([t/0,
  77. project_type/0]).
  78. -type project_type() :: rebar3 | mix | undefined.
  79. -record(app_info_t, {name :: binary() | undefined,
  80. app_file_src :: file:filename_all() | undefined,
  81. app_file_src_script:: file:filename_all() | undefined,
  82. app_file :: file:filename_all() | undefined,
  83. original_vsn :: binary() | undefined,
  84. vsn :: binary() | undefined,
  85. parent=root :: binary() | root,
  86. app_details=[] :: list(),
  87. applications=[] :: list(),
  88. included_applications=[] :: [atom()],
  89. deps=[] :: list(),
  90. profiles=[default] :: [atom()],
  91. default=dict:new() :: rebar_dict(),
  92. opts=dict:new() :: rebar_dict(),
  93. dep_level=0 :: integer(),
  94. fetch_dir :: file:name(),
  95. dir :: file:name(),
  96. out_dir :: file:name(),
  97. ebin_dir :: file:name(),
  98. source :: string() | tuple() | checkout | undefined,
  99. is_lock=false :: boolean(),
  100. is_checkout=false :: boolean(),
  101. valid :: boolean() | undefined,
  102. project_type :: project_type(),
  103. is_available=false :: boolean()}).
  104. %%============================================================================
  105. %% types
  106. %%============================================================================
  107. -type t() :: #app_info_t{}.
  108. %%============================================================================
  109. %% API
  110. %% ============================================================================
  111. %% @doc Build a new, empty, app info value. This is not of a lot of use and you
  112. %% probably wont be doing this much.
  113. -spec new() -> t().
  114. new() ->
  115. #app_info_t{}.
  116. %% @doc Build a new app info value with only the app name set.
  117. -spec new(atom() | binary() | string()) ->
  118. {ok, t()}.
  119. new(AppName) ->
  120. {ok, #app_info_t{name=rebar_utils:to_binary(AppName)}}.
  121. %% @doc Build a new app info value with only the name and version set.
  122. -spec new(atom() | binary() | string(), binary() | string()) ->
  123. {ok, t()}.
  124. new(AppName, Vsn) ->
  125. {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
  126. vsn=Vsn,
  127. original_vsn=Vsn}}.
  128. %% @doc build a complete version of the app info with all fields set.
  129. -spec new(atom() | binary() | string(), binary() | string(), file:name()) ->
  130. {ok, t()}.
  131. new(AppName, Vsn, Dir) ->
  132. {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
  133. vsn=Vsn,
  134. original_vsn=Vsn,
  135. fetch_dir=rebar_utils:to_list(Dir),
  136. dir=rebar_utils:to_list(Dir),
  137. out_dir=rebar_utils:to_list(Dir),
  138. ebin_dir=filename:join(rebar_utils:to_list(Dir), "ebin")}}.
  139. %% @doc build a complete version of the app info with all fields set.
  140. -spec new(atom() | binary() | string(), binary() | string(), file:name(), list()) ->
  141. {ok, t()}.
  142. new(AppName, Vsn, Dir, Deps) ->
  143. {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
  144. vsn=Vsn,
  145. original_vsn=Vsn,
  146. fetch_dir=rebar_utils:to_list(Dir),
  147. dir=rebar_utils:to_list(Dir),
  148. out_dir=rebar_utils:to_list(Dir),
  149. ebin_dir=filename:join(rebar_utils:to_list(Dir), "ebin"),
  150. deps=Deps}}.
  151. %% @doc build a complete version of the app info with all fields set.
  152. -spec new(atom() | binary(), atom() | binary() | string(), binary() | string(), file:name(), list()) ->
  153. {ok, t()}.
  154. new(Parent, AppName, Vsn, Dir, Deps) ->
  155. {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
  156. parent=Parent,
  157. vsn=Vsn,
  158. original_vsn=Vsn,
  159. fetch_dir=rebar_utils:to_list(Dir),
  160. dir=rebar_utils:to_list(Dir),
  161. out_dir=rebar_utils:to_list(Dir),
  162. ebin_dir=filename:join(rebar_utils:to_list(Dir), "ebin"),
  163. deps=Deps}}.
  164. -spec app_to_map(t()) -> #{name := atom(),
  165. vsn := string(),
  166. applications := [atom()],
  167. included_applications := [atom()],
  168. dir := file:name(),
  169. out_dir := file:name(),
  170. ebin_dir := file:name(),
  171. link := boolean()}.
  172. app_to_map(#app_info_t{name=Name,
  173. vsn=Vsn,
  174. applications=Applications,
  175. included_applications=IncludedApplications,
  176. out_dir=OutDir,
  177. ebin_dir=EbinDir}) ->
  178. #{name => ec_cnv:to_atom(Name),
  179. vsn => Vsn,
  180. applications => Applications,
  181. included_applications => IncludedApplications,
  182. dir => OutDir,
  183. out_dir => OutDir,
  184. ebin_dir => EbinDir,
  185. link => false}.
  186. %% @doc update the opts based on the contents of a config
  187. %% file for the app
  188. -spec update_opts(t(), rebar_dict(), [any()]) -> t().
  189. update_opts(AppInfo, Opts, Config) ->
  190. LockDeps = case source(AppInfo) of
  191. Tuple when is_tuple(Tuple) andalso element(1, Tuple) =:= pkg ->
  192. %% Deps are set separate for packages
  193. %% instead of making it seem we have no deps
  194. %% don't set anything here.
  195. [];
  196. _ ->
  197. deps_from_config(dir(AppInfo), proplists:get_value(deps, Config, []))
  198. end,
  199. Plugins = proplists:get_value(plugins, Config, []),
  200. Terms = LockDeps++[{{plugins, default}, Plugins} | Config],
  201. true = rebar_config:verify_config_format(Terms),
  202. LocalOpts = dict:from_list(Terms),
  203. NewOpts = rebar_opts:merge_opts(LocalOpts, Opts),
  204. AppInfo#app_info_t{opts=NewOpts,
  205. default=NewOpts}.
  206. %% @doc update current app info opts by merging in a new dict of opts
  207. -spec update_opts(t(), rebar_dict()) -> t().
  208. update_opts(AppInfo=#app_info_t{opts=LocalOpts}, Opts) ->
  209. NewOpts = rebar_opts:merge_opts(LocalOpts, Opts),
  210. AppInfo#app_info_t{opts=NewOpts,
  211. default=NewOpts}.
  212. %% @doc update the opts based on new deps, usually from an app's hex registry metadata
  213. -spec update_opts_deps(t(), [any()]) -> t().
  214. update_opts_deps(AppInfo=#app_info_t{opts=Opts}, Deps) ->
  215. LocalOpts = dict:from_list([{{locks, default}, Deps}, {{deps, default}, Deps}]),
  216. NewOpts = rebar_opts:merge_opts(LocalOpts, Opts),
  217. AppInfo#app_info_t{opts=NewOpts,
  218. default=NewOpts,
  219. deps=Deps}.
  220. %% @private extract the deps for an app in `Dir' based on its config file data
  221. -spec deps_from_config(file:filename(), [any()]) -> [{tuple(), any()}, ...].
  222. deps_from_config(Dir, ConfigDeps) ->
  223. case rebar_config:consult_lock_file(filename:join(Dir, ?LOCK_FILE)) of
  224. [] ->
  225. [{{deps, default}, ConfigDeps}];
  226. D ->
  227. %% We want the top level deps only from the lock file.
  228. %% This ensures deterministic overrides for configs.
  229. Deps = [X || X <- D, element(3, X) =:= 0],
  230. [{{locks, default}, D}, {{deps, default}, Deps}]
  231. end.
  232. %% @doc discover a complete version of the app info with all fields set.
  233. -spec discover(file:filename_all()) -> {ok, t()} | not_found.
  234. discover(Dir) ->
  235. case rebar_app_discover:find_app(Dir, all) of
  236. {true, AppInfo} ->
  237. {ok, AppInfo};
  238. false ->
  239. not_found
  240. end.
  241. %% @doc get the name of the app.
  242. -spec name(t()) -> binary().
  243. name(#app_info_t{name=Name}) ->
  244. Name.
  245. %% @doc set the name of the app.
  246. -spec name(t(), atom() | binary() | string()) -> t().
  247. name(AppInfo=#app_info_t{}, AppName) ->
  248. AppInfo#app_info_t{name=rebar_utils:to_binary(AppName)}.
  249. %% @doc get the dictionary of options for the app.
  250. -spec opts(t()) -> rebar_dict().
  251. opts(#app_info_t{opts=Opts}) ->
  252. Opts.
  253. %% @doc set the dictionary of options for the app.
  254. -spec opts(t(), rebar_dict()) -> t().
  255. opts(AppInfo, Opts) ->
  256. AppInfo#app_info_t{opts=Opts}.
  257. %% @doc get the dictionary of options under the default profile.
  258. %% Represents a root set prior to applying other profiles.
  259. -spec default(t()) -> rebar_dict().
  260. default(#app_info_t{default=Default}) ->
  261. Default.
  262. %% @doc set the dictionary of options under the default profile.
  263. %% Useful when re-applying profile.
  264. -spec default(t(), rebar_dict()) -> t().
  265. default(AppInfo, Default) ->
  266. AppInfo#app_info_t{default=Default}.
  267. %% @doc look up a value in the dictionary of options; fails if
  268. %% the key for it does not exist.
  269. -spec get(t(), term()) -> term().
  270. get(AppInfo, Key) ->
  271. {ok, Value} = dict:find(Key, AppInfo#app_info_t.opts),
  272. Value.
  273. %% @doc look up a value in the dictionary of options; returns
  274. %% a `Default' value otherwise.
  275. -spec get(t(), term(), term()) -> term().
  276. get(AppInfo, Key, Default) ->
  277. case dict:find(Key, AppInfo#app_info_t.opts) of
  278. {ok, Value} ->
  279. Value;
  280. error ->
  281. Default
  282. end.
  283. %% @doc sets a given value in the dictionary of options for the app.
  284. -spec set(t(), any(), any()) -> t().
  285. set(AppInfo=#app_info_t{opts=Opts}, Key, Value) ->
  286. AppInfo#app_info_t{opts = dict:store(Key, Value, Opts)}.
  287. %% @doc finds the .app.src file for an app, if any.
  288. -spec app_file_src(t()) -> file:filename_all() | undefined.
  289. app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name, opts=Opts}) ->
  290. CandidatePaths = [filename:join([rebar_utils:to_list(Dir), Src, rebar_utils:to_list(Name)++".app.src"])
  291. || Src <- rebar_opts:get(Opts, src_dirs, ["src"])],
  292. case lists:dropwhile(fun(Path) -> not filelib:is_file(Path) end, CandidatePaths) of
  293. [] -> undefined;
  294. [AppFileSrc|_] -> AppFileSrc
  295. end;
  296. app_file_src(#app_info_t{app_file_src=AppFileSrc}) ->
  297. rebar_utils:to_list(AppFileSrc).
  298. %% @doc sets the .app.src file for an app. An app without such a file
  299. %% can explicitly be set with `undefined'.
  300. -spec app_file_src(t(), file:filename_all() | undefined) -> t().
  301. app_file_src(AppInfo=#app_info_t{}, undefined) ->
  302. AppInfo#app_info_t{app_file_src=undefined};
  303. app_file_src(AppInfo=#app_info_t{}, AppFileSrc) ->
  304. AppInfo#app_info_t{app_file_src=rebar_utils:to_list(AppFileSrc)}.
  305. %% @doc finds the .app.src.script file for an app, if any.
  306. -spec app_file_src_script(t()) -> file:filename_all() | undefined.
  307. app_file_src_script(#app_info_t{app_file_src_script=undefined, dir=Dir, name=Name}) ->
  308. AppFileSrcScript = filename:join([rebar_utils:to_list(Dir), "src", rebar_utils:to_list(Name)++".app.src.script"]),
  309. case filelib:is_file(AppFileSrcScript) of
  310. true ->
  311. AppFileSrcScript;
  312. false ->
  313. undefined
  314. end;
  315. app_file_src_script(#app_info_t{app_file_src_script=AppFileSrcScript}) ->
  316. rebar_utils:to_list(AppFileSrcScript).
  317. %% @doc sets the .app.src.script file for an app. An app without such a file
  318. %% can explicitly be set with `undefined'.
  319. -spec app_file_src_script(t(), file:filename_all()) -> t().
  320. app_file_src_script(AppInfo=#app_info_t{}, undefined) ->
  321. AppInfo#app_info_t{app_file_src_script=undefined};
  322. app_file_src_script(AppInfo=#app_info_t{}, AppFileSrcScript) ->
  323. AppInfo#app_info_t{app_file_src_script=rebar_utils:to_list(AppFileSrcScript)}.
  324. %% @doc finds the .app file for an app, if any.
  325. -spec app_file(t()) -> file:filename_all() | undefined.
  326. app_file(#app_info_t{app_file=undefined, out_dir=Dir, name=Name}) ->
  327. AppFile = filename:join([rebar_utils:to_list(Dir), "ebin", rebar_utils:to_list(Name)++".app"]),
  328. case filelib:is_file(AppFile) of
  329. true ->
  330. AppFile;
  331. false ->
  332. undefined
  333. end;
  334. app_file(#app_info_t{app_file=AppFile}) ->
  335. AppFile.
  336. %% @doc sets the .app file for an app.
  337. -spec app_file(t(), file:filename_all() | undefined) -> t().
  338. app_file(AppInfo=#app_info_t{}, AppFile) ->
  339. AppInfo#app_info_t{app_file=AppFile}.
  340. %% @doc returns the information stored in the app's app file,
  341. %% or if none, from the .app.src file.
  342. -spec app_details(t()) -> list().
  343. app_details(AppInfo=#app_info_t{app_details=[]}) ->
  344. case app_file(AppInfo) of
  345. undefined ->
  346. try rebar_config:consult_app_file(app_file_src(AppInfo)) of
  347. [] -> [];
  348. [{application, _Name, AppDetails}] -> AppDetails
  349. catch
  350. _:_ ->
  351. []
  352. end;
  353. AppFile ->
  354. try rebar_file_utils:try_consult(AppFile) of
  355. [] -> [];
  356. [{application, _Name, AppDetails}] -> AppDetails
  357. catch
  358. throw:{error, {Module, Reason}} ->
  359. ?DEBUG("Warning, falling back to .app.src because of: ~ts",
  360. [Module:format_error(Reason)]),
  361. case rebar_config:consult_app_file(app_file_src(AppInfo)) of
  362. [] -> [];
  363. [{application, _Name, AppDetails}] -> AppDetails
  364. end
  365. end
  366. end;
  367. app_details(#app_info_t{app_details=AppDetails}) ->
  368. AppDetails.
  369. %% @doc stores the information that would be returned from the
  370. %% app file, when reading from `app_details/1'.
  371. -spec app_details(t(), list()) -> t().
  372. app_details(AppInfo=#app_info_t{}, AppDetails) ->
  373. AppInfo#app_info_t{app_details=AppDetails}.
  374. %% @doc returns the app's parent in the dep tree.
  375. -spec parent(t()) -> root | binary().
  376. parent(#app_info_t{parent=Parent}) ->
  377. Parent.
  378. %% @doc sets the app's parent.
  379. -spec parent(t(), binary() | root) -> t().
  380. parent(AppInfo=#app_info_t{}, Parent) ->
  381. AppInfo#app_info_t{parent=Parent}.
  382. %% @doc returns the original version of the app (unevaluated if
  383. %% asking for a semver)
  384. -spec original_vsn(t()) -> binary().
  385. original_vsn(#app_info_t{original_vsn=Vsn}) ->
  386. Vsn.
  387. %% @doc stores the original version of the app (unevaluated if
  388. %% asking for a semver)
  389. -spec original_vsn(t(), binary() | string()) -> t().
  390. original_vsn(AppInfo=#app_info_t{}, Vsn) ->
  391. AppInfo#app_info_t{original_vsn=Vsn}.
  392. %% @doc returns the version of the app after evaluation
  393. -spec vsn(t()) -> binary().
  394. vsn(#app_info_t{vsn=Vsn}) ->
  395. Vsn.
  396. %% @doc sets the evaluated vsn of the app
  397. -spec vsn(t(), binary() | string()) -> t().
  398. vsn(AppInfo=#app_info_t{}, Vsn) ->
  399. AppInfo#app_info_t{vsn=Vsn}.
  400. %% @doc returns the list of applications the app depends on.
  401. -spec applications(t()) -> list().
  402. applications(#app_info_t{applications=Applications}) ->
  403. Applications.
  404. %% @doc sets the list of applications the app depends on.
  405. %% Should be obtained from the app file.
  406. -spec applications(t(), list()) -> t().
  407. applications(AppInfo=#app_info_t{}, Applications) ->
  408. AppInfo#app_info_t{applications=Applications}.
  409. %% @doc returns the list of included_applications the app depends on.
  410. -spec included_applications(t()) -> list().
  411. included_applications(#app_info_t{included_applications=Applications}) ->
  412. Applications.
  413. %% @doc sets the list of applications the app depends on.
  414. %% Should be obtained from the app file.
  415. -spec included_applications(t(), list()) -> t().
  416. included_applications(AppInfo=#app_info_t{}, Applications) ->
  417. AppInfo#app_info_t{included_applications=Applications}.
  418. %% @doc returns the list of active profiles
  419. -spec profiles(t()) -> list().
  420. profiles(#app_info_t{profiles=Profiles}) ->
  421. Profiles.
  422. %% @doc sets the list of active profiles
  423. -spec profiles(t(), list()) -> t().
  424. profiles(AppInfo=#app_info_t{}, Profiles) ->
  425. AppInfo#app_info_t{profiles=Profiles}.
  426. %% @doc returns the list of dependencies
  427. -spec deps(t()) -> list().
  428. deps(#app_info_t{deps=Deps}) ->
  429. Deps.
  430. %% @doc sets the list of dependencies.
  431. -spec deps(t(), list()) -> t().
  432. deps(AppInfo=#app_info_t{}, Deps) ->
  433. AppInfo#app_info_t{deps=Deps}.
  434. %% @doc returns the level the app has in the lock files or in the
  435. %% dep tree.
  436. -spec dep_level(t()) -> non_neg_integer().
  437. dep_level(#app_info_t{dep_level=Level}) ->
  438. Level.
  439. %% @doc sets the level the app has in the lock files or in the
  440. %% dep tree.
  441. -spec dep_level(t(), non_neg_integer()) -> t().
  442. dep_level(AppInfo=#app_info_t{}, Level) ->
  443. AppInfo#app_info_t{dep_level=Level}.
  444. %% @doc returns the directory to fetch the dep source to
  445. -spec fetch_dir(t()) -> file:name().
  446. fetch_dir(#app_info_t{fetch_dir=FetchDir}) ->
  447. FetchDir.
  448. %% @doc returns the directory to fetch the dep source to
  449. -spec fetch_dir(t(), file:name()) -> file:name().
  450. fetch_dir(AppInfo=#app_info_t{}, FetchDir) ->
  451. AppInfo#app_info_t{fetch_dir=FetchDir}.
  452. %% @doc returns the directory that contains the app.
  453. -spec dir(t()) -> file:name().
  454. dir(#app_info_t{dir=Dir}) ->
  455. Dir.
  456. %% @doc sets the directory that contains the app.
  457. -spec dir(t(), file:name()) -> t().
  458. dir(AppInfo=#app_info_t{out_dir=undefined}, Dir) ->
  459. AppInfo#app_info_t{dir=rebar_utils:to_list(Dir),
  460. out_dir=rebar_utils:to_list(Dir)};
  461. dir(AppInfo=#app_info_t{}, Dir) ->
  462. AppInfo#app_info_t{dir=rebar_utils:to_list(Dir)}.
  463. %% @doc returns the directory where build artifacts for the app
  464. %% should go
  465. -spec out_dir(t()) -> file:name().
  466. out_dir(#app_info_t{out_dir=OutDir}) ->
  467. OutDir.
  468. %% @doc sets the directory where build artifacts for the app
  469. %% should go
  470. -spec out_dir(t(), file:name()) -> t().
  471. out_dir(AppInfo=#app_info_t{}, OutDir) ->
  472. AppInfo#app_info_t{out_dir=rebar_utils:to_list(OutDir),
  473. ebin_dir=filename:join(rebar_utils:to_list(OutDir), "ebin")}.
  474. %% @doc gets the directory where ebin files for the app should go
  475. -spec ebin_dir(t()) -> file:name().
  476. ebin_dir(#app_info_t{ebin_dir=undefined,
  477. out_dir=OutDir}) ->
  478. filename:join(rebar_utils:to_list(OutDir), "ebin");
  479. ebin_dir(#app_info_t{ebin_dir=EbinDir}) ->
  480. EbinDir.
  481. %% @doc sets the directory where beam files should go
  482. -spec ebin_dir(t(), file:name()) -> t().
  483. ebin_dir(AppInfo, EbinDir) ->
  484. AppInfo#app_info_t{ebin_dir=EbinDir}.
  485. %% @doc gets the directory where private files for the app should go
  486. -spec priv_dir(t()) -> file:name().
  487. priv_dir(#app_info_t{out_dir=OutDir}) ->
  488. rebar_utils:to_list(filename:join(OutDir, "priv")).
  489. %% @doc finds the source specification for the app
  490. -spec source(t()) -> string() | tuple().
  491. source(#app_info_t{source=Source}) ->
  492. Source.
  493. %% @doc sets the source specification for the app
  494. -spec source(t(), string() | tuple() | checkout) -> t().
  495. source(AppInfo=#app_info_t{}, Source) ->
  496. AppInfo#app_info_t{source=Source}.
  497. %% @doc returns the lock status for the app
  498. -spec is_lock(t()) -> boolean().
  499. is_lock(#app_info_t{is_lock=IsLock}) ->
  500. IsLock.
  501. %% @doc sets the lock status for the app
  502. -spec is_lock(t(), boolean()) -> t().
  503. is_lock(AppInfo=#app_info_t{}, IsLock) ->
  504. AppInfo#app_info_t{is_lock=IsLock}.
  505. %% @doc returns whether the app is a checkout app or not
  506. -spec is_checkout(t()) -> boolean().
  507. is_checkout(#app_info_t{is_checkout=IsCheckout}) ->
  508. IsCheckout.
  509. %% @doc sets whether the app is a checkout app or not
  510. -spec is_checkout(t(), boolean()) -> t().
  511. is_checkout(AppInfo=#app_info_t{}, IsCheckout) ->
  512. AppInfo#app_info_t{is_checkout=IsCheckout}.
  513. %% @doc returns whether the app source exists in the deps dir
  514. -spec is_available(t()) -> boolean().
  515. is_available(#app_info_t{is_available=IsAvailable}) ->
  516. IsAvailable.
  517. %% @doc sets whether the app's source is available
  518. %% only set if the app's source is found in the expected dep directory
  519. -spec is_available(t(), boolean()) -> t().
  520. is_available(AppInfo=#app_info_t{}, IsAvailable) ->
  521. AppInfo#app_info_t{is_available=IsAvailable}.
  522. %% @doc
  523. -spec project_type(t()) -> atom().
  524. project_type(#app_info_t{project_type=ProjectType}) ->
  525. ProjectType.
  526. %% @doc
  527. -spec project_type(t(), atom()) -> t().
  528. project_type(AppInfo=#app_info_t{}, ProjectType) ->
  529. AppInfo#app_info_t{project_type=ProjectType}.
  530. %% @doc returns whether the app is valid (built) or not
  531. -spec valid(t()) -> boolean().
  532. valid(AppInfo=#app_info_t{valid=undefined}) ->
  533. case rebar_app_utils:validate_application_info(AppInfo) =:= true
  534. andalso has_all_artifacts(AppInfo) =:= true of
  535. true ->
  536. true;
  537. _ ->
  538. false
  539. end;
  540. valid(#app_info_t{valid=Valid}) ->
  541. Valid.
  542. %% @doc sets whether the app is valid (built) or not. If left unset,
  543. %% rebar3 will do the detection of the status itself.
  544. -spec valid(t(), boolean()) -> t().
  545. valid(AppInfo=#app_info_t{}, Valid) ->
  546. AppInfo#app_info_t{valid=Valid}.
  547. %% @doc checks whether the app can be built with the current
  548. %% Erlang/OTP version. If the check fails, the function raises
  549. %% an exception and displays an error.
  550. -spec verify_otp_vsn(t()) -> ok | no_return().
  551. verify_otp_vsn(AppInfo) ->
  552. rebar_utils:check_min_otp_version(rebar_app_info:get(AppInfo, minimum_otp_vsn, undefined)),
  553. rebar_utils:check_blacklisted_otp_versions(rebar_app_info:get(AppInfo, blacklisted_otp_vsns, [])).
  554. %% @doc checks whether all the build artifacts for an app to be considered
  555. %% valid are present.
  556. -spec has_all_artifacts(#app_info_t{}) -> true | {false, file:filename()}.
  557. has_all_artifacts(AppInfo) ->
  558. Artifacts = rebar_app_info:get(AppInfo, artifacts, []),
  559. OutDir = out_dir(AppInfo),
  560. Context = [{base_dir, rebar_app_info:get(AppInfo, base_dir, ?DEFAULT_BASE_DIR)}
  561. ,{profile_dir, rebar_dir:profile_dir(opts(AppInfo), profiles(AppInfo))}
  562. ,{out_dir, OutDir}],
  563. all(OutDir, Context, Artifacts).
  564. %% @private checks that all files/artifacts in the directory are found.
  565. %% Template evaluation must happen and a bbmustache context needs to
  566. %% be provided.
  567. -spec all(file:filename(), term(), [string()]) -> true | {false, string()}.
  568. all(_, _, []) ->
  569. true;
  570. all(Dir, Context, [File|Artifacts]) ->
  571. FilePath = filename:join(Dir, rebar_templater:render(File, Context)),
  572. case filelib:is_regular(FilePath) of
  573. false ->
  574. ?DEBUG("Missing artifact ~ts", [FilePath]),
  575. {false, File};
  576. true ->
  577. all(Dir, Context, Artifacts)
  578. end.
  579. %%%%%
  580. %% @doc given a set of override rules, modify the app info accordingly
  581. -spec apply_overrides(list(), t()) -> t().
  582. apply_overrides(Overrides, AppInfo) ->
  583. Name = binary_to_atom(rebar_app_info:name(AppInfo), utf8),
  584. Opts = rebar_opts:apply_overrides(opts(AppInfo), Name, Overrides),
  585. AppInfo#app_info_t{default=Opts, opts=Opts}.
  586. %% @doc adds a new profile with its own config to the app data
  587. -spec add_to_profile(t(), atom(), [{_,_}]) -> t().
  588. add_to_profile(AppInfo, Profile, KVs) when is_atom(Profile), is_list(KVs) ->
  589. Opts = rebar_opts:add_to_profile(opts(AppInfo), Profile, KVs),
  590. AppInfo#app_info_t{opts=Opts}.
  591. %% @doc applies and merges the profile configuration in the specified order
  592. %% of profiles (or for a single profile) and returns an app info record
  593. %% with the resulting configuration
  594. -spec apply_profiles(t(), atom() | [atom(),...]) -> t().
  595. apply_profiles(AppInfo, Profile) when not is_list(Profile) ->
  596. apply_profiles(AppInfo, [Profile]);
  597. apply_profiles(AppInfo, [default]) ->
  598. AppInfo;
  599. apply_profiles(AppInfo=#app_info_t{default = Defaults, profiles=CurrentProfiles}, Profiles) ->
  600. AppliedProfiles = case Profiles of
  601. %% Head of list global profile is special, only for use by rebar3
  602. %% It does not clash if a user does `rebar3 as global...` but when
  603. %% it is the head we must make sure not to prepend `default`
  604. [global | _] ->
  605. Profiles;
  606. _ ->
  607. deduplicate(CurrentProfiles ++ Profiles)
  608. end,
  609. ConfigProfiles = rebar_app_info:get(AppInfo, profiles, []),
  610. NewOpts =
  611. lists:foldl(fun(default, OptsAcc) ->
  612. OptsAcc;
  613. (Profile, OptsAcc) ->
  614. case proplists:get_value(Profile, ConfigProfiles, []) of
  615. OptsList when is_list(OptsList) ->
  616. ProfileOpts = dict:from_list(OptsList),
  617. rebar_opts:merge_opts(Profile, ProfileOpts, OptsAcc);
  618. Other ->
  619. throw(?PRV_ERROR({profile_not_list, Profile, Other}))
  620. end
  621. end, Defaults, AppliedProfiles),
  622. AppInfo#app_info_t{profiles = AppliedProfiles, opts=NewOpts}.
  623. %% @private drops duplicated profile definitions
  624. -spec deduplicate(list()) -> list().
  625. deduplicate(Profiles) ->
  626. do_deduplicate(lists:reverse(Profiles), []).
  627. %% @private drops duplicated profile definitions
  628. -spec do_deduplicate(list(), list()) -> list().
  629. do_deduplicate([], Acc) ->
  630. Acc;
  631. do_deduplicate([Head | Rest], Acc) ->
  632. case lists:member(Head, Acc) of
  633. true -> do_deduplicate(Rest, Acc);
  634. false -> do_deduplicate(Rest, [Head | Acc])
  635. end.