Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

166 lignes
6.1 KiB

  1. %%% Mock a package resource and create an app magically for each URL submitted.
  2. -module(mock_pkg_resource).
  3. -export([mock/0, mock/1, unmock/0]).
  4. -define(MOD, rebar_pkg_resource).
  5. %%%%%%%%%%%%%%%%%
  6. %%% Interface %%%
  7. %%%%%%%%%%%%%%%%%
  8. %% @doc same as `mock([])'.
  9. mock() -> mock([]).
  10. %% @doc Mocks a fake version of the git resource fetcher that creates
  11. %% empty applications magically, rather than trying to download them.
  12. %% Specific config options are explained in each of the private functions.
  13. -spec mock(Opts) -> ok when
  14. Opts :: [Option],
  15. Option :: {upgrade, [App]}
  16. | {cache_dir, string()}
  17. | {default_vsn, Vsn}
  18. | {override_vsn, [{App, Vsn}]}
  19. | {not_in_index, [{App, Vsn}]}
  20. | {pkgdeps, [{{App,Vsn}, [Dep]}]},
  21. App :: string(),
  22. Dep :: {App, string(), {pkg, App, Vsn, Hash}},
  23. Vsn :: string(),
  24. Hash :: string() | undefined.
  25. mock(Opts) ->
  26. meck:new(?MOD, [no_link]),
  27. mock_lock(Opts),
  28. mock_update(Opts),
  29. mock_vsn(Opts),
  30. mock_download(Opts),
  31. mock_pkg_index(Opts),
  32. ok.
  33. unmock() ->
  34. meck:unload(?MOD),
  35. meck:unload(rebar_packages).
  36. %%%%%%%%%%%%%%%
  37. %%% Private %%%
  38. %%%%%%%%%%%%%%%
  39. %% @doc creates values for a lock file.
  40. mock_lock(_) ->
  41. meck:expect(?MOD, lock, fun(_AppDir, Source) -> Source end).
  42. %% @doc The config passed to the `mock/2' function can specify which apps
  43. %% should be updated on a per-name basis: `{update, ["App1", "App3"]}'.
  44. mock_update(Opts) ->
  45. ToUpdate = proplists:get_value(upgrade, Opts, []),
  46. meck:expect(
  47. ?MOD, needs_update,
  48. fun(_Dir, {pkg, App, _Vsn, _Hash}) ->
  49. lists:member(binary_to_list(App), ToUpdate)
  50. end).
  51. %% @doc Replicated an unsupported call.
  52. mock_vsn(_Opts) ->
  53. meck:expect(
  54. ?MOD, make_vsn,
  55. fun(_Dir) ->
  56. {error, "Replacing version of type pkg not supported."}
  57. end).
  58. %% @doc For each app to download, create a dummy app on disk instead.
  59. %% The configuration for this one (passed in from `mock/1') includes:
  60. %%
  61. %% - Specify a version with `{pkg, _, Vsn, _}'
  62. %% - Dependencies for each application must be passed of the form:
  63. %% `{pkgdeps, [{"app1", [{app2, ".*", {pkg, ...}}]}]}' -- basically
  64. %% the `pkgdeps' option takes a key/value list of terms to output directly
  65. %% into a `rebar.config' file to describe dependencies.
  66. mock_download(Opts) ->
  67. Deps = proplists:get_value(pkgdeps, Opts, []),
  68. Config = proplists:get_value(config, Opts, []),
  69. meck:expect(
  70. ?MOD, download,
  71. fun (Dir, {pkg, AppBin, Vsn, _}, _) ->
  72. App = binary_to_list(AppBin),
  73. filelib:ensure_dir(Dir),
  74. AppDeps = proplists:get_value({App,Vsn}, Deps, []),
  75. {ok, AppInfo} = rebar_test_utils:create_app(
  76. Dir, App, binary_to_list(Vsn),
  77. [kernel, stdlib] ++ [element(1,D) || D <- AppDeps]
  78. ),
  79. rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config),
  80. TarApp = App++"-"++binary_to_list(Vsn)++".tar",
  81. Tarball = filename:join([Dir, TarApp]),
  82. Contents = filename:join([Dir, "contents.tar.gz"]),
  83. Files = all_files(rebar_app_info:dir(AppInfo)),
  84. ok = erl_tar:create(Contents,
  85. archive_names(Dir, App, Vsn, Files),
  86. [compressed]),
  87. ok = erl_tar:create(Tarball,
  88. [{"contents.tar.gz", Contents}],
  89. []),
  90. Cache = proplists:get_value(cache_dir, Opts, filename:join(Dir,"cache")),
  91. Cached = filename:join([Cache, TarApp]),
  92. filelib:ensure_dir(Cached),
  93. rebar_file_utils:mv(Tarball, Cached),
  94. {ok, true}
  95. end).
  96. %% @doc On top of the pkg resource mocking, we need to mock the package
  97. %% index.
  98. %%
  99. %% A special option, `{not_in_index, [App]}' lets the index leave out
  100. %% specific applications otherwise listed.
  101. mock_pkg_index(Opts) ->
  102. Deps = proplists:get_value(pkgdeps, Opts, []),
  103. Skip = proplists:get_value(not_in_index, Opts, []),
  104. %% Dict: {App, Vsn}: [{<<"link">>, <<>>}, {<<"deps">>, []}]
  105. %% Index: all apps and deps in the index
  106. Dict = find_parts(Deps, Skip),
  107. meck:new(rebar_packages, [passthrough, no_link]),
  108. meck:expect(rebar_packages, packages,
  109. fun(_State) -> to_index(Deps, Dict) end),
  110. meck:expect(rebar_packages, verify_table,
  111. fun(_State) -> to_index(Deps, Dict), true end).
  112. %%%%%%%%%%%%%%%
  113. %%% Helpers %%%
  114. %%%%%%%%%%%%%%%
  115. all_files(Dir) ->
  116. filelib:wildcard(filename:join([Dir, "**"])).
  117. archive_names(Dir, _App, _Vsn, Files) ->
  118. [{(F -- Dir) -- "/", F} || F <- Files].
  119. find_parts(Apps, Skip) -> find_parts(Apps, Skip, dict:new()).
  120. find_parts([], _, Acc) -> Acc;
  121. find_parts([{AppName, Deps}|Rest], Skip, Acc) ->
  122. case lists:member(AppName, Skip) orelse dict:is_key(AppName,Acc) of
  123. true -> find_parts(Rest, Skip, Acc);
  124. false ->
  125. AccNew = dict:store(AppName,
  126. Deps,
  127. Acc),
  128. find_parts(Rest, Skip, AccNew)
  129. end.
  130. to_index(AllDeps, Dict) ->
  131. catch ets:delete(package_index),
  132. ets:new(package_index, [named_table, public]),
  133. dict:fold(
  134. fun(K, Deps, _) ->
  135. DepsList = [{DKB, {pkg, DKB, DVB, undefined}}
  136. || {DK, DV} <- Deps,
  137. DKB <- [ec_cnv:to_binary(DK)],
  138. DVB <- [ec_cnv:to_binary(DV)]],
  139. ets:insert(package_index, {K, DepsList, <<"checksum">>})
  140. end, ok, Dict),
  141. ets:insert(package_index, {package_index_version, 3}),
  142. lists:foreach(fun({{Name, Vsn}, _}) ->
  143. case ets:lookup(package_index, ec_cnv:to_binary(Name)) of
  144. [{_, Vsns}] ->
  145. ets:insert(package_index, {ec_cnv:to_binary(Name), [ec_cnv:to_binary(Vsn) | Vsns]});
  146. _ ->
  147. ets:insert(package_index, {ec_cnv:to_binary(Name), [ec_cnv:to_binary(Vsn)]})
  148. end
  149. end, AllDeps).