summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml10
-rw-r--r--Makefile22
-rw-r--r--README.md61
-rw-r--r--THANKS6
-rwxr-xr-xbootstrap48
-rw-r--r--dialyzer_reference2
-rw-r--r--ebin/rebar.app20
-rw-r--r--include/rebar.hrl2
-rw-r--r--inttest/t_custom_config/t_custom_config_rt.erl2
-rw-r--r--inttest/tplugins/tplugins_rt.erl2
-rw-r--r--priv/templates/simplenode.reltool.config8
-rw-r--r--rebar.config5
-rw-r--r--rebar.config.sample3
-rw-r--r--rebar.config.script20
-rw-r--r--src/rebar.erl38
-rw-r--r--src/rebar_abnfc_compiler.erl4
-rw-r--r--src/rebar_asn1_compiler.erl2
-rw-r--r--src/rebar_base_compiler.erl76
-rw-r--r--src/rebar_core.erl98
-rw-r--r--src/rebar_ct.erl26
-rw-r--r--src/rebar_deps.erl2
-rw-r--r--src/rebar_edoc.erl51
-rw-r--r--src/rebar_erlc_compiler.erl98
-rw-r--r--src/rebar_erlydtl_compiler.erl4
-rw-r--r--src/rebar_escripter.erl20
-rw-r--r--src/rebar_eunit.erl54
-rw-r--r--src/rebar_file_utils.erl4
-rw-r--r--src/rebar_lfe_compiler.erl12
-rw-r--r--src/rebar_neotoma_compiler.erl4
-rw-r--r--src/rebar_otp_app.erl8
-rw-r--r--src/rebar_port_compiler.erl23
-rw-r--r--src/rebar_protobuffs_compiler.erl4
-rw-r--r--src/rebar_reltool.erl38
-rw-r--r--src/rebar_require_vsn.erl4
-rw-r--r--src/rebar_shell.erl58
-rw-r--r--src/rebar_templater.erl17
-rw-r--r--src/rebar_utils.erl150
-rw-r--r--src/rebar_xref.erl2
-rw-r--r--test/rebar_eunit_tests.erl14
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"
diff --git a/Makefile b/Makefile
index 6f307c5..68f0f52 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/README.md b/README.md
index 74e3392..2bc7831 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/THANKS b/THANKS
index f38b7e6..d87e7c4 100644
--- a/THANKS
+++ b/THANKS
@@ -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
diff --git a/bootstrap b/bootstrap
index e86ad8e..fc6d1a8 100755
--- a/bootstrap
+++ b/bootstrap
@@ -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.