Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

489 рядки
21 KiB

9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
  1. -module(rebar_test_utils).
  2. -include_lib("common_test/include/ct.hrl").
  3. -include_lib("eunit/include/eunit.hrl").
  4. -export([init_rebar_state/1, init_rebar_state/2, run_and_check/4, check_results/3]).
  5. -export([expand_deps/2, flat_deps/1, top_level_deps/1]).
  6. -export([create_app/4, create_plugin/4, create_eunit_app/4, create_empty_app/4,
  7. create_config/2, create_config/3, package_app/3]).
  8. -export([create_random_name/1, create_random_vsn/0, write_src_file/2]).
  9. %% Pick the right random module
  10. -ifdef(rand_only).
  11. -define(random, rand).
  12. -else.
  13. -define(random, random).
  14. -endif.
  15. %%%%%%%%%%%%%%
  16. %%% Public %%%
  17. %%%%%%%%%%%%%%
  18. %% @doc {@see init_rebar_state/2}
  19. init_rebar_state(Config) -> init_rebar_state(Config, "apps_dir1_").
  20. %% @doc Takes a common test config and a name (string) and sets up
  21. %% a basic OTP app directory with a pre-configured rebar state to
  22. %% run tests with.
  23. init_rebar_state(Config, Name) ->
  24. application:load(rebar),
  25. DataDir = ?config(priv_dir, Config),
  26. AppsDir = filename:join([DataDir, create_random_name(Name)]),
  27. CheckoutsDir = filename:join([AppsDir, "_checkouts"]),
  28. ok = ec_file:mkdir_p(AppsDir),
  29. ok = ec_file:mkdir_p(CheckoutsDir),
  30. Verbosity = rebar3:log_level(),
  31. rebar_log:init(command_line, Verbosity),
  32. GlobalDir = filename:join([DataDir, "cache"]),
  33. State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])}
  34. ,{global_rebar_dir, GlobalDir}
  35. ,{root_dir, AppsDir}]),
  36. [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, State} | Config].
  37. %% @doc Takes common test config, a rebar config ([] if empty), a command to
  38. %% run ("install_deps", "compile", etc.), and a list of expected applications
  39. %% and/or dependencies to be present, and verifies whether they are all in
  40. %% place.
  41. %%
  42. %% The expectation list takes elements of the form:
  43. %% - `{app, Name :: string()}': checks that the app is properly built.
  44. %% - `{dep, Name :: string()}': checks that the dependency has been fetched.
  45. %% Ignores the build status of the dependency.
  46. %% - `{dep, Name :: string(), Vsn :: string()}': checks that the dependency
  47. %% has been fetched, and that a given version has been chosen. Useful to
  48. %% test for conflict resolution. Also ignores the build status of the
  49. %% dependency.
  50. %%
  51. %% This function assumes `init_rebar_state/1-2' has run before, in order to
  52. %% fetch the `apps' and `state' values from the CT config.
  53. run_and_check(Config, RebarConfig, Command, Expect) ->
  54. %% Assumes init_rebar_state has run first
  55. AppDir = ?config(apps, Config),
  56. State = ?config(state, Config),
  57. try
  58. Res = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), Command),
  59. case Expect of
  60. {error, Reason} ->
  61. ?assertEqual({error, Reason}, Res);
  62. {ok, Expected} ->
  63. {ok, _} = Res,
  64. check_results(AppDir, Expected, "*"),
  65. Res;
  66. {ok, Expected, ProfileRun} ->
  67. {ok, _} = Res,
  68. check_results(AppDir, Expected, ProfileRun),
  69. Res;
  70. return ->
  71. Res
  72. end
  73. catch
  74. rebar_abort when Expect =:= rebar_abort -> rebar_abort
  75. end.
  76. %% @doc Creates a dummy application including:
  77. %% - src/<file>.erl
  78. %% - src/<file>.app.src
  79. %% And returns a `rebar_app_info' object.
  80. create_app(AppDir, Name, Vsn, Deps) ->
  81. write_src_file(AppDir, Name ++ ".erl"),
  82. write_src_file(AppDir, "not_a_real_src_" ++ Name ++ ".erl"),
  83. write_app_src_file(AppDir, Name, Vsn, Deps),
  84. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  85. %% @doc Creates a dummy plugin including:
  86. %% - src/<file>.erl
  87. %% - src/<file>.app.src
  88. %% And returns a `rebar_app_info' object.
  89. create_plugin(AppDir, Name, Vsn, Deps) ->
  90. write_plugin_file(AppDir, Name ++ ".erl"),
  91. write_src_file(AppDir, "not_a_real_src_" ++ Name ++ ".erl"),
  92. write_app_src_file(AppDir, Name, Vsn, Deps),
  93. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  94. %% @doc Creates a dummy application including:
  95. %% - src/<file>.erl
  96. %% - src/<file>.app.src
  97. %% - test/<file>_tests.erl
  98. %% And returns a `rebar_app_info' object.
  99. create_eunit_app(AppDir, Name, Vsn, Deps) ->
  100. write_eunitized_src_file(AppDir, Name),
  101. write_eunit_suite_file(AppDir, Name),
  102. write_app_src_file(AppDir, Name, Vsn, Deps),
  103. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  104. %% @doc Creates a dummy application including:
  105. %% - ebin/<file>.app
  106. %% And returns a `rebar_app_info' object.
  107. create_empty_app(AppDir, Name, Vsn, Deps) ->
  108. write_app_file(AppDir, Name, Vsn, Deps),
  109. rebar_app_info:new(Name, Vsn, AppDir, Deps).
  110. %% @doc Creates a rebar.config file. The function accepts a list of terms,
  111. %% each of which will be dumped as a consult file. For example, the list
  112. %% `[a, b, c]' will return the consult file `a. b. c.'.
  113. create_config(AppDir, Contents) ->
  114. ConfFilename = filename:join([AppDir, "rebar.config"]),
  115. create_config(AppDir, ConfFilename, Contents).
  116. create_config(_AppDir, ConfFilename, Contents) ->
  117. ok = filelib:ensure_dir(ConfFilename),
  118. Config = lists:flatten([io_lib:fwrite("~p.~n", [Term]) || Term <- Contents]),
  119. ok = ec_file:write(ConfFilename, Config),
  120. ConfFilename.
  121. %% @doc Util to create a random variation of a given name.
  122. create_random_name(Name) ->
  123. random_seed(),
  124. Name ++ erlang:integer_to_list(?random:uniform(1000000)).
  125. %% @doc Util to create a random variation of a given version.
  126. create_random_vsn() ->
  127. random_seed(),
  128. lists:flatten([erlang:integer_to_list(?random:uniform(100)),
  129. ".", erlang:integer_to_list(?random:uniform(100)),
  130. ".", erlang:integer_to_list(?random:uniform(100))]).
  131. -ifdef(rand_only).
  132. random_seed() ->
  133. %% the rand module self-seeds
  134. ok.
  135. -else.
  136. random_seed() ->
  137. <<A:32, B:32, C:32>> = crypto:rand_bytes(12),
  138. random:seed({A,B,C}).
  139. -endif.
  140. expand_deps(_, []) -> [];
  141. expand_deps(git, [{Name, Deps} | Rest]) ->
  142. Dep = {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}},
  143. [{Dep, expand_deps(git, Deps)} | expand_deps(git, Rest)];
  144. expand_deps(git, [{Name, Vsn, Deps} | Rest]) ->
  145. Dep = {Name, Vsn, {git, "https://example.org/user/"++Name++".git", {tag, Vsn}}},
  146. [{Dep, expand_deps(git, Deps)} | expand_deps(git, Rest)];
  147. expand_deps(pkg, [{Name, Deps} | Rest]) ->
  148. Dep = {pkg, Name, "0.0.0", undefined},
  149. [{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)];
  150. expand_deps(pkg, [{Name, Vsn, Deps} | Rest]) ->
  151. Dep = {pkg, Name, Vsn, undefined},
  152. [{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)];
  153. expand_deps(mixed, [{Name, Deps} | Rest]) ->
  154. Dep = if hd(Name) >= $a, hd(Name) =< $z ->
  155. {pkg, string:to_upper(Name), "0.0.0", undefined}
  156. ; hd(Name) >= $A, hd(Name) =< $Z ->
  157. {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}}
  158. end,
  159. [{Dep, expand_deps(mixed, Deps)} | expand_deps(mixed, Rest)];
  160. expand_deps(mixed, [{Name, Vsn, Deps} | Rest]) ->
  161. Dep = if hd(Name) >= $a, hd(Name) =< $z ->
  162. {pkg, string:to_upper(Name), Vsn, undefined}
  163. ; hd(Name) >= $A, hd(Name) =< $Z ->
  164. {Name, Vsn, {git, "https://example.org/user/"++Name++".git", {tag, Vsn}}}
  165. end,
  166. [{Dep, expand_deps(mixed, Deps)} | expand_deps(mixed, Rest)].
  167. %% Source deps can depend on both source and package dependencies;
  168. %% package deps can only depend on package deps.
  169. %% For things to work we have to go down the dep tree and find all
  170. %% lineages of pkg deps and return them, whereas the source deps
  171. %% can be left as is.
  172. flat_deps(Deps) -> flat_deps(Deps, [], []).
  173. flat_deps([], Src, Pkg) -> {Src, Pkg};
  174. flat_deps([{{pkg, Name, Vsn, undefined}, PkgDeps} | Rest], Src, Pkg) ->
  175. Current = {{iolist_to_binary(Name), iolist_to_binary(Vsn)},
  176. top_level_deps(PkgDeps)},
  177. {[], FlatPkgDeps} = flat_deps(PkgDeps),
  178. flat_deps(Rest,
  179. Src,
  180. Pkg ++ [Current | FlatPkgDeps]);
  181. flat_deps([{{Name,_Vsn,Ref}, Deps} | Rest], Src, Pkg) ->
  182. Current = {{Name,vsn_from_ref(Ref)}, top_level_deps(Deps)},
  183. {FlatDeps, FlatPkgDeps} = flat_deps(Deps),
  184. flat_deps(Rest,
  185. Src ++ [Current | FlatDeps],
  186. Pkg ++ FlatPkgDeps).
  187. vsn_from_ref({git, _, {_, Vsn}}) -> Vsn;
  188. vsn_from_ref({git, _, Vsn}) -> Vsn.
  189. top_level_deps([]) -> [];
  190. top_level_deps([{{pkg, Name, Vsn, undefined}, _} | Deps]) ->
  191. [{list_to_atom(Name), Vsn} | top_level_deps(Deps)];
  192. top_level_deps([{{Name, Vsn, Ref}, _} | Deps]) ->
  193. [{list_to_atom(Name), Vsn, Ref} | top_level_deps(Deps)].
  194. %%%%%%%%%%%%%%%
  195. %%% Helpers %%%
  196. %%%%%%%%%%%%%%%
  197. check_results(AppDir, Expected, ProfileRun) ->
  198. BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "lib", "*"])),
  199. PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "plugins", "*"])),
  200. GlobalPluginDirs = filelib:wildcard(filename:join([AppDir, "global", "plugins", "*"])),
  201. CheckoutsDir = filename:join([AppDir, "_checkouts", "*"]),
  202. LockFile = filename:join([AppDir, "rebar.lock"]),
  203. Locks = lists:flatten(rebar_config:consult_lock_file(LockFile)),
  204. InvalidApps = rebar_app_discover:find_apps(BuildDirs, invalid),
  205. ValidApps = rebar_app_discover:find_apps(BuildDirs, valid),
  206. InvalidDepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- InvalidApps],
  207. ValidDepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- ValidApps],
  208. Deps = rebar_app_discover:find_apps(BuildDirs, all),
  209. DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
  210. Checkouts = rebar_app_discover:find_apps([CheckoutsDir], all),
  211. CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts],
  212. Plugins = rebar_app_discover:find_apps(PluginDirs, all),
  213. PluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Plugins],
  214. GlobalPlugins = rebar_app_discover:find_apps(GlobalPluginDirs, all),
  215. GlobalPluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- GlobalPlugins],
  216. lists:foreach(
  217. fun({app, Name}) ->
  218. ct:pal("App Name: ~p", [Name]),
  219. case lists:keyfind(Name, 1, DepsNames) of
  220. false ->
  221. error({app_not_found, Name});
  222. {Name, _App} ->
  223. ok
  224. end
  225. ; ({app, Name, invalid}) ->
  226. ct:pal("Invalid Name: ~p", [Name]),
  227. case lists:keyfind(Name, 1, InvalidDepsNames) of
  228. false ->
  229. error({app_not_found, Name});
  230. {Name, _App} ->
  231. ok
  232. end
  233. ; ({app, Name, valid}) ->
  234. ct:pal("Valid Name: ~p", [Name]),
  235. case lists:keyfind(Name, 1, ValidDepsNames) of
  236. false ->
  237. error({app_not_found, Name});
  238. {Name, _App} ->
  239. ok
  240. end
  241. ; ({dep_not_exist, Name}) ->
  242. ct:pal("App Not Exist Name: ~p", [Name]),
  243. case lists:keyfind(Name, 1, DepsNames) of
  244. false ->
  245. ok;
  246. {Name, _App} ->
  247. error({app_found, Name})
  248. end
  249. ; ({checkout, Name}) ->
  250. ct:pal("Checkout Name: ~p", [Name]),
  251. ?assertNotEqual(false, lists:keyfind(Name, 1, CheckoutsNames))
  252. ; ({dep, Name}) ->
  253. ct:pal("Dep Name: ~p", [Name]),
  254. ?assertNotEqual(false, lists:keyfind(Name, 1, DepsNames))
  255. ; ({dep, Name, Vsn}) ->
  256. ct:pal("Dep Name: ~p, Vsn: ~p", [Name, Vsn]),
  257. case lists:keyfind(Name, 1, DepsNames) of
  258. false ->
  259. error({dep_not_found, Name});
  260. {Name, App} ->
  261. ?assertEqual(iolist_to_binary(Vsn),
  262. iolist_to_binary(rebar_app_info:original_vsn(App)))
  263. end
  264. ; ({plugin, Name}) ->
  265. ct:pal("Plugin Name: ~p", [Name]),
  266. ?assertNotEqual(false, lists:keyfind(Name, 1, PluginsNames))
  267. ; ({plugin, Name, Vsn}) ->
  268. ct:pal("Plugin Name: ~p, Vsn: ~p", [Name, Vsn]),
  269. case lists:keyfind(Name, 1, PluginsNames) of
  270. false ->
  271. error({plugin_not_found, Name});
  272. {Name, App} ->
  273. ?assertEqual(iolist_to_binary(Vsn),
  274. iolist_to_binary(rebar_app_info:original_vsn(App)))
  275. end
  276. ; ({global_plugin, Name}) ->
  277. ct:pal("Global Plugin Name: ~p", [Name]),
  278. ?assertNotEqual(false, lists:keyfind(Name, 1, GlobalPluginsNames))
  279. ; ({global_plugin, Name, Vsn}) ->
  280. ct:pal("Global Plugin Name: ~p, Vsn: ~p", [Name, Vsn]),
  281. case lists:keyfind(Name, 1, GlobalPluginsNames) of
  282. false ->
  283. error({global_plugin_not_found, Name});
  284. {Name, App} ->
  285. ?assertEqual(iolist_to_binary(Vsn),
  286. iolist_to_binary(rebar_app_info:original_vsn(App)))
  287. end
  288. ; ({lock, Name}) ->
  289. ct:pal("Lock Name: ~p", [Name]),
  290. ?assertNotEqual(false, lists:keyfind(iolist_to_binary(Name), 1, Locks))
  291. ; ({lock, Name, Vsn}) ->
  292. ct:pal("Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
  293. case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
  294. false ->
  295. error({lock_not_found, Name});
  296. {_LockName, {pkg, _, LockVsn, Hash}, _} ->
  297. ?assertEqual(iolist_to_binary(Vsn),
  298. iolist_to_binary(LockVsn)),
  299. ?assertNotEqual(undefined, Hash);
  300. {_LockName, {_, _, {ref, LockVsn}}, _} ->
  301. ?assertEqual(iolist_to_binary(Vsn),
  302. iolist_to_binary(LockVsn))
  303. end
  304. ; ({lock, pkg, Name, Vsn}) ->
  305. ct:pal("Pkg Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
  306. case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
  307. false ->
  308. error({lock_not_found, Name});
  309. {_LockName, {pkg, _, LockVsn, Hash}, _} ->
  310. ?assertEqual(iolist_to_binary(Vsn),
  311. iolist_to_binary(LockVsn)),
  312. ?assertNotEqual(undefined, Hash);
  313. {_LockName, {_, _, {ref, LockVsn}}, _} ->
  314. error({source_lock, {Name, LockVsn}})
  315. end
  316. ; ({lock, src, Name, Vsn}) ->
  317. ct:pal("Src Lock Name: ~p, Vsn: ~p", [Name, Vsn]),
  318. case lists:keyfind(iolist_to_binary(Name), 1, Locks) of
  319. false ->
  320. error({lock_not_found, Name});
  321. {_LockName, {pkg, _, LockVsn, _}, _} ->
  322. error({pkg_lock, {Name, LockVsn}});
  323. {_LockName, {_, _, {ref, LockVsn}}, _} ->
  324. ?assertEqual(iolist_to_binary(Vsn),
  325. iolist_to_binary(LockVsn))
  326. end
  327. ; ({release, Name, Vsn, ExpectedDevMode}) ->
  328. ct:pal("Release: ~p-~s", [Name, Vsn]),
  329. {ok, Cwd} = file:get_cwd(),
  330. try
  331. file:set_cwd(AppDir),
  332. [ReleaseDir] = filelib:wildcard(filename:join([AppDir, "_build", "*", "rel"])),
  333. RelxState = rlx_state:new("", [], []),
  334. RelxState1 = rlx_state:base_output_dir(RelxState, ReleaseDir),
  335. {ok, RelxState2} = rlx_prv_app_discover:do(RelxState1),
  336. {ok, RelxState3} = rlx_prv_rel_discover:do(RelxState2),
  337. LibDir = filename:join([ReleaseDir, Name, "lib"]),
  338. {ok, RelLibs} = rebar_utils:list_dir(LibDir),
  339. IsSymLinkFun =
  340. fun(X) ->
  341. ec_file:is_symlink(filename:join(LibDir, X))
  342. end,
  343. DevMode = lists:all(IsSymLinkFun, RelLibs),
  344. ?assertEqual(ExpectedDevMode, DevMode),
  345. %% throws not_found if it doesn't exist
  346. rlx_state:get_realized_release(RelxState3, Name, Vsn)
  347. catch
  348. _ ->
  349. ct:fail(release_not_found)
  350. after
  351. file:set_cwd(Cwd)
  352. end
  353. ; ({tar, Name, Vsn}) ->
  354. ct:pal("Tarball: ~s-~s", [Name, Vsn]),
  355. Tarball = filename:join([AppDir, "_build", "rel", Name, Name++"-"++Vsn++".tar.gz"]),
  356. ?assertNotEqual([], filelib:is_file(Tarball))
  357. ; ({file, Filename}) ->
  358. ct:pal("Filename: ~s", [Filename]),
  359. ?assert(filelib:is_file(Filename))
  360. ; ({dir, Dirname}) ->
  361. ct:pal("Directory: ~s", [Dirname]),
  362. ?assert(filelib:is_dir(Dirname))
  363. end, Expected).
  364. write_plugin_file(Dir, Name) ->
  365. Erl = filename:join([Dir, "src", Name]),
  366. ok = filelib:ensure_dir(Erl),
  367. ok = ec_file:write(Erl, plugin_src_file(Name)).
  368. write_src_file(Dir, Name) ->
  369. Erl = filename:join([Dir, "src", Name]),
  370. ok = filelib:ensure_dir(Erl),
  371. ok = ec_file:write(Erl, erl_src_file(Name)).
  372. write_eunitized_src_file(Dir, Name) ->
  373. Erl = filename:join([Dir, "src", "not_a_real_src_" ++ Name ++ ".erl"]),
  374. ok = filelib:ensure_dir(Erl),
  375. ok = ec_file:write(Erl, erl_eunitized_src_file("not_a_real_src_" ++ Name ++ ".erl")).
  376. write_eunit_suite_file(Dir, Name) ->
  377. Erl = filename:join([Dir, "test", "not_a_real_src_" ++ Name ++ "_tests.erl"]),
  378. ok = filelib:ensure_dir(Erl),
  379. ok = ec_file:write(Erl, erl_eunit_suite_file("not_a_real_src_" ++ Name ++ ".erl")).
  380. write_app_file(Dir, Name, Version, Deps) ->
  381. Filename = filename:join([Dir, "ebin", Name ++ ".app"]),
  382. ok = filelib:ensure_dir(Filename),
  383. ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
  384. write_app_src_file(Dir, Name, Version, Deps) ->
  385. Filename = filename:join([Dir, "src", Name ++ ".app.src"]),
  386. ok = filelib:ensure_dir(Filename),
  387. ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
  388. erl_src_file(Name) ->
  389. io_lib:format("-module('~s').\n"
  390. "-export([main/0]).\n"
  391. "main() -> ok.\n", [filename:basename(Name, ".erl")]).
  392. plugin_src_file(Name) ->
  393. io_lib:format("-module('~s').\n"
  394. "-export([init/1]).\n"
  395. "init(State) -> \n"
  396. "Provider = providers:create([\n"
  397. "{name, '~s'},\n"
  398. "{module, '~s'}\n"
  399. "]),\n"
  400. "{ok, rebar_state:add_provider(State, Provider)}.\n", [filename:basename(Name, ".erl"),
  401. filename:basename(Name, ".erl"),
  402. filename:basename(Name, ".erl")]).
  403. erl_eunitized_src_file(Name) ->
  404. io_lib:format("-module('~s').\n"
  405. "-export([main/0]).\n"
  406. "main() -> ok.\n"
  407. "-ifdef(TEST).\n"
  408. "-include_lib(\"eunit/include/eunit.hrl\").\n"
  409. "some_test_() -> ?_assertEqual(ok, main()).\n"
  410. "-endif.\n", [filename:basename(Name, ".erl")]).
  411. erl_eunit_suite_file(Name) ->
  412. BaseName = filename:basename(Name, ".erl"),
  413. io_lib:format("-module('~s_tests').\n"
  414. "-compile(export_all).\n"
  415. "-ifndef(some_define).\n"
  416. "-define(some_define, false).\n"
  417. "-endif.\n"
  418. "-ifdef(TEST).\n"
  419. "-include_lib(\"eunit/include/eunit.hrl\").\n"
  420. "some_test_() -> ?_assertEqual(ok, ~s:main()).\n"
  421. "define_test_() -> ?_assertEqual(true, ?some_define).\n"
  422. "-endif.\n", [BaseName, BaseName]).
  423. get_app_metadata(Name, Vsn, Deps) ->
  424. {application, erlang:list_to_atom(Name),
  425. [{description, ""},
  426. {vsn, Vsn},
  427. {modules, []},
  428. {included_applications, []},
  429. {registered, []},
  430. {applications, Deps}]}.
  431. package_app(AppDir, DestDir, PkgName) ->
  432. Name = PkgName++".tar",
  433. {ok, Fs} = rebar_utils:list_dir(AppDir),
  434. ok = erl_tar:create(filename:join(DestDir, "contents.tar.gz"),
  435. lists:zip(Fs, [filename:join(AppDir,F) || F <- Fs]),
  436. [compressed]),
  437. ok = file:write_file(filename:join(DestDir, "metadata.config"), "who cares"),
  438. ok = file:write_file(filename:join(DestDir, "VERSION"), "3"),
  439. {ok, Contents} = file:read_file(filename:join(DestDir, "contents.tar.gz")),
  440. Blob = <<"3who cares", Contents/binary>>,
  441. <<X:256/big-unsigned>> = crypto:hash(sha256, Blob),
  442. BinChecksum = list_to_binary(string:to_upper(lists:flatten(io_lib:format("~64.16.0b", [X])))),
  443. ok = file:write_file(filename:join(DestDir, "CHECKSUM"), BinChecksum),
  444. PkgFiles = ["contents.tar.gz", "VERSION", "metadata.config", "CHECKSUM"],
  445. Archive = filename:join(DestDir, Name),
  446. ok = erl_tar:create(Archive,
  447. lists:zip(PkgFiles, [filename:join(DestDir,F) || F <- PkgFiles])),
  448. {ok, BinFull} = file:read_file(Archive),
  449. <<E:128/big-unsigned-integer>> = crypto:hash(md5, BinFull),
  450. Etag = string:to_lower(lists:flatten(io_lib:format("~32.16.0b", [E]))),
  451. {BinChecksum, Etag}.