diff options
39 files changed, 648 insertions, 374 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fc9c771 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: erlang +notifications: + webhooks: http://basho-engbot.herokuapp.com/travis?key=a0e66154af272adba328195454cfdc10ff5f33f5 + email: eng@basho.com +otp_release: + - R15B01 + - R15B + - R14B04 + - R14B03 +script: "make debug xref clean all deps test" @@ -1,15 +1,18 @@ -.PHONY: dialyzer_warnings xref_warnings +.PHONY: clean dialyzer_warnings xref_warnings deps test + +REBAR=$(PWD)/rebar +RETEST=$(PWD)/deps/retest/retest all: ./bootstrap clean: - @rm -rf rebar ebin/*.beam inttest/rt.work + @rm -rf rebar ebin/*.beam inttest/rt.work rt.work .eunit debug: @./bootstrap debug -check: debug xref dialyzer +check: debug xref dialyzer deps test xref: @./rebar xref @@ -20,3 +23,16 @@ dialyzer: dialyzer_warnings dialyzer_warnings: -@dialyzer -q -n ebin -Wunmatched_returns -Werror_handling \ -Wrace_conditions > dialyzer_warnings + +binary: VSN = $(shell ./rebar -V) +binary: clean all + @cp rebar ../rebar.wiki/rebar + (cd ../rebar.wiki && git commit -m "Update $(VSN)" rebar) + +deps: + @REBAR_EXTRA_DEPS=1 ./rebar get-deps + @(cd deps/retest && $(REBAR) compile escriptize) + +test: + @$(REBAR) eunit + @$(RETEST) inttest @@ -4,6 +4,8 @@ rebar rebar is an Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +[![Build Status](https://secure.travis-ci.org/basho/rebar.png?branch=master)](http://travis-ci.org/basho/rebar) + rebar is a self-contained Erlang script, so it's easy to distribute or even embed directly in a project. Where possible, rebar uses standard Erlang/OTP conventions for project structures, thus minimizing the amount of build @@ -27,15 +29,14 @@ Should you want to clone the rebar repository, you will also require git. #### Downloading -Clone the git repository: +You can download a pre-built binary version of rebar from: -```sh -$ git clone git://github.com/basho/rebar.git -``` +https://github.com/basho/rebar/wiki/rebar #### Building rebar ```sh +$ git clone git://github.com/basho/rebar.git $ cd rebar $ ./bootstrap Recompile: src/getopt @@ -72,8 +73,8 @@ Do not mix spaces and tabs. Do not introduce lines longer than 80 characters. [erlang-mode (emacs)](http://www.erlang.org/doc/man/erlang.el.html) indentation is preferred. -vi-only users are encouraged to give [Vim emulation](http://emacswiki.org/emacs/Evil) -([more info](https://gitorious.org/evil/pages/Home)) a try. +vi-only users are encouraged to +give [Vim emulation](http://emacswiki.org/emacs/Evil) ([more info](https://gitorious.org/evil/pages/Home)) a try. Writing Commit Messages ----------------------- @@ -107,42 +108,26 @@ Longer description (wrap at 72 characters) * Break up logical changes * Make whitespace changes separately -Dialyzer and Tidier -------------------- +Run checks +---------- -Before you submit a patch check for +Before you submit a patch, run ``make check`` to execute +the test suite and check for [xref](http://www.erlang.org/doc/man/xref.html) and [Dialyzer](http://www.erlang.org/doc/man/dialyzer.html) -warnings. +warnings. You may have to run ``make clean`` first. -A successful run of ``make check`` looks like: - -```sh -$ make check -Recompile: src/rebar_core -==> rebar (compile) -Command 'debug' not understood or not applicable -Congratulations! You now have a self-contained script called "rebar" in -your current working directory. Place this script anywhere in your path -and you can use rebar to build OTP-compliant apps. -==> rebar (xref) -make: [dialyzer_warnings] Error 2 (ignored) -``` - -[xref](http://www.erlang.org/doc/man/xref.html) and [Dialyzer](http://www.erlang.org/doc/man/dialyzer.html) warnings are compared -against a set of safe-to-ignore warnings -found in -[dialyzer_reference](https://raw.github.com/tuncer/rebar/maint/dialyzer_reference) -and -[xref_reference](https://raw.github.com/tuncer/rebar/maint/xref_reference). +against a set of safe-to-ignore warnings found in +[dialyzer_reference](https://raw.github.com/basho/rebar/master/dialyzer_reference). +[xref](http://www.erlang.org/doc/man/xref.html) is run with +[custom queries](https://raw.github.com/basho/rebar/master/rebar.config) +to suppress safe-to-ignore warnings. It is **strongly recommended** to check the code with -[Tidier](http://tidier.softlab.ntua.gr:20000/tidier/getstarted). -Select all transformation options and enable **automatic** -transformation. -If Tidier suggests a transformation apply the changes **manually** -to the source code. -Do not use the code from the tarball (*out.tgz*) as it will have -white-space changes -applied by Erlang's pretty-printer. +[Tidier](http://tidier.softlab.ntua.gr:20000/tidier/getstarted). +Select all transformation +options and enable **automatic** transformation. If Tidier suggests a transformation, +apply the changes **manually** to the source code. Do not use the code from +the +tarball (*out.tgz*) as it will have white-space changes applied by Erlang's pretty-printer. @@ -82,7 +82,7 @@ Ali Sabil Tomas Abrahamsson Francis Joanis fisher@yun.io -Yurin Slava +Slava Yurin Phillip Toland Mike Lazar Loic Hoguin @@ -91,3 +91,7 @@ Adam Schepis Amit Kapoor Ulf Wiger Nick Vatamaniuc +Daniel Luna +Motiejus Jakstys +Eric B Merritt +Fred Hebert @@ -8,7 +8,7 @@ main(Args) -> %% Get a string repr of first matching VCS changeset VcsInfo = vcs_info([{hg, ".hg", "hg identify -i"}, - {git, ".git", "git describe --always"}]), + {git, ".git", "git describe --always --tags"}]), %% Check for force=1 flag to force a rebuild case lists:member("force=1", Args) of @@ -24,12 +24,16 @@ main(Args) -> false -> undefined end, + %% Extract the system info of the version of OTP we use to compile rebar + OtpInfo = string:strip(erlang:system_info(otp_release), both, $\n), + %% Compile all src/*.erl to ebin case make:files(filelib:wildcard("src/*.erl"), [{outdir, "ebin"}, {i, "include"}, DebugFlag, {d, 'BUILD_TIME', Built}, - {d, 'VCS_INFO', VcsInfo}]) of + {d, 'VCS_INFO', VcsInfo}, + {d, 'OTP_INFO', OtpInfo}]) of up_to_date -> ok; error -> @@ -49,35 +53,9 @@ main(Args) -> %% Add ebin/ to our path true = code:add_path("ebin"), - %% Run rebar to do proper .app validation and such - rebar:main(["compile"] ++ Args), - - %% Read the contents of the files in ebin and templates; note that we - %% place all the beam files at the top level of the code archive so - %% that code loading works properly. - Files = load_files("*", "ebin") ++ load_files("priv/templates/*", "."), - - case zip:create("mem", Files, [memory]) of - {ok, {"mem", ZipBin}} -> - %% Archive was successfully created. Prefix that binary with our - %% header and write to "rebar" file. - %% Without -noshell -noinput escript consumes all input that would - %% otherwise go to the shell for the next command. - Script = <<"#!/usr/bin/env escript\n%%! -noshell -noinput\n", - ZipBin/binary>>, - case file:write_file("rebar", Script) of - ok -> - ok; - {error, WriteError} -> - io:format("Failed to write rebar script: ~p\n", - [WriteError]), - halt(1) - end; - {error, ZipError} -> - io:format("Failed to construct rebar script archive: ~p\n", - [ZipError]), - halt(1) - end, + %% Run rebar compile to do proper .app validation etc. + %% and rebar escriptize to create the rebar script + rebar:main(["compile", "escriptize"] ++ Args), %% Finally, update executable perms for our script on *nix, %% or write out script files on win32. @@ -113,14 +91,6 @@ build_time() -> lists:flatten(io_lib:format("~4..0w~2..0w~2..0w_~2..0w~2..0w~2..0w", [Y, M, D, H, Min, S])). - -load_files(Wildcard, Dir) -> - [read_file(Filename, Dir) || Filename <- filelib:wildcard(Wildcard, Dir)]. - -read_file(Filename, Dir) -> - {ok, Bin} = file:read_file(filename:join(Dir, Filename)), - {Filename, Bin}. - vcs_info([]) -> "No VCS info available."; vcs_info([{Id, Dir, Cmd} | Rest]) -> diff --git a/dialyzer_reference b/dialyzer_reference index 29744a3..22d1e81 100644 --- a/dialyzer_reference +++ b/dialyzer_reference @@ -1,2 +1,2 @@ -rebar_utils.erl:154: Call to missing or unexported function escript:foldl/3 +rebar_utils.erl:161: Call to missing or unexported function escript:foldl/3 diff --git a/ebin/rebar.app b/ebin/rebar.app index 0c6e4c3..9553c67 100644 --- a/ebin/rebar.app +++ b/ebin/rebar.app @@ -3,30 +3,30 @@ {application, rebar, [{description, "Rebar: Erlang Build Tool"}, - {vsn, "2"}, + {vsn, "2.0.0"}, {modules, [ rebar, rebar_abnfc_compiler, - rebar_appups, rebar_app_utils, + rebar_appups, + rebar_asn1_compiler, rebar_base_compiler, + rebar_cleaner, rebar_config, rebar_core, - rebar_cleaner, rebar_ct, rebar_deps, - rebar_asn1_compiler, rebar_edoc, rebar_erlc_compiler, + rebar_erlydtl_compiler, rebar_escripter, rebar_eunit, rebar_file_utils, rebar_lfe_compiler, - rebar_erlydtl_compiler, rebar_log, + rebar_neotoma_compiler, rebar_otp_app, rebar_port_compiler, rebar_protobuffs_compiler, - rebar_neotoma_compiler, rebar_rel_utils, rebar_reltool, rebar_require_vsn, @@ -35,12 +35,17 @@ rebar_upgrade, rebar_utils, rebar_xref, + rebar_shell, getopt, mustache ]}, {registered, []}, {applications, [kernel, stdlib, - sasl]}, + sasl, + compiler, + crypto, + syntax_tools, + tools]}, {env, [ %% Default log level {log_level, error}, @@ -73,6 +78,7 @@ rebar_eunit, rebar_escripter, rebar_edoc, + rebar_shell, rebar_xref ]}, diff --git a/include/rebar.hrl b/include/rebar.hrl index 0f4e90f..7568898 100644 --- a/include/rebar.hrl +++ b/include/rebar.hrl @@ -1,5 +1,5 @@ --define(FAIL, throw({error, failed})). +-define(ABORT, rebar_utils:abort()). -define(ABORT(Str, Args), rebar_utils:abort(Str, Args)). -define(CONSOLE(Str, Args), io:format(Str, Args)). diff --git a/inttest/t_custom_config/t_custom_config_rt.erl b/inttest/t_custom_config/t_custom_config_rt.erl index d333b11..db1b29a 100644 --- a/inttest/t_custom_config/t_custom_config_rt.erl +++ b/inttest/t_custom_config/t_custom_config_rt.erl @@ -11,7 +11,7 @@ files() -> run(Dir) -> retest_log:log(debug, "Running in Dir: ~s~n", [Dir]), - Ref = retest:sh("./rebar -C custom.config check-deps -v", [{async, true}]), + Ref = retest:sh("./rebar -C custom.config check-deps -vvv", [{async, true}]), {ok, Captured} = retest:sh_expect(Ref, "DEBUG: Consult config file .*/custom.config.*", diff --git a/inttest/tplugins/tplugins_rt.erl b/inttest/tplugins/tplugins_rt.erl index d2ef382..d6908ad 100644 --- a/inttest/tplugins/tplugins_rt.erl +++ b/inttest/tplugins/tplugins_rt.erl @@ -18,7 +18,7 @@ files() -> {create, "ebin/fish.app", app(fish, [fish])} ]. -run(Dir) -> +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}]), diff --git a/priv/templates/simplenode.reltool.config b/priv/templates/simplenode.reltool.config index 932b148..b580c2a 100644 --- a/priv/templates/simplenode.reltool.config +++ b/priv/templates/simplenode.reltool.config @@ -16,15 +16,13 @@ ]}, {boot_rel, "{{nodeid}}"}, {profile, embedded}, - {incl_cond, exclude}, + {incl_cond, derived}, + {mod_cond, derived}, {excl_archive_filters, [".*"]}, %% Do not archive built libs {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)", "^erts.*/(doc|info|include|lib|man|src)"]}, {excl_app_filters, ["\.gitignore"]}, - {app, sasl, [{incl_cond, include}]}, - {app, stdlib, [{incl_cond, include}]}, - {app, kernel, [{incl_cond, include}]}, - {app, {{nodeid}}, [{incl_cond, include}]} + {app, {{nodeid}}, [{mod_cond, app}, {incl_cond, include}]} ]}. {target_dir, "{{nodeid}}"}. diff --git a/rebar.config b/rebar.config index 10c0771..9afa8da 100644 --- a/rebar.config +++ b/rebar.config @@ -2,6 +2,11 @@ %% ex: ts=4 sw=4 ft=erlang et {app_bin, ["priv/rebar"]}. +{escript_shebang, "#!/usr/bin/env escript\n"}. +{escript_emu_args, "%%! -noshell -noinput\n"}. +%% escript_incl_extra is for internal rebar-private use only. +%% Do not use outside rebar. Config interface is not stable. +{escript_incl_extra, [{"priv/templates/*", "."}]}. {erl_opts, [warnings_as_errors]}. {xref_checks, []}. {xref_queries, diff --git a/rebar.config.sample b/rebar.config.sample index dc4253b..0e846f9 100644 --- a/rebar.config.sample +++ b/rebar.config.sample @@ -85,6 +85,9 @@ %% Option to pass extra parameters when launching Common Test {ct_extra_params, "-boot start_sasl -s myapp"}. +%% Option to use short names (i.e., -sname test) when starting ct +{ct_use_short_names, true}. + %% == Cleanup == %% Which files to cleanup diff --git a/rebar.config.script b/rebar.config.script new file mode 100644 index 0000000..07feb95 --- /dev/null +++ b/rebar.config.script @@ -0,0 +1,20 @@ +%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 ft=erlang et + +%% TODO: Change temporary retest fork back to dizzyd/retest after merge +%% ExtraDeps = [{retest, ".*", {git, "git://github.com/dizzyd/retest.git"}}], +ExtraDeps = [{retest, ".*", + {git, "git://github.com/tuncer/retest.git", "next"}}], + +case os:getenv("REBAR_EXTRA_DEPS") of + false -> + CONFIG; + _ -> + case lists:keysearch(deps, 1, CONFIG) of + {value, {deps, Deps}} -> + NDeps = Deps ++ ExtraDeps, + lists:keyreplace(deps, 1, CONFIG, {deps, NDeps}); + false -> + CONFIG ++ [{deps, ExtraDeps}] + end +end. diff --git a/src/rebar.erl b/src/rebar.erl index 1f72a4c..0b7602b 100644 --- a/src/rebar.erl +++ b/src/rebar.erl @@ -41,6 +41,10 @@ -define(VCS_INFO, "undefined"). -endif. +-ifndef(OTP_INFO). +-define(OTP_INFO, "undefined"). +-endif. + %% ==================================================================== %% Public API %% ==================================================================== @@ -49,13 +53,13 @@ main(Args) -> case catch(run(Args)) of ok -> ok; - {error, failed} -> - halt(1); + rebar_abort -> + rebar_utils:delayed_halt(1); Error -> %% Nothing should percolate up from rebar_core; %% Dump this error to console io:format("Uncaught error in rebar_core: ~p\n", [Error]), - halt(1) + rebar_utils:delayed_halt(1) end. %% ==================================================================== @@ -91,7 +95,10 @@ run_aux(["version"]) -> ok; run_aux(Commands) -> %% Make sure crypto is running - ok = crypto:start(), + case crypto:start() of + ok -> ok; + {error,{already_started,crypto}} -> ok + end, %% Initialize logging system rebar_log:init(), @@ -158,6 +165,10 @@ parse_args(Args) -> rebar_config:set_global(enable_profiling, proplists:get_bool(profile, Options)), + %% Setup flag to keep running after a single command fails + rebar_config:set_global(keep_going, + proplists:get_bool(keep_going, Options)), + %% Set global variables based on getopt options set_log_level(Options), set_global_flag(Options, force), @@ -182,7 +193,7 @@ parse_args(Args) -> {error, {Reason, Data}} -> ?ERROR("~s ~p~n~n", [Reason, Data]), help(), - halt(1) + rebar_utils:delayed_halt(1) end. %% @@ -202,8 +213,8 @@ set_log_level(Options) -> %% version() -> {ok, Vsn} = application:get_key(rebar, vsn), - ?CONSOLE("rebar version: ~s date: ~s vcs: ~s\n", - [Vsn, ?BUILD_TIME, ?VCS_INFO]). + ?CONSOLE("rebar ~s ~s ~s ~s\n", + [Vsn, ?OTP_INFO, ?BUILD_TIME, ?VCS_INFO]). %% @@ -229,7 +240,7 @@ show_info_maybe_halt(Opts, NonOptArgs) -> [] -> ?CONSOLE("No command to run specified!~n",[]), help(), - halt(1); + rebar_utils:delayed_halt(1); _ -> ok end. @@ -271,8 +282,8 @@ generate-upgrade previous_release=path Build an upgrade package generate-appups previous_release=path Generate appup files -eunit [suite=foo] Run eunit [test/foo_tests.erl] tests -ct [suites=] [case=] Run common_test suites in ./test +eunit [suites=foo] Run eunit [test/foo_tests.erl] tests +ct [suites=] [case=] Run common_test suites xref Run cross reference analysis @@ -300,7 +311,9 @@ option_spec_list() -> {defines, $D, undefined, string, "Define compiler macro"}, {jobs, $j, "jobs", integer, JobsHelp}, {config, $C, "config", string, "Rebar config file to use"}, - {profile, $p, "profile", undefined, "Profile this run of rebar"} + {profile, $p, "profile", undefined, "Profile this run of rebar"}, + {keep_going, $k, "keep-going", undefined, + "Keep running after a command fails"} ]. %% @@ -332,7 +345,8 @@ command_names() -> ["check-deps", "clean", "compile", "create", "create-app", "create-node", "ct", "delete-deps", "doc", "eunit", "generate", "generate-appups", "generate-upgrade", "get-deps", "help", "list-deps", "list-templates", - "update-deps", "overlay", "version", "xref"]. + "update-deps", "overlay", "shell", "version", "xref"]. + unabbreviate_command_names([]) -> []; diff --git a/src/rebar_abnfc_compiler.erl b/src/rebar_abnfc_compiler.erl index 0e6749a..cb56854 100644 --- a/src/rebar_abnfc_compiler.erl +++ b/src/rebar_abnfc_compiler.erl @@ -90,7 +90,7 @@ compile_abnfc(Source, _Target, Config) -> " https://github.com/nygge/abnfc~n" " and install it into your erlang library dir~n" "===============================================~n~n", []), - ?FAIL; + ?ABORT; true -> AbnfcOpts = abnfc_opts(Config), SourceExt = option(source_ext, AbnfcOpts), @@ -103,6 +103,6 @@ compile_abnfc(Source, _Target, Config) -> Error -> ?ERROR("Compiling grammar ~s failed:~n ~p~n", [Source, Error]), - ?FAIL + ?ABORT end end. diff --git a/src/rebar_asn1_compiler.erl b/src/rebar_asn1_compiler.erl index 40129c9..c9dca1f 100644 --- a/src/rebar_asn1_compiler.erl +++ b/src/rebar_asn1_compiler.erl @@ -65,7 +65,7 @@ compile_asn1(Source, Target, Config) -> ok end; {error, _Reason} -> - ?FAIL + ?ABORT end. asn_generated_files(AsnDir, SrcDir, IncDir) -> diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl index 10a495d..7d1fb22 100644 --- a/src/rebar_base_compiler.erl +++ b/src/rebar_base_compiler.erl @@ -28,7 +28,8 @@ -include("rebar.hrl"). --export([run/4, run/7, run/8]). +-export([run/4, run/7, run/8, + ok_tuple/2, error_tuple/4]). %% =================================================================== @@ -79,6 +80,11 @@ run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt, simple_compile_wrapper(S, Target, Compile3Fn, C, CheckLastMod) end). +ok_tuple(Source, Ws) -> + {ok, format_warnings(Source, Ws)}. + +error_tuple(Source, Es, Ws, Opts) -> + {error, format_errors(Source, Es), format_warnings(Source, Ws, Opts)}. %% =================================================================== %% Internal functions @@ -116,23 +122,29 @@ compile(Source, Config, CompileFn) -> ok -> ok; skipped -> - skipped + skipped; + Error -> + Error end. - compile_each([], _Config, _CompileFn) -> ok; compile_each([Source | Rest], Config, CompileFn) -> case compile(Source, Config, CompileFn) of ok -> ?CONSOLE("Compiled ~s\n", [Source]); + {ok, Warnings} -> + report(Warnings), + ?CONSOLE("Compiled ~s\n", [Source]); skipped -> - ?INFO("Skipped ~s\n", [Source]) + ?INFO("Skipped ~s\n", [Source]); + Error -> + maybe_report(Error), + ?DEBUG("Compilation failed: ~p\n", [Error]), + ?ABORT end, compile_each(Rest, Config, CompileFn). - - compile_queue([], []) -> ok; compile_queue(Pids, Targets) -> @@ -148,8 +160,14 @@ compile_queue(Pids, Targets) -> end; {fail, Error} -> + maybe_report(Error), ?DEBUG("Worker compilation failed: ~p\n", [Error]), - ?FAIL; + ?ABORT; + + {compiled, Source, Warnings} -> + report(Warnings), + ?CONSOLE("Compiled ~s\n", [Source]), + compile_queue(Pids, Targets); {compiled, Source} -> ?CONSOLE("Compiled ~s\n", [Source]), @@ -166,7 +184,7 @@ compile_queue(Pids, Targets) -> {'DOWN', _Mref, _, _Pid, Info} -> ?DEBUG("Worker failed: ~p\n", [Info]), - ?FAIL + ?ABORT end. compile_worker(QueuePid, Config, CompileFn) -> @@ -174,6 +192,9 @@ compile_worker(QueuePid, Config, CompileFn) -> receive {compile, Source} -> case catch(compile(Source, Config, CompileFn)) of + {ok, Ws} -> + QueuePid ! {compiled, Source, Ws}, + compile_worker(QueuePid, Config, CompileFn); ok -> QueuePid ! {compiled, Source}, compile_worker(QueuePid, Config, CompileFn); @@ -189,3 +210,42 @@ compile_worker(QueuePid, Config, CompileFn) -> empty -> ok end. + +format_errors(Source, Errors) -> + format_errors(Source, "", Errors). + +format_warnings(Source, Warnings) -> + format_warnings(Source, Warnings, []). + +format_warnings(Source, Warnings, Opts) -> + Prefix = case lists:member(warnings_as_errors, Opts) of + true -> ""; + false -> "Warning: " + end, + format_errors(Source, Prefix, Warnings). + +maybe_report([{error, {error, _Es, _Ws}=ErrorsAndWarnings}, {source, _}]) -> + maybe_report(ErrorsAndWarnings); +maybe_report({error, Es, Ws}) -> + report(Es), + report(Ws); +maybe_report(_) -> + ok. + +report(Messages) -> + lists:foreach(fun(Msg) -> io:format("~s", [Msg]) end, Messages). + +format_errors(Source, Extra, Errors) -> + AbsSource = filename:absname(Source), + [[format_error(AbsSource, Extra, Desc) || Desc <- Descs] + || {_, Descs} <- Errors]. + +format_error(AbsSource, Extra, {{Line, Column}, Mod, Desc}) -> + ErrorDesc = Mod:format_error(Desc), + ?FMT("~s:~w:~w: ~s~s~n", [AbsSource, Line, Column, Extra, ErrorDesc]); +format_error(AbsSource, Extra, {Line, Mod, Desc}) -> + ErrorDesc = Mod:format_error(Desc), + ?FMT("~s:~w: ~s~s~n", [AbsSource, Line, Extra, ErrorDesc]); +format_error(AbsSource, Extra, {Mod, Desc}) -> + ErrorDesc = Mod:format_error(Desc), + ?FMT("~s: ~s~s~n", [AbsSource, Extra, ErrorDesc]). diff --git a/src/rebar_core.erl b/src/rebar_core.erl index 7828c66..99d3c38 100644 --- a/src/rebar_core.erl +++ b/src/rebar_core.erl @@ -64,35 +64,51 @@ skip_dirs() -> %% =================================================================== process_commands([], _ParentConfig) -> - case erlang:get(operations) of - 0 -> - %% none of the commands had an effect - ?FAIL; + AbortTrapped = rebar_config:get_global(abort_trapped, false), + case {erlang:get(operations), AbortTrapped} of + {0, _} -> + %% None of the commands had any effect + ?ABORT; + {_, true} -> + %% An abort was previously trapped + ?ABORT; _ -> ok end; process_commands([Command | Rest], ParentConfig) -> - %% Reset skip dirs - lists:foreach(fun (D) -> erlang:erase({skip_dir, D}) end, skip_dirs()), - Operations = erlang:get(operations), - - %% Convert the code path so that all the entries are absolute paths. - %% If not, code:set_path() may choke on invalid relative paths when trying - %% to restore the code path from inside a subdirectory. - true = rebar_utils:expand_code_path(), - _ = process_dir(rebar_utils:get_cwd(), ParentConfig, - Command, sets:new()), - case erlang:get(operations) of - Operations -> - %% This command didn't do anything - ?CONSOLE("Command '~p' not understood or not applicable~n", - [Command]); - _ -> - ok + try + %% Reset skip dirs + lists:foreach(fun (D) -> erlang:erase({skip_dir, D}) end, skip_dirs()), + Operations = erlang:get(operations), + + %% Convert the code path so that all the entries are absolute paths. + %% If not, code:set_path() may choke on invalid relative paths when + %% trying to restore the code path from inside a subdirectory. + true = rebar_utils:expand_code_path(), + _ = process_dir(rebar_utils:get_cwd(), ParentConfig, + Command, sets:new()), + case erlang:get(operations) of + Operations -> + %% This command didn't do anything + ?CONSOLE("Command '~p' not understood or not applicable~n", + [Command]); + _ -> + ok + end, + %% Wipe out vsn cache to avoid invalid hits when + %% dependencies are updated + ets:delete_all_objects(rebar_vsn_cache) + catch + throw:rebar_abort -> + case rebar_config:get_global(keep_going, false) of + false -> + ?ABORT; + true -> + ?WARN("Continuing on after abort: ~p\n", [Rest]), + rebar_config:set_global(abort_trapped, true), + ok + end end, - %% Wipe out vsn cache to avoid invalid hits when - %% dependencies are updated - ets:delete_all_objects(rebar_vsn_cache), process_commands(Rest, ParentConfig). @@ -103,16 +119,6 @@ process_dir(Dir, ParentConfig, Command, DirSet) -> DirSet; true -> - AbsDir = filename:absname(Dir), - ShouldPrintDir = not (is_skip_dir(Dir) orelse processing_base_dir(Dir)), - - case ShouldPrintDir of - true -> - ?CONSOLE("==> Entering directory `~s'\n", [AbsDir]); - _ -> - ok - end, - ok = file:set_cwd(Dir), Config = maybe_load_local_config(Dir, ParentConfig), @@ -127,17 +133,8 @@ process_dir(Dir, ParentConfig, Command, DirSet) -> %% to process this dir. {ok, AvailModuleSets} = application:get_env(rebar, modules), ModuleSet = choose_module_set(AvailModuleSets, Dir), - Res = maybe_process_dir(ModuleSet, Config, CurrentCodePath, - Dir, Command, DirSet), - - case ShouldPrintDir of - true -> - ?CONSOLE("==> Leaving directory `~s'\n", [AbsDir]); - false -> - ok - end, - - Res + maybe_process_dir(ModuleSet, Config, CurrentCodePath, + Dir, Command, DirSet) end. maybe_process_dir({[], undefined}=ModuleSet, Config, CurrentCodePath, @@ -256,7 +253,8 @@ remember_cwd_subdir(Cwd, Subdirs) -> Store = fun(Dir, Dict) -> case dict:find(Dir, Dict) of error -> - ?DEBUG("Associate sub_dir ~s with ~s~n", [Dir, Cwd]), + ?DEBUG("Associate sub_dir ~s with ~s~n", + [Dir, Cwd]), dict:store(Dir, Cwd, Dict); {ok, Existing} -> ?ABORT("Internal consistency assertion failed.~n" @@ -362,7 +360,7 @@ execute(Command, Modules, Config, ModuleFile, Env) -> apply_hooks(post_hooks, Config, Command, Env), ok; {error, failed} -> - ?FAIL; + ?ABORT; {Module, {error, _} = Other} -> ?ABORT("~p failed while processing ~s in module ~s: ~s\n", [Command, Dir, Module, @@ -498,11 +496,13 @@ plugin_modules(Config, SubdirAssoc, Modules) -> plugin_modules(_Config, _SubdirAssoc, FoundModules, []) -> {ok, FoundModules}; plugin_modules(Config, SubdirAssoc, FoundModules, MissingModules) -> - {Loaded, NotLoaded} = load_plugin_modules(Config, SubdirAssoc, MissingModules), + {Loaded, NotLoaded} = load_plugin_modules(Config, SubdirAssoc, + MissingModules), AllViablePlugins = FoundModules ++ Loaded, case NotLoaded =/= [] of true -> - %% NB: we continue to ignore this situation, as did the original code + %% NB: we continue to ignore this situation, as did the + %% original code ?WARN("Missing plugins: ~p\n", [NotLoaded]); false -> ?DEBUG("Loaded plugins: ~p~n", [AllViablePlugins]), diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl index b3e77b0..57f038a 100644 --- a/src/rebar_ct.erl +++ b/src/rebar_ct.erl @@ -83,7 +83,7 @@ clear_log(RawLog) -> ok = file:write_file(RawLog, LogHeader); {error, Reason} -> ?ERROR("Could not create log dir - ~p\n", [Reason]), - ?FAIL + ?ABORT end. %% calling ct with erl does not return non-zero on failure - have to check @@ -98,12 +98,12 @@ check_log(RawLog) -> MakeFailed -> show_log(RawLog), ?ERROR("Building tests failed\n",[]), - ?FAIL; + ?ABORT; RunFailed -> show_log(RawLog), ?ERROR("One or more tests failed\n",[]), - ?FAIL; + ?ABORT; true -> ?CONSOLE("DONE.\n~s\n", [Msg]) @@ -145,33 +145,33 @@ make_cmd(TestDir, Config) -> undefined -> ?FMT("erl " % should we expand ERL_PATH? " -noshell -pa ~s ~s" - " -name test@~s" + " ~s" " -logdir \"~s\"" " -env TEST_DIR \"~s\"" " ~s" " -s ct_run script_start -s erlang halt", [CodePathString, Include, - net_adm:localhost(), + build_name(Config), LogDir, filename:join(Cwd, TestDir), get_extra_params(Config)]) ++ get_cover_config(Config, Cwd) ++ get_ct_config_file(TestDir) ++ get_config_file(TestDir) ++ - get_suite(TestDir) ++ + get_suites(TestDir) ++ get_case(); SpecFlags -> ?FMT("erl " % should we expand ERL_PATH? " -noshell -pa ~s ~s" - " -name test@~s" + " ~s" " -logdir \"~s\"" " -env TEST_DIR \"~s\"" " ~s" " -s ct_run script_start -s erlang halt", [CodePathString, Include, - net_adm:localhost(), + build_name(Config), LogDir, filename:join(Cwd, TestDir), get_extra_params(Config)]) ++ @@ -180,6 +180,12 @@ make_cmd(TestDir, Config) -> RawLog = filename:join(LogDir, "raw.log"), {Cmd, RawLog}. +build_name(Config) -> + case rebar_config:get_local(Config, ct_use_short_names, false) of + true -> "-sname test"; + false -> " -name test@" ++ net_adm:localhost() + end. + get_extra_params(Config) -> rebar_config:get_local(Config, ct_extra_params, ""). @@ -242,7 +248,7 @@ get_config_file(TestDir) -> " -config " ++ Config end. -get_suite(TestDir) -> +get_suites(TestDir) -> case rebar_utils:get_deprecated_global(suite, suites, "soon") of undefined -> " -dir " ++ TestDir; @@ -257,7 +263,7 @@ find_suite_path(Suite, TestDir) -> case filelib:is_regular(Path) of false -> ?ERROR("Suite ~s not found\n", [Suite]), - ?FAIL; + ?ABORT; true -> Path end. diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl index f06eb76..dc2fe84 100644 --- a/src/rebar_deps.erl +++ b/src/rebar_deps.erl @@ -123,7 +123,7 @@ setup_env(_Config) -> ?CONSOLE("Dependency not available: " "~p-~s (~p)\n", [App, Vsn, Src]) end, MissingDeps), - ?FAIL + ?ABORT end. 'get-deps'(Config, _) -> diff --git a/src/rebar_edoc.erl b/src/rebar_edoc.erl index 27e0015..5d85146 100644 --- a/src/rebar_edoc.erl +++ b/src/rebar_edoc.erl @@ -50,9 +50,31 @@ doc(Config, File) -> %% Save code path CodePath = setup_code_path(), - {ok, AppName, _AppData} = rebar_app_utils:load_app_file(File), + + %% Get the edoc_opts and app file info EDocOpts = rebar_config:get(Config, edoc_opts, []), - ok = edoc:application(AppName, ".", EDocOpts), + {ok, AppName, _AppData} = rebar_app_utils:load_app_file(File), + + %% Determine the age of the summary file + EDocInfoName = filename:join(proplists:get_value(dir, EDocOpts, "doc"), + "edoc-info"), + EDocInfoLastMod = filelib:last_modified(EDocInfoName), + + %% For each source directory, look for a more recent file than + %% SumaryLastMod; in that case, we go ahead and do a full regen + NeedsRegen = newer_file_exists(proplists:get_value(source_path, + EDocOpts, ["src"]), + EDocInfoLastMod), + + case NeedsRegen 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. @@ -71,3 +93,28 @@ setup_code_path() -> ebin_dir() -> filename:join(rebar_utils:get_cwd(), "ebin"). + +newer_file_exists(Paths, LastMod) -> + CheckFile = fun(Filename, _) -> + FLast = filelib:last_modified(Filename), + case FLast > LastMod of + true -> + ?DEBUG("~p is more recent than edoc-info: " + "~120p > ~120p\n", + [Filename, FLast, LastMod]), + throw(newer_file_exists); + false -> + false + end + end, + try + lists:foldl(fun(P, _) -> + filelib:fold_files(P, ".*.erl", true, + CheckFile, false) + end, undefined, Paths), + false + catch + throw:newer_file_exists -> + true + end. + diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl index 6535324..be2b59d 100644 --- a/src/rebar_erlc_compiler.erl +++ b/src/rebar_erlc_compiler.erl @@ -122,12 +122,12 @@ doterl_compile(Config, OutDir) -> doterl_compile(Config, OutDir, MoreSources) -> FirstErls = rebar_config:get_list(Config, erl_first_files, []), - ErlOpts = erl_opts(Config), + ErlOpts = rebar_utils:erl_opts(Config), ?DEBUG("erl_opts ~p~n", [ErlOpts]), %% Support the src_dirs option allowing multiple directories to %% contain erlang source. This might be used, for example, should %% eunit tests be separated from the core application source. - SrcDirs = src_dirs(proplists:append_values(src_dirs, ErlOpts)), + SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), RestErls = [Source || Source <- gather_src(SrcDirs, []) ++ MoreSources, not lists:member(Source, FirstErls)], @@ -166,18 +166,6 @@ doterl_compile(Config, OutDir, MoreSources) -> %% Internal functions %% =================================================================== -erl_opts(Config) -> - RawErlOpts = filter_defines(rebar_config:get(Config, erl_opts, []), []), - GlobalDefines = [{d, list_to_atom(D)} || - D <- rebar_config:get_global(defines, [])], - Opts = GlobalDefines ++ RawErlOpts, - case proplists:is_defined(no_debug_info, Opts) of - true -> - [O || O <- Opts, O =/= no_debug_info]; - false -> - [debug_info|Opts] - end. - -spec include_path(Source::file:filename(), Config::rebar_config:config()) -> [file:filename(), ...]. include_path(Source, Config) -> @@ -202,22 +190,23 @@ inspect(Source, IncludePath) -> inspect_epp(Epp, Source, Module, Includes) -> case epp:parse_erl_form(Epp) of {ok, {attribute, _, module, ModInfo}} -> - case ModInfo of - %% Typical module name, single atom - ActualModule when is_atom(ActualModule) -> - ActualModuleStr = atom_to_list(ActualModule); - %% Packag-ized module name, list of atoms - ActualModule when is_list(ActualModule) -> - ActualModuleStr = string:join([atom_to_list(P) || - P <- ActualModule], "."); - %% Parameterized module name, single atom - {ActualModule, _} when is_atom(ActualModule) -> - ActualModuleStr = atom_to_list(ActualModule); - %% Parameterized and packagized module name, list of atoms - {ActualModule, _} when is_list(ActualModule) -> - ActualModuleStr = string:join([atom_to_list(P) || - P <- ActualModule], ".") - end, + ActualModuleStr = + case ModInfo of + %% Typical module name, single atom + ActualModule when is_atom(ActualModule) -> + atom_to_list(ActualModule); + %% Packag-ized module name, list of atoms + ActualModule when is_list(ActualModule) -> + string:join([atom_to_list(P) || + P <- ActualModule], "."); + %% Parameterized module name, single atom + {ActualModule, _} when is_atom(ActualModule) -> + atom_to_list(ActualModule); + %% Parameterized and packagized module name, list of atoms + {ActualModule, _} when is_list(ActualModule) -> + string:join([atom_to_list(P) || + P <- ActualModule], ".") + end, inspect_epp(Epp, Source, ActualModuleStr, Includes); {ok, {attribute, 1, file, {Module, 1}}} -> inspect_epp(Epp, Source, Module, Includes); @@ -256,12 +245,14 @@ internal_erl_compile(Source, Config, Outdir, ErlOpts) -> case needs_compile(Source, Target, Hrls) of true -> Opts = [{outdir, filename:dirname(Target)}] ++ - ErlOpts ++ [{i, "include"}, report], + ErlOpts ++ [{i, "include"}, return], case compile:file(Source, Opts) of - {ok, _} -> + {ok, _Mod} -> ok; - _ -> - ?FAIL + {ok, _Mod, Ws} -> + rebar_base_compiler:ok_tuple(Source, Ws); + {error, Es, Ws} -> + rebar_base_compiler:error_tuple(Source, Es, Ws, Opts) end; false -> skipped @@ -282,7 +273,7 @@ compile_mib(Source, Target, Config) -> rebar_file_utils:mv(Hrl_filename, "include"), ok; {error, compilation_failed} -> - ?FAIL + ?ABORT end. -spec compile_xrl(Source::file:filename(), Target::file:filename(), @@ -302,11 +293,13 @@ compile_yrl(Source, Target, Config) -> compile_xrl_yrl(Source, Target, Opts, Mod) -> case needs_compile(Source, Target, []) of true -> - case Mod:file(Source, Opts) of + case Mod:file(Source, Opts ++ [{return, true}]) of {ok, _} -> ok; - _X -> - ?FAIL + {ok, _Mod, Ws} -> + rebar_base_compiler:ok_tuple(Source, Ws); + {error, Es, Ws} -> + rebar_base_compiler:error_tuple(Source, Es, Ws, Opts) end; false -> skipped @@ -317,11 +310,6 @@ gather_src([], Srcs) -> gather_src([Dir|Rest], Srcs) -> gather_src(Rest, Srcs ++ rebar_utils:find_files(Dir, ".*\\.erl\$")). --spec src_dirs(SrcDirs::[string()]) -> [file:filename(), ...]. -src_dirs([]) -> - ["src"]; -src_dirs(SrcDirs) -> - SrcDirs. -spec dirs(Dir::file:filename()) -> [file:filename()]. dirs(Dir) -> @@ -370,30 +358,6 @@ compile_priority(File) -> end. %% -%% Filter a list of erl_opts platform_define options such that only -%% those which match the provided architecture regex are returned. -%% --spec filter_defines(ErlOpts::list(), Acc::list()) -> list(). -filter_defines([], Acc) -> - lists:reverse(Acc); -filter_defines([{platform_define, ArchRegex, Key} | Rest], Acc) -> - case rebar_utils:is_arch(ArchRegex) of - true -> - filter_defines(Rest, [{d, Key} | Acc]); - false -> - filter_defines(Rest, Acc) - end; -filter_defines([{platform_define, ArchRegex, Key, Value} | Rest], Acc) -> - case rebar_utils:is_arch(ArchRegex) of - true -> - filter_defines(Rest, [{d, Key, Value} | Acc]); - false -> - filter_defines(Rest, Acc) - end; -filter_defines([Opt | Rest], Acc) -> - filter_defines(Rest, [Opt | Acc]). - -%% %% Ensure all files in a list are present and abort if one is missing %% -spec check_files(FileList::[file:filename()]) -> [file:filename()]. diff --git a/src/rebar_erlydtl_compiler.erl b/src/rebar_erlydtl_compiler.erl index 9c47a63..2a9cb63 100644 --- a/src/rebar_erlydtl_compiler.erl +++ b/src/rebar_erlydtl_compiler.erl @@ -120,7 +120,7 @@ compile_dtl(Source, Target, Config) -> " http://code.google.com/p/erlydtl/~n" " and install it into your erlang library dir~n" "===============================================~n~n", []), - ?FAIL; + ?ABORT; _ -> case needs_compile(Source, Target, Config) of true -> @@ -146,7 +146,7 @@ do_compile(Source, Target, Config) -> Reason -> ?ERROR("Compiling template ~s failed:~n ~p~n", [Source, Reason]), - ?FAIL + ?ABORT end. module_name(Target) -> diff --git a/src/rebar_escripter.erl b/src/rebar_escripter.erl index f7f45ba..b51a2a5 100644 --- a/src/rebar_escripter.erl +++ b/src/rebar_escripter.erl @@ -51,9 +51,14 @@ escriptize(Config, AppFile) -> InclBeams = get_app_beams( rebar_config:get_local(Config, escript_incl_apps, []), []), + %% Look for a list extra files to include in the output file. + %% For internal rebar-private use only. Do not use outside rebar. + InclExtra = get_extra(Config), + %% Construct the archive of everything in ebin/ dir -- put it on the %% top-level of the zip file so that code loading works properly. - Files = load_files("*", "ebin") ++ InclBeams, + Files = load_files("*", "ebin") ++ InclBeams ++ InclExtra, + case zip:create("mem", Files, [memory]) of {ok, {"mem", ZipBin}} -> %% Archive was successfully created. Prefix that binary with our @@ -69,17 +74,17 @@ escriptize(Config, AppFile) -> {error, WriteError} -> ?ERROR("Failed to write ~p script: ~p\n", [AppName, WriteError]), - ?FAIL + ?ABORT end; {error, ZipError} -> ?ERROR("Failed to construct ~p escript: ~p\n", [AppName, ZipError]), - ?FAIL + ?ABORT end, %% Finally, update executable perms for our script {ok, #file_info{mode = Mode}} = file:read_file_info(Filename), - ok = file:change_mode(Filename, Mode bor 8#00100), + ok = file:change_mode(Filename, Mode bor 8#00111), ok. clean(Config, AppFile) -> @@ -91,7 +96,6 @@ clean(Config, AppFile) -> Filename = rebar_config:get_local(Config, escript_name, AppName), rebar_file_utils:delete_each([Filename]). - %% =================================================================== %% Internal functions %% =================================================================== @@ -110,6 +114,12 @@ get_app_beams([App | Rest], Acc) -> get_app_beams(Rest, Acc2 ++ Acc) end. +get_extra(Config) -> + Extra = rebar_config:get_local(Config, escript_incl_extra, []), + lists:foldl(fun({Wildcard, Dir}, Files) -> + load_files(Wildcard, Dir) ++ Files + end, [], Extra). + load_files(Wildcard, Dir) -> [read_file(Filename, Dir) || Filename <- filelib:wildcard(Wildcard, Dir)]. diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl index b34ad84..b966985 100644 --- a/src/rebar_eunit.erl +++ b/src/rebar_eunit.erl @@ -43,7 +43,7 @@ %% The following Global options are supported: %% <ul> %% <li>verbose=1 - show extra output from the eunit test</li> -%% <li>suite="foo"" - runs test/foo_tests.erl</li> +%% <li>suites="foo,bar" - runs test/foo_tests.erl and test/bar_tests.erl</li> %% </ul> %% Additionally, for projects that have separate folders for the core %% implementation, and for the unit tests, then the following @@ -84,8 +84,16 @@ eunit(Config, _AppFile) -> %% Copy source files to eunit dir for cover in case they are not directly %% in src but in a subdirectory of src. Cover only looks in cwd and ../src - %% for source files. - SrcErls = rebar_utils:find_files("src", ".*\\.erl\$"), + %% for source files. Also copy files from src_dirs. + ErlOpts = rebar_utils:erl_opts(Config), + + SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)), + SrcErls = lists:foldl( + fun(Dir, Acc) -> + Files = rebar_utils:find_files(Dir, ".*\\.erl\$"), + lists:append(Acc, Files) + end, [], SrcDirs), + ?DEBUG("SrcErls: ~s\n", [SrcErls]), %% If it is not the first time rebar eunit is executed, there will be source %% files already present in ?EUNIT_DIR. Since some SCMs (like Perforce) set @@ -132,12 +140,14 @@ eunit(Config, _AppFile) -> ModuleBeamFiles = BeamFiles ++ OtherBeamFiles, Modules = [rebar_utils:beam_to_mod(?EUNIT_DIR, N) || N <- ModuleBeamFiles], SrcModules = [rebar_utils:erl_to_mod(M) || M <- SrcErls], + Suites = get_suites(), + FilteredModules = filtered_modules(Modules, Suites), {ok, CoverLog} = cover_init(Config, ModuleBeamFiles), StatusBefore = status_before_eunit(), - EunitResult = perform_eunit(Config, Modules), - perform_cover(Config, Modules, SrcModules), + EunitResult = perform_eunit(Config, FilteredModules), + perform_cover(Config, FilteredModules, SrcModules), cover_close(CoverLog), @@ -173,10 +183,16 @@ eunit_dir() -> ebin_dir() -> filename:join(rebar_utils:get_cwd(), "ebin"). -perform_eunit(Config, Modules) -> - %% suite defined, so only specify the module that relates to the - %% suite (if any). Suite can be a comma seperated list of modules to run. - Suite = rebar_config:get_global(suite, undefined), +get_suites() -> + Suites = rebar_utils:get_deprecated_global(suite, suites, [], "soon"), + [list_to_atom(Suite) || Suite <- string:tokens(Suites, ",")]. + +filtered_modules(Modules, []) -> + Modules; +filtered_modules(Modules, Suites) -> + [M || M <- Modules, lists:member(M, Suites)]. + +perform_eunit(Config, FilteredModules) -> EunitOpts = get_eunit_opts(Config), %% Move down into ?EUNIT_DIR while we run tests so any generated files @@ -184,19 +200,13 @@ perform_eunit(Config, Modules) -> Cwd = rebar_utils:get_cwd(), ok = file:set_cwd(?EUNIT_DIR), - EunitResult = perform_eunit(EunitOpts, Modules, Suite), + EunitResult = (catch eunit:test(FilteredModules, EunitOpts)), %% Return to original working dir ok = file:set_cwd(Cwd), EunitResult. -perform_eunit(EunitOpts, Modules, undefined) -> - (catch eunit:test(Modules, EunitOpts)); -perform_eunit(EunitOpts, _Modules, Suites) -> - (catch eunit:test([list_to_atom(Suite) || - Suite <- string:tokens(Suites, ",")], EunitOpts)). - get_eunit_opts(Config) -> %% Enable verbose in eunit if so requested.. BaseOpts = case rebar_config:is_verbose() of @@ -260,15 +270,7 @@ perform_cover(true, Config, BeamFiles, SrcModules) -> cover_analyze(_Config, [], _SrcModules) -> ok; -cover_analyze(Config, Modules, SrcModules) -> - %% suite can be a comma seperated list of modules to test - Suite = [list_to_atom(S) || - S <- string:tokens(rebar_config:get_global(suite, ""), ",")], - FilteredModules = case Suite of - [] -> Modules; - _ -> [M || M <- Modules, lists:member(M, Suite)] - end, - +cover_analyze(Config, FilteredModules, SrcModules) -> %% Generate coverage info for all the cover-compiled modules Coverage = lists:flatten([cover_analyze_mod(M) || M <- FilteredModules]), @@ -329,7 +331,7 @@ cover_init(true, BeamFiles) -> [] -> %% No modules compiled successfully...fail ?ERROR("Cover failed to compile any modules; aborting.~n", []), - ?FAIL; + ?ABORT; _ -> %% At least one module compiled successfully diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl index 2a782f0..51ba96e 100644 --- a/src/rebar_file_utils.erl +++ b/src/rebar_file_utils.erl @@ -57,6 +57,8 @@ rm_rf(Target) -> end. -spec cp_r(Sources::list(string()), Dest::file:filename()) -> ok. +cp_r([], _Dest) -> + ok; cp_r(Sources, Dest) -> case os:type() of {unix, _} -> @@ -106,7 +108,7 @@ delete_each([File | Rest]) -> delete_each(Rest); {error, Reason} -> ?ERROR("Failed to delete file ~s: ~p\n", [File, Reason]), - ?FAIL + ?ABORT end. %% =================================================================== diff --git a/src/rebar_lfe_compiler.erl b/src/rebar_lfe_compiler.erl index d2c2dfe..d688e9c 100644 --- a/src/rebar_lfe_compiler.erl +++ b/src/rebar_lfe_compiler.erl @@ -57,14 +57,16 @@ compile_lfe(Source, _Target, Config) -> " {git, \"git://github.com/rvirding/lfe\",~n" " {tag, \"v0.6.1\"}}}~n" "~n", []), - ?FAIL; + ?ABORT; _ -> - Opts = [{i, "include"}, {outdir, "ebin"}, report] + Opts = [{i, "include"}, {outdir, "ebin"}, return] ++ rebar_config:get_list(Config, erl_opts, []), case lfe_comp:file(Source, Opts) of - {ok, _} -> - ok; + {ok, _Mod, Ws} -> + rebar_base_compiler:ok_tuple(Source, Ws); + {error, Es, Ws} -> + rebar_base_compiler:error_tuple(Source, Es, Ws, Opts); _ -> - ?FAIL + ?ABORT end end. diff --git a/src/rebar_neotoma_compiler.erl b/src/rebar_neotoma_compiler.erl index 9bff892..d0f618f 100644 --- a/src/rebar_neotoma_compiler.erl +++ b/src/rebar_neotoma_compiler.erl @@ -80,7 +80,7 @@ compile_neo(Source, Target, Config) -> " https://github.com/seancribbs/neotoma~n" " and install it into your erlang library dir~n" "===============================================~n~n", []), - ?FAIL; + ?ABORT; _ -> case needs_compile(Source, Target, Config) of true -> @@ -104,7 +104,7 @@ do_compile(Source, _Target, Config) -> Reason -> ?ERROR("Compiling peg ~s failed:~n ~p~n", [Source, Reason]), - ?FAIL + ?ABORT end. needs_compile(Source, Target, Config) -> diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl index 89730a6..0b2e8be 100644 --- a/src/rebar_otp_app.erl +++ b/src/rebar_otp_app.erl @@ -146,12 +146,12 @@ validate_name(AppName, File) -> false -> ?ERROR("Invalid ~s: name of application (~p) " "must match filename.\n", [File, AppName]), - ?FAIL + ?ABORT end. validate_modules(AppName, undefined) -> ?ERROR("Missing modules declaration in ~p.app~n", [AppName]), - ?FAIL; + ?ABORT; validate_modules(AppName, Mods) -> %% Construct two sets -- one for the actual .beam files in ebin/ @@ -169,7 +169,7 @@ validate_modules(AppName, Mods) -> M <- MissingBeams]), ?ERROR("One or more modules listed in ~p.app are not " "present in ebin/*.beam:\n~s", [AppName, Msg1]), - ?FAIL + ?ABORT end, %% Identify .beam files NOT list in the .app, but present in ebin/ @@ -181,7 +181,7 @@ validate_modules(AppName, Mods) -> M <- MissingMods]), ?ERROR("One or more .beam files exist that are not " "listed in ~p.app:\n~s", [AppName, Msg2]), - ?FAIL + ?ABORT end. ebin_modules() -> diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl index 1f935de..0ccabc8 100644 --- a/src/rebar_port_compiler.erl +++ b/src/rebar_port_compiler.erl @@ -214,16 +214,30 @@ compile_each([Source | Rest], Type, Env, NewBins) -> Bin = replace_extension(Source, Ext, ".o"), case needs_compile(Source, Bin) of true -> - ?CONSOLE("Compiling ~s\n", [Source]), Template = select_compile_template(Type, compiler(Ext)), - rebar_utils:sh(expand_command(Template, Env, Source, Bin), - [{env, Env}]), + Cmd = expand_command(Template, Env, Source, Bin), + ShOpts = [{env, Env}, return_on_error, {use_stdout, false}], + exec_compiler(Source, Cmd, ShOpts), compile_each(Rest, Type, Env, [Bin | NewBins]); false -> ?INFO("Skipping ~s\n", [Source]), compile_each(Rest, Type, Env, NewBins) end. +exec_compiler(Source, Cmd, ShOpts) -> + case rebar_utils:sh(Cmd, ShOpts) of + {error, {_RC, RawError}} -> + AbsSource = filename:absname(Source), + ?CONSOLE("Compiling ~s\n", [AbsSource]), + Error = re:replace(RawError, Source, AbsSource, + [{return, list}, global]), + ?CONSOLE("~s", [Error]), + ?ABORT; + {ok, Output} -> + ?CONSOLE("Compiling ~s\n", [Source]), + ?CONSOLE("~s", [Output]) + end. + needs_compile(Source, Bin) -> %% TODO: Generate depends using gcc -MM so we can also %% check for include changes @@ -473,8 +487,7 @@ expand_keys_in_value([Key | Rest], Value, Vars) -> expand_command(TmplName, Env, InFiles, OutFile) -> Cmd0 = proplists:get_value(TmplName, Env), Cmd1 = rebar_utils:expand_env_variable(Cmd0, "PORT_IN_FILES", InFiles), - Cmd2 = rebar_utils:expand_env_variable(Cmd1, "PORT_OUT_FILE", OutFile), - re:replace(Cmd2, "\\\$\\w+|\\\${\\w+}", "", [global, {return, list}]). + rebar_utils:expand_env_variable(Cmd1, "PORT_OUT_FILE", OutFile). %% %% Given a string, determine if it is expandable diff --git a/src/rebar_protobuffs_compiler.erl b/src/rebar_protobuffs_compiler.erl index 249588c..ea34d4f 100644 --- a/src/rebar_protobuffs_compiler.erl +++ b/src/rebar_protobuffs_compiler.erl @@ -53,7 +53,7 @@ compile(_Config, _AppFile) -> false -> ?ERROR("Protobuffs library not present in code path!\n", []), - ?FAIL + ?ABORT end end. @@ -115,7 +115,7 @@ compile_each([{Proto, Beam, Hrl} | Rest]) -> Other -> ?ERROR("Protobuff compile of ~s failed: ~p\n", [Proto, Other]), - ?FAIL + ?ABORT end; false -> ok diff --git a/src/rebar_reltool.erl b/src/rebar_reltool.erl index 42c7f15..06411da 100644 --- a/src/rebar_reltool.erl +++ b/src/rebar_reltool.erl @@ -58,10 +58,10 @@ generate(Config, ReltoolFile) -> ok -> ok; {error, failed} -> - ?FAIL; + ?ABORT; Other2 -> ?ERROR("Unexpected error: ~p\n", [Other2]), - ?FAIL + ?ABORT end. overlay(_Config, ReltoolFile) -> @@ -150,7 +150,7 @@ load_vars_file(File) -> {ok, Terms} -> dict:from_list(Terms); {error, Reason} -> - ?ABORT("Unable to load overlay_vars from ~s: ~p\n", [File, Reason]) + ?ABORT("Unable to load overlay_vars from ~p: ~p\n", [File, Reason]) end. @@ -223,7 +223,7 @@ run_reltool(Server, _Config, ReltoolConfig) -> mk_target_dir(TargetDir) -> - case file:make_dir(TargetDir) of + case filelib:ensure_dir(filename:join(TargetDir, "dummy")) of ok -> ok; {error, eexist} -> @@ -235,8 +235,12 @@ mk_target_dir(TargetDir) -> _ -> ?ERROR("Release target directory ~p already exists!\n", [TargetDir]), - ?FAIL - end + ?ABORT + end; + {error, Reason} -> + ?ERROR("Failed to make target dir ~p: ~s\n", + [TargetDir, file:format_error(Reason)]), + ?ABORT end. @@ -255,7 +259,8 @@ dump_spec(Spec) -> execute_overlay([], _Vars, _BaseDir, _TargetDir) -> ok; execute_overlay([{mkdir, Out} | Rest], Vars, BaseDir, TargetDir) -> - OutFile = rebar_templater:render(filename:join([TargetDir, Out, "dummy"]), Vars), + OutFile = rebar_templater:render( + filename:join([TargetDir, Out, "dummy"]), Vars), ok = filelib:ensure_dir(OutFile), ?DEBUG("Created dir ~s\n", [filename:dirname(OutFile)]), execute_overlay(Rest, Vars, BaseDir, TargetDir); @@ -272,16 +277,19 @@ execute_overlay([{copy, In, Out} | Rest], Vars, BaseDir, TargetDir) -> end, rebar_file_utils:cp_r([InFile], OutFile), execute_overlay(Rest, Vars, BaseDir, TargetDir); -execute_overlay([{template_wildcard, Wildcard, OutDir} | Rest], Vars, BaseDir, TargetDir) -> +execute_overlay([{template_wildcard, Wildcard, OutDir} | Rest], Vars, + BaseDir, TargetDir) -> %% Generate a series of {template, In, Out} instructions from the wildcard %% that will get processed per normal Ifun = fun(F, Acc0) -> - [{template, F, filename:join(OutDir, filename:basename(F))} | Acc0] + [{template, F, + filename:join(OutDir, filename:basename(F))} | Acc0] end, NewInstrs = lists:foldl(Ifun, Rest, filelib:wildcard(Wildcard, BaseDir)), case length(NewInstrs) =:= length(Rest) of true -> - ?WARN("template_wildcard: ~s did not match any files!\n", [Wildcard]); + ?WARN("template_wildcard: ~s did not match any files!\n", + [Wildcard]); false -> ok end, @@ -318,7 +326,8 @@ execute_overlay([{replace, Out, Regex, Replacement, Opts} | Rest], Vars, BaseDir, TargetDir) -> Filename = rebar_templater:render(filename:join(TargetDir, Out), Vars), {ok, OrigData} = file:read_file(Filename), - Data = re:replace(OrigData, Regex, rebar_templater:render(Replacement, Vars), + Data = re:replace(OrigData, Regex, + rebar_templater:render(Replacement, Vars), [global, {return, binary}] ++ Opts), case file:write_file(Filename, Data) of ok -> @@ -337,9 +346,10 @@ apply_file_info(InFile, OutFile) -> create_RELEASES(TargetDir, RelName, RelVsn) -> ReleasesDir = filename:join(TargetDir, "releases"), - case release_handler:create_RELEASES(TargetDir, ReleasesDir, - filename:join([ReleasesDir, RelVsn, RelName ++ ".rel"]), - filename:join(TargetDir, "lib")) of + case release_handler:create_RELEASES( + TargetDir, ReleasesDir, + filename:join([ReleasesDir, RelVsn, RelName ++ ".rel"]), + filename:join(TargetDir, "lib")) of ok -> ok; {error, Reason} -> diff --git a/src/rebar_require_vsn.erl b/src/rebar_require_vsn.erl index a9991e9..327f75c 100644 --- a/src/rebar_require_vsn.erl +++ b/src/rebar_require_vsn.erl @@ -43,6 +43,10 @@ compile(Config, _) -> eunit(Config, _) -> check_versions(Config). +%% ==================================================================== +%% Internal functions +%% ==================================================================== + check_versions(Config) -> ErtsRegex = rebar_config:get(Config, require_erts_vsn, ".*"), ReOpts = [{capture, none}], diff --git a/src/rebar_shell.erl b/src/rebar_shell.erl new file mode 100644 index 0000000..aed7879 --- /dev/null +++ b/src/rebar_shell.erl @@ -0,0 +1,58 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et +%% ------------------------------------------------------------------- +%% +%% rebar: Erlang Build Tools +%% +%% Copyright (c) 2011 Trifork +%% +%% 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_shell). +-author("Kresten Krab Thorup <krab@trifork.com>"). + +-include("rebar.hrl"). + +-export([shell/2]). + +shell(_Config, _AppFile) -> + %% backwards way to say we only want this executed + %% for the "top level" directory + case is_deps_dir(rebar_utils:get_cwd()) of + false -> + true = code:add_pathz(ebin_dir()), + user_drv:start(), + %% this call never returns (until user quits shell) + shell:server(false, false); + true -> + ok + end, + ok. + +ebin_dir() -> + filename:join(rebar_utils:get_cwd(), "ebin"). + +is_deps_dir(Dir) -> + case lists:reverse(filename:split(Dir)) of + [_, "deps" | _] -> + true; + _V -> + false + end. diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl index f608512..603942a 100644 --- a/src/rebar_templater.erl +++ b/src/rebar_templater.erl @@ -62,10 +62,17 @@ %% Build a list of available templates AvailTemplates = find_disk_templates() ++ find_escript_templates(), ?CONSOLE("Available templates:\n", []), - _ = [begin - BaseName = filename:basename(F, ".template"), - ?CONSOLE("\t* ~s: ~s (~p)\n", [BaseName, F, Type]) - end || {Type, F} <- AvailTemplates], + lists:foreach( + fun({Type, F}) -> + BaseName = filename:basename(F, ".template"), + TemplateTerms = consult(load_file(Type, F)), + {_, VarList} = lists:keyfind(variables, 1, TemplateTerms), + Vars = lists:foldl(fun({V,_}, Acc) -> + [atom_to_list(V) | Acc] + end, [], VarList), + ?CONSOLE(" * ~s: ~s (~p) (variables: ~p)\n", + [BaseName, F, Type, string:join(Vars, ", ")]) + end, AvailTemplates), ok. @@ -258,7 +265,7 @@ update_vars([Key | Rest], Dict) -> %% -%% Given a string or binary, parse it into a list of terms, ala file:consult/0 +%% Given a string or binary, parse it into a list of terms, ala file:consult/1 %% consult(Str) when is_list(Str) -> consult([], Str, []); diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl index b01a35a..36348e7 100644 --- a/src/rebar_utils.erl +++ b/src/rebar_utils.erl @@ -31,24 +31,26 @@ get_arch/0, wordsize/0, sh/2, - find_files/2, - find_files/3, + find_files/2, find_files/3, now_str/0, ensure_dir/1, beam_to_mod/2, beams/1, erl_to_mod/1, - abort/2, + abort/0, abort/2, escript_foldl/3, find_executable/1, prop_check/3, expand_code_path/0, - deprecated/3, deprecated/4, expand_env_variable/3, vcs_vsn/2, - get_deprecated_global/3, + deprecated/3, deprecated/4, + get_deprecated_global/3, get_deprecated_global/4, get_deprecated_list/4, get_deprecated_list/5, get_deprecated_local/4, get_deprecated_local/5, - delayed_halt/1]). + delayed_halt/1, + erl_opts/1, + src_dirs/1 + ]). -include("rebar.hrl"). @@ -71,7 +73,8 @@ is_arch(ArchRegex) -> get_arch() -> Words = wordsize(), erlang:system_info(otp_release) ++ "-" - ++ erlang:system_info(system_architecture) ++ "-" ++ Words. + ++ erlang:system_info(system_architecture) ++ "-" ++ Words + ++ "-" ++ os_family(). wordsize() -> try erlang:system_info({wordsize, external}) of @@ -137,10 +140,14 @@ ensure_dir(Path) -> Error end. +-spec abort() -> no_return(). +abort() -> + throw(rebar_abort). + -spec abort(string(), [term()]) -> no_return(). abort(String, Args) -> ?ERROR(String, Args), - delayed_halt(1). + abort(). %% TODO: Rename emulate_escript_foldl to escript_foldl and remove %% this function when the time is right. escript:foldl/3 was an @@ -201,48 +208,15 @@ vcs_vsn(Vcs, Dir) -> VsnString end. -vcs_vsn_1(Vcs, Dir) -> - case vcs_vsn_cmd(Vcs) of - {unknown, VsnString} -> - ?DEBUG("vcs_vsn: Unknown VCS atom in vsn field: ~p\n", [Vcs]), - VsnString; - {cmd, CmdString} -> - vcs_vsn_invoke(CmdString, Dir); - Cmd -> - %% If there is a valid VCS directory in the application directory, - %% use that version info - Extension = lists:concat([".", Vcs]), - case filelib:is_dir(filename:join(Dir, Extension)) of - true -> - ?DEBUG("vcs_vsn: Primary vcs used for ~s\n", [Dir]), - vcs_vsn_invoke(Cmd, Dir); - false -> - %% No VCS directory found for the app. Depending on source - %% tree structure, there may be one higher up, but that can - %% yield unexpected results when used with deps. So, we - %% fallback to searching for a priv/vsn.Vcs file. - VsnFile = filename:join([Dir, "priv", "vsn" ++ Extension]), - case file:read_file(VsnFile) of - {ok, VsnBin} -> - ?DEBUG("vcs_vsn: Read ~s from priv/vsn.~p\n", - [VsnBin, Vcs]), - string:strip(binary_to_list(VsnBin), right, $\n); - {error, enoent} -> - ?DEBUG("vcs_vsn: Fallback to vcs for ~s\n", [Dir]), - vcs_vsn_invoke(Cmd, Dir) - end - end - end. - get_deprecated_global(OldOpt, NewOpt, When) -> get_deprecated_global(OldOpt, NewOpt, undefined, When). get_deprecated_global(OldOpt, NewOpt, Default, When) -> case rebar_config:get_global(NewOpt, Default) of - undefined -> + Default -> case rebar_config:get_global(OldOpt, Default) of - undefined -> - undefined; + Default -> + Default; Old -> deprecated(OldOpt, NewOpt, When), Old @@ -251,7 +225,6 @@ get_deprecated_global(OldOpt, NewOpt, Default, When) -> New end. - get_deprecated_list(Config, OldOpt, NewOpt, When) -> get_deprecated_list(Config, OldOpt, NewOpt, undefined, When). @@ -310,10 +283,34 @@ delayed_halt(Code) -> end end. +%% @doc Return list of erl_opts +-spec erl_opts(rebar_config:config()) -> list(). +erl_opts(Config) -> + RawErlOpts = filter_defines(rebar_config:get(Config, erl_opts, []), []), + GlobalDefines = [{d, list_to_atom(D)} || + D <- rebar_config:get_global(defines, [])], + Opts = GlobalDefines ++ RawErlOpts, + case proplists:is_defined(no_debug_info, Opts) of + true -> + [O || O <- Opts, O =/= no_debug_info]; + false -> + [debug_info|Opts] + end. + +-spec src_dirs(SrcDirs::[string()]) -> [file:filename(), ...]. +src_dirs([]) -> + ["src"]; +src_dirs(SrcDirs) -> + SrcDirs. + %% ==================================================================== %% Internal functions %% ==================================================================== +os_family() -> + {OsFamily, _} = os:type(), + atom_to_list(OsFamily). + get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) -> case Get(Config, NewOpt, Default) of Default -> @@ -333,10 +330,12 @@ get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) -> patch_on_windows(Cmd, Env) -> case os:type() of {win32,nt} -> - "cmd /q /c " + Cmd1 = "cmd /q /c " ++ lists:foldl(fun({Key, Value}, Acc) -> expand_env_variable(Acc, Key, Value) - end, Cmd, Env); + end, Cmd, Env), + %% Remove left-over vars + re:replace(Cmd1, "\\\$\\w+|\\\${\\w+}", "", [global, {return, list}]); _ -> Cmd end. @@ -422,6 +421,39 @@ emulate_escript_foldl(Fun, Acc, File) -> Error end. +vcs_vsn_1(Vcs, Dir) -> + case vcs_vsn_cmd(Vcs) of + {unknown, VsnString} -> + ?DEBUG("vcs_vsn: Unknown VCS atom in vsn field: ~p\n", [Vcs]), + VsnString; + {cmd, CmdString} -> + vcs_vsn_invoke(CmdString, Dir); + Cmd -> + %% If there is a valid VCS directory in the application directory, + %% use that version info + Extension = lists:concat([".", Vcs]), + case filelib:is_dir(filename:join(Dir, Extension)) of + true -> + ?DEBUG("vcs_vsn: Primary vcs used for ~s\n", [Dir]), + vcs_vsn_invoke(Cmd, Dir); + false -> + %% No VCS directory found for the app. Depending on source + %% tree structure, there may be one higher up, but that can + %% yield unexpected results when used with deps. So, we + %% fallback to searching for a priv/vsn.Vcs file. + VsnFile = filename:join([Dir, "priv", "vsn" ++ Extension]), + case file:read_file(VsnFile) of + {ok, VsnBin} -> + ?DEBUG("vcs_vsn: Read ~s from priv/vsn.~p\n", + [VsnBin, Vcs]), + string:strip(binary_to_list(VsnBin), right, $\n); + {error, enoent} -> + ?DEBUG("vcs_vsn: Fallback to vcs for ~s\n", [Dir]), + vcs_vsn_invoke(Cmd, Dir) + end + end + end. + vcs_vsn_cmd(git) -> %% git describe the last commit that touched CWD %% required for correct versioning of apps in subdirs, such as apps/app1 @@ -442,3 +474,27 @@ vcs_vsn_cmd(Version) -> {unknown, Version}. vcs_vsn_invoke(Cmd, Dir) -> {ok, VsnString} = rebar_utils:sh(Cmd, [{cd, Dir}, {use_stdout, false}]), string:strip(VsnString, right, $\n). + +%% +%% Filter a list of erl_opts platform_define options such that only +%% those which match the provided architecture regex are returned. +%% +-spec filter_defines(ErlOpts::list(), Acc::list()) -> list(). +filter_defines([], Acc) -> + lists:reverse(Acc); +filter_defines([{platform_define, ArchRegex, Key} | Rest], Acc) -> + case rebar_utils:is_arch(ArchRegex) of + true -> + filter_defines(Rest, [{d, Key} | Acc]); + false -> + filter_defines(Rest, Acc) + end; +filter_defines([{platform_define, ArchRegex, Key, Value} | Rest], Acc) -> + case rebar_utils:is_arch(ArchRegex) of + true -> + filter_defines(Rest, [{d, Key, Value} | Acc]); + false -> + filter_defines(Rest, Acc) + end; +filter_defines([Opt | Rest], Acc) -> + filter_defines(Rest, [Opt | Acc]). diff --git a/src/rebar_xref.erl b/src/rebar_xref.erl index 94103eb..73afdf9 100644 --- a/src/rebar_xref.erl +++ b/src/rebar_xref.erl @@ -90,7 +90,7 @@ xref(Config, _) -> case lists:member(false, [ExportsNoWarn, UndefNoWarn, QueryNoWarn]) of true -> - ?FAIL; + ?ABORT; false -> ok end. diff --git a/test/rebar_eunit_tests.erl b/test/rebar_eunit_tests.erl index 2b9c44e..72fb3ea 100644 --- a/test/rebar_eunit_tests.erl +++ b/test/rebar_eunit_tests.erl @@ -77,18 +77,21 @@ cover_with_suite_test_() -> setup, fun() -> setup_cover_project_with_suite(), - rebar("-v eunit suite=mysuite") + rebar("-v eunit suites=mysuite") end, fun teardown/1, - [{"All cover reports are generated", + [{"Cover reports are generated for module", assert_files_in("the temporary eunit directory", - expected_cover_generated_files())}, + [".eunit/index.html", + ".eunit/mysuite.COVER.html"])}, {"Only production modules get coverage reports", assert_files_not_in("the temporary eunit directory", - [".eunit/myapp_mymod_tests.COVER.html", - ".eunit/mysuite.COVER.html"])}]}. + [".eunit/myapp_app.COVER.html", + ".eunit/myapp_mymod.COVER.html", + ".eunit/myapp_sup.COVER.html", + ".eunit/myapp_mymod_tests.COVER.html"])}]}. expected_cover_generated_files() -> [".eunit/index.html", @@ -247,6 +250,5 @@ assert_full_coverage(Mod) -> Result = [X || X <- string:tokens(binary_to_list(F), "\n"), string:str(X, Mod) =/= 0, string:str(X, "100%") =/= 0], - ok = file:close(F), ?assert(length(Result) =:= 1) end. |