diff options
144 files changed, 106 insertions, 5898 deletions
diff --git a/ebin/rebar.app b/ebin/rebar.app index cc754f9..9b719d3 100644 --- a/ebin/rebar.app +++ b/ebin/rebar.app @@ -9,18 +9,10 @@ rebar_app_info, rebar_app_discover, rebar_base_compiler, - rebar_cleaner, rebar_config, rebar_core, - rebar_cover_utils, - rebar_ct, - rebar_prv_deps, - rebar_prv_install_deps, - rebar_edoc, rebar_erlc_compiler, rebar_erlydtl_compiler, - rebar_escripter, - rebar_eunit, rebar_fetch, rebar_file_utils, rebar_log, @@ -28,21 +20,22 @@ rebar_otp_app, rebar_provider, rebar_packages, + rebar_prv_deps, + rebar_prv_install_deps, rebar_prv_app_builder, rebar_prv_app_discovery, - rebar_require_vsn, + rebar_prv_escripter, rebar_prv_release, rebar_prv_packages, rebar_prv_new, rebar_prv_update, - rebar_mustache, rebar_prv_shell, - rebar_state, rebar_prv_tar, + rebar_mustache, + rebar_state, rebar_templater, rebar_topo, - rebar_utils, - rebar_getopt]}, + rebar_utils]}, {registered, []}, {applications, [kernel, stdlib, @@ -59,7 +52,7 @@ {log_level, warn}, %% any_dir processing modules - {providers, [rebar_escripter, + {providers, [rebar_prv_escripter, rebar_prv_deps, rebar_prv_install_deps, rebar_prv_packages, @@ -67,7 +60,6 @@ rebar_prv_app_builder, rebar_prv_app_discovery, rebar_prv_shell, - rebar_ct, rebar_prv_tar, rebar_prv_new, rebar_prv_update, diff --git a/inttest/bug_5_rt.erl b/inttest/bug_5_rt.erl deleted file mode 100644 index a06b693..0000000 --- a/inttest/bug_5_rt.erl +++ /dev/null @@ -1,29 +0,0 @@ --module(bug_5_rt). - --compile(export_all). - - -files() -> - [{create, "ebin/a1.app", app(a1)}, - {create, "deps/d1/src/d1.app.src", app(d1)}, - {create, "rebar.config", - <<"{deps, [{d1, \"1\", {hg, \"http://example.com\", \"tip\"}}]}.\n">>}, - {copy, "../rebar", "rebar"}]. - -run(_Dir) -> - {ok, _} = retest:sh("./rebar compile"), - ok. - - - -%% -%% Generate the contents of a simple .app file -%% -app(Name) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, []}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl b/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl deleted file mode 100644 index d884bcc..0000000 --- a/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl +++ /dev/null @@ -1,19 +0,0 @@ --module(code_path_no_recurse_rt). --export([files/0, - run/1]). - -files() -> - [ - {copy, "../../rebar", "rebar"}, - {copy, "rebar.config", "rebar.config"}, - {copy, "src", "src"}, - {copy, "test", "test"}, - {copy, "deps", "deps"} - ]. - -run(_Dir) -> - retest:log(info, "Compile project~n"), - {ok, _} = retest:sh("./rebar -v compile"), - retest:log(info, "Run eunit with referenced deps on the code path~n"), - {ok, _} = retest:sh("./rebar -v eunit"), - ok. diff --git a/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src b/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src deleted file mode 100644 index 7f7b3f9..0000000 --- a/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application, bazdep, - [ - {description, ""}, - {vsn, "1"}, - {registered, []}, - {applications, [ - kernel, - stdlib - ]}, - {mod, {bazdep, []}}, - {env, []} - ]}. diff --git a/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl b/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl deleted file mode 100644 index aef4cf3..0000000 --- a/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(bazdep). - --export([bazdep/0]). - -bazdep() -> - bazdep. diff --git a/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl b/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl deleted file mode 100644 index b5190f6..0000000 --- a/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(bazdep_tests). --include_lib("eunit/include/eunit.hrl"). - -bazdep_test() -> - ?assert(bazdep:bazdep() =:= bazdep). diff --git a/inttest/code_path_no_recurse/deps/foodep/rebar.config b/inttest/code_path_no_recurse/deps/foodep/rebar.config deleted file mode 100644 index cdaf168..0000000 --- a/inttest/code_path_no_recurse/deps/foodep/rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{bazdep, "1"}]}. diff --git a/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src b/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src deleted file mode 100644 index c0642fb..0000000 --- a/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application, foodep, - [ - {description, ""}, - {vsn, "1"}, - {registered, []}, - {applications, [ - kernel, - stdlib - ]}, - {mod, {foodep, []}}, - {env, []} - ]}. diff --git a/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl b/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl deleted file mode 100644 index 3d43d0e..0000000 --- a/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(foodep). - --export([foodep/0]). - -foodep() -> - bazdep:bazdep() =:= bazdep. diff --git a/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl b/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl deleted file mode 100644 index 66d7b8b..0000000 --- a/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(foodep_tests). --include_lib("eunit/include/eunit.hrl"). - -foodep_test() -> - ?assert(foodep:foodep()). diff --git a/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src b/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src deleted file mode 100644 index d0bc233..0000000 --- a/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application, unuseddep, - [ - {description, ""}, - {vsn, "1"}, - {registered, []}, - {applications, [ - kernel, - stdlib - ]}, - {mod, {unuseddep, []}}, - {env, []} - ]}. diff --git a/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl b/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl deleted file mode 100644 index a990345..0000000 --- a/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(unuseddep). - --export([unuseddep/0]). - -unuseddep() -> - unuseddep. diff --git a/inttest/code_path_no_recurse/rebar.config b/inttest/code_path_no_recurse/rebar.config deleted file mode 100644 index 4b358de..0000000 --- a/inttest/code_path_no_recurse/rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{foodep, "1"}]}. diff --git a/inttest/code_path_no_recurse/src/codepath.app.src b/inttest/code_path_no_recurse/src/codepath.app.src deleted file mode 100644 index 3aa200f..0000000 --- a/inttest/code_path_no_recurse/src/codepath.app.src +++ /dev/null @@ -1,12 +0,0 @@ -{application, codepath, - [ - {description, ""}, - {vsn, "1"}, - {registered, []}, - {applications, [ - kernel, - stdlib - ]}, - {mod, {codepath, []}}, - {env, []} - ]}. diff --git a/inttest/code_path_no_recurse/src/codepath.erl b/inttest/code_path_no_recurse/src/codepath.erl deleted file mode 100644 index df4e6b0..0000000 --- a/inttest/code_path_no_recurse/src/codepath.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(codepath). - --export([codepath/0]). - -codepath() -> - foodep:foodep(). diff --git a/inttest/code_path_no_recurse/test/codepath_tests.erl b/inttest/code_path_no_recurse/test/codepath_tests.erl deleted file mode 100644 index 01a1d2a..0000000 --- a/inttest/code_path_no_recurse/test/codepath_tests.erl +++ /dev/null @@ -1,12 +0,0 @@ --module(codepath_tests). --include_lib("eunit/include/eunit.hrl"). - -codepath_test() -> - ?assertEqual({module, codepath}, code:ensure_loaded(codepath)), - ?assertEqual({module, foodep}, code:ensure_loaded(foodep)), - ?assertEqual({module, bazdep}, code:ensure_loaded(bazdep)), - ?assert(codepath:codepath()). - -unuseddep_test() -> - ?assertEqual(non_existing, code:which(unuseddep)), - ?assertEqual({error, nofile}, code:ensure_loaded(unuseddep)). diff --git a/inttest/ct1/app.config b/inttest/ct1/app.config deleted file mode 100644 index bb718b2..0000000 --- a/inttest/ct1/app.config +++ /dev/null @@ -1,2 +0,0 @@ -%% This file is an application config file, not a CT test config file -[{a1, [{foo, bar}]}]. diff --git a/inttest/ct1/ct1_rt.erl b/inttest/ct1/ct1_rt.erl deleted file mode 100644 index f9de372..0000000 --- a/inttest/ct1/ct1_rt.erl +++ /dev/null @@ -1,30 +0,0 @@ --module(ct1_rt). - --compile(export_all). - - -files() -> - [{create, "ebin/a1.app", app(a1)}, - {copy, "../../rebar", "rebar"}, - {copy, "rebar.config", "rebar.config"}, - {copy, "app.config", "app.config"}, - {copy, "test_SUITE.erl", "itest/test_SUITE.erl"}]. - -run(_Dir) -> - {ok, _} = retest:sh("./rebar compile ct"), - {ok, _} = retest:sh("./rebar compile ct -v"), - ok. - - - -%% -%% Generate the contents of a simple .app file -%% -app(Name) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, []}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/ct1/rebar.config b/inttest/ct1/rebar.config deleted file mode 100644 index 58047ba..0000000 --- a/inttest/ct1/rebar.config +++ /dev/null @@ -1,2 +0,0 @@ -{ct_dir, "itest"}. -{ct_extra_params, "-repeat 2 -erl_args -config app"}. diff --git a/inttest/ct1/test_SUITE.erl b/inttest/ct1/test_SUITE.erl deleted file mode 100644 index e8a2bb8..0000000 --- a/inttest/ct1/test_SUITE.erl +++ /dev/null @@ -1,17 +0,0 @@ --module(test_SUITE). - --compile(export_all). - --include_lib("ct.hrl"). - -all() -> - [simple_test, - app_config_file_test]. - -simple_test(Config) -> - io:format("Test: ~p\n", [Config]). - -app_config_file_test(_Config) -> - application:start(a1), - {ok, bar} = application:get_env(a1, foo), - application:stop(a1). diff --git a/inttest/ct2/ct2_rt.erl b/inttest/ct2/ct2_rt.erl deleted file mode 100644 index ecab0e4..0000000 --- a/inttest/ct2/ct2_rt.erl +++ /dev/null @@ -1,26 +0,0 @@ --module(ct2_rt). - --compile(export_all). - - -files() -> - [{create, "ebin/foo.app", app(foo)}, - {copy, "../../rebar", "rebar"}, - {copy, "foo.test.spec", "foo.test.spec"}, - {copy, "foo_SUITE.erl", "test/foo_SUITE.erl"}]. - -run(_Dir) -> - {ok, _} = retest:sh("./rebar compile ct -vvv"), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, []}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/ct2/foo.test.spec b/inttest/ct2/foo.test.spec deleted file mode 100644 index f3e4cb0..0000000 --- a/inttest/ct2/foo.test.spec +++ /dev/null @@ -1 +0,0 @@ -{suites, "test", all}. diff --git a/inttest/ct2/foo_SUITE.erl b/inttest/ct2/foo_SUITE.erl deleted file mode 100644 index d03aedf..0000000 --- a/inttest/ct2/foo_SUITE.erl +++ /dev/null @@ -1,10 +0,0 @@ --module(foo_SUITE). - --include_lib("common_test/include/ct.hrl"). - --compile(export_all). - -all() -> [foo]. - -foo(Config) -> - io:format("Test: ~p\n", [Config]). diff --git a/inttest/depplugins/base_dir_cwd_plugin.erl b/inttest/depplugins/base_dir_cwd_plugin.erl deleted file mode 100644 index 4953b8b..0000000 --- a/inttest/depplugins/base_dir_cwd_plugin.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(base_dir_cwd_plugin). --export([pre_compile/2]). - -pre_compile(_, _) -> - File = "base_dir_cwd_pre.compile", - ok = file:write_file(File, <<"base_dir cwd pre_compile plugin">>), - rebar_log:log(info, "Wrote ~p/~s~n", [rebar_utils:get_cwd(), File]). diff --git a/inttest/depplugins/dep_cwd_plugin.erl b/inttest/depplugins/dep_cwd_plugin.erl deleted file mode 100644 index fe1ceba..0000000 --- a/inttest/depplugins/dep_cwd_plugin.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(dep_cwd_plugin). --export([pre_compile/2]). - -pre_compile(_, _) -> - File = "dep_cwd_pre.compile", - ok = file:write_file(File, <<"dep cwd pre_compile plugin">>), - rebar_log:log(info, "Wrote ~p/~s~n", [rebar_utils:get_cwd(), File]). diff --git a/inttest/depplugins/depplugins_rt.erl b/inttest/depplugins/depplugins_rt.erl deleted file mode 100644 index a45fa93..0000000 --- a/inttest/depplugins/depplugins_rt.erl +++ /dev/null @@ -1,69 +0,0 @@ -%%% @doc Plugin handling test -%%% -%%% This test checks if plugins are loaded correctly. -%%% -%%% It has three applications: -%%% <ol> -%%% <li>fish. top-level app, has one dependency: `dependsonplugin'. -%%% It also loads a plugin from CWD which creates -%%% base_dir_cwd_pre.compile on pre_compile.</li> -%%% <li>dependsonplugin, has one dependency: `testplugin' and loads -%%% the testplugin_mod plugin.</li> -%%% <li>testplugin. This is a plugin application which creates -%%% plugin_pre.compile on pre_compile. It also loads a plugin from CWD -%%% which creates dep_cwd_pre.compile on pre_compile.</li> -%%% </ol> - --module(depplugins_rt). --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - -files() -> - [ - {copy, "../../rebar", "rebar"}, - {copy, "rebar.config", "rebar.config"}, - {copy, "base_dir_cwd_plugin.erl", "base_dir_cwd_plugin.erl"}, - {create, "ebin/fish.app", app(fish, [])}, - - {copy, "rebar_dependsonplugin.config", - "deps/dependsonplugin/rebar.config"}, - {create, "deps/dependsonplugin/ebin/dependsonplugin.app", - app(dependsonplugin, [])}, - - {copy, "rebar_testplugin.config", "deps/testplugin/rebar.config"}, - {copy, "testplugin_mod.erl", - "deps/testplugin/plugins/testplugin_mod.erl"}, - {copy, "dep_cwd_plugin.erl", "deps/testplugin/dep_cwd_plugin.erl"}, - {create, "deps/testplugin/ebin/testplugin.app", app(testplugin, [])} - ]. - -run(_Dir) -> - ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])), - - ?assertEqual(true, filelib:is_regular("base_dir_cwd_pre.compile")), - - ?assertEqual(true, filelib:is_regular( - "deps/dependsonplugin/base_dir_cwd_pre.compile")), - ?assertEqual(true, filelib:is_regular( - "deps/dependsonplugin/plugin_pre.compile")), - - ?assertEqual(true, filelib:is_regular( - "deps/testplugin/base_dir_cwd_pre.compile")), - ?assertEqual(true, filelib:is_regular( - "deps/testplugin/dep_cwd_pre.compile")), - ?assertEqual(true, filelib:is_regular( - "deps/testplugin/plugin_pre.compile")), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/depplugins/rebar.config b/inttest/depplugins/rebar.config deleted file mode 100644 index 86fb037..0000000 --- a/inttest/depplugins/rebar.config +++ /dev/null @@ -1,2 +0,0 @@ -{deps, [dependsonplugin]}. -{plugins, [base_dir_cwd_plugin]}. diff --git a/inttest/depplugins/rebar_dependsonplugin.config b/inttest/depplugins/rebar_dependsonplugin.config deleted file mode 100644 index df36213..0000000 --- a/inttest/depplugins/rebar_dependsonplugin.config +++ /dev/null @@ -1,2 +0,0 @@ -{deps, [testplugin]}. -{plugins, [testplugin_mod]}. diff --git a/inttest/depplugins/rebar_testplugin.config b/inttest/depplugins/rebar_testplugin.config deleted file mode 100644 index 58a1f99..0000000 --- a/inttest/depplugins/rebar_testplugin.config +++ /dev/null @@ -1 +0,0 @@ -{plugins, [dep_cwd_plugin]}. diff --git a/inttest/depplugins/testplugin_mod.erl b/inttest/depplugins/testplugin_mod.erl deleted file mode 100644 index d829ff0..0000000 --- a/inttest/depplugins/testplugin_mod.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(testplugin_mod). --export([pre_compile/2]). - -pre_compile(_, _) -> - File = "plugin_pre.compile", - ok = file:write_file(File, <<"Yadda!">>), - rebar_log:log(info, "Wrote ~p/~s~n", [rebar_utils:get_cwd(), File]). diff --git a/inttest/erlc/asn1/SIMPLE-ASN.asn1 b/inttest/erlc/asn1/SIMPLE-ASN.asn1 deleted file mode 100644 index 62f0860..0000000 --- a/inttest/erlc/asn1/SIMPLE-ASN.asn1 +++ /dev/null @@ -1,7 +0,0 @@ -SIMPLE-ASN DEFINITIONS ::= BEGIN - - SimpleMessage ::= SEQUENCE { - id INTEGER - } - -END diff --git a/inttest/erlc/erlc_rt.erl b/inttest/erlc/erlc_rt.erl deleted file mode 100644 index 50cdb83..0000000 --- a/inttest/erlc/erlc_rt.erl +++ /dev/null @@ -1,137 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et --module(erlc_rt). --export([files/0, - run/1]). - --include_lib("eunit/include/eunit.hrl"). - --define(MODULES, - [first_xrl, - first_yrl, - first_erl, - foo, - foo_app, - foo_sup, - foo_test_worker, - foo_worker, - 'SIMPLE-ASN']). - --define(BEAM_FILES, - ["first_xrl.beam", - "first_yrl.beam", - "first_erl.beam", - "foo.beam", - "foo_app.beam", - "foo_sup.beam", - "foo_test_worker.beam", - "foo_worker.beam", - "SIMPLE-ASN.beam"]). - -files() -> - [ - {copy, "../../rebar", "rebar"}, - {copy, "rebar.config", "rebar.config"}, - {copy, "rebar-no_debug_info.config", "rebar-no_debug_info.config"}, - {copy, "include", "include"}, - {copy, "extra-include", "extra-include"}, - {copy, "src", "src"}, - {copy, "extra-src", "extra-src"}, - {copy, "mibs", "mibs"}, - {copy, "asn1", "asn1"}, - {create, "ebin/foo.app", app(foo, ?MODULES)}, - %% deps - {create, "deps/foobar/ebin/foobar.app", app(foobar, [foobar])}, - {copy, "foobar.erl", "deps/foobar/src/foobar.erl"} - ]. - -run(_Dir) -> - ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])), - ok = check_beams(true), - ok = check_debug_info(true), - MibResult = filename:join(["priv", "mibs", "SIMPLE-MIB.bin"]), - ?assertMatch(true, filelib:is_regular(MibResult)), - ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])), - ok = check_beams(false), - ?assertMatch(false, filelib:is_regular(MibResult)), - ?assertMatch( - {ok, _}, - retest_sh:run("./rebar -C rebar-no_debug_info.config compile", [])), - ok = check_beams(true), - ok = check_debug_info(false), - ?assertMatch(true, filelib:is_regular(MibResult)), - %% Regression test for https://github.com/rebar/rebar/issues/249 - %% - %% Root cause: We didn't have per-project .rebar/erlcinfo but just one in - %% <base_dir>/.rebar/erlcinfo. - %% - %% Solution: Ensure every project has its own .rebar/erlcinfo - %% - %% For the bug to happen, the following conditions must be met: - %% - %% 1. <base_dir>/rebar.config has erl_first_files - %% 2. one of the 'first' files depends on another file (in this - %% case via -include_lib()) - %% 3. a sub project's rebar.config, if any, has no erl_first_files entry - %% - %% Now because erl_first_files is retrieved via rebar_config:get_list/3, - %% base_dir/rebar.config's erl_first_files is inherited, and because we had - %% a shared <base_dir>/.rebar/erlcinfo instead of one per project, the - %% cached entry was reused. Next, while compiling the sub project - %% rebar_erlc_compiler:needs_compile/3 gets a last modification time of - %% zero for the 'first' file which does not exist inside the sub project. - %% This, and the fact that it has at least one dependency, makes - %% needs_compile/3 return 'true'. The root cause is that we didn't have per - %% project .rebar/erlcinfo. For <base_dir>/.rebar/erlcinfo to be populated, - %% base_dir has to be compiled at least once. Therefore, after the first - %% compile any compile processing the sub project will fail because - %% needs_compile/3 will always return true for the non-existent 'first' - %% file. - ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])), - ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])), - ok = check_beams(true), - ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])), - ok = check_beams(true), - ok. - -check_beams(Exist) -> - check_files(Exist, fun filelib:is_regular/1). - -check_debug_info(HasDebugInfo) -> - check_files(HasDebugInfo, fun has_debug_info/1). - -check_files(Expected, Check) -> - lists:foreach( - fun(F) -> - File = filename:join("ebin", F), - ?assertEqual(Expected, Check(File)) - end, - ?BEAM_FILES). - -%% NOTE: Copied from dialyzer_utils:get_abstract_code_from_beam/1 and -%% modified for local use. We could have called the function directly, -%% but dialyzer_utils is not an official API to rely on. -has_debug_info(File) -> - case beam_lib:chunks(File, [abstract_code]) of - {ok, {_Mod, List}} -> - case lists:keyfind(abstract_code, 1, List) of - {abstract_code, {raw_abstract_v1, _Abstr}} -> - true; - _ -> - false - end; - _ -> - false - end. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/erlc/extra-include/foo_extra.hrl b/inttest/erlc/extra-include/foo_extra.hrl deleted file mode 100644 index 19e9f94..0000000 --- a/inttest/erlc/extra-include/foo_extra.hrl +++ /dev/null @@ -1,3 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et --define(FOO_EXTRA, foo_extra). diff --git a/inttest/erlc/extra-src/foo_sup.erl b/inttest/erlc/extra-src/foo_sup.erl deleted file mode 100644 index c68194e..0000000 --- a/inttest/erlc/extra-src/foo_sup.erl +++ /dev/null @@ -1,15 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et --module(foo_sup). - --behavior(supervisor). - --export([start_link/0, - init/1]). - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -init(_Args) -> - FooChild = {foo,{foo, start_link, []}, permanent, 5000, worker, [foo]}, - {ok,{{one_for_all,1,1}, [FooChild]}}. diff --git a/inttest/erlc/foobar.erl b/inttest/erlc/foobar.erl deleted file mode 100644 index b6d55a8..0000000 --- a/inttest/erlc/foobar.erl +++ /dev/null @@ -1,8 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et --module(foobar). - --export([test/0]). - -test() -> - true. diff --git a/inttest/erlc/include/foo_core.hrl b/inttest/erlc/include/foo_core.hrl deleted file mode 100644 index 803f2f0..0000000 --- a/inttest/erlc/include/foo_core.hrl +++ /dev/null @@ -1,3 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et --define(FOO_CORE, foo_core). diff --git a/inttest/erlc/mibs/SIMPLE-MIB.mib b/inttest/erlc/mibs/SIMPLE-MIB.mib deleted file mode 100644 index ca8735a..0000000 --- a/inttest/erlc/mibs/SIMPLE-MIB.mib +++ /dev/null @@ -1,26 +0,0 @@ --- SIMPLE-MIB. --- This is just a simple MIB used for testing! --- - - -SIMPLE-MIB DEFINITIONS ::= BEGIN - -IMPORTS - MODULE-IDENTITY, enterprises - FROM SNMPv2-SMI; - -ericsson MODULE-IDENTITY - LAST-UPDATED - "201403060000Z" - ORGANIZATION - "rebar" - CONTACT-INFO - "rebar <rebar@example.com> - or - whoever is currently responsible for the SIMPLE - enterprise MIB tree branch (enterprises.999)." - DESCRIPTION - "This very small module is made available - for mib-compilation testing." - ::= { enterprises 999 } -END diff --git a/inttest/erlc/rebar-no_debug_info.config b/inttest/erlc/rebar-no_debug_info.config deleted file mode 100644 index 07b6fed..0000000 --- a/inttest/erlc/rebar-no_debug_info.config +++ /dev/null @@ -1,11 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et -{erl_first_files, ["src/first_xrl.erl", "src/first_yrl.erl"]}. - -{erl_opts, - [ - no_debug_info, - {i, "extra-include"}, - {src_dirs, ["src", "extra-src"]}, - {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'} - ]}. diff --git a/inttest/erlc/rebar.config b/inttest/erlc/rebar.config deleted file mode 100644 index 71d6660..0000000 --- a/inttest/erlc/rebar.config +++ /dev/null @@ -1,13 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et -{erl_first_files, - ["src/first_xrl.erl", "src/first_yrl.erl", "src/first_erl.erl"]}. - -{deps, [foobar]}. - -{erl_opts, - [ - {i, "extra-include"}, - {src_dirs, ["src", "extra-src"]}, - {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'} - ]}. diff --git a/inttest/erlc/src/._do_not_compile.erl b/inttest/erlc/src/._do_not_compile.erl deleted file mode 100644 index c9d743b..0000000 --- a/inttest/erlc/src/._do_not_compile.erl +++ /dev/null @@ -1,4 +0,0 @@ -syntax error -this is file is here to verify that rebar does not try to -compile files like OS X resource forks and should not be -processed at all diff --git a/inttest/erlc/src/behaviour/foo_worker.erl b/inttest/erlc/src/behaviour/foo_worker.erl deleted file mode 100644 index 307c69a..0000000 --- a/inttest/erlc/src/behaviour/foo_worker.erl +++ /dev/null @@ -1,14 +0,0 @@ --module(foo_worker). - --ifdef(NO_CALLBACK_ATTRIBUTE). - --export([behaviour_info/1]). - -behaviour_info(callbacks) -> [{status, 0}]; -behaviour_info(_) -> undefined. - --else. - --callback status() -> 'idle' | 'busy'. - --endif. diff --git a/inttest/erlc/src/first_erl.erl b/inttest/erlc/src/first_erl.erl deleted file mode 100644 index 4e9ff20..0000000 --- a/inttest/erlc/src/first_erl.erl +++ /dev/null @@ -1,10 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 ft=erlang et --module(first_erl). - --include_lib("eunit/include/eunit.hrl"). - --export([test/0]). - -test() -> - ?debugHere. diff --git a/inttest/erlc/src/first_xrl.xrl b/inttest/erlc/src/first_xrl.xrl deleted file mode 100644 index 0de4c70..0000000 --- a/inttest/erlc/src/first_xrl.xrl +++ /dev/null @@ -1,13 +0,0 @@ -Definitions. - -D = [0-9] - -Rules. - -{D}+ : - {token,{integer,TokenLine,list_to_integer(TokenChars)}}. - -{D}+\.{D}+((E|e)(\+|\-)?{D}+)? : - {token,{float,TokenLine,list_to_float(TokenChars)}}. - -Erlang code. diff --git a/inttest/erlc/src/first_yrl.yrl b/inttest/erlc/src/first_yrl.yrl deleted file mode 100644 index 8ccdb0e..0000000 --- a/inttest/erlc/src/first_yrl.yrl +++ /dev/null @@ -1,9 +0,0 @@ -Nonterminals list elements element. -Terminals atom '(' ')'. -Rootsymbol list. -list -> '(' ')'. -list -> '(' elements ')'. -elements -> element. -elements -> element elements. -element -> atom. -element -> list. diff --git a/inttest/erlc/src/foo.erl b/inttest/erlc/src/foo.erl deleted file mode 100644 index 33e6cfc..0000000 --- a/inttest/erlc/src/foo.erl +++ /dev/null @@ -1,35 +0,0 @@ --module(foo). - --export([start_link/0, - start_link/1, - init/1, - terminate/2, - handle_info/2, - handle_call/3, - handle_cast/2, - code_change/3]). - --behavior(gen_server). - --include("foo_core.hrl"). --include("foo_extra.hrl"). --include_lib("kernel/include/file.hrl"). - --record(state, {node :: node()}). - -start_link() -> start_link(undefined). - -start_link(Args) -> - gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []). - -init(_Args) -> {ok, #state{node=node()}}. - -terminate(_Reason, _Data) -> ok. - -handle_info(_Info, State) -> {noreply, State}. - -handle_cast(_Msg, State) -> {noreply, State}. - -handle_call(_Msg, _From, State) -> {reply, ok, State}. - -code_change(_OldVsn, State, _Extra) -> {ok, State}. diff --git a/inttest/erlc/src/foo_app.erl b/inttest/erlc/src/foo_app.erl deleted file mode 100644 index a3c7a96..0000000 --- a/inttest/erlc/src/foo_app.erl +++ /dev/null @@ -1,10 +0,0 @@ --module(foo_app). - --behaviour(application). - --export([start/2, - stop/1]). - -start(_Type, _Args) -> foo_sup:start_link(). - -stop(_State) -> ok. diff --git a/inttest/erlc/src/foo_test_worker.erl b/inttest/erlc/src/foo_test_worker.erl deleted file mode 100644 index 96ae932..0000000 --- a/inttest/erlc/src/foo_test_worker.erl +++ /dev/null @@ -1,34 +0,0 @@ --module(foo_test_worker). - --behaviour(gen_server). --behaviour(foo_worker). - --export([start_link/0, - start_link/1, - init/1, - handle_call/3, - handle_cast/2, - handle_info/2, - terminate/2, - code_change/3, - status/0]). - --include_lib("kernel/include/inet.hrl"). - -start_link() -> start_link(undefined). - -start_link(Args) -> gen_server:start_link(?MODULE, Args, []). - -init([]) -> {ok, undefined}. - -handle_call(_Event, _From, State) -> {reply, ok, State}. - -handle_cast(_Event, State) -> {noreply, State}. - -handle_info(_Info, State) -> {noreply, State}. - -terminate(_Reason, _State) -> ok. - -code_change(_OldVsn, State, _Extra) -> {ok, State}. - -status() -> busy. diff --git a/inttest/eunit/eunit_rt.erl b/inttest/eunit/eunit_rt.erl deleted file mode 100644 index 47f3331..0000000 --- a/inttest/eunit/eunit_rt.erl +++ /dev/null @@ -1,48 +0,0 @@ --module(eunit_rt). --export([files/0, run/1]). - --include_lib("eunit/include/eunit.hrl"). - -files() -> - [{create, "ebin/foo.app", app(foo)}, - {copy, "../../rebar", "rebar"}, - {copy, "src", "src"}, - {copy, "eunit_src", "eunit_src"}, - {copy, - "rebar-eunit_compile_opts.config", - "rebar-eunit_compile_opts.config"}]. - -run(_Dir) -> - ifdef_test(), - eunit_compile_opts_test(), - ok. - -ifdef_test() -> - {ok, Output} = retest:sh("./rebar -v eunit"), - ?assert(check_output(Output, "foo_test")), - ?assertMatch({ok, _}, retest:sh("./rebar clean")). - -eunit_compile_opts_test() -> - {ok, Output} = - retest:sh("./rebar -v -C rebar-eunit_compile_opts.config eunit"), - ?assert(check_output(Output, "bar_test")), - ?assertMatch( - {ok, _}, - retest:sh("./rebar -C rebar-eunit_compile_opts.config clean")). - -check_output(Output, Target) -> - lists:any(fun(Line) -> - string:str(Line, Target) > 0 - end, Output). - -%% -%% Generate the contents of a simple .app file -%% -app(Name) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, []}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/eunit/eunit_src/bar.erl b/inttest/eunit/eunit_src/bar.erl deleted file mode 100644 index 6a80dac..0000000 --- a/inttest/eunit/eunit_src/bar.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(bar). - --include_lib("eunit/include/eunit.hrl"). - -bar_test() -> - ?assert(true). diff --git a/inttest/eunit/rebar-eunit_compile_opts.config b/inttest/eunit/rebar-eunit_compile_opts.config deleted file mode 100644 index 13b2d94..0000000 --- a/inttest/eunit/rebar-eunit_compile_opts.config +++ /dev/null @@ -1 +0,0 @@ -{eunit_compile_opts, [{src_dirs, ["eunit_src"]}]}. diff --git a/inttest/eunit/src/foo.erl b/inttest/eunit/src/foo.erl deleted file mode 100644 index a4c91ba..0000000 --- a/inttest/eunit/src/foo.erl +++ /dev/null @@ -1,10 +0,0 @@ --module(foo). - --ifdef(TEST). - --include_lib("eunit/include/eunit.hrl"). - -foo_test() -> - ?assert(true). - --endif. diff --git a/inttest/logging/logging_rt.erl b/inttest/logging/logging_rt.erl deleted file mode 100644 index 2b8e54b..0000000 --- a/inttest/logging/logging_rt.erl +++ /dev/null @@ -1,99 +0,0 @@ --module(logging_rt). --export([files/0, - run/1]). - --define(APP_FILE, "ebin/logging.app"). - -files() -> - [ - {copy, "../../rebar", "rebar"}, - {create, ?APP_FILE, app(invalid_name, [])} - ]. - -run(_Dir) -> - SharedExpected = "==> logging_rt \\(compile\\)", - %% provoke ERROR due to an invalid app file - retest:log(info, "Check 'compile' failure output~n"), - ok = check_output("./rebar compile -q", should_fail, - [SharedExpected, "ERROR: "], - ["WARN: ", "INFO: ", "DEBUG: "]), - %% fix bad app file - ok = file:write_file(?APP_FILE, app(logging, [])), - retest:log(info, "Check 'compile' success output~n"), - ok = check_output("./rebar compile", should_succeed, - [SharedExpected], - ["ERROR: ", "WARN: ", "INFO: ", "DEBUG: "]), - retest:log(info, "Check 'compile -v' success output~n"), - ok = check_output("./rebar compile -v", should_succeed, - [SharedExpected], - ["ERROR: ", "INFO: ", "DEBUG: "]), - retest:log(info, "Check 'compile -vv' success output~n"), - ok = check_output("./rebar compile -vv", should_succeed, - [SharedExpected, "DEBUG: "], - ["ERROR: ", "INFO: "]), - ok. - -check_output(Cmd, FailureMode, Expected, Unexpected) -> - case {retest:sh(Cmd), FailureMode} of - {{error, _}=Error, should_succeed} -> - retest:log(error, "cmd '~s' failed:~n~p~n", [Cmd, Error]), - Error; - {{ok, Captured}, should_succeed} -> - Joined = string:join(Captured, "\n"), - check_output1(Cmd, Joined, Expected, Unexpected); - {{error, {stopped, {_Rc, Captured}}}, should_fail} -> - Joined = string:join(Captured, "\n"), - check_output1(Cmd, Joined, Expected, Unexpected) - end. - -check_output1(Cmd, Captured, Expected, Unexpected) -> - ReOpts = [{capture, all, list}], - ExMatches = - lists:zf( - fun(Pattern) -> - case re:run(Captured, Pattern, ReOpts) of - nomatch -> - retest:log(error, - "Expected pattern '~s' missing " - "in the following output:~n" - "=== BEGIN ===~n~s~n=== END ===~n", - [Pattern, Captured]), - {true, Pattern}; - {match, _} -> - false - end - end, Expected), - - UnExMatches = - lists:zf( - fun(Pattern) -> - case re:run(Captured, Pattern, ReOpts) of - nomatch -> - false; - {match, [Match]} -> - retest:log( - console, - "Unexpected output when running cmd '~s':~n~s~n", - [Cmd, Match]), - {true, Match} - end - end, Unexpected), - - case {ExMatches, UnExMatches} of - {[], []} -> - ok; - _ -> - error - end. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/rgen1/reltool.config b/inttest/rgen1/reltool.config deleted file mode 100644 index 4c4713c..0000000 --- a/inttest/rgen1/reltool.config +++ /dev/null @@ -1,31 +0,0 @@ -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -{sys, [ - {rel, "rgen1", "0.1", - [ - kernel, - stdlib, - sasl, - crypto - ]}, - {rel, "start_clean", "", - [ - kernel, - stdlib - ]}, - {boot_rel, "rgen1"}, - {profile, embedded}, - {excl_sys_filters, ["^bin/.*", - "^erts.*/bin/(dialyzer|typer)"]}, - {excl_archive_filters, [".*"]}, - {app, sasl, [{incl_cond, include}]} - ]}. - -{target_dir, "mytarget"}. - -{overlay_vars, "vars.config"}. - -{overlay, [ - {mkdir, "data"}, - {template, "test.config", "etc/test.config"} - ]}. diff --git a/inttest/rgen1/retest.config b/inttest/rgen1/retest.config deleted file mode 100644 index b569f14..0000000 --- a/inttest/rgen1/retest.config +++ /dev/null @@ -1 +0,0 @@ -{timeout, 120000}. diff --git a/inttest/rgen1/rgen1_rt.erl b/inttest/rgen1/rgen1_rt.erl deleted file mode 100644 index 68b6eaf..0000000 --- a/inttest/rgen1/rgen1_rt.erl +++ /dev/null @@ -1,18 +0,0 @@ --module(rgen1_rt). - --compile(export_all). - -%% Exercise release generation w/ templating - -files() -> - [ - {copy, "reltool.config"}, - {copy, "test.config"}, - {copy, "vars.config"}, - {copy, "../../rebar"} - ]. - -run(_Dir) -> - {ok, _} = retest_sh:run("./rebar -v generate", []), - true = filelib:is_dir("mytarget"), - ok. diff --git a/inttest/rgen1/test.config b/inttest/rgen1/test.config deleted file mode 100644 index 2fd1385..0000000 --- a/inttest/rgen1/test.config +++ /dev/null @@ -1 +0,0 @@ -{web_port, {{web_port}} }. diff --git a/inttest/rgen1/vars.config b/inttest/rgen1/vars.config deleted file mode 100644 index 174c51e..0000000 --- a/inttest/rgen1/vars.config +++ /dev/null @@ -1 +0,0 @@ -{web_port, 1234}. diff --git a/inttest/t_custom_config/custom.config b/inttest/t_custom_config/custom.config deleted file mode 100644 index 711c27f..0000000 --- a/inttest/t_custom_config/custom.config +++ /dev/null @@ -1,4 +0,0 @@ -{deps, [ - {boo, "."} -]}. -{erl_opts, [warnings_as_errors]}. diff --git a/inttest/t_custom_config/custom_config.erl b/inttest/t_custom_config/custom_config.erl deleted file mode 100644 index 8656201..0000000 --- a/inttest/t_custom_config/custom_config.erl +++ /dev/null @@ -1,6 +0,0 @@ --module(custom_config). - --compile(export_all). - -test() -> - ok. diff --git a/inttest/t_custom_config/t_custom_config_rt.erl b/inttest/t_custom_config/t_custom_config_rt.erl deleted file mode 100644 index b56eb1a..0000000 --- a/inttest/t_custom_config/t_custom_config_rt.erl +++ /dev/null @@ -1,39 +0,0 @@ --module(t_custom_config_rt). - --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - -files() -> - [{copy, "../../rebar", "rebar"}, - {copy, "custom.config", "custom.config"}, - {create, "ebin/custom_config.app", app(custom_config, [custom_config])}]. - -run(Dir) -> - retest_log:log(debug, "Running in Dir: ~s~n", [Dir]), - Ref = retest:sh("./rebar -C custom.config check-deps -vv", - [{async, true}]), - {ok, Captured} = - retest:sh_expect(Ref, - "DEBUG: Consult config file .*/custom.config.*", - [{capture, all, list}]), - {ok, Missing} = - retest:sh_expect(Ref, - "DEBUG: Missing deps : \\[\\{dep,bad_name," - "boo,\"\\.\",undefined,false\\}\\]", - [{capture, all, list}]), - retest_log:log(debug, "[CAPTURED]: ~s~n", [Captured]), - retest_log:log(debug, "[Missing]: ~s~n", [Missing]), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/tdeps1/a.erl b/inttest/tdeps1/a.erl deleted file mode 100644 index 835522a..0000000 --- a/inttest/tdeps1/a.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(a). - --compile(export_all). - --include_lib("b/include/b.hrl"). - -hello() -> - io:format("~s\n", [?HELLO]). diff --git a/inttest/tdeps1/a.rebar.config b/inttest/tdeps1/a.rebar.config deleted file mode 100644 index 991ea5a..0000000 --- a/inttest/tdeps1/a.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{b, "1", {git, "../repo/b"}}]}. diff --git a/inttest/tdeps1/b.hrl b/inttest/tdeps1/b.hrl deleted file mode 100644 index efbeab1..0000000 --- a/inttest/tdeps1/b.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("c/include/c.hrl"). diff --git a/inttest/tdeps1/b.rebar.config b/inttest/tdeps1/b.rebar.config deleted file mode 100644 index ffbd0db..0000000 --- a/inttest/tdeps1/b.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{c, "1", {git, "../repo/c"}}]}. diff --git a/inttest/tdeps1/c.hrl b/inttest/tdeps1/c.hrl deleted file mode 100644 index 9f02fab..0000000 --- a/inttest/tdeps1/c.hrl +++ /dev/null @@ -1 +0,0 @@ --define(HELLO, hello). diff --git a/inttest/tdeps1/tdeps1_rt.erl b/inttest/tdeps1/tdeps1_rt.erl deleted file mode 100644 index a72cc83..0000000 --- a/inttest/tdeps1/tdeps1_rt.erl +++ /dev/null @@ -1,60 +0,0 @@ --module(tdeps1_rt). - --compile(export_all). - -%% Exercise transitive dependencies -%% A -> B -> C, where A includes a .hrl from B which includes .hrl from C - -files() -> - [ - %% A application - {create, "ebin/a.app", app(a, [a])}, - {copy, "a.rebar.config", "rebar.config"}, - {copy, "a.erl", "src/a.erl"}, - {copy, "../../rebar", "rebar"}, - - %% B application - {create, "repo/b/ebin/b.app", app(b, [])}, - {copy, "b.rebar.config", "repo/b/rebar.config"}, - {copy, "b.hrl", "repo/b/include/b.hrl"}, - - %% C application - {create, "repo/c/ebin/c.app", app(c, [])}, - {copy, "c.hrl", "repo/c/include/c.hrl"} - ]. - -apply_cmds([], _Params) -> - ok; -apply_cmds([Cmd | Rest], Params) -> - io:format("Running: ~s (~p)\n", [Cmd, Params]), - {ok, _} = retest_sh:run(Cmd, Params), - apply_cmds(Rest, Params). - -run(_Dir) -> - %% Initialize the b/c apps as git repos so that dependencies pull - %% properly - GitCmds = ["git init", - "git add -A", - "git config user.email 'tdeps@example.com'", - "git config user.name 'tdeps'", - "git commit -a -m 'Initial Commit'"], - apply_cmds(GitCmds, [{dir, "repo/b"}]), - apply_cmds(GitCmds, [{dir, "repo/c"}]), - - {ok, _} = retest_sh:run("./rebar get-deps", []), - {ok, _} = retest_sh:run("./rebar compile", []), - - true = filelib:is_regular("ebin/a.beam"), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/tdeps2/a.erl b/inttest/tdeps2/a.erl deleted file mode 100644 index 294ae21..0000000 --- a/inttest/tdeps2/a.erl +++ /dev/null @@ -1,3 +0,0 @@ --module({{module}}). - --include_lib("b/include/b.hrl"). diff --git a/inttest/tdeps2/a.rebar.config b/inttest/tdeps2/a.rebar.config deleted file mode 100644 index 991ea5a..0000000 --- a/inttest/tdeps2/a.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{b, "1", {git, "../repo/b"}}]}. diff --git a/inttest/tdeps2/b.hrl b/inttest/tdeps2/b.hrl deleted file mode 100644 index efbeab1..0000000 --- a/inttest/tdeps2/b.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("c/include/c.hrl"). diff --git a/inttest/tdeps2/b.rebar.config b/inttest/tdeps2/b.rebar.config deleted file mode 100644 index ffbd0db..0000000 --- a/inttest/tdeps2/b.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{c, "1", {git, "../repo/c"}}]}. diff --git a/inttest/tdeps2/c.hrl b/inttest/tdeps2/c.hrl deleted file mode 100644 index 9f02fab..0000000 --- a/inttest/tdeps2/c.hrl +++ /dev/null @@ -1 +0,0 @@ --define(HELLO, hello). diff --git a/inttest/tdeps2/root.rebar.config b/inttest/tdeps2/root.rebar.config deleted file mode 100644 index 005adfe..0000000 --- a/inttest/tdeps2/root.rebar.config +++ /dev/null @@ -1,2 +0,0 @@ -{sub_dirs, ["apps/a1", - "apps/a2"]}. diff --git a/inttest/tdeps2/tdeps2_rt.erl b/inttest/tdeps2/tdeps2_rt.erl deleted file mode 100644 index 22f0abe..0000000 --- a/inttest/tdeps2/tdeps2_rt.erl +++ /dev/null @@ -1,66 +0,0 @@ --module(tdeps2_rt). - --compile(export_all). - -%% Exercise transitive dependencies where there are multiple files -%% depending on the same set of deps -%% [A1, A2] -> B -> C ; A1 and A2 includes B.hrl which includes C.hrl - -files() -> - [ - %% A1 application - {create, "apps/a1/ebin/a1.app", app(a1, [a1])}, - {copy, "a.rebar.config", "apps/a1/rebar.config"}, - {template, "a.erl", "apps/a1/src/a1.erl", dict:from_list([{module, a1}])}, - - %% A2 application - {create, "apps/a2/ebin/a2.app", app(a2, [a2])}, - {copy, "a.rebar.config", "apps/a2/rebar.config"}, - {template, "a.erl", "apps/a2/src/a2.erl", dict:from_list([{module, a2}])}, - - {copy, "root.rebar.config", "rebar.config"}, - {copy, "../../rebar", "rebar"}, - - %% B application - {create, "repo/b/ebin/b.app", app(b, [])}, - {copy, "b.rebar.config", "repo/b/rebar.config"}, - {copy, "b.hrl", "repo/b/include/b.hrl"}, - - %% C application - {create, "repo/c/ebin/c.app", app(c, [])}, - {copy, "c.hrl", "repo/c/include/c.hrl"} - ]. - -apply_cmds([], _Params) -> - ok; -apply_cmds([Cmd | Rest], Params) -> - io:format("Running: ~s (~p)\n", [Cmd, Params]), - {ok, _} = retest_sh:run(Cmd, Params), - apply_cmds(Rest, Params). - -run(_Dir) -> - %% Initialize the b/c apps as git repos so that dependencies pull - %% properly - GitCmds = ["git init", - "git add -A", - "git config user.email 'tdeps@example.com'", - "git config user.name 'tdeps'", - "git commit -a -m 'Initial Commit'"], - ok = apply_cmds(GitCmds, [{dir, "repo/b"}]), - ok = apply_cmds(GitCmds, [{dir, "repo/c"}]), - - {ok, _} = retest_sh:run("./rebar -v get-deps", []), - {ok, _} = retest_sh:run("./rebar -v compile", []), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/tdeps3/a.erl b/inttest/tdeps3/a.erl deleted file mode 100644 index 5a387eb..0000000 --- a/inttest/tdeps3/a.erl +++ /dev/null @@ -1,3 +0,0 @@ --module({{module}}). - --include_lib("{{dep}}/include/{{dep}}.hrl"). diff --git a/inttest/tdeps3/a.rebar.config b/inttest/tdeps3/a.rebar.config deleted file mode 100644 index 19b8ef8..0000000 --- a/inttest/tdeps3/a.rebar.config +++ /dev/null @@ -1,4 +0,0 @@ -{deps, [ - {b, "1", {git, "../repo/b"}}, - {f, "1", {git, "../repo/f"}} -]}. diff --git a/inttest/tdeps3/b.hrl b/inttest/tdeps3/b.hrl deleted file mode 100644 index efbeab1..0000000 --- a/inttest/tdeps3/b.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("c/include/c.hrl"). diff --git a/inttest/tdeps3/b.rebar.config b/inttest/tdeps3/b.rebar.config deleted file mode 100644 index d1ccae2..0000000 --- a/inttest/tdeps3/b.rebar.config +++ /dev/null @@ -1,5 +0,0 @@ -{deps, [ - {c, "1", {git, "../repo/c"}} -]}. - -{lib_dirs, [apps]}. diff --git a/inttest/tdeps3/c.hrl b/inttest/tdeps3/c.hrl deleted file mode 100644 index cc87fff..0000000 --- a/inttest/tdeps3/c.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("d/include/d.hrl"). diff --git a/inttest/tdeps3/c.rebar.config b/inttest/tdeps3/c.rebar.config deleted file mode 100644 index b590771..0000000 --- a/inttest/tdeps3/c.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{d, "1", {git, "../repo/d"}}]}. diff --git a/inttest/tdeps3/d.hrl b/inttest/tdeps3/d.hrl deleted file mode 100644 index 02f8088..0000000 --- a/inttest/tdeps3/d.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("e/include/e.hrl"). diff --git a/inttest/tdeps3/d.rebar.config b/inttest/tdeps3/d.rebar.config deleted file mode 100644 index 4c7cd54..0000000 --- a/inttest/tdeps3/d.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{e, "1", {git, "../repo/e"}}]}. diff --git a/inttest/tdeps3/e.hrl b/inttest/tdeps3/e.hrl deleted file mode 100644 index 9f02fab..0000000 --- a/inttest/tdeps3/e.hrl +++ /dev/null @@ -1 +0,0 @@ --define(HELLO, hello). diff --git a/inttest/tdeps3/f.hrl b/inttest/tdeps3/f.hrl deleted file mode 100644 index 02f8088..0000000 --- a/inttest/tdeps3/f.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("e/include/e.hrl"). diff --git a/inttest/tdeps3/root.rebar.config b/inttest/tdeps3/root.rebar.config deleted file mode 100644 index d1c3793..0000000 --- a/inttest/tdeps3/root.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{sub_dirs, ["apps/a"]}. diff --git a/inttest/tdeps3/tdeps3_rt.erl b/inttest/tdeps3/tdeps3_rt.erl deleted file mode 100644 index da87d43..0000000 --- a/inttest/tdeps3/tdeps3_rt.erl +++ /dev/null @@ -1,89 +0,0 @@ --module(tdeps3_rt). - --compile(export_all). - -%% Exercise transitive dependencies where there are multiple files -%% depending on the same set of deps as well as lib_dir directives -%% A -> B -> C -> D -> E -%% |--> G(via lib_dir) -%% |--> F -> D -> E - -files() -> - [ - %% A1 application - {create, "ebin/a.app", app(a, [a])}, - {template, "a.erl", "src/a.erl", dict:from_list([{module, a}, {dep, b}])}, - - {copy, "a.rebar.config", "rebar.config"}, - {copy, "../../rebar", "rebar"}, - - %% B application - {create, "repo/b/ebin/b.app", app(b, [b])}, - {template, "a.erl", "repo/b/src/b.erl", dict:from_list([{module, b}, {dep, b}])}, - {copy, "b.rebar.config", "repo/b/rebar.config"}, - {copy, "b.hrl", "repo/b/include/b.hrl"}, - - %% C application - {create, "repo/c/ebin/c.app", app(c, [c])}, - {template, "a.erl", "repo/c/src/c.erl", dict:from_list([{module, c}, {dep, d}])}, - {copy, "c.rebar.config", "repo/c/rebar.config"}, - {copy, "c.hrl", "repo/c/include/c.hrl"}, - - %% D application - {create, "repo/d/ebin/d.app", app(d, [d])}, - {template, "a.erl", "repo/d/src/d.erl", dict:from_list([{module, d}, {dep, e}])}, - {copy, "d.rebar.config", "repo/d/rebar.config"}, - {copy, "d.hrl", "repo/d/include/d.hrl"}, - - %% E application - {create, "repo/e/ebin/e.app", app(e, [])}, - {copy, "e.hrl", "repo/e/include/e.hrl"}, - - - %% F application - {create, "repo/f/ebin/f.app", app(f, [f])}, - {template, "a.erl", "repo/f/src/f.erl", dict:from_list([{module, f}, {dep, d}])}, - {copy, "c.rebar.config", "repo/f/rebar.config"}, - {copy, "f.hrl", "repo/f/include/f.hrl"}, - - %% G application, which is part of the B repo, in a lib_dir - {create, "repo/b/apps/g/ebin/g.app", app(g, [])}, - {copy, "e.hrl", "repo/b/apps/g/include/g.hrl"} - - ]. - -apply_cmds([], _Params) -> - ok; -apply_cmds([Cmd | Rest], Params) -> - io:format("Running: ~s (~p)\n", [Cmd, Params]), - {ok, _} = retest_sh:run(Cmd, Params), - apply_cmds(Rest, Params). - -run(_Dir) -> - %% Initialize the b/c apps as git repos so that dependencies pull - %% properly - GitCmds = ["git init", - "git add -A", - "git config user.email 'tdeps@example.com'", - "git config user.name 'tdeps'", - "git commit -a -m 'Initial Commit'"], - ok = apply_cmds(GitCmds, [{dir, "repo/b"}]), - ok = apply_cmds(GitCmds, [{dir, "repo/c"}]), - ok = apply_cmds(GitCmds, [{dir, "repo/d"}]), - ok = apply_cmds(GitCmds, [{dir, "repo/e"}]), - ok = apply_cmds(GitCmds, [{dir, "repo/f"}]), - - {ok, _} = retest_sh:run("./rebar -v get-deps compile", []), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/tdeps_update/a.erl b/inttest/tdeps_update/a.erl deleted file mode 100644 index 294ae21..0000000 --- a/inttest/tdeps_update/a.erl +++ /dev/null @@ -1,3 +0,0 @@ --module({{module}}). - --include_lib("b/include/b.hrl"). diff --git a/inttest/tdeps_update/a.rebar.config b/inttest/tdeps_update/a.rebar.config deleted file mode 100644 index 3b721dc..0000000 --- a/inttest/tdeps_update/a.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{b, "0.2.3", {git, "../repo/b", {tag, "0.2.3"}}}]}. diff --git a/inttest/tdeps_update/a2.rebar.config b/inttest/tdeps_update/a2.rebar.config deleted file mode 100644 index 5687349..0000000 --- a/inttest/tdeps_update/a2.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{b, "0.2.4", {git, "../repo/b", {tag, "0.2.4"}}}]}. diff --git a/inttest/tdeps_update/a3.rebar.config b/inttest/tdeps_update/a3.rebar.config deleted file mode 100644 index 86bf462..0000000 --- a/inttest/tdeps_update/a3.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{b, "0.2.5", {git, "../repo/b", {tag, "0.2.5"}}}]}. diff --git a/inttest/tdeps_update/a4.rebar.config b/inttest/tdeps_update/a4.rebar.config deleted file mode 100644 index bfba813..0000000 --- a/inttest/tdeps_update/a4.rebar.config +++ /dev/null @@ -1,4 +0,0 @@ -{deps, [ - {b, "0.2.6", {git, "../repo/b", {tag, "0.2.6"}}}, - {f, "0.1", {git, "../repo/f", {tag, "0.1"}}} - ]}. diff --git a/inttest/tdeps_update/b.hrl b/inttest/tdeps_update/b.hrl deleted file mode 100644 index efbeab1..0000000 --- a/inttest/tdeps_update/b.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("c/include/c.hrl"). diff --git a/inttest/tdeps_update/b.rebar.config b/inttest/tdeps_update/b.rebar.config deleted file mode 100644 index 536aaa9..0000000 --- a/inttest/tdeps_update/b.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{c, "1.0", {git, "../repo/c", {tag, "1.0"}}}]}. diff --git a/inttest/tdeps_update/b2.rebar.config b/inttest/tdeps_update/b2.rebar.config deleted file mode 100644 index b603277..0000000 --- a/inttest/tdeps_update/b2.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{c, "1.1", {git, "../repo/c", {tag, "1.1"}}}]}. diff --git a/inttest/tdeps_update/b3.rebar.config b/inttest/tdeps_update/b3.rebar.config deleted file mode 100644 index 5f4e20a..0000000 --- a/inttest/tdeps_update/b3.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{c, "1.2", {git, "../repo/c", {tag, "1.2"}}}]}. diff --git a/inttest/tdeps_update/b4.rebar.config b/inttest/tdeps_update/b4.rebar.config deleted file mode 100644 index 5fd1dca..0000000 --- a/inttest/tdeps_update/b4.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{c, "1.3", {git, "../repo/c", {tag, "1.3"}}}]}. diff --git a/inttest/tdeps_update/c.hrl b/inttest/tdeps_update/c.hrl deleted file mode 100644 index 9f02fab..0000000 --- a/inttest/tdeps_update/c.hrl +++ /dev/null @@ -1 +0,0 @@ --define(HELLO, hello). diff --git a/inttest/tdeps_update/c.rebar.config b/inttest/tdeps_update/c.rebar.config deleted file mode 100644 index d99b963..0000000 --- a/inttest/tdeps_update/c.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{deps, [{d, "0.7", {git, "../repo/d", {tag, "0.7"}}}]}. diff --git a/inttest/tdeps_update/c2.hrl b/inttest/tdeps_update/c2.hrl deleted file mode 100644 index cc87fff..0000000 --- a/inttest/tdeps_update/c2.hrl +++ /dev/null @@ -1 +0,0 @@ --include_lib("d/include/d.hrl"). diff --git a/inttest/tdeps_update/c2.rebar.config b/inttest/tdeps_update/c2.rebar.config deleted file mode 100644 index 1297e07..0000000 --- a/inttest/tdeps_update/c2.rebar.config +++ /dev/null @@ -1,4 +0,0 @@ -{deps, [ - {d, "0.7", {git, "../repo/d", {tag, "0.7"}}}, - {e, "2.0", {git, "../repo/e", {tag, "2.0"}}} - ]}. diff --git a/inttest/tdeps_update/c3.rebar.config b/inttest/tdeps_update/c3.rebar.config deleted file mode 100644 index 40c93c5..0000000 --- a/inttest/tdeps_update/c3.rebar.config +++ /dev/null @@ -1,4 +0,0 @@ -{deps, [ - {d, "0.7", {git, "../repo/d", {tag, "0.7"}}}, - {e, "2.1", {git, "../repo/e", {tag, "2.1"}}} - ]}. diff --git a/inttest/tdeps_update/d.hrl b/inttest/tdeps_update/d.hrl deleted file mode 100644 index 9f02fab..0000000 --- a/inttest/tdeps_update/d.hrl +++ /dev/null @@ -1 +0,0 @@ --define(HELLO, hello). diff --git a/inttest/tdeps_update/root.rebar.config b/inttest/tdeps_update/root.rebar.config deleted file mode 100644 index ea03437..0000000 --- a/inttest/tdeps_update/root.rebar.config +++ /dev/null @@ -1 +0,0 @@ -{sub_dirs, ["apps/a1"]}. diff --git a/inttest/tdeps_update/tdeps_update_rt.erl b/inttest/tdeps_update/tdeps_update_rt.erl deleted file mode 100644 index e182ae2..0000000 --- a/inttest/tdeps_update/tdeps_update_rt.erl +++ /dev/null @@ -1,148 +0,0 @@ --module(tdeps_update_rt). - --compile(export_all). - -%% Exercises update deps, with recursive dependency updates. -%% Initially: -%% A(v0.5) -> B(v0.2.3) -> C(v1.0) -%% But after updating A to 0.6: -%% A(v0.6) -> B(v0.2.4) -> C(v1.1) -%% -> D(v0.7) -%% And after updating A to 0.7: -%% A(v0.7) -> B(v0.2.5) -> C(v1.2) -> E(v2.0) -%% -> D(v0.7) -%% And after updating A to 0.8: -%% A(v0.8) -> B(v0.2.6) -> C(v1.3) -> E(v2.1) -%% -> D(v0.7) -%% -> F(v0.1) -> E(v2.1) -files() -> - [ - %% A1 application - {create, "apps/a1/ebin/a1.app", app(a1, [a1], "0.5")}, - {copy, "a.rebar.config", "apps/a1/rebar.config"}, - {template, "a.erl", "apps/a1/src/a1.erl", dict:from_list([{module, a1}])}, - - {copy, "root.rebar.config", "rebar.config"}, - {copy, "../../rebar", "rebar"}, - - %% B application - {create, "repo/b/ebin/b.app", app(b, [], "0.2.3")}, - {create, "b2.app", app(b, [], "0.2.4")}, - {create, "b3.app", app(b, [], "0.2.5")}, - {create, "b4.app", app(b, [], "0.2.6")}, - {copy, "b.rebar.config", "repo/b/rebar.config"}, - {copy, "b.hrl", "repo/b/include/b.hrl"}, - - %% C application - {create, "repo/c/ebin/c.app", app(c, [], "1.0")}, - {create, "c2.app", app(c, [], "1.1")}, - {create, "c3.app", app(c, [], "1.2")}, - {create, "c4.app", app(c, [], "1.3")}, - {copy, "c.hrl", "repo/c/include/c.hrl"}, - - %% D application - {create, "repo/d/ebin/d.app", app(d, [], "0.7")}, - {copy, "d.hrl", "repo/d/include/d.hrl"}, - - %% E application - {create, "repo/e/ebin/e.app", app(e, [], "2.0")}, - {create, "e2.app", app(e, [], "2.1")}, - - %% F application - {create, "repo/f/ebin/f.app", app(f, [], "0.1")}, - - %% update files - {copy, "a2.rebar.config", "a2.rebar.config"}, - {copy, "a3.rebar.config", "a3.rebar.config"}, - {copy, "a4.rebar.config", "a4.rebar.config"}, - {copy, "b2.rebar.config", "b2.rebar.config"}, - {copy, "b3.rebar.config", "b3.rebar.config"}, - {copy, "b4.rebar.config", "b4.rebar.config"}, - {copy, "c2.hrl", "c2.hrl"}, - {copy, "c.rebar.config", "c.rebar.config"}, - {copy, "c2.rebar.config", "c2.rebar.config"}, - {copy, "c3.rebar.config", "c3.rebar.config"} - ]. - -apply_cmds([], _Params) -> - ok; -apply_cmds([Cmd | Rest], Params) -> - io:format("Running: ~s (~p)\n", [Cmd, Params]), - {ok, _} = retest_sh:run(Cmd, Params), - apply_cmds(Rest, Params). - -run(_Dir) -> - %% Initialize the b/c/d apps as git repos so that dependencies pull - %% properly - GitCmds = ["git init", - "git add -A", - "git config user.email 'tdeps@example.com'", - "git config user.name 'tdeps'", - "git commit -a -m 'Initial Commit'"], - BCmds = ["git tag 0.2.3", - "cp ../../b2.rebar.config rebar.config", - "cp ../../b2.app ebin/b.app", - "git commit -a -m 'update to 0.2.4'", - "git tag 0.2.4", - "cp ../../b3.rebar.config rebar.config", - "cp ../../b3.app ebin/b.app", - "git commit -a -m 'update to 0.2.5'", - "git tag 0.2.5", - "cp ../../b4.rebar.config rebar.config", - "cp ../../b4.app ebin/b.app", - "git commit -a -m 'update to 0.2.6'", - "git tag 0.2.6"], - %"git checkout 0.2.3"], - CCmds = ["git tag 1.0", - "cp ../../c2.hrl include/c.hrl", - "cp ../../c2.app ebin/c.app", - "cp ../../c.rebar.config rebar.config", - "git add rebar.config", - "git commit -a -m 'update to 1.1'", - "git tag 1.1", - "cp ../../c3.app ebin/c.app", - "cp ../../c2.rebar.config rebar.config", - "git commit -a -m 'update to 1.2'", - "git tag 1.2", - "cp ../../c4.app ebin/c.app", - "cp ../../c3.rebar.config rebar.config", - "git commit -a -m 'update to 1.3'", - "git tag 1.3"], - %"git checkout 1.0"], - DCmds = ["git tag 0.7"], - ECmds = ["git tag 2.0", - "cp ../../e2.app ebin/e.app", - "git commit -a -m 'update to 2.1'", - "git tag 2.1"], - FCmds = ["git tag 0.1"], - - ok = apply_cmds(GitCmds++BCmds, [{dir, "repo/b"}]), - ok = apply_cmds(GitCmds++CCmds, [{dir, "repo/c"}]), - ok = apply_cmds(GitCmds++DCmds, [{dir, "repo/d"}]), - ok = apply_cmds(GitCmds++ECmds, [{dir, "repo/e"}]), - ok = apply_cmds(GitCmds++FCmds, [{dir, "repo/f"}]), - - {ok, _} = retest_sh:run("./rebar -v get-deps", []), - {ok, _} = retest_sh:run("./rebar -v compile", []), - os:cmd("cp a2.rebar.config apps/a1/rebar.config"), - {ok, _} = retest_sh:run("./rebar -v update-deps", []), - {ok, _} = retest_sh:run("./rebar -v compile", []), - os:cmd("cp a3.rebar.config apps/a1/rebar.config"), - {ok, _} = retest_sh:run("./rebar -v update-deps", []), - {ok, _} = retest_sh:run("./rebar -v compile", []), - os:cmd("cp a4.rebar.config apps/a1/rebar.config"), - {ok, _} = retest_sh:run("./rebar -v update-deps", []), - {ok, _} = retest_sh:run("./rebar -v compile", []), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules, Version) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, Version}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/thooks/fish.erl b/inttest/thooks/fish.erl deleted file mode 100644 index 739cb94..0000000 --- a/inttest/thooks/fish.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(fish). - --compile(export_all). - -fish() -> fish. diff --git a/inttest/thooks/rebar.config b/inttest/thooks/rebar.config deleted file mode 100644 index 6514818..0000000 --- a/inttest/thooks/rebar.config +++ /dev/null @@ -1,7 +0,0 @@ -%% pre-scripts -{pre_hooks, [{clean, "echo preclean >> preclean.out"}, - {compile, "echo precompile >> precompile.out"}]}. - -%% post-scripts -{post_hooks, [{clean, "echo postclean >> postclean.out"}, - {compile, "echo postcompile >> postcompile.out"}]}. diff --git a/inttest/thooks/thooks_rt.erl b/inttest/thooks/thooks_rt.erl deleted file mode 100644 index 52af9f5..0000000 --- a/inttest/thooks/thooks_rt.erl +++ /dev/null @@ -1,40 +0,0 @@ --module(thooks_rt). - --include_lib("eunit/include/eunit.hrl"). --compile(export_all). - -files() -> - [ - %% dummy lfe files - {copy, "../../rebar", "rebar"}, - {copy, "rebar.config", "rebar.config"}, - {copy, "fish.erl", "src/fish.erl"}, - {create, "ebin/fish.app", app(fish, [fish])} - ]. - -run(_Dir) -> - ?assertMatch({ok, _}, retest_sh:run("./rebar -v clean compile", [])), - ensure_command_ran_only_once("preclean"), - ensure_command_ran_only_once("precompile"), - ensure_command_ran_only_once("postclean"), - ensure_command_ran_only_once("postcompile"), - ok. - -ensure_command_ran_only_once(Command) -> - File = Command ++ ".out", - ?assert(filelib:is_regular(File)), - %% ensure that this command only ran once (not for each module) - {ok, Content} = file:read_file(File), - ?assertEqual(Command ++ "\n", binary_to_list(Content)). - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/inttest/tplugins/bad.config b/inttest/tplugins/bad.config deleted file mode 100644 index 23069b8..0000000 --- a/inttest/tplugins/bad.config +++ /dev/null @@ -1,2 +0,0 @@ -{plugins, [bad_plugin]}. -{plugin_dir, "bad_plugins"}. diff --git a/inttest/tplugins/bad_plugin.erl b/inttest/tplugins/bad_plugin.erl deleted file mode 100644 index 77ec01b..0000000 --- a/inttest/tplugins/bad_plugin.erl +++ /dev/null @@ -1,7 +0,0 @@ --module(bad_plugin). --compile(export_all). - -%% this plugin contains numerous DELIBERATE syntax errors - -fwibble(Config, _) > - file:delete("fwibble.test") diff --git a/inttest/tplugins/fish.erl b/inttest/tplugins/fish.erl deleted file mode 100644 index 739cb94..0000000 --- a/inttest/tplugins/fish.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(fish). - --compile(export_all). - -fish() -> fish. diff --git a/inttest/tplugins/rebar.config b/inttest/tplugins/rebar.config deleted file mode 100644 index 0b9c887..0000000 --- a/inttest/tplugins/rebar.config +++ /dev/null @@ -1 +0,0 @@ -{plugins, [test_plugin]}. diff --git a/inttest/tplugins/test_plugin.erl b/inttest/tplugins/test_plugin.erl deleted file mode 100644 index 461247c..0000000 --- a/inttest/tplugins/test_plugin.erl +++ /dev/null @@ -1,8 +0,0 @@ --module(test_plugin). --compile(export_all). - -fwibble(Config, _) -> - Pwd = rebar_utils:get_cwd(), - Ok = filelib:is_regular(filename:join(Pwd, "fwibble.test")), - rebar_log:log(info, "~p:~p in ~s :: ~p~n", [test_plugin, clean, Pwd, Ok]), - ok = file:delete("fwibble.test"). diff --git a/inttest/tplugins/tplugins_rt.erl b/inttest/tplugins/tplugins_rt.erl deleted file mode 100644 index d6908ad..0000000 --- a/inttest/tplugins/tplugins_rt.erl +++ /dev/null @@ -1,40 +0,0 @@ --module(tplugins_rt). --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - --define(COMPILE_ERROR, - "ERROR: Plugin bad_plugin contains compilation errors:"). - -files() -> - [ - {copy, "../../rebar", "rebar"}, - {copy, "rebar.config", "rebar.config"}, - {copy, "bad.config", "bad.config"}, - {copy, "fish.erl", "src/fish.erl"}, - {copy, "test_plugin.erl", "plugins/test_plugin.erl"}, - {copy, "bad_plugin.erl", "bad_plugins/bad_plugin.erl"}, - {create, "fwibble.test", <<"fwibble">>}, - {create, "ebin/fish.app", app(fish, [fish])} - ]. - -run(_Dir) -> - ?assertMatch({ok, _}, retest_sh:run("./rebar fwibble -v", [])), - ?assertEqual(false, filelib:is_regular("fwibble.test")), - Ref = retest:sh("./rebar -C bad.config -v clean", [{async, true}]), - {ok, _} = retest:sh_expect(Ref, "ERROR: Plugin .*bad_plugin.erl " - "contains compilation errors:.*", - [{newline, any}]), - ok. - -%% -%% Generate the contents of a simple .app file -%% -app(Name, Modules) -> - App = {application, Name, - [{description, atom_to_list(Name)}, - {vsn, "1"}, - {modules, Modules}, - {registered, []}, - {applications, [kernel, stdlib]}]}, - io_lib:format("~p.\n", [App]). diff --git a/rebar.config b/rebar.config index 3c4e0cf..302bc62 100644 --- a/rebar.config +++ b/rebar.config @@ -38,4 +38,5 @@ {deps, [{relx, "", {git, "https://github.com/erlware/relx.git", - {branch, "master"}}}]}. + {branch, "master"}}}, + {getopt, "", {git, "git@github.com:jcomellas/getopt.git", {branch, "master"}}}]}. diff --git a/src/rebar.erl b/src/rebar.erl index 01dca79..48a3ac6 100644 --- a/src/rebar.erl +++ b/src/rebar.erl @@ -189,10 +189,10 @@ run_aux(BaseConfig, Commands) -> %% help() -> OptSpecList = option_spec_list(), - rebar_getopt:usage(OptSpecList, "rebar", - "[var=value,...] <command,...>", - [{"var=value", "rebar global variables (e.g. force=1)"}, - {"command", "Command to run (e.g. compile)"}]), + getopt:usage(OptSpecList, "rebar", + "[var=value,...] <command,...>", + [{"var=value", "rebar global variables (e.g. force=1)"}, + {"command", "Command to run (e.g. compile)"}]), ?CONSOLE("To see a list of built-in commands, execute rebar -c.~n~n", []), ?CONSOLE( @@ -206,7 +206,7 @@ help() -> parse_args(RawArgs) -> %% Parse getopt options OptSpecList = option_spec_list(), - case rebar_getopt:parse(OptSpecList, RawArgs) of + case getopt:parse(OptSpecList, RawArgs) of {ok, Args} -> Args; {error, {Reason, Data}} -> diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl index a08ca92..698ebd7 100644 --- a/src/rebar_app_info.erl +++ b/src/rebar_app_info.erl @@ -86,14 +86,30 @@ config(AppInfo=#app_info_t{}, Config) -> AppInfo#app_info_t{config=Config}. -spec app_file_src(t()) -> file:name(). +app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) -> + AppFileSrc = filename:join([Dir, "src", <<Name/binary, ".app.src">>]), + case filelib:is_file(AppFileSrc) of + true -> + ec_cnv:to_list(AppFileSrc); + false -> + undefined + end; app_file_src(#app_info_t{app_file_src=AppFileSrc}) -> - AppFileSrc. + ec_cnv:to_list(AppFileSrc). -spec app_file_src(t(), file:name()) -> t(). app_file_src(AppInfo=#app_info_t{}, AppFileSrc) -> AppInfo#app_info_t{app_file_src=AppFileSrc}. -spec app_file(t()) -> file:name(). +app_file(#app_info_t{app_file=undefined, dir=Dir, name=Name}) -> + AppFile = filename:join([Dir, "ebin", <<Name/binary, ".app">>]), + case filelib:is_file(AppFile) of + true -> + AppFile; + false -> + undefined + end; app_file(#app_info_t{app_file=AppFile}) -> AppFile. diff --git a/src/rebar_cleaner.erl b/src/rebar_cleaner.erl deleted file mode 100644 index 7a762f5..0000000 --- a/src/rebar_cleaner.erl +++ /dev/null @@ -1,56 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- --module(rebar_cleaner). - --export([clean/2]). - -%% for internal use only --export([info/2]). - --include("rebar.hrl"). - -%% =================================================================== -%% Public API -%% =================================================================== -clean(Config, _AppFile) -> - %% Get a list of files to delete from config and remove them - FilesToClean = rebar_config:get(Config, clean_files, []), - lists:foreach(fun (F) -> rebar_file_utils:rm_rf(F) end, FilesToClean). - -%% =================================================================== -%% Internal functions -%% =================================================================== - -info(help, clean) -> - ?CONSOLE( - "Delete list of files.~n" - "~n" - "Valid rebar.config options:~n" - " ~p~n", - [ - {clean_files, ["file", "file2"]} - ]). diff --git a/src/rebar_cover_utils.erl b/src/rebar_cover_utils.erl deleted file mode 100644 index 3195fe2..0000000 --- a/src/rebar_cover_utils.erl +++ /dev/null @@ -1,261 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com) -%% Copyright (c) 2013 Andras Horvath (andras.horvath@erlang-solutions.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- --module(rebar_cover_utils). - -%% for internal use only --export([init/3, - perform_cover/4, - close/1, - exit/0]). - --include("rebar.hrl"). - -%% ==================================================================== -%% Internal functions -%% ==================================================================== - -perform_cover(Config, BeamFiles, SrcModules, TargetDir) -> - perform_cover(rebar_config:get(Config, cover_enabled, false), - Config, BeamFiles, SrcModules, TargetDir). - -perform_cover(false, _Config, _BeamFiles, _SrcModules, _TargetDir) -> - ok; -perform_cover(true, Config, BeamFiles, SrcModules, TargetDir) -> - analyze(Config, BeamFiles, SrcModules, TargetDir). - -close(not_enabled) -> - ok; -close(F) -> - ok = file:close(F). - -exit() -> - cover:stop(). - -init(false, _BeamFiles, _TargetDir) -> - {ok, not_enabled}; -init(true, BeamFiles, TargetDir) -> - %% Attempt to start the cover server, then set its group leader to - %% TargetDir/cover.log, so all cover log messages will go there instead of - %% to stdout. If the cover server is already started, we'll kill that - %% server and start a new one in order not to inherit a polluted - %% cover_server state. - {ok, CoverPid} = case whereis(cover_server) of - undefined -> - cover:start(); - _ -> - cover:stop(), - cover:start() - end, - - {ok, F} = OkOpen = file:open( - filename:join([TargetDir, "cover.log"]), - [write]), - - group_leader(F, CoverPid), - - ?INFO("Cover compiling ~s\n", [rebar_utils:get_cwd()]), - - Compiled = [{Beam, cover:compile_beam(Beam)} || Beam <- BeamFiles], - case [Module || {_, {ok, Module}} <- Compiled] of - [] -> - %% No modules compiled successfully...fail - ?ERROR("Cover failed to compile any modules; aborting.~n", []), - ?FAIL; - _ -> - %% At least one module compiled successfully - - %% It's not an error for cover compilation to fail partially, - %% but we do want to warn about them - PrintWarning = - fun(Beam, Desc) -> - ?CONSOLE("Cover compilation warning for ~p: ~p", - [Beam, Desc]) - end, - _ = [PrintWarning(Beam, Desc) || {Beam, {error, Desc}} <- Compiled], - OkOpen - end; -init(Config, BeamFiles, TargetDir) -> - init(rebar_config:get(Config, cover_enabled, false), BeamFiles, TargetDir). - -analyze(_Config, [], _SrcModules, _TargetDir) -> - ok; -analyze(Config, FilteredModules, SrcModules, TargetDir) -> - %% Generate coverage info for all the cover-compiled modules - Coverage = lists:flatten([analyze_mod(M) - || M <- FilteredModules, - cover:is_compiled(M) =/= false]), - - %% Write index of coverage info - write_index(lists:sort(Coverage), SrcModules, TargetDir), - - %% Write coverage details for each file - lists:foreach( - fun({M, _, _}) -> - {ok, _} = cover:analyze_to_file(M, - cover_file(M, TargetDir), - [html]) - end, Coverage), - - Index = filename:join([rebar_utils:get_cwd(), TargetDir, "index.html"]), - ?CONSOLE("Cover analysis: ~s\n", [Index]), - - %% Export coverage data, if configured - case rebar_config:get(Config, cover_export_enabled, false) of - true -> - export_coverdata(TargetDir); - false -> - ok - end, - - %% Print coverage report, if configured - case rebar_config:get(Config, cover_print_enabled, false) of - true -> - print_coverage(lists:sort(Coverage)); - false -> - ok - end. - -analyze_mod(Module) -> - case cover:analyze(Module, coverage, module) of - {ok, {Module, {Covered, NotCovered}}} -> - %% Modules that include the eunit header get an implicit - %% test/0 fun, which cover considers a runnable line, but - %% eunit:test(TestRepresentation) never calls. Decrement - %% NotCovered in this case. - [align_notcovered_count(Module, Covered, NotCovered, - is_eunitized(Module))]; - {error, Reason} -> - ?ERROR("Cover analyze failed for ~p: ~p ~p\n", - [Module, Reason, code:which(Module)]), - [] - end. - -is_eunitized(Mod) -> - has_eunit_test_fun(Mod) andalso - has_header(Mod, "include/eunit.hrl"). - -has_eunit_test_fun(Mod) -> - [F || {exports, Funs} <- Mod:module_info(), - {F, 0} <- Funs, F =:= test] =/= []. - -has_header(Mod, Header) -> - Mod1 = case code:which(Mod) of - cover_compiled -> - {file, File} = cover:is_compiled(Mod), - File; - non_existing -> Mod; - preloaded -> Mod; - L -> L - end, - {ok, {_, [{abstract_code, {_, AC}}]}} = - beam_lib:chunks(Mod1, [abstract_code]), - [F || {attribute, 1, file, {F, 1}} <- AC, - string:str(F, Header) =/= 0] =/= []. - -align_notcovered_count(Module, Covered, NotCovered, false) -> - {Module, Covered, NotCovered}; -align_notcovered_count(Module, Covered, NotCovered, true) -> - {Module, Covered, NotCovered - 1}. - -write_index(Coverage, SrcModules, TargetDir) -> - {ok, F} = file:open(filename:join([TargetDir, "index.html"]), [write]), - ok = file:write(F, "<!DOCTYPE HTML><html>\n" - "<head><meta charset=\"utf-8\">" - "<title>Coverage Summary</title></head>\n" - "<body>\n"), - IsSrcCoverage = fun({Mod,_C,_N}) -> lists:member(Mod, SrcModules) end, - {SrcCoverage, TestCoverage} = lists:partition(IsSrcCoverage, Coverage), - write_index_section(F, "Source", SrcCoverage), - write_index_section(F, "Test", TestCoverage), - ok = file:write(F, "</body></html>"), - ok = file:close(F). - -write_index_section(_F, _SectionName, []) -> - ok; -write_index_section(F, SectionName, Coverage) -> - %% Calculate total coverage - {Covered, NotCovered} = lists:foldl(fun({_Mod, C, N}, {CAcc, NAcc}) -> - {CAcc + C, NAcc + N} - end, {0, 0}, Coverage), - TotalCoverage = percentage(Covered, NotCovered), - - %% Write the report - ok = file:write(F, ?FMT("<h1>~s Summary</h1>\n", [SectionName])), - ok = file:write(F, ?FMT("<h3>Total: ~s</h3>\n", [TotalCoverage])), - ok = file:write(F, "<table><tr><th>Module</th><th>Coverage %</th></tr>\n"), - - FmtLink = - fun(Module, Cov, NotCov) -> - ?FMT("<tr><td><a href='~s.COVER.html'>~s</a></td><td>~s</td>\n", - [Module, Module, percentage(Cov, NotCov)]) - end, - lists:foreach(fun({Module, Cov, NotCov}) -> - ok = file:write(F, FmtLink(Module, Cov, NotCov)) - end, Coverage), - ok = file:write(F, "</table>\n"). - -print_coverage(Coverage) -> - {Covered, NotCovered} = lists:foldl(fun({_Mod, C, N}, {CAcc, NAcc}) -> - {CAcc + C, NAcc + N} - end, {0, 0}, Coverage), - TotalCoverage = percentage(Covered, NotCovered), - - %% Determine the longest module name for right-padding - Width = lists:foldl(fun({Mod, _, _}, Acc) -> - case length(atom_to_list(Mod)) of - N when N > Acc -> - N; - _ -> - Acc - end - end, 0, Coverage) * -1, - - %% Print the output the console - ?CONSOLE("~nCode Coverage:~n", []), - lists:foreach(fun({Mod, C, N}) -> - ?CONSOLE("~*s : ~3s~n", - [Width, Mod, percentage(C, N)]) - end, Coverage), - ?CONSOLE("~n~*s : ~s~n", [Width, "Total", TotalCoverage]). - -cover_file(Module, TargetDir) -> - filename:join([TargetDir, atom_to_list(Module) ++ ".COVER.html"]). - -export_coverdata(TargetDir) -> - ExportFile = filename:join(TargetDir, "cover.coverdata"), - case cover:export(ExportFile) of - ok -> - ?CONSOLE("Coverdata export: ~s~n", [ExportFile]); - {error, Reason} -> - ?ERROR("Coverdata export failed: ~p~n", [Reason]) - end. - -percentage(0, 0) -> - "not executed"; -percentage(Cov, NotCov) -> - integer_to_list(trunc((Cov / (Cov + NotCov)) * 100)) ++ "%". diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl deleted file mode 100644 index b5abeae..0000000 --- a/src/rebar_ct.erl +++ /dev/null @@ -1,388 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- -%% -%% Targets: -%% test - run common test suites in ./test -%% int_test - run suites in ./int_test -%% perf_test - run suites inm ./perf_test -%% -%% Global options: -%% verbose=1 - show output from the common_test run as it goes -%% suites="foo,bar" - run <test>/foo_SUITE and <test>/bar_SUITE -%% case="mycase" - run individual test case foo_SUITE:mycase -%% ------------------------------------------------------------------- --module(rebar_ct). - --behaviour(rebar_provider). - --export([init/1, - do/1]). - -%% for internal use only --export([info/2]). - --include("rebar.hrl"). - --define(PROVIDER, ct). --define(DEPS, [compile]). - -%% =================================================================== -%% Public API -%% =================================================================== - --spec init(rebar_state:t()) -> {ok, rebar_state:t()}. -init(State) -> - State1 = rebar_state:add_provider(State, #provider{name = ?PROVIDER, - provider_impl = ?MODULE, - bare = false, - deps = ?DEPS, - example = "rebar ct", - short_desc = "", - desc = "", - opts = []}), - {ok, State1}. - --spec do(rebar_state:t()) -> {ok, rebar_state:t()}. -do(State) -> - TestDir = rebar_state:get(State, ct_dir, "test"), - LogDir = rebar_state:get(State, ct_log_dir, "logs"), - run_test_if_present(TestDir, LogDir, State), - {ok, State}. - -%% =================================================================== -%% Internal functions -%% =================================================================== - -info(help, ct) -> - ?CONSOLE( - "Run common_test suites.~n" - "~n" - "Valid rebar.config options:~n" - " ~p~n" - " ~p~n" - " ~p~n" - " ~p~n" - "Valid command line options:~n" - " suites=foo,bar - run <test>/foo_SUITE and <test>/bar_SUITE~n" - " case=\"mycase\" - run individual test case foo_SUITE:mycase~n", - [ - {ct_dir, "itest"}, - {ct_log_dir, "test/logs"}, - {ct_extra_params, "-boot start_sasl -s myapp"}, - {ct_use_short_names, true} - ]). - -run_test_if_present(TestDir, LogDir, State) -> - case filelib:is_dir(TestDir) of - false -> - ?WARN("~s directory not present - skipping\n", [TestDir]), - ok; - true -> - case filelib:wildcard(TestDir ++ "/*_SUITE.{beam,erl}") of - [] -> - ?WARN("~s directory present, but no common_test" - ++ " SUITES - skipping\n", [TestDir]), - ok; - _ -> - try - run_test(TestDir, LogDir, State) - catch - throw:skip -> - ok - end - end - end. - -run_test(TestDir, LogDir, State) -> - {Cmd, RawLog} = make_cmd(TestDir, LogDir, State), - ?DEBUG("ct_run cmd:~n~p~n", [Cmd]), - clear_log(LogDir, RawLog), - Output = case rebar_log:is_verbose(State) of - false -> - " >> " ++ RawLog ++ " 2>&1"; - true -> - " 2>&1 | tee -a " ++ RawLog - end, - - ShOpts = [{env,[{"TESTDIR", TestDir}]}, return_on_error], - case rebar_utils:sh(Cmd ++ Output, ShOpts) of - {ok,_} -> - %% in older versions of ct_run, this could have been a failure - %% that returned a non-0 code. Check for that! - check_success_log(State, RawLog); - {error,Res} -> - %% In newer ct_run versions, this may be a sign of a good compile - %% that failed cases. In older version, it's a worse error. - check_fail_log(State, RawLog, Cmd ++ Output, Res) - end. - -clear_log(LogDir, RawLog) -> - case filelib:ensure_dir(filename:join(LogDir, "index.html")) of - ok -> - NowStr = rebar_utils:now_str(), - LogHeader = "--- Test run on " ++ NowStr ++ " ---\n", - ok = file:write_file(RawLog, LogHeader); - {error, Reason} -> - ?ERROR("Could not create log dir - ~p\n", [Reason]), - ?FAIL - end. - -%% calling ct with erl does not return non-zero on failure - have to check -%% log results -check_success_log(State, RawLog) -> - check_log(State, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end). - --type err_handler() :: fun((string()) -> no_return()). --spec failure_logger(string(), {integer(), string()}) -> err_handler(). -failure_logger(Command, {Rc, Output}) -> - fun(_Msg) -> - ?ABORT("~s failed with error: ~w and output:~n~s~n", - [Command, Rc, Output]) - end. - -check_fail_log(State, RawLog, Command, Result) -> - check_log(State, RawLog, failure_logger(Command, Result)). - -check_log(State,RawLog,Fun) -> - {ok, Msg} = - rebar_utils:sh("grep -e \"TEST COMPLETE\" -e \"{error,make_failed}\" " - ++ RawLog, [{use_stdout, false}]), - MakeFailed = string:str(Msg, "{error,make_failed}") =/= 0, - RunFailed = string:str(Msg, ", 0 failed") =:= 0, - if - MakeFailed -> - show_log(State, RawLog), - ?ERROR("Building tests failed\n",[]), - ?FAIL; - - RunFailed -> - show_log(State, RawLog), - ?ERROR("One or more tests failed\n",[]), - ?FAIL; - - true -> - Fun(Msg) - end. - - -%% Show the log if it hasn't already been shown because verbose was on -show_log(State, RawLog) -> - ?CONSOLE("Showing log\n", []), - case rebar_log:is_verbose(State) of - false -> - {ok, Contents} = file:read_file(RawLog), - ?CONSOLE("~s", [Contents]); - true -> - ok - end. - -make_cmd(TestDir, RawLogDir, State) -> - Cwd = rebar_utils:get_cwd(), - LogDir = filename:join(Cwd, RawLogDir), - IncludeDir = filename:join(Cwd, "include"), - Include = case filelib:is_dir(IncludeDir) of - true -> - " -include \"" ++ IncludeDir ++ "\""; - false -> - "" - end, - - %% Check for the availability of ct_run; if we can't find it, generate a - %% warning and use the old school, less reliable approach to running CT. - BaseCmd = case os:find_executable("ct_run") of - false -> - "erl -noshell -s ct_run script_start -s erlang halt"; - _ -> - "ct_run -noshell" - end, - - %% Add the code path of the rebar process to the code path. This - %% includes the dependencies in the code path. The directories - %% that are part of the root Erlang install are filtered out to - %% avoid duplication - Apps = rebar_state:apps_to_build(State), - DepsDir = rebar_prv_install_deps:get_deps_dir(State), - DepsDirEbin = filename:join([DepsDir, "*", "ebin"]), - AppDirs = [filename:join(rebar_app_info:dir(A), "ebin") || A <- Apps], - CodeDirs = [io_lib:format("\"~s\"", [Dir]) || Dir <- [DepsDirEbin | AppDirs]], - CodePathString = string:join(CodeDirs, " "), - Cmd = case get_ct_specs(State, Cwd) of - undefined -> - ?FMT("~s" - " -pa ~s" - " ~s" - " ~s" - " -logdir \"~s\"" - " -env TEST_DIR \"~s\"", - [BaseCmd, - CodePathString, - Include, - build_name(State), - LogDir, - filename:join(Cwd, TestDir)]) ++ - get_cover_config(State, Cwd) ++ - get_ct_config_file(TestDir) ++ - get_config_file(TestDir) ++ - get_suites(State, TestDir) ++ - get_case(State); - SpecFlags -> - ?FMT("~s" - " -pa ~s" - " ~s" - " ~s" - " -logdir \"~s\"" - " -env TEST_DIR \"~s\"", - [BaseCmd, - CodePathString, - Include, - build_name(State), - LogDir, - filename:join(Cwd, TestDir)]) ++ - SpecFlags ++ get_cover_config(State, Cwd) - end, - io:format("Cmd ~s~n", [Cmd]), - Cmd1 = Cmd ++ get_extra_params(State), - RawLog = filename:join(LogDir, "raw.log"), - {Cmd1, RawLog}. - -build_name(State) -> - case rebar_state:get(State, ct_use_short_names, false) of - true -> "-sname test"; - false -> " -name test@" ++ net_adm:localhost() - end. - -get_extra_params(State) -> - case rebar_state:get(State, ct_extra_params, undefined) of - undefined -> - ""; - Defined -> - " " ++ Defined - end. - -get_ct_specs(State, Cwd) -> - case collect_glob(State, Cwd, ".*\.test\.spec\$") of - [] -> undefined; - [Spec] -> - " -spec " ++ Spec; - Specs -> - " -spec " ++ - lists:flatten([io_lib:format("~s ", [Spec]) || Spec <- Specs]) - end. - -get_cover_config(State, Cwd) -> - case rebar_state:get(State, cover_enabled, false) of - false -> - ""; - true -> - case collect_glob(State, Cwd, ".*cover\.spec\$") of - [] -> - ?DEBUG("No cover spec found: ~s~n", [Cwd]), - ""; - [Spec] -> - ?DEBUG("Found cover file ~s~n", [Spec]), - " -cover " ++ Spec; - Specs -> - ?ABORT("Multiple cover specs found: ~p~n", [Specs]) - end - end. - -collect_glob(State, Cwd, Glob) -> - DepsDir = rebar_prv_install_deps:get_deps_dir(State), - CwdParts = filename:split(Cwd), - filelib:fold_files(Cwd, Glob, true, fun(F, Acc) -> - %% Ignore any specs under the deps/ directory. Do this pulling - %% the dirname off the F and then splitting it into a list. - Parts = filename:split(filename:dirname(F)), - Parts2 = remove_common_prefix(Parts, CwdParts), - case lists:member(DepsDir, Parts2) of - true -> - Acc; % There is a directory named "deps" in path - false -> - [F | Acc] % No "deps" directory in path - end - end, []). - -remove_common_prefix([H1|T1], [H1|T2]) -> - remove_common_prefix(T1, T2); -remove_common_prefix(L1, _) -> - L1. - -get_ct_config_file(TestDir) -> - State = filename:join(TestDir, "test.config"), - case filelib:is_regular(State) of - false -> - " "; - true -> - " -ct_config " ++ State - end. - -get_config_file(TestDir) -> - State = filename:join(TestDir, "app.config"), - case filelib:is_regular(State) of - false -> - " "; - true -> - " -config " ++ State - end. - -get_suites(State, TestDir) -> - case get_suites(State) of - undefined -> - " -dir " ++ TestDir; - Suites -> - Suites1 = string:tokens(Suites, ","), - Suites2 = [find_suite_path(Suite, TestDir) || Suite <- Suites1], - string:join([" -suite"] ++ Suites2, " ") - end. - -get_suites(State) -> - case rebar_state:get(State, suites, undefined) of - undefined -> - rebar_state:get(State, suite, undefined); - Suites -> - Suites - end. - -find_suite_path(Suite, TestDir) -> - Path = filename:join(TestDir, Suite ++ "_SUITE.erl"), - case filelib:is_regular(Path) of - false -> - ?WARN("Suite ~s not found\n", [Suite]), - %% Note - this throw is caught in run_test_if_present/3; - %% this solution was easier than refactoring the entire module. - throw(skip); - true -> - Path - end. - -get_case(State) -> - case rebar_state:get(State, 'case', undefined) of - undefined -> - ""; - Case -> - " -case " ++ Case - end. diff --git a/src/rebar_edoc.erl b/src/rebar_edoc.erl deleted file mode 100644 index c828d27..0000000 --- a/src/rebar_edoc.erl +++ /dev/null @@ -1,130 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2010 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- -%% @author Dave Smith <dizzyd@dizzyd.com> -%% @doc rebar_edoc supports the following command: -%% <ul> -%% <li>doc (essentially erl -noshell -run edoc_run application -%% "'$(<app_name>)'" -%% '"."' '[<options>]')</li> -%% </ul> -%% EDoc options can be given in the <code>edoc_opts</code> option in -%% <code>rebar.config</code>. -%% @copyright 2010 Dave Smith -%% ------------------------------------------------------------------- --module(rebar_edoc). - --export([doc/2]). - -%% for internal use only --export([info/2]). - --include("rebar.hrl"). - -%% =================================================================== -%% Public API -%% =================================================================== - -doc(Config, File) -> - %% Save code path - CodePath = setup_code_path(), - - %% Get the edoc_opts and app file info - EDocOpts = rebar_config:get(Config, edoc_opts, []), - {ok, Config1, AppName, _AppData} = - rebar_app_utils:load_app_file(Config, File), - - case needs_regen(EDocOpts) of - true -> - ?INFO("Regenerating edocs for ~p\n", [AppName]), - ok = edoc:application(AppName, ".", EDocOpts); - false -> - ?INFO("Skipping regeneration of edocs for ~p\n", [AppName]), - ok - end, - - %% Restore code path - true = code:set_path(CodePath), - {ok, Config1}. - -%% =================================================================== -%% Internal functions -%% =================================================================== - -info(help, doc) -> - ?CONSOLE( - "Generate Erlang program documentation.~n" - "~n" - "Valid rebar.config options:~n" - " {edoc_opts, []} (see edoc:application/3 documentation)~n", - []). - -setup_code_path() -> - %% Setup code path prior to calling edoc so that edown, asciiedoc, - %% and the like can work properly when generating their own - %% documentation. - CodePath = code:get_path(), - true = code:add_patha(rebar_utils:ebin_dir()), - CodePath. - --type path_spec() :: {'file', file:filename()} | file:filename(). --spec newer_file_exists(Paths::[path_spec()], OldFile::string()) -> boolean(). -newer_file_exists(Paths, OldFile) -> - OldModTime = filelib:last_modified(OldFile), - - ThrowIfNewer = fun(Fn, _Acc) -> - FModTime = filelib:last_modified(Fn), - (FModTime > OldModTime) andalso - throw({newer_file_exists, {Fn, FModTime}}) - end, - - try - lists:foldl(fun({file, F}, _) -> - ThrowIfNewer(F, false); - (P, _) -> - filelib:fold_files(P, ".*.erl", true, - ThrowIfNewer, false) - end, undefined, Paths) - catch - throw:{newer_file_exists, {Filename, FMod}} -> - ?DEBUG("~p is more recent than ~p: " - "~120p > ~120p\n", - [Filename, OldFile, FMod, OldModTime]), - true - end. - -%% Needs regen if any dependent file is changed since the last -%% edoc run. Dependent files are the erlang source files, -%% and the overview file, if it exists. --spec needs_regen(proplists:proplist()) -> boolean(). -needs_regen(EDocOpts) -> - DocDir = proplists:get_value(dir, EDocOpts, "doc"), - EDocInfoName = filename:join(DocDir, "edoc-info"), - OverviewFile = proplists:get_value(overview, EDocOpts, "overview.edoc"), - EDocOverviewName = filename:join(DocDir, OverviewFile), - SrcPaths = proplists:get_value(source_path, EDocOpts, ["src"]), - - newer_file_exists([{file, EDocOverviewName} | SrcPaths], EDocInfoName). diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl deleted file mode 100644 index 39dd35d..0000000 --- a/src/rebar_eunit.erl +++ /dev/null @@ -1,675 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- -%% @author Dave Smith <dizzyd@dizzyd.com> -%% @doc rebar_eunit supports the following commands: -%% <ul> -%% <li>eunit - runs eunit tests</li> -%% <li>clean - remove ?EUNIT_DIR directory</li> -%% <li>reset_after_eunit::boolean() - default = true. -%% If true, try to "reset" VM state to approximate state prior to -%% running the EUnit tests: -%% <ul> -%% <li>Stop net_kernel if it was started</li> -%% <li>Stop OTP applications not running before EUnit tests were run</li> -%% <li>Kill processes not running before EUnit tests were run</li> -%% <li>Reset OTP application environment variables</li> -%% </ul> -%% </li> -%% </ul> -%% The following Global options are supported: -%% <ul> -%% <li>verbose=1 - show extra output from the eunit test</li> -%% <li> -%% suites="foo,bar" - runs tests in foo.erl, test/foo_tests.erl and -%% tests in bar.erl, test/bar_tests.erl -%% </li> -%% <li> -%% suites="foo,bar" tests="baz"- runs first test with name starting -%% with 'baz' in foo.erl, test/foo_tests.erl and tests in bar.erl, -%% test/bar_tests.erl -%% </li> -%% <li> -%% tests="baz"- For every existing suite, run the first test whose -%% name starts with bar and, if no such test exists, run the test -%% whose name starts with bar in the suite's _tests module -%% </li> -%% </ul> -%% Additionally, for projects that have separate folders for the core -%% implementation, and for the unit tests, then the following -%% <code>rebar.config</code> option can be provided: -%% <code>{eunit_compile_opts, [{src_dirs, ["src", "dir"]}]}.</code>. -%% @copyright 2009, 2010 Dave Smith -%% ------------------------------------------------------------------- --module(rebar_eunit). - --export([eunit/2, - clean/2]). - -%% for internal use only --export([info/2]). - --include("rebar.hrl"). - --define(EUNIT_DIR, ".eunit"). - -%% =================================================================== -%% Public API -%% =================================================================== - -eunit(Config, _AppFile) -> - ok = ensure_dirs(), - %% Save code path - CodePath = setup_code_path(), - CompileOnly = rebar_config:get_global(Config, compile_only, false), - {ok, SrcErls} = rebar_erlc_compiler:test_compile(Config, "eunit", - ?EUNIT_DIR), - case CompileOnly of - "true" -> - true = code:set_path(CodePath), - ?CONSOLE("Compiled modules for eunit~n", []); - false -> - run_eunit(Config, CodePath, SrcErls) - end. - -clean(_Config, _File) -> - rebar_file_utils:rm_rf(?EUNIT_DIR). - -%% =================================================================== -%% Internal functions -%% =================================================================== - -info(help, eunit) -> - info_help("Run eunit tests"); -info(help, clean) -> - Description = ?FMT("Delete eunit test dir (~s)", [?EUNIT_DIR]), - info_help(Description). - -info_help(Description) -> - ?CONSOLE( - "~s.~n" - "~n" - "Valid rebar.config options:~n" - " ~p~n" - " ~p~n" - " ~p~n" - " ~p~n" - " ~p~n" - " ~p~n" - "Valid command line options:~n" - " suite[s]=\"foo,bar\" (Run tests in foo.erl, test/foo_tests.erl and~n" - " tests in bar.erl, test/bar_tests.erl)~n" - " test[s]=\"baz\" (For every existing suite, run the first test whose~n" - " name starts with bar and, if no such test exists,~n" - " run the test whose name starts with bar in the~n" - " suite's _tests module)~n" - " random_suite_order=true (Run tests in random order)~n" - " random_suite_order=Seed (Run tests in random order,~n" - " with the PRNG seeded with Seed)~n" - " compile_only=true (Compile but do not run tests)", - [ - Description, - {eunit_opts, []}, - {eunit_compile_opts, []}, - {eunit_first_files, []}, - {cover_enabled, false}, - {cover_print_enabled, false}, - {cover_export_enabled, false} - ]). - -run_eunit(Config, CodePath, SrcErls) -> - %% Build a list of all the .beams in ?EUNIT_DIR -- use this for - %% cover and eunit testing. Normally you can just tell cover - %% and/or eunit to scan the directory for you, but eunit does a - %% code:purge in conjunction with that scan and causes any cover - %% compilation info to be lost. - - AllBeamFiles = rebar_utils:beams(?EUNIT_DIR), - {BeamFiles, TestBeamFiles} = - lists:partition(fun(N) -> string:str(N, "_tests.beam") =:= 0 end, - AllBeamFiles), - OtherBeamFiles = TestBeamFiles -- - [filename:rootname(N) ++ "_tests.beam" || N <- AllBeamFiles], - ModuleBeamFiles = randomize_suites(Config, BeamFiles ++ OtherBeamFiles), - - %% Get matching tests and modules - AllModules = [rebar_utils:beam_to_mod(?EUNIT_DIR, N) || N <- AllBeamFiles], - {Tests, FilteredModules} = - get_tests_and_modules(Config, ModuleBeamFiles, AllModules), - - SrcModules = [rebar_utils:erl_to_mod(M) || M <- SrcErls], - - {ok, CoverLog} = rebar_cover_utils:init(Config, ModuleBeamFiles, - eunit_dir()), - - StatusBefore = status_before_eunit(), - EunitResult = perform_eunit(Config, Tests), - - rebar_cover_utils:perform_cover(Config, FilteredModules, SrcModules, - eunit_dir()), - rebar_cover_utils:close(CoverLog), - - case proplists:get_value(reset_after_eunit, get_eunit_opts(Config), - true) of - true -> - reset_after_eunit(StatusBefore); - false -> - ok - end, - - %% Stop cover to clean the cover_server state. This is important if we want - %% eunit+cover to not slow down when analyzing many Erlang modules. - ok = rebar_cover_utils:exit(), - - case EunitResult of - ok -> - ok; - _ -> - ?ABORT("One or more eunit tests failed.~n", []) - end, - - %% Restore code path - true = code:set_path(CodePath), - ok. - -ensure_dirs() -> - %% Make sure ?EUNIT_DIR/ and ebin/ directory exists (append dummy module) - ok = filelib:ensure_dir(filename:join(eunit_dir(), "dummy")), - ok = filelib:ensure_dir(filename:join(rebar_utils:ebin_dir(), "dummy")). - -eunit_dir() -> - filename:join(rebar_utils:get_cwd(), ?EUNIT_DIR). - -setup_code_path() -> - %% Setup code path prior to compilation so that parse_transforms - %% and the like work properly. Also, be sure to add ebin_dir() - %% to the END of the code path so that we don't have to jump - %% through hoops to access the .app file - CodePath = code:get_path(), - true = code:add_patha(eunit_dir()), - true = code:add_pathz(rebar_utils:ebin_dir()), - CodePath. - -%% -%% == get matching tests == -%% -get_tests_and_modules(Config, ModuleBeamFiles, AllModules) -> - SelectedSuites = get_selected_suites(Config, AllModules), - {Tests, QualifiedTests} = get_qualified_and_unqualified_tests(Config), - Modules = get_test_modules(SelectedSuites, Tests, - QualifiedTests, ModuleBeamFiles), - FilteredModules = get_matching_modules(AllModules, Modules, QualifiedTests), - MatchedTests = get_matching_tests(Modules, Tests, QualifiedTests), - {MatchedTests, FilteredModules}. - -%% -%% == get suites specified via 'suites' option == -%% -get_selected_suites(Config, Modules) -> - RawSuites = get_suites(Config), - Suites = [list_to_atom(Suite) || Suite <- string:tokens(RawSuites, ",")], - [M || M <- Suites, lists:member(M, Modules)]. - -get_suites(Config) -> - case rebar_config:get_global(Config, suites, "") of - "" -> - rebar_config:get_global(Config, suite, ""); - Suites -> - Suites - end. - -get_qualified_and_unqualified_tests(Config) -> - RawFunctions = rebar_config:get_global(Config, tests, ""), - FunctionNames = [FunctionName || - FunctionName <- string:tokens(RawFunctions, ",")], - get_qualified_and_unqualified_tests1(FunctionNames, [], []). - -get_qualified_and_unqualified_tests1([], Functions, QualifiedFunctions) -> - {Functions, QualifiedFunctions}; -get_qualified_and_unqualified_tests1([TestName|TestNames], Functions, - QualifiedFunctions) -> - case string:tokens(TestName, ":") of - [TestName] -> - Function = list_to_atom(TestName), - get_qualified_and_unqualified_tests1( - TestNames, [Function|Functions], QualifiedFunctions); - [ModuleName, FunctionName] -> - M = list_to_atom(ModuleName), - F = list_to_atom(FunctionName), - get_qualified_and_unqualified_tests1(TestNames, Functions, - [{M, F}|QualifiedFunctions]); - _ -> - ?ABORT("Unsupported test function specification: ~s~n", [TestName]) - end. - -%% Provide modules which are to be searched for tests. -%% Several scenarios are possible: -%% -%% == randomize suites == -%% - -randomize_suites(Config, Modules) -> - case rebar_config:get_global(Config, random_suite_order, undefined) of - undefined -> - Modules; - "true" -> - Seed = crypto:rand_uniform(1, 65535), - randomize_suites1(Modules, Seed); - String -> - try list_to_integer(String) of - Seed -> - randomize_suites1(Modules, Seed) - catch - error:badarg -> - ?ERROR("Bad random seed provided: ~p~n", [String]), - ?FAIL - end - end. - -randomize_suites1(Modules, Seed) -> - _ = random:seed(35, Seed, 1337), - ?CONSOLE("Randomizing suite order with seed ~b~n", [Seed]), - [X||{_,X} <- lists:sort([{random:uniform(), M} || M <- Modules])]. - -%% -%% == get matching tests == -%% 1) Specific tests have been provided and/or -%% no unqualified tests have been specified and -%% there were some qualified tests, then we can search for -%% functions in specified suites (or in empty set of suites). -%% -%% 2) Neither specific suites nor qualified test names have been -%% provided use ModuleBeamFiles which filters out "*_tests" -%% modules so EUnit won't doubly run them and cover only -%% calculates coverage on production code. However, -%% keep "*_tests" modules that are not automatically -%% included by EUnit. -%% -%% From 'Primitives' in the EUnit User's Guide -%% http://www.erlang.org/doc/apps/eunit/chapter.html -%% "In addition, EUnit will also look for another -%% module whose name is ModuleName plus the suffix -%% _tests, and if it exists, all the tests from that -%% module will also be added. (If ModuleName already -%% contains the suffix _tests, this is not done.) E.g., -%% the specification {module, mymodule} will run all -%% tests in the modules mymodule and mymodule_tests. -%% Typically, the _tests module should only contain -%% test cases that use the public interface of the main -%% module (and no other code)." -get_test_modules(SelectedSuites, Tests, QualifiedTests, ModuleBeamFiles) -> - SuitesProvided = SelectedSuites =/= [], - OnlyQualifiedTestsProvided = QualifiedTests =/= [] andalso Tests =:= [], - if - SuitesProvided orelse OnlyQualifiedTestsProvided -> - SelectedSuites; - true -> - [rebar_utils:beam_to_mod(?EUNIT_DIR, N) || - N <- ModuleBeamFiles] - end. - -get_matching_modules(AllModules, Modules, QualifiedTests) -> - ModuleFilterMapper = - fun({M, _}) -> - case lists:member(M, AllModules) of - true -> {true, M}; - _-> false - end - end, - ModulesFromQualifiedTests = lists:zf(ModuleFilterMapper, QualifiedTests), - lists:usort(Modules ++ ModulesFromQualifiedTests). - -get_matching_tests(Modules, [], []) -> - Modules; -get_matching_tests(Modules, [], QualifiedTests) -> - FilteredQualifiedTests = filter_qualified_tests(Modules, QualifiedTests), - lists:merge(Modules, make_test_primitives(FilteredQualifiedTests)); -get_matching_tests(Modules, Tests, QualifiedTests) -> - AllTests = lists:merge(QualifiedTests, - get_matching_tests1(Modules, Tests, [])), - make_test_primitives(AllTests). - -filter_qualified_tests(Modules, QualifiedTests) -> - TestsFilter = fun({Module, _Function}) -> - lists:all(fun(M) -> M =/= Module end, Modules) end, - lists:filter(TestsFilter, QualifiedTests). - -get_matching_tests1([], _Functions, TestFunctions) -> - TestFunctions; - -get_matching_tests1([Module|TModules], Functions, TestFunctions) -> - %% Get module exports - ModuleStr = atom_to_list(Module), - ModuleExports = get_beam_test_exports(ModuleStr), - %% Get module _tests exports - TestModuleStr = string:concat(ModuleStr, "_tests"), - TestModuleExports = get_beam_test_exports(TestModuleStr), - %% Build tests {M, F} list - Tests = get_matching_tests2(Functions, {Module, ModuleExports}, - {list_to_atom(TestModuleStr), - TestModuleExports}), - get_matching_tests1(TModules, Functions, - lists:merge([TestFunctions, Tests])). - -get_matching_tests2(Functions, {Mod, ModExports}, {TestMod, TestModExports}) -> - %% Look for matching functions into ModExports - ModExportsStr = [atom_to_list(E1) || E1 <- ModExports], - TestModExportsStr = [atom_to_list(E2) || E2 <- TestModExports], - get_matching_exports(Functions, {Mod, ModExportsStr}, - {TestMod, TestModExportsStr}, []). - -get_matching_exports([], _, _, Matched) -> - Matched; -get_matching_exports([Function|TFunctions], {Mod, ModExportsStr}, - {TestMod, TestModExportsStr}, Matched) -> - - FunctionStr = atom_to_list(Function), - %% Get matching Function in module, otherwise look in _tests module - NewMatch = case get_matching_export(FunctionStr, ModExportsStr) of - [] -> - {TestMod, get_matching_export(FunctionStr, - TestModExportsStr)}; - MatchingExport -> - {Mod, MatchingExport} - end, - case NewMatch of - {_, []} -> - get_matching_exports(TFunctions, {Mod, ModExportsStr}, - {TestMod, TestModExportsStr}, Matched); - _ -> - get_matching_exports(TFunctions, {Mod, ModExportsStr}, - {TestMod, TestModExportsStr}, - [NewMatch|Matched]) - end. - -get_matching_export(_FunctionStr, []) -> - []; -get_matching_export(FunctionStr, [ExportStr|TExportsStr]) -> - case string:str(ExportStr, FunctionStr) of - 1 -> - list_to_atom(ExportStr); - _ -> - get_matching_export(FunctionStr, TExportsStr) - end. - -get_beam_test_exports(ModuleStr) -> - FilePath = filename:join(eunit_dir(), - string:concat(ModuleStr, ".beam")), - case filelib:is_regular(FilePath) of - true -> - {beam_file, _, Exports0, _, _, _} = beam_disasm:file(FilePath), - Exports1 = [FunName || {FunName, FunArity, _} <- Exports0, - FunArity =:= 0], - F = fun(FName) -> - FNameStr = atom_to_list(FName), - re:run(FNameStr, "_test(_)?") =/= nomatch - end, - lists:filter(F, Exports1); - _ -> - [] - end. - -make_test_primitives(RawTests) -> - %% Use {test,M,F} and {generator,M,F} if at least R15B02. Otherwise, - %% use eunit_test:function_wrapper/2 fallback. - %% eunit_test:function_wrapper/2 was renamed to eunit_test:mf_wrapper/2 - %% in R15B02; use that as >= R15B02 check. - %% TODO: remove fallback and use only {test,M,F} and {generator,M,F} - %% primitives once at least R15B02 is required. - {module, eunit_test} = code:ensure_loaded(eunit_test), - MakePrimitive = case erlang:function_exported(eunit_test, mf_wrapper, 2) of - true -> fun eunit_primitive/3; - false -> fun pre15b02_eunit_primitive/3 - end, - - ?CONSOLE(" Running test function(s):~n", []), - F = fun({M, F2}, Acc) -> - ?CONSOLE(" ~p:~p/0~n", [M, F2]), - FNameStr = atom_to_list(F2), - NewFunction = - case re:run(FNameStr, "_test_") of - nomatch -> - %% Normal test - MakePrimitive(test, M, F2); - _ -> - %% Generator - MakePrimitive(generator, M, F2) - end, - [NewFunction|Acc] - end, - lists:foldl(F, [], RawTests). - -eunit_primitive(Type, M, F) -> - {Type, M, F}. - -pre15b02_eunit_primitive(test, M, F) -> - eunit_test:function_wrapper(M, F); -pre15b02_eunit_primitive(generator, M, F) -> - {generator, eunit_test:function_wrapper(M, F)}. - -%% -%% == run tests == -%% - -perform_eunit(Config, Tests) -> - EunitOpts = get_eunit_opts(Config), - - %% Move down into ?EUNIT_DIR while we run tests so any generated files - %% are created there (versus in the source dir) - Cwd = rebar_utils:get_cwd(), - ok = file:set_cwd(?EUNIT_DIR), - - EunitResult = (catch eunit:test(Tests, EunitOpts)), - - %% Return to original working dir - ok = file:set_cwd(Cwd), - - EunitResult. - -get_eunit_opts(Config) -> - %% Enable verbose in eunit if so requested.. - BaseOpts = case rebar_log:is_verbose(Config) of - true -> - [verbose]; - false -> - [] - end, - - BaseOpts ++ rebar_config:get_list(Config, eunit_opts, []). - -%% -%% == reset_after_eunit == -%% - -status_before_eunit() -> - Apps = get_app_names(), - AppEnvs = [{App, application:get_all_env(App)} || App <- Apps], - {erlang:processes(), erlang:is_alive(), AppEnvs, ets:tab2list(ac_tab)}. - -get_app_names() -> - [AppName || {AppName, _, _} <- application:loaded_applications()]. - -reset_after_eunit({OldProcesses, WasAlive, OldAppEnvs, _OldACs}) -> - IsAlive = erlang:is_alive(), - if not WasAlive andalso IsAlive -> - ?DEBUG("Stopping net kernel....\n", []), - erl_epmd:stop(), - _ = net_kernel:stop(), - pause_until_net_kernel_stopped(); - true -> - ok - end, - - OldApps = [App || {App, _} <- OldAppEnvs], - Apps = get_app_names(), - _ = [begin - _ = case lists:member(App, OldApps) of - true -> ok; - false -> application:stop(App) - end, - ok = application:unset_env(App, K) - end || App <- Apps, App /= rebar, - {K, _V} <- application:get_all_env(App), - K =/= included_applications], - - reconstruct_app_env_vars(Apps), - - Processes = erlang:processes(), - _ = kill_extras(Processes -- OldProcesses), - - ok. - -kill_extras(Pids) -> - %% Killing any of the procs below will either: - %% 1. Interfere with stuff that we don't want interfered with, or - %% 2. May/will force the 'kernel' app to shutdown, which *will* - %% interfere with rebar's ability To Do Useful Stuff(tm). - %% This list may require changes as OTP versions and/or - %% rebar use cases change. - KeepProcs = [cover_server, eunit_server, - eqc, eqc_license, eqc_locked, - %% inet_gethost_native is started on demand, when - %% doing name lookups. It is under kernel_sup, under - %% a supervisor_bridge. - inet_gethost_native], - Killed = [begin - Info = case erlang:process_info(Pid) of - undefined -> []; - Else -> Else - end, - Keep1 = case proplists:get_value(registered_name, Info) of - undefined -> - false; - Name -> - lists:member(Name, KeepProcs) - end, - Keep2 = case proplists:get_value(dictionary, Info) of - undefined -> - false; - Ds -> - case proplists:get_value('$ancestors', Ds) of - undefined -> - false; - As -> - lists:member(kernel_sup, As) - end - end, - if Keep1 orelse Keep2 -> - ok; - true -> - ?DEBUG("Kill ~p ~p\n", [Pid, Info]), - exit(Pid, kill), - Pid - end - end || Pid <- Pids], - case lists:usort(Killed) -- [ok] of - [] -> - ?DEBUG("No processes to kill\n", []), - []; - Else -> - lists:foreach(fun(Pid) -> wait_until_dead(Pid) end, Else), - Else - end. - -reconstruct_app_env_vars([App|Apps]) -> - CmdLine0 = proplists:get_value(App, init:get_arguments(), []), - CmdVars = [{list_to_atom(K), list_to_atom(V)} || {K, V} <- CmdLine0], - AppFile = (catch filename:join([code:lib_dir(App), - "ebin", - atom_to_list(App) ++ ".app"])), - AppVars = case file:consult(AppFile) of - {ok, [{application, App, Ps}]} -> - proplists:get_value(env, Ps, []); - _ -> - [] - end, - - %% App vars specified in config files override those in the .app file. - %% Config files later in the args list override earlier ones. - AppVars1 = case init:get_argument(config) of - {ok, ConfigFiles} -> - {App, MergedAppVars} = lists:foldl(fun merge_app_vars/2, - {App, AppVars}, - ConfigFiles), - MergedAppVars; - error -> - AppVars - end, - AllVars = CmdVars ++ AppVars1, - ?DEBUG("Reconstruct ~p ~p\n", [App, AllVars]), - lists:foreach(fun({K, V}) -> application:set_env(App, K, V) end, AllVars), - reconstruct_app_env_vars(Apps); -reconstruct_app_env_vars([]) -> - ok. - -merge_app_vars(ConfigFile, {App, AppVars}) -> - File = ensure_config_extension(ConfigFile), - FileAppVars = app_vars_from_config_file(File, App), - Dict1 = dict:from_list(AppVars), - Dict2 = dict:from_list(FileAppVars), - Dict3 = dict:merge(fun(_Key, _Value1, Value2) -> Value2 end, Dict1, Dict2), - {App, dict:to_list(Dict3)}. - -ensure_config_extension(File) -> - %% config files must end with .config on disk but when specifying them - %% via the -config option the extension is optional - BaseFileName = filename:basename(File, ".config"), - DirName = filename:dirname(File), - filename:join(DirName, BaseFileName ++ ".config"). - -app_vars_from_config_file(File, App) -> - case file:consult(File) of - {ok, [Env]} -> - proplists:get_value(App, Env, []); - _ -> - [] - end. - -wait_until_dead(Pid) when is_pid(Pid) -> - Ref = erlang:monitor(process, Pid), - receive - {'DOWN', Ref, process, _Obj, Info} -> - Info - after 10*1000 -> - exit({timeout_waiting_for, Pid}) - end; -wait_until_dead(_) -> - ok. - -pause_until_net_kernel_stopped() -> - pause_until_net_kernel_stopped(10). - -pause_until_net_kernel_stopped(0) -> - exit(net_kernel_stop_failed); -pause_until_net_kernel_stopped(N) -> - case node() of - 'nonode@nohost' -> - ?DEBUG("Stopped net kernel.\n", []), - ok; - _ -> - timer:sleep(100), - pause_until_net_kernel_stopped(N - 1) - end. diff --git a/src/rebar_fetch.erl b/src/rebar_fetch.erl index 2845b49..2cad9f2 100644 --- a/src/rebar_fetch.erl +++ b/src/rebar_fetch.erl @@ -45,13 +45,14 @@ current_ref(AppDir, {git, _, _}) -> download_source(AppDir, Source) -> TmpDir = ec_file:insecure_mkdtemp(), + AppDir1 = ec_cnv:to_list(AppDir), case download_source_tmp(TmpDir, Source) of {ok, _} -> - ec_file:mkdir_p(AppDir), - ok = ec_file:copy(TmpDir, binary_to_list(filename:absname(AppDir)), [recursive]); + ec_file:mkdir_p(AppDir1), + ok = ec_file:copy(TmpDir, filename:absname(AppDir1), [recursive]); {tarball, File} -> ok = erl_tar:extract(File, [{cwd, - (filename:dirname(filename:absname(binary_to_list(AppDir))))} + (filename:dirname(filename:absname(AppDir1)))} ,compressed]) end. diff --git a/src/rebar_getopt.erl b/src/rebar_getopt.erl deleted file mode 100644 index 79b871d..0000000 --- a/src/rebar_getopt.erl +++ /dev/null @@ -1,914 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author Juan Jose Comellas <juanjo@comellas.org> -%%% @copyright (C) 2009 Juan Jose Comellas -%%% @doc Parses command line options with a format similar to that of GNU getopt. -%%% @end -%%% -%%% This source file is subject to the New BSD License. You should have received -%%% a copy of the New BSD license with this software. If not, it can be -%%% retrieved from: http://www.opensource.org/licenses/bsd-license.php -%%%------------------------------------------------------------------- --module(rebar_getopt). --author('juanjo@comellas.org'). - --export([parse/2, check/2, parse_and_check/2, format_error/2, - usage/2, usage/3, usage/4, tokenize/1]). --export([usage_cmd_line/2]). - --define(LINE_LENGTH, 75). --define(MIN_USAGE_COMMAND_LINE_OPTION_LENGTH, 25). - -%% Position of each field in the option specification tuple. --define(OPT_NAME, 1). --define(OPT_SHORT, 2). --define(OPT_LONG, 3). --define(OPT_ARG, 4). --define(OPT_HELP, 5). - --define(IS_OPT_SPEC(Opt), (tuple_size(Opt) =:= ?OPT_HELP)). --define(IS_WHITESPACE(Char), ((Char) =:= $\s orelse (Char) =:= $\t orelse - (Char) =:= $\n orelse (Char) =:= $\r)). - -%% Atom indicating the data type that an argument can be converted to. --type arg_type() :: 'atom' | 'binary' | 'boolean' | 'float' | 'integer' | 'string'. -%% Data type that an argument can be converted to. --type arg_value() :: atom() | binary() | boolean() | float() | integer() | string(). -%% Argument specification. --type arg_spec() :: arg_type() | {arg_type(), arg_value()} | undefined. -%% Option type and optional default argument. --type simple_option() :: atom(). --type compound_option() :: {atom(), arg_value()}. --type option() :: simple_option() | compound_option(). -%% Command line option specification. --type option_spec() :: { - Name :: atom(), - Short :: char() | undefined, - Long :: string() | undefined, - ArgSpec :: arg_spec(), - Help :: string() | undefined - }. -%% Output streams --type output_stream() :: 'standard_io' | 'standard_error'. - -%% For internal use --type usage_line() :: {OptionText :: string(), HelpText :: string()}. --type usage_line_with_length() :: {OptionLength :: non_neg_integer(), OptionText :: string(), HelpText :: string()}. - - --export_type([arg_type/0, arg_value/0, arg_spec/0, simple_option/0, compound_option/0, option/0, option_spec/0]). - - -%% @doc Parse the command line options and arguments returning a list of tuples -%% and/or atoms using the Erlang convention for sending options to a -%% function. Additionally perform check if all required options (the ones -%% without default values) are present. The function is a combination of -%% two calls: parse/2 and check/2. --spec parse_and_check([option_spec()], string() | [string()]) -> - {ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data :: term()}}. -parse_and_check(OptSpecList, CmdLine) when is_list(OptSpecList), is_list(CmdLine) -> - case parse(OptSpecList, CmdLine) of - {ok, {Opts, _}} = Result -> - case check(OptSpecList, Opts) of - ok -> Result; - Error -> Error - end; - Error -> - Error - end. - -%% @doc Check the parsed command line arguments returning ok if all required -%% options (i.e. that don't have defaults) are present, and returning -%% error otherwise. --spec check([option_spec()], [option()]) -> - ok | {error, {Reason :: atom(), Option :: atom()}}. -check(OptSpecList, ParsedOpts) when is_list(OptSpecList), is_list(ParsedOpts) -> - try - RequiredOpts = [Name || {Name, _, _, Arg, _} <- OptSpecList, - not is_tuple(Arg) andalso Arg =/= undefined], - lists:foreach(fun (Option) -> - case proplists:is_defined(Option, ParsedOpts) of - true -> - ok; - false -> - throw({error, {missing_required_option, Option}}) - end - end, RequiredOpts) - catch - _:Error -> - Error - end. - - -%% @doc Parse the command line options and arguments returning a list of tuples -%% and/or atoms using the Erlang convention for sending options to a -%% function. --spec parse([option_spec()], string() | [string()]) -> - {ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data :: term()}}. -parse(OptSpecList, CmdLine) when is_list(CmdLine) -> - try - Args = if - is_integer(hd(CmdLine)) -> tokenize(CmdLine); - true -> CmdLine - end, - parse(OptSpecList, [], [], 0, Args) - catch - throw: {error, {_Reason, _Data}} = Error -> - Error - end. - - --spec parse([option_spec()], [option()], [string()], integer(), [string()]) -> - {ok, {[option()], [string()]}}. -%% Process the option terminator. -parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, ["--" | Tail]) -> - %% Any argument present after the terminator is not considered an option. - {ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc, Tail)}}; -%% Process long options. -parse(OptSpecList, OptAcc, ArgAcc, ArgPos, ["--" ++ OptArg = OptStr | Tail]) -> - parse_long_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg); -%% Process short options. -parse(OptSpecList, OptAcc, ArgAcc, ArgPos, ["-" ++ ([_Char | _] = OptArg) = OptStr | Tail]) -> - parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg); -%% Process non-option arguments. -parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [Arg | Tail]) -> - case find_non_option_arg(OptSpecList, ArgPos) of - {value, OptSpec} when ?IS_OPT_SPEC(OptSpec) -> - parse(OptSpecList, add_option_with_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos + 1, Tail); - false -> - parse(OptSpecList, OptAcc, [Arg | ArgAcc], ArgPos, Tail) - end; -parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, []) -> - %% Once we have completed gathering the options we add the ones that were - %% not present but had default arguments in the specification. - {ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc)}}. - - -%% @doc Format the error code returned by prior call to parse/2 or check/2. --spec format_error([option_spec()], {error, {Reason :: atom(), Data :: term()}} | - {Reason :: term(), Data :: term()}) -> string(). -format_error(OptSpecList, {error, Reason}) -> - format_error(OptSpecList, Reason); -format_error(OptSpecList, {missing_required_option, Name}) -> - {_Name, Short, Long, _Type, _Help} = lists:keyfind(Name, 1, OptSpecList), - lists:flatten(["missing required option: -", [Short], " (", to_string(Long), ")"]); -format_error(_OptSpecList, {invalid_option, OptStr}) -> - lists:flatten(["invalid option: ", to_string(OptStr)]); -format_error(_OptSpecList, {invalid_option_arg, {Name, Arg}}) -> - lists:flatten(["option \'", to_string(Name) ++ "\' has invalid argument: ", to_string(Arg)]); -format_error(_OptSpecList, {invalid_option_arg, OptStr}) -> - lists:flatten(["invalid option argument: ", to_string(OptStr)]); -format_error(_OptSpecList, {Reason, Data}) -> - lists:flatten([to_string(Reason), " ", to_string(Data)]). - - -%% @doc Parse a long option, add it to the option accumulator and continue -%% parsing the rest of the arguments recursively. -%% A long option can have the following syntax: -%% --foo Single option 'foo', no argument -%% --foo=bar Single option 'foo', argument "bar" -%% --foo bar Single option 'foo', argument "bar" --spec parse_long_option([option_spec()], [option()], [string()], integer(), [string()], string(), string()) -> - {ok, {[option()], [string()]}}. -parse_long_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) -> - case split_assigned_arg(OptArg) of - {Long, Arg} -> - %% Get option that has its argument within the same string - %% separated by an equal ('=') character (e.g. "--port=1000"). - parse_long_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg); - - Long -> - case lists:keyfind(Long, ?OPT_LONG, OptSpecList) of - {Name, _Short, Long, undefined, _Help} -> - parse(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args); - - {_Name, _Short, Long, _ArgSpec, _Help} = OptSpec -> - %% The option argument string is empty, but the option requires - %% an argument, so we look into the next string in the list. - %% e.g ["--port", "1000"] - parse_long_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec); - false -> - throw({error, {invalid_option, OptStr}}) - end - end. - - -%% @doc Parse an option where the argument is 'assigned' in the same string using -%% the '=' character, add it to the option accumulator and continue parsing the -%% rest of the arguments recursively. This syntax is only valid for long options. --spec parse_long_option_assigned_arg([option_spec()], [option()], [string()], integer(), - [string()], string(), string(), string()) -> - {ok, {[option()], [string()]}}. -parse_long_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg) -> - case lists:keyfind(Long, ?OPT_LONG, OptSpecList) of - {_Name, _Short, Long, ArgSpec, _Help} = OptSpec -> - case ArgSpec of - undefined -> - throw({error, {invalid_option_arg, OptStr}}); - _ -> - parse(OptSpecList, add_option_with_assigned_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos, Args) - end; - false -> - throw({error, {invalid_option, OptStr}}) - end. - - -%% @doc Split an option string that may contain an option with its argument -%% separated by an equal ('=') character (e.g. "port=1000"). --spec split_assigned_arg(string()) -> {Name :: string(), Arg :: string()} | string(). -split_assigned_arg(OptStr) -> - split_assigned_arg(OptStr, OptStr, []). - -split_assigned_arg(_OptStr, "=" ++ Tail, Acc) -> - {lists:reverse(Acc), Tail}; -split_assigned_arg(OptStr, [Char | Tail], Acc) -> - split_assigned_arg(OptStr, Tail, [Char | Acc]); -split_assigned_arg(OptStr, [], _Acc) -> - OptStr. - - -%% @doc Retrieve the argument for an option from the next string in the list of -%% command-line parameters or set the value of the argument from the argument -%% specification (for boolean and integer arguments), if possible. -parse_long_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec) -> - ArgSpecType = arg_spec_type(ArgSpec), - case Args =:= [] orelse is_implicit_arg(ArgSpecType, hd(Args)) of - true -> - parse(OptSpecList, add_option_with_implicit_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args); - false -> - [Arg | Tail] = Args, - try - parse(OptSpecList, [{Name, to_type(ArgSpecType, Arg)} | OptAcc], ArgAcc, ArgPos, Tail) - catch - error:_ -> - throw({error, {invalid_option_arg, {Name, Arg}}}) - end - end. - - -%% @doc Parse a short option, add it to the option accumulator and continue -%% parsing the rest of the arguments recursively. -%% A short option can have the following syntax: -%% -a Single option 'a', no argument or implicit boolean argument -%% -a foo Single option 'a', argument "foo" -%% -afoo Single option 'a', argument "foo" -%% -abc Multiple options: 'a'; 'b'; 'c' -%% -bcafoo Multiple options: 'b'; 'c'; 'a' with argument "foo" -%% -aaa Multiple repetitions of option 'a' (only valid for options with integer arguments) --spec parse_short_option([option_spec()], [option()], [string()], integer(), [string()], string(), string()) -> - {ok, {[option()], [string()]}}. -parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) -> - parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, first, OptArg). - -parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptPos, [Short | Arg]) -> - case lists:keyfind(Short, ?OPT_SHORT, OptSpecList) of - {Name, Short, _Long, undefined, _Help} -> - parse_short_option(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args, OptStr, first, Arg); - - {_Name, Short, _Long, ArgSpec, _Help} = OptSpec -> - %% The option has a specification, so it requires an argument. - case Arg of - [] -> - %% The option argument string is empty, but the option requires - %% an argument, so we look into the next string in the list. - parse_short_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec, OptPos); - - _ -> - case is_valid_arg(ArgSpec, Arg) of - true -> - parse(OptSpecList, add_option_with_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos, Args); - _ -> - NewOptAcc = case OptPos of - first -> add_option_with_implicit_arg(OptSpec, OptAcc); - _ -> add_option_with_implicit_incrementable_arg(OptSpec, OptAcc) - end, - parse_short_option(OptSpecList, NewOptAcc, ArgAcc, ArgPos, Args, OptStr, next, Arg) - end - end; - - false -> - throw({error, {invalid_option, OptStr}}) - end; -parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, _OptStr, _OptPos, []) -> - parse(OptSpecList, OptAcc, ArgAcc, ArgPos, Args). - - -%% @doc Retrieve the argument for an option from the next string in the list of -%% command-line parameters or set the value of the argument from the argument -%% specification (for boolean and integer arguments), if possible. -parse_short_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec, OptPos) -> - case Args =:= [] orelse is_implicit_arg(ArgSpec, hd(Args)) of - true when OptPos =:= first -> - parse(OptSpecList, add_option_with_implicit_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args); - true -> - parse(OptSpecList, add_option_with_implicit_incrementable_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args); - false -> - [Arg | Tail] = Args, - try - parse(OptSpecList, [{Name, to_type(ArgSpec, Arg)} | OptAcc], ArgAcc, ArgPos, Tail) - catch - error:_ -> - throw({error, {invalid_option_arg, {Name, Arg}}}) - end - end. - - -%% @doc Find the option for the discrete argument in position specified in the -%% Pos argument. --spec find_non_option_arg([option_spec()], integer()) -> {value, option_spec()} | false. -find_non_option_arg([{_Name, undefined, undefined, _ArgSpec, _Help} = OptSpec | _Tail], 0) -> - {value, OptSpec}; -find_non_option_arg([{_Name, undefined, undefined, _ArgSpec, _Help} | Tail], Pos) -> - find_non_option_arg(Tail, Pos - 1); -find_non_option_arg([_Head | Tail], Pos) -> - find_non_option_arg(Tail, Pos); -find_non_option_arg([], _Pos) -> - false. - - -%% @doc Append options that were not present in the command line arguments with -%% their default arguments. --spec append_default_options([option_spec()], [option()]) -> [option()]. -append_default_options([{Name, _Short, _Long, {_Type, DefaultArg}, _Help} | Tail], OptAcc) -> - append_default_options(Tail, - case lists:keymember(Name, 1, OptAcc) of - false -> - [{Name, DefaultArg} | OptAcc]; - _ -> - OptAcc - end); -%% For options with no default argument. -append_default_options([_Head | Tail], OptAcc) -> - append_default_options(Tail, OptAcc); -append_default_options([], OptAcc) -> - OptAcc. - - -%% @doc Add an option with argument converting it to the data type indicated by the -%% argument specification. --spec add_option_with_arg(option_spec(), string(), [option()]) -> [option()]. -add_option_with_arg({Name, _Short, _Long, ArgSpec, _Help} = OptSpec, Arg, OptAcc) -> - case is_valid_arg(ArgSpec, Arg) of - true -> - try - [{Name, to_type(ArgSpec, Arg)} | OptAcc] - catch - error:_ -> - throw({error, {invalid_option_arg, {Name, Arg}}}) - end; - false -> - add_option_with_implicit_arg(OptSpec, OptAcc) - end. - - -%% @doc Add an option with argument that was part of an assignment expression -%% (e.g. "--verbose=3") converting it to the data type indicated by the -%% argument specification. --spec add_option_with_assigned_arg(option_spec(), string(), [option()]) -> [option()]. -add_option_with_assigned_arg({Name, _Short, _Long, ArgSpec, _Help}, Arg, OptAcc) -> - try - [{Name, to_type(ArgSpec, Arg)} | OptAcc] - catch - error:_ -> - throw({error, {invalid_option_arg, {Name, Arg}}}) - end. - - -%% @doc Add an option that required an argument but did not have one. Some data -%% types (boolean, integer) allow implicit or assumed arguments. --spec add_option_with_implicit_arg(option_spec(), [option()]) -> [option()]. -add_option_with_implicit_arg({Name, _Short, _Long, ArgSpec, _Help}, OptAcc) -> - case arg_spec_type(ArgSpec) of - boolean -> - %% Special case for boolean arguments: if there is no argument we - %% set the value to 'true'. - [{Name, true} | OptAcc]; - integer -> - %% Special case for integer arguments: if the option had not been set - %% before we set the value to 1. This is needed to support options like - %% "-v" to return something like {verbose, 1}. - [{Name, 1} | OptAcc]; - _ -> - throw({error, {missing_option_arg, Name}}) - end. - - -%% @doc Add an option with an implicit or assumed argument. --spec add_option_with_implicit_incrementable_arg(option_spec() | arg_spec(), [option()]) -> [option()]. -add_option_with_implicit_incrementable_arg({Name, _Short, _Long, ArgSpec, _Help}, OptAcc) -> - case arg_spec_type(ArgSpec) of - boolean -> - %% Special case for boolean arguments: if there is no argument we - %% set the value to 'true'. - [{Name, true} | OptAcc]; - integer -> - %% Special case for integer arguments: if the option had not been set - %% before we set the value to 1; if not we increment the previous value - %% the option had. This is needed to support options like "-vvv" to - %% return something like {verbose, 3}. - case OptAcc of - [{Name, Count} | Tail] -> - [{Name, Count + 1} | Tail]; - _ -> - [{Name, 1} | OptAcc] - end; - _ -> - throw({error, {missing_option_arg, Name}}) - end. - - -%% @doc Retrieve the data type form an argument specification. --spec arg_spec_type(arg_spec()) -> arg_type() | undefined. -arg_spec_type({Type, _DefaultArg}) -> - Type; -arg_spec_type(Type) when is_atom(Type) -> - Type. - - -%% @doc Convert an argument string to its corresponding data type. --spec to_type(arg_spec() | arg_type(), string()) -> arg_value(). -to_type({Type, _DefaultArg}, Arg) -> - to_type(Type, Arg); -to_type(binary, Arg) -> - list_to_binary(Arg); -to_type(atom, Arg) -> - list_to_atom(Arg); -to_type(integer, Arg) -> - list_to_integer(Arg); -to_type(float, Arg) -> - list_to_float(Arg); -to_type(boolean, Arg) -> - LowerArg = string:to_lower(Arg), - case is_arg_true(LowerArg) of - true -> - true; - _ -> - case is_arg_false(LowerArg) of - true -> - false; - false -> - erlang:error(badarg) - end - end; -to_type(_Type, Arg) -> - Arg. - - --spec is_arg_true(string()) -> boolean(). -is_arg_true(Arg) -> - (Arg =:= "true") orelse (Arg =:= "t") orelse - (Arg =:= "yes") orelse (Arg =:= "y") orelse - (Arg =:= "on") orelse (Arg =:= "enabled") orelse - (Arg =:= "1"). - - --spec is_arg_false(string()) -> boolean(). -is_arg_false(Arg) -> - (Arg =:= "false") orelse (Arg =:= "f") orelse - (Arg =:= "no") orelse (Arg =:= "n") orelse - (Arg =:= "off") orelse (Arg =:= "disabled") orelse - (Arg =:= "0"). - - --spec is_valid_arg(arg_spec(), nonempty_string()) -> boolean(). -is_valid_arg({Type, _DefaultArg}, Arg) -> - is_valid_arg(Type, Arg); -is_valid_arg(boolean, Arg) -> - is_boolean_arg(Arg); -is_valid_arg(integer, Arg) -> - is_non_neg_integer_arg(Arg); -is_valid_arg(float, Arg) -> - is_non_neg_float_arg(Arg); -is_valid_arg(_Type, _Arg) -> - true. - - --spec is_implicit_arg(arg_spec(), nonempty_string()) -> boolean(). -is_implicit_arg({Type, _DefaultArg}, Arg) -> - is_implicit_arg(Type, Arg); -is_implicit_arg(boolean, Arg) -> - not is_boolean_arg(Arg); -is_implicit_arg(integer, Arg) -> - not is_integer_arg(Arg); -is_implicit_arg(_Type, _Arg) -> - false. - - --spec is_boolean_arg(string()) -> boolean(). -is_boolean_arg(Arg) -> - LowerArg = string:to_lower(Arg), - is_arg_true(LowerArg) orelse is_arg_false(LowerArg). - - --spec is_integer_arg(string()) -> boolean(). -is_integer_arg("-" ++ Tail) -> - is_non_neg_integer_arg(Tail); -is_integer_arg(Arg) -> - is_non_neg_integer_arg(Arg). - - --spec is_non_neg_integer_arg(string()) -> boolean(). -is_non_neg_integer_arg([Head | Tail]) when Head >= $0, Head =< $9 -> - is_non_neg_integer_arg(Tail); -is_non_neg_integer_arg([_Head | _Tail]) -> - false; -is_non_neg_integer_arg([]) -> - true. - - --spec is_non_neg_float_arg(string()) -> boolean(). -is_non_neg_float_arg([Head | Tail]) when (Head >= $0 andalso Head =< $9) orelse Head =:= $. -> - is_non_neg_float_arg(Tail); -is_non_neg_float_arg([_Head | _Tail]) -> - false; -is_non_neg_float_arg([]) -> - true. - - -%% @doc Show a message on standard_error indicating the command line options and -%% arguments that are supported by the program. --spec usage([option_spec()], string()) -> ok. -usage(OptSpecList, ProgramName) -> - usage(OptSpecList, ProgramName, standard_error). - - -%% @doc Show a message on standard_error or standard_io indicating the command line options and -%% arguments that are supported by the program. --spec usage([option_spec()], string(), output_stream() | string()) -> ok. -usage(OptSpecList, ProgramName, OutputStream) when is_atom(OutputStream) -> - io:format(OutputStream, "~s~n~n~s~n", - [usage_cmd_line(ProgramName, OptSpecList), usage_options(OptSpecList)]); -%% @doc Show a message on standard_error indicating the command line options and -%% arguments that are supported by the program. The CmdLineTail argument -%% is a string that is added to the end of the usage command line. -usage(OptSpecList, ProgramName, CmdLineTail) -> - usage(OptSpecList, ProgramName, CmdLineTail, standard_error). - - -%% @doc Show a message on standard_error or standard_io indicating the command line options and -%% arguments that are supported by the program. The CmdLineTail argument -%% is a string that is added to the end of the usage command line. --spec usage([option_spec()], ProgramName :: string(), CmdLineTail :: string(), output_stream() | [{string(), string()}]) -> ok. -usage(OptSpecList, ProgramName, CmdLineTail, OutputStream) when is_atom(OutputStream) -> - io:format(OutputStream, "~s~n~n~s~n", - [usage_cmd_line(ProgramName, OptSpecList, CmdLineTail), usage_options(OptSpecList)]); -%% @doc Show a message on standard_error indicating the command line options and -%% arguments that are supported by the program. The CmdLineTail and OptionsTail -%% arguments are a string that is added to the end of the usage command line -%% and a list of tuples that are added to the end of the options' help lines. -usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail) -> - usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail, standard_error). - - -%% @doc Show a message on standard_error or standard_io indicating the command line options and -%% arguments that are supported by the program. The CmdLineTail and OptionsTail -%% arguments are a string that is added to the end of the usage command line -%% and a list of tuples that are added to the end of the options' help lines. --spec usage([option_spec()], ProgramName :: string(), CmdLineTail :: string(), - [{OptionName :: string(), Help :: string()}], output_stream()) -> ok. -usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail, OutputStream) -> - io:format(OutputStream, "~s~n~n~s~n", - [usage_cmd_line(ProgramName, OptSpecList, CmdLineTail), usage_options(OptSpecList, OptionsTail)]). - - --spec usage_cmd_line(ProgramName :: string(), [option_spec()]) -> iolist(). -usage_cmd_line(ProgramName, OptSpecList) -> - usage_cmd_line(ProgramName, OptSpecList, ""). - --spec usage_cmd_line(ProgramName :: string(), [option_spec()], CmdLineTail :: string()) -> iolist(). -usage_cmd_line(ProgramName, OptSpecList, CmdLineTail) -> - Prefix = "Usage: " ++ ProgramName, - PrefixLength = length(Prefix), - LineLength = line_length(), - %% Only align the command line options after the program name when there is - %% enough room to do so (i.e. at least 25 characters). If not, show the - %% command line options below the program name with a 2-character indentation. - if - (LineLength - PrefixLength) > ?MIN_USAGE_COMMAND_LINE_OPTION_LENGTH -> - Indentation = lists:duplicate(PrefixLength, $\s), - [FirstOptLine | OptLines] = usage_cmd_line_options(LineLength - PrefixLength, OptSpecList, CmdLineTail), - IndentedOptLines = [[Indentation | OptLine] || OptLine <- OptLines], - [Prefix, FirstOptLine | IndentedOptLines]; - true -> - IndentedOptLines = [[" " | OptLine] || OptLine <- usage_cmd_line_options(LineLength, OptSpecList, CmdLineTail)], - [Prefix, $\n, IndentedOptLines] - end. - - -%% @doc Return a list of the lines corresponding to the usage command line -%% already wrapped according to the maximum MaxLineLength. --spec usage_cmd_line_options(MaxLineLength :: non_neg_integer(), [option_spec()], CmdLineTail :: string()) -> iolist(). -usage_cmd_line_options(MaxLineLength, OptSpecList, CmdLineTail) -> - usage_cmd_line_options(MaxLineLength, OptSpecList ++ string:tokens(CmdLineTail, " "), [], 0, []). - -usage_cmd_line_options(MaxLineLength, [OptSpec | Tail], LineAcc, LineAccLength, Acc) -> - Option = [$\s | lists:flatten(usage_cmd_line_option(OptSpec))], - OptionLength = length(Option), - %% We accumulate the options in LineAcc until its length is over the - %% maximum allowed line length. When that happens, we append the line in - %% LineAcc to the list with all the lines in the command line (Acc). - NewLineAccLength = LineAccLength + OptionLength, - if - NewLineAccLength < MaxLineLength -> - usage_cmd_line_options(MaxLineLength, Tail, [Option | LineAcc], NewLineAccLength, Acc); - true -> - usage_cmd_line_options(MaxLineLength, Tail, [Option], OptionLength + 1, - [lists:reverse([$\n | LineAcc]) | Acc]) - end; -usage_cmd_line_options(MaxLineLength, [], [_ | _] = LineAcc, _LineAccLength, Acc) -> - %% If there was a non-empty line in LineAcc when there are no more options - %% to process, we add it to the list of lines to return. - usage_cmd_line_options(MaxLineLength, [], [], 0, [lists:reverse(LineAcc) | Acc]); -usage_cmd_line_options(_MaxLineLength, [], [], _LineAccLength, Acc) -> - lists:reverse(Acc). - - --spec usage_cmd_line_option(option_spec()) -> string(). -usage_cmd_line_option({_Name, Short, _Long, undefined, _Help}) when Short =/= undefined -> - %% For options with short form and no argument. - [$[, $-, Short, $]]; -usage_cmd_line_option({_Name, _Short, Long, undefined, _Help}) when Long =/= undefined -> - %% For options with only long form and no argument. - [$[, $-, $-, Long, $]]; -usage_cmd_line_option({_Name, _Short, _Long, undefined, _Help}) -> - []; -usage_cmd_line_option({Name, Short, Long, ArgSpec, _Help}) when is_atom(ArgSpec) -> - %% For options with no default argument. - if - %% For options with short form and argument. - Short =/= undefined -> [$[, $-, Short, $\s, $<, atom_to_list(Name), $>, $]]; - %% For options with only long form and argument. - Long =/= undefined -> [$[, $-, $-, Long, $\s, $<, atom_to_list(Name), $>, $]]; - %% For options with neither short nor long form and argument. - true -> [$[, $<, atom_to_list(Name), $>, $]] - end; -usage_cmd_line_option({Name, Short, Long, ArgSpec, _Help}) when is_tuple(ArgSpec) -> - %% For options with default argument. - if - %% For options with short form and default argument. - Short =/= undefined -> [$[, $-, Short, $\s, $[, $<, atom_to_list(Name), $>, $], $]]; - %% For options with only long form and default argument. - Long =/= undefined -> [$[, $-, $-, Long, $\s, $[, $<, atom_to_list(Name), $>, $], $]]; - %% For options with neither short nor long form and default argument. - true -> [$[, $<, atom_to_list(Name), $>, $]] - end; -usage_cmd_line_option(Option) when is_list(Option) -> - %% For custom options that are added to the command line. - Option. - - -%% @doc Return a list of help messages to print for each of the options and arguments. --spec usage_options([option_spec()]) -> [string()]. -usage_options(OptSpecList) -> - usage_options(OptSpecList, []). - - -%% @doc Return a list of usage lines to print for each of the options and arguments. --spec usage_options([option_spec()], [{OptionName :: string(), Help :: string()}]) -> [string()]. -usage_options(OptSpecList, CustomHelp) -> - %% Add the usage lines corresponding to the option specifications. - {MaxOptionLength0, UsageLines0} = add_option_spec_help_lines(OptSpecList, 0, []), - %% Add the custom usage lines. - {MaxOptionLength, UsageLines} = add_custom_help_lines(CustomHelp, MaxOptionLength0, UsageLines0), - MaxLineLength = line_length(), - lists:reverse([format_usage_line(MaxOptionLength + 1, MaxLineLength, UsageLine) || UsageLine <- UsageLines]). - - --spec add_option_spec_help_lines([option_spec()], PrevMaxOptionLength :: non_neg_integer(), [usage_line_with_length()]) -> - {MaxOptionLength :: non_neg_integer(), [usage_line_with_length()]}. -add_option_spec_help_lines([OptSpec | Tail], PrevMaxOptionLength, Acc) -> - OptionText = usage_option_text(OptSpec), - HelpText = usage_help_text(OptSpec), - {MaxOptionLength, ColsWithLength} = get_max_option_length({OptionText, HelpText}, PrevMaxOptionLength), - add_option_spec_help_lines(Tail, MaxOptionLength, [ColsWithLength | Acc]); -add_option_spec_help_lines([], MaxOptionLength, Acc) -> - {MaxOptionLength, Acc}. - - --spec add_custom_help_lines([usage_line()], PrevMaxOptionLength :: non_neg_integer(), [usage_line_with_length()]) -> - {MaxOptionLength :: non_neg_integer(), [usage_line_with_length()]}. -add_custom_help_lines([CustomCols | Tail], PrevMaxOptionLength, Acc) -> - {MaxOptionLength, ColsWithLength} = get_max_option_length(CustomCols, PrevMaxOptionLength), - add_custom_help_lines(Tail, MaxOptionLength, [ColsWithLength | Acc]); -add_custom_help_lines([], MaxOptionLength, Acc) -> - {MaxOptionLength, Acc}. - - --spec usage_option_text(option_spec()) -> string(). -usage_option_text({Name, undefined, undefined, _ArgSpec, _Help}) -> - %% Neither short nor long form (non-option argument). - "<" ++ atom_to_list(Name) ++ ">"; -usage_option_text({_Name, Short, undefined, _ArgSpec, _Help}) -> - %% Only short form. - [$-, Short]; -usage_option_text({_Name, undefined, Long, _ArgSpec, _Help}) -> - %% Only long form. - [$-, $- | Long]; -usage_option_text({_Name, Short, Long, _ArgSpec, _Help}) -> - %% Both short and long form. - [$-, Short, $,, $\s, $-, $- | Long]. - - --spec usage_help_text(option_spec()) -> string(). -usage_help_text({_Name, _Short, _Long, {_ArgType, ArgValue}, [_ | _] = Help}) -> - Help ++ " [default: " ++ default_arg_value_to_string(ArgValue) ++ "]"; -usage_help_text({_Name, _Short, _Long, _ArgSpec, Help}) -> - Help. - - -%% @doc Calculate the maximum width of the column that shows the option's short -%% and long form. --spec get_max_option_length(usage_line(), PrevMaxOptionLength :: non_neg_integer()) -> - {MaxOptionLength :: non_neg_integer(), usage_line_with_length()}. -get_max_option_length({OptionText, HelpText}, PrevMaxOptionLength) -> - OptionLength = length(OptionText), - {erlang:max(OptionLength, PrevMaxOptionLength), {OptionLength, OptionText, HelpText}}. - - -%% @doc Format the usage line that is shown for the options' usage. Each usage -%% line has 2 columns. The first column shows the options in their short -%% and long form. The second column shows the wrapped (if necessary) help -%% text lines associated with each option. e.g.: -%% -%% -h, --host Database server host name or IP address; this is the -%% hostname of the server where the database is running -%% [default: localhost] -%% -p, --port Database server port [default: 1000] -%% --spec format_usage_line(MaxOptionLength :: non_neg_integer(), MaxLineLength :: non_neg_integer(), - usage_line_with_length()) -> iolist(). -format_usage_line(MaxOptionLength, MaxLineLength, {OptionLength, OptionText, [_ | _] = HelpText}) - when MaxOptionLength < (MaxLineLength div 2) -> - %% If the width of the column where the options are shown is smaller than - %% half the width of a console line then we show the help text line aligned - %% next to its corresponding option, with a separation of at least 2 - %% characters. - [Head | Tail] = wrap_text_line(MaxLineLength - MaxOptionLength - 3, HelpText), - FirstLineIndentation = lists:duplicate(MaxOptionLength - OptionLength + 1, $\s), - Indentation = [$\n | lists:duplicate(MaxOptionLength + 3, $\s)], - [" ", OptionText, FirstLineIndentation, Head, - [[Indentation, Line] || Line <- Tail], $\n]; -format_usage_line(_MaxOptionLength, MaxLineLength, {_OptionLength, OptionText, [_ | _] = HelpText}) -> - %% If the width of the first column is bigger than the width of a console - %% line, we show the help text on the next line with an indentation of 6 - %% characters. - HelpLines = wrap_text_line(MaxLineLength - 6, HelpText), - [" ", OptionText, [["\n ", Line] || Line <- HelpLines], $\n]; -format_usage_line(_MaxOptionLength, _MaxLineLength, {_OptionLength, OptionText, _HelpText}) -> - [" ", OptionText, $\n]. - - -%% @doc Wrap a text line converting it into several text lines so that the -%% length of each one of them is never over Length characters. --spec wrap_text_line(Length :: non_neg_integer(), Text :: string()) -> [string()]. -wrap_text_line(Length, Text) -> - wrap_text_line(Length, Text, [], 0, []). - -wrap_text_line(Length, [Char | Tail], Acc, Count, CurrentLineAcc) when Count < Length -> - wrap_text_line(Length, Tail, Acc, Count + 1, [Char | CurrentLineAcc]); -wrap_text_line(Length, [_ | _] = Help, Acc, Count, CurrentLineAcc) -> - %% Look for the first whitespace character in the current (reversed) line - %% buffer to get a wrapped line. If there is no whitespace just cut the - %% line at the position corresponding to the maximum length. - {NextLineAcc, WrappedLine} = case string:cspan(CurrentLineAcc, " \t") of - WhitespacePos when WhitespacePos < Count -> - lists:split(WhitespacePos, CurrentLineAcc); - _ -> - {[], CurrentLineAcc} - end, - wrap_text_line(Length, Help, [lists:reverse(WrappedLine) | Acc], length(NextLineAcc), NextLineAcc); -wrap_text_line(_Length, [], Acc, _Count, [_ | _] = CurrentLineAcc) -> - %% If there was a non-empty line when we reached the buffer, add it to the accumulator - lists:reverse([lists:reverse(CurrentLineAcc) | Acc]); -wrap_text_line(_Length, [], Acc, _Count, _CurrentLineAcc) -> - lists:reverse(Acc). - - -default_arg_value_to_string(Value) when is_atom(Value) -> - atom_to_list(Value); -default_arg_value_to_string(Value) when is_binary(Value) -> - binary_to_list(Value); -default_arg_value_to_string(Value) when is_integer(Value) -> - integer_to_list(Value); -default_arg_value_to_string(Value) when is_float(Value) -> - lists:flatten(io_lib:format("~w", [Value])); -default_arg_value_to_string(Value) -> - Value. - - -%% @doc Tokenize a command line string with support for single and double -%% quoted arguments (needed for arguments that have embedded whitespace). -%% The function also supports the expansion of environment variables in -%% both the Unix (${VAR}; $VAR) and Windows (%VAR%) formats. It does NOT -%% support wildcard expansion of paths. --spec tokenize(CmdLine :: string()) -> [nonempty_string()]. -tokenize(CmdLine) -> - tokenize(CmdLine, [], []). - --spec tokenize(CmdLine :: string(), Acc :: [string()], ArgAcc :: string()) -> [string()]. -tokenize([Sep | Tail], Acc, ArgAcc) when ?IS_WHITESPACE(Sep) -> - NewAcc = case ArgAcc of - [_ | _] -> - %% Found separator: add to the list of arguments. - [lists:reverse(ArgAcc) | Acc]; - [] -> - %% Found separator with no accumulated argument; discard it. - Acc - end, - tokenize(Tail, NewAcc, []); -tokenize([QuotationMark | Tail], Acc, ArgAcc) when QuotationMark =:= $"; QuotationMark =:= $' -> - %% Quoted argument (might contain spaces, tabs, etc.) - tokenize_quoted_arg(QuotationMark, Tail, Acc, ArgAcc); -tokenize([Char | _Tail] = CmdLine, Acc, ArgAcc) when Char =:= $$; Char =:= $% -> - %% Unix and Windows environment variable expansion: ${VAR}; $VAR; %VAR% - {NewCmdLine, Var} = expand_env_var(CmdLine), - tokenize(NewCmdLine, Acc, lists:reverse(Var, ArgAcc)); -tokenize([$\\, Char | Tail], Acc, ArgAcc) -> - %% Escaped char. - tokenize(Tail, Acc, [Char | ArgAcc]); -tokenize([Char | Tail], Acc, ArgAcc) -> - tokenize(Tail, Acc, [Char | ArgAcc]); -tokenize([], Acc, []) -> - lists:reverse(Acc); -tokenize([], Acc, ArgAcc) -> - lists:reverse([lists:reverse(ArgAcc) | Acc]). - --spec tokenize_quoted_arg(QuotationMark :: char(), CmdLine :: string(), Acc :: [string()], ArgAcc :: string()) -> [string()]. -tokenize_quoted_arg(QuotationMark, [QuotationMark | Tail], Acc, ArgAcc) -> - %% End of quoted argument - tokenize(Tail, Acc, ArgAcc); -tokenize_quoted_arg(QuotationMark, [$\\, Char | Tail], Acc, ArgAcc) -> - %% Escaped char. - tokenize_quoted_arg(QuotationMark, Tail, Acc, [Char | ArgAcc]); -tokenize_quoted_arg($" = QuotationMark, [Char | _Tail] = CmdLine, Acc, ArgAcc) when Char =:= $$; Char =:= $% -> - %% Unix and Windows environment variable expansion (only for double-quoted arguments): ${VAR}; $VAR; %VAR% - {NewCmdLine, Var} = expand_env_var(CmdLine), - tokenize_quoted_arg(QuotationMark, NewCmdLine, Acc, lists:reverse(Var, ArgAcc)); -tokenize_quoted_arg(QuotationMark, [Char | Tail], Acc, ArgAcc) -> - tokenize_quoted_arg(QuotationMark, Tail, Acc, [Char | ArgAcc]); -tokenize_quoted_arg(_QuotationMark, CmdLine, Acc, ArgAcc) -> - tokenize(CmdLine, Acc, ArgAcc). - - --spec expand_env_var(CmdLine :: nonempty_string()) -> {string(), string()}. -expand_env_var(CmdLine) -> - case CmdLine of - "${" ++ Tail -> - expand_env_var("${", $}, Tail, []); - "$" ++ Tail -> - expand_env_var("$", Tail, []); - "%" ++ Tail -> - expand_env_var("%", $%, Tail, []) - end. - --spec expand_env_var(Prefix :: string(), EndMark :: char(), CmdLine :: string(), Acc :: string()) -> {string(), string()}. -expand_env_var(Prefix, EndMark, [Char | Tail], Acc) - when (Char >= $A andalso Char =< $Z) orelse (Char >= $a andalso Char =< $z) orelse - (Char >= $0 andalso Char =< $9) orelse (Char =:= $_) -> - expand_env_var(Prefix, EndMark, Tail, [Char | Acc]); -expand_env_var(Prefix, EndMark, [EndMark | Tail], Acc) -> - {Tail, get_env_var(Prefix, [EndMark], Acc)}; -expand_env_var(Prefix, _EndMark, CmdLine, Acc) -> - {CmdLine, Prefix ++ lists:reverse(Acc)}. - - --spec expand_env_var(Prefix :: string(), CmdLine :: string(), Acc :: string()) -> {string(), string()}. -expand_env_var(Prefix, [Char | Tail], Acc) - when (Char >= $A andalso Char =< $Z) orelse (Char >= $a andalso Char =< $z) orelse - (Char >= $0 andalso Char =< $9) orelse (Char =:= $_) -> - expand_env_var(Prefix, Tail, [Char | Acc]); -expand_env_var(Prefix, CmdLine, Acc) -> - {CmdLine, get_env_var(Prefix, "", Acc)}. - - --spec get_env_var(Prefix :: string(), Suffix :: string(), Acc :: string()) -> string(). -get_env_var(Prefix, Suffix, [_ | _] = Acc) -> - Name = lists:reverse(Acc), - %% Only expand valid/existing variables. - case os:getenv(Name) of - false -> Prefix ++ Name ++ Suffix; - Value -> Value - end; -get_env_var(Prefix, Suffix, []) -> - Prefix ++ Suffix. - - --spec line_length() -> 0..?LINE_LENGTH. -line_length() -> - case io:columns() of - {ok, Columns} when Columns < ?LINE_LENGTH -> - Columns - 1; - _ -> - ?LINE_LENGTH - end. - - --spec to_string(term()) -> string(). -to_string(List) when is_list(List) -> - case io_lib:printable_list(List) of - true -> List; - false -> io_lib:format("~p", [List]) - end; -to_string(Atom) when is_atom(Atom) -> - atom_to_list(Atom); -to_string(Value) -> - io_lib:format("~p", [Value]). diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl index 3d946e9..14a01d7 100644 --- a/src/rebar_otp_app.erl +++ b/src/rebar_otp_app.erl @@ -42,7 +42,7 @@ compile(Config, App) -> %% If we get an .app.src file, it needs to be pre-processed and %% written out as a ebin/*.app file. That resulting file will then %% be validated as usual. - Dir = rebar_app_info:dir(App), + Dir = ec_cnv:to_list(rebar_app_info:dir(App)), {Config2, App1} = case rebar_app_info:app_file_src(App) of undefined -> {Config, App}; diff --git a/src/rebar_prv_app_builder.erl b/src/rebar_prv_app_builder.erl index 52a6b68..4c2d978 100644 --- a/src/rebar_prv_app_builder.erl +++ b/src/rebar_prv_app_builder.erl @@ -39,9 +39,8 @@ do(State) -> {ok, State}. build(State, AppInfo) -> - ?INFO("Compiling ~s ~s~n", [rebar_app_info:name(AppInfo) - ,rebar_app_info:original_vsn(AppInfo)]), - rebar_erlc_compiler:compile(State, rebar_app_info:dir(AppInfo)), + ?INFO("Compiling ~s~n", [rebar_app_info:name(AppInfo)]), + rebar_erlc_compiler:compile(State, ec_cnv:to_list(rebar_app_info:dir(AppInfo))), {ok, AppInfo1} = rebar_otp_app:compile(State, AppInfo), AppInfo1. diff --git a/src/rebar_escripter.erl b/src/rebar_prv_escripter.erl index 2feb186..f153564 100644 --- a/src/rebar_escripter.erl +++ b/src/rebar_prv_escripter.erl @@ -24,7 +24,7 @@ %% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN %% THE SOFTWARE. %% ------------------------------------------------------------------- --module(rebar_escripter). +-module(rebar_prv_escripter). -behaviour(rebar_provider). diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl index 40df88c..3e13fc2 100644 --- a/src/rebar_prv_install_deps.erl +++ b/src/rebar_prv_install_deps.erl @@ -69,28 +69,43 @@ do(State) -> {ok, State}; Deps -> %% Split source deps form binary deps, needed to keep backwards compatibility - {SrcDeps, Goals} = parse_deps(Deps), - State1 = rebar_state:src_deps(rebar_state:goals(State, Goals), SrcDeps), + DepsDir = get_deps_dir(State), + {SrcDeps, Goals} = parse_deps(DepsDir, Deps), + State1 = rebar_state:src_deps(rebar_state:goals(State, Goals), lists:ukeysort(2, SrcDeps)), State2 = update_src_deps(State1), - Goals1 = rebar_state:goals(State2), - {ok, Solved} = rlx_depsolver:solve(Graph, Goals1), - Final = lists:map(fun({Name, Vsn}) -> - FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)), - {ok, P} = dict:find({Name, FmtVsn}, Packages), - PkgDeps = proplists:get_value(<<"deps">>, P), - Link = proplists:get_value(<<"link">>, P), - Source = {Name, FmtVsn, Link}, - {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), - AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), - rebar_app_info:source(AppInfo1, Source) - end, Solved), - ProjectApps = lists:map(fun(X) -> - rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps] ++ [element(1, G) || G <- Goals]) - end, rebar_state:apps_to_build(State2)), - FinalDeps = ProjectApps ++ rebar_state:src_deps(State2) ++ Final, - {ok, Sort} = rebar_topo:sort_apps(FinalDeps), - [io:format("Build ~p~n", [rebar_app_info:name(A)]) || A <- Sort], - {ok, State2} + case rebar_state:goals(State2) of + [] -> + ProjectApps = lists:map(fun(X) -> + rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps]) + end, rebar_state:apps_to_build(State2)), + FinalDeps = ProjectApps ++ rebar_state:src_deps(State2), + {ok, Sort} = rebar_topo:sort_apps(FinalDeps), + State3 = rebar_state:apps_to_build(State2, Sort), + {ok, State3}; + Goals1 -> + {ok, Solved} = rlx_depsolver:solve(Graph, Goals1), + Final = lists:map(fun({Name, Vsn}) -> + FmtVsn = ec_cnv:to_binary(rlx_depsolver:format_version(Vsn)), + {ok, P} = dict:find({Name, FmtVsn}, Packages), + PkgDeps = proplists:get_value(<<"deps">>, P), + Link = proplists:get_value(<<"link">>, P), + Source = {Name, FmtVsn, Link}, + {ok, AppInfo} = rebar_app_info:new(Name, FmtVsn), + AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps), + AppInfo2 = + rebar_app_info:dir(AppInfo1, get_deps_dir(DepsDir, <<Name/binary, "-", FmtVsn/binary>>)), + AppInfo3 = rebar_app_info:source(AppInfo2, Source), + ok = maybe_fetch(AppInfo3), + AppInfo3 + end, Solved), + ProjectApps = lists:map(fun(X) -> + rebar_app_info:deps(X, [rebar_app_info:name(Y) || Y <- SrcDeps] ++ [element(1, G) || G <- Goals1]) + end, rebar_state:apps_to_build(State2)), + FinalDeps = ProjectApps ++ rebar_state:src_deps(State2) ++ Final, + {ok, Sort} = rebar_topo:sort_apps(FinalDeps), + State3 = rebar_state:apps_to_build(State2, Sort), + {ok, State3} + end end; _Locks -> {ok, State} @@ -126,32 +141,40 @@ get_deps_dir(DepsDir, App) -> %% Internal functions %% =================================================================== -%% Fetch missing binary deps -update_deps(State) -> - State. - update_src_deps(State) -> SrcDeps = rebar_state:src_deps(State), - case lists:foldl(fun(AppInfo, {StateAcc, SrcDepsAcc, GoalsAcc}) -> - ok = maybe_fetch(StateAcc, AppInfo), - C = rebar_config:consult(rebar_app_info:dir(AppInfo)), - S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), - Deps = rebar_state:get(S, deps, []), - {SrcDeps1, Goals} = parse_deps(Deps), - NewSrcDeps = SrcDeps1++SrcDepsAcc, - {StateAcc, NewSrcDeps, Goals++GoalsAcc} - end, {State, [], rebar_state:goals(State)}, SrcDeps) of - {State1, [], NewGoals} -> - rebar_state:goals(State1, NewGoals); - {State1, NewSrcDeps, NewGoals}-> - State2 = rebar_state:src_deps(rebar_state:goals(State1, NewGoals), SrcDeps++NewSrcDeps), - update_src_deps(State2) + DepsDir = get_deps_dir(State), + case lists:foldl(fun(AppInfo, {SrcDepsAcc, GoalsAcc}) -> + ok = maybe_fetch(AppInfo), + {NewSrcDeps, NewGoals} = handle_dep(DepsDir, AppInfo), + {lists:ukeymerge(2, SrcDepsAcc, lists:ukeysort(2, NewSrcDeps)), NewGoals++GoalsAcc} + end, {SrcDeps, rebar_state:goals(State)}, SrcDeps) of + {SrcDeps, NewGoals} -> + rebar_state:goals(State, NewGoals); + {NewSrcDeps, NewGoals} -> + io:format("NEWSRC ~p~n", [NewSrcDeps]), + State1 = rebar_state:src_deps(rebar_state:goals(State, NewGoals), NewSrcDeps), + update_src_deps(State1) end. -maybe_fetch(_State, _Dep) -> - ok. +handle_dep(DepsDir, AppInfo) -> + C = rebar_config:consult(rebar_app_info:dir(AppInfo)), + S = rebar_state:new(rebar_state:new(), C, rebar_app_info:dir(AppInfo)), + Deps = rebar_state:get(S, deps, []), + parse_deps(DepsDir, Deps). + +maybe_fetch(AppInfo) -> + AppDir = rebar_app_info:dir(AppInfo), + case filelib:is_dir(AppDir) of + false -> + ?INFO("Fetching ~s~n", [rebar_app_info:name(AppInfo)]), + Source = rebar_app_info:source(AppInfo), + rebar_fetch:download_source(AppDir, Source); + true -> + ok + end. -parse_deps(Deps) -> +parse_deps(DepsDir, Deps) -> lists:foldl(fun({Name, Vsn}, {SrcDepsAcc, GoalsAcc}) -> {SrcDepsAcc, [parse_goal(ec_cnv:to_binary(Name) ,ec_cnv:to_binary(Vsn)) | GoalsAcc]}; @@ -159,7 +182,8 @@ parse_deps(Deps) -> {SrcDepsAcc, [ec_cnv:to_binary(Name) | GoalsAcc]}; ({Name, _, Source}, {SrcDepsAcc, GoalsAcc}) -> {ok, Dep} = rebar_app_info:new(Name), - Dep1 = rebar_app_info:source(Dep, Source), + Dep1 = rebar_app_info:source( + rebar_app_info:dir(Dep, get_deps_dir(DepsDir, Name)), Source), {[Dep1 | SrcDepsAcc], GoalsAcc} end, {[], []}, Deps). diff --git a/src/rebar_require_vsn.erl b/src/rebar_require_vsn.erl deleted file mode 100644 index af805c8..0000000 --- a/src/rebar_require_vsn.erl +++ /dev/null @@ -1,122 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% -%% ------------------------------------------------------------------- - --module(rebar_require_vsn). - --include("rebar.hrl"). - --export([compile/2, - eunit/2]). - -%% for internal use only --export([info/2, - version_tuple/2]). - -%% =================================================================== -%% Public API -%% =================================================================== - -compile(Config, _) -> - check_versions(Config). - -eunit(Config, _) -> - check_versions(Config). - -%% ==================================================================== -%% Internal functions -%% ==================================================================== - -info(help, compile) -> - info_help(); -info(help, eunit) -> - info_help(). - -info_help() -> - ?CONSOLE( - "Check required ERTS or OTP release version.~n" - "~n" - "Valid rebar.config options:~n" - " ~p~n" - " ~p~n" - " ~p~n", - [ - {require_erts_vsn, ".*"}, - {require_otp_vsn, ".*"}, - {require_min_otp_vsn, ".*"} - ]). - -check_versions(Config) -> - ErtsRegex = rebar_config:get(Config, require_erts_vsn, ".*"), - ReOpts = [{capture, none}], - case re:run(erlang:system_info(version), ErtsRegex, ReOpts) of - match -> - ?DEBUG("Matched required ERTS version: ~s -> ~s\n", - [erlang:system_info(version), ErtsRegex]); - nomatch -> - ?ABORT("ERTS version ~s does not match required regex ~s\n", - [erlang:system_info(version), ErtsRegex]) - end, - - OtpRegex = rebar_config:get(Config, require_otp_vsn, ".*"), - case re:run(erlang:system_info(otp_release), OtpRegex, ReOpts) of - match -> - ?DEBUG("Matched required OTP release: ~s -> ~s\n", - [erlang:system_info(otp_release), OtpRegex]); - nomatch -> - ?ABORT("OTP release ~s does not match required regex ~s\n", - [erlang:system_info(otp_release), OtpRegex]) - end, - - case rebar_config:get(Config, require_min_otp_vsn, undefined) of - undefined -> ?DEBUG("Min OTP version unconfigured~n", []); - MinOtpVsn -> - {MinMaj, MinMin} = version_tuple(MinOtpVsn, "configured"), - {OtpMaj, OtpMin} = version_tuple(erlang:system_info(otp_release), - "OTP Release"), - case {OtpMaj, OtpMin} >= {MinMaj, MinMin} of - true -> - ?DEBUG("~s satisfies the requirement for vsn ~s~n", - [erlang:system_info(otp_release), - MinOtpVsn]); - false -> - ?ABORT("OTP release ~s or later is required, you have: ~s~n", - [MinOtpVsn, - erlang:system_info(otp_release)]) - end - end. - -version_tuple(OtpRelease, Type) -> - case re:run(OtpRelease, "R?(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of - {match, [_Full, Maj, Min]} -> - {list_to_integer(Maj), list_to_integer(Min)}; - {match, [_Full, Maj]} -> - {list_to_integer(Maj), 0}; - nomatch -> - ?ABORT("Cannot parse ~s version string: ~s~n", - [Type, OtpRelease]) - end. diff --git a/test/rebar_eunit_tests.erl b/test/rebar_eunit_tests.erl deleted file mode 100644 index bb64507..0000000 --- a/test/rebar_eunit_tests.erl +++ /dev/null @@ -1,474 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- -%% @author Chris Bernard <cebernard@gmail.com> -%% @doc This tests functionality provided by the rebar command 'eunit'. -%% @copyright 2009, 2010 Dave Smith -%% ------------------------------------------------------------------- --module(rebar_eunit_tests). - --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - -%% Assuming this test is run inside the rebar 'eunit' -%% command, the current working directory will be '.eunit' --define(REBAR_SCRIPT, "../rebar"). - --define(TMP_DIR, "tmp_eunit/"). - -%% ==================================================================== -%% Rebar EUnit and Cover Tests -%% ==================================================================== - -eunit_test_() -> - {"Ensure EUnit runs with tests in a 'test' dir and no defined suite", - setup, fun() -> setup_basic_project(), rebar("-v eunit") end, - fun teardown/1, - fun(RebarOut) -> - [{"Tests in 'test' directory are found and run", - ?_assert(string:str(RebarOut, "myapp_mymod_tests:") =/= 0)}, - - {"Tests in 'src' directory are found and run", - ?_assert(string:str(RebarOut, "myapp_mymod:") =/= 0)}, - - {"Tests are only run once", - ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}] - end}. - -eunit_with_suites_and_tests_test_() -> - [{"Ensure EUnit runs selected suites", - setup, fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod2") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected suite tests in 'test' directory are found and run", - ?_assert(string:str(RebarOut, "myapp_mymod2_tests:") =/= 0)}, - - {"Selected suite tests in 'src' directory are found and run", - ?_assert(string:str(RebarOut, "myapp_mymod2:") =/= 0)}, - - {"Unselected suite tests in 'test' directory are not run", - ?_assert(string:str(RebarOut, "myapp_mymod_tests:") =:= 0)}, - - {"Unselected suite tests in 'src' directory are not run", - ?_assert(string:str(RebarOut, "myapp_mymod:") =:= 0)}, - - {"Selected suite tests are only run once", - ?_assert(string:str(RebarOut, "All 4 tests passed") =/= 0)}] - end}, - {"Ensure EUnit runs selected _tests suites", - setup, fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod2_tests") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected suite tests in 'test' directory are found and run", - ?_assert(string:str(RebarOut, "myapp_mymod2_tests:") =/= 0)}, - - {"Selected suite tests in 'src' directory are not run", - ?_assert(string:str(RebarOut, "myapp_mymod2:") =:= 0)}, - - {"Unselected suite tests in 'test' directory are not run", - ?_assert(string:str(RebarOut, "myapp_mymod_tests:") =:= 0)}, - - {"Unselected suite tests in 'src' directory are not run", - ?_assert(string:str(RebarOut, "myapp_mymod:") =:= 0)}, - - {"Selected suite tests are only run once", - ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}] - end}, - {"Ensure EUnit runs a specific test defined in a selected suite", - setup, fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod2 tests=myprivate2") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected suite tests are found and run", - ?_assert(string:str(RebarOut, - "myapp_mymod2:myprivate2_test/0") =/= 0)}, - - {"Selected suite tests is run once", - ?_assert(string:str(RebarOut, "Test passed") =/= 0)}] - end}, - {"Ensure EUnit runs a specific generator test defined in a selected suite", - setup, fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod3 tests=mygenerator") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected suite's generator test is found and run", - ?_assert(string:str(RebarOut, - "myapp_mymod3:mygenerator_test_/0") =/= 0)}, - - {"Selected suite's generator test raises an error", - ?_assert(string:str(RebarOut, - "assertEqual_failed") =/= 0)}, - - {"Selected suite tests is run once", - ?_assert(string:str(RebarOut, "Failed: 1.") =/= 0)}] - end}, - {"Ensure EUnit runs specific tests defined in selected suites", - setup, fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod,myapp_mymod2" - " tests=myprivate,myfunc2") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected suite tests are found and run", - [?_assert(string:str(RebarOut, - "myapp_mymod:myprivate_test/0") =/= 0), - ?_assert(string:str(RebarOut, - "myapp_mymod2:myprivate2_test/0") =/= 0), - ?_assert( - string:str(RebarOut, - "myapp_mymod2_tests:myfunc2_test/0") =/= 0)]}, - - {"Selected suite tests are run once", - ?_assert(string:str(RebarOut, "All 3 tests passed") =/= 0)}] - end}, - {"Ensure EUnit runs specific test in a _tests suite", - setup, - fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod2_tests tests=common_name_test") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Only selected suite tests are found and run", - [?_assert(string:str(RebarOut, - "myapp_mymod2:common_name_test/0") =:= 0), - ?_assert(string:str(RebarOut, - "myapp_mymod2_tests:common_name_test/0") - =/= 0)]}, - - {"Selected suite tests is run once", - ?_assert(string:str(RebarOut, "Test passed") =/= 0)}] - end}, - {"Ensure EUnit runs a specific test without a specified suite", - setup, - fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit tests=myprivate") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Only selected suite tests are found and run", - [?_assert(string:str(RebarOut, - "myapp_mymod:myprivate_test/0") =/= 0), - ?_assert(string:str(RebarOut, - "myapp_mymod2:myprivate2_test/0") - =/= 0)]}, - - {"Selected suite tests is run once", - ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}] - end}, - {"Ensure EUnit runs a specific test by qualified function name", - setup, - fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit tests=myapp_mymod:myprivate_test") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected test is run", - [?_assert(string:str(RebarOut, - "myapp_mymod:myprivate_test/0") - =/= 0)]}, - - {"Only selected test is run", - [?_assert(string:str(RebarOut, - "Test passed.") =/= 0)]}] - end}, - {"Ensure EUnit runs a specific test by qualified function " - ++ "name and tests from other module", - setup, - fun() -> - setup_project_with_multiple_modules(), - rebar("-v eunit suites=myapp_mymod3 " - ++ "tests=myapp_mymod:myprivate_test") - end, - fun teardown/1, - fun(RebarOut) -> - [{"Selected test is run", - [?_assert(string:str(RebarOut, - "myapp_mymod:myprivate_test/0") =/= 0)]}, - - {"Tests from module are run", - [?_assert(string:str(RebarOut, - "myapp_mymod3:") =/= 0)]}, - - {"Only selected tests are run", - [?_assert(string:str(RebarOut, - "Failed: 1. Skipped: 0. Passed: 1") - =/= 0)]}] - end}]. - -cover_test_() -> - {"Ensure Cover runs with tests in a test dir and no defined suite", - setup, fun() -> setup_cover_project(), rebar("-v eunit") end, - fun teardown/1, - - fun(RebarOut) -> - [{"Error messages are not present", - ?_assert(string:str(RebarOut, "Cover analyze failed for") =:= 0)}, - - {"All cover reports are generated", - assert_files_in("the temporary eunit directory", - expected_cover_generated_files())}, - - {"Only production modules get coverage reports", - assert_files_not_in("the temporary eunit directory", - [".eunit/myapp_mymod_tests.COVER.html"])}] - end}. - -cover_with_suite_test_() -> - {"Ensure Cover runs with Tests in a test dir and a test suite", - setup, - fun() -> - setup_cover_project_with_suite(), - rebar("-v eunit suites=mysuite") - end, - fun teardown/1, - - fun(RebarOut) -> - [{"Error messages are not present", - ?_assert(string:str(RebarOut, "Cover analyze failed for") =:= 0)}, - - {"Cover reports are generated for module", - assert_files_in("the temporary eunit directory", - [".eunit/index.html", - ".eunit/mysuite.COVER.html"])}, - - {"Only production modules get coverage reports", - assert_files_not_in("the temporary eunit directory", - [".eunit/myapp_app.COVER.html", - ".eunit/myapp_mymod.COVER.html", - ".eunit/myapp_sup.COVER.html", - ".eunit/myapp_mymod_tests.COVER.html"])}] - end}. - -expected_cover_generated_files() -> - [".eunit/index.html", - ".eunit/myapp_app.COVER.html", - ".eunit/myapp_mymod.COVER.html", - ".eunit/myapp_sup.COVER.html"]. - -cover_coverage_test_() -> - {"Coverage is accurately calculated", - setup, fun() -> setup_cover_project(), rebar("-v eunit") end, - fun teardown/1, - - [{"Modules that include the EUnit header can still have 100% coverage", - %% cover notices the implicit EUnit test/0 func that never gets - %% called during eunit:test(TestRepresentation), so NotCounted - %% needs to be decremented in this case. - assert_full_coverage("myapp_mymod")}]}. - -%% ==================================================================== -%% Environment and Setup Tests -%% ==================================================================== - -environment_test_() -> - {"Sanity check the testing environment", - setup, fun make_tmp_dir/0, fun remove_tmp_dir/1, - - [{"Ensure a test project can be created", - ?_assert(filelib:is_dir(?TMP_DIR))}, - - {"Ensure the rebar script can be found, copied, and run", - [?_assert(filelib:is_regular(?REBAR_SCRIPT)), - fun assert_rebar_runs/0]}]}. - -assert_rebar_runs() -> - prepare_rebar_script(), - ?assert(string:str(os:cmd(filename:nativename("./" ++ ?TMP_DIR ++ "rebar")), - "No command to run specified!") =/= 0). - -basic_setup_test_() -> - {"Create a simple project with a 'test' directory, a test, and a module", - setup, fun setup_basic_project/0, fun teardown/1, - - %% Test the setup function - assert_dirs_in("Basic Project", - ["src", "ebin", "test"]) ++ - assert_files_in("Basic Project", - ["test/myapp_mymod_tests.erl", - "src/myapp_mymod.erl"])}. - -%% ==================================================================== -%% Setup and Teardown -%% ==================================================================== - --define(myapp_mymod, - ["-module(myapp_mymod).\n", - "-export([myfunc/0]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc() -> ok.\n", - "myprivate_test() -> ?assert(true).\n"]). - --define(myapp_mymod_tests, - ["-module(myapp_mymod_tests).\n", - "-compile([export_all]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n"]). - --define(myapp_mymod2, - ["-module(myapp_mymod2).\n", - "-export([myfunc2/0]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc2() -> ok.\n", - "myprivate2_test() -> ?assert(true).\n", - "common_name_test() -> ?assert(true).\n"]). - --define(myapp_mymod2_tests, - ["-module(myapp_mymod2_tests).\n", - "-compile([export_all]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc2_test() -> ?assertMatch(ok, myapp_mymod2:myfunc2()).\n", - "common_name_test() -> ?assert(true).\n"]). - --define(myapp_mymod3, - ["-module(myapp_mymod3).\n", - "-export([myfunc3/0]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc3() -> ok.\n", - "mygenerator_test_() -> [?_assertEqual(true, false)].\n"]). - --define(mysuite, - ["-module(mysuite).\n", - "-export([all_test_/0]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "all_test_() -> [myapp_mymod_defined_in_mysuite_tests].\n"]). - --define(myapp_mymod_defined_in_mysuite_tests, - ["-module(myapp_mymod_defined_in_mysuite_tests).\n", - "-compile([export_all]).\n", - "-include_lib(\"eunit/include/eunit.hrl\").\n", - "myfunc_test() -> ?assertMatch(ok, myapp_mymod:myfunc()).\n"]). - -make_tmp_dir() -> - case file:make_dir(?TMP_DIR) of - ok -> - ok; - {error, eexist} -> - remove_tmp_dir(), - make_tmp_dir(); - Error -> - throw(Error) - end. - -setup_environment() -> - ok = make_tmp_dir(), - prepare_rebar_script(), - ok = file:set_cwd(?TMP_DIR). - -setup_basic_project() -> - setup_environment(), - rebar("create-app appid=myapp"), - ok = file:make_dir("ebin"), - ok = file:make_dir("test"), - ok = file:write_file("test/myapp_mymod_tests.erl", ?myapp_mymod_tests), - ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod). - -setup_project_with_multiple_modules() -> - setup_basic_project(), - ok = file:write_file("test/myapp_mymod2_tests.erl", ?myapp_mymod2_tests), - ok = file:write_file("src/myapp_mymod2.erl", ?myapp_mymod2), - ok = file:write_file("src/myapp_mymod3.erl", ?myapp_mymod3). - -setup_cover_project() -> - setup_basic_project(), - ok = file:write_file("rebar.config", "{cover_enabled, true}.\n"). - -setup_cover_project_with_suite() -> - setup_cover_project(), - ok = file:write_file("test/mysuite.erl", ?mysuite), - ok = file:write_file("test/myapp_mymod_defined_in_mysuite_tests.erl", - ?myapp_mymod_defined_in_mysuite_tests). - -teardown(_) -> - ok = file:set_cwd(".."), - ok = remove_tmp_dir(). - -remove_tmp_dir() -> - remove_tmp_dir(arg_for_eunit). - -remove_tmp_dir(_) -> - ok = rebar_file_utils:rm_rf(?TMP_DIR). - -%% ==================================================================== -%% Helper Functions -%% ==================================================================== - -prepare_rebar_script() -> - Rebar = ?TMP_DIR ++ "rebar", - {ok, _} = file:copy(?REBAR_SCRIPT, Rebar), - case os:type() of - {unix, _} -> - [] = os:cmd("chmod u+x " ++ Rebar); - {win32, _} -> - {ok, _} = file:copy(?REBAR_SCRIPT ++ ".cmd", - ?TMP_DIR ++ "rebar.cmd") - end. - -rebar() -> - rebar([]). - -rebar(Args) when is_list(Args) -> - Out = os:cmd(filename:nativename("./rebar") ++ " " ++ Args), - %% ?debugMsg("**** Begin"), ?debugMsg(Out), ?debugMsg("**** End"), - Out. - -assert_dirs_in(Name, [Dir|T]) -> - [{Name ++ " has directory: " ++ Dir, ?_assert(filelib:is_dir(Dir))} | - assert_dirs_in(Name, T)]; -assert_dirs_in(_, []) -> []. - -assert_files_in(Name, [File|T]) -> - [{Name ++ " has file: " ++ File, ?_assert(filelib:is_regular(File))} | - assert_files_in(Name, T)]; -assert_files_in(_, []) -> []. - -assert_files_not_in(Name, [File|T]) -> - [{Name ++ " does not have file: " ++ File, - ?_assertNot(filelib:is_regular(File))} | assert_files_not_in(Name, T)]; -assert_files_not_in(_, []) -> []. - -assert_full_coverage(Mod) -> - fun() -> - {ok, F} = file:read_file(".eunit/index.html"), - Result = [X || X <- string:tokens(binary_to_list(F), "\n"), - string:str(X, Mod) =/= 0, - string:str(X, "100%") =/= 0], - ?assert(length(Result) =:= 1) - end. diff --git a/test/rebar_file_utils_tests.erl b/test/rebar_file_utils_tests.erl deleted file mode 100644 index a191765..0000000 --- a/test/rebar_file_utils_tests.erl +++ /dev/null @@ -1,278 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com) -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- -%% @author Juhani Rankimies <juhani@juranki.com> -%% @doc Tests functionality of rebar_file_utils module. -%% @copyright 2009, 2010 Dave Smith -%% ------------------------------------------------------------------- --module(rebar_file_utils_tests). - --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - --define(TMP_DIR, "tmp_file_utils"). --define(DIR_TREE, [{d,"source",[{f,"file1"}, - {f,"file2"}]}, - {d,"dest",[]}]). --define(FILE_CONTENT, <<"1234567890">>). - -%% ==================================================================== -%% delete_each tests -%% ==================================================================== - -delete_bogus_test_() -> - {"delete_each survives nonexisting files", - [?_assertMatch(ok, rebar_file_utils:delete_each(["bogus"])), - ?_assertMatch(ok, rebar_file_utils:delete_each(["bogus1","bogus2"]))]}. - -delete_each_test_() -> - {"delete_each removes files", - setup, - fun() -> - setup(), - rebar_file_utils:delete_each(file_list()) - end, - fun teardown/1, - [assert_files_not_in("source", file_list())]}. - -%% ==================================================================== -%% rm_rf tests -%% ==================================================================== - -rm_rf_wildcard_test_() -> - {"rm_rf removes files based on wildcard spec", - setup, - fun() -> - setup(), - rebar_file_utils:rm_rf(filename:join([?TMP_DIR,"source","file*"])) - end, - fun teardown/1, - [assert_files_not_in("source", file_list())]}. - -rm_rf_dir_test_() -> - {"rm_rf removes directory tree", - setup, - fun() -> - setup(), - rebar_file_utils:rm_rf(filename:join([?TMP_DIR,"source"])) - end, - fun teardown/1, - [?_assertNot(filelib:is_dir(filename:join([?TMP_DIR,"source"])))]}. - -%% ==================================================================== -%% cp_r tests -%% ==================================================================== - -cp_r_file_to_file_test_() -> - {"cp_r copies a file to file", - setup, - fun() -> - setup(), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"source","file1"])], - filename:join([?TMP_DIR,"dest","new_file"])) - end, - fun teardown/1, - [?_assert(filelib:is_regular(filename:join([?TMP_DIR,"dest","new_file"])))]}. - -cp_r_file_to_dir_test_() -> - {"cp_r copies a file to directory", - setup, - fun() -> - setup(), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"source","file1"])], - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assert(filelib:is_regular(filename:join([?TMP_DIR,"dest","file1"])))]}. - -cp_r_dir_to_dir_test_() -> - {"cp_r copies a directory to directory", - setup, - fun() -> - setup(), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"source"])], - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assert(filelib:is_dir(filename:join([?TMP_DIR,"dest","source"]))), - assert_files_in("dest/source", - [filename:join([?TMP_DIR,"dest","source",F]) || - F <- ["file1","file2"]])]}. - -cp_r_wildcard_file_to_dir_test_() -> - {"cp_r copies wildcard files to directory", - setup, - fun() -> - setup(), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"source","*1"])], - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assert(filelib:is_regular(filename:join([?TMP_DIR,"dest","file1"])))]}. - -cp_r_wildcard_dir_to_dir_test_() -> - {"cp_r copies wildcard directory to directory", - setup, - fun() -> - setup(), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"sour*"])], - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assert(filelib:is_dir(filename:join([?TMP_DIR,"dest","source"]))), - assert_files_in("dest/source", - [filename:join([?TMP_DIR,"dest","source",F]) || - F <- ["file1","file2"]])]}. - -cp_r_overwrite_file_test_() -> - {"cp_r overwrites destination file", - setup, - fun() -> - setup(), - ok = file:write_file(filename:join([?TMP_DIR,"dest","file1"]), - <<"test">>), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"source","file1"])], - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assertMatch({ok,?FILE_CONTENT}, - file:read_file( - filename:join([?TMP_DIR,"dest","file1"])))]}. - -cp_r_overwrite_dir_test_() -> - {"cp_r overwrites destination file (xcopy case on win32)", - setup, - fun() -> - setup(), - ok = file:make_dir(filename:join([?TMP_DIR,"dest","source"])), - ok = file:write_file( - filename:join([?TMP_DIR,"dest","source","file1"]), - <<"test">>), - rebar_file_utils:cp_r([filename:join([?TMP_DIR,"source"])], - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assertMatch({ok,?FILE_CONTENT}, - file:read_file( - filename:join([?TMP_DIR,"dest","source","file1"])))]}. - -cp_r_overwrite_file_fail_test_() -> - {"cp_r fails to fs permission errors (file:copy/2 case on win32)", - setup, - fun() -> - setup(), - ok = file:write_file( - filename:join([?TMP_DIR,"dest","file1"]),<<"test">>), - ok = file:change_mode( - filename:join([?TMP_DIR,"dest","file1"]),0) - end, - fun teardown/1, - [?_assertThrow(rebar_abort, - rebar_file_utils:cp_r( - [filename:join([?TMP_DIR,"source","file1"])], - filename:join([?TMP_DIR,"dest"])))]}. - -cp_r_overwrite_dir_fail_test_() -> - {"cp_r fails to fs permission error (xcopy case on win32)", - setup, - fun() -> - setup(), - ok = file:make_dir( - filename:join([?TMP_DIR,"dest","source"])), - ok = file:write_file( - filename:join([?TMP_DIR,"dest","source","file1"]), - <<"test">>), - ok = file:change_mode( - filename:join([?TMP_DIR,"dest","source","file1"]),0) - end, - fun teardown/1, - [?_assertThrow(rebar_abort, - rebar_file_utils:cp_r( - [filename:join([?TMP_DIR,"source"])], - filename:join([?TMP_DIR,"dest"])))]}. - -mv_file_test_() -> - {"move a file to folder", - setup, - fun() -> - setup(), - rebar_file_utils:mv(filename:join([?TMP_DIR,"source","file1"]), - filename:join([?TMP_DIR,"dest"])) - end, - fun teardown/1, - [?_assert(filelib:is_regular(filename:join([?TMP_DIR,"dest","file1"]))), - ?_assertNot(filelib:is_regular( - filename:join([?TMP_DIR,"source","file1"])))]}. - -%% ==================================================================== -%% Utilities -%% ==================================================================== - -file_list() -> - [filename:join([?TMP_DIR,"source",F]) || F <- ["file1","file2"]]. - -%% ==================================================================== -%% Setup and Teardown -%% ==================================================================== - -setup() -> - file:make_dir(?TMP_DIR), - make_dir_tree(?TMP_DIR,?DIR_TREE). - -make_dir_tree(Parent, [{d,Dir,Contents} | Rest]) -> - NewDir = filename:join(Parent,Dir), - ok = file:make_dir(NewDir), - ok = make_dir_tree(NewDir,Contents), - ok = make_dir_tree(Parent,Rest); -make_dir_tree(Parent, [{f,File} | Rest]) -> - ok = file:write_file(filename:join(Parent,File),?FILE_CONTENT), - ok = make_dir_tree(Parent,Rest); -make_dir_tree(_,[]) -> - ok. - -teardown(_) -> - case os:type() of - {unix, _} -> - os:cmd("rm -rf " ++ ?TMP_DIR ++ " 2>/dev/null"); - {win32, _} -> - os:cmd("rmdir /S /Q " ++ filename:nativename(?TMP_DIR)) - end. - -%% ==================================================================== -%% Assert helpers -%% ==================================================================== - -assert_files_in(Name, [File|T]) -> - [{Name ++ " has file: " ++ File, ?_assert(filelib:is_regular(File))} | - assert_files_in(Name, T)]; -assert_files_in(_, []) -> []. - -assert_files_not_in(Name, [File|T]) -> - [{Name ++ " does not have file: " ++ File, - ?_assertNot(filelib:is_regular(File))} | - assert_files_not_in(Name, T)]; -assert_files_not_in(_, []) -> []. diff --git a/test/rebar_otp_release_tests.erl b/test/rebar_otp_release_tests.erl deleted file mode 100644 index 3045136..0000000 --- a/test/rebar_otp_release_tests.erl +++ /dev/null @@ -1,47 +0,0 @@ -%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% rebar: Erlang Build Tools -%% -%% Copyright (c) 2014 Tuncer Ayaz -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. -%% ------------------------------------------------------------------- --module(rebar_otp_release_tests). - --include_lib("eunit/include/eunit.hrl"). - -check_otp_release_test() -> - case rebar_utils:otp_release() of - %% <= R16 - [$R,N|_] when is_integer(N) -> - ?assert(true); - %% >= 17.x - [N|_]=Rel when is_integer(N) -> - %% Check that it has at least Major.Minor. - ?assert(length(string:tokens(Rel, ".")) > 1), - - %% If otp_patch_apply was used and the release version has - %% a "**" suffix, we drop that part in otp_release/0. - ?assertEqual(0, string:str(Rel, "*")), - - %% Check that "\n" is dropped in otp_release/0. - ?assertEqual(0, string:str(Rel, "\n")) - end. diff --git a/test/rebar_require_vsn_tests.erl b/test/rebar_require_vsn_tests.erl deleted file mode 100644 index 2d3a1ec..0000000 --- a/test/rebar_require_vsn_tests.erl +++ /dev/null @@ -1,23 +0,0 @@ --module(rebar_require_vsn_tests). - --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - -version_tuple_test_() -> - [%% typical cases - ?_assert(rebar_require_vsn:version_tuple("R15B", "eunit") =:= {15, 0}), - ?_assert(rebar_require_vsn:version_tuple("R15B01", "eunit") =:= {15, 1}), - ?_assert(rebar_require_vsn:version_tuple("R15B02", "eunit") =:= {15, 2}), - ?_assert(rebar_require_vsn:version_tuple("R15B03-1", "eunit") =:= {15, 3}), - ?_assert(rebar_require_vsn:version_tuple("R15B03", "eunit") =:= {15, 3}), - ?_assert(rebar_require_vsn:version_tuple("R16B", "eunit") =:= {16, 0}), - ?_assert(rebar_require_vsn:version_tuple("R16B01", "eunit") =:= {16, 1}), - ?_assert(rebar_require_vsn:version_tuple("R16B02", "eunit") =:= {16, 2}), - ?_assert(rebar_require_vsn:version_tuple("R16B03", "eunit") =:= {16, 3}), - ?_assert(rebar_require_vsn:version_tuple("R16B03-1", "eunit") =:= {16, 3}), - ?_assert(rebar_require_vsn:version_tuple("17", "eunit") =:= {17, 0}), - %% error cases - ?_assertException(throw, rebar_abort, rebar_require_vsn:version_tuple("", "eunit")), - ?_assertException(throw, rebar_abort, rebar_require_vsn:version_tuple("abc", "eunit")) - ]. diff --git a/test/rebar_xref_eunit.erl b/test/rebar_xref_eunit.erl deleted file mode 100644 index 45ec283..0000000 --- a/test/rebar_xref_eunit.erl +++ /dev/null @@ -1,203 +0,0 @@ --module(rebar_xref_eunit). - --compile(export_all). - --include_lib("eunit/include/eunit.hrl"). - --define(REBAR_SCRIPT, "../rebar"). - --define(TMP_DIR, "tmp_xref_eunit/"). - -xref_test_() -> - {"Test the various xref warnings", - setup, fun() -> setup_project(false), rebar("compile"), rebar("skip_deps=true xref") end, - fun teardown/1, - fun(RebarOut) -> - [ - {"Undefined function", ?_assert(string:str(RebarOut, - "myapp_somemod:notavailable/1 is undefined function") =/= 0)}, - {"Undefined function call", ?_assert(string:str(RebarOut, - "myapp_othermod:somefunc/0 calls undefined function myapp_somemod:notavailable/1") =/= 0)}, - {"Deprecated function", ?_assert(string:str(RebarOut, - "myapp_mymod:fdeprecated/0 is deprecated function") =/= 0)}, - {"Deprecated function call", ?_assert(string:str(RebarOut, - "myapp_othermod:somefunc/0 calls deprecated function myapp_mymod:fdeprecated/0") =/= 0)}, - {"Unused local", ?_assert(string:str(RebarOut, - "myapp_mymod:localfunc2/0 is unused local function") =/= 0)}, - {"Unused export 1", ?_assert(string:str(RebarOut, - "myapp_behaviour1:behaviour_info/1 is unused export") =/= 0)}, - {"Unused export 2", ?_assert(string:str(RebarOut, - "myapp_behaviour2:behaviour_info/1 is unused export") =/= 0)}, - {"Unused export 3", ?_assert(string:str(RebarOut, - "myapp_mymod:other2/1 is unused export") =/= 0)}, - {"Unused export 4", ?_assert(string:str(RebarOut, - "myapp_othermod:somefunc/0 is unused export") =/= 0)}, - {"Suppressed behaviour export 1", ?_assert(string:str(RebarOut, - "myapp_mymod:bh1_a/1 is unused export") =:= 0)}, - {"Suppressed behaviour export 2", ?_assert(string:str(RebarOut, - "myapp_mymod:bh1_b/1 is unused export") =:= 0)}, - {"Suppressed behaviour export 3", ?_assert(string:str(RebarOut, - "myapp_mymod:bh2_a/1 is unused export") =:= 0)}, - {"Suppressed behaviour export 4", ?_assert(string:str(RebarOut, - "myapp_mymod:bh2_b/1 is unused export") =:= 0)} - ] - end}. - -xref_ignore_test_() -> - {"Test the suppression of xref warnings", - setup, fun() -> setup_project(ignore_xref), rebar("compile"), rebar("skip_deps=true xref") end, - fun teardown/1, - fun(RebarOut) -> - [ - {"Undefined function can not be suppressed.", ?_assert(string:str(RebarOut, - "myapp_somemod:notavailable/1 is undefined function") =/= 0)}, - {"Supppressed undefined function call", ?_assert(string:str(RebarOut, - "myapp_othermod:somefunc/0 calls undefined function myapp_somemod:notavailable/1") =:= 0)}, - {"Supppressed deprecated function", ?_assert(string:str(RebarOut, - "myapp_mymod:fdeprecated/0 is deprecated function") =:= 0)}, - {"Supppressed deprecated function call", ?_assert(string:str(RebarOut, - "myapp_othermod:somefunc/0 calls deprecated function myapp_mymod:fdeprecated/0") =:= 0)}, - {"Supppressed unused local", ?_assert(string:str(RebarOut, - "myapp_mymod:localfunc2/0 is unused local function") =:= 0)}, - {"Supppressed unused export 1", ?_assert(string:str(RebarOut, - "myapp_behaviour1:behaviour_info/1 is unused export") =:= 0)}, - {"Supppressed unused export 2", ?_assert(string:str(RebarOut, - "myapp_behaviour2:behaviour_info/1 is unused export") =:= 0)}, - {"Supppressed unused export 3", ?_assert(string:str(RebarOut, - "myapp_mymod:other2/1 is unused export") =:= 0)}, - {"Supppressed unused export 4", ?_assert(string:str(RebarOut, - "myapp_othermod:somefunc/0 is unused export") =:= 0)}, - {"Suppressed behaviour export 1", ?_assert(string:str(RebarOut, - "myapp_mymod:bh1_a/1 is unused export") =:= 0)}, - {"Suppressed behaviour export 2", ?_assert(string:str(RebarOut, - "myapp_mymod:bh1_b/1 is unused export") =:= 0)}, - {"Suppressed behaviour export 3", ?_assert(string:str(RebarOut, - "myapp_mymod:bh2_a/1 is unused export") =:= 0)}, - {"Suppressed behaviour export 4", ?_assert(string:str(RebarOut, - "myapp_mymod:bh2_b/1 is unused export") =:= 0)} - ] - - end}. - - -%% ==================================================================== -%% Setup and Teardown -%% ==================================================================== - --define(myapp_behaviour1, - ["-module(myapp_behaviour1).\n", - "-export([behaviour_info/1]).\n"]). --define(myapp_behaviour1_body, - ["behaviour_info(callbacks) -> [{bh1_a,1},{bh1_b,1}];\n", - "behaviour_info(_Other) -> undefined.\n"]). --define(myapp_behaviour1_ignorexref, - ["-ignore_xref({behaviour_info,1}).\n"]). - --define(myapp_behaviour2, - ["-module(myapp_behaviour2).\n", - "-export([behaviour_info/1]).\n"]). --define(myapp_behaviour2_body, - ["behaviour_info(callbacks) -> [{bh2_a,1},{bh2_b,1}];\n", - "behaviour_info(_Other) -> undefined.\n"]). --define(myapp_behaviour2_ignorexref, - ["-ignore_xref({behaviour_info,1}).\n"]). - --define(myapp_mymod, - ["-module(myapp_mymod).\n", - "-export([bh1_a/1,bh1_b/1,bh2_a/1,bh2_b/1,other1/1,other2/1,fdeprecated/0]).\n", - "-behaviour(myapp_behaviour1).\n", % 2 behaviours - "-behaviour(myapp_behaviour2).\n", - "-deprecated({fdeprecated,0}).\n"]). % deprecated function --define(myapp_mymod_body, - ["bh1_a(A) -> localfunc1(bh1_a, A).\n", % behaviour functions - "bh1_b(A) -> localfunc1(bh1_b, A).\n", - "bh2_a(A) -> localfunc1(bh2_a, A).\n", - "bh2_b(A) -> localfunc1(bh2_b, A).\n", - "other1(A) -> localfunc1(other1, A).\n", % regular exported functions - "other2(A) -> localfunc1(other2, A).\n", - "localfunc1(A, B) -> {A, B}.\n", % used local - "localfunc2() -> ok.\n", % unused local - "fdeprecated() -> ok.\n" % deprecated function - ]). --define(myapp_mymod_ignorexref, - ["-ignore_xref([{other2,1},{localfunc2,0},{fdeprecated,0}]).\n"]). - - - --define(myapp_othermod, - ["-module(myapp_othermod).\n", - "-export([somefunc/0]).\n"]). --define(myapp_othermod_body, - ["somefunc() ->\n", - " myapp_mymod:other1(arg),\n", - " myapp_somemod:notavailable(arg),\n", - " myapp_mymod:fdeprecated().\n" - ]). --define(myapp_othermod_ignorexref, - ["-ignore_xref([{myapp_somemod,notavailable,1},{somefunc,0}]).\n", - "-ignore_xref({myapp_mymod,fdeprecated,0}).\n"]). - - --define(myapp_rebarconfig, - ["{erl_opts, [debug_info]}.\n", - "{xref_checks, [deprecated_function_calls,deprecated_functions,\n", - " undefined_function_calls,undefined_functions,\n", - " exports_not_used,locals_not_used]}.\n" - ]). - -setup_environment() -> - ok = file:make_dir(?TMP_DIR), - prepare_rebar_script(), - ok = file:set_cwd(?TMP_DIR). - -prepare_project() -> - setup_environment(), - rebar("create-app appid=myapp"), - ok = file:make_dir("ebin"). - -setup_project(ignore_xref) -> - prepare_project(), - ok = file:write_file("src/myapp_behaviour1.erl", ?myapp_behaviour1 ++ ?myapp_behaviour1_ignorexref ++ ?myapp_behaviour1_body), - ok = file:write_file("src/myapp_behaviour2.erl", ?myapp_behaviour2 ++ ?myapp_behaviour2_ignorexref++ ?myapp_behaviour2_body), - ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod ++ ?myapp_mymod_ignorexref ++ ?myapp_mymod_body), - ok = file:write_file("src/myapp_othermod.erl", ?myapp_othermod ++ ?myapp_othermod_ignorexref ++ ?myapp_othermod_body), - ok = file:write_file("rebar.config", ?myapp_rebarconfig); - -setup_project(_) -> - prepare_project(), - ok = file:write_file("src/myapp_behaviour1.erl", ?myapp_behaviour1 ++ ?myapp_behaviour1_body), - ok = file:write_file("src/myapp_behaviour2.erl", ?myapp_behaviour2 ++ ?myapp_behaviour2_body), - ok = file:write_file("src/myapp_mymod.erl", ?myapp_mymod ++ ?myapp_mymod_body), - ok = file:write_file("src/myapp_othermod.erl", ?myapp_othermod ++ ?myapp_othermod_body), - ok = file:write_file("rebar.config", ?myapp_rebarconfig). - - -teardown(_) -> - ok = file:set_cwd(".."), - ok = remove_tmp_dir(). - -remove_tmp_dir() -> - ok = rebar_file_utils:rm_rf(?TMP_DIR). - -%% ==================================================================== -%% Helper Functions -%% ==================================================================== - -prepare_rebar_script() -> - Rebar = ?TMP_DIR ++ "rebar", - {ok, _} = file:copy(?REBAR_SCRIPT, Rebar), - case os:type() of - {unix, _} -> - [] = os:cmd("chmod u+x " ++ Rebar); - {win32, _} -> - {ok, _} = file:copy(?REBAR_SCRIPT ++ ".bat", - ?TMP_DIR ++ "rebar.bat") - end. - -rebar() -> - rebar([]). - -rebar(Args) when is_list(Args) -> - Out = os:cmd(filename:nativename("./rebar") ++ " " ++ Args), - %% ?debugMsg("**** Begin"), ?debugMsg(Out), ?debugMsg("**** End"), - Out. diff --git a/test/upgrade_project/README.md b/test/upgrade_project/README.md deleted file mode 100644 index 8df5383..0000000 --- a/test/upgrade_project/README.md +++ /dev/null @@ -1,40 +0,0 @@ -#### Building version 0.1 - rebar compile - rebar generate - mv rel/dummy rel/dummy_0.1 - rebar clean - # start the release: - cd rel/dummy_0.1 - bin/dummy console - - erl> dummy_server:get_state(). - erl> dummy_server:set_state(123). - erl> dummy_server:get_state(). - -#### Building version 0.2 - - # Now, in another terminal we prepare an upgrade.. - - # change release version numbers from 0.1 to 0.2 in - $EDITOR apps/dummy/src/dummy.app.src - $EDITOR rel/reltool.config - - rebar compile - rebar generate - # previous_release path is relative to your rel directory - rebar generate-appups previous_release=dummy_0.1 - rebar generate-upgrade previous_release=dummy_0.1 - tar -zvtf rel/dummy_0.2.tar.gz - - -#### Deploying with release_handler - mv rel/dummy_0.2.tar.gz rel/dummy_0.1/releases/ - - # Now use release_handler in the running erlang console for the deploy: - - erl> release_handler:unpack_release("dummy_0.2"). - erl> release_handler:install_release("0.2"). - erl> release_handler:make_permanent("0.2"). - - erl> release_handler:which_releases(). - erl> dummy_server:get_state(). diff --git a/test/upgrade_project/apps/dummy/src/dummy.app.src b/test/upgrade_project/apps/dummy/src/dummy.app.src deleted file mode 100644 index dd06752..0000000 --- a/test/upgrade_project/apps/dummy/src/dummy.app.src +++ /dev/null @@ -1,9 +0,0 @@ -{application, dummy, [ - {description, "a dummy app"}, - {vsn, "0.1"}, - {registered, [ - dummy_app - ]}, - {mod, {dummy_app, []}}, - {applications, [kernel, stdlib, sasl]} -]}. diff --git a/test/upgrade_project/apps/dummy/src/dummy_app.erl b/test/upgrade_project/apps/dummy/src/dummy_app.erl deleted file mode 100644 index 51363b3..0000000 --- a/test/upgrade_project/apps/dummy/src/dummy_app.erl +++ /dev/null @@ -1,9 +0,0 @@ --module(dummy_app). --behaviour(application). - --export([start/2, stop/1]). - -start(_,_) -> - dummy_sup:start_link(). - -stop(_) -> ok. diff --git a/test/upgrade_project/apps/dummy/src/dummy_server.erl b/test/upgrade_project/apps/dummy/src/dummy_server.erl deleted file mode 100644 index 382251e..0000000 --- a/test/upgrade_project/apps/dummy/src/dummy_server.erl +++ /dev/null @@ -1,56 +0,0 @@ --module(dummy_server). --behaviour(gen_server). - --export([start_link/0, set_state/1, get_state/0]). - --export([init/1, - handle_call/3, - handle_cast/2, - handle_info/2, - terminate/2, - code_change/3]). - -%% - -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -set_state(What) -> - gen_server:call(?MODULE, {set_state, What}). - -get_state() -> - gen_server:call(?MODULE, get_state). - - -%% - -init([]) -> - say("init, setting state to 0", []), - {ok, 0}. - - -handle_call({set_state, NewState}, _From, _State) -> - {reply, {ok, NewState}, NewState}; - -handle_call(get_state, _From, State) -> - {reply, State, State}. - -handle_cast('__not_implemented', State) -> - {noreply, State}. - -handle_info(_Info, State) -> - say("info ~p, ~p.", [_Info, State]), - {noreply, State}. - -terminate(_Reason, _State) -> - say("terminate ~p, ~p", [_Reason, _State]), - ok. - -code_change(_OldVsn, State, _Extra) -> - say("code_change ~p, ~p, ~p", [_OldVsn, State, _Extra]), - {ok, State}. - -%% Internal - -say(Format, Data) -> - io:format("~p:~p: ~s~n", [?MODULE, self(), io_lib:format(Format, Data)]). diff --git a/test/upgrade_project/apps/dummy/src/dummy_sup.erl b/test/upgrade_project/apps/dummy/src/dummy_sup.erl deleted file mode 100644 index b5617c7..0000000 --- a/test/upgrade_project/apps/dummy/src/dummy_sup.erl +++ /dev/null @@ -1,15 +0,0 @@ --module(dummy_sup). --behaviour(supervisor). - --export([start_link/0]). --export([init/1]). - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -init([]) -> - Dummy = {dummy_server, - {dummy_server, start_link, []}, - permanent, 5000, worker, [dummy_server]}, - - {ok, {{one_for_one, 10, 10}, [Dummy]}}. diff --git a/test/upgrade_project/rebar.config b/test/upgrade_project/rebar.config deleted file mode 100644 index 11b5b9a..0000000 --- a/test/upgrade_project/rebar.config +++ /dev/null @@ -1,4 +0,0 @@ -{sub_dirs, [ - "apps/dummy", - "rel" -]}. diff --git a/test/upgrade_project/rel/files/dummy b/test/upgrade_project/rel/files/dummy deleted file mode 100755 index c2ef258..0000000 --- a/test/upgrade_project/rel/files/dummy +++ /dev/null @@ -1,347 +0,0 @@ -#!/bin/sh -# -*- tab-width:4;indent-tabs-mode:nil -*- -# ex: ts=4 sw=4 et - -# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is. -if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then - POSIX_SHELL="true" - export POSIX_SHELL - # To support 'whoami' add /usr/ucb to path - PATH=/usr/ucb:$PATH - export PATH - exec /usr/bin/ksh $0 "$@" -fi - -# clear it so if we invoke other scripts, they run as ksh -unset POSIX_SHELL - -RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P) - -CALLER_DIR=$PWD - -RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*} -RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc -# Note the trailing slash on $PIPE_DIR/ -PIPE_DIR=/tmp/$RUNNER_BASE_DIR/ -RUNNER_USER= -WHOAMI=$(whoami) - -# Make sure this script is running as the appropriate user -if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then - type sudo > /dev/null 2>&1 - if [ $? -ne 0 ]; then - echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2 - exit 1 - fi - echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2 - exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@ -fi - -# Identify the script name -SCRIPT=`basename $0` - -# Parse out release and erts info -START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data` -ERTS_VSN=${START_ERL% *} -APP_VSN=${START_ERL#* } - -# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or -# else etc/vm.args -if [ -e "$CALLER_DIR/vm.args" ]; then - VMARGS_PATH=$CALLER_DIR/vm.args - USE_DIR=$CALLER_DIR -else - USE_DIR=$RUNNER_BASE_DIR - if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then - VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" - else - VMARGS_PATH="$RUNNER_ETC_DIR/vm.args" - fi -fi - -RUNNER_LOG_DIR=$USE_DIR/log -# Make sure log directory exists -mkdir -p $RUNNER_LOG_DIR - -# Use releases/VSN/sys.config if it exists otherwise use etc/app.config -if [ -e "$USE_DIR/sys.config" ]; then - CONFIG_PATH="$USE_DIR/sys.config" -else - if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then - CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" - else - CONFIG_PATH="$RUNNER_ETC_DIR/app.config" - fi -fi - -# Extract the target node name from node.args -NAME_ARG=`egrep '^\-s?name' $VMARGS_PATH` -if [ -z "$NAME_ARG" ]; then - echo "vm.args needs to have either -name or -sname parameter." - exit 1 -fi - -# Extract the name type and name from the NAME_ARG for REMSH -REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'` -REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'` - -# Note the `date +%s`, used to allow multiple remsh to the same node -# transparently -REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`" -REMSH_REMSH_ARG="-remsh $REMSH_NAME" - -# Extract the target cookie -COOKIE_ARG=`grep '^\-setcookie' $VMARGS_PATH` -if [ -z "$COOKIE_ARG" ]; then - echo "vm.args needs to have a -setcookie parameter." - exit 1 -fi - -# Make sure CWD is set to the right dir -cd $USE_DIR - -# Make sure log directory exists -mkdir -p $USE_DIR/log - -# Add ERTS bin dir to our path -ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin - -# Setup command to control the node -NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG" - -# Setup remote shell command to control node -REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG" - -# Common functions - -# Ping node without allowing nodetool to take stdin -ping_node() { - $NODETOOL ping < /dev/null -} - -# Set the PID global variable, return 1 on error -get_pid() { - PID=`$NODETOOL getpid < /dev/null` - ES=$? - if [ "$ES" -ne 0 ]; then - echo "Node is not running!" - return 1 - fi - - # don't allow empty or init pid's - if [ -z $PID ] || [ "$PID" -le 1 ]; then - return 1 - fi - - return 0 -} - -# Check the first argument for instructions -case "$1" in - start|start_boot) - # Make sure there is not already a node running - RES=`ping_node` - if [ "$RES" = "pong" ]; then - echo "Node is already running!" - exit 1 - fi - case "$1" in - start) - shift - START_OPTION="console" - HEART_OPTION="start" - ;; - start_boot) - shift - START_OPTION="console_boot" - HEART_OPTION="start_boot" - ;; - esac - RUN_PARAM=$(printf "\'%s\' " "$@") - HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM" - export HEART_COMMAND - mkdir -p $PIPE_DIR - $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1 - ;; - - stop) - # Wait for the node to completely stop... - case `uname -s` in - Darwin) - # Make sure we explicitly set this because iTerm.app doesn't for - # some reason. - COMMAND_MODE=unix2003 - esac - - # Get the PID from nodetool - get_pid - GPR=$? - if [ "$GPR" -ne 0 ] || [ -z $PID ]; then - exit $GPR - fi - - # Tell nodetool to initiate a stop - $NODETOOL stop - ES=$? - if [ "$ES" -ne 0 ]; then - exit $ES - fi - - # Wait for the node to completely stop... - while `kill -s 0 $PID 2>/dev/null` - do - sleep 1 - done - ;; - - restart) - ## Restart the VM without exiting the process - $NODETOOL restart - ES=$? - if [ "$ES" -ne 0 ]; then - exit $ES - fi - ;; - - reboot) - ## Restart the VM completely (uses heart to restart it) - $NODETOOL reboot - ES=$? - if [ "$ES" -ne 0 ]; then - exit $ES - fi - ;; - - ping) - ## See if the VM is alive - ping_node - ES=$? - if [ "$ES" -ne 0 ]; then - exit $ES - fi - ;; - - attach) - # Make sure a node is running - ping_node - ES=$? - if [ "$ES" -ne 0 ]; then - echo "Node is not running!" - exit $ES - fi - - shift - exec $ERTS_PATH/to_erl $PIPE_DIR - ;; - - remote_console) - # Make sure a node is running - ping_node - ES=$? - if [ "$ES" -ne 0 ]; then - echo "Node is not running!" - exit $ES - fi - - shift - exec $REMSH - ;; - - upgrade) - if [ -z "$2" ]; then - echo "Missing upgrade package argument" - echo "Usage: $SCRIPT upgrade {package base name}" - echo "NOTE {package base name} MUST NOT include the .tar.gz suffix" - exit 1 - fi - - # Make sure a node IS running - ping_node - ES=$? - if [ "$ES" -ne 0 ]; then - echo "Node is not running!" - exit $ES - fi - - node_name=`echo $NAME_ARG | awk '{print $2}'` - erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'` - - $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2 - ;; - - console|console_clean|console_boot) - # .boot file typically just $SCRIPT (ie, the app name) - # however, for debugging, sometimes start_clean.boot is useful. - # For e.g. 'setup', one may even want to name another boot script. - case "$1" in - console) BOOTFILE=$SCRIPT ;; - console_clean) BOOTFILE=start_clean ;; - console_boot) - shift - BOOTFILE="$1" - shift - ;; - esac - # Setup beam-required vars - ROOTDIR=$RUNNER_BASE_DIR - BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin - EMU=beam - PROGNAME=`echo $0 | sed 's/.*\\///'` - CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH" - export EMU - export ROOTDIR - export BINDIR - export PROGNAME - - # Dump environment info for logging purposes - echo "Exec: $CMD" -- ${1+"$@"} - echo "Root: $ROOTDIR" - - # Log the startup - logger -t "$SCRIPT[$$]" "Starting up" - - # Start the VM - exec $CMD -- ${1+"$@"} - ;; - - foreground) - # start up the release in the foreground for use by runit - # or other supervision services - - BOOTFILE=$SCRIPT - FOREGROUNDOPTIONS="-noinput +Bd" - - # Setup beam-required vars - ROOTDIR=$RUNNER_BASE_DIR - BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin - EMU=beam - PROGNAME=`echo $0 | sed 's/.*\///'` - CMD="$BINDIR/erlexec $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH" - export EMU - export ROOTDIR - export BINDIR - export PROGNAME - - # Dump environment info for logging purposes - echo "Exec: $CMD" -- ${1+"$@"} - echo "Root: $ROOTDIR" - - # Start the VM - exec $CMD -- ${1+"$@"} - ;; - getpid) - # Get the PID from nodetool - get_pid - ES=$? - if [ "$ES" -ne 0 ] || [ -z $PID ]; then - exit $ES - fi - echo $PID - ;; - *) - echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}" - exit 1 - ;; -esac - -exit 0 diff --git a/test/upgrade_project/rel/files/erl b/test/upgrade_project/rel/files/erl deleted file mode 100755 index f4c63af..0000000 --- a/test/upgrade_project/rel/files/erl +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is. -if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then - POSIX_SHELL="true" - export POSIX_SHELL - exec /usr/bin/ksh $0 "$@" -fi - -# clear it so if we invoke other scripts, they run as ksh as well -unset POSIX_SHELL - -## This script replaces the default "erl" in erts-VSN/bin. This is -## necessary as escript depends on erl and in turn, erl depends on -## having access to a bootscript (start.boot). Note that this script -## is ONLY invoked as a side-effect of running escript -- the embedded -## node bypasses erl and uses erlexec directly (as it should). -## -## Note that this script makes the assumption that there is a -## start_clean.boot file available in $ROOTDIR/release/VSN. - -# Determine the abspath of where this script is executing from. -ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P) - -# Now determine the root directory -- this script runs from erts-VSN/bin, -# so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR -# path. -ROOTDIR=${ERTS_BIN_DIR%/*/*} - -# Parse out release and erts info -START_ERL=`cat $ROOTDIR/releases/start_erl.data` -ERTS_VSN=${START_ERL% *} -APP_VSN=${START_ERL#* } - -BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin -EMU=beam -PROGNAME=`echo $0 | sed 's/.*\\///'` -CMD="$BINDIR/erlexec" -export EMU -export ROOTDIR -export BINDIR -export PROGNAME - -exec $CMD -boot $ROOTDIR/releases/$APP_VSN/start_clean ${1+"$@"} diff --git a/test/upgrade_project/rel/files/nodetool b/test/upgrade_project/rel/files/nodetool deleted file mode 100644 index ce06c6a..0000000 --- a/test/upgrade_project/rel/files/nodetool +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env escript -%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- -%% ex: ft=erlang ts=4 sw=4 et -%% ------------------------------------------------------------------- -%% -%% nodetool: Helper Script for interacting with live nodes -%% -%% ------------------------------------------------------------------- -main(Args) -> - ok = start_epmd(), - %% Extract the args - {RestArgs, TargetNode} = process_args(Args, [], undefined), - - %% any commands that don't need a running node - case RestArgs of - ["chkconfig", File] -> - case file:consult(File) of - {ok, _} -> - io:format("ok\n"), - halt(0); - {error, {Line, Mod, Term}} -> - io:format(standard_error, ["Error on line ", - file:format_error({Line, Mod, Term}), "\n"], []), - halt(1); - {error, R} -> - io:format(standard_error, ["Error reading config file: ", - file:format_error(R), "\n"], []), - halt(1) - end; - _ -> - ok - end, - - %% See if the node is currently running -- if it's not, we'll bail - case {net_kernel:hidden_connect_node(TargetNode), - net_adm:ping(TargetNode)} of - {true, pong} -> - ok; - {false,pong} -> - io:format("Failed to connect to node ~p .\n", [TargetNode]), - halt(1); - {_, pang} -> - io:format("Node ~p not responding to pings.\n", [TargetNode]), - halt(1) - end, - - case RestArgs of - ["getpid"] -> - io:format("~p\n", - [list_to_integer(rpc:call(TargetNode, os, getpid, []))]); - ["ping"] -> - %% If we got this far, the node already responsed to a - %% ping, so just dump a "pong" - io:format("pong\n"); - ["stop"] -> - io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]); - ["restart"] -> - io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]); - ["reboot"] -> - io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]); - ["rpc", Module, Function | RpcArgs] -> - case rpc:call(TargetNode, - list_to_atom(Module), - list_to_atom(Function), - [RpcArgs], 60000) of - ok -> - ok; - {badrpc, Reason} -> - io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), - halt(1); - _ -> - halt(1) - end; - ["rpc_infinity", Module, Function | RpcArgs] -> - case rpc:call(TargetNode, - list_to_atom(Module), - list_to_atom(Function), - [RpcArgs], infinity) of - ok -> - ok; - {badrpc, Reason} -> - io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), - halt(1); - _ -> - halt(1) - end; - ["rpcterms", Module, Function, ArgsAsString] -> - case rpc:call(TargetNode, - list_to_atom(Module), - list_to_atom(Function), - consult(ArgsAsString), 60000) of - {badrpc, Reason} -> - io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), - halt(1); - Other -> - io:format("~p\n", [Other]) - end; - Other -> - io:format("Other: ~p\n", [Other]), - io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n") - end, - net_kernel:stop(). - -process_args([], Acc, TargetNode) -> - {lists:reverse(Acc), TargetNode}; -process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) -> - erlang:set_cookie(node(), list_to_atom(Cookie)), - process_args(Rest, Acc, TargetNode); -process_args(["-name", TargetName | Rest], Acc, _) -> - ThisNode = append_node_suffix(TargetName, "_maint_"), - {ok, _} = net_kernel:start([ThisNode, longnames]), - process_args(Rest, Acc, nodename(TargetName)); -process_args(["-sname", TargetName | Rest], Acc, _) -> - ThisNode = append_node_suffix(TargetName, "_maint_"), - {ok, _} = net_kernel:start([ThisNode, shortnames]), - process_args(Rest, Acc, nodename(TargetName)); -process_args([Arg | Rest], Acc, Opts) -> - process_args(Rest, [Arg | Acc], Opts). - - -start_epmd() -> - [] = os:cmd(epmd_path() ++ " -daemon"), - ok. - -epmd_path() -> - ErtsBinDir = filename:dirname(escript:script_name()), - Name = "epmd", - case os:find_executable(Name, ErtsBinDir) of - false -> - case os:find_executable(Name) of - false -> - io:format("Could not find epmd.~n"), - halt(1); - GlobalEpmd -> - GlobalEpmd - end; - Epmd -> - Epmd - end. - - -nodename(Name) -> - case string:tokens(Name, "@") of - [_Node, _Host] -> - list_to_atom(Name); - [Node] -> - [_, Host] = string:tokens(atom_to_list(node()), "@"), - list_to_atom(lists:concat([Node, "@", Host])) - end. - -append_node_suffix(Name, Suffix) -> - case string:tokens(Name, "@") of - [Node, Host] -> - list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host])); - [Node] -> - list_to_atom(lists:concat([Node, Suffix, os:getpid()])) - end. - - -%% -%% Given a string or binary, parse it into a list of terms, ala file:consult/0 -%% -consult(Str) when is_list(Str) -> - consult([], Str, []); -consult(Bin) when is_binary(Bin)-> - consult([], binary_to_list(Bin), []). - -consult(Cont, Str, Acc) -> - case erl_scan:tokens(Cont, Str, 0) of - {done, Result, Remaining} -> - case Result of - {ok, Tokens, _} -> - {ok, Term} = erl_parse:parse_term(Tokens), - consult([], Remaining, [Term | Acc]); - {eof, _Other} -> - lists:reverse(Acc); - {error, Info, _} -> - {error, Info} - end; - {more, Cont1} -> - consult(Cont1, eof, Acc) - end. diff --git a/test/upgrade_project/rel/files/sys.config b/test/upgrade_project/rel/files/sys.config deleted file mode 100644 index 3b7f6bd..0000000 --- a/test/upgrade_project/rel/files/sys.config +++ /dev/null @@ -1,11 +0,0 @@ -[ - %% SASL config - {sasl, [ - {sasl_error_logger, {file, "log/sasl-error.log"}}, - {errlog_type, error}, - {error_logger_mf_dir, "log/sasl"}, % Log directory - {error_logger_mf_maxbytes, 10485760}, % 10 MB max file size - {error_logger_mf_maxfiles, 5} % 5 files max - ]} -]. - diff --git a/test/upgrade_project/rel/files/vm.args b/test/upgrade_project/rel/files/vm.args deleted file mode 100644 index a9aeb64..0000000 --- a/test/upgrade_project/rel/files/vm.args +++ /dev/null @@ -1,19 +0,0 @@ -## Name of the node --name dummy@127.0.0.1 - -## Cookie for distributed erlang --setcookie dummy - -## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive -## (Disabled by default..use with caution!) -##-heart - -## Enable kernel poll and a few async threads -##+K true -##+A 5 - -## Increase number of concurrent ports/sockets -##-env ERL_MAX_PORTS 4096 - -## Tweak GC to run more often -##-env ERL_FULLSWEEP_AFTER 10 diff --git a/test/upgrade_project/rel/reltool.config b/test/upgrade_project/rel/reltool.config deleted file mode 100644 index b691c77..0000000 --- a/test/upgrade_project/rel/reltool.config +++ /dev/null @@ -1,27 +0,0 @@ -{sys, [ - {lib_dirs, ["../apps"]}, - {rel, "dummy", "0.1", [ - kernel, - stdlib, - sasl, - dummy - ]}, - {rel, "start_clean", "", [kernel, stdlib]}, - {boot_rel, "dummy"}, - {profile, embedded}, - {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)"]}, - {excl_archive_filters, [".*"]}, - - {app, hipe, [{incl_cond, exclude}]}, - - {app, dummy, [{incl_cond, include}]} -]}. - -{overlay, [ - {mkdir, "log/sasl"}, - {copy, "files/erl", "{{erts_vsn}}/bin/erl"}, - {copy, "files/nodetool", "{{erts_vsn}}/bin/nodetool"}, - {copy, "files/dummy", "bin/dummy"}, - {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"}, - {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"} - ]}. |