Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

480 wiersze
19 KiB

Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
Properly support package aliasing and alt names Aliasing only had a bit of ad-hoc support in rebar3, and various issues have encountered problems related to the package names not mapping properly with the application name. One such issue is https://github.com/erlang/rebar3/issues/1290 The problem has been hard to find because it only impacts transitive dependencies (not top-level ones) of other packages. The root cause for this is that the application name was not being tracked by rebar3's internal index, only the package name and its version were. When a given application was a package app, the data for the application name would be reconstructed from the lock file, but only if it were a top-level app or a dependency of a source application where parsing the lock file is necessary to know what comes next. When a transitive dependency of a package dependency was fetched, we instead read its dependencies directly from the in-memory package index within rebar3. This caused us to only read the package name and version, and lost all information regarding application name. This worked fine for most cases since for the vast majority of packages, the package name matches the app name, but failed for all aliases, which would then be moved to directories that wouldn't match the app name. This in turn broke some aspects of code analysis (in Dialyzer), or other functionality relying on static paths, such as including .hrl files from dependencies. This patch reformats the internal storage format of dependencies to align with the internal one used by rebar3, so that the app name can be carried along with the package name and its version. The fix can only work once `rebar3 update` is called so the index is rebuilt internally, and will the file cached on disk will be incompatible with older rebar3 versions. Currently, the following is not covered: - Tests - Including the package hashes of dependencies so they may match what is in a lock file -- they're being `undefined` instead, which may break some lookups. The previous format did not lend itself to hashing in the same way, and it is possible transitive deps were not being tracked properly, or worked by respecting the current package hierarchy. This will require further analysis For now this commit can allow reviewing and discussion.
8 lat temu
  1. -module(rebar_deps_SUITE).
  2. -compile(export_all).
  3. -include_lib("common_test/include/ct.hrl").
  4. -include_lib("eunit/include/eunit.hrl").
  5. all() -> [sub_app_deps, newly_added_dep, newly_added_after_empty_lock,
  6. http_proxy_settings, https_proxy_settings,
  7. http_os_proxy_settings, https_os_proxy_settings,
  8. semver_matching_lt, semver_matching_lte, semver_matching_gt,
  9. valid_version, {group, git}, {group, pkg}].
  10. groups() ->
  11. [{all, [], [flat, pick_highest_left, pick_highest_right,
  12. pick_smallest1, pick_smallest2,
  13. circular1, circular2, circular_skip]},
  14. {git, [], [{group, all}]},
  15. {pkg, [], [{group, all}]}].
  16. init_per_suite(Config) ->
  17. application:start(meck),
  18. Config.
  19. end_per_suite(_Config) ->
  20. application:stop(meck).
  21. init_per_group(git, Config) ->
  22. [{deps_type, git} | Config];
  23. init_per_group(pkg, Config) ->
  24. [{deps_type, pkg} | Config];
  25. init_per_group(_, Config) ->
  26. Config.
  27. end_per_group(_, Config) ->
  28. Config.
  29. init_per_testcase(valid_version, Config) ->
  30. rebar_test_utils:init_rebar_state(Config);
  31. init_per_testcase(semver_matching_lt, Config) ->
  32. rebar_test_utils:init_rebar_state(Config);
  33. init_per_testcase(semver_matching_lte, Config) ->
  34. rebar_test_utils:init_rebar_state(Config);
  35. init_per_testcase(semver_matching_gt, Config) ->
  36. rebar_test_utils:init_rebar_state(Config);
  37. init_per_testcase(newly_added_after_empty_lock, Config) ->
  38. rebar_test_utils:init_rebar_state(Config);
  39. init_per_testcase(newly_added_dep, Config) ->
  40. rebar_test_utils:init_rebar_state(Config);
  41. init_per_testcase(sub_app_deps, Config) ->
  42. rebar_test_utils:init_rebar_state(Config);
  43. init_per_testcase(http_proxy_settings, Config) ->
  44. %% Create private rebar.config
  45. Priv = ?config(priv_dir, Config),
  46. GlobalDir = filename:join(Priv, "global"),
  47. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  48. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  49. meck:new(rebar_dir, [passthrough]),
  50. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  51. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  52. %% Insert proxy variables into config
  53. rebar_test_utils:create_config(GlobalConfigDir,
  54. [{http_proxy, "http://localhost:1234"}
  55. ]),
  56. rebar_test_utils:init_rebar_state(Config);
  57. init_per_testcase(https_proxy_settings, Config) ->
  58. SupportsHttpsProxy = case erlang:system_info(otp_release) of
  59. "R16"++_ -> true;
  60. "R"++_ -> false;
  61. _ -> true % 17 and up don't have a "R" in the version
  62. end,
  63. if not SupportsHttpsProxy ->
  64. {skip, https_proxy_unsupported_before_R16};
  65. SupportsHttpsProxy ->
  66. %% Create private rebar.config
  67. Priv = ?config(priv_dir, Config),
  68. GlobalDir = filename:join(Priv, "global"),
  69. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  70. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  71. meck:new(rebar_dir, [passthrough]),
  72. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  73. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  74. %% Insert proxy variables into config
  75. rebar_test_utils:create_config(GlobalConfigDir,
  76. [{https_proxy, "http://localhost:1234"}
  77. ]),
  78. %% Add a bad value by default to show config overtakes default
  79. os:putenv("https_proxy", "unparseable-garbage"),
  80. rebar_test_utils:init_rebar_state(Config)
  81. end;
  82. init_per_testcase(http_os_proxy_settings, Config) ->
  83. %% Create private rebar.config
  84. Priv = ?config(priv_dir, Config),
  85. GlobalDir = filename:join(Priv, "global"),
  86. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  87. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  88. meck:new(rebar_dir, [passthrough]),
  89. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  90. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  91. %% Insert proxy variables into os env, but not config
  92. os:putenv("http_proxy", "http://localhost:1234"),
  93. rebar_test_utils:create_config(GlobalConfigDir, []),
  94. rebar_test_utils:init_rebar_state(Config);
  95. init_per_testcase(https_os_proxy_settings, Config) ->
  96. SupportsHttpsProxy = case erlang:system_info(otp_release) of
  97. "R16"++_ -> true;
  98. "R"++_ -> false;
  99. _ -> true % 17 and up don't have a "R" in the version
  100. end,
  101. if not SupportsHttpsProxy ->
  102. {skip, https_proxy_unsupported_before_R16};
  103. SupportsHttpsProxy ->
  104. %% Create private rebar.config
  105. Priv = ?config(priv_dir, Config),
  106. GlobalDir = filename:join(Priv, "global"),
  107. GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
  108. GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
  109. meck:new(rebar_dir, [passthrough]),
  110. meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
  111. meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
  112. %% Insert proxy variables into os env, not in config
  113. os:putenv("https_proxy", "http://localhost:1234"),
  114. rebar_test_utils:create_config(GlobalConfigDir, []),
  115. rebar_test_utils:init_rebar_state(Config)
  116. end;
  117. init_per_testcase(Case, Config) ->
  118. {Deps, Warnings, Expect} = deps(Case),
  119. Expected = case Expect of
  120. {ok, List} -> {ok, format_expected_deps(List)};
  121. {error, Reason} -> {error, Reason}
  122. end,
  123. DepsType = ?config(deps_type, Config),
  124. mock_warnings(),
  125. [{expect, Expected},
  126. {warnings, Warnings}
  127. | setup_project(Case, Config, rebar_test_utils:expand_deps(DepsType, Deps))].
  128. end_per_testcase(https_proxy_settings, Config) ->
  129. os:putenv("https_proxy", ""),
  130. meck:unload(rebar_dir),
  131. Config;
  132. end_per_testcase(http_proxy_settings, Config) ->
  133. meck:unload(rebar_dir),
  134. Config;
  135. end_per_testcase(http_os_proxy_settings, Config) ->
  136. os:putenv("http_proxy", ""),
  137. meck:unload(rebar_dir),
  138. Config;
  139. end_per_testcase(https_os_proxy_settings, Config) ->
  140. os:putenv("https_proxy", ""),
  141. meck:unload(rebar_dir),
  142. Config;
  143. end_per_testcase(_, Config) ->
  144. meck:unload(),
  145. Config.
  146. format_expected_deps(Deps) ->
  147. [case Dep of
  148. {N,V} -> {dep, N, V};
  149. N -> {dep, N}
  150. end || Dep <- Deps].
  151. %% format:
  152. %% {Spec,
  153. %% [Warning],
  154. %% {ok, Result} | {error, Reason}}
  155. %%
  156. %% Spec is a list of levelled dependencies of two possible forms:
  157. %% - {"Name", Spec}
  158. %% - {"Name", "Vsn", Spec}
  159. %%
  160. %% Warnings are going to match on mocked ?WARN(...)
  161. %% calls to be evaluated. An empty list means we do not care about
  162. %% warnings, not that no warnings will be printed. This means
  163. %% the list of warning isn't interpreted to be exhaustive, and more
  164. %% warnings may be generated than are listed.
  165. deps(flat) ->
  166. {[{"B", []},
  167. {"C", []}],
  168. [],
  169. {ok, ["B", "C"]}};
  170. deps(pick_highest_left) ->
  171. {[{"B", [{"C", "2", []}]},
  172. {"C", "1", []}],
  173. [{"C","2"}],
  174. {ok, ["B", {"C", "1"}]}};
  175. deps(pick_highest_right) ->
  176. {[{"B", "1", []},
  177. {"C", [{"B", "2", []}]}],
  178. [{"B","2"}],
  179. {ok, [{"B","1"}, "C"]}};
  180. deps(pick_smallest1) ->
  181. {[{"B", [{"D", "1", []}]},
  182. {"C", [{"D", "2", []}]}],
  183. [{"D","2"}],
  184. %% we pick D1 because B < C
  185. {ok, ["B","C",{"D","1"}]}};
  186. deps(pick_smallest2) ->
  187. {[{"C", [{"D", "2", []}]},
  188. {"B", [{"D", "1", []}]}],
  189. [{"D","2"}],
  190. %% we pick D1 because B < C
  191. {ok, ["B","C",{"D","1"}]}};
  192. deps(circular1) ->
  193. {[{"B", [{"A", []}]}, % A is the top-level app
  194. {"C", []}],
  195. [],
  196. {error, {rebar_prv_install_deps, {cycles, [[<<"A">>,<<"B">>]]}}}};
  197. deps(circular2) ->
  198. {[{"B", [{"C", [{"B", []}]}]},
  199. {"C", []}],
  200. [],
  201. {error, {rebar_prv_install_deps, {cycles, [[<<"B">>,<<"C">>]]}}}};
  202. deps(circular_skip) ->
  203. %% Never spot the circular dep due to being to low in the deps tree
  204. %% in source deps
  205. {[{"B", [{"C", "2", [{"B", []}]}]},
  206. {"C", "1", [{"D",[]}]}],
  207. [{"C","2"}],
  208. {ok, ["B", {"C","1"}, "D"]}}.
  209. setup_project(Case, Config0, Deps) ->
  210. DepsType = ?config(deps_type, Config0),
  211. Config = rebar_test_utils:init_rebar_state(
  212. Config0,
  213. atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_"
  214. ),
  215. AppDir = ?config(apps, Config),
  216. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  217. TopDeps = rebar_test_utils:top_level_deps(Deps),
  218. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
  219. {SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps),
  220. mock_git_resource:mock([{deps, SrcDeps}]),
  221. mock_pkg_resource:mock([{pkgdeps, PkgDeps}]),
  222. [{rebarconfig, RebarConf} | Config].
  223. mock_warnings() ->
  224. %% just let it do its thing, we check warnings through
  225. %% the call log.
  226. meck:new(rebar_log, [no_link, passthrough]).
  227. %%% TESTS %%%
  228. flat(Config) -> run(Config).
  229. pick_highest_left(Config) -> run(Config).
  230. pick_highest_right(Config) -> run(Config).
  231. pick_smallest1(Config) -> run(Config).
  232. pick_smallest2(Config) -> run(Config).
  233. circular1(Config) -> run(Config).
  234. circular2(Config) -> run(Config).
  235. circular_skip(Config) -> run(Config).
  236. %% Test that the deps of project apps that have their own rebar.config
  237. %% are included, but that top level rebar.config deps take precedence
  238. sub_app_deps(Config) ->
  239. AppDir = ?config(apps, Config),
  240. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  241. ,{"b", "1.0.0", []}
  242. ,{"b", "2.0.0", []}]),
  243. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  244. mock_git_resource:mock([{deps, SrcDeps}]),
  245. Name = rebar_test_utils:create_random_name("sub_app1_"),
  246. Vsn = rebar_test_utils:create_random_vsn(),
  247. SubAppsDir = filename:join([AppDir, "apps", Name]),
  248. SubDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  249. ,{"b", "2.0.0", []}])),
  250. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  251. rebar_test_utils:create_config(SubAppsDir, [{deps, SubDeps}]),
  252. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  253. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  254. rebar_test_utils:run_and_check(
  255. Config, RebarConfig, ["compile"],
  256. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}]}).
  257. %% Newly added dependency after locking
  258. newly_added_dep(Config) ->
  259. AppDir = ?config(apps, Config),
  260. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  261. ,{"b", "1.0.0", [{"c", "1.0.0", []}]}
  262. ,{"c", "2.0.0", []}]),
  263. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  264. mock_git_resource:mock([{deps, SrcDeps}]),
  265. Name = rebar_test_utils:create_random_name("app_"),
  266. Vsn = rebar_test_utils:create_random_vsn(),
  267. SubAppsDir = filename:join([AppDir, "apps", Name]),
  268. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  269. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"b", "1.0.0", []}])),
  270. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  271. rebar_test_utils:run_and_check(
  272. Config, RebarConfig, ["compile"],
  273. {ok, [{app, Name}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}),
  274. %% Add a and c to top level
  275. TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}
  276. ,{"c", "2.0.0", []}
  277. ,{"b", "1.0.0", []}])),
  278. {ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
  279. LockFile = filename:join(AppDir, "rebar.lock"),
  280. RebarConfig3 = rebar_config:merge_locks(RebarConfig2,
  281. rebar_config:consult_lock_file(LockFile)),
  282. %% a should now be installed and c should not change
  283. rebar_test_utils:run_and_check(
  284. Config, RebarConfig3, ["compile"],
  285. {ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}).
  286. newly_added_after_empty_lock(Config) ->
  287. AppDir = ?config(apps, Config),
  288. Deps = rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}]),
  289. {SrcDeps, _} = rebar_test_utils:flat_deps(Deps),
  290. mock_git_resource:mock([{deps, SrcDeps}]),
  291. Name = rebar_test_utils:create_random_name("app_"),
  292. Vsn = rebar_test_utils:create_random_vsn(),
  293. SubAppsDir = filename:join([AppDir, "apps", Name]),
  294. rebar_test_utils:create_app(SubAppsDir, Name, Vsn, [kernel, stdlib]),
  295. TopDeps = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [])),
  296. {ok, RebarConfig} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps}])),
  297. rebar_test_utils:run_and_check(
  298. Config, RebarConfig, ["compile"],
  299. {ok, []}),
  300. %% Add a and c to top level
  301. TopDeps2 = rebar_test_utils:top_level_deps(rebar_test_utils:expand_deps(git, [{"a", "1.0.0", []}])),
  302. {ok, RebarConfig2} = file:consult(rebar_test_utils:create_config(AppDir, [{deps, TopDeps2}])),
  303. LockFile = filename:join(AppDir, "rebar.lock"),
  304. RebarConfig3 = rebar_config:merge_locks(RebarConfig2,
  305. rebar_config:consult_lock_file(LockFile)),
  306. %% a should now be installed and c should not change
  307. rebar_test_utils:run_and_check(
  308. Config, RebarConfig3, ["compile"],
  309. {ok, [{app, Name}, {dep, "a", "1.0.0"}]}).
  310. http_proxy_settings(_Config) ->
  311. %% Load config
  312. rebar_utils:set_httpc_options(),
  313. rebar3:init_config(),
  314. %% Assert variable is right
  315. ?assertEqual({ok,{{"localhost", 1234}, []}},
  316. httpc:get_option(proxy, rebar)).
  317. https_proxy_settings(_Config) ->
  318. %% Load config
  319. rebar_utils:set_httpc_options(),
  320. rebar3:init_config(),
  321. %% Assert variable is right
  322. ?assertEqual({ok,{{"localhost", 1234}, []}},
  323. httpc:get_option(https_proxy, rebar)).
  324. http_os_proxy_settings(_Config) ->
  325. %% Load config
  326. rebar_utils:set_httpc_options(),
  327. rebar3:init_config(),
  328. %% Assert variable is right
  329. ?assertEqual({ok,{{"localhost", 1234}, []}},
  330. httpc:get_option(proxy, rebar)).
  331. https_os_proxy_settings(_Config) ->
  332. %% Load config
  333. rebar_utils:set_httpc_options(),
  334. rebar3:init_config(),
  335. %% Assert variable is right
  336. ?assertEqual({ok,{{"localhost", 1234}, []}},
  337. httpc:get_option(https_proxy, rebar)).
  338. semver_matching_lt(_Config) ->
  339. Dep = <<"test">>,
  340. Dep1 = {Dep, <<"1.0.0">>, Dep, Dep},
  341. MaxVsn = <<"0.2.0">>,
  342. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
  343. ?assertEqual([{Dep, {pkg, Dep, <<"0.1.9">>, undefined}}],
  344. rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1,
  345. fun ec_semver:lt/2)).
  346. semver_matching_lte(_Config) ->
  347. Dep = <<"test">>,
  348. Dep1 = {Dep, <<"1.0.0">>, Dep, Dep},
  349. MaxVsn = <<"0.2.0">>,
  350. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
  351. ?assertEqual([{Dep, {pkg, Dep, <<"0.2.0">>, undefined}}],
  352. rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1,
  353. fun ec_semver:lte/2)).
  354. semver_matching_gt(_Config) ->
  355. Dep = <<"test">>,
  356. Dep1 = {Dep, <<"1.0.0">>, Dep, Dep},
  357. MaxVsn = <<"0.2.0">>,
  358. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>],
  359. ?assertEqual([{Dep, {pkg, Dep, <<"0.2.1">>, undefined}}],
  360. rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1,
  361. fun ec_semver:gt/2)).
  362. semver_matching_gte(_Config) ->
  363. Dep = <<"test">>,
  364. Dep1 = {Dep, <<"1.0.0">>, Dep, Dep},
  365. MaxVsn = <<"0.2.0">>,
  366. Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>],
  367. ?assertEqual([{Dep, {pkg, Dep, <<"0.2.0">>, undefined}}],
  368. rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1,
  369. fun ec_semver:gt/2)).
  370. valid_version(_Config) ->
  371. ?assert(rebar_prv_update:valid_vsn(<<"0.1">>)),
  372. ?assert(rebar_prv_update:valid_vsn(<<"0.1.0">>)),
  373. ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)),
  374. ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)),
  375. ?assert(rebar_prv_update:valid_vsn(<<"<0.1">>)),
  376. ?assert(rebar_prv_update:valid_vsn(<<"<0.1.0">>)),
  377. ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)),
  378. ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)),
  379. ?assert(rebar_prv_update:valid_vsn(<<">0.1">>)),
  380. ?assert(rebar_prv_update:valid_vsn(<<">0.1.0">>)),
  381. ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)),
  382. ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)),
  383. ?assert(rebar_prv_update:valid_vsn(<<"<=0.1">>)),
  384. ?assert(rebar_prv_update:valid_vsn(<<"<=0.1.0">>)),
  385. ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)),
  386. ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)),
  387. ?assert(rebar_prv_update:valid_vsn(<<">=0.1">>)),
  388. ?assert(rebar_prv_update:valid_vsn(<<">=0.1.0">>)),
  389. ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)),
  390. ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)),
  391. ?assert(rebar_prv_update:valid_vsn(<<"==0.1">>)),
  392. ?assert(rebar_prv_update:valid_vsn(<<"==0.1.0">>)),
  393. ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)),
  394. ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)),
  395. ?assert(rebar_prv_update:valid_vsn(<<"~>0.1">>)),
  396. ?assert(rebar_prv_update:valid_vsn(<<"~>0.1.0">>)),
  397. ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)),
  398. ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)),
  399. ?assertNot(rebar_prv_update:valid_vsn(<<"> 0.1.0 and < 0.2.0">>)),
  400. ok.
  401. run(Config) ->
  402. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  403. rebar_test_utils:run_and_check(
  404. Config, RebarConfig, ["install_deps"], ?config(expect, Config)
  405. ),
  406. check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
  407. warning_calls() ->
  408. History = meck:history(rebar_log),
  409. [{Str, Args} || {_, {rebar_log, log, [warn, Str, Args]}, _} <- History].
  410. check_warnings(_, [], _) ->
  411. ok;
  412. check_warnings(Warns, [{Name, Vsn} | Rest], Type) ->
  413. ct:pal("Checking for warning ~p in ~p", [{Name,Vsn},Warns]),
  414. ?assert(in_warnings(Type, Warns, Name, Vsn)),
  415. check_warnings(Warns, Rest, Type).
  416. in_warnings(git, Warns, NameRaw, VsnRaw) ->
  417. Name = iolist_to_binary(NameRaw),
  418. 1 =< length([1 || {_, [AppName, {git, _, {_, Vsn}}]} <- Warns,
  419. AppName =:= Name, Vsn =:= VsnRaw]);
  420. in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
  421. Name = iolist_to_binary(NameRaw),
  422. Vsn = iolist_to_binary(VsnRaw),
  423. 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn, _}]} <- Warns,
  424. AppName =:= Name, AppVsn =:= Vsn]).