diff -Nru rebar-2.0.0/bootstrap rebar-2.6.0/bootstrap
--- rebar-2.0.0/bootstrap 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/bootstrap 2015-06-19 16:14:28.000000000 +0000
@@ -3,19 +3,28 @@
%% ex: ft=erlang ts=4 sw=4 et
main(Args) ->
+ case lists:member("--help", Args) of
+ true ->
+ usage(),
+ halt(0);
+ false ->
+ ok
+ end,
+
%% Get a string repr of build time
Built = build_time(),
%% Get a string repr of first matching VCS changeset
- VcsInfo = vcs_info([{hg, ".hg", "hg identify -i"},
- {git, ".git", "git describe --always"}]),
+ VcsInfo = vcs_info([{hg, ".hg", "hg identify -i", "hg status"},
+ {git, ".git", "git describe --always --tags",
+ "git status -s"}]),
%% Check for force=1 flag to force a rebuild
case lists:member("force=1", Args) of
true ->
rm("ebin/*.beam");
false ->
- rm("ebin/rebar_core.beam")
+ rm("ebin/rebar.beam")
end,
%% Add check for debug flag
@@ -27,10 +36,23 @@
%% Extract the system info of the version of OTP we use to compile rebar
OtpInfo = string:strip(erlang:system_info(otp_release), both, $\n),
+ %% Types dict:dict() and digraph:digraph() have been introduced in
+ %% Erlang 17.
+ %% At the same time, their counterparts dict() and digraph() are to be
+ %% deprecated in Erlang 18. namespaced_types option is used to select
+ %% proper type name depending on the OTP version used.
+ NamespacedTypes = case is_otp(OtpInfo, "^[0-9]+") of
+ true -> {d, namespaced_types};
+ false -> undefined
+ end,
+
%% Compile all src/*.erl to ebin
- case make:files(filelib:wildcard("src/*.erl"),
+ %% To not accidentally try to compile files like Mac OS X resource forks,
+ %% we only look for rebar source files that start with a letter.
+ case make:files(filelib:wildcard("src/[a-zA-Z]*.erl"),
[{outdir, "ebin"}, {i, "include"},
DebugFlag,
+ NamespacedTypes,
{d, 'BUILD_TIME', Built},
{d, 'VCS_INFO', VcsInfo},
{d, 'OTP_INFO', OtpInfo}]) of
@@ -53,35 +75,10 @@
%% 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
+ RebarArgs = Args -- ["debug"], %% Avoid trying to run 'debug' command
+ rebar:main(["compile", "escriptize"] ++ RebarArgs),
%% Finally, update executable perms for our script on *nix,
%% or write out script files on win32.
@@ -103,6 +100,17 @@
"Place this script anywhere in your path\n"
"and you can use rebar to build OTP-compliant apps.\n").
+usage() ->
+ io:format("Usage: bootstrap [OPTION]...~n"),
+ io:format(" force=1 unconditional build~n"),
+ io:format(" debug add debug information~n").
+
+is_otp(OtpInfo, Regex) ->
+ case re:run(OtpInfo, Regex, [{capture, none}]) of
+ match -> true;
+ nomatch -> false
+ end.
+
rm(Path) ->
NativePath = filename:nativename(Path),
Cmd = case os:type() of
@@ -113,24 +121,36 @@
ok.
build_time() ->
- {{Y, M, D}, {H, Min, S}} = calendar:now_to_universal_time(now()),
+ {{Y, M, D}, {H, Min, S}} = calendar:now_to_universal_time(rebar_now()),
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}.
+rebar_now() ->
+ case erlang:function_exported(erlang, timestamp, 0) of
+ true ->
+ erlang:timestamp();
+ false ->
+ %% erlang:now/0 was deprecated in 18.0, and as the escript has to
+ %% pass erl_lint:module/1 (even without -mode(compile)), we would
+ %% see a deprecation warning for erlang:now/0. One solution is to
+ %% use -compile({nowarn_deprecated_function, [{erlang, now, 0}]}),
+ %% but that would raise a warning in versions older than 18.0.
+ %% Calling erlang:now/0 via apply/3 avoids that.
+ apply(erlang, now, [])
+ end.
vcs_info([]) ->
"No VCS info available.";
-vcs_info([{Id, Dir, Cmd} | Rest]) ->
+vcs_info([{Id, Dir, VsnCmd, StatusCmd} | Rest]) ->
case filelib:is_dir(Dir) of
true ->
- lists:concat([Id, " ", string:strip(os:cmd(Cmd), both, $\n)]);
+ Vsn = string:strip(os:cmd(VsnCmd), both, $\n),
+ Status = case string:strip(os:cmd(StatusCmd), both, $\n) of
+ [] ->
+ "";
+ _ ->
+ "-dirty"
+ end,
+ lists:concat([Id, " ", Vsn, Status]);
false ->
vcs_info(Rest)
end.
diff -Nru rebar-2.0.0/CONTRIBUTING.md rebar-2.6.0/CONTRIBUTING.md
--- rebar-2.0.0/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/CONTRIBUTING.md 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,121 @@
+Contributing to rebar
+---------------------
+
+Before implementing a new feature, please submit a ticket to discuss your plans.
+The feature might have been rejected already, or the implementation might already be decided.
+
+See [Community and Resources](README.md#community-and-resources).
+
+Code style
+----------
+
+The following rules must be followed:
+ * Do not introduce trailing whitespace
+ * Do not mix spaces and tabs
+ * Do not introduce lines longer than 80 characters
+
+The following rules should be followed:
+ * Write small functions whenever possible
+ * Avoid having too many clauses containing clauses containing clauses.
+ Basically, avoid deeply nested functions.
+
+[erlang-mode (emacs)](http://www.erlang.org/doc/man/erlang.el.html)
+indentation is preferred. This will keep the code base consistent.
+vi users are encouraged to give [Vim emulation](http://emacswiki.org/emacs/Evil) ([more
+info](https://gitorious.org/evil/pages/Home)) a try.
+
+Pull requests and branching
+---------------------------
+
+Use one topic branch per pull request. If you do that, you can add extra commits or fix up
+buggy commits via `git rebase -i`, and update the branch. The updated branch will be
+visible in the same pull request. Therefore, you should not open a new pull request when
+you have to fix your changes.
+
+Do not commit to master in your fork.
+
+Provide a clean branch without merge commits.
+
+Tests
+-----
+
+As a general rule, any behavioral change to rebar requires a test to go with it. If there's
+already a test case, you may have to modify that one. If there isn't a test case or a test
+suite, add a new test case or suite in `inttest/`. [retest](https://github.com/dizzyd/retest) based tests are preferred, but
+we also have EUnit tests in `test/`.
+
+Say you've added a new test case in `inttest/erlc`. To only execute the modified suite,
+you would do the following:
+```sh
+# First we build rebar and its deps to also get `deps/retest/retest`
+$ make debug deps
+# Now we can test the modified erlc suite
+$ deps/retest/retest -v inttest/erlc
+```
+
+To test EUnit tests, you would do:
+```sh
+$ make debug
+$ ./rebar -v eunit
+```
+
+You can also run `make test` to execute both EUnit and [retest](https://github.com/dizzyd/retest) tests as `make check` does.
+
+Credit
+------
+
+To give everyone proper credit in addition to the git history, please feel free to append
+your name to `THANKS` in your first contribution.
+
+Committing your changes
+-----------------------
+
+Please ensure that all commits pass all tests, and do not have extra Dialyzer warnings.
+To do that, run `make check`. If you didn't build via `make debug` at first, the beam files in
+`ebin/` might be missing debug_info required for [xref](http://www.erlang.org/doc/man/xref.html)
+and [Dialyzer](http://www.erlang.org/doc/man/dialyzer.html), causing a test
+failure.
+If that happens, running `make clean` before running `make check` could solve the problem.
+
+#### Structuring your commits
+
+Fixing a bug is one commit.
+Adding a feature is one commit.
+Adding two features is two commits.
+Two unrelated changes is two commits.
+
+If you fix a (buggy) commit, squash (`git rebase -i`) the changes as a fixup commit into
+the original commit.
+
+#### Writing Commit Messages
+
+It's important to write a proper commit title and description. The commit title must be
+at most 50 characters; it is the first line of the commit text. The second line of the
+commit text must be left blank. The third line and beyond is the commit message. You
+should write a commit message. If you do, wrap all lines at 72 characters. You should
+explain what the commit does, what references you used, and any other information
+that helps understanding your changes.
+
+Basically, structure your commit message like this:
+
+
+One line summary (at most 50 characters)
+
+Longer description (wrap at 72 characters)
+
+
+##### Commit title/summary
+
+* At most 50 characters
+* What was changed
+* Imperative present tense (Fix, Add, Change)
+ * `Fix bug 123`
+ * `Add 'foobar' command`
+ * `Change default timeout to 123`
+* No period
+
+##### Commit description
+
+* Wrap at 72 characters
+* Why, explain intention and implementation approach
+* Present tense
diff -Nru rebar-2.0.0/debian/changelog rebar-2.6.0/debian/changelog
--- rebar-2.0.0/debian/changelog 2013-10-15 02:14:00.000000000 +0000
+++ rebar-2.6.0/debian/changelog 2016-03-12 09:03:18.000000000 +0000
@@ -1,18 +1,55 @@
-rebar (2.0.0-5) unstable; urgency=low
+rebar (2.6.0-2~14.04.1) trusty; urgency=medium
+ * backport to trusty
+
+ -- Richard Hansen Sat, 12 Mar 2016 02:28:30 -0500
+
+rebar (2.6.0-2) unstable; urgency=medium
+
+ * Fix build on arm64 with commad line option -m64. (Closes: #795932)
+ Add patches/fix-build-on-64bit-arch.patch.
+ * Update contorol file.
+ - Add erlang-syntax-tools to Depends. (Closes: #794223)
+ - Add Vcs-Git and Vcs-Browser field.
+
+ -- Nobuhiro Iwamatsu Thu, 03 Sep 2015 03:03:33 +0900
+
+rebar (2.6.0-1) unstable; urgency=medium
+
+ * New upstream released.
+ * Update debian/rules. (Closes: #790633)
+ - Disabled test. Test of rebar became necessary retest package.
+ However, this package is not yet. This is until the retest is installed on
+ Debian, to disable test.
+
+ -- Nobuhiro Iwamatsu Sat, 04 Jul 2015 03:25:04 +0900
+
+rebar (2.5.1-2) unstable; urgency=medium
+
+ * Upload to unstable.
+
+ -- Nobuhiro Iwamatsu Thu, 30 Apr 2015 06:38:58 +0900
+
+rebar (2.5.1-1) experimental; urgency=medium
+
+ * New upstream released.
* Update debian/control.
- Add erlang-dialyzer to Depends.
+ - Bump Standards-Version to 3.9.6.
+ - Update Homepage section to https://github.com/rebar/rebar.
+ - Add erlang-syntax-tools and erlang-eunit to Build-Depends.
+ * Update debian/copyright.
+ - Update Source section to https://github.com/rebar/rebar.git.
+ * Update debian/watch.
+ - Update URL to https://github.com/rebar/rebar.
- -- Nobuhiro Iwamatsu Tue, 15 Oct 2013 11:13:27 +0900
+ -- Nobuhiro Iwamatsu Wed, 14 Jan 2015 08:26:22 +0900
rebar (2.0.0-4) unstable; urgency=low
* Update debian/control.
- - Add erlang-dialyzer to Build-Depends.
- Fix FTBFS if built with Erlang R16B01.
- - Bump Standards-Version to 3.9.4.
+ - Dump Standards-Version to 3.9.4.
- -- Nobuhiro Iwamatsu Mon, 29 Jul 2013 09:59:58 +0900
+ -- Nobuhiro Iwamatsu Sun, 19 May 2013 03:55:27 +0900
rebar (2.0.0-3) unstable; urgency=low
diff -Nru rebar-2.0.0/debian/control rebar-2.6.0/debian/control
--- rebar-2.0.0/debian/control 2013-10-15 02:13:20.000000000 +0000
+++ rebar-2.6.0/debian/control 2015-09-02 18:16:42.000000000 +0000
@@ -3,9 +3,12 @@
Uploaders: Nobuhiro Iwamatsu
Section: devel
Priority: optional
-Standards-Version: 3.9.4
-Homepage: https://github.com/basho/rebar
-Build-Depends: debhelper (>= 9), erlang-dev, erlang-tools, erlang-dialyzer
+Build-Depends: debhelper (>= 9), erlang-dev, erlang-tools, erlang-syntax-tools,
+ erlang-eunit
+Standards-Version: 3.9.6
+Homepage: https://github.com/rebar/rebar
+Vcs-Git: git://anonscm.debian.org/pkg-leofs/rebar.git
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-leofs/rebar.git;a=summary
Package: rebar
Architecture: any
@@ -13,7 +16,7 @@
Priority: optional
Depends: ${misc:Depends}, ${shlibs:Depends},
erlang-base | erlang-base-hipe,
- erlang-dev, erlang-tools, erlang-dialyzer
+ erlang-dev, erlang-tools, erlang-syntax-tools
Recommends: git, mercurial
Enhances: erlang
Description: Sophisticated build-tool for Erlang projects that follows OTP principles
diff -Nru rebar-2.0.0/debian/copyright rebar-2.6.0/debian/copyright
--- rebar-2.0.0/debian/copyright 2013-07-29 00:50:04.000000000 +0000
+++ rebar-2.6.0/debian/copyright 2015-01-14 00:19:33.000000000 +0000
@@ -1,7 +1,7 @@
Format: Format: http://dep.debian.net/deps/dep5
Name: rebar
Maintainer: Nobuhiro Iwamatsu
-Source: https://github.com/basho/rebar
+Source: https://github.com/rebar/rebar.git
Files: src/getopt.erl
Copyright: Juan Jose Comellas
diff -Nru rebar-2.0.0/debian/patches/Add-build-target-to-Makefile.patch rebar-2.6.0/debian/patches/Add-build-target-to-Makefile.patch
--- rebar-2.0.0/debian/patches/Add-build-target-to-Makefile.patch 2013-07-29 00:50:04.000000000 +0000
+++ rebar-2.6.0/debian/patches/Add-build-target-to-Makefile.patch 2015-07-13 19:11:28.000000000 +0000
@@ -1,49 +1,35 @@
-From e815298b6abff3ac1cf58c360e03ee9a849a9614 Mon Sep 17 00:00:00 2001
+From 398c3174cf5d5709816093c51e94e7afd3c9c103 Mon Sep 17 00:00:00 2001
From: Nobuhiro Iwamatsu
-Date: Mon, 16 Jul 2012 01:56:58 +0900
+Date: Wed, 14 Jan 2015 08:38:20 +0900
Subject: [PATCH] Add build target to Makefile
Signed-off-by: Nobuhiro Iwamatsu
---
- Makefile | 15 +++++++++++----
- 1 file changed, 11 insertions(+), 4 deletions(-)
+ Makefile | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
-index 1fda878..b11dccf 100644
+index d0d16f8..db23420 100644
--- a/Makefile
+++ b/Makefile
-@@ -1,6 +1,10 @@
--.PHONY: dialyzer_warnings xref_warnings
-+.PHONY: all build clean install
+@@ -1,7 +1,7 @@
+-.PHONY: clean xref_warnings deps test test_eunit test_inttest
++.PHONY: clean xref_warnings deps test test_eunit test_inttest all build install
--all:
-+all: build
-+
-+build: bootstrap
-+
-+bootstrap:
- ./bootstrap
-
- clean:
-@@ -9,7 +13,7 @@ clean:
- debug:
- @./bootstrap debug
+-REBAR=$(PWD)/rebar
+-RETEST=$(PWD)/deps/retest/retest
++REBAR=$(CURDIR)/rebar
++RETEST=$(CURDIR)/deps/retest/retest
+ LOG_LEVEL?=debug
+ RT_TARGETS?=inttest
--check: debug xref dialyzer
-+check: debug # xref dialyzer
+@@ -33,6 +33,9 @@ binary: clean all
+ @cp rebar ../rebar.wiki/rebar
+ (cd ../rebar.wiki && git commit -m "Update $(VSN)" rebar)
- xref:
- @./rebar xref
-@@ -24,4 +28,7 @@ dialyzer_warnings:
- binary: VSN = $(shell ./rebar -V)
- binary: clean all
- cp rebar ../rebar.wiki/rebar
-- (cd ../rebar.wiki && git commit -m "Update $(VSN)" rebar)
-\ No newline at end of file
-+ (cd ../rebar.wiki && git commit -m "Update $(VSN)" rebar)
-+
-+install: build
++install: all
+ install -D -m 755 ./rebar $(DESTDIR)/usr/bin/rebar
---
-1.7.10.4
-
++
+ deps:
+ @REBAR_EXTRA_DEPS=1 $(REBAR) get-deps
+ @(cd deps/retest && $(REBAR) compile escriptize)
diff -Nru rebar-2.0.0/debian/patches/fix-build-on-64bit-arch.patch rebar-2.6.0/debian/patches/fix-build-on-64bit-arch.patch
--- rebar-2.0.0/debian/patches/fix-build-on-64bit-arch.patch 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/debian/patches/fix-build-on-64bit-arch.patch 2015-09-02 18:09:23.000000000 +0000
@@ -0,0 +1,23 @@
+Description: Fix build on arm64 with commad line option -m64
+Author: Christopher S. Meiklejohn
+Bug: https://github.com/rebar/rebar/pull/459
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=795932
+Last-Update: 2015-09-03
+ ---
+
+diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl
+index 5855589..037567a 100644
+--- a/src/rebar_port_compiler.erl
++++ b/src/rebar_port_compiler.erl
+@@ -604,11 +604,6 @@ default_env() ->
+ {"solaris.*-64$", "CXXFLAGS", "-D_REENTRANT -m64 $CXXFLAGS"},
+ {"solaris.*-64$", "LDFLAGS", "-m64 $LDFLAGS"},
+
+- %% Linux specific flags for multiarch
+- {"linux.*-64$", "CFLAGS", "-m64 $CFLAGS"},
+- {"linux.*-64$", "CXXFLAGS", "-m64 $CXXFLAGS"},
+- {"linux.*-64$", "LDFLAGS", "$LDFLAGS"},
+-
+ %% OS X Leopard flags for 64-bit
+ {"darwin9.*-64$", "CFLAGS", "-m64 $CFLAGS"},
+ {"darwin9.*-64$", "CXXFLAGS", "-m64 $CXXFLAGS"},
diff -Nru rebar-2.0.0/debian/patches/series rebar-2.6.0/debian/patches/series
--- rebar-2.0.0/debian/patches/series 2013-07-29 00:50:04.000000000 +0000
+++ rebar-2.6.0/debian/patches/series 2015-09-02 18:03:04.000000000 +0000
@@ -1 +1,2 @@
Add-build-target-to-Makefile.patch
+fix-build-on-64bit-arch.patch
diff -Nru rebar-2.0.0/debian/rules rebar-2.6.0/debian/rules
--- rebar-2.0.0/debian/rules 2013-07-29 00:50:04.000000000 +0000
+++ rebar-2.6.0/debian/rules 2015-07-13 19:13:21.000000000 +0000
@@ -2,3 +2,5 @@
%:
dh $@
+
+override_dh_auto_test:
diff -Nru rebar-2.0.0/debian/watch rebar-2.6.0/debian/watch
--- rebar-2.0.0/debian/watch 2013-07-29 00:50:04.000000000 +0000
+++ rebar-2.6.0/debian/watch 2015-01-14 00:20:21.000000000 +0000
@@ -1,4 +1,4 @@
version=3
opts=uversionmangle=s/_/./g;s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|b|a)[\-\.]?\d*)$/$1~$2/ \
- https://github.com/basho/rebar/tags .*[^n]/(?:v||release-|rebar[_\-])(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz))
+ https://https://github.com/rebar/rebar/tags .*[^n]/(?:v||release-|rebar[_\-])(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz))
# Bart Martens Tue, 15 Jan 2013 20:52:43 +0000
diff -Nru rebar-2.0.0/dialyzer_reference rebar-2.6.0/dialyzer_reference
--- rebar-2.0.0/dialyzer_reference 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/dialyzer_reference 1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-
-rebar_utils.erl:154: Call to missing or unexported function escript:foldl/3
diff -Nru rebar-2.0.0/ebin/rebar.app rebar-2.6.0/ebin/rebar.app
--- rebar-2.0.0/ebin/rebar.app 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/ebin/rebar.app 2015-06-19 16:14:28.000000000 +0000
@@ -3,50 +3,70 @@
{application, rebar,
[{description, "Rebar: Erlang Build Tool"},
- {vsn, "2.0.0"},
+ {vsn, "2.6.0"},
{modules, [ rebar,
rebar_abnfc_compiler,
- rebar_appups,
rebar_app_utils,
+ rebar_appups,
+ rebar_asn1_compiler,
+ rebar_dia_compiler,
rebar_base_compiler,
+ rebar_cleaner,
rebar_config,
rebar_core,
- rebar_cleaner,
+ rebar_cover_utils,
rebar_ct,
rebar_deps,
- rebar_asn1_compiler,
+ rebar_dialyzer,
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_otp_appup,
rebar_port_compiler,
+ rebar_proto_compiler,
rebar_protobuffs_compiler,
- rebar_neotoma_compiler,
+ rebar_proto_gpb_compiler,
+ rebar_qc,
rebar_rel_utils,
rebar_reltool,
rebar_require_vsn,
+ rebar_shell,
rebar_subdirs,
rebar_templater,
rebar_upgrade,
rebar_utils,
rebar_xref,
- getopt,
- mustache ]},
+ rebar_metacmds,
+ rebar_getopt,
+ rebar_mustache,
+ rmemo ]},
{registered, []},
- {applications, [kernel,
- stdlib,
- sasl]},
+ {applications,
+ [
+ kernel,
+ stdlib,
+ sasl,
+ compiler,
+ crypto,
+ syntax_tools,
+ tools,
+ eunit,
+ reltool,
+ dialyzer,
+ asn1,
+ snmp,
+ edoc
+ ]},
{env, [
%% Default log level
- {log_level, error},
-
- %% Default parallel jobs
- {jobs, 3},
+ {log_level, warn},
%% any_dir processing modules
{any_dir_modules, [
@@ -61,19 +81,27 @@
{modules, [
{app_dir, [
rebar_abnfc_compiler,
+ rebar_proto_compiler,
rebar_protobuffs_compiler,
+ rebar_proto_gpb_compiler,
rebar_neotoma_compiler,
rebar_asn1_compiler,
+ rebar_dia_compiler,
+ rebar_dialyzer,
rebar_erlc_compiler,
rebar_lfe_compiler,
rebar_erlydtl_compiler,
rebar_port_compiler,
rebar_otp_app,
+ rebar_otp_appup,
rebar_ct,
rebar_eunit,
+ rebar_qc,
rebar_escripter,
rebar_edoc,
- rebar_xref
+ rebar_shell,
+ rebar_xref,
+ rebar_metacmds
]},
{rel_dir, [
@@ -81,6 +109,14 @@
rebar_reltool,
rebar_upgrade
]}
- ]}
+ ]},
+ {recursive_cmds, [
+ 'check-deps',
+ compile,
+ 'delete-deps',
+ 'get-deps',
+ 'list-deps',
+ 'update-deps'
+ ]}
]}
]}.
diff -Nru rebar-2.0.0/.gitignore rebar-2.6.0/.gitignore
--- rebar-2.0.0/.gitignore 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/.gitignore 2015-06-19 16:14:28.000000000 +0000
@@ -1,12 +1,11 @@
-*.beam
-rebar
+/ebin/*.beam
+/rebar
*~
*.orig
.*.swp
-rt.work
-.hgignore
-.eunit
-dialyzer_warnings
-xref_warnings
-rebar.cmd
-rebar.ps1
+/rt.work
+/rebar.cmd
+/.eunit
+/deps
+/.rebar
+env
diff -Nru rebar-2.0.0/.hgignore rebar-2.6.0/.hgignore
--- rebar-2.0.0/.hgignore 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/.hgignore 1970-01-01 00:00:00.000000000 +0000
@@ -1,7 +0,0 @@
-\.beam
-^rebar$
-.~
-\.orig
-\.swp
-rt.work/*
-^.gitignore$
diff -Nru rebar-2.0.0/.hgtags rebar-2.6.0/.hgtags
--- rebar-2.0.0/.hgtags 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/.hgtags 1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-e8747041ef63f1b394d3b156c72c5bc12e92ecc4 RELEASE-1
diff -Nru rebar-2.0.0/include/rebar.hrl rebar-2.6.0/include/rebar.hrl
--- rebar-2.0.0/include/rebar.hrl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/include/rebar.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -1,5 +1,7 @@
--define(FAIL, throw({error, failed})).
-
+%% TODO: rename FAIL to ABORT once we require at least R13B04 for
+%% building rebar. Macros with different arity were not supported by the
+%% compiler before 13B04.
+-define(FAIL, rebar_utils:abort()).
-define(ABORT(Str, Args), rebar_utils:abort(Str, Args)).
-define(CONSOLE(Str, Args), io:format(Str, Args)).
@@ -7,6 +9,6 @@
-define(DEBUG(Str, Args), rebar_log:log(debug, Str, Args)).
-define(INFO(Str, Args), rebar_log:log(info, Str, Args)).
-define(WARN(Str, Args), rebar_log:log(warn, Str, Args)).
--define(ERROR(Str, Args), rebar_log:log(error, Str, Args)).
+-define(ERROR(Str, Args), rebar_log:log(standard_error, error, Str, Args)).
-define(FMT(Str, Args), lists:flatten(io_lib:format(Str, Args))).
diff -Nru rebar-2.0.0/inttest/app_src/app_src.erl rebar-2.6.0/inttest/app_src/app_src.erl
--- rebar-2.0.0/inttest/app_src/app_src.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/app_src/app_src.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(app_src).
+
+-compile(export_all).
+
+test() ->
+ ok.
diff -Nru rebar-2.0.0/inttest/app_src/app_src_rt.erl rebar-2.6.0/inttest/app_src/app_src_rt.erl
--- rebar-2.0.0/inttest/app_src/app_src_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/app_src/app_src_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,78 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Vlad Dumitrescu
+%%
+%% 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(app_src_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {create, "src/app_src.app.src", app(app_src)}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ LineRegexp = "DEBUG: Consult config file .*/app_src\.app\.src.*",
+ ?assertEqual(true, has_line(Output, LineRegexp)),
+ retest_log:log(debug, "Evaluated .app.src.script~n", []),
+
+ %% check that ebin/app_src.app exists
+ ?assertMatch(true, filelib:is_regular("ebin/app_src.app")),
+ retest_log:log(debug, "Generated ebin/.app~n", []),
+
+ %% check that ebin/.app has vsn="2"
+ {ok, Bin} = file:read_file("ebin/app_src.app"),
+ Str = binary_to_list(Bin),
+ ?assertMatch({match, _}, re:run(Str, "{vsn, *\"2\"}")),
+ retest_log:log(debug, "Variable replacement in .app is ok.~n", []),
+
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
+
+%%
+%% Generate the contents of a simple .app.src file
+%%
+app(Name) ->
+ "{application, " ++ atom_to_list(Name) ++ ",
+ [{vsn, \"2\"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.\n".
diff -Nru rebar-2.0.0/inttest/app_src_script/app_src_script.erl rebar-2.6.0/inttest/app_src_script/app_src_script.erl
--- rebar-2.0.0/inttest/app_src_script/app_src_script.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/app_src_script/app_src_script.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(app_src_script).
+
+-compile(export_all).
+
+test() ->
+ ok.
diff -Nru rebar-2.0.0/inttest/app_src_script/app_src_script_rt.erl rebar-2.6.0/inttest/app_src_script/app_src_script_rt.erl
--- rebar-2.0.0/inttest/app_src_script/app_src_script_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/app_src_script/app_src_script_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,83 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Vlad Dumitrescu
+%%
+%% 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(app_src_script_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {create, "src/app_src_script.app.src.script", app_script(app_src_script)}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ Regexp = "DEBUG: Evaluating config script .*/app_src_script\.app\.src\.script.*",
+ ?assertEqual(true, has_line(Output, Regexp)),
+ retest_log:log(debug, "Evaluated .app.src.script~n", []),
+
+ %% check that ebin/app_src.app exists
+ ?assertMatch(true, filelib:is_regular("ebin/app_src_script.app")),
+ retest_log:log(debug, "Generated ebin/.app~n", []),
+
+ %% check that ebin/.app has vsn="2"
+ {ok, Bin} = file:read_file("ebin/app_src_script.app"),
+ Str = binary_to_list(Bin),
+ ?assertMatch({match, _}, re:run(Str, "{vsn, *\"2\"}")),
+ retest_log:log(debug, "Variable replacement in .app is ok.~n", []),
+
+ %% check that ebin/.app doesn't have foo=ok
+ ?assertMatch(nomatch, re:run(Str, "{foo, *ok}")),
+ retest_log:log(debug, "app.src hasn't 'foo' config.~n", []),
+
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
+
+%%
+%% Generate the contents of a simple .app.src.script file
+%%
+app_script(Name) ->
+ "Vsn=\"2\".\n" ++
+ "{application, " ++ atom_to_list(Name) ++ ",
+ [{vsn, Vsn},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.\n".
diff -Nru rebar-2.0.0/inttest/app_src_script_2/app_src_script_2.erl rebar-2.6.0/inttest/app_src_script_2/app_src_script_2.erl
--- rebar-2.0.0/inttest/app_src_script_2/app_src_script_2.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/app_src_script_2/app_src_script_2.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(app_src_script_2).
+
+-compile(export_all).
+
+test() ->
+ ok.
diff -Nru rebar-2.0.0/inttest/app_src_script_2/app_src_script_2_rt.erl rebar-2.6.0/inttest/app_src_script_2/app_src_script_2_rt.erl
--- rebar-2.0.0/inttest/app_src_script_2/app_src_script_2_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/app_src_script_2/app_src_script_2_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,93 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Vlad Dumitrescu
+%%
+%% 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(app_src_script_2_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {create, "src/app_src_script_2.app.src.script", app_script(app_src_script_2)},
+ {create, "src/app_src_script_2.app.src", app(app_src_script_2)}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ Regexp = "DEBUG: Evaluating config script .*/app_src_script_2\.app\.src\.script.*",
+ ?assertEqual(true, has_line(Output, Regexp)),
+ retest_log:log(debug, "Evaluated .app.src.script~n", []),
+
+ %% check that ebin/app_src.app exists
+ ?assertMatch(true, filelib:is_regular("ebin/app_src_script_2.app")),
+ retest_log:log(debug, "Generated ebin/.app~n", []),
+
+ %% check that ebin/.app has vsn="2" (as in .script)
+ {ok, Bin} = file:read_file("ebin/app_src_script_2.app"),
+ Str = binary_to_list(Bin),
+ retest_log:log(debug, "app=~p~n", [Str]),
+ ?assertMatch({match, _}, re:run(Str, "{vsn, *\"2\"}")),
+ retest_log:log(debug, "app.src has version from script.~n", []),
+
+ %% check that ebin/.app has foo=ok (from .src)
+ ?assertMatch({match, _}, re:run(Str, "{foo, *ok}")),
+ retest_log:log(debug, "app.src has 'foo' config from .src.~n", []),
+
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
+
+%%
+%% Generate the contents of a simple .app.src.script file
+%%
+app_script(Name) ->
+ "[{application," ++ atom_to_list(Name) ++ ",Cfg}] = CONFIG,
+ [{application," ++ atom_to_list(Name) ++ ",lists:keyreplace(vsn, 1, Cfg,
+ {vsn, \"2\"})}].".
+
+%%
+%% Generate the contents of a simple .app.src file
+%%
+app(Name) ->
+ "{application, " ++ atom_to_list(Name) ++ ",
+ [{vsn, \"3\"},
+ {foo, ok},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.\n".
diff -Nru rebar-2.0.0/inttest/appup_src/appup_src_rt.erl rebar-2.6.0/inttest/appup_src/appup_src_rt.erl
--- rebar-2.0.0/inttest/appup_src/appup_src_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src/appup_src_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,67 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 Luis Rascao (luis.rascao@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(appup_src_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {copy, "src", "src"}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ LineRegexp = "Compiled src/app\.appup\.src",
+ ?assertEqual(true, has_line(Output, LineRegexp)),
+
+ %% check that ebin/app.appup exists
+ ?assertMatch(true, filelib:is_regular("ebin/app.appup")),
+ retest_log:log(debug, "Generated ebin/app.appup~n", []),
+
+ %% check that ebin/app.appup has expected version
+ {ok, [{AppVersion, [{UpgradeFrom, _} | _UpgradeFromRest], [{DowngradeTo, _} | _DowngradeToRest]}]} =
+ file:consult("ebin/app.appup"),
+ ?assertEqual(AppVersion, "%VSN%"),
+ ?assertEqual(UpgradeFrom, "1.3"),
+ ?assertEqual(DowngradeTo, "1.3"),
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
diff -Nru rebar-2.0.0/inttest/appup_src/src/app.app.src rebar-2.6.0/inttest/appup_src/src/app.app.src
--- rebar-2.0.0/inttest/appup_src/src/app.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src/src/app.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,5 @@
+{application, app,
+ [{vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff -Nru rebar-2.0.0/inttest/appup_src/src/app.appup.src rebar-2.6.0/inttest/appup_src/src/app.appup.src
--- rebar-2.0.0/inttest/appup_src/src/app.appup.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src/src/app.appup.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,162 @@
+{"%VSN%",
+ [
+ {"1.3",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {add_module, asn1rt_per_bin},
+ {add_module, asn1rt_check},
+ {add_module, asn1rt_per_bin_rt2ct},
+ {add_module, asn1rt_ber_bin_v2},
+ {add_module, asn1rt_driver_handler},
+ {remove, {asn1rt_ber_v1, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.1",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {add_module, asn1rt_per_bin},
+ {add_module, asn1rt_check},
+ {add_module, asn1rt_per_bin_rt2ct},
+ {add_module, asn1rt_ber_bin_v2},
+ {add_module, asn1rt_driver_handler},
+ {remove, {asn1rt_ber_v1, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.1.1",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {add_module, asn1rt_per_bin},
+ {add_module, asn1rt_check},
+ {add_module, asn1rt_per_bin_rt2ct},
+ {add_module, asn1rt_ber_bin_v2},
+ {add_module, asn1rt_driver_handler},
+ {remove, {asn1rt_ber_v1, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.2",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt_check, soft_purge, soft_purge, []},
+ {add_module, asn1rt_per_bin_rt2ct},
+ {add_module, asn1rt_ber_bin_v2},
+ {add_module, asn1rt_driver_handler},
+ {remove, {asn1rt_ber_v1, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.3",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt_check, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin_rt2ct, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_bin_v2},
+ {add_module, asn1rt_driver_handler},
+ {remove, {asn1rt_ber_v1, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.3.1",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt_check, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin_rt2ct, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_bin_v2},
+ {add_module, asn1rt_driver_handler},
+ {remove, {asn1rt_ber_v1, soft_purge, soft_purge}}
+ ]
+ }
+ ],
+ [
+ {"1.3",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_v1},
+ {remove, {asn1rt_per_bin, soft_purge, soft_purge}},
+ {remove, {asn1rt_check, soft_purge, soft_purge}},
+ {remove, {asn1rt_per_bin_rt2ct, soft_purge, soft_purge}},
+ {remove, {asn1rt_ber_bin_v2, soft_purge, soft_purge}},
+ {remove, {asn1rt_driver_handler, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.1",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_v1},
+ {remove, {asn1rt_per_bin, soft_purge, soft_purge}},
+ {remove, {asn1rt_check, soft_purge, soft_purge}},
+ {remove, {asn1rt_per_bin_rt2ct, soft_purge, soft_purge}},
+ {remove, {asn1rt_ber_bin_v2, soft_purge, soft_purge}},
+ {remove, {asn1rt_driver_handler, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.1.1",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_v1},
+ {remove, {asn1rt_per_bin, soft_purge, soft_purge}},
+ {remove, {asn1rt_check, soft_purge, soft_purge}},
+ {remove, {asn1rt_per_bin_rt2ct, soft_purge, soft_purge}},
+ {remove, {asn1rt_ber_bin_v2, soft_purge, soft_purge}},
+ {remove, {asn1rt_driver_handler, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.2",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt_check, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_v1},
+ {remove, {asn1rt_per_bin_rt2ct, soft_purge, soft_purge}},
+ {remove, {asn1rt_ber_bin_v2, soft_purge, soft_purge}},
+ {remove, {asn1rt_driver_handler, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.3",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt_check, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin_rt2ct, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_v1},
+ {remove, {asn1rt_ber_bin_v2, soft_purge, soft_purge}},
+ {remove, {asn1rt_driver_handler, soft_purge, soft_purge}}
+ ]
+ },
+ {"1.3.3.1",
+ [
+ {load_module, asn1rt_per_v1, soft_purge, soft_purge, []},
+ {load_module, asn1rt_ber_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin, soft_purge, soft_purge, []},
+ {load_module, asn1rt_check, soft_purge, soft_purge, []},
+ {load_module, asn1rt_per_bin_rt2ct, soft_purge, soft_purge, []},
+ {add_module, asn1rt_ber_v1},
+ {remove, {asn1rt_ber_bin_v2, soft_purge, soft_purge}},
+ {remove, {asn1rt_driver_handler, soft_purge, soft_purge}}
+ ]
+ }
+
+ ]}.
diff -Nru rebar-2.0.0/inttest/appup_src/src/appup_src.erl rebar-2.6.0/inttest/appup_src/src/appup_src.erl
--- rebar-2.0.0/inttest/appup_src/src/appup_src.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src/src/appup_src.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(appup_src).
+
+-compile(export_all).
+
+test() ->
+ ok.
diff -Nru rebar-2.0.0/inttest/appup_src_2/appup_src_2_rt.erl rebar-2.6.0/inttest/appup_src_2/appup_src_2_rt.erl
--- rebar-2.0.0/inttest/appup_src_2/appup_src_2_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_2/appup_src_2_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,65 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 Luis Rascao (luis.rascao@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(appup_src_2_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {copy, "src", "src"}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ LineRegexp = "Compiled src/app\.appup\.src",
+ ?assertEqual(true, has_line(Output, LineRegexp)),
+
+ %% check that ebin/app.appup exists
+ ?assertMatch(true, filelib:is_regular("ebin/app.appup")),
+ retest_log:log(debug, "Generated ebin/app.appup~n", []),
+
+ %% check that ebin/app.appup has expected version
+ {ok, [{AppVersion, [], []}]} =
+ file:consult("ebin/app.appup"),
+ ?assertEqual(AppVersion, "1.24"),
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
diff -Nru rebar-2.0.0/inttest/appup_src_2/appup_src_rt_2.erl rebar-2.6.0/inttest/appup_src_2/appup_src_rt_2.erl
--- rebar-2.0.0/inttest/appup_src_2/appup_src_rt_2.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_2/appup_src_rt_2.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,67 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 Luis Rascao (luis.rascao@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(appup_src_rt_2).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {copy, "src", "src"}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ LineRegexp = "Compiled src/app\.appup\.src",
+ ?assertEqual(true, has_line(Output, LineRegexp)),
+
+ %% check that ebin/app.appup exists
+ ?assertMatch(true, filelib:is_regular("ebin/app.appup")),
+ retest_log:log(debug, "Generated ebin/app.appup~n", []),
+
+ %% check that ebin/app.appup has expected version
+ {ok, [{AppVersion, [{UpgradeFrom, _}], [{DowngradeTo, _}]}]} =
+ file:consult("ebin/app.appup"),
+ ?assertEqual(AppVersion, "1.2.2"),
+ ?assertEqual(UpgradeFrom, "1.2.1"),
+ ?assertEqual(DowngradeTo, "1.2.1"),
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
diff -Nru rebar-2.0.0/inttest/appup_src_2/src/app.app.src rebar-2.6.0/inttest/appup_src_2/src/app.app.src
--- rebar-2.0.0/inttest/appup_src_2/src/app.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_2/src/app.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,5 @@
+{application, app,
+ [{vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff -Nru rebar-2.0.0/inttest/appup_src_2/src/app.appup.src rebar-2.6.0/inttest/appup_src_2/src/app.appup.src
--- rebar-2.0.0/inttest/appup_src_2/src/app.appup.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_2/src/app.appup.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+{"1.24",
+ [],
+ []
+}.
diff -Nru rebar-2.0.0/inttest/appup_src_2/src/appup_src.erl rebar-2.6.0/inttest/appup_src_2/src/appup_src.erl
--- rebar-2.0.0/inttest/appup_src_2/src/appup_src.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_2/src/appup_src.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(appup_src).
+
+-compile(export_all).
+
+test() ->
+ ok.
diff -Nru rebar-2.0.0/inttest/appup_src_script/appup_src_script_rt.erl rebar-2.6.0/inttest/appup_src_script/appup_src_script_rt.erl
--- rebar-2.0.0/inttest/appup_src_script/appup_src_script_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_script/appup_src_script_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,67 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 Luis Rascao (luis.rascao@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(appup_src_script_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {copy, "src", "src"}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ {ok, [_Pid|Output]} = retest:sh("./rebar compile -vv",
+ [{async, false}]),
+
+ LineRegexp = "Compiled src/app\.appup\.src",
+ ?assertEqual(true, has_line(Output, LineRegexp)),
+
+ %% check that ebin/app.appup exists
+ ?assertMatch(true, filelib:is_regular("ebin/app.appup")),
+ retest_log:log(debug, "Generated ebin/app.appup~n", []),
+
+ %% check that ebin/app.appup has expected version
+ {ok, [{AppVersion, [{UpgradeFrom, _}], [{DowngradeTo, _}]}]} =
+ file:consult("ebin/app.appup"),
+ ?assertEqual(AppVersion, "2.1.2"),
+ ?assertEqual(UpgradeFrom, "2.1.1"),
+ ?assertEqual(DowngradeTo, "2.1.1"),
+ ok.
+
+has_line([], _RE) ->
+ false;
+has_line([L|T], RE) ->
+ case re:run(L, RE, []) of
+ {match, _Captured} ->
+ true;
+ match ->
+ true;
+ nomatch ->
+ has_line(T, RE)
+ end.
diff -Nru rebar-2.0.0/inttest/appup_src_script/src/app.app.src rebar-2.6.0/inttest/appup_src_script/src/app.app.src
--- rebar-2.0.0/inttest/appup_src_script/src/app.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_script/src/app.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,5 @@
+{application, app,
+ [{vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff -Nru rebar-2.0.0/inttest/appup_src_script/src/app.appup.src rebar-2.6.0/inttest/appup_src_script/src/app.appup.src
--- rebar-2.0.0/inttest/appup_src_script/src/app.appup.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_script/src/app.appup.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+{"1.2.2",
+ [{"1.2.1",
+ [{update,proc1,{advanced,[]},[]},
+ {update,proc2,{advanced,[]},[]}]
+ }],
+ [{"1.2.1", []}]}.
diff -Nru rebar-2.0.0/inttest/appup_src_script/src/app.appup.src.script rebar-2.6.0/inttest/appup_src_script/src/app.appup.src.script
--- rebar-2.0.0/inttest/appup_src_script/src/app.appup.src.script 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_script/src/app.appup.src.script 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,9 @@
+%% decompose the appup
+[{AppVersion,
+ [{UpgradeFrom, UpgradeInstructions}],
+ [{DowngradeTo, DowngradeInstructions}]}] = CONFIG,
+
+%% and replace the version strings
+[{"2.1.2",
+ [{"2.1.1", UpgradeInstructions}],
+ [{"2.1.1", DowngradeInstructions}]}].
diff -Nru rebar-2.0.0/inttest/appup_src_script/src/appup_src.erl rebar-2.6.0/inttest/appup_src_script/src/appup_src.erl
--- rebar-2.0.0/inttest/appup_src_script/src/appup_src.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/appup_src_script/src/appup_src.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(appup_src).
+
+-compile(export_all).
+
+test() ->
+ ok.
diff -Nru rebar-2.0.0/inttest/bug_5_rt.erl rebar-2.6.0/inttest/bug_5_rt.erl
--- rebar-2.0.0/inttest/bug_5_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/bug_5_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(bug_5_rt).
-compile(export_all).
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl rebar-2.6.0/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,45 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(code_path_no_recurse_rt).
+-export([files/0,
+ run/1]).
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "src", "src"},
+ {copy, "test", "test"},
+ {copy, "deps", "deps"}
+ ].
+
+run(_Dir) ->
+ retest:log(info, "Compile project~n"),
+ {ok, _} = retest:sh("./rebar -v compile"),
+ retest:log(info, "Run eunit with referenced deps on the code path~n"),
+ {ok, _} = retest:sh("./rebar -v eunit"),
+ ok.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src rebar-2.6.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+{application, bazdep,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, {bazdep, []}},
+ {env, []}
+ ]}.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl rebar-2.6.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/bazdep/src/bazdep.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(bazdep).
+
+-export([bazdep/0]).
+
+bazdep() ->
+ bazdep.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl rebar-2.6.0/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/bazdep/test/bazdep_tests.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,5 @@
+-module(bazdep_tests).
+-include_lib("eunit/include/eunit.hrl").
+
+bazdep_test() ->
+ ?assert(bazdep:bazdep() =:= bazdep).
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/rebar.config rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/rebar.config
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{bazdep, "1"}]}.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+{application, foodep,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, {foodep, []}},
+ {env, []}
+ ]}.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/src/foodep.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(foodep).
+
+-export([foodep/0]).
+
+foodep() ->
+ bazdep:bazdep() =:= bazdep.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/foodep/test/foodep_tests.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,5 @@
+-module(foodep_tests).
+-include_lib("eunit/include/eunit.hrl").
+
+foodep_test() ->
+ ?assert(foodep:foodep()).
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src rebar-2.6.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+{application, unuseddep,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, {unuseddep, []}},
+ {env, []}
+ ]}.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl rebar-2.6.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/deps/unuseddep/src/unuseddep.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(unuseddep).
+
+-export([unuseddep/0]).
+
+unuseddep() ->
+ unuseddep.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/rebar.config rebar-2.6.0/inttest/code_path_no_recurse/rebar.config
--- rebar-2.0.0/inttest/code_path_no_recurse/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{foodep, "1"}]}.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/src/codepath.app.src rebar-2.6.0/inttest/code_path_no_recurse/src/codepath.app.src
--- rebar-2.0.0/inttest/code_path_no_recurse/src/codepath.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/src/codepath.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+{application, codepath,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, {codepath, []}},
+ {env, []}
+ ]}.
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/src/codepath.erl rebar-2.6.0/inttest/code_path_no_recurse/src/codepath.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/src/codepath.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/src/codepath.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(codepath).
+
+-export([codepath/0]).
+
+codepath() ->
+ foodep:foodep().
diff -Nru rebar-2.0.0/inttest/code_path_no_recurse/test/codepath_tests.erl rebar-2.6.0/inttest/code_path_no_recurse/test/codepath_tests.erl
--- rebar-2.0.0/inttest/code_path_no_recurse/test/codepath_tests.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/code_path_no_recurse/test/codepath_tests.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+-module(codepath_tests).
+-include_lib("eunit/include/eunit.hrl").
+
+codepath_test() ->
+ ?assertEqual({module, codepath}, code:ensure_loaded(codepath)),
+ ?assertEqual({module, foodep}, code:ensure_loaded(foodep)),
+ ?assertEqual({module, bazdep}, code:ensure_loaded(bazdep)),
+ ?assert(codepath:codepath()).
+
+unuseddep_test() ->
+ ?assertEqual(non_existing, code:which(unuseddep)),
+ ?assertEqual({error, nofile}, code:ensure_loaded(unuseddep)).
diff -Nru rebar-2.0.0/inttest/cover/cover_rt.erl rebar-2.6.0/inttest/cover/cover_rt.erl
--- rebar-2.0.0/inttest/cover/cover_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/cover/cover_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,76 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Brian H. Ward
+%%
+%% 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(cover_rt).
+
+-export([files/0,run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{create, "ebin/foo.app", app(foo)},
+ {copy, "../../rebar","rebar"},
+ {copy, "src", "src"},
+ {copy,
+ "rebar-cover_export_json.config",
+ "rebar-cover_export_json.config"}].
+
+run(_Dir) ->
+ ifdef_test(),
+ cover_export_json_test(),
+ ok.
+
+ifdef_test() ->
+ {ok, Output} = retest:sh("./rebar -v eunit"),
+ io:format("output => ~p~n", [Output]),
+ ?assert(check_output(Output, "foo")),
+ {ok, Listing} = file:list_dir(".eunit"),
+ ?assert(check_output(Listing, "foo.beam")),
+ ?assertMatch({ok,_}, retest:sh("./rebar clean")).
+
+cover_export_json_test() ->
+ {ok, Output} =
+ retest:sh("./rebar -v -C rebar-cover_export_json.config eunit"),
+ ?assert(check_output(Output, "foo")),
+ ?assertEqual(
+ {ok, <<"{\"module\":\"foo\",\"covered\":2,\"not_covered\":1}">>},
+ file:read_file(".eunit/foo.COVER.json")),
+ ?assertMatch(
+ {ok, _},
+ retest:sh("./rebar -C rebar-cover_export_json.config clean")).
+
+check_output(Output,Target) ->
+ lists:any(fun(Line) ->
+ string:str(Line, Target) > 0
+ end, Output).
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/cover/rebar-cover_export_json.config rebar-2.6.0/inttest/cover/rebar-cover_export_json.config
--- rebar-2.0.0/inttest/cover/rebar-cover_export_json.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/cover/rebar-cover_export_json.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+{cover_enabled, true}.
+{cover_export_json, true}.
diff -Nru rebar-2.0.0/inttest/cover/src/foo.erl rebar-2.6.0/inttest/cover/src/foo.erl
--- rebar-2.0.0/inttest/cover/src/foo.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/cover/src/foo.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,18 @@
+-module(foo).
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-endif.
+
+covered_function() ->
+ "I am tested".
+
+uncovered_function() ->
+ "I am not tested".
+
+-ifdef(EUNIT).
+
+covered_function_test() ->
+ ?assertEqual("I am tested", covered_function()).
+
+-endif.
diff -Nru rebar-2.0.0/inttest/ct1/app.config rebar-2.6.0/inttest/ct1/app.config
--- rebar-2.0.0/inttest/ct1/app.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/ct1/app.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+%% This file is an application config file, not a CT test config file
+[{a1, [{foo, bar}]}].
diff -Nru rebar-2.0.0/inttest/ct1/ct1_rt.erl rebar-2.6.0/inttest/ct1/ct1_rt.erl
--- rebar-2.0.0/inttest/ct1/ct1_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/ct1/ct1_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(ct1_rt).
-compile(export_all).
@@ -7,10 +9,12 @@
[{create, "ebin/a1.app", app(a1)},
{copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
+ {copy, "app.config", "app.config"},
{copy, "test_SUITE.erl", "itest/test_SUITE.erl"}].
run(_Dir) ->
{ok, _} = retest:sh("./rebar compile ct"),
+ {ok, _} = retest:sh("./rebar compile ct -v"),
ok.
diff -Nru rebar-2.0.0/inttest/ct1/rebar.config rebar-2.6.0/inttest/ct1/rebar.config
--- rebar-2.0.0/inttest/ct1/rebar.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/ct1/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1,2 @@
-
{ct_dir, "itest"}.
+{ct_extra_params, "-repeat 2 -erl_args -config app"}.
diff -Nru rebar-2.0.0/inttest/ct1/test_SUITE.erl rebar-2.6.0/inttest/ct1/test_SUITE.erl
--- rebar-2.0.0/inttest/ct1/test_SUITE.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/ct1/test_SUITE.erl 2015-06-19 16:14:28.000000000 +0000
@@ -5,7 +5,13 @@
-include_lib("ct.hrl").
all() ->
- [simple_test].
+ [simple_test,
+ app_config_file_test].
simple_test(Config) ->
io:format("Test: ~p\n", [Config]).
+
+app_config_file_test(_Config) ->
+ application:start(a1),
+ {ok, bar} = application:get_env(a1, foo),
+ application:stop(a1).
diff -Nru rebar-2.0.0/inttest/ct2/ct2_rt.erl rebar-2.6.0/inttest/ct2/ct2_rt.erl
--- rebar-2.0.0/inttest/ct2/ct2_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/ct2/ct2_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(ct2_rt).
-compile(export_all).
@@ -6,11 +8,17 @@
files() ->
[{create, "ebin/foo.app", app(foo)},
{copy, "../../rebar", "rebar"},
- {copy, "foo.test.spec", "test/foo.test.spec"},
+ {copy, "foo.test.spec", "foo.test.spec"},
+ {copy, "deps/bar.test.spec", "deps/bar.test.spec"},
{copy, "foo_SUITE.erl", "test/foo_SUITE.erl"}].
run(_Dir) ->
- {ok, _} = retest:sh("./rebar compile ct -v"),
+ Ref = retest:sh("./rebar compile ct -vvv", [async]),
+ {ok, [[CTRunCmd]]} = retest:sh_expect(Ref, "^\"ct_run.*",
+ [global, {capture, first, binary}]),
+ {match, _} = re:run(CTRunCmd, "foo.test.spec", [global]),
+ %% deps/bar.test.spec should be ignored by rebar_ct:collect_glob/3
+ nomatch = re:run(CTRunCmd, "bar.test.spec", [global]),
ok.
%%
diff -Nru rebar-2.0.0/inttest/ct2/deps/bar.test.spec rebar-2.6.0/inttest/ct2/deps/bar.test.spec
--- rebar-2.0.0/inttest/ct2/deps/bar.test.spec 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/ct2/deps/bar.test.spec 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+%% this test spec should be ignored
diff -Nru rebar-2.0.0/inttest/ct3/app.config rebar-2.6.0/inttest/ct3/app.config
--- rebar-2.0.0/inttest/ct3/app.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/ct3/app.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+%% This file is an application config file, not a CT test config file
+[{a1, [{foo, bar}]}].
diff -Nru rebar-2.0.0/inttest/ct3/ct3_rt.erl rebar-2.6.0/inttest/ct3/ct3_rt.erl
--- rebar-2.0.0/inttest/ct3/ct3_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/ct3/ct3_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,56 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Savchuk Igor
+%%
+%% 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(ct3_rt).
+
+-compile(export_all).
+
+
+files() ->
+ [{create, "ebin/a1.app", app(a1)},
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "app.config", "itest/app.config"},
+ {copy, "test_SUITE.erl", "itest/test_SUITE.erl"},
+ {copy, "converted"},
+ {copy, "unconverted"}].
+
+run(_Dir) ->
+ {ok, _} = retest:sh("./rebar compile ct -v",
+ [{env, [{"ERL_FLAGS", "-name ct_rt3"}]}]),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/ct3/rebar.config rebar-2.6.0/inttest/ct3/rebar.config
--- rebar-2.0.0/inttest/ct3/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/ct3/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+{ct_dir, "itest"}.
+{ct_extra_params, "-repeat 2 -pa converted -erl_args -pa unconverted"}.
diff -Nru rebar-2.0.0/inttest/ct3/test_SUITE.erl rebar-2.6.0/inttest/ct3/test_SUITE.erl
--- rebar-2.0.0/inttest/ct3/test_SUITE.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/ct3/test_SUITE.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,52 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Savchuk Igor
+%%
+%% 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(test_SUITE).
+
+-compile(export_all).
+
+-include_lib("ct.hrl").
+
+all() ->
+ [simple_test,
+ app_config_file_test,
+ check_path].
+
+simple_test(Config) ->
+ io:format("Test: ~p\n", [Config]).
+
+app_config_file_test(_Config) ->
+ application:start(a1),
+ {ok, bar} = application:get_env(a1, foo),
+ application:stop(a1).
+
+%% check if -erl_args in ct_extra_params of rebar.config is working
+%% if it is, path before -erl_args is converted to absolute
+%% and path after -erl_args is not
+check_path(_Config) ->
+ Path = code:get_path(),
+ false = lists:member("converted", Path),
+ true = lists:member("unconverted", Path).
diff -Nru rebar-2.0.0/inttest/depplugins/base_dir_cwd_plugin.erl rebar-2.6.0/inttest/depplugins/base_dir_cwd_plugin.erl
--- rebar-2.0.0/inttest/depplugins/base_dir_cwd_plugin.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/base_dir_cwd_plugin.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,7 @@
+-module(base_dir_cwd_plugin).
+-export([pre_compile/2]).
+
+pre_compile(_, _) ->
+ File = "base_dir_cwd_pre.compile",
+ ok = file:write_file(File, <<"base_dir cwd pre_compile plugin">>),
+ rebar_log:log(info, "Wrote ~p/~s~n", [rebar_utils:get_cwd(), File]).
diff -Nru rebar-2.0.0/inttest/depplugins/dep_cwd_plugin.erl rebar-2.6.0/inttest/depplugins/dep_cwd_plugin.erl
--- rebar-2.0.0/inttest/depplugins/dep_cwd_plugin.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/dep_cwd_plugin.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,7 @@
+-module(dep_cwd_plugin).
+-export([pre_compile/2]).
+
+pre_compile(_, _) ->
+ File = "dep_cwd_pre.compile",
+ ok = file:write_file(File, <<"dep cwd pre_compile plugin">>),
+ rebar_log:log(info, "Wrote ~p/~s~n", [rebar_utils:get_cwd(), File]).
diff -Nru rebar-2.0.0/inttest/depplugins/depplugins_rt.erl rebar-2.6.0/inttest/depplugins/depplugins_rt.erl
--- rebar-2.0.0/inttest/depplugins/depplugins_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/depplugins_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,71 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%%% @doc Plugin handling test
+%%%
+%%% This test checks if plugins are loaded correctly.
+%%%
+%%% It has three applications:
+%%%
+%%% - fish. top-level app, has one dependency: `dependsonplugin'.
+%%% It also loads a plugin from CWD which creates
+%%% base_dir_cwd_pre.compile on pre_compile.
+%%% - dependsonplugin, has one dependency: `testplugin' and loads
+%%% the testplugin_mod plugin.
+%%% - testplugin. This is a plugin application which creates
+%%% plugin_pre.compile on pre_compile. It also loads a plugin from CWD
+%%% which creates dep_cwd_pre.compile on pre_compile.
+%%%
+
+-module(depplugins_rt).
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "base_dir_cwd_plugin.erl", "base_dir_cwd_plugin.erl"},
+ {create, "ebin/fish.app", app(fish, [])},
+
+ {copy, "rebar_dependsonplugin.config",
+ "deps/dependsonplugin/rebar.config"},
+ {create, "deps/dependsonplugin/ebin/dependsonplugin.app",
+ app(dependsonplugin, [])},
+
+ {copy, "rebar_testplugin.config", "deps/testplugin/rebar.config"},
+ {copy, "testplugin_mod.erl",
+ "deps/testplugin/plugins/testplugin_mod.erl"},
+ {copy, "dep_cwd_plugin.erl", "deps/testplugin/dep_cwd_plugin.erl"},
+ {create, "deps/testplugin/ebin/testplugin.app", app(testplugin, [])}
+ ].
+
+run(_Dir) ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+
+ ?assertEqual(true, filelib:is_regular("base_dir_cwd_pre.compile")),
+
+ ?assertEqual(true, filelib:is_regular(
+ "deps/dependsonplugin/base_dir_cwd_pre.compile")),
+ ?assertEqual(true, filelib:is_regular(
+ "deps/dependsonplugin/plugin_pre.compile")),
+
+ ?assertEqual(true, filelib:is_regular(
+ "deps/testplugin/base_dir_cwd_pre.compile")),
+ ?assertEqual(true, filelib:is_regular(
+ "deps/testplugin/dep_cwd_pre.compile")),
+ ?assertEqual(true, filelib:is_regular(
+ "deps/testplugin/plugin_pre.compile")),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/depplugins/rebar.config rebar-2.6.0/inttest/depplugins/rebar.config
--- rebar-2.0.0/inttest/depplugins/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+{deps, [dependsonplugin]}.
+{plugins, [base_dir_cwd_plugin]}.
diff -Nru rebar-2.0.0/inttest/depplugins/rebar_dependsonplugin.config rebar-2.6.0/inttest/depplugins/rebar_dependsonplugin.config
--- rebar-2.0.0/inttest/depplugins/rebar_dependsonplugin.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/rebar_dependsonplugin.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+{deps, [testplugin]}.
+{plugins, [testplugin_mod]}.
diff -Nru rebar-2.0.0/inttest/depplugins/rebar_testplugin.config rebar-2.6.0/inttest/depplugins/rebar_testplugin.config
--- rebar-2.0.0/inttest/depplugins/rebar_testplugin.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/rebar_testplugin.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{plugins, [dep_cwd_plugin]}.
diff -Nru rebar-2.0.0/inttest/depplugins/testplugin_mod.erl rebar-2.6.0/inttest/depplugins/testplugin_mod.erl
--- rebar-2.0.0/inttest/depplugins/testplugin_mod.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/depplugins/testplugin_mod.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,7 @@
+-module(testplugin_mod).
+-export([pre_compile/2]).
+
+pre_compile(_, _) ->
+ File = "plugin_pre.compile",
+ ok = file:write_file(File, <<"Yadda!">>),
+ rebar_log:log(info, "Wrote ~p/~s~n", [rebar_utils:get_cwd(), File]).
diff -Nru rebar-2.0.0/inttest/erlc/asn1/SIMPLE-ASN.asn1 rebar-2.6.0/inttest/erlc/asn1/SIMPLE-ASN.asn1
--- rebar-2.0.0/inttest/erlc/asn1/SIMPLE-ASN.asn1 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/asn1/SIMPLE-ASN.asn1 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,7 @@
+SIMPLE-ASN DEFINITIONS ::= BEGIN
+
+ SimpleMessage ::= SEQUENCE {
+ id INTEGER
+ }
+
+END
diff -Nru rebar-2.0.0/inttest/erlc/erlc_rt.erl rebar-2.6.0/inttest/erlc/erlc_rt.erl
--- rebar-2.0.0/inttest/erlc/erlc_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/erlc_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,163 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(erlc_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-define(MODULES,
+ [after_first_erl,
+ first_xrl,
+ first_yrl,
+ first_erl,
+ foo,
+ foo_app,
+ foo_sup,
+ foo_test_worker,
+ foo_worker,
+ 'SIMPLE-ASN']).
+
+-define(BEAM_FILES,
+ ["after_first_erl.beam",
+ "first_xrl.beam",
+ "first_yrl.beam",
+ "first_erl.beam",
+ "foo.beam",
+ "foo_app.beam",
+ "foo_sup.beam",
+ "foo_test_worker.beam",
+ "foo_worker.beam",
+ "SIMPLE-ASN.beam"]).
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "rebar-no_debug_info.config", "rebar-no_debug_info.config"},
+ {copy, "include", "include"},
+ {copy, "extra-include", "extra-include"},
+ {copy, "src", "src"},
+ {copy, "extra-src", "extra-src"},
+ {copy, "mibs", "mibs"},
+ {copy, "asn1", "asn1"},
+ {create, "ebin/foo.app", app(foo, ?MODULES)},
+ %% deps
+ {create, "deps/foobar/ebin/foobar.app", app(foobar, [foobar])},
+ {copy, "foobar.erl", "deps/foobar/src/foobar.erl"}
+ ].
+
+run(_Dir) ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ ok = check_beams(true),
+ ok = check_debug_info(true),
+ MibResult = filename:join(["priv", "mibs", "SIMPLE-MIB.bin"]),
+ ?assertMatch(true, filelib:is_regular(MibResult)),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])),
+ ok = check_beams(false),
+ ?assertMatch(false, filelib:is_regular(MibResult)),
+ ?assertMatch(
+ {ok, _},
+ retest_sh:run("./rebar -C rebar-no_debug_info.config compile", [])),
+ ok = check_beams(true),
+ ok = check_debug_info(false),
+ ?assertMatch(true, filelib:is_regular(MibResult)),
+ %% Regression test for https://github.com/rebar/rebar/issues/249
+ %%
+ %% Root cause: We didn't have per-project .rebar/erlcinfo but just one in
+ %% /.rebar/erlcinfo.
+ %%
+ %% Solution: Ensure every project has its own .rebar/erlcinfo
+ %%
+ %% For the bug to happen, the following conditions must be met:
+ %%
+ %% 1. /rebar.config has erl_first_files
+ %% 2. one of the 'first' files depends on another file (in this
+ %% case via -include_lib())
+ %% 3. a sub project's rebar.config, if any, has no erl_first_files entry
+ %%
+ %% Now because erl_first_files is retrieved via rebar_config:get_list/3,
+ %% base_dir/rebar.config's erl_first_files is inherited, and because we had
+ %% a shared /.rebar/erlcinfo instead of one per project, the
+ %% cached entry was reused. Next, while compiling the sub project
+ %% rebar_erlc_compiler:needs_compile/3 gets a last modification time of
+ %% zero for the 'first' file which does not exist inside the sub project.
+ %% This, and the fact that it has at least one dependency, makes
+ %% needs_compile/3 return 'true'. The root cause is that we didn't have per
+ %% project .rebar/erlcinfo. For /.rebar/erlcinfo to be populated,
+ %% base_dir has to be compiled at least once. Therefore, after the first
+ %% compile any compile processing the sub project will fail because
+ %% needs_compile/3 will always return true for the non-existent 'first'
+ %% file.
+ ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ ok = check_beams(true),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ ok = check_beams(true),
+ ok.
+
+check_beams(Exist) ->
+ check_files(Exist, fun filelib:is_regular/1).
+
+check_debug_info(HasDebugInfo) ->
+ check_files(HasDebugInfo, fun has_debug_info/1).
+
+check_files(Expected, Check) ->
+ lists:foreach(
+ fun(F) ->
+ File = filename:join("ebin", F),
+ ?assertEqual(Expected, Check(File))
+ end,
+ ?BEAM_FILES).
+
+%% NOTE: Copied from dialyzer_utils:get_abstract_code_from_beam/1 and
+%% modified for local use. We could have called the function directly,
+%% but dialyzer_utils is not an official API to rely on.
+has_debug_info(File) ->
+ case beam_lib:chunks(File, [abstract_code]) of
+ {ok, {_Mod, List}} ->
+ case lists:keyfind(abstract_code, 1, List) of
+ {abstract_code, {raw_abstract_v1, _Abstr}} ->
+ true;
+ _ ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/erlc/extra-include/foo_extra.hrl rebar-2.6.0/inttest/erlc/extra-include/foo_extra.hrl
--- rebar-2.0.0/inttest/erlc/extra-include/foo_extra.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/extra-include/foo_extra.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-define(FOO_EXTRA, foo_extra).
diff -Nru rebar-2.0.0/inttest/erlc/extra-src/after_first_erl.erl rebar-2.6.0/inttest/erlc/extra-src/after_first_erl.erl
--- rebar-2.0.0/inttest/erlc/extra-src/after_first_erl.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/extra-src/after_first_erl.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,11 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(after_first_erl).
+-compile({parse_transform, first_erl}).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-export([test/0]).
+
+test() ->
+ ?debugHere.
diff -Nru rebar-2.0.0/inttest/erlc/extra-src/foo_sup.erl rebar-2.6.0/inttest/erlc/extra-src/foo_sup.erl
--- rebar-2.0.0/inttest/erlc/extra-src/foo_sup.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/extra-src/foo_sup.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,15 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(foo_sup).
+
+-behavior(supervisor).
+
+-export([start_link/0,
+ init/1]).
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init(_Args) ->
+ FooChild = {foo,{foo, start_link, []}, permanent, 5000, worker, [foo]},
+ {ok,{{one_for_all,1,1}, [FooChild]}}.
diff -Nru rebar-2.0.0/inttest/erlc/foobar.erl rebar-2.6.0/inttest/erlc/foobar.erl
--- rebar-2.0.0/inttest/erlc/foobar.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/foobar.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,8 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(foobar).
+
+-export([test/0]).
+
+test() ->
+ true.
diff -Nru rebar-2.0.0/inttest/erlc/include/foo_core.hrl rebar-2.6.0/inttest/erlc/include/foo_core.hrl
--- rebar-2.0.0/inttest/erlc/include/foo_core.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/include/foo_core.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-define(FOO_CORE, foo_core).
diff -Nru rebar-2.0.0/inttest/erlc/mibs/SIMPLE-MIB.mib rebar-2.6.0/inttest/erlc/mibs/SIMPLE-MIB.mib
--- rebar-2.0.0/inttest/erlc/mibs/SIMPLE-MIB.mib 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/mibs/SIMPLE-MIB.mib 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,26 @@
+-- SIMPLE-MIB.
+-- This is just a simple MIB used for testing!
+--
+
+
+SIMPLE-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, enterprises
+ FROM SNMPv2-SMI;
+
+ericsson MODULE-IDENTITY
+ LAST-UPDATED
+ "201403060000Z"
+ ORGANIZATION
+ "rebar"
+ CONTACT-INFO
+ "rebar
+ or
+ whoever is currently responsible for the SIMPLE
+ enterprise MIB tree branch (enterprises.999)."
+ DESCRIPTION
+ "This very small module is made available
+ for mib-compilation testing."
+ ::= { enterprises 999 }
+END
diff -Nru rebar-2.0.0/inttest/erlc/rebar.config rebar-2.6.0/inttest/erlc/rebar.config
--- rebar-2.0.0/inttest/erlc/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,13 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+{erl_first_files,
+ ["src/first_xrl.erl", "src/first_yrl.erl", "src/first_erl.erl", "extra-src/after_first_erl.erl"]}.
+
+{deps, [foobar]}.
+
+{erl_opts,
+ [
+ {i, "extra-include"},
+ {src_dirs, ["extra-src", "src"]},
+ {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'}
+ ]}.
diff -Nru rebar-2.0.0/inttest/erlc/rebar-no_debug_info.config rebar-2.6.0/inttest/erlc/rebar-no_debug_info.config
--- rebar-2.0.0/inttest/erlc/rebar-no_debug_info.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/rebar-no_debug_info.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,11 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+{erl_first_files, ["src/first_xrl.erl", "src/first_yrl.erl"]}.
+
+{erl_opts,
+ [
+ no_debug_info,
+ {i, "extra-include"},
+ {src_dirs, ["src", "extra-src"]},
+ {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'}
+ ]}.
diff -Nru rebar-2.0.0/inttest/erlc/src/behaviour/foo_worker.erl rebar-2.6.0/inttest/erlc/src/behaviour/foo_worker.erl
--- rebar-2.0.0/inttest/erlc/src/behaviour/foo_worker.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/behaviour/foo_worker.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,14 @@
+-module(foo_worker).
+
+-ifdef(NO_CALLBACK_ATTRIBUTE).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) -> [{status, 0}];
+behaviour_info(_) -> undefined.
+
+-else.
+
+-callback status() -> 'idle' | 'busy'.
+
+-endif.
diff -Nru rebar-2.0.0/inttest/erlc/src/._do_not_compile.erl rebar-2.6.0/inttest/erlc/src/._do_not_compile.erl
--- rebar-2.0.0/inttest/erlc/src/._do_not_compile.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/._do_not_compile.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+syntax error
+this file is here to verify that rebar does not try to
+compile files like OS X resource forks and should not be
+processed at all
diff -Nru rebar-2.0.0/inttest/erlc/src/first_erl.erl rebar-2.6.0/inttest/erlc/src/first_erl.erl
--- rebar-2.0.0/inttest/erlc/src/first_erl.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/first_erl.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,13 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(first_erl).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-export([test/0, parse_transform/2]).
+
+test() ->
+ ?debugHere.
+
+parse_transform(Forms, _Options) ->
+ Forms.
diff -Nru rebar-2.0.0/inttest/erlc/src/first_xrl.xrl rebar-2.6.0/inttest/erlc/src/first_xrl.xrl
--- rebar-2.0.0/inttest/erlc/src/first_xrl.xrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/first_xrl.xrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,13 @@
+Definitions.
+
+D = [0-9]
+
+Rules.
+
+{D}+ :
+ {token,{integer,TokenLine,list_to_integer(TokenChars)}}.
+
+{D}+\.{D}+((E|e)(\+|\-)?{D}+)? :
+ {token,{float,TokenLine,list_to_float(TokenChars)}}.
+
+Erlang code.
diff -Nru rebar-2.0.0/inttest/erlc/src/first_yrl.yrl rebar-2.6.0/inttest/erlc/src/first_yrl.yrl
--- rebar-2.0.0/inttest/erlc/src/first_yrl.yrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/first_yrl.yrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,9 @@
+Nonterminals list elements element.
+Terminals atom '(' ')'.
+Rootsymbol list.
+list -> '(' ')'.
+list -> '(' elements ')'.
+elements -> element.
+elements -> element elements.
+element -> atom.
+element -> list.
diff -Nru rebar-2.0.0/inttest/erlc/src/foo_app.erl rebar-2.6.0/inttest/erlc/src/foo_app.erl
--- rebar-2.0.0/inttest/erlc/src/foo_app.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/foo_app.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,10 @@
+-module(foo_app).
+
+-behaviour(application).
+
+-export([start/2,
+ stop/1]).
+
+start(_Type, _Args) -> foo_sup:start_link().
+
+stop(_State) -> ok.
diff -Nru rebar-2.0.0/inttest/erlc/src/foo.erl rebar-2.6.0/inttest/erlc/src/foo.erl
--- rebar-2.0.0/inttest/erlc/src/foo.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/foo.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,35 @@
+-module(foo).
+
+-export([start_link/0,
+ start_link/1,
+ init/1,
+ terminate/2,
+ handle_info/2,
+ handle_call/3,
+ handle_cast/2,
+ code_change/3]).
+
+-behavior(gen_server).
+
+-include("foo_core.hrl").
+-include("foo_extra.hrl").
+-include_lib("kernel/include/file.hrl").
+
+-record(state, {node :: node()}).
+
+start_link() -> start_link(undefined).
+
+start_link(Args) ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).
+
+init(_Args) -> {ok, #state{node=node()}}.
+
+terminate(_Reason, _Data) -> ok.
+
+handle_info(_Info, State) -> {noreply, State}.
+
+handle_cast(_Msg, State) -> {noreply, State}.
+
+handle_call(_Msg, _From, State) -> {reply, ok, State}.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
diff -Nru rebar-2.0.0/inttest/erlc/src/foo_test_worker.erl rebar-2.6.0/inttest/erlc/src/foo_test_worker.erl
--- rebar-2.0.0/inttest/erlc/src/foo_test_worker.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc/src/foo_test_worker.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,34 @@
+-module(foo_test_worker).
+
+-behaviour(gen_server).
+-behaviour(foo_worker).
+
+-export([start_link/0,
+ start_link/1,
+ init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3,
+ status/0]).
+
+-include_lib("kernel/include/inet.hrl").
+
+start_link() -> start_link(undefined).
+
+start_link(Args) -> gen_server:start_link(?MODULE, Args, []).
+
+init([]) -> {ok, undefined}.
+
+handle_call(_Event, _From, State) -> {reply, ok, State}.
+
+handle_cast(_Event, State) -> {noreply, State}.
+
+handle_info(_Info, State) -> {noreply, State}.
+
+terminate(_Reason, _State) -> ok.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+status() -> busy.
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl rebar-2.6.0/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl
--- rebar-2.0.0/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,111 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 David Kubecka
+%%
+%% 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(erlc_dep_graph_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "src", "src"},
+ {copy, "include", "include"},
+ {copy, "extra_include", "extra_include"}].
+
+run(_Dir) ->
+ compile_all(ok, ""),
+ check_beams_ok(),
+ check_beams_untouched(filelib:wildcard("ebin/*.beam")),
+ modify_and_recompile_ok("src/lisp.erl", "ebin/lisp.beam"),
+
+ clean_all_ok(),
+ compile_all(error, "-C rebar.config.non-existing"),
+ compile_all(ok, ""),
+ modify_and_recompile_ok("extra_include/extra.hrl", "ebin/java.beam"),
+
+ Java = "src/java.erl",
+ {ok, OrigContent} = file:read_file(Java),
+ %% Remove header file inclusion
+ {ok, _} = file:copy("src/java.erl.no_extra", Java),
+ %% Ensure recompilation
+ touch([Java]),
+ compile_all(ok, ""),
+ %% Modify that header file
+ touch(["extra_include/extra.hrl"]),
+ %% Ensure we don't have to recompile anything
+ check_beams_untouched(["ebin/java.beam"]),
+ %% Clean up
+ ok = file:write_file(Java, OrigContent),
+
+ %% Check that changes propagate deeply through the dependency tree
+ modify_and_recompile_ok("include/lambda.hrl", "ebin/perl.beam"),
+
+ ok.
+
+check_beams_ok() ->
+ F = fun(BeamFile) -> ?assert(filelib:is_regular(BeamFile)) end,
+ with_erl_beams(F).
+
+check_beams_untouched(Beams) ->
+ compile_all_and_assert_mtimes(Beams, fun erlang:'=:='/2).
+
+modify_and_recompile_ok(TouchFile, CheckFile) ->
+ touch([TouchFile]),
+ compile_all_and_assert_mtimes([CheckFile], fun erlang:'<'/2).
+
+compile_all_and_assert_mtimes(Beams, Cmp) ->
+ BeamsModifiedBefore = mtime_ns(Beams),
+ compile_all(ok, ""),
+ BeamsModifiedAfter = mtime_ns(Beams),
+ lists:zipwith(fun(Before, After) -> ?assert(Cmp(Before, After)) end,
+ BeamsModifiedBefore, BeamsModifiedAfter).
+
+with_erl_beams(F) ->
+ lists:map(
+ fun(ErlFile) ->
+ ErlRoot = filename:rootname(filename:basename(ErlFile)),
+ BeamFile = filename:join("ebin", ErlRoot ++ ".beam"),
+ F(BeamFile)
+ end,
+ filelib:wildcard("src/*.erl")).
+
+mtime_ns(Files) ->
+ [os:cmd("stat -c%y " ++ File) || File <- Files].
+
+touch(Files) ->
+ %% Sleep one second so that filelib:last_modified/1 is guaranteed to notice
+ %% that files have changed.
+ ok = timer:sleep(1000),
+ [os:cmd("touch " ++ File) || File <- Files].
+
+compile_all(Result, Opts) ->
+ ?assertMatch({Result, _},
+ retest_sh:run("./rebar " ++ Opts ++ " compile", [])).
+
+clean_all_ok() ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])).
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/extra_include/extra.hrl rebar-2.6.0/inttest/erlc_dep_graph/extra_include/extra.hrl
--- rebar-2.0.0/inttest/erlc_dep_graph/extra_include/extra.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/extra_include/extra.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-define(CONCISE, impossible).
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/include/lambda.hrl rebar-2.6.0/inttest/erlc_dep_graph/include/lambda.hrl
--- rebar-2.0.0/inttest/erlc_dep_graph/include/lambda.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/include/lambda.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-define(FUN, fake).
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/rebar.config rebar-2.6.0/inttest/erlc_dep_graph/rebar.config
--- rebar-2.0.0/inttest/erlc_dep_graph/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,8 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+{erl_opts,
+ [
+ {i, "extra_include"},
+ {parse_transform, lisp},
+ {parse_transform, pascal}
+ ]}.
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/src/foo.app.src rebar-2.6.0/inttest/erlc_dep_graph/src/foo.app.src
--- rebar-2.0.0/inttest/erlc_dep_graph/src/foo.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/src/foo.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,7 @@
+{application,foo,
+ [{description,[]},
+ {vsn,"1.0.0"},
+ {registered,[]},
+ {applications,[kernel,stdlib]},
+ {env,[]}
+ ]}.
\ No newline at end of file
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/src/java.erl rebar-2.6.0/inttest/erlc_dep_graph/src/java.erl
--- rebar-2.0.0/inttest/erlc_dep_graph/src/java.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/src/java.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,11 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(java).
+
+-export([factory/0]).
+
+-include("lambda.hrl").
+-include("extra.hrl").
+
+factory() ->
+ ?FUN.
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/src/java.erl.no_extra rebar-2.6.0/inttest/erlc_dep_graph/src/java.erl.no_extra
--- rebar-2.0.0/inttest/erlc_dep_graph/src/java.erl.no_extra 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/src/java.erl.no_extra 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,10 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(java).
+
+-export([factory/0]).
+
+-include("lambda.hrl").
+
+factory() ->
+ ?FUN.
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/src/lisp.erl rebar-2.6.0/inttest/erlc_dep_graph/src/lisp.erl
--- rebar-2.0.0/inttest/erlc_dep_graph/src/lisp.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/src/lisp.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,13 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(lisp).
+
+-export([parse_transform/2]).
+
+-include("lambda.hrl").
+-ifdef(NOT_DEFINED).
+-include_lib("include/non/existent.hrl").
+-endif.
+
+parse_transform(Forms, _Options) ->
+ Forms.
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/src/pascal.erl rebar-2.6.0/inttest/erlc_dep_graph/src/pascal.erl
--- rebar-2.0.0/inttest/erlc_dep_graph/src/pascal.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/src/pascal.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,8 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(pascal).
+
+-export([parse_transform/2]).
+
+parse_transform(Forms, _Options) ->
+ Forms.
diff -Nru rebar-2.0.0/inttest/erlc_dep_graph/src/perl.erl rebar-2.6.0/inttest/erlc_dep_graph/src/perl.erl
--- rebar-2.0.0/inttest/erlc_dep_graph/src/perl.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/erlc_dep_graph/src/perl.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,10 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+-module(perl).
+
+-export(['$_'/0]).
+
+-compile({parse_transform, lisp}).
+
+'$_'() ->
+ anything.
diff -Nru rebar-2.0.0/inttest/eunit/eunit_rt.erl rebar-2.6.0/inttest/eunit/eunit_rt.erl
--- rebar-2.0.0/inttest/eunit/eunit_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/eunit/eunit_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,50 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(eunit_rt).
+-export([files/0, run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [{create, "ebin/foo.app", app(foo)},
+ {copy, "../../rebar", "rebar"},
+ {copy, "src", "src"},
+ {copy, "eunit_src", "eunit_src"},
+ {copy,
+ "rebar-eunit_compile_opts.config",
+ "rebar-eunit_compile_opts.config"}].
+
+run(_Dir) ->
+ ifdef_test(),
+ eunit_compile_opts_test(),
+ ok.
+
+ifdef_test() ->
+ {ok, Output} = retest:sh("./rebar -v eunit"),
+ ?assert(check_output(Output, "foo_test")),
+ ?assertMatch({ok, _}, retest:sh("./rebar clean")).
+
+eunit_compile_opts_test() ->
+ {ok, Output} =
+ retest:sh("./rebar -v -C rebar-eunit_compile_opts.config eunit"),
+ ?assert(check_output(Output, "bar_test")),
+ ?assertMatch(
+ {ok, _},
+ retest:sh("./rebar -C rebar-eunit_compile_opts.config clean")).
+
+check_output(Output, Target) ->
+ lists:any(fun(Line) ->
+ string:str(Line, Target) > 0
+ end, Output).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/eunit/eunit_src/bar.erl rebar-2.6.0/inttest/eunit/eunit_src/bar.erl
--- rebar-2.0.0/inttest/eunit/eunit_src/bar.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/eunit/eunit_src/bar.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,6 @@
+-module(bar).
+
+-include_lib("eunit/include/eunit.hrl").
+
+bar_test() ->
+ ?assert(true).
diff -Nru rebar-2.0.0/inttest/eunit/rebar-eunit_compile_opts.config rebar-2.6.0/inttest/eunit/rebar-eunit_compile_opts.config
--- rebar-2.0.0/inttest/eunit/rebar-eunit_compile_opts.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/eunit/rebar-eunit_compile_opts.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{eunit_compile_opts, [{src_dirs, ["eunit_src"]}]}.
diff -Nru rebar-2.0.0/inttest/eunit/src/foo.erl rebar-2.6.0/inttest/eunit/src/foo.erl
--- rebar-2.0.0/inttest/eunit/src/foo.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/eunit/src/foo.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,10 @@
+-module(foo).
+
+-ifdef(TEST).
+
+-include_lib("eunit/include/eunit.hrl").
+
+foo_test() ->
+ ?assert(true).
+
+-endif.
diff -Nru rebar-2.0.0/inttest/logging/logging_rt.erl rebar-2.6.0/inttest/logging/logging_rt.erl
--- rebar-2.0.0/inttest/logging/logging_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/logging/logging_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,125 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(logging_rt).
+-export([files/0,
+ run/1]).
+
+-define(APP_FILE, "ebin/logging.app").
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {create, ?APP_FILE, app(invalid_name, [])}
+ ].
+
+run(_Dir) ->
+ SharedExpected = "==> logging_rt \\(compile\\)",
+ %% provoke ERROR due to an invalid app file
+ retest:log(info, "Check 'compile' failure output~n"),
+ ok = check_output("./rebar compile -q", should_fail,
+ [SharedExpected, "ERROR: "],
+ ["WARN: ", "INFO: ", "DEBUG: "]),
+ %% fix bad app file
+ ok = file:write_file(?APP_FILE, app(logging, [])),
+ retest:log(info, "Check 'compile' success output~n"),
+ ok = check_output("./rebar compile", should_succeed,
+ [SharedExpected],
+ ["ERROR: ", "WARN: ", "INFO: ", "DEBUG: "]),
+ retest:log(info, "Check 'compile -v' success output~n"),
+ ok = check_output("./rebar compile -v", should_succeed,
+ [SharedExpected],
+ ["ERROR: ", "INFO: ", "DEBUG: "]),
+ retest:log(info, "Check 'compile -vv' success output~n"),
+ ok = check_output("./rebar compile -vv", should_succeed,
+ [SharedExpected, "DEBUG: "],
+ ["ERROR: ", "INFO: "]),
+ ok.
+
+check_output(Cmd, FailureMode, Expected, Unexpected) ->
+ case {retest:sh(Cmd), FailureMode} of
+ {{error, _}=Error, should_succeed} ->
+ retest:log(error, "cmd '~s' failed:~n~p~n", [Cmd, Error]),
+ Error;
+ {{ok, Captured}, should_succeed} ->
+ Joined = string:join(Captured, "\n"),
+ check_output1(Cmd, Joined, Expected, Unexpected);
+ {{error, {stopped, {_Rc, Captured}}}, should_fail} ->
+ Joined = string:join(Captured, "\n"),
+ check_output1(Cmd, Joined, Expected, Unexpected)
+ end.
+
+check_output1(Cmd, Captured, Expected, Unexpected) ->
+ ReOpts = [{capture, all, list}],
+ ExMatches =
+ lists:zf(
+ fun(Pattern) ->
+ case re:run(Captured, Pattern, ReOpts) of
+ nomatch ->
+ retest:log(error,
+ "Expected pattern '~s' missing "
+ "in the following output:~n"
+ "=== BEGIN ===~n~s~n=== END ===~n",
+ [Pattern, Captured]),
+ {true, Pattern};
+ {match, _} ->
+ false
+ end
+ end, Expected),
+
+ UnExMatches =
+ lists:zf(
+ fun(Pattern) ->
+ case re:run(Captured, Pattern, ReOpts) of
+ nomatch ->
+ false;
+ {match, [Match]} ->
+ retest:log(
+ error,
+ "Unexpected output when running cmd '~s':~n~s~n",
+ [Cmd, Match]),
+ {true, Match}
+ end
+ end, Unexpected),
+
+ case {ExMatches, UnExMatches} of
+ {[], []} ->
+ ok;
+ _ ->
+ error
+ end.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/port/c_src/test1.c rebar-2.6.0/inttest/port/c_src/test1.c
--- rebar-2.0.0/inttest/port/c_src/test1.c 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/port/c_src/test1.c 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+#include "test1.h"
diff -Nru rebar-2.0.0/inttest/port/c_src/test2.c rebar-2.6.0/inttest/port/c_src/test2.c
--- rebar-2.0.0/inttest/port/c_src/test2.c 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/port/c_src/test2.c 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+#include "test2.h"
diff -Nru rebar-2.0.0/inttest/port/c_src/test2.h rebar-2.6.0/inttest/port/c_src/test2.h
--- rebar-2.0.0/inttest/port/c_src/test2.h 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/port/c_src/test2.h 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+#include "test1.h"
diff -Nru rebar-2.0.0/inttest/port/port_rt.erl rebar-2.6.0/inttest/port/port_rt.erl
--- rebar-2.0.0/inttest/port/port_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/port/port_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,100 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tomas Janousek
+%%
+%% 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(port_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "c_src", "c_src"},
+ {create, "ebin/foo.app", app(foo, [])}
+ ].
+
+run(_Dir) ->
+ %% wait a bit for new files to have different timestamps
+ wait(),
+ %% test.so is created during first compile
+ ?assertEqual(0, filelib:last_modified("priv/test.so")),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ TestSo1 = filelib:last_modified("priv/test.so"),
+ ?assert(TestSo1 > 0),
+ wait(),
+ %% nothing happens during second compile
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ TestSo2 = filelib:last_modified("priv/test.so"),
+ Test1o2 = filelib:last_modified("c_src/test1.o"),
+ Test2o2 = filelib:last_modified("c_src/test2.o"),
+ ?assertEqual(TestSo1, TestSo2),
+ ?assert(TestSo1 >= Test1o2),
+ ?assert(TestSo1 >= Test2o2),
+ wait(),
+ %% when test2.c changes, at least test2.o and test.so are rebuilt
+ ?assertMatch({ok, _}, retest_sh:run("touch c_src/test2.c", [])),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ TestSo3 = filelib:last_modified("priv/test.so"),
+ Test2o3 = filelib:last_modified("c_src/test2.o"),
+ ?assert(TestSo3 > TestSo2),
+ ?assert(Test2o3 > TestSo2),
+ wait(),
+ %% when test2.h changes, at least test2.o and test.so are rebuilt
+ ?assertMatch({ok, _}, retest_sh:run("touch c_src/test2.h", [])),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ TestSo4 = filelib:last_modified("priv/test.so"),
+ Test2o4 = filelib:last_modified("c_src/test2.o"),
+ ?assert(TestSo4 > TestSo3),
+ ?assert(Test2o4 > TestSo3),
+ wait(),
+ %% when test1.h changes, everything is rebuilt
+ ?assertMatch({ok, _}, retest_sh:run("touch c_src/test1.h", [])),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ TestSo5 = filelib:last_modified("priv/test.so"),
+ Test1o5 = filelib:last_modified("c_src/test1.o"),
+ Test2o5 = filelib:last_modified("c_src/test2.o"),
+ ?assert(TestSo5 > TestSo4),
+ ?assert(Test1o5 > TestSo4),
+ ?assert(Test2o5 > TestSo4),
+ ok.
+
+wait() ->
+ timer:sleep(1000).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/port/rebar.config rebar-2.6.0/inttest/port/rebar.config
--- rebar-2.0.0/inttest/port/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/port/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{port_specs, [{"priv/test.so", ["c_src/*.c"]}]}.
diff -Nru rebar-2.0.0/inttest/profile/profile_rt.erl rebar-2.6.0/inttest/profile/profile_rt.erl
--- rebar-2.0.0/inttest/profile/profile_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/profile/profile_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,192 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(profile_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"}
+ ].
+
+run(_Dir) ->
+ Cmd = "./rebar list-deps",
+ FprofFiles = fprof_files(),
+ EflameFiles = ["eflame.trace", "eflame.svg"],
+
+ %% run a simple command (list-deps) without profiling
+ SharedExpected = "==> profile_rt \\(list-deps\\)",
+ %% run Cmd without profiling
+ retest:log(info, "Check '~s' without profiling~n", [Cmd]),
+ ok = check(Cmd, should_succeed, [SharedExpected], ["Profiling!"],
+ [], FprofFiles ++ EflameFiles),
+
+ %% run Cmd with fprof profiling
+ retest:log(info, "Check '~s' with fprof profiling~n", [Cmd]),
+ ok = check(Cmd ++ " -p", should_succeed,
+ [SharedExpected, "Profiling!", "See fprof\.analysis"],
+ ["See eflame\.svg"],
+ FprofFiles, EflameFiles),
+ delete_files(FprofFiles),
+
+ %% run Cmd with explicitly selected fprof profiling
+ retest:log(info, "Check '~s' with explicitly selected fprof profiling~n",
+ [Cmd]),
+ ok = check(Cmd ++ " -p profiler=fprof", should_succeed,
+ [SharedExpected, "Profiling!", "See fprof\.analysis"],
+ ["See eflame\.svg"],
+ FprofFiles, EflameFiles),
+ delete_files(FprofFiles),
+
+ case code:lib_dir(eflame) of
+ {error, bad_name} ->
+ retest:log(info,
+ "eflame not found in code path. skip eflame test~n"),
+ ok;
+ _EflameDir ->
+ %% run Cmd with eflame profiling
+ retest:log(info, "Check '~s' with eflame profiling~n", [Cmd]),
+ ok = check(Cmd ++ " -p profiler=eflame", should_succeed,
+ [SharedExpected, "Profiling!", "See eflame\.svg"],
+ ["See fprof\.analysis"],
+ EflameFiles, FprofFiles),
+ delete_files(EflameFiles)
+ end,
+
+ ok.
+
+fprof_files() ->
+ FprofFiles = ["fprof.trace", "fprof.analysis"],
+ CgrindFiles = ["fprof.cgrind"],
+ case os:find_executable("erlgrind") of
+ false ->
+ retest:log(info,
+ "erlgrind escript not found. skip fprof.cgrind check~n"),
+ FprofFiles;
+ _ErlGrind ->
+ FprofFiles ++ CgrindFiles
+ end.
+
+check(Cmd, FailureMode, ExpectedOutput, UnexpectedOutput,
+ ExpectedFiles, UnexpectedFiles) ->
+ case {retest:sh(Cmd), FailureMode} of
+ {{error, _}=Error, should_succeed} ->
+ retest:log(error, "cmd '~s' failed:~n~p~n", [Cmd, Error]),
+ Error;
+ {{ok, CapturedOutput}, should_succeed} ->
+ JoinedOutput = string:join(CapturedOutput, "\n"),
+ check1(Cmd, JoinedOutput, ExpectedOutput, UnexpectedOutput,
+ ExpectedFiles, UnexpectedFiles);
+ {{error, {stopped, {_Rc, CapturedOutput}}}, should_fail} ->
+ JoinedOutput = string:join(CapturedOutput, "\n"),
+ check1(Cmd, JoinedOutput, ExpectedOutput, UnexpectedOutput,
+ ExpectedFiles, UnexpectedFiles)
+ end.
+
+check1(Cmd, CapturedOutput, ExpectedOutput, UnexpectedOutput,
+ ExpectedFiles, UnexpectedFiles) ->
+ ReOpts = [{capture, all, list}],
+ ExMatches =
+ lists:zf(
+ fun(Pattern) ->
+ case re:run(CapturedOutput, Pattern, ReOpts) of
+ nomatch ->
+ retest:log(error,
+ "Expected pattern '~s' missing "
+ "in the following output:~n"
+ "=== BEGIN ===~n~s~n=== END ===~n",
+ [Pattern, CapturedOutput]),
+ {true, Pattern};
+ {match, _} ->
+ false
+ end
+ end, ExpectedOutput),
+
+ UnExMatches =
+ lists:zf(
+ fun(Pattern) ->
+ case re:run(CapturedOutput, Pattern, ReOpts) of
+ nomatch ->
+ false;
+ {match, [Match]} ->
+ retest:log(
+ console,
+ "Unexpected output when running cmd '~s':~n~s~n",
+ [Cmd, Match]),
+ {true, Match}
+ end
+ end, UnexpectedOutput),
+
+ ExFiles =
+ lists:zf(
+ fun(File) ->
+ case filelib:is_regular(File) of
+ true ->
+ false;
+ false ->
+ retest:log(error,
+ "Expected file missing: ~s~n", [File]),
+ {true, File}
+ end
+ end, ExpectedFiles),
+
+ UnExFiles =
+ lists:zf(
+ fun(File) ->
+ case filelib:is_regular(File) of
+ true ->
+ retest:log(error,
+ "Unexpected file found: ~s~n", [File]),
+ {true, File};
+ false ->
+ false
+ end
+ end, UnexpectedFiles),
+
+ case {ExMatches, UnExMatches, ExFiles, UnExFiles} of
+ {[], [], [], []} ->
+ ok;
+ _ ->
+ error
+ end.
+
+delete_files(Files) ->
+ lists:foreach(fun(File) -> ok = file:delete(File) end, Files).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/proto_gpb/include/.gitignore rebar-2.6.0/inttest/proto_gpb/include/.gitignore
--- rebar-2.0.0/inttest/proto_gpb/include/.gitignore 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/include/.gitignore 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
diff -Nru rebar-2.0.0/inttest/proto_gpb/mock/gpb/src/gpb.app.src rebar-2.6.0/inttest/proto_gpb/mock/gpb/src/gpb.app.src
--- rebar-2.0.0/inttest/proto_gpb/mock/gpb/src/gpb.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/mock/gpb/src/gpb.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,9 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+
+{application, gpb,
+ [{description, "Simple mock of gpb, with enough to generate dummy files"},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [kernel, stdlib]},
+ {env, []}]}.
diff -Nru rebar-2.0.0/inttest/proto_gpb/mock/gpb/src/gpb_compile.erl rebar-2.6.0/inttest/proto_gpb/mock/gpb/src/gpb_compile.erl
--- rebar-2.0.0/inttest/proto_gpb/mock/gpb/src/gpb_compile.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/mock/gpb/src/gpb_compile.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,78 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 Tomas Abrahamsson (tomas.abrahamsson@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(gpb_compile).
+-export([file/2]).
+
+%% Simulate gpb compiling some proto files,
+%% but generate only enough of what's needed for testing -- dummy stuff only.
+%% if a bad.proto file is supplied then gpb fails
+file(Proto, Opts) ->
+ ok = case filename:basename(Proto) of
+ "bad.proto" -> error;
+ _ -> ok
+ end,
+ Prefix = proplists:get_value(module_name_prefix, Opts, ""),
+ Suffix = proplists:get_value(module_name_suffix, Opts, ""),
+ ProtoBase = filename:basename(Proto, ".proto"),
+ ModBase = Prefix ++ ProtoBase ++ Suffix,
+ ErlDest = filename:join(get_erl_outdir(Opts), ModBase ++ ".erl"),
+ HrlDest = filename:join(get_hrl_outdir(Opts), ModBase ++ ".hrl"),
+ ok = file:write_file(ErlDest, erl_text(ModBase)),
+ ok = file:write_file(HrlDest, hrl_text(ModBase)).
+
+erl_text(ModBase) ->
+ io_lib:format(
+ lines(["-module(~p).",
+ "-export([encode_msg/1]).",
+ "-export([decode_msg/2]).",
+ "",
+ "encode_msg(some_dummy_msg) -> <<1,2,3>>.",
+ "",
+ "decode_msg(<<1,2,3>>, _) -> some_dummy_msg."]),
+ [list_to_atom(ModBase)]).
+
+hrl_text(ModBase) ->
+ io_lib:format(
+ lines(["-ifndef(~s_hrl).",
+ "-define(~s_hrl, true).",
+ "",
+ "%% some record definitions would normally go here...",
+ ""
+ "-endif. %% ~s_hrl"]),
+ [ModBase, ModBase, ModBase]).
+
+get_erl_outdir(Opts) ->
+ proplists:get_value(o_erl, Opts, get_outdir(Opts)).
+
+get_hrl_outdir(Opts) ->
+ proplists:get_value(o_hrl, Opts, get_outdir(Opts)).
+
+get_outdir(Opts) ->
+ proplists:get_value(o, Opts, ".").
+
+lines(Lines) ->
+ lists:flatten([[L, $\n] || L <- Lines]).
diff -Nru rebar-2.0.0/inttest/proto_gpb/mock/gpb/src/gpb.erl rebar-2.6.0/inttest/proto_gpb/mock/gpb/src/gpb.erl
--- rebar-2.0.0/inttest/proto_gpb/mock/gpb/src/gpb.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/mock/gpb/src/gpb.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+
+-module(gpb).
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto/a/b/test3.proto rebar-2.6.0/inttest/proto_gpb/proto/a/b/test3.proto
--- rebar-2.0.0/inttest/proto_gpb/proto/a/b/test3.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto/a/b/test3.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test3;
+
+service test3
+{
+ rpc testRpc3(RPC_INPUT3) returns (RPC_OUTPUT3);
+}
+
+message RPC_INPUT3
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT3
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto/a/test2.proto rebar-2.6.0/inttest/proto_gpb/proto/a/test2.proto
--- rebar-2.0.0/inttest/proto_gpb/proto/a/test2.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto/a/test2.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test2;
+
+service test2
+{
+ rpc testRpc2(RPC_INPUT2) returns (RPC_OUTPUT2);
+}
+
+message RPC_INPUT2
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT2
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto/c/d/test5.proto rebar-2.6.0/inttest/proto_gpb/proto/c/d/test5.proto
--- rebar-2.0.0/inttest/proto_gpb/proto/c/d/test5.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto/c/d/test5.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test5;
+
+service test5
+{
+ rpc testRpc5(RPC_INPUT5) returns (RPC_OUTPUT5);
+}
+
+message RPC_INPUT5
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT5
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto/c/test4.proto rebar-2.6.0/inttest/proto_gpb/proto/c/test4.proto
--- rebar-2.0.0/inttest/proto_gpb/proto/c/test4.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto/c/test4.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test4;
+
+service test4
+{
+ rpc testRpc4(RPC_INPUT4) returns (RPC_OUTPUT4);
+}
+
+message RPC_INPUT4
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT4
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto/test.proto rebar-2.6.0/inttest/proto_gpb/proto/test.proto
--- rebar-2.0.0/inttest/proto_gpb/proto/test.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto/test.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test;
+
+service test
+{
+ rpc testRpc(RPC_INPUT) returns (RPC_OUTPUT);
+}
+
+message RPC_INPUT
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto.bad/a/b/test3.proto rebar-2.6.0/inttest/proto_gpb/proto.bad/a/b/test3.proto
--- rebar-2.0.0/inttest/proto_gpb/proto.bad/a/b/test3.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto.bad/a/b/test3.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test3;
+
+service test3
+{
+ rpc testRpc3(RPC_INPUT3) returns (RPC_OUTPUT3);
+}
+
+message RPC_INPUT3
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT3
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto.bad/a/test2.proto rebar-2.6.0/inttest/proto_gpb/proto.bad/a/test2.proto
--- rebar-2.0.0/inttest/proto_gpb/proto.bad/a/test2.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto.bad/a/test2.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test2;
+
+service test2
+{
+ rpc testRpc2(RPC_INPUT2) returns (RPC_OUTPUT2);
+}
+
+message RPC_INPUT2
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT2
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto.bad/bad.proto rebar-2.6.0/inttest/proto_gpb/proto.bad/bad.proto
--- rebar-2.0.0/inttest/proto_gpb/proto.bad/bad.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto.bad/bad.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test;
+
+service test
+{
+ rpc testRpc(RPC_INPUT) returns (RPC_OUTPUT);
+}
+
+message RPC_INPUT
+ // bug introduced intentionally here
+ optional string str = 1;
+}
+
+message RPC_OUTPUT
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto.bad/c/d/test5.proto rebar-2.6.0/inttest/proto_gpb/proto.bad/c/d/test5.proto
--- rebar-2.0.0/inttest/proto_gpb/proto.bad/c/d/test5.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto.bad/c/d/test5.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test5;
+
+service test5
+{
+ rpc testRpc5(RPC_INPUT5) returns (RPC_OUTPUT5);
+}
+
+message RPC_INPUT5
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT5
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto.bad/c/test4.proto rebar-2.6.0/inttest/proto_gpb/proto.bad/c/test4.proto
--- rebar-2.0.0/inttest/proto_gpb/proto.bad/c/test4.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto.bad/c/test4.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test4;
+
+service test4
+{
+ rpc testRpc4(RPC_INPUT4) returns (RPC_OUTPUT4);
+}
+
+message RPC_INPUT4
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT4
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto.bad/test.proto rebar-2.6.0/inttest/proto_gpb/proto.bad/test.proto
--- rebar-2.0.0/inttest/proto_gpb/proto.bad/test.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto.bad/test.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test;
+
+service test
+{
+ rpc testRpc(RPC_INPUT) returns (RPC_OUTPUT);
+}
+
+message RPC_INPUT
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/proto_gpb_rt.erl rebar-2.6.0/inttest/proto_gpb/proto_gpb_rt.erl
--- rebar-2.0.0/inttest/proto_gpb/proto_gpb_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/proto_gpb_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,204 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Luis Rascão (luis.rascao@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(proto_gpb_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("kernel/include/file.hrl").
+-include_lib("deps/retest/include/retest.hrl").
+
+-define(MODULES,
+ [foo,
+ foo_app,
+ foo_sup]).
+
+-define(GENERATED_MODULES,
+ [test_gpb,
+ test2_gpb,
+ test3_gpb,
+ test4_gpb,
+ test5_gpb]).
+
+-define(SOURCE_PROTO_FILES,
+ ["test.proto",
+ "a/test2.proto",
+ "a/b/test3.proto",
+ "c/test4.proto",
+ "c/d/test5.proto"]).
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "rebar2.config", "rebar2.config"},
+ {copy, "rebar.bad.config", "rebar.bad.config"},
+ {copy, "include", "include"},
+ {copy, "src", "src"},
+ {copy, "proto", "proto"},
+ {copy, "proto.bad", "proto.bad"},
+ {copy, "mock", "deps"},
+ {create, "ebin/foo.app", app(foo, ?MODULES ++ ?GENERATED_MODULES)}
+ ].
+
+run(_Dir) ->
+ % perform test obtaining the .proto files from src dir
+ ok = run_from_dir(success_expected, "src", "rebar.config"),
+ % perform test obtaining the .proto files from proto dir
+ ok = run_from_dir(success_expected, "proto", "rebar2.config"),
+ % perform a test where a failure is expected
+ ok = run_from_dir(fail_expected, "proto.bad", "rebar.bad.config").
+
+run_from_dir(fail_expected, _ProtoDir, ConfigFile) ->
+ %% we expect a failure to happen, however rebar should not crash;
+ %% We make sure of that by scanning the error.
+ {error, {stopped, {1, Error}}} = retest_sh:run("./rebar --config "
+ ++ ConfigFile
+ ++ " compile",
+ []),
+ %% No matches of the string 'EXIT' should occur, these
+ %% indicate a rebar crash and not a exit with error.
+ 0 = string:str(lists:flatten(Error), "'EXIT'"),
+ ok;
+run_from_dir(success_expected, ProtoDir, ConfigFile) ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar --config "
+ ++ ConfigFile
+ ++ " clean",
+ [])),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar --config "
+ ++ ConfigFile
+ ++ " compile",
+ [])),
+ %% Foo includes test_gpb.hrl,
+ %% So if it compiled, that also means gpb succeeded in
+ %% generating the test_gpb.hrl file, and also that it generated
+ %% the .hrl file was generated before foo was compiled.
+ ok = check_beams_generated(),
+
+ ?DEBUG("Verifying recompilation~n", []),
+ TestErl = hd(generated_erl_files()),
+ TestProto = hd(source_proto_files(ProtoDir)),
+ make_proto_newer_than_erl(TestProto, TestErl),
+ TestMTime1 = read_mtime(TestErl),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar --config "
+ ++ ConfigFile
+ ++ " compile",
+ [])),
+ TestMTime2 = read_mtime(TestErl),
+ ?assert(TestMTime2 > TestMTime1),
+
+ ?DEBUG("Verifying recompilation with no changes~n", []),
+ TestMTime3 = read_mtime(TestErl),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar --config "
+ ++ ConfigFile
+ ++ " compile",
+ [])),
+ TestMTime4 = read_mtime(TestErl),
+ ?assert(TestMTime3 =:= TestMTime4),
+
+ ?DEBUG("Verify cleanup~n", []),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar --config "
+ ++ ConfigFile
+ ++ " clean",
+ [])),
+ ok = check_files_deleted(),
+ ok.
+
+check_beams_generated() ->
+ check(fun filelib:is_regular/1,
+ beam_files()).
+
+check_files_deleted() ->
+ check(fun file_does_not_exist/1,
+ beam_files() ++ generated_erl_files() ++ generated_hrl_files()).
+
+beam_files() ->
+ add_dir("ebin", add_ext(?MODULES, ".beam")).
+
+generated_erl_files() ->
+ add_dir("src", add_ext(?GENERATED_MODULES, ".erl")).
+
+generated_hrl_files() ->
+ add_dir("include", add_ext(?GENERATED_MODULES, ".hrl")).
+
+generated_beam_files() ->
+ add_dir("ebin", add_ext(?GENERATED_MODULES, ".beam")).
+
+source_proto_files(ProtoDir) ->
+ add_dir(ProtoDir, ?SOURCE_PROTO_FILES).
+
+file_does_not_exist(F) ->
+ not filelib:is_regular(F).
+
+add_ext(Modules, Ext) ->
+ [lists:concat([Module, Ext]) || Module <- Modules].
+
+add_dir(Dir, Files) ->
+ [filename:join(Dir, File) || File <- Files].
+
+read_mtime(File) ->
+ {ok, #file_info{mtime=MTime}} = file:read_file_info(File),
+ MTime.
+
+
+make_proto_newer_than_erl(Proto, Erl) ->
+ %% Do this by back-dating the erl file instead of touching the
+ %% proto file. Do this instead of sleeping for a second to get a
+ %% reliable test. Sleeping would have been needed sin ce the
+ %% #file_info{} (used by eg. filelib:last_modified) does not have
+ %% sub-second resolution (even though most file systems have).
+ {ok, #file_info{mtime=ProtoMTime}} = file:read_file_info(Proto),
+ {ok, ErlInfo} = file:read_file_info(Erl),
+ OlderMTime = update_seconds_to_datetime(ProtoMTime, -2),
+ OlderErlInfo = ErlInfo#file_info{mtime = OlderMTime},
+ ok = file:write_file_info(Erl, OlderErlInfo).
+
+update_seconds_to_datetime(DT, ToAdd) ->
+ calendar:gregorian_seconds_to_datetime(
+ calendar:datetime_to_gregorian_seconds(DT) + ToAdd).
+
+touch_file(File) ->
+ ?assertMatch({ok, _}, retest_sh:run("touch " ++ File, [])).
+
+check(Check, Files) ->
+ lists:foreach(
+ fun(F) ->
+ ?assertMatch({true, _}, {Check(F), F})
+ end,
+ Files).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib, gpb]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/proto_gpb/rebar2.config rebar-2.6.0/inttest/proto_gpb/rebar2.config
--- rebar-2.0.0/inttest/proto_gpb/rebar2.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/rebar2.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,23 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
+{erl_opts,
+ [
+ {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'}
+ ]}.
+
+{deps,
+ [
+ %% The dependency below to gpb is needed for "rebar compile" to
+ %% work, thus for the inttest to work, but the gpb that is actually
+ %% used in inttest is brought in from the inttest/proto_gpb/mock
+ %% subdirectory.
+ {gpb, ".*"}
+ ]}.
+
+{proto_opts, [
+ {compiler, gpb},
+ {src_dirs, ["proto"]}
+]}.
+
+{gpb_opts, [{module_name_suffix, "_gpb"}]}.
diff -Nru rebar-2.0.0/inttest/proto_gpb/rebar.bad.config rebar-2.6.0/inttest/proto_gpb/rebar.bad.config
--- rebar-2.0.0/inttest/proto_gpb/rebar.bad.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/rebar.bad.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,23 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
+{erl_opts,
+ [
+ {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'}
+ ]}.
+
+{deps,
+ [
+ %% The dependency below to gpb is needed for "rebar compile" to
+ %% work, thus for the inttest to work, but the gpb that is actually
+ %% used in inttest is brought in from the inttest/proto_gpb/mock
+ %% subdirectory.
+ {gpb, ".*"}
+ ]}.
+
+{proto_opts, [
+ {compiler, gpb},
+ {src_dirs, ["proto.bad"]}
+]}.
+
+{gpb_opts, [{module_name_suffix, "_gpb"}]}.
diff -Nru rebar-2.0.0/inttest/proto_gpb/rebar.config rebar-2.6.0/inttest/proto_gpb/rebar.config
--- rebar-2.0.0/inttest/proto_gpb/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,22 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
+{erl_opts,
+ [
+ {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'}
+ ]}.
+
+{deps,
+ [
+ %% The dependency below to gpb is needed for "rebar compile" to
+ %% work, thus for the inttest to work, but the gpb that is actually
+ %% used in inttest is brought in from the inttest/proto_gpb/mock
+ %% subdirectory.
+ {gpb, ".*"}
+ ]}.
+
+{proto_opts, [
+ {compiler, gpb}
+]}.
+
+{gpb_opts, [{module_name_suffix, "_gpb"}]}.
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/a/b/test3.proto rebar-2.6.0/inttest/proto_gpb/src/a/b/test3.proto
--- rebar-2.0.0/inttest/proto_gpb/src/a/b/test3.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/a/b/test3.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test3;
+
+service test3
+{
+ rpc testRpc3(RPC_INPUT3) returns (RPC_OUTPUT3);
+}
+
+message RPC_INPUT3
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT3
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/a/test2.proto rebar-2.6.0/inttest/proto_gpb/src/a/test2.proto
--- rebar-2.0.0/inttest/proto_gpb/src/a/test2.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/a/test2.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test2;
+
+service test2
+{
+ rpc testRpc2(RPC_INPUT2) returns (RPC_OUTPUT2);
+}
+
+message RPC_INPUT2
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT2
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/c/d/test5.proto rebar-2.6.0/inttest/proto_gpb/src/c/d/test5.proto
--- rebar-2.0.0/inttest/proto_gpb/src/c/d/test5.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/c/d/test5.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test5;
+
+service test5
+{
+ rpc testRpc5(RPC_INPUT5) returns (RPC_OUTPUT5);
+}
+
+message RPC_INPUT5
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT5
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/c/test4.proto rebar-2.6.0/inttest/proto_gpb/src/c/test4.proto
--- rebar-2.0.0/inttest/proto_gpb/src/c/test4.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/c/test4.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test4;
+
+service test4
+{
+ rpc testRpc4(RPC_INPUT4) returns (RPC_OUTPUT4);
+}
+
+message RPC_INPUT4
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT4
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/foo_app.erl rebar-2.6.0/inttest/proto_gpb/src/foo_app.erl
--- rebar-2.0.0/inttest/proto_gpb/src/foo_app.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/foo_app.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(foo_app).
+
+-behaviour(application).
+
+-export([start/2,
+ stop/1]).
+
+start(_Type, _Args) -> foo_sup:start_link().
+
+stop(_State) -> ok.
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/foo.erl rebar-2.6.0/inttest/proto_gpb/src/foo.erl
--- rebar-2.0.0/inttest/proto_gpb/src/foo.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/foo.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,39 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(foo).
+
+-export([start_link/0,
+ start_link/1,
+ init/1,
+ terminate/2,
+ handle_info/2,
+ handle_call/3,
+ handle_cast/2,
+ code_change/3]).
+
+-behavior(gen_server).
+
+-include("../include/test_gpb.hrl").
+-include("../include/test2_gpb.hrl").
+-include("../include/test3_gpb.hrl").
+-include("../include/test4_gpb.hrl").
+-include("../include/test5_gpb.hrl").
+
+-record(state, {node :: node()}).
+
+start_link() -> start_link(undefined).
+
+start_link(Args) ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).
+
+init(_Args) -> {ok, #state{node=node()}}.
+
+terminate(_Reason, _Data) -> ok.
+
+handle_info(_Info, State) -> {noreply, State}.
+
+handle_cast(_Msg, State) -> {noreply, State}.
+
+handle_call(_Msg, _From, State) -> {reply, ok, State}.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/foo_sup.erl rebar-2.6.0/inttest/proto_gpb/src/foo_sup.erl
--- rebar-2.0.0/inttest/proto_gpb/src/foo_sup.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/foo_sup.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,15 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(foo_sup).
+
+-behavior(supervisor).
+
+-export([start_link/0,
+ init/1]).
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init(_Args) ->
+ FooChild = {foo,{foo, start_link, []}, permanent, 5000, worker, [foo]},
+ {ok,{{one_for_all,1,1}, [FooChild]}}.
diff -Nru rebar-2.0.0/inttest/proto_gpb/src/test.proto rebar-2.6.0/inttest/proto_gpb/src/test.proto
--- rebar-2.0.0/inttest/proto_gpb/src/test.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_gpb/src/test.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,19 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+package test;
+
+service test
+{
+ rpc testRpc(RPC_INPUT) returns (RPC_OUTPUT);
+}
+
+message RPC_INPUT
+{
+ optional string str = 1;
+}
+
+message RPC_OUTPUT
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/include/.gitignore rebar-2.6.0/inttest/proto_protobuffs/include/.gitignore
--- rebar-2.0.0/inttest/proto_protobuffs/include/.gitignore 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/include/.gitignore 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+# Ignore everything in this directory
+*
+# Except this file
+!.gitignore
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.app.src rebar-2.6.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.app.src
--- rebar-2.0.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,10 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+
+{application, protobuffs,
+ [{description,
+ "Simple mock of erlang_protobuffs, with enough to generate dummy files"},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [kernel, stdlib]},
+ {env, []}]}.
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs_compile.erl rebar-2.6.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs_compile.erl
--- rebar-2.0.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs_compile.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs_compile.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,68 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2015 Tomas Abrahamsson (tomas.abrahamsson@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(protobuffs_compile).
+-export([scan_file/2]).
+
+%% Simulate protobuffs compiling some proto files,
+%% but generate only enough of what's needed for testing -- dummy stuff only.
+scan_file(Proto, _Opts) ->
+ ProtoBase = filename:basename(Proto, ".proto"),
+ ModBase = ProtoBase ++ "_pb",
+ BeamDest = filename:join(get_beam_outdir(), ModBase ++ ".beam"),
+ HrlDest = filename:join(get_hrl_outdir(), ModBase ++ ".hrl"),
+ ok = file:write_file(BeamDest, beam_text(ModBase)),
+ ok = file:write_file(HrlDest, hrl_text(ModBase)).
+
+beam_text(ModBase) ->
+ Mod = list_to_atom(ModBase),
+ Forms = [mk_attr(module, Mod)], % just a -module(...). line
+ {ok, Mod, Bin} = compile:forms(Forms),
+ Bin.
+
+mk_attr(AttrName, AttrValue) ->
+ erl_syntax:revert(
+ erl_syntax:attribute(erl_syntax:atom(AttrName),
+ [erl_syntax:abstract(AttrValue)])).
+
+hrl_text(ModBase) ->
+ io_lib:format(
+ lines(["-ifndef(~s_hrl).",
+ "-define(~s_hrl, true).",
+ "",
+ "%% some record definitions would normally go here...",
+ ""
+ "-endif. %% ~s_hrl"]),
+ [ModBase, ModBase, ModBase]).
+
+get_beam_outdir() ->
+ ".".
+
+get_hrl_outdir() ->
+ ".".
+
+lines(Lines) ->
+ lists:flatten([[L, $\n] || L <- Lines]).
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.erl rebar-2.6.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.erl
--- rebar-2.0.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/mock/protobuffs/src/protobuffs.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+
+-module(protobuffs).
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/proto_protobuffs_rt.erl rebar-2.6.0/inttest/proto_protobuffs/proto_protobuffs_rt.erl
--- rebar-2.0.0/inttest/proto_protobuffs/proto_protobuffs_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/proto_protobuffs_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,79 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tomas Abrahamsson (tomas.abrahamsson@gmail.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(proto_protobuffs_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-define(MODULES,
+ [foo,
+ foo_app,
+ foo_sup,
+ test_pb]).
+
+-define(BEAM_FILES,
+ ["foo.beam",
+ "foo_app.beam",
+ "foo_sup.beam",
+ "test_pb.beam"]).
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "include", "include"},
+ {copy, "src", "src"},
+ {copy, "mock", "deps"},
+ {create, "ebin/foo.app", app(foo, ?MODULES)}
+ ].
+
+run(_Dir) ->
+ ?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
+ ok = check_beams_generated(),
+ ok.
+
+check_beams_generated() ->
+ lists:foreach(
+ fun(F) ->
+ File = filename:join("ebin", F),
+ ?assert(filelib:is_regular(File))
+ end,
+ ?BEAM_FILES).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib, gpb]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/rebar.config rebar-2.6.0/inttest/proto_protobuffs/rebar.config
--- rebar-2.0.0/inttest/proto_protobuffs/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,20 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
+{erl_opts,
+ [
+ {platform_define, "R13|R14", 'NO_CALLBACK_ATTRIBUTE'}
+ ]}.
+
+{deps,
+ [
+ %% The dependency below to protobuffs is needed for "rebar compile" to
+ %% work, thus for the inttest to work, but the protobuffs that is actually
+ %% used in inttest is brought in from the inttest/proto_protobuffs/mock
+ %% subdirectory.
+ {protobuffs, ".*"}
+ ]}.
+
+%% The default proto compiler is protobuffs
+%% so don't need to specify this
+%% {proto_compiler, protobuffs}.
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/src/foo_app.erl rebar-2.6.0/inttest/proto_protobuffs/src/foo_app.erl
--- rebar-2.0.0/inttest/proto_protobuffs/src/foo_app.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/src/foo_app.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(foo_app).
+
+-behaviour(application).
+
+-export([start/2,
+ stop/1]).
+
+start(_Type, _Args) -> foo_sup:start_link().
+
+stop(_State) -> ok.
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/src/foo.erl rebar-2.6.0/inttest/proto_protobuffs/src/foo.erl
--- rebar-2.0.0/inttest/proto_protobuffs/src/foo.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/src/foo.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,35 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(foo).
+
+-export([start_link/0,
+ start_link/1,
+ init/1,
+ terminate/2,
+ handle_info/2,
+ handle_call/3,
+ handle_cast/2,
+ code_change/3]).
+
+-behavior(gen_server).
+
+-include("../include/test_pb.hrl").
+
+-record(state, {node :: node()}).
+
+start_link() -> start_link(undefined).
+
+start_link(Args) ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, Args, []).
+
+init(_Args) -> {ok, #state{node=node()}}.
+
+terminate(_Reason, _Data) -> ok.
+
+handle_info(_Info, State) -> {noreply, State}.
+
+handle_cast(_Msg, State) -> {noreply, State}.
+
+handle_call(_Msg, _From, State) -> {reply, ok, State}.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/src/foo_sup.erl rebar-2.6.0/inttest/proto_protobuffs/src/foo_sup.erl
--- rebar-2.0.0/inttest/proto_protobuffs/src/foo_sup.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/src/foo_sup.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,15 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(foo_sup).
+
+-behavior(supervisor).
+
+-export([start_link/0,
+ init/1]).
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init(_Args) ->
+ FooChild = {foo,{foo, start_link, []}, permanent, 5000, worker, [foo]},
+ {ok,{{one_for_all,1,1}, [FooChild]}}.
diff -Nru rebar-2.0.0/inttest/proto_protobuffs/src/test.proto rebar-2.6.0/inttest/proto_protobuffs/src/test.proto
--- rebar-2.0.0/inttest/proto_protobuffs/src/test.proto 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/proto_protobuffs/src/test.proto 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,12 @@
+// -*- c-basic-offset: 4; indent-tabs-mode: nil -*-
+// ex: ts=4 sw=4 et
+
+message m1
+{
+ optional string str = 1;
+}
+
+message m2
+{
+ optional string str = 1;
+}
diff -Nru rebar-2.0.0/inttest/require_vsn/rebar.config rebar-2.6.0/inttest/require_vsn/rebar.config
--- rebar-2.0.0/inttest/require_vsn/rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/require_vsn/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+{require_erts_vsn, "no_such_erts_vsn-1.2"}.
+{require_otp_vsn, "no_such_otp_vsn-1.2"}.
+{require_min_otp_vsn, "no_such_min_otp_vsn-1.0"}.
diff -Nru rebar-2.0.0/inttest/require_vsn/require_vsn_rt.erl rebar-2.6.0/inttest/require_vsn/require_vsn_rt.erl
--- rebar-2.0.0/inttest/require_vsn/require_vsn_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/require_vsn/require_vsn_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,115 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(require_vsn_rt).
+-export([files/0,
+ run/1]).
+
+files() ->
+ [
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {create, "ebin/require_vsn.app", app(require_vsn, [])}
+ ].
+
+run(_Dir) ->
+ SharedExpected = "==> require_vsn_rt \\(compile\\)",
+ %% Provoke ABORT due to failed require vsn check.
+ retest:log(info, "Check require vsn failure~n"),
+ ok = check_output("./rebar compile", should_fail,
+ [SharedExpected, "ERROR: "],
+ ["WARN: "]),
+ %% Treat version constraints as warnings.
+ retest:log(info, "Check require vsn success with -k/--keep-going~n"),
+ ok = check_output("./rebar -k compile", should_succeed,
+ [SharedExpected, "ERROR: "],
+ ["WARN: "]),
+ ok.
+
+check_output(Cmd, FailureMode, Expected, Unexpected) ->
+ case {retest:sh(Cmd), FailureMode} of
+ {{error, _}=Error, should_succeed} ->
+ retest:log(error, "cmd '~s' failed:~n~p~n", [Cmd, Error]),
+ Error;
+ {{ok, Captured}, should_succeed} ->
+ Joined = string:join(Captured, "\n"),
+ check_output1(Cmd, Joined, Expected, Unexpected);
+ {{error, {stopped, {_Rc, Captured}}}, should_fail} ->
+ Joined = string:join(Captured, "\n"),
+ check_output1(Cmd, Joined, Expected, Unexpected)
+ end.
+
+check_output1(Cmd, Captured, Expected, Unexpected) ->
+ ReOpts = [{capture, all, list}],
+ ExMatches =
+ lists:zf(
+ fun(Pattern) ->
+ case re:run(Captured, Pattern, ReOpts) of
+ nomatch ->
+ retest:log(error,
+ "Expected pattern '~s' missing "
+ "in the following output:~n"
+ "=== BEGIN ===~n~s~n=== END ===~n",
+ [Pattern, Captured]),
+ {true, Pattern};
+ {match, _} ->
+ false
+ end
+ end, Expected),
+
+ UnExMatches =
+ lists:zf(
+ fun(Pattern) ->
+ case re:run(Captured, Pattern, ReOpts) of
+ nomatch ->
+ false;
+ {match, [Match]} ->
+ retest:log(
+ console,
+ "Unexpected output when running cmd '~s':~n~s~n",
+ [Cmd, Match]),
+ {true, Match}
+ end
+ end, Unexpected),
+
+ case {ExMatches, UnExMatches} of
+ {[], []} ->
+ ok;
+ _ ->
+ error
+ end.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
Binary files /tmp/tmpDfMbnv/3RQpdXjcS8/rebar-2.0.0/inttest/retest and /tmp/tmpDfMbnv/2bJx_Hzbkj/rebar-2.6.0/inttest/retest differ
diff -Nru rebar-2.0.0/inttest/rgen1/retest.config rebar-2.6.0/inttest/rgen1/retest.config
--- rebar-2.0.0/inttest/rgen1/retest.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/rgen1/retest.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{timeout, 120000}.
diff -Nru rebar-2.0.0/inttest/rgen1/rgen1_rt.erl rebar-2.6.0/inttest/rgen1/rgen1_rt.erl
--- rebar-2.0.0/inttest/rgen1/rgen1_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/rgen1/rgen1_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(rgen1_rt).
-compile(export_all).
diff -Nru rebar-2.0.0/inttest/t_custom_config/custom.config rebar-2.6.0/inttest/t_custom_config/custom.config
--- rebar-2.0.0/inttest/t_custom_config/custom.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/t_custom_config/custom.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,4 +1,3 @@
-
{deps, [
{boo, "."}
]}.
diff -Nru rebar-2.0.0/inttest/t_custom_config/t_custom_config_rt.erl rebar-2.6.0/inttest/t_custom_config/t_custom_config_rt.erl
--- rebar-2.0.0/inttest/t_custom_config/t_custom_config_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/t_custom_config/t_custom_config_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(t_custom_config_rt).
-compile(export_all).
@@ -11,16 +13,17 @@
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 -vv",
+ [{async, true}]),
{ok, Captured} =
retest:sh_expect(Ref,
"DEBUG: Consult config file .*/custom.config.*",
[{capture, all, list}]),
{ok, Missing} =
retest:sh_expect(Ref,
- "DEBUG: Missing deps : \\[\\{dep,bad_name,"
- "boo,\"\\.\",undefined\\}\\]",
- [{capture, all, list}]),
+ "DEBUG: Missing deps : \\[\\{dep,bad_name,"
+ "boo,\"\\.\",undefined,false\\}\\]",
+ [{capture, all, list}]),
retest_log:log(debug, "[CAPTURED]: ~s~n", [Captured]),
retest_log:log(debug, "[Missing]: ~s~n", [Missing]),
ok.
diff -Nru rebar-2.0.0/inttest/tdeps1/a.erl rebar-2.6.0/inttest/tdeps1/a.erl
--- rebar-2.0.0/inttest/tdeps1/a.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps1/a.erl 2015-06-19 16:14:28.000000000 +0000
@@ -6,4 +6,3 @@
hello() ->
io:format("~s\n", [?HELLO]).
-
diff -Nru rebar-2.0.0/inttest/tdeps1/a.rebar.config rebar-2.6.0/inttest/tdeps1/a.rebar.config
--- rebar-2.0.0/inttest/tdeps1/a.rebar.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps1/a.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1 @@
-{deps, [{b, "1", {hg, "../repo/b", "tip"}}]}.
-
+{deps, [{b, "1", {git, "../repo/b"}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps1/b.hrl rebar-2.6.0/inttest/tdeps1/b.hrl
--- rebar-2.0.0/inttest/tdeps1/b.hrl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps1/b.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1 @@
-
-include_lib("c/include/c.hrl").
-
diff -Nru rebar-2.0.0/inttest/tdeps1/b.rebar.config rebar-2.6.0/inttest/tdeps1/b.rebar.config
--- rebar-2.0.0/inttest/tdeps1/b.rebar.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps1/b.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1 @@
-{deps, [{c, "1", {hg, "../repo/c", "tip"}}]}.
-
+{deps, [{c, "1", {git, "../repo/c"}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps1/c.hrl rebar-2.6.0/inttest/tdeps1/c.hrl
--- rebar-2.0.0/inttest/tdeps1/c.hrl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps1/c.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1 @@
-define(HELLO, hello).
-
diff -Nru rebar-2.0.0/inttest/tdeps1/tdeps1_rt.erl rebar-2.6.0/inttest/tdeps1/tdeps1_rt.erl
--- rebar-2.0.0/inttest/tdeps1/tdeps1_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps1/tdeps1_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(tdeps1_rt).
-compile(export_all).
@@ -23,21 +25,30 @@
{copy, "c.hrl", "repo/c/include/c.hrl"}
].
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
run(_Dir) ->
- %% Initialize the b/c apps as mercurial repos so that dependencies pull
+ %% Initialize the b/c apps as git repos so that dependencies pull
%% properly
- HgCmd = "/bin/sh -c \"hg init && hg add && hg commit -m 'Initial commit'\"",
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/b"}]),
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/c"}]),
-
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ apply_cmds(GitCmds, [{dir, "repo/c"}]),
- {ok, _} = retest_sh:run("./rebar get-deps compile", []),
+ {ok, _} = retest_sh:run("./rebar get-deps", []),
+ {ok, _} = retest_sh:run("./rebar compile", []),
true = filelib:is_regular("ebin/a.beam"),
ok.
-
-
%%
%% Generate the contents of a simple .app file
%%
diff -Nru rebar-2.0.0/inttest/tdeps2/a.erl rebar-2.6.0/inttest/tdeps2/a.erl
--- rebar-2.0.0/inttest/tdeps2/a.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps2/a.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,4 +1,3 @@
-module({{module}}).
-include_lib("b/include/b.hrl").
-
diff -Nru rebar-2.0.0/inttest/tdeps2/a.rebar.config rebar-2.6.0/inttest/tdeps2/a.rebar.config
--- rebar-2.0.0/inttest/tdeps2/a.rebar.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps2/a.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1 @@
-{deps, [{b, "1", {hg, "../repo/b", "tip"}}]}.
-
+{deps, [{b, "1", {git, "../repo/b"}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps2/b.hrl rebar-2.6.0/inttest/tdeps2/b.hrl
--- rebar-2.0.0/inttest/tdeps2/b.hrl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps2/b.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1 @@
-
-include_lib("c/include/c.hrl").
-
diff -Nru rebar-2.0.0/inttest/tdeps2/b.rebar.config rebar-2.6.0/inttest/tdeps2/b.rebar.config
--- rebar-2.0.0/inttest/tdeps2/b.rebar.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps2/b.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1 @@
-{deps, [{c, "1", {hg, "../repo/c", "tip"}}]}.
-
+{deps, [{c, "1", {git, "../repo/c"}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps2/c.hrl rebar-2.6.0/inttest/tdeps2/c.hrl
--- rebar-2.0.0/inttest/tdeps2/c.hrl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps2/c.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -1,2 +1 @@
-define(HELLO, hello).
-
diff -Nru rebar-2.0.0/inttest/tdeps2/tdeps2_rt.erl rebar-2.6.0/inttest/tdeps2/tdeps2_rt.erl
--- rebar-2.0.0/inttest/tdeps2/tdeps2_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps2/tdeps2_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(tdeps2_rt).
-compile(export_all).
@@ -31,19 +33,28 @@
{copy, "c.hrl", "repo/c/include/c.hrl"}
].
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
run(_Dir) ->
- %% Initialize the b/c apps as mercurial repos so that dependencies pull
+ %% Initialize the b/c apps as git repos so that dependencies pull
%% properly
- HgCmd = "/bin/sh -c \"hg init && hg add && hg commit -m 'Initial commit'\"",
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/b"}]),
- {ok, _} = retest_sh:run(HgCmd, [{dir, "repo/c"}]),
-
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ ok = apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/c"}]),
- {ok, _} = retest_sh:run("./rebar -v get-deps compile", []),
+ {ok, _} = retest_sh:run("./rebar -v get-deps", []),
+ {ok, _} = retest_sh:run("./rebar -v compile", []),
ok.
-
-
%%
%% Generate the contents of a simple .app file
%%
diff -Nru rebar-2.0.0/inttest/tdeps3/a.erl rebar-2.6.0/inttest/tdeps3/a.erl
--- rebar-2.0.0/inttest/tdeps3/a.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/a.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+-module({{module}}).
+
+-include_lib("{{dep}}/include/{{dep}}.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps3/a.rebar.config rebar-2.6.0/inttest/tdeps3/a.rebar.config
--- rebar-2.0.0/inttest/tdeps3/a.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/a.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+{deps, [
+ {b, "1", {git, "../repo/b"}},
+ {f, "1", {git, "../repo/f"}}
+]}.
diff -Nru rebar-2.0.0/inttest/tdeps3/b.hrl rebar-2.6.0/inttest/tdeps3/b.hrl
--- rebar-2.0.0/inttest/tdeps3/b.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/b.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-include_lib("c/include/c.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps3/b.rebar.config rebar-2.6.0/inttest/tdeps3/b.rebar.config
--- rebar-2.0.0/inttest/tdeps3/b.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/b.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,5 @@
+{deps, [
+ {c, "1", {git, "../repo/c"}}
+]}.
+
+{lib_dirs, [apps]}.
diff -Nru rebar-2.0.0/inttest/tdeps3/c.hrl rebar-2.6.0/inttest/tdeps3/c.hrl
--- rebar-2.0.0/inttest/tdeps3/c.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/c.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-include_lib("d/include/d.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps3/c.rebar.config rebar-2.6.0/inttest/tdeps3/c.rebar.config
--- rebar-2.0.0/inttest/tdeps3/c.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/c.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{d, "1", {git, "../repo/d"}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps3/d.hrl rebar-2.6.0/inttest/tdeps3/d.hrl
--- rebar-2.0.0/inttest/tdeps3/d.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/d.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-include_lib("e/include/e.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps3/d.rebar.config rebar-2.6.0/inttest/tdeps3/d.rebar.config
--- rebar-2.0.0/inttest/tdeps3/d.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/d.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{e, "1", {git, "../repo/e"}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps3/e.hrl rebar-2.6.0/inttest/tdeps3/e.hrl
--- rebar-2.0.0/inttest/tdeps3/e.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/e.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-define(HELLO, hello).
diff -Nru rebar-2.0.0/inttest/tdeps3/f.hrl rebar-2.6.0/inttest/tdeps3/f.hrl
--- rebar-2.0.0/inttest/tdeps3/f.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/f.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-include_lib("e/include/e.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps3/root.rebar.config rebar-2.6.0/inttest/tdeps3/root.rebar.config
--- rebar-2.0.0/inttest/tdeps3/root.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/root.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{sub_dirs, ["apps/a"]}.
diff -Nru rebar-2.0.0/inttest/tdeps3/tdeps3_rt.erl rebar-2.6.0/inttest/tdeps3/tdeps3_rt.erl
--- rebar-2.0.0/inttest/tdeps3/tdeps3_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps3/tdeps3_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,91 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(tdeps3_rt).
+
+-compile(export_all).
+
+%% Exercise transitive dependencies where there are multiple files
+%% depending on the same set of deps as well as lib_dir directives
+%% A -> B -> C -> D -> E
+%% |--> G(via lib_dir)
+%% |--> F -> D -> E
+
+files() ->
+ [
+ %% A1 application
+ {create, "ebin/a.app", app(a, [a])},
+ {template, "a.erl", "src/a.erl", dict:from_list([{module, a}, {dep, b}])},
+
+ {copy, "a.rebar.config", "rebar.config"},
+ {copy, "../../rebar", "rebar"},
+
+ %% B application
+ {create, "repo/b/ebin/b.app", app(b, [b])},
+ {template, "a.erl", "repo/b/src/b.erl", dict:from_list([{module, b}, {dep, b}])},
+ {copy, "b.rebar.config", "repo/b/rebar.config"},
+ {copy, "b.hrl", "repo/b/include/b.hrl"},
+
+ %% C application
+ {create, "repo/c/ebin/c.app", app(c, [c])},
+ {template, "a.erl", "repo/c/src/c.erl", dict:from_list([{module, c}, {dep, d}])},
+ {copy, "c.rebar.config", "repo/c/rebar.config"},
+ {copy, "c.hrl", "repo/c/include/c.hrl"},
+
+ %% D application
+ {create, "repo/d/ebin/d.app", app(d, [d])},
+ {template, "a.erl", "repo/d/src/d.erl", dict:from_list([{module, d}, {dep, e}])},
+ {copy, "d.rebar.config", "repo/d/rebar.config"},
+ {copy, "d.hrl", "repo/d/include/d.hrl"},
+
+ %% E application
+ {create, "repo/e/ebin/e.app", app(e, [])},
+ {copy, "e.hrl", "repo/e/include/e.hrl"},
+
+
+ %% F application
+ {create, "repo/f/ebin/f.app", app(f, [f])},
+ {template, "a.erl", "repo/f/src/f.erl", dict:from_list([{module, f}, {dep, d}])},
+ {copy, "c.rebar.config", "repo/f/rebar.config"},
+ {copy, "f.hrl", "repo/f/include/f.hrl"},
+
+ %% G application, which is part of the B repo, in a lib_dir
+ {create, "repo/b/apps/g/ebin/g.app", app(g, [])},
+ {copy, "e.hrl", "repo/b/apps/g/include/g.hrl"}
+
+ ].
+
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
+run(_Dir) ->
+ %% Initialize the b/c apps as git repos so that dependencies pull
+ %% properly
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ ok = apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/c"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/d"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/e"}]),
+ ok = apply_cmds(GitCmds, [{dir, "repo/f"}]),
+
+ {ok, _} = retest_sh:run("./rebar -v get-deps compile", []),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/tdeps_update/a2.rebar.config rebar-2.6.0/inttest/tdeps_update/a2.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/a2.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/a2.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{b, "0.2.4", {git, "../repo/b", {tag, "0.2.4"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/a3.rebar.config rebar-2.6.0/inttest/tdeps_update/a3.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/a3.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/a3.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{b, "0.2.5", {git, "../repo/b", {tag, "0.2.5"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/a4.rebar.config rebar-2.6.0/inttest/tdeps_update/a4.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/a4.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/a4.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+{deps, [
+ {b, "0.2.6", {git, "../repo/b", {tag, "0.2.6"}}},
+ {f, "0.1", {git, "../repo/f", {tag, "0.1"}}}
+ ]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/a.erl rebar-2.6.0/inttest/tdeps_update/a.erl
--- rebar-2.0.0/inttest/tdeps_update/a.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/a.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+-module({{module}}).
+
+-include_lib("b/include/b.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps_update/a.rebar.config rebar-2.6.0/inttest/tdeps_update/a.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/a.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/a.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{b, "0.2.3", {git, "../repo/b", {tag, "0.2.3"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/b2.rebar.config rebar-2.6.0/inttest/tdeps_update/b2.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/b2.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/b2.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{c, "1.1", {git, "../repo/c", {tag, "1.1"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/b3.rebar.config rebar-2.6.0/inttest/tdeps_update/b3.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/b3.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/b3.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{c, "1.2", {git, "../repo/c", {tag, "1.2"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/b4.rebar.config rebar-2.6.0/inttest/tdeps_update/b4.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/b4.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/b4.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{c, "1.3", {git, "../repo/c", {tag, "1.3"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/b.hrl rebar-2.6.0/inttest/tdeps_update/b.hrl
--- rebar-2.0.0/inttest/tdeps_update/b.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/b.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-include_lib("c/include/c.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps_update/b.rebar.config rebar-2.6.0/inttest/tdeps_update/b.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/b.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/b.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{c, "1.0", {git, "../repo/c", {tag, "1.0"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/c2.hrl rebar-2.6.0/inttest/tdeps_update/c2.hrl
--- rebar-2.0.0/inttest/tdeps_update/c2.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/c2.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-include_lib("d/include/d.hrl").
diff -Nru rebar-2.0.0/inttest/tdeps_update/c2.rebar.config rebar-2.6.0/inttest/tdeps_update/c2.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/c2.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/c2.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+{deps, [
+ {d, "0.7", {git, "../repo/d", {tag, "0.7"}}},
+ {e, "2.0", {git, "../repo/e", {tag, "2.0"}}}
+ ]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/c3.rebar.config rebar-2.6.0/inttest/tdeps_update/c3.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/c3.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/c3.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,4 @@
+{deps, [
+ {d, "0.7", {git, "../repo/d", {tag, "0.7"}}},
+ {e, "2.1", {git, "../repo/e", {tag, "2.1"}}}
+ ]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/c.hrl rebar-2.6.0/inttest/tdeps_update/c.hrl
--- rebar-2.0.0/inttest/tdeps_update/c.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/c.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-define(HELLO, hello).
diff -Nru rebar-2.0.0/inttest/tdeps_update/c.rebar.config rebar-2.6.0/inttest/tdeps_update/c.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/c.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/c.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{deps, [{d, "0.7", {git, "../repo/d", {tag, "0.7"}}}]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/d.hrl rebar-2.6.0/inttest/tdeps_update/d.hrl
--- rebar-2.0.0/inttest/tdeps_update/d.hrl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/d.hrl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+-define(HELLO, hello).
diff -Nru rebar-2.0.0/inttest/tdeps_update/root.rebar.config rebar-2.6.0/inttest/tdeps_update/root.rebar.config
--- rebar-2.0.0/inttest/tdeps_update/root.rebar.config 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/root.rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1 @@
+{sub_dirs, ["apps/a1"]}.
diff -Nru rebar-2.0.0/inttest/tdeps_update/tdeps_update_rt.erl rebar-2.6.0/inttest/tdeps_update/tdeps_update_rt.erl
--- rebar-2.0.0/inttest/tdeps_update/tdeps_update_rt.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/inttest/tdeps_update/tdeps_update_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,150 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(tdeps_update_rt).
+
+-compile(export_all).
+
+%% Exercises update deps, with recursive dependency updates.
+%% Initially:
+%% A(v0.5) -> B(v0.2.3) -> C(v1.0)
+%% But after updating A to 0.6:
+%% A(v0.6) -> B(v0.2.4) -> C(v1.1)
+%% -> D(v0.7)
+%% And after updating A to 0.7:
+%% A(v0.7) -> B(v0.2.5) -> C(v1.2) -> E(v2.0)
+%% -> D(v0.7)
+%% And after updating A to 0.8:
+%% A(v0.8) -> B(v0.2.6) -> C(v1.3) -> E(v2.1)
+%% -> D(v0.7)
+%% -> F(v0.1) -> E(v2.1)
+files() ->
+ [
+ %% A1 application
+ {create, "apps/a1/ebin/a1.app", app(a1, [a1], "0.5")},
+ {copy, "a.rebar.config", "apps/a1/rebar.config"},
+ {template, "a.erl", "apps/a1/src/a1.erl", dict:from_list([{module, a1}])},
+
+ {copy, "root.rebar.config", "rebar.config"},
+ {copy, "../../rebar", "rebar"},
+
+ %% B application
+ {create, "repo/b/ebin/b.app", app(b, [], "0.2.3")},
+ {create, "b2.app", app(b, [], "0.2.4")},
+ {create, "b3.app", app(b, [], "0.2.5")},
+ {create, "b4.app", app(b, [], "0.2.6")},
+ {copy, "b.rebar.config", "repo/b/rebar.config"},
+ {copy, "b.hrl", "repo/b/include/b.hrl"},
+
+ %% C application
+ {create, "repo/c/ebin/c.app", app(c, [], "1.0")},
+ {create, "c2.app", app(c, [], "1.1")},
+ {create, "c3.app", app(c, [], "1.2")},
+ {create, "c4.app", app(c, [], "1.3")},
+ {copy, "c.hrl", "repo/c/include/c.hrl"},
+
+ %% D application
+ {create, "repo/d/ebin/d.app", app(d, [], "0.7")},
+ {copy, "d.hrl", "repo/d/include/d.hrl"},
+
+ %% E application
+ {create, "repo/e/ebin/e.app", app(e, [], "2.0")},
+ {create, "e2.app", app(e, [], "2.1")},
+
+ %% F application
+ {create, "repo/f/ebin/f.app", app(f, [], "0.1")},
+
+ %% update files
+ {copy, "a2.rebar.config", "a2.rebar.config"},
+ {copy, "a3.rebar.config", "a3.rebar.config"},
+ {copy, "a4.rebar.config", "a4.rebar.config"},
+ {copy, "b2.rebar.config", "b2.rebar.config"},
+ {copy, "b3.rebar.config", "b3.rebar.config"},
+ {copy, "b4.rebar.config", "b4.rebar.config"},
+ {copy, "c2.hrl", "c2.hrl"},
+ {copy, "c.rebar.config", "c.rebar.config"},
+ {copy, "c2.rebar.config", "c2.rebar.config"},
+ {copy, "c3.rebar.config", "c3.rebar.config"}
+ ].
+
+apply_cmds([], _Params) ->
+ ok;
+apply_cmds([Cmd | Rest], Params) ->
+ io:format("Running: ~s (~p)\n", [Cmd, Params]),
+ {ok, _} = retest_sh:run(Cmd, Params),
+ apply_cmds(Rest, Params).
+
+run(_Dir) ->
+ %% Initialize the b/c/d apps as git repos so that dependencies pull
+ %% properly
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m 'Initial Commit'"],
+ BCmds = ["git tag 0.2.3",
+ "cp ../../b2.rebar.config rebar.config",
+ "cp ../../b2.app ebin/b.app",
+ "git commit -a -m 'update to 0.2.4'",
+ "git tag 0.2.4",
+ "cp ../../b3.rebar.config rebar.config",
+ "cp ../../b3.app ebin/b.app",
+ "git commit -a -m 'update to 0.2.5'",
+ "git tag 0.2.5",
+ "cp ../../b4.rebar.config rebar.config",
+ "cp ../../b4.app ebin/b.app",
+ "git commit -a -m 'update to 0.2.6'",
+ "git tag 0.2.6"],
+ %"git checkout 0.2.3"],
+ CCmds = ["git tag 1.0",
+ "cp ../../c2.hrl include/c.hrl",
+ "cp ../../c2.app ebin/c.app",
+ "cp ../../c.rebar.config rebar.config",
+ "git add rebar.config",
+ "git commit -a -m 'update to 1.1'",
+ "git tag 1.1",
+ "cp ../../c3.app ebin/c.app",
+ "cp ../../c2.rebar.config rebar.config",
+ "git commit -a -m 'update to 1.2'",
+ "git tag 1.2",
+ "cp ../../c4.app ebin/c.app",
+ "cp ../../c3.rebar.config rebar.config",
+ "git commit -a -m 'update to 1.3'",
+ "git tag 1.3"],
+ %"git checkout 1.0"],
+ DCmds = ["git tag 0.7"],
+ ECmds = ["git tag 2.0",
+ "cp ../../e2.app ebin/e.app",
+ "git commit -a -m 'update to 2.1'",
+ "git tag 2.1"],
+ FCmds = ["git tag 0.1"],
+
+ ok = apply_cmds(GitCmds++BCmds, [{dir, "repo/b"}]),
+ ok = apply_cmds(GitCmds++CCmds, [{dir, "repo/c"}]),
+ ok = apply_cmds(GitCmds++DCmds, [{dir, "repo/d"}]),
+ ok = apply_cmds(GitCmds++ECmds, [{dir, "repo/e"}]),
+ ok = apply_cmds(GitCmds++FCmds, [{dir, "repo/f"}]),
+
+ {ok, _} = retest_sh:run("./rebar -v get-deps", []),
+ {ok, _} = retest_sh:run("./rebar -v compile", []),
+ os:cmd("cp a2.rebar.config apps/a1/rebar.config"),
+ {ok, _} = retest_sh:run("./rebar -v update-deps", []),
+ {ok, _} = retest_sh:run("./rebar -v compile", []),
+ os:cmd("cp a3.rebar.config apps/a1/rebar.config"),
+ {ok, _} = retest_sh:run("./rebar -v update-deps", []),
+ {ok, _} = retest_sh:run("./rebar -v compile", []),
+ os:cmd("cp a4.rebar.config apps/a1/rebar.config"),
+ {ok, _} = retest_sh:run("./rebar -v update-deps", []),
+ {ok, _} = retest_sh:run("./rebar -v compile", []),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules, Version) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, Version},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff -Nru rebar-2.0.0/inttest/thooks/thooks_rt.erl rebar-2.6.0/inttest/thooks/thooks_rt.erl
--- rebar-2.0.0/inttest/thooks/thooks_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/thooks/thooks_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(thooks_rt).
-include_lib("eunit/include/eunit.hrl").
diff -Nru rebar-2.0.0/inttest/tplugins/tplugins_rt.erl rebar-2.6.0/inttest/tplugins/tplugins_rt.erl
--- rebar-2.0.0/inttest/tplugins/tplugins_rt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/inttest/tplugins/tplugins_rt.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
-module(tplugins_rt).
-compile(export_all).
@@ -18,7 +20,7 @@
{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 -Nru rebar-2.0.0/Makefile rebar-2.6.0/Makefile
--- rebar-2.0.0/Makefile 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/Makefile 2015-06-19 16:14:28.000000000 +0000
@@ -1,27 +1,48 @@
-.PHONY: dialyzer_warnings xref_warnings
+.PHONY: clean xref_warnings deps test test_eunit test_inttest
+
+REBAR=$(PWD)/rebar
+RETEST=$(PWD)/deps/retest/retest
+LOG_LEVEL?=debug
+RT_TARGETS?=inttest
all:
./bootstrap
clean:
- @rm -rf rebar ebin/*.beam inttest/rt.work
+ @rm -rf rebar .rebar/erlcinfo ebin/*.beam inttest/rt.work rt.work .eunit
+
+distclean: clean
+ @rm -rf deps
debug:
@./bootstrap debug
-check: debug xref dialyzer
+check: debug xref dialyzer deps test
xref:
@./rebar xref
-dialyzer: dialyzer_warnings
- @diff -U0 dialyzer_reference dialyzer_warnings
+build_plt:
+ @./rebar build-plt
-dialyzer_warnings:
- -@dialyzer -q -n ebin -Wunmatched_returns -Werror_handling \
- -Wrace_conditions > dialyzer_warnings
+dialyzer:
+ @./rebar dialyze
binary: VSN = $(shell ./rebar -V)
binary: clean all
- cp rebar ../rebar.wiki/rebar
- (cd ../rebar.wiki && git commit -m "Update $(VSN)" rebar)
\ No newline at end of file
+ @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: test_eunit test_inttest
+
+test_eunit: all
+ @$(REBAR) eunit
+
+test_inttest: all deps
+ @$(RETEST) -l $(LOG_LEVEL) $(RT_TARGETS)
+
+travis: clean debug xref clean all deps test
diff -Nru rebar-2.0.0/NOTES.org rebar-2.6.0/NOTES.org
--- rebar-2.0.0/NOTES.org 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/NOTES.org 1970-01-01 00:00:00.000000000 +0000
@@ -1,28 +0,0 @@
-
-* Major operations
-** Compile
-*** Code generation
-*** Compilation/linking
-*** App validation
-** Clean
-** ct testing
-** eunit testing
-** Installation
-** Doc generation
-
-* Modes/File types
-** Erlang
-** Port driver
-** NIF driver
-** SNMP MIBs
-** ASN.1 files
-
-* Misc. Notes
-** Port/NIF driver compilation needs pre/post hook
-** Need to support code generation for things like protobuf
-** Need to support compilation flags
-
-* Contexts
-** Application
-** General
-** Release ?!
diff -Nru rebar-2.0.0/pr2relnotes.py rebar-2.6.0/pr2relnotes.py
--- rebar-2.0.0/pr2relnotes.py 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/pr2relnotes.py 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+
+## Install info
+## $ virtualenv env
+## $ source env/bin/activate
+## $ pip install PyGithub
+##
+## Examples:
+## Find the differences from last tag to current
+## $ pr2relnotes.py alpha-6 HEAD
+
+import argparse
+import re
+import os
+import subprocess
+from github import Github
+from github import GithubException
+
+
+def dprint(*args):
+ if VERBOSE:
+ print str(args)
+
+def get_args():
+ """
+ Get command line arguments
+ """
+ parser = argparse.ArgumentParser(description="Find the PR's between two versions")
+ parser.add_argument("old", help = "old version to use")
+ parser.add_argument("new", help = "new version to use")
+ parser.add_argument("-v", "--verbose", help="Enable debug output",
+ default=False,
+ action="store_true")
+ parser.add_argument("-f", "--file",
+ help="Output file to store results (default: tagdiff.md)",
+ default="tagdiff.md")
+ return parser.parse_args()
+
+def search_prs(log):
+ """
+ Search lines of text for PR numbers
+ """
+ # Find all matches using regex iterator, using the PR # as the group match
+ resultlist = [str(m.group(1)) for m in re.finditer(r"erge pull request #(\d+)", log)]
+ return sorted(resultlist)
+
+def get_env(env):
+ return os.environ[env]
+
+def get_formatted_issue(repo, issue, title, url):
+ """
+ Single place to adjust formatting output of PR data
+ """
+ # Newline support writelines() call which doesn't add newlines
+ # on its own
+ return("* {}/{}: [{}]({})\n".format(repo, issue, title, url))
+
+def gh_get_issue_output(org, repo, issuenum):
+ """
+ Look up PR information using the GitHub api
+ """
+ # Attempt to look up the PR, and don't take down the whole
+ # shebang if a API call fails
+ # This will fail often on forks who don't have the
+ # PRs numbers associated with the forked account
+ # Return empty string on error
+ try:
+ repoObj = gh.get_repo(org + "/" + repo)
+ issue = repoObj.get_issue(int(issuenum))
+ title = issue.title
+ html_url = issue.html_url
+ except GithubException as e:
+ print "Github error({0}): {1}".format(e.status, e.data)
+ return ""
+ except:
+ print "Some github error"
+ return ""
+
+ return(get_formatted_issue(repo, issuenum, title, html_url))
+
+
+def get_org(repourl):
+ """
+ Simple function to parse the organization out of a GitHub URL
+ """
+ dprint("Current repourl to search: " + repourl)
+ # GitHub URLs can be:
+ # http[s]://www.github.com/org/repo
+ # or git@github.com:/org/repo
+ pattern = re.compile(r"github.com[/:]+(\w+)/")
+ m = re.search(pattern, repourl)
+ # Fail fast if this is wrong so we can add a pattern to the search
+ if m:
+ return m.group(1)
+ else:
+ raise Exception("Incorrect regex pattern finding repo org")
+
+def get_name(repourl):
+ """
+ Simple function to parse the repository name out of a GitHub URL
+ """
+ dprint("Current repourl to search: " + repourl)
+ repo_pattern = re.compile(r"github.com[/:]\w+/(\w+)")
+ m = re.search(repo_pattern, repourl)
+ if m:
+ return m.group(1)
+ else:
+ raise Exception("Incorrect rexex pattern finding repo url")
+
+def get_repo_url_from_remote():
+ """
+ Function that gets the repository URL from the `git remote` listing
+ """
+ git_remote_bytes = subprocess.check_output(["git", "remote", "-v"])
+ # check_output returns the command results in raw byte format
+ remote_string = git_remote_bytes.decode('utf-8')
+
+ pattern = re.compile(r"github.com[/:]\w+/\w+")
+ m = re.search(pattern, remote_string)
+ if m:
+ return m.group(0)
+ else:
+ raise Exception("Incorrect rexex pattern finding repo url")
+
+def process_log(gitlog, repo_url):
+ """
+ Handles the processing of the gitlog and returns a list
+ of PRs already formatted for output
+ """
+ pr_list = search_prs(gitlog)
+ repoorg = get_org(repo_url)
+ reponame = get_name(repo_url)
+ pr_buffer = []
+ for issue in pr_list:
+ pr_buffer.append(gh_get_issue_output(repoorg, reponame, issue))
+
+ return pr_buffer
+
+def fetch_log(old_ver, new_ver):
+ """
+ Function that processes the git log between the old and new versions
+ """
+ dprint("Current working directory", os.getcwd())
+ gitlogbytes = subprocess.check_output(["git", "log",
+ str(old_ver + ".." + new_ver)])
+ return gitlogbytes.decode('utf-8')
+
+
+def compare_versions(repo_url, old_ver, new_ver):
+ # Formatted list of all PRs for all repos
+ pr_out = []
+ gitlog = fetch_log(old_ver, new_ver)
+ pr_out.extend(process_log(gitlog, repo_url))
+ return pr_out
+
+def main():
+ args = get_args()
+
+ # Setup the GitHub object for later use
+ global gh
+ gh = Github(get_env("GHAUTH"))
+
+ if gh == "":
+ raise Exception("Env var GHAUTH must be set to a valid GitHub API key")
+
+ if args.verbose:
+ global VERBOSE
+ VERBOSE=True
+
+ dprint("Inspecting difference in between: ", args.old, " and ", args.new)
+
+ # Find the github URL of the repo we are operating on
+ repo_url = get_repo_url_from_remote()
+
+ # Compare old and new versions
+ pr_list = compare_versions(repo_url, args.old, args.new)
+
+ # Writeout PR listing
+ print "Writing output to file %s" % args.file
+ with open(args.file, 'w') as output:
+ output.writelines(pr_list)
+
+
+if __name__ == "__main__":
+ VERBOSE=False
+ gh=None
+ topdir=os.getcwd()
+ main()
diff -Nru rebar-2.0.0/priv/shell-completion/bash/rebar rebar-2.6.0/priv/shell-completion/bash/rebar
--- rebar-2.0.0/priv/shell-completion/bash/rebar 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/shell-completion/bash/rebar 2015-06-19 16:14:28.000000000 +0000
@@ -6,13 +6,67 @@
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
- sopts="-h -c -v -V -f -j"
- lopts=" --help --commands --verbose --force --jobs= --version"
- cmdsnvars="check-deps clean compile create create-app create-node ct \
- doc delete-deps escriptize eunit get-deps generate generate-upgrade \
- help list-deps list-templates update-deps version xref overlay \
- apps= case= force=1 jobs= suites= verbose=1 appid= previous_release= \
- nodeid= root_dir= skip_deps=true skip_apps= template= template_dir="
+ sopts="-h -c -v -V -f -D -j -C -p -k -r"
+ lopts="--help \
+ --commands \
+ --verbose \
+ --force \
+ --jobs \
+ --config \
+ --profile \
+ --keep-going \
+ --recursive \
+ --version"
+ cmdsnvars=" \
+ build-plt \
+ check-deps \
+ clean \
+ compile \
+ check-plt \
+ create \
+ create-app \
+ create-lib \
+ create-node \
+ ct \
+ dialyze \
+ doc \
+ delete-deps \
+ escriptize \
+ eunit \
+ get-deps \
+ generate \
+ generate-appups \
+ generate-upgrade \
+ help \
+ list-deps \
+ list-templates \
+ prepare-deps \
+ qc \
+ refresh-deps \
+ shell \
+ update-deps \
+ version \
+ xref \
+ overlay \
+ apps= \
+ case= \
+ dump_spec=1 \
+ force=1 \
+ jobs= \
+ suites= \
+ verbose=1 \
+ appid= \
+ overlay_vars= \
+ previous_release= \
+ profiler= \
+ nodeid= \
+ root_dir= \
+ skip_deps=true \
+ skip_apps= \
+ target_dir= \
+ template= \
+ template_dir= \
+ tests="
if [[ ${cur} == --* ]] ; then
COMPREPLY=( $(compgen -W "${lopts}" -- ${cur}) )
diff -Nru rebar-2.0.0/priv/shell-completion/fish/rebar.fish rebar-2.6.0/priv/shell-completion/fish/rebar.fish
--- rebar-2.0.0/priv/shell-completion/fish/rebar.fish 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/shell-completion/fish/rebar.fish 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,189 @@
+## fish completions for rebar 2.5.0
+
+function __fish_rebar_needs_command
+ set cmd (commandline -opc)
+ if [ (count $cmd) -eq 1 -a $cmd[1] = 'rebar' -o $cmd[1] = './rebar' ]
+ return 0
+ end
+ return 1
+end
+
+function __fish_rebar_using_command
+ set cmd (commandline -opc)
+ if [ (count $cmd) -gt 1 ]
+ if [ $argv[1] = $cmd[2] ]
+ return 0
+ end
+ end
+ return 1
+end
+
+## Rebar Command Output
+## ➜ ~ rebar --version
+## rebar 2.5.0 R16B02 20140716_213805 git 2.5.0-14-g1e7c742
+## ➜ ~ rebar --help
+## Usage: rebar [-h] [-c] [-v ] [-q ] [-V] [-f]
+## [-D ] [-j ] [-C ] [-p] [-k]
+## [-r ] [var=value,...]
+##
+## -h, --help Show the program options
+## -c, --commands Show available commands
+## -v, --verbose Verbosity level (-v, -vv)
+## -q, --quiet Quiet, only print error messages
+## -V, --version Show version information
+## -f, --force Force
+## -D Define compiler macro
+## -j, --jobs Number of concurrent workers a command may use.
+## Default: 3
+## -C, --config Rebar config file to use
+## -p, --profile Profile this run of rebar
+## -k, --keep-going Keep running after a command fails
+## -r, --recursive Apply commands to subdirs and dependencies
+## var=value rebar global variables (e.g. force=1)
+## command Command to run (e.g. compile)
+##
+## To see a list of built-in commands, execute rebar -c.
+##
+## Type 'rebar help ' for help on specific commands.
+
+# general options
+complete -f -c rebar -n 'not __fish_rebar_needs_command' -l help -d 'Display the manual of a rebar command'
+
+## Flags
+complete -c rebar -s h -l help -d "Show the program options"
+complete -c rebar -s c -l commands -d "Show available commands"
+complete -c rebar -s v -l verbose -d "Verbosity level (-v, -vv, -vvv, --verbose 3). Default: 0"
+complete -c rebar -s vv -d "Verbosity level 2"
+complete -c rebar -s vvv -d "Verbosity level 2"
+complete -c rebar -s q -l quiet -d "Quiet, only print error messages"
+complete -c rebar -s V -l version -d "Show version information"
+complete -c rebar -s f -l force -d "Force"
+complete -c rebar -s D -d "Define compiler macro"
+complete -c rebar -s j -l jobs -d "Number of concurrent workers a command may use. Default: 3"
+complete -c rebar -s C -l config -d "Rebar config file to use"
+complete -c rebar -s p -l profile -d "Profile this run of rebar"
+complete -c rebar -s k -l keep-going -d "Keep running after a command fails"
+complete -c rebar -s r -l recursive -d "Apply commands to subdirs and dependencies"
+
+
+## Not going to cover abbreviations, since this is for completions anyway :D
+## rebar allows you to abbreviate the command to run:
+## $ rebar co # same as rebar compile
+## $ rebar eu # same as rebar eunit
+## $ rebar g-d # same as rebar get-deps
+## $ rebar x eu # same as rebar xref eunit
+## $ rebar l-d # same as rebar list-deps
+## $ rebar l-d l-t # same as rebar list-deps list-templates
+## $ rebar list-d l-te # same as rebar list-deps list-templates
+##
+## Core command line options:
+## apps=app1,app2 (specify apps to process)
+## skip_apps=app1,app2 (specify apps to skip)
+
+## COMMANDS!
+## ➜ ~ rebar -c
+## clean Clean
+complete -f -c rebar -n '__fish_rebar_needs_command' -a clean -d 'Clean'
+
+## compile Compile sources
+complete -f -c rebar -n '__fish_rebar_needs_command' -a compile -d 'Compile sources'
+
+## escriptize Generate escript archive
+complete -f -c rebar -n '__fish_rebar_needs_command' -a escriptize -d 'Generate escript archive'
+
+## create template= [var=foo,...] Create skel based on template and vars
+complete -f -c rebar -n '__fish_rebar_needs_command' -a create -d 'Create skel based on template and vars'
+complete -f -c rebar -n '__fish_rebar_using_command create' -a 'template=' -d 'Template name'
+
+## create-app [appid=myapp] Create simple app skel
+complete -f -c rebar -n '__fish_rebar_needs_command' -a create-app -d 'Create simple app skel'
+complete -f -c rebar -n '__fish_rebar_using_command create-app' -a 'appid=' -d 'Application name'
+
+## create-lib [libid=mylib] Create simple lib skel
+complete -f -c rebar -n '__fish_rebar_needs_command' -a create-lib -d 'Create simple lib skel'
+complete -f -c rebar -n '__fish_rebar_using_command create-lib' -a 'libid=' -d 'Library name'
+
+## create-node [nodeid=mynode] Create simple node skel
+complete -f -c rebar -n '__fish_rebar_needs_command' -a create-node -d 'Create simple node skel'
+complete -f -c rebar -n '__fish_rebar_using_command create-node' -a 'nodeid=' -d 'Node name'
+
+## list-templates List available templates
+complete -f -c rebar -n '__fish_rebar_needs_command' -a list-templates -d 'List available templates'
+
+## doc Generate Erlang program documentation
+complete -f -c rebar -n '__fish_rebar_needs_command' -a doc -d 'Generate Erlang program documentation'
+
+## prepare-deps Run 'rebar -r get-deps compile'
+complete -f -c rebar -n '__fish_rebar_needs_command' -a prepare-deps -d 'Prepare Dependencies'
+
+## refresh-deps Run 'rebar -r update-deps compile'
+complete -f -c rebar -n '__fish_rebar_needs_command' -a refresh-deps -d 'Refresh Dependencies'
+
+## check-deps Display to be fetched dependencies
+complete -f -c rebar -n '__fish_rebar_needs_command' -a check-deps -d 'Display to be fetched dependencies'
+
+## get-deps Fetch dependencies
+complete -f -c rebar -n '__fish_rebar_needs_command' -a get-deps -d 'Fetch dependencies'
+
+## update-deps Update fetched dependencies
+complete -f -c rebar -n '__fish_rebar_needs_command' -a update-deps -d 'Update fetched dependencies'
+
+## delete-deps Delete fetched dependencies
+complete -f -c rebar -n '__fish_rebar_needs_command' -a delete-deps -d 'Delete fetched dependencies'
+
+## list-deps List dependencies
+complete -f -c rebar -n '__fish_rebar_needs_command' -a list-deps -d 'List Dependencies'
+
+## generate [dump_spec=0/1] Build release with reltool
+complete -f -c rebar -n '__fish_rebar_needs_command' -a generate -d 'Build release with reltool'
+complete -f -c rebar -n '__fish_rebar_using_command generate' -a 'dump_spec=0 dump_spec=1'
+
+## overlay Run reltool overlays only
+complete -f -c rebar -n '__fish_rebar_needs_command' -a overlay -d 'Run reltool overlays only'
+
+## generate-upgrade previous_release=path Build an upgrade package
+complete -f -c rebar -n '__fish_rebar_needs_command' -a generate-upgrade -d 'Build an upgrade package'
+complete -f -c rebar -n '__fish_rebar_using_command generate-upgrade' -a 'previous_release='
+
+## generate-appups previous_release=path Generate appup files
+complete -f -c rebar -n '__fish_rebar_needs_command' -a generate-appups -d 'Generate appup files'
+complete -f -c rebar -n '__fish_rebar_using_command generate-appups' -a 'previous_release='
+
+## eunit [suite[s]=foo] Run EUnit tests in foo.erl and
+## test/foo_tests.erl
+## [suite[s]=foo] [test[s]=bar] Run specific EUnit tests [first test
+## name starting with 'bar' in foo.erl
+## and test/foo_tests.erl]
+## [test[s]=bar] For every existing suite, run the first
+## test whose name starts with bar and, if
+## no such test exists, run the test whose
+## name starts with bar in the suite's
+## _tests module.
+## [random_suite_order=true] Run tests in a random order, either
+## [random_suite_order=Seed] with a random seed for the PRNG, or a
+## specific one.
+complete -f -c rebar -n '__fish_rebar_needs_command' -a eunit -d 'Run EUnit tests'
+complete -f -c rebar -n '__fish_rebar_using_command eunit' -a 'suites='
+complete -f -c rebar -n '__fish_rebar_using_command eunit' -a 'tests='
+complete -f -c rebar -n '__fish_rebar_using_command eunit' -a 'random_suite_order='
+
+## ct [suite[s]=] [case=] Run common_test suites
+complete -f -c rebar -n '__fish_rebar_needs_command' -a ct -d 'Run common_test suites'
+complete -f -c rebar -n '__fish_rebar_using_command ct' -a 'suites='
+complete -f -c rebar -n '__fish_rebar_using_command ct' -a 'case='
+
+## qc Test QuickCheck properties
+complete -f -c rebar -n '__fish_rebar_needs_command' -a qc -d 'Test QuickCheck properties'
+
+## xref Run cross reference analysis
+complete -f -c rebar -n '__fish_rebar_needs_command' -a xref -d 'Run cross reference analysis'
+
+## shell Start a shell similar to
+## 'erl -pa ebin -pa deps/*/ebin'
+complete -f -c rebar -n '__fish_rebar_needs_command' -a shell -d 'Start a shell'
+
+## help Show the program options
+complete -f -c rebar -n '__fish_rebar_needs_command' -a help -d 'Show the program options'
+
+## version Show version information
+complete -f -c rebar -n '__fish_rebar_needs_command' -a version -d 'Show version information'
diff -Nru rebar-2.0.0/priv/shell-completion/zsh/_rebar rebar-2.6.0/priv/shell-completion/zsh/_rebar
--- rebar-2.0.0/priv/shell-completion/zsh/_rebar 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/shell-completion/zsh/_rebar 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,92 @@
+#compdef rebar
+
+local curcontext=$curcontext state ret=1
+typeset -ga _rebar_global_opts
+
+_rebar_global_opts=(
+ '(--help -h)'{--help,-h}'[Show the program options]'
+ '(--commands -c)'{--commands,-c}'[Show available commands]'
+ '(--version -V)'{--version,-V}'[Show version information]'
+ '(-vv -v)'--verbose'[Enforce verbosity level]'
+ '(-vv)-v[Slightly more verbose output]'
+ '(-v)-vv[More verbose output]'
+ '(-vv -v --verbose)'{--quiet,-q}'[Quiet, only print error messages]'
+ '(--force -f)'{--force,-f}'[Force]'
+ '-D+[Define compiler macro]'
+ '(--jobs -j)'{--jobs+,-j+}'[Number of concurrent workers a command may use. Default: 3]:workers:(1 2 3 4 5 6 7 8 9)'
+ '(--config -C)'{--config,-C}'[Rebar config file to use]:files:_files'
+ '(--profile -p)'{--profile,-p}'[Profile this run of rebar]'
+ '(--keep-going -k)'{--keep-going,-k}'[Keep running after a command fails]'
+ '(--recursive -r)'{--recursive,-r}'[Apply commands to subdirs and dependencies]'
+)
+
+_rebar () {
+ _arguments -C $_rebar_global_opts \
+ '*::command and variable:->cmd_and_var' \
+ && return
+
+ case $state in
+ cmd_and_var)
+ _values -S = 'variables' \
+ 'dialyze[Analyze the code for discrepancies]' \
+ 'build-plt[Build project-specific PLT]' \
+ 'check-plt[Check the plt for consistency and rebuild it if it is not up-to-date]' \
+ 'clean[Clean]' \
+ 'compile[Compile sources]' \
+ 'create[Create skel based on template and vars]' \
+ 'create-app[Create simple app skel]' \
+ 'create-lib[Create simple lib skel]' \
+ 'create-node[Create simple node skel]' \
+ 'list-template[List available templates]' \
+ 'doc[Generate Erlang program documentation]' \
+ 'check-deps[Display to be fetched dependencies]' \
+ 'prepare-deps[Fetch and build dependencies]' \
+ 'refresh-deps[Update and build dependencies]' \
+ 'get-deps[Fetch dependencies]' \
+ 'update-deps[Update fetched dependencies]' \
+ 'delete-deps[Delete fetched dependencies]' \
+ 'list-deps[List dependencies]' \
+ 'generate[Build release with reltool]' \
+ 'overlay[Run reltool overlays only]' \
+ 'generate-appups[Generate appup files]' \
+ 'generate-upgrade[Build an upgrade package]' \
+ 'escriptize[Create stand-alone escript executable]' \
+ 'eunit[Run eunit tests]' \
+ 'ct[Run common_test suites]' \
+ 'qc[Test QuickCheck properties]' \
+ 'xref[Run cross reference analysis]' \
+ 'help[Show the program options]' \
+ 'version[Show version information]' \
+ 'apps[Application names to process]:' \
+ 'case[Common Test case]:' \
+ 'dump_spec[Dump reltool spec]::flag:(1)' \
+ 'jobs[Number of workers]::workers:(0 1 2 3 4 5 6 7 8 9)' \
+ 'suites[Common Test suites]::suite name:_path_files -W "(src test)" -g "*.erl(:r)"' \
+ 'verbose[Verbosity level]::verbosity level:(0 1 2 3)' \
+ 'appid[Application id]:' \
+ 'overlay_vars[Overlay variables file]:' \
+ 'previous_release[Previous release path]:' \
+ 'profiler[Select profiler]::flag:(fprof eflame)' \
+ 'nodeid[Node id]:' \
+ 'root_dir[Reltool config root directory]::directory:_files -/' \
+ 'shell[Start a shell similar to erl -pa ebin -pa deps/*/ebin]' \
+ 'skip_deps[Skip deps]::flag:(true false)' \
+ 'skip_apps[Application names to not process]::flag:(true false)' \
+ 'target_dir[Target directory]:' \
+ 'template[Template name]:' \
+ 'template_dir[Template directory]::directory:_files -/' \
+ 'tests[Run eunit tests whose name starts with given string]:' \
+ && ret=0
+ ;;
+ esac
+}
+
+_rebar
+
+# Local variables:
+# mode: shell-script
+# sh-basic-offset: 2
+# sh-indent-comment: t
+# indent-tabs-mode: nil
+# End:
+# ex: sw=2 ts=2 et filetype=sh
diff -Nru rebar-2.0.0/priv/templates/simpleapp_sup.erl rebar-2.6.0/priv/templates/simpleapp_sup.erl
--- rebar-2.0.0/priv/templates/simpleapp_sup.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simpleapp_sup.erl 2015-06-19 16:14:28.000000000 +0000
@@ -1,4 +1,3 @@
-
-module({{appid}}_sup).
-behaviour(supervisor).
diff -Nru rebar-2.0.0/priv/templates/simpleevent.erl rebar-2.6.0/priv/templates/simpleevent.erl
--- rebar-2.0.0/priv/templates/simpleevent.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/templates/simpleevent.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,60 @@
+-module({{eventid}}).
+-behaviour(gen_event).
+
+%% ------------------------------------------------------------------
+%% API Function Exports
+%% ------------------------------------------------------------------
+
+-export([start_link/0,
+ add_handler/2]).
+
+%% ------------------------------------------------------------------
+%% gen_event Function Exports
+%% ------------------------------------------------------------------
+
+-export([init/1,
+ handle_event/2,
+ handle_call/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+-record(state, {}).
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+start_link() ->
+ gen_event:start_link({local, ?MODULE}).
+
+add_handler(Handler, Args) ->
+ gen_event:add_handler(?MODULE, Handler, Args).
+
+%% ------------------------------------------------------------------
+%% gen_event Function Definitions
+%% ------------------------------------------------------------------
+
+init([]) ->
+ {ok, #state{}}.
+
+handle_event(_Event, State) ->
+ {ok, State}.
+
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+
+handle_info(_Info, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
diff -Nru rebar-2.0.0/priv/templates/simpleevent.template rebar-2.6.0/priv/templates/simpleevent.template
--- rebar-2.0.0/priv/templates/simpleevent.template 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/templates/simpleevent.template 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,2 @@
+{variables, [{eventid, "myevent"}]}.
+{template, "simpleevent.erl", "src/{{eventid}}.erl"}.
diff -Nru rebar-2.0.0/priv/templates/simplelib.app.src rebar-2.6.0/priv/templates/simplelib.app.src
--- rebar-2.0.0/priv/templates/simplelib.app.src 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplelib.app.src 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,14 @@
+{application, {{libid}},
+ [
+ {description, "An Erlang {{libid}} library"},
+ {vsn, "1"},
+ {modules, [
+ {{libid}}
+ ]},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {env, []}
+ ]}.
diff -Nru rebar-2.0.0/priv/templates/simplelib.erl rebar-2.6.0/priv/templates/simplelib.erl
--- rebar-2.0.0/priv/templates/simplelib.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplelib.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,18 @@
+-module({{libid}}).
+
+%% {{libid}}: {{libid}} library's entry point.
+
+-export([my_func/0]).
+
+
+%% API
+
+my_func() ->
+ ok().
+
+%% Internals
+
+ok() ->
+ ok.
+
+%% End of Module.
diff -Nru rebar-2.0.0/priv/templates/simplelib.template rebar-2.6.0/priv/templates/simplelib.template
--- rebar-2.0.0/priv/templates/simplelib.template 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplelib.template 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,3 @@
+{variables, [{libid, "mylib"}]}.
+{template, "simplelib.app.src", "src/{{libid}}.app.src"}.
+{template, "simplelib.erl", "src/{{libid}}.erl"}.
diff -Nru rebar-2.0.0/priv/templates/simplenode.erl.script rebar-2.6.0/priv/templates/simplenode.erl.script
--- rebar-2.0.0/priv/templates/simplenode.erl.script 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.erl.script 2015-06-19 16:14:28.000000000 +0000
@@ -1,16 +1,26 @@
#!/bin/sh
-## This script replaces the default "erl" in erts-VSN/bin. This is necessary
-## as escript depends on erl and in turn, erl depends on having access to a
-## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect
-## of running escript -- the embedded node bypasses erl and uses erlexec directly
-## (as it should).
+# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
+if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
+ POSIX_SHELL="true"
+ export POSIX_SHELL
+ exec /usr/bin/ksh $0 "$@"
+fi
+
+# clear it so if we invoke other scripts, they run as ksh as well
+unset POSIX_SHELL
+
+## This script replaces the default "erl" in erts-VSN/bin. This is
+## necessary as escript depends on erl and in turn, erl depends on
+## having access to a bootscript (start.boot). Note that this script
+## is ONLY invoked as a side-effect of running escript -- the embedded
+## node bypasses erl and uses erlexec directly (as it should).
##
-## Note that this script makes the assumption that there is a start_clean.boot
-## file available in $ROOTDIR/release/VSN.
+## Note that this script makes the assumption that there is a
+## start_clean.boot file available in $ROOTDIR/release/VSN.
# Determine the abspath of where this script is executing from.
-ERTS_BIN_DIR=$(cd ${0%/*} && pwd)
+ERTS_BIN_DIR=$(cd ${0%/*} && pwd -P)
# Now determine the root directory -- this script runs from erts-VSN/bin,
# so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR
diff -Nru rebar-2.0.0/priv/templates/simplenode.install_upgrade.escript rebar-2.6.0/priv/templates/simplenode.install_upgrade.escript
--- rebar-2.0.0/priv/templates/simplenode.install_upgrade.escript 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.install_upgrade.escript 2015-06-19 16:14:28.000000000 +0000
@@ -2,43 +2,54 @@
%%! -noshell -noinput
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
+%% This file is left for backward-compatibility.
+%% You, probably, shouldn't include it to new projects.
--define(TIMEOUT, 60000).
--define(INFO(Fmt,Args), io:format(Fmt,Args)).
main([NodeName, Cookie, ReleasePackage]) ->
- TargetNode = start_distribution(NodeName, Cookie),
- {ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release,
- [ReleasePackage], ?TIMEOUT),
- ?INFO("Unpacked Release ~p~n", [Vsn]),
- {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
- check_install_release, [Vsn], ?TIMEOUT),
- {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
- install_release, [Vsn], ?TIMEOUT),
- ?INFO("Installed Release ~p~n", [Vsn]),
- ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT),
- ?INFO("Made Release ~p Permanent~n", [Vsn]);
+ io:format("WARNING: 'install_upgrade.escript' is deprecated! "
+ "Use 'nodetool upgrade' instead.~n"),
+ NodeRoot = filename:dirname(filename:dirname(escript:script_name())),
+ NodeTool = which_nodetool(NodeRoot),
+ process_flag(trap_exit, true),
+ Port = erlang:open_port(
+ {spawn_executable, NodeTool},
+ [{args, ["-sname", NodeName,
+ "-setcookie", Cookie,
+ "upgrade", ReleasePackage]},
+ binary, exit_status, use_stdio, stderr_to_stdout, hide]),
+ port_loop(Port);
main(_) ->
- init:stop(1).
+ halt(1).
-start_distribution(NodeName, Cookie) ->
- MyNode = make_script_node(NodeName),
- {ok, _Pid} = net_kernel:start([MyNode, shortnames]),
- erlang:set_cookie(node(), list_to_atom(Cookie)),
- TargetNode = make_target_node(NodeName),
- case {net_kernel:hidden_connect_node(TargetNode),
- net_adm:ping(TargetNode)} of
- {true, pong} ->
- ok;
- {_, pang} ->
- io:format("Node ~p not responding to pings.\n", [TargetNode]),
- init:stop(1)
- end,
- TargetNode.
-make_target_node(Node) ->
- [_, Host] = string:tokens(atom_to_list(node()), "@"),
- list_to_atom(lists:concat([Node, "@", Host])).
+which_nodetool(NodeRoot) ->
+ %% ${RELEASE_ROOT}/
+ %% bin/install_upgrade.escript
+ %% bin/nodetool ?
+ %% erts-/bin/nodetool ?
+ %% releases//nodetool ?
+ %% releases/start_erl.data
+ {ok, Content} = file:read_file(filename:join([NodeRoot, "releases", "start_erl.data"])),
+ [ErtsVsn, AppVsn] = binary:split(Content, <<" ">>),
+ Probes = [
+ filename:join([NodeRoot, "bin", "nodetool"]),
+ filename:join([NodeRoot, <<"erts-", ErtsVsn/binary>>, "bin", "nodetool"]),
+ filename:join([NodeRoot, "releases", AppVsn, "bin", "nodetool"])
+ ],
+ case lists:dropwhile(fun(Path) -> not filelib:is_regular(Path) end, Probes) of
+ [] ->
+ io:format("ERROR: can't find 'nodetool' in ~p.~n", [Probes]),
+ halt(2);
+ [Path | _] ->
+ Path
+ end.
-make_script_node(Node) ->
- list_to_atom(lists:concat([Node, "_upgrader_", os:getpid()])).
+port_loop(Port) ->
+ receive
+ {Port, {data, Data}} ->
+ io:put_chars(Data),
+ port_loop(Port);
+ {Port, {exit_status, Status}} ->
+ halt(Status)
+ end.
diff -Nru rebar-2.0.0/priv/templates/simplenode.nodetool rebar-2.6.0/priv/templates/simplenode.nodetool
--- rebar-2.0.0/priv/templates/simplenode.nodetool 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.nodetool 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,4 @@
+#!/usr/bin/env escript
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
%% -------------------------------------------------------------------
@@ -5,25 +6,51 @@
%% nodetool: Helper Script for interacting with live nodes
%%
%% -------------------------------------------------------------------
-
main(Args) ->
ok = start_epmd(),
%% Extract the args
{RestArgs, TargetNode} = process_args(Args, [], undefined),
+ %% any commands that don't need a running node
+ case RestArgs of
+ ["chkconfig", File] ->
+ case file:consult(File) of
+ {ok, _} ->
+ io:format("ok\n"),
+ halt(0);
+ {error, {Line, Mod, Term}} ->
+ io:format(standard_error, ["Error on line ",
+ file:format_error({Line, Mod, Term}), "\n"], []),
+ halt(1);
+ {error, R} ->
+ io:format(standard_error, ["Error reading config file: ",
+ file:format_error(R), "\n"], []),
+ halt(1)
+ end;
+ _ ->
+ ok
+ end,
+
%% See if the node is currently running -- if it's not, we'll bail
- case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of
+ case {net_kernel:hidden_connect_node(TargetNode),
+ net_adm:ping(TargetNode)} of
{true, pong} ->
ok;
+ {false,pong} ->
+ io:format("Failed to connect to node ~p .\n", [TargetNode]),
+ halt(1);
{_, pang} ->
io:format("Node ~p not responding to pings.\n", [TargetNode]),
halt(1)
end,
case RestArgs of
+ ["getpid"] ->
+ io:format("~p\n",
+ [list_to_integer(rpc:call(TargetNode, os, getpid, []))]);
["ping"] ->
- %% If we got this far, the node already responsed to a ping, so just dump
- %% a "pong"
+ %% If we got this far, the node already responsed to a
+ %% ping, so just dump a "pong"
io:format("pong\n");
["stop"] ->
io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]);
@@ -32,7 +59,9 @@
["reboot"] ->
io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]);
["rpc", Module, Function | RpcArgs] ->
- case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
[RpcArgs], 60000) of
ok ->
ok;
@@ -42,8 +71,23 @@
_ ->
halt(1)
end;
+ ["rpc_infinity", Module, Function | RpcArgs] ->
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
+ [RpcArgs], infinity) of
+ ok ->
+ ok;
+ {badrpc, Reason} ->
+ io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
+ halt(1);
+ _ ->
+ halt(1)
+ end;
["rpcterms", Module, Function, ArgsAsString] ->
- case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
+ case rpc:call(TargetNode,
+ list_to_atom(Module),
+ list_to_atom(Function),
consult(ArgsAsString), 60000) of
{badrpc, Reason} ->
io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
@@ -51,9 +95,41 @@
Other ->
io:format("~p\n", [Other])
end;
+ ["eval", Str0] ->
+ Str = string:strip(Str0, right, $.) ++ ".",
+ Bindings = erl_eval:new_bindings(),
+ case rpc:call(TargetNode,
+ erl_eval,
+ exprs,
+ [parse(Str), Bindings],
+ 60000) of
+ {badrpc, Reason} ->
+ io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
+ halt(1);
+ {value, Value, _Bindings} ->
+ io:format("~p\n", [Value])
+ end;
+ ["upgrade", ReleasePackage] ->
+ %% TODO: This script currently does NOT support slim releases.
+ %% Necessary steps to upgrade a slim release are as follows:
+ %% 1. unpack relup archive manually
+ %% 2. copy releases directory and necessary libraries
+ %% 3. using release_hander:set_unpacked/2 .
+ %% For more details, see https://github.com/rebar/rebar/pull/52
+ %% and https://github.com/rebar/rebar/issues/202
+ {ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release,
+ [ReleasePackage], 60000),
+ io:format("Unpacked Release ~p\n", [Vsn]),
+ {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
+ check_install_release, [Vsn], 60000),
+ {ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
+ install_release, [Vsn], 60000),
+ io:format("Installed Release ~p\n", [Vsn]),
+ ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], 60000),
+ io:format("Made Release ~p Permanent\n", [Vsn]);
Other ->
io:format("Other: ~p\n", [Other]),
- io:format("Usage: nodetool {ping|stop|restart|reboot}\n")
+ io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms|eval|upgrade}\n")
end,
net_kernel:stop().
@@ -136,3 +212,8 @@
{more, Cont1} ->
consult(Cont1, eof, Acc)
end.
+
+parse(Str) ->
+ {ok, Tokens, _} = erl_scan:string(Str),
+ {ok, Exprs} = erl_parse:parse_exprs(Tokens),
+ Exprs.
diff -Nru rebar-2.0.0/priv/templates/simplenode.reltool.config rebar-2.6.0/priv/templates/simplenode.reltool.config
--- rebar-2.0.0/priv/templates/simplenode.reltool.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.reltool.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,3 +1,5 @@
+%% -*- mode: erlang -*-
+%% ex: ft=erlang
{sys, [
{lib_dirs, []},
{erts, [{mod_cond, derived}, {app_file, strip}]},
@@ -16,15 +18,13 @@
]},
{boot_rel, "{{nodeid}}"},
{profile, embedded},
- {incl_cond, exclude},
+ {incl_cond, derived},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
- {excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
+ {excl_sys_filters, ["^bin/(?!start_clean.boot)",
+ "^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}}"}.
@@ -32,10 +32,13 @@
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
- {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
+ {copy, "files/nodetool", "releases/\{\{rel_vsn\}\}/nodetool"},
+ {copy, "{{nodeid}}/bin/start_clean.boot",
+ "\{\{erts_vsn\}\}/bin/start_clean.boot"},
{copy, "files/{{nodeid}}", "bin/{{nodeid}}"},
{copy, "files/{{nodeid}}.cmd", "bin/{{nodeid}}.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
+ %% Following line may be safely removed in new projects
{copy, "files/install_upgrade.escript", "bin/install_upgrade.escript"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
diff -Nru rebar-2.0.0/priv/templates/simplenode.runner rebar-2.6.0/priv/templates/simplenode.runner
--- rebar-2.0.0/priv/templates/simplenode.runner 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.runner 2015-06-19 16:14:28.000000000 +0000
@@ -2,25 +2,42 @@
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
-RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)
+# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
+if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
+ POSIX_SHELL="true"
+ export POSIX_SHELL
+ # To support 'whoami' add /usr/ucb to path
+ PATH=/usr/ucb:$PATH
+ export PATH
+ exec /usr/bin/ksh $0 "$@"
+fi
+
+# clear it so if we invoke other scripts, they run as ksh
+unset POSIX_SHELL
+
+RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd -P)
+RUNNER_SCRIPT=${0##*/}
+
+CALLER_DIR=$PWD
RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
-RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log
# Note the trailing slash on $PIPE_DIR/
PIPE_DIR=/tmp/$RUNNER_BASE_DIR/
RUNNER_USER=
+WHOAMI=$(whoami)
# Make sure this script is running as the appropriate user
-if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
- exec sudo -u $RUNNER_USER -i $0 $@
+if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
+ type sudo > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
+ exit 1
+ fi
+ echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2
+ exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
fi
-# Make sure CWD is set to runner base dir
-cd $RUNNER_BASE_DIR
-
-# Make sure log directory exists
-mkdir -p $RUNNER_LOG_DIR
# Identify the script name
SCRIPT=`basename $0`
@@ -29,22 +46,37 @@
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
-# Use releases/VSN/vm.args if it exists otherwise use etc/vm.args
-if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
- VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
+# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or
+# else etc/vm.args
+if [ -e "$CALLER_DIR/vm.args" ]; then
+ VMARGS_PATH=$CALLER_DIR/vm.args
+ USE_DIR=$CALLER_DIR
else
- VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
+ USE_DIR=$RUNNER_BASE_DIR
+ if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
+ VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
+ else
+ VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
+ fi
fi
+RUNNER_LOG_DIR=$USE_DIR/log
+# Make sure log directory exists
+mkdir -p $RUNNER_LOG_DIR
+
# Use releases/VSN/sys.config if it exists otherwise use etc/app.config
-if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
- CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
+if [ -e "$USE_DIR/sys.config" ]; then
+ CONFIG_PATH="$USE_DIR/sys.config"
else
- CONFIG_PATH="$RUNNER_ETC_DIR/app.config"
+ if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
+ CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
+ else
+ CONFIG_PATH="$RUNNER_ETC_DIR/app.config"
+ fi
fi
# Extract the target node name from node.args
-NAME_ARG=`egrep '^-s?name' $VMARGS_PATH`
+NAME_ARG=`egrep '^\-s?name' $VMARGS_PATH`
if [ -z "$NAME_ARG" ]; then
echo "vm.args needs to have either -name or -sname parameter."
exit 1
@@ -54,67 +86,168 @@
REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'`
REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'`
-# Note the `date +%s`, used to allow multiple remsh to the same node transparently
-REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
-REMSH_REMSH_ARG="-remsh $REMSH_NAME"
+# Test if REMSH_NAME contains a @ and set REMSH_HOSTNAME_PART
+# and REMSH_NAME_PART according REMSH_TYPE
+MAYBE_FQDN_HOSTNAME=`hostname`
+HOSTNAME=`echo $MAYBE_FQDN_HOSTNAME | awk -F. '{print $1}'`
+
+REMSH_HOSTNAME_PART="$MAYBE_FQDN_HOSTNAME"
+case "$REMSH_NAME" in
+ *@*)
+ REMSH_HOSTNAME_PART=`echo $REMSH_NAME | awk -F@ '{print $2}'`
+ REMSH_NAME_PART=`echo $REMSH_NAME | awk -F@ '{print $1}'`
+ ;;
+ *)
+ REMSH_NAME_PART="$REMSH_NAME"
+ if [ "$REMSH_TYPE" = "-sname" ]; then
+ REMSH_HOSTNAME_PART="$HOSTNAME"
+ else
+ # -name type, check if `hostname` is fqdn
+ if [ "$MAYBE_FQDN_HOSTNAME" = "$HOSTNAME" ]; then
+ echo "Hostname must be a fqdn domain name when node is configured with long names"
+ echo "and the full node name isn't configured in vm.args"
+ exit 1
+ fi
+ fi
+ ;;
+esac
+
+# Note the `date +%s`, used to allow multiple remsh to the same node
+# transparently
+REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@$REMSH_HOSTNAME_PART"
+REMSH_REMSH_ARG="-remsh $REMSH_NAME_PART@$REMSH_HOSTNAME_PART"
# Extract the target cookie
-COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH`
+COOKIE_ARG=`grep '^\-setcookie' $VMARGS_PATH`
if [ -z "$COOKIE_ARG" ]; then
echo "vm.args needs to have a -setcookie parameter."
exit 1
fi
-# Add ERTS bin dir to our path
-ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
+# Make sure CWD is set to the right dir
+cd $USE_DIR
+
+# Make sure log directory exists
+mkdir -p $USE_DIR/log
+
+RUNNER_SCRIPT_DATA=
+if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/runner_script.data" ]; then
+ RUNNER_SCRIPT_DATA=`cat $RUNNER_BASE_DIR/releases/$APP_VSN/runner_script.data`
+fi
-# Setup command to control the node
-NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
+if [ -z "$RUNNER_SCRIPT_DATA" ]; then
+ ROOTDIR=$RUNNER_BASE_DIR
+ ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
+ if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/nodetool" ]; then
+ NODETOOL="$ERTS_PATH/escript $RUNNER_BASE_DIR/releases/$APP_VSN/nodetool $NAME_ARG $COOKIE_ARG"
+ else
+ NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
+ fi
+ SLIM_ARGS=
+elif [ "$RUNNER_SCRIPT_DATA" = "slim" ]; then
+ # Setup system paths
+ SYSTEM_ERL_PATH=`which erl`
+ if [ ! -x "$SYSTEM_ERL_PATH" ]; then
+ echo "Failed to find erl. Is Erlang/OTP available in PATH?"
+ exit 1
+ fi
+ SYSTEM_HOME_BIN=${SYSTEM_ERL_PATH%/*}
+ ROOTDIR=$SYSTEM_HOME_BIN/../lib/erlang
+ ERTS_PATH=$ROOTDIR/erts-$ERTS_VSN/bin
+ unset SYSTEM_ERL_PATH
+ unset SYSTEM_HOME_BIN
+
+ LOCAL_ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
+ NODETOOL="$ERTS_PATH/escript $RUNNER_BASE_DIR/releases/$APP_VSN/nodetool $NAME_ARG $COOKIE_ARG"
+ unset LOCAL_ERL_PATH
+
+ # Setup additional arguments for slim release
+ SLIM_ARGS="-boot_var RELTOOL_EXT_LIB $RUNNER_BASE_DIR/lib -sasl releases_dir \"$RUNNER_BASE_DIR/releases\""
+else
+ echo "Unknown runner_script.data"
+ exit 1
+fi
# Setup remote shell command to control node
-REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"
+REMSH="$ERTS_PATH/erl -hidden $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"
+
+# Common functions
+
+# Ping node without allowing nodetool to take stdin
+ping_node() {
+ $NODETOOL ping < /dev/null
+}
+
+# Set the PID global variable, return 1 on error
+get_pid() {
+ PID=`$NODETOOL getpid < /dev/null`
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ echo "Node is not running!"
+ return 1
+ fi
+
+ # don't allow empty or init pid's
+ if [ -z $PID ] || [ "$PID" -le 1 ]; then
+ return 1
+ fi
+
+ return 0
+}
# Check the first argument for instructions
case "$1" in
- start)
+ start|start_boot)
# Make sure there is not already a node running
- RES=`$NODETOOL ping`
+ RES=`ping_node`
if [ "$RES" = "pong" ]; then
echo "Node is already running!"
exit 1
fi
- shift # remove $1
+ case "$1" in
+ start)
+ shift
+ START_OPTION="console"
+ HEART_OPTION="start"
+ ;;
+ start_boot)
+ shift
+ START_OPTION="console_boot"
+ HEART_OPTION="start_boot"
+ ;;
+ esac
RUN_PARAM=$(printf "\'%s\' " "$@")
- HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start $RUN_PARAM"
+ HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM"
export HEART_COMMAND
mkdir -p $PIPE_DIR
- $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console $RUN_PARAM" 2>&1
+ $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1
;;
stop)
# Wait for the node to completely stop...
case `uname -s` in
- Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
- # PID COMMAND
- PID=`ps ax -o pid= -o command=|\
- grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
- ;;
- SunOS)
- # PID COMMAND
- PID=`ps -ef -o pid= -o args=|\
- grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'`
- ;;
- CYGWIN*)
- # UID PID PPID TTY STIME COMMAND
- PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'`
- ;;
+ Darwin)
+ # Make sure we explicitly set this because iTerm.app doesn't for
+ # some reason.
+ COMMAND_MODE=unix2003
esac
+
+ # Get the PID from nodetool
+ get_pid
+ GPR=$?
+ if [ "$GPR" -ne 0 ] || [ -z $PID ]; then
+ exit $GPR
+ fi
+
+ # Tell nodetool to initiate a stop
$NODETOOL stop
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
fi
- while `kill -0 $PID 2>/dev/null`;
+
+ # Wait for the node to completely stop...
+ while `kill -s 0 $PID 2>/dev/null`
do
sleep 1
done
@@ -140,7 +273,7 @@
ping)
## See if the VM is alive
- $NODETOOL ping
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
@@ -148,8 +281,8 @@
;;
attach)
- # Make sure a node IS running
- RES=`$NODETOOL ping`
+ # Make sure a node is running
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -160,9 +293,26 @@
exec $ERTS_PATH/to_erl $PIPE_DIR
;;
- remote_console)
+ eval)
# Make sure a node IS running
- RES=`$NODETOOL ping`
+ ping_node > /dev/null 2>&1
+ ES=$?
+ if [ "$ES" -ne 0 ]; then
+ echo "Node is not running!"
+ exit $ES
+ fi
+
+ shift
+ $NODETOOL eval "$1"
+ ES_EVAL=$?
+ if [ "$ES_EVAL" -ne 0 ]; then
+ exit $ES_EVAL
+ fi
+ ;;
+
+ remote_console)
+ # Make sure a node is running
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
@@ -182,32 +332,34 @@
fi
# Make sure a node IS running
- RES=`$NODETOOL ping`
+ ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
exit $ES
fi
- node_name=`echo $NAME_ARG | awk '{print $2}'`
- erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'`
-
- $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2
+ $NODETOOL upgrade $2
;;
- console|console_clean)
+ console|console_clean|console_boot)
# .boot file typically just $SCRIPT (ie, the app name)
- # however, for debugging, sometimes start_clean.boot is useful:
+ # however, for debugging, sometimes start_clean.boot is useful.
+ # For e.g. 'setup', one may even want to name another boot script.
case "$1" in
console) BOOTFILE=$SCRIPT ;;
console_clean) BOOTFILE=start_clean ;;
+ console_boot)
+ shift
+ BOOTFILE="$1"
+ shift
+ ;;
esac
# Setup beam-required vars
- ROOTDIR=$RUNNER_BASE_DIR
BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\\///'`
- CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH"
+ CMD="$BINDIR/erlexec $SLIM_ARGS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH"
export EMU
export ROOTDIR
export BINDIR
@@ -232,11 +384,10 @@
FOREGROUNDOPTIONS="-noinput +Bd"
# Setup beam-required vars
- ROOTDIR=$RUNNER_BASE_DIR
BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\///'`
- CMD="$BINDIR/erlexec $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH"
+ CMD="$BINDIR/erlexec $SLIM_ARGS $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -config $CONFIG_PATH -args_file $VMARGS_PATH"
export EMU
export ROOTDIR
export BINDIR
@@ -249,8 +400,17 @@
# Start the VM
exec $CMD -- ${1+"$@"}
;;
+ getpid)
+ # Get the PID from nodetool
+ get_pid
+ ES=$?
+ if [ "$ES" -ne 0 ] || [ -z $PID ]; then
+ exit $ES
+ fi
+ echo $PID
+ ;;
*)
- echo "Usage: $SCRIPT {start|foreground|stop|restart|reboot|ping|console|console_clean|attach|remote_console|upgrade}"
+ echo "Usage: $SCRIPT {start|start_boot |foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot |attach|eval|remote_console|upgrade}"
exit 1
;;
esac
diff -Nru rebar-2.0.0/priv/templates/simplenode.windows.runner.cmd rebar-2.6.0/priv/templates/simplenode.windows.runner.cmd
--- rebar-2.0.0/priv/templates/simplenode.windows.runner.cmd 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.windows.runner.cmd 2015-06-19 16:14:28.000000000 +0000
@@ -6,22 +6,35 @@
@rem which is assumed to be the node root.
@for /F "delims=" %%I in ("%~dp0..") do @set node_root=%%~fI
+@rem CWD to the node root directory
+@cd %node_root%
+
@set releases_dir=%node_root%\releases
@rem Parse ERTS version and release version from start_erl.data
-@for /F "tokens=1,2" %%I in (%releases_dir%\start_erl.data) do @(
+@for /F "usebackq tokens=1,2" %%I in ("%releases_dir%\start_erl.data") do @(
@call :set_trim erts_version %%I
@call :set_trim release_version %%J
)
-@rem extract erlang cookie from vm.args
@set vm_args=%releases_dir%\%release_version%\vm.args
-@for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie %vm_args%`) do @set erlang_cookie=%%J
+@set sys_config=%releases_dir%\%release_version%\sys.config
+@set node_boot_script=%releases_dir%\%release_version%\%node_name%
+@set clean_boot_script=%releases_dir%\%release_version%\start_clean
+
+@rem extract erlang cookie from vm.args
+@for /f "usebackq tokens=1-2" %%I in (`findstr /b \-setcookie "%vm_args%"`) do @set erlang_cookie=%%J
@set erts_bin=%node_root%\erts-%erts_version%\bin
@set service_name=%node_name%_%release_version%
+@set erlsrv="%erts_bin%\erlsrv.exe"
+@set epmd="%erts_bin%\epmd.exe"
+@set escript="%erts_bin%\escript.exe"
+@set werl="%erts_bin%\werl.exe"
+@set nodetool="%erts_bin%\nodetool"
+
@if "%1"=="usage" @goto usage
@if "%1"=="install" @goto install
@if "%1"=="uninstall" @goto uninstall
@@ -29,44 +42,53 @@
@if "%1"=="stop" @goto stop
@if "%1"=="restart" @call :stop && @goto start
@if "%1"=="console" @goto console
+@if "%1"=="ping" @goto ping
@if "%1"=="query" @goto query
@if "%1"=="attach" @goto attach
@if "%1"=="upgrade" @goto upgrade
@echo Unknown command: "%1"
:usage
-@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|query^|attach^|upgrade]
+@echo Usage: %~n0 [install^|uninstall^|start^|stop^|restart^|console^|ping^|query^|attach^|upgrade]
@goto :EOF
:install
-@%erts_bin%\erlsrv.exe add %service_name% -c "Erlang node %node_name% in %node_root%" -sname %node_name% -w %node_root% -m %node_root%\bin\start_erl.cmd -args " ++ %node_name% ++ %node_root%" -stopaction "init:stop()."
+@set description=Erlang node %node_name% in %node_root%
+@set start_erl=%node_root%\bin\start_erl.cmd
+@set args= ++ %node_name% ++ %node_root%
+@%erlsrv% add %service_name% -c "%description%" -sname %node_name% -w "%node_root%" -m "%start_erl%" -args "%args%" -stopaction "init:stop()."
@goto :EOF
:uninstall
-@%erts_bin%\erlsrv.exe remove %service_name%
-@%erts_bin%\epmd.exe -kill
+@%erlsrv% remove %service_name%
+@%epmd% -kill
@goto :EOF
:start
-@%erts_bin%\erlsrv.exe start %service_name%
+@%erlsrv% start %service_name%
@goto :EOF
:stop
-@%erts_bin%\erlsrv.exe stop %service_name%
+@%erlsrv% stop %service_name%
@goto :EOF
:console
-@start %erts_bin%\werl.exe -boot %releases_dir%\%release_version%\%node_name% -config %releases_dir%\%release_version%\sys.config -args_file %vm_args% -sname %node_name%
+@start "%node_name% console" %werl% -boot "%node_boot_script%" -config "%sys_config%" -args_file "%vm_args%" -sname %node_name%
+@goto :EOF
+
+:ping
+@%escript% %nodetool% ping -sname "%node_name%" -setcookie "%erlang_cookie%"
+@exit %ERRORLEVEL%
@goto :EOF
:query
-@%erts_bin%\erlsrv.exe list %service_name%
-@exit /b %ERRORLEVEL%
+@%erlsrv% list %service_name%
+@exit %ERRORLEVEL%
@goto :EOF
:attach
@for /f "usebackq" %%I in (`hostname`) do @set hostname=%%I
-start %erts_bin%\werl.exe -boot %releases_dir%\%release_version%\start_clean -remsh %node_name%@%hostname% -sname console -setcookie %erlang_cookie%
+start "%node_name% attach" %werl% -boot "%clean_boot_script%" -remsh %node_name%@%hostname% -sname console -setcookie %erlang_cookie%
@goto :EOF
:upgrade
@@ -76,7 +98,7 @@
@echo NOTE {package base name} MUST NOT include the .tar.gz suffix
@goto :EOF
)
-@%erts_bin%\escript.exe %node_root%\bin\install_upgrade.escript %node_name% %erlang_cookie% %2
+@%escript% %nodetool% -sname "%node_name%" -setcookie "%erlang_cookie%" upgrade %2
@goto :EOF
:set_trim
diff -Nru rebar-2.0.0/priv/templates/simplenode.windows.start_erl.cmd rebar-2.6.0/priv/templates/simplenode.windows.start_erl.cmd
--- rebar-2.0.0/priv/templates/simplenode.windows.start_erl.cmd 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/priv/templates/simplenode.windows.start_erl.cmd 2015-06-19 16:14:28.000000000 +0000
@@ -6,30 +6,31 @@
@for /F "delims=++ tokens=1,2,3" %%I in (%args%) do @(
@set erl_args=%%I
@call :set_trim node_name %%J
- @call :set_trim node_root %%K
+ @rem Trim spaces from the left of %%K (node_root), which may have spaces inside
+ @for /f "tokens=* delims= " %%a in ("%%K") do @set node_root=%%a
)
@set releases_dir=%node_root%\releases
@rem parse ERTS version and release version from start_erl.dat
-@for /F "tokens=1,2" %%I in (%releases_dir%\start_erl.data) do @(
+@for /F "usebackq tokens=1,2" %%I in ("%releases_dir%\start_erl.data") do @(
@call :set_trim erts_version %%I
@call :set_trim release_version %%J
)
-@set erl_exe=%node_root%\erts-%erts_version%\bin\erl.exe
-@set boot_file=%releases_dir%\%release_version%\%node_name%
+@set erl_exe="%node_root%\erts-%erts_version%\bin\erl.exe"
+@set boot_file="%releases_dir%\%release_version%\%node_name%"
-@if exist %releases_dir%\%release_version%\sys.config (
- @set app_config=%releases_dir%\%release_version%\sys.config
+@if exist "%releases_dir%\%release_version%\sys.config" (
+ @set app_config="%releases_dir%\%release_version%\sys.config"
) else (
- @set app_config=%node_root%\etc\app.config
+ @set app_config="%node_root%\etc\app.config"
)
-@if exist %releases_dir%\%release_version%\vm.args (
- @set vm_args=%releases_dir%\%release_version%\vm.args
+@if exist "%releases_dir%\%release_version%\vm.args" (
+ @set vm_args="%releases_dir%\%release_version%\vm.args"
) else (
- @set vm_args=%node_root%\etc\vm.args
+ @set vm_args="%node_root%\etc\vm.args"
)
@%erl_exe% %erl_args% -boot %boot_file% -config %app_config% -args_file %vm_args%
diff -Nru rebar-2.0.0/README.md rebar-2.6.0/README.md
--- rebar-2.0.0/README.md 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/README.md 2015-06-19 16:14:28.000000000 +0000
@@ -1,27 +1,28 @@
rebar
=====
-rebar is an Erlang build tool that makes it easy to compile and
-test Erlang applications, port drivers and releases.
+rebar is an Erlang build tool that makes it easy to compile and test Erlang
+applications, port drivers and releases.
-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
-configuration work. rebar also provides dependency management, enabling
-application writers to easily re-use common libraries from a variety of
+[![Build Status](https://secure.travis-ci.org/rebar/rebar.png?branch=master)](http://travis-ci.org/rebar/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
+configuration work. rebar also provides dependency management, enabling
+application writers to easily re-use common libraries from a variety of
locations (git, hg, etc).
Building
--------
-Information on building and installing [Erlang/OTP](http://www.erlang.org)
-can be found [here](https://github.com/erlang/otp/wiki/Installation)
-([more info](https://github.com/erlang/otp/blob/master/INSTALL.md)).
+Information on building and installing [Erlang/OTP](http://www.erlang.org) can
+be found [here](https://github.com/erlang/otp/wiki/Installation) ([more
+info](https://github.com/erlang/otp/blob/master/HOWTO/INSTALL.md)).
### Dependencies
-To build rebar you will need a working installation of Erlang R13B03 (or
-later).
+To build rebar you will need a working installation of Erlang R13B03 (or later).
Should you want to clone the rebar repository, you will also require git.
@@ -29,12 +30,12 @@
You can download a pre-built binary version of rebar from:
-https://github.com/basho/rebar/wiki/rebar
+https://github.com/rebar/rebar/wiki/rebar
#### Building rebar
```sh
-$ git clone git://github.com/basho/rebar.git
+$ git clone git://github.com/rebar/rebar.git
$ cd rebar
$ ./bootstrap
Recompile: src/getopt
@@ -50,98 +51,29 @@
Contributing to rebar
=====================
-Pull requests and branching
----------------------------
-
-Use one topic branch per pull request.
-
-Do not commit to master in your fork.
-
-Provide a clean branch without any merge commits from upstream.
-
-Usually you should squash any intermediate commits into the original single commit.
-
-Code style
-----------
-
-Do not introduce trailing whitespace.
-
-Do not mix spaces and tabs.
+Please refer to [CONTRIBUTING](CONTRIBUTING.md).
-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.
-
-Writing Commit Messages
+Community and Resources
-----------------------
-Structure your commit message like this:
-
-
-One line summary (less than 50 characters)
-
-Longer description (wrap at 72 characters)
-
-
-### Summary
-
-* Less than 50 characters
-* What was changed
-* Imperative present tense (fix, add, change)
- * `Fix bug 123`
- * `Add 'foobar' command`
- * `Change default timeout to 123`
-* No period
-
-### Description
-
-* Wrap at 72 characters
-* Why, explain intention and implementation approach
-* Present tense
-
-### Atomicity
-
-* Break up logical changes
-* Make whitespace changes separately
-
-Dialyzer and Tidier
--------------------
-
-Before you submit a patch check for
-[xref](http://www.erlang.org/doc/man/xref.html) and
-[Dialyzer](http://www.erlang.org/doc/man/dialyzer.html)
-warnings.
-
-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).
-
-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.
+In case of problems that cannot be solved through documentation or examples, you
+may want to try to contact members of the community for help. The community is
+also where you want to go for questions about how to extend rebar, fill in bug
+reports, and so on.
+
+The main place to go for questions is the [rebar mailing
+list](http://lists.basho.com/pipermail/rebar_lists.basho.com/). If you need
+quick feedback, you can try the #rebar channel on
+[irc.freenode.net](http://freenode.net). Be sure to check the
+[wiki](https://github.com/rebar/rebar/wiki) first, just to be sure you're not
+asking about things with well known answers.
+
+For bug reports, roadmaps, and issues, visit the [github issues
+page](https://github.com/rebar/rebar/issues).
+
+General rebar community resources and links:
+
+- [Rebar Mailing List](http://lists.basho.com/pipermail/rebar_lists.basho.com/)
+- #rebar on [irc.freenode.net](http://freenode.net/)
+- [wiki](https://github.com/rebar/rebar/wiki)
+- [issues](https://github.com/rebar/rebar/issues)
diff -Nru rebar-2.0.0/rebar.config rebar-2.6.0/rebar.config
--- rebar-2.0.0/rebar.config 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/rebar.config 2015-06-19 16:14:28.000000000 +0000
@@ -1,15 +1,44 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-{app_bin, ["priv/rebar"]}.
-{erl_opts, [warnings_as_errors]}.
+%% 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/*", "."}]}.
+
+%% Types dict:dict() and digraph:digraph() have been introduced in Erlang 17.
+%% At the same time, their counterparts dict() and digraph() are to be
+%% deprecated in Erlang 18. namespaced_types option is used to select proper
+%% type name depending on the OTP version used.
+{erl_opts,
+ [
+ {platform_define, "^[0-9]+", namespaced_types}
+ ]}.
+
{xref_checks, []}.
{xref_queries,
[{"(XC - UC) || (XU - X - B
- (\"escript\":\"foldl\"/\"3\")
+ - (\"eunit_test\":\"function_wrapper\"/\"2\")
+ - (\"eflame\":\"apply\"/\"5\")
- (\"abnfc\":\"file\"/\"2\")
- (\"erlydtl\":\"compile\"/\"3\")
- (\"lfe_comp\":\"file\"/\"2\")
- (\"neotoma\":\"file\"/\"2\")
- - (\"protobuffs_compile\":\"scan_file\"/\"1\"))",
+ - (\"protobuffs_compile\":\"scan_file\"/\"2\")
+ - (\"gpb_compile\":\"file\"/\"2\")
+ - (\"gpb_compile\":\"format_error\"/\"1\")
+ - (\"diameter_codegen\":\"from_dict\"/\"4\")
+ - (\"diameter_dict_util\":\"format_error\"/\"1\")
+ - (\"diameter_dict_util\":\"parse\"/\"2\"))",
[]}]}.
+
+{dialyzer,
+ [
+ {plt_extra_apps, [diameter]},
+ {warnings,
+ [
+ unmatched_returns,
+ error_handling,
+ race_conditions
+ ]}
+ ]}.
diff -Nru rebar-2.0.0/rebar.config.sample rebar-2.6.0/rebar.config.sample
--- rebar-2.0.0/rebar.config.sample 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/rebar.config.sample 2015-06-19 16:14:28.000000000 +0000
@@ -5,6 +5,14 @@
%% == Core ==
+%% Extend list of always recursive commands
+{recursive_cmds, []}.
+
+%% Check required ERTS or OTP release version
+{require_erts_vsn, ".*"}.
+{require_otp_vsn, ".*"}.
+{require_min_otp_vsn, ".*"}.
+
%% Additional library directories to add to the code path
{lib_dirs, []}.
@@ -13,10 +21,12 @@
%% Erlang files to compile before the rest. Rebar automatically compiles
%% parse_transforms and custom behaviours before anything other than the files
%% in this list.
-{erl_first_files, ["mymib1", "mymib2"]}.
+{erl_first_files, ["src/mymib1.erl", "src/mymib2.erl"]}.
%% Erlang compiler options
-{erl_opts, [no_debug_info, {i, "myinclude"}, {src_dirs, ["src1", "src2"]},
+{erl_opts, [no_debug_info,
+ {i, "myinclude"},
+ {src_dirs, ["src", "src2", "src3"]},
{platform_define,
"(linux|solaris|freebsd|darwin)", 'HAVE_SENDFILE'},
{platform_define, "(linux|freebsd)", 'BACKLOG', 128},
@@ -28,6 +38,18 @@
%% SNMP mibs to compile first?
{mib_first_files, []}.
+%% leex options
+{xrl_opts, []}.
+
+%% leex files to compile first
+{xrl_first_files, []}.
+
+%% yecc options
+{yrl_opts, []}.
+
+%% yecc files to compile first
+{yrl_first_files, []}.
+
%% == EDoc ==
%% EDoc options
@@ -46,7 +68,14 @@
%% architecture as a filter.
{port_specs, [{"priv/so_name.so", ["c_src/*.c"]},
{"linux", "priv/hello_linux", ["c_src/hello_linux.c"]},
- {"linux", "priv/hello_linux", ["c_src/*.c"], [{env, []}]}}.
+ {"linux", "priv/hello_linux", ["c_src/*.c"], [{env, []}]}]}.
+
+%% == escriptize ==
+{escript_name, "application"}.
+{escript_incl_apps, []}.
+{escript_shebang, "#!/usr/bin/env escript\n"}.
+{escript_comment, "%%\n"}.
+{escript_emu_args, "%%! -pa application/application/ebin\n"}.
%% == LFE Compiler ==
@@ -60,46 +89,83 @@
%% Options for the ErlyDTL compiler
{erlydtl_opts, []}.
+%% == Proto compiler ==
+{proto_opts, [
+ {compiler, protobuffs},
+ {src_dirs, ["src"]}
+ ]}.
+%% Available compilers for protocol buffer files (*.proto):
+%% protobuffs (default)
+%% gpb
+%% Optional src_dirs which is a list of directories where
+%% to look for .proto files, default is src
+
+%% Options for the gpb protocol buffer compiler,
+%% if selected by the proto_compiler option
+{gpb_opts, []}.
+
+%% == Diameter compiler ==
+
+%% Diameter files to compile before the rest
+{dia_first_files, []}.
+
+%% Options for the diameter compiler
+{dia_opts, []}.
+
%% == EUnit ==
%% Options for eunit:test()
{eunit_opts, []}.
-%% Additional compile options for eunit. erl_opts from above is also used
+%% Additional compile options for eunit. erl_opts is also used
{eunit_compile_opts, []}.
%% Same as erl_first_files, but used only when running 'eunit'
{eunit_first_files, []}.
+%% == Cover ==
+
%% Whether to enable coverage reporting. Default is `false'
{cover_enabled, false}.
%% Whether to print coverage report to console. Default is `false'
{cover_print_enabled, false}.
+%% Whether to export coverage report to file. Default is `false'
+{cover_export_enabled, false}.
+
%% == Common Test ==
%% Override the default "test" directory in which SUITEs are located
{ct_dir, "itest"}.
+%% Override the default "logs" directory in which SUITEs are logged
+{ct_log_dir, "test/logs"}.
+
%% 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}.
+
+%% == QuickCheck ==
+
+%% If qc_mod is unspecified, rebar tries to detect Triq or EQC
+{qc_opts, [{qc_mod, module()}, Options]}.
+
+%% Additional compile options for qc. erl_opts is also used
+{qc_compile_opts, []}.
+
+%% Same as erl_first_files, but used only when running 'qc'
+{qc_first_files, []}.
+
%% == Cleanup ==
%% Which files to cleanup
{clean_files, ["file", "file2"]}.
-%% == Reltool ==
-
-%% Target directory for the release
-{target, "target"}.
-
%% == OTP Applications ==
-%% Binaries to link into the erlang path?
-{app_bin, []}.
-
%% Enable validation of the OTP app module list. Default is 'true'
{validate_app_modules, true}.
@@ -111,11 +177,42 @@
%% What dependencies we have, dependencies can be of 3 forms, an application
%% name as an atom, eg. mochiweb, a name and a version (from the .app file), or
%% an application name, a version and the SCM details on how to fetch it (SCM
-%% type, location and revision). Rebar currently supports git, hg, bzr and svn.
-{deps, [application_name,
- {application_name, "1.0.*"},
- {application_name, "1.0.*",
- {git, "git://github.com/basho/rebar.git", {branch, "master"}}}]}.
+%% type, location and revision).
+%% Rebar currently supports git, hg, bzr, svn, rsync, fossil, and p4.
+{deps, [app_name,
+ {rebar, "1.0.*"},
+ {rebar, ".*",
+ {git, "git://github.com/rebar/rebar.git"}},
+ {rebar, ".*",
+ {git, "git://github.com/rebar/rebar.git", "Rev"}},
+ {rebar, "1.0.*",
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
+ {rebar, "1.0.0",
+ {git, "git://github.com/rebar/rebar.git", {tag, "1.0.0"}}},
+ %% Dependencies can be marked as 'raw'. Rebar does not require
+ %% such dependencies to have a standard Erlang/OTP layout
+ %% which assumes the presence of either
+ %% "src/dependency_name.app.src" or "ebin/dependency_name.app"
+ %% files.
+ %%
+ %% 'raw' dependencies can still contain 'rebar.config' and
+ %% even can have the proper OTP directory layout, but they
+ %% won't be compiled.
+ %%
+ %% Only a subset of rebar commands will be executed on the
+ %% 'raw' subdirectories: get-deps, update-deps, check-deps,
+ %% list-deps and delete-deps.
+ {rebar, "",
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}},
+ [raw]},
+ {app_name, ".*", {hg, "https://www.example.org/url"}},
+ {app_name, ".*", {rsync, "Url"}},
+ {app_name, ".*", {svn, "https://www.example.org/url"}},
+ {app_name, ".*", {svn, "svn://svn.example.org/url"}},
+ {app_name, ".*", {bzr, "https://www.example.org/url", "Rev"}},
+ {app_name, ".*", {fossil, "https://www.example.org/url"}},
+ {app_name, ".*", {fossil, "https://www.example.org/url", "Vsn"}},
+ {app_name, ".*", {p4, "//depot/subdir/app_dir"}}]}.
%% == Subdirectories ==
@@ -151,14 +248,34 @@
{xref_warnings, false}.
+%% optional extra paths to include in xref:set_library_path/2.
+%% specified relative location of rebar.config.
+%% e.g. {xref_extra_paths,["../gtknode/src"]}
+{xref_extra_paths,[]}.
+
%% xref checks to run
-{xref_checks, [exports_not_used, undefined_function_calls]}.
+{xref_checks, [undefined_function_calls, undefined_functions,
+ locals_not_used, exports_not_used,
+ deprecated_function_calls, deprecated_functions]}.
%% Optional custom xref queries (xref manual has details) specified as
%% {xref_queries, [{query_string(), expected_query_result()},...]}
-%% The following for example removes all references to ejabberd:*_msg/4
+%% The following for example removes all references to mod:*foo/4
%% functions from undefined external function calls as those are in a
%% generated module
{xref_queries,
[{"(XC - UC) || (XU - X - B"
- " - (\"ejabberd_logger\":\".*_msg\"/\"4\"))",[]}]}.
+ " - (\"mod\":\".*foo\"/\"4\"))",[]}]}.
+
+%% == Dialyzer ==
+
+{dialyzer,
+ [
+ %% Store PLT locally inside the project in .rebar (Default)
+ {plt_location, local},
+ %% Store PLT in custom directory
+ {plt_location, "custom_dir"},
+ %% Extra apps to include in the PLT
+ {plt_extra_apps, [app1, app2]},
+ {warnings, [unmatched_returns, error_handling]}
+ ]}.
diff -Nru rebar-2.0.0/rebar.config.script rebar-2.6.0/rebar.config.script
--- rebar-2.0.0/rebar.config.script 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/rebar.config.script 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,17 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
+ExtraDeps = [{retest, ".*", {git, "git://github.com/dizzyd/retest.git"}}],
+
+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 -Nru rebar-2.0.0/RELEASE-NOTES.md rebar-2.6.0/RELEASE-NOTES.md
--- rebar-2.0.0/RELEASE-NOTES.md 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/RELEASE-NOTES.md 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,186 @@
+# 2.6.0
+
+* rebar/203: [Pluggable proto compilers gpb](https://github.com/rebar/rebar/pull/203)
+* rebar/273: [Use target_dir as source of new version in generate-appups](https://github.com/rebar/rebar/pull/273)
+* rebar/293: [Check C source dependencies in needs_compile](https://github.com/rebar/rebar/pull/293)
+* rebar/305: [Fix compiler invocation on multiarch Linux](https://github.com/rebar/rebar/pull/305)
+* rebar/322: [Treat vsn mismatch as warning if -k/--keep-going](https://github.com/rebar/rebar/pull/322)
+* rebar/336: [Add details on Dialyzer with "make check"](https://github.com/rebar/rebar/pull/336)
+* rebar/337: [Implement eflame -p/--profile support](https://github.com/rebar/rebar/pull/337)
+* rebar/338: [Processing .app.src.script expects a single value to be returned.](https://github.com/rebar/rebar/pull/338)
+* rebar/344: [Manually clean up paths.](https://github.com/rebar/rebar/pull/344)
+* rebar/351: [fish shell completions for rebar](https://github.com/rebar/rebar/pull/351)
+* rebar/352: [Add typer target (rebase of #309)](https://github.com/rebar/rebar/pull/352)
+* rebar/354: [compiler respects 'keep_going' flag](https://github.com/rebar/rebar/pull/354)
+* rebar/355: [Fix 'make build_plt'](https://github.com/rebar/rebar/pull/355)
+* rebar/356: [Fix minor typo in CONTRIBUTING.md](https://github.com/rebar/rebar/pull/356)
+* rebar/360: [Minor follow-up fixes for #293](https://github.com/rebar/rebar/pull/360)
+* rebar/368: [Escape more characters in path (fix #367)](https://github.com/rebar/rebar/pull/368)
+* rebar/371: [Fix cover print truncation when coverage is 100%](https://github.com/rebar/rebar/pull/371)
+* rebar/372: [Implement eval command via nodetool](https://github.com/rebar/rebar/pull/372)
+* rebar/376: [Remove check adding ebin to path for edoc target](https://github.com/rebar/rebar/pull/376)
+* rebar/378: [deps: fix delete-deps if deps_dir ends with dot](https://github.com/rebar/rebar/pull/378)
+* rebar/382: [Adapt dialyzer_reference to ba466e2d changes](https://github.com/rebar/rebar/pull/382)
+* rebar/385: [Fix Dialyzer warning introduced in 0caf047f](https://github.com/rebar/rebar/pull/385)
+* rebar/386: [Recompile .proto files with gpb also with prefix/suffix](https://github.com/rebar/rebar/pull/386)
+* rebar/386: [Recompile .proto files with gpb also with prefix/suffix](https://github.com/rebar/rebar/pull/386)
+* rebar/386: [Recompile .proto files with gpb also with prefix/suffix](https://github.com/rebar/rebar/pull/386)
+* rebar/399: [Increase the timeout for the inttest/proto_gpb](https://github.com/rebar/rebar/pull/399)
+* rebar/400: [add Emacs/vi header to non-dummy test modules](https://github.com/rebar/rebar/pull/400)
+* rebar/403: [Update reference to installation notes](https://github.com/rebar/rebar/pull/403)
+* rebar/404: [Consistently format export attributes](https://github.com/rebar/rebar/pull/404)
+* rebar/405: [Generate cachegrind file if erlgrind is available](https://github.com/rebar/rebar/pull/405)
+* rebar/406: [Fix deps path check in rebar_ct:collect_glob/3](https://github.com/rebar/rebar/pull/406)
+* rebar/408: [Fix/remove duplicate console message](https://github.com/rebar/rebar/pull/408)
+* rebar/411: [Fix app.config argument passing when using ct_run (take 2)](https://github.com/rebar/rebar/pull/411)
+* rebar/413: [Revert "Merge pull request #386 ... gpb-recompilation...detection"](https://github.com/rebar/rebar/pull/413)
+* rebar/418: [Fix #415 (reltool vsn check)](https://github.com/rebar/rebar/pull/418)
+* rebar/420: [Mock gpb and protobuffs, in inttest, replacing external dependencies](https://github.com/rebar/rebar/pull/420)
+* rebar/421: [inttest/ct3: fix travis-ci breakage](https://github.com/rebar/rebar/pull/421)
+* rebar/424: [Gpb recompilation detection (using base compiler)](https://github.com/rebar/rebar/pull/424)
+* rebar/425: [Copy instead of rsync gpb and protobuffs inttest mocks](https://github.com/rebar/rebar/pull/425)
+* rebar/426: [Fixed #133. Release upgrade now handle long and short names properly.](https://github.com/rebar/rebar/pull/426)
+* rebar/428: [Remove a git url in gpb and protobuffs inttest configs](https://github.com/rebar/rebar/pull/428)
+* rebar/430: [Exit with proper status code if 'eval' fails](https://github.com/rebar/rebar/pull/430)
+* rebar/432: [Document recursive_cmds in -r help string as well](https://github.com/rebar/rebar/pull/432)
+* rebar/433: [inttest/ct3: fix overlong line](https://github.com/rebar/rebar/pull/433)
+* rebar/437: [Fix .app.src.script bug introduced in b44b4f4](https://github.com/rebar/rebar/pull/437)
+* rebar/440: [Delete obsolete file](https://github.com/rebar/rebar/pull/440)
+* rebar/442: [.travis.yml: print information before running script](https://github.com/rebar/rebar/pull/442)
+* rebar/444: [Fix incorrect "not an app dir" warning](https://github.com/rebar/rebar/pull/444)
+* rebar/445: [rebar doesn't respect the order of erl_first_files given in the rebar.conf file](https://github.com/rebar/rebar/pull/445)
+* rebar/447: [Support custom protobuf directory](https://github.com/rebar/rebar/pull/447)
+* rebar/449: [Support .appup.src files](https://github.com/rebar/rebar/pull/449)
+* rebar/452: [added 'shell' command to bash-completion](https://github.com/rebar/rebar/pull/452)
+* rebar/456: [Generate json output from cover](https://github.com/rebar/rebar/pull/456)
+* rebar/458: [Change env var delimiter to match non-word](https://github.com/rebar/rebar/pull/458)
+* rebar/459: [Remove -m64 flag.](https://github.com/rebar/rebar/pull/459)
+* rebar/460: [Add Dialyzer plugin](https://github.com/rebar/rebar/pull/460)
+* rebar/461: [Fix OTP .appup.src processing on empty lists](https://github.com/rebar/rebar/pull/461)
+* rebar/463: [Print more info when profiling](https://github.com/rebar/rebar/pull/463)
+* rebar/466: [Improve test targets in Makefile](https://github.com/rebar/rebar/pull/466)
+* rebar/467: [Refactor logic and optimizations in rebar_erlc_compiler:doterl_compile/4](https://github.com/rebar/rebar/pull/467)
+* rebar/469: [Fix dialyzer warnings](https://github.com/rebar/rebar/pull/469)
+* rebar/470: [Fix whitespace errors](https://github.com/rebar/rebar/pull/470)
+* rebar/471: [Fix whitespace errors](https://github.com/rebar/rebar/pull/471)
+* rebar/475: [Adapt to 18.x time api changes](https://github.com/rebar/rebar/pull/475)
+* rebar/477: [Enable parse transformations in rebar config](https://github.com/rebar/rebar/pull/477)
+* rebar/478: [bootstrap: better warning fix (Thanks James Fish)](https://github.com/rebar/rebar/pull/478)
+* rebar/482: [Windows runner - CD to node root](https://github.com/rebar/rebar/pull/482)
+* rebar/484: [/me added to THANKS](https://github.com/rebar/rebar/pull/484)
+* rebar/485: [avoid pre-compile time errors in expand_include_lib_path](https://github.com/rebar/rebar/pull/485)
+* rebar/487: [erlc: fix recently introduced whitespace errors](https://github.com/rebar/rebar/pull/487)
+* rebar/489: [Fix crash on failed build console output](https://github.com/rebar/rebar/pull/489)
+* rebar/494: [Update line number of allowed dialyzer error](https://github.com/rebar/rebar/pull/494)
+* rebar/496: [Update PLT detail for make build_plt](https://github.com/rebar/rebar/pull/496)
+* rebar/499: [Try one more location for the OTP_VERSION file](https://github.com/rebar/rebar/pull/499)
+* rebar/500: [Makefile: clean only .rebar/erlcinfo](https://github.com/rebar/rebar/pull/500)
+* rebar/502: [Don't crash if missing OTP_VERSION file (fix #350)](https://github.com/rebar/rebar/pull/502)
+* rebar/504: [Drop `shared` PLTs support and change PLT name to .plt](https://github.com/rebar/rebar/pull/504)
+* rebar/505: [rebar_utils: explain pdict use](https://github.com/rebar/rebar/pull/505)
+* rebar/508: [rebar_core: add missing newline in log msg](https://github.com/rebar/rebar/pull/508)
+* rebar/509: [erlc: do not crash if dep file cannot be found](https://github.com/rebar/rebar/pull/509)
+* rebar/510: [Fix 'make deps'](https://github.com/rebar/rebar/pull/510)
+* rebar/511: [Add and use memoization server](https://github.com/rebar/rebar/pull/511)
+* rebar/512: [rmemo: properly handle unsupported call](https://github.com/rebar/rebar/pull/512)
+
+
+# Rebar 2.5.1
+
+* rebar/299: [Fix OS X resource fork handling (Reported-by: Richard O'Keefe)](https://github.com/rebar/rebar/pull/299)
+* rebar/307: [bootstrap now accepts --help usage flag](https://github.com/rebar/rebar/pull/307)
+* rebar/316: [fix for #314 (rebar shell somehow blocks using io:format in gen_server handle_call)](https://github.com/rebar/rebar/pull/316)
+* rebar/327: [Adapt arch string to versioning scheme changes (>= 17.x)](https://github.com/rebar/rebar/pull/327)
+* rebar/328: [Follow-up typo fixes for #327](https://github.com/rebar/rebar/pull/328)
+* rebar/330: [Remove experimental label from 'eunit tests='](https://github.com/rebar/rebar/pull/330)
+* rebar/332: [Update dialyzer_reference](https://github.com/rebar/rebar/pull/332)
+
+# Rebar 2.5.0
+
+* Reverted rebar/281: [Move include/rebar.hrl to src/rebar.hrl](https://github.com/rebar/rebar/pull/281) as it broke backwards compatibility
+
+# Rebar 2.4.0
+
+* rebar/52: [Slim release support](https://github.com/rebar/rebar/pull/52)
+* rebar/112: [Add code coverage analysis functionality to `qc'](https://github.com/rebar/rebar/pull/112)
+* rebar/119: [Add qualified name tests specification (see #118)](https://github.com/rebar/rebar/pull/119)
+* rebar/130: [ct fixes](https://github.com/rebar/rebar/pull/130)
+* rebar/136: [Add support for the Perforce VCS client via the "p4" tool](https://github.com/rebar/rebar/pull/136)
+* rebar/195: [Switch template instructions](https://github.com/rebar/rebar/pull/195)
+* rebar/229: [Add REBAR to environment before executing hooks](https://github.com/rebar/rebar/pull/229)
+* rebar/260: [Quote include/lib paths to handle spaces in Erlang installs (fixes build on windows)](https://github.com/rebar/rebar/pull/260)
+* rebar/280: [improve output when using `rebar shell`](https://github.com/rebar/rebar/pull/280)
+* rebar/281: [Move include/rebar.hrl to src/rebar.hrl](https://github.com/rebar/rebar/pull/281)
+* rebar/284: [Error 'Command not found' when sname is used](https://github.com/rebar/rebar/pull/284)
+* rebar/285: [Fix #249 (erlc regression)](https://github.com/rebar/rebar/pull/285)
+* rebar/288: [Extend and document contributing rules](https://github.com/rebar/rebar/pull/288)
+* rebar/289: [erlc: fix typo in update_erlcinfo/3 clause that would make the function fail](https://github.com/rebar/rebar/pull/289)
+* rebar/290: [erlc: replace if expression with case of](https://github.com/rebar/rebar/pull/290)
+* rebar/292: [Namespaced types: fix build for 17.0](https://github.com/rebar/rebar/pull/292)
+* rebar/296: [Add gen_event template](https://github.com/rebar/rebar/pull/296)
+
+
+# Rebar 2.3.1
+
+## PR's Merged
+
+* rebar/242: [Extra commits for #129](https://github.com/rebar/rebar/pull/242)
+* rebar/244: [Document skip_apps=, apps=, and require_*_vsn](https://github.com/rebar/rebar/pull/244)
+* rebar/251: [Make sure that eunit/qc_compile_opts works](https://github.com/rebar/rebar/pull/251)
+* rebar/255: [rebar.app: remove superfluous quoting](https://github.com/rebar/rebar/pull/255)
+* rebar/274: [Use lowercase for Windows drive name to resolve issue #250](https://github.com/rebar/rebar/pull/274)
+
+# Rebar 2.3.0
+
+## PR's Merged
+
+* rebar/98: [Repetition of environment variable definitions in child processes (ports)](https://github.com/rebar/rebar/pull/98)
+* rebar/115: [Incorrect REMSH args when sname is used.](https://github.com/rebar/rebar/pull/115)
+* rebar/129: [Speed up the compilation process v5](https://github.com/rebar/rebar/pull/129)
+* rebar/139: [Allow specification of module dependencies for appups](https://github.com/rebar/rebar/pull/139)
+* rebar/175: [CWD plugins regression](https://github.com/rebar/rebar/pull/175)
+* rebar/188: [Xref extra path](https://github.com/rebar/rebar/pull/188)
+* rebar/208: [Fix typo in rebar_erlydtl_compiler](https://github.com/rebar/rebar/pull/208)
+* rebar/219: [Added R16B01 and R16B02 to travis config.](https://github.com/rebar/rebar/pull/219)
+* rebar/221: [Adapt erlydtl compiler plugin to latest version of erlydtl](https://github.com/rebar/rebar/pull/221)
+* rebar/223: [Add random_suite_order option to eunit command](https://github.com/rebar/rebar/pull/223)
+* rebar/224: [allow suites or tests as options for eunit and ct](https://github.com/rebar/rebar/pull/224)
+* rebar/230: [eunit: fix dialyzer warnings introduced in 03da5e0b](https://github.com/rebar/rebar/pull/230)
+* rebar/232: [Document support for abbreviated commands](https://github.com/rebar/rebar/pull/232)
+* rebar/233: [docs: fix #228](https://github.com/rebar/rebar/pull/233)
+* rebar/234: [Fix #220 (Reported-by: Joseph Norton)](https://github.com/rebar/rebar/pull/234)
+* rebar/237: [Add partial support for Erlang/OTP 17](https://github.com/rebar/rebar/pull/237)
+* rebar/252: [file_utils: properly report errors (fix #95)](https://github.com/rebar/rebar/pull/252)
+* rebar/254: [Fix 'rebar generate' regression (#253)](https://github.com/rebar/rebar/pull/254)
+* rebar/265: [Fix 'rebar help clean' function_clause error](https://github.com/rebar/rebar/pull/265)
+* rebar/268: [Fix #267 (code path regression)](https://github.com/rebar/rebar/pull/268)
+* rebar/269: [Update THANKS](https://github.com/rebar/rebar/pull/269)
+
+# Rebar 2.2.0
+
+## PR's Merged
+
+* rebar/152: [Fix erl_opts use](https://github.com/rebar/rebar/pull/152)
+* rebar/154: [Fix update-deps with certain forms of the {tag, ...} type](https://github.com/rebar/rebar/pull/154)
+* rebar/155: [Fixes for #137 and #142](https://github.com/rebar/rebar/pull/155)
+* rebar/157: [Don't over-aggressively clean the code path in the presence of lib_dir directives](https://github.com/rebar/rebar/pull/157)
+* rebar/172: [Add missing dep examples and fix existing ones](https://github.com/rebar/rebar/pull/172)
+* rebar/173: [Fix false reporting of (plain) vsn strings](https://github.com/rebar/rebar/pull/173)
+* rebar/174: [rebar_core: fix Dialyzer warning introduced in aa46d85 (#157)](https://github.com/rebar/rebar/pull/174)
+* rebar/177: [Delete unused inttest/retest binary](https://github.com/rebar/rebar/pull/177)
+* rebar/179: [Make list of commands (for unabbreviation) easier to maintain](https://github.com/rebar/rebar/pull/179)
+* rebar/183: [generate-upgrade can now take target_dir argument](https://github.com/rebar/rebar/pull/183)
+* rebar/184: [Fix log levels](https://github.com/rebar/rebar/pull/184)
+* rebar/185: [Switch retest dep to upstream (dizzyd/retest.git)](https://github.com/rebar/rebar/pull/185)
+* rebar/189: [inttest/rgen1: increase retest timeout (30s -> 60s)](https://github.com/rebar/rebar/pull/189)
+* rebar/190: [inttest/rgen_1: double the timeout a second time](https://github.com/rebar/rebar/pull/190)
+* rebar/191: [Fix #187 (rename getopt and mustache)](https://github.com/rebar/rebar/pull/191)
+* rebar/196: [Print a more appropriate message on 'rebar info'](https://github.com/rebar/rebar/pull/196)
+* rebar/198: [Clean up rebar.config.script](https://github.com/rebar/rebar/pull/198)
+* rebar/199: [rebar_dia_compiler: fix Dialyzer warnings](https://github.com/rebar/rebar/pull/199)
+* rebar/200: [bootstrap: avoid trying to run 'debug' command](https://github.com/rebar/rebar/pull/200)
+* rebar/201: [Added a library template.](https://github.com/rebar/rebar/pull/201)
+* rebar/210: [Fix #205 (erlydtl:compile/3 returns warnings)](https://github.com/rebar/rebar/pull/210)
+* rebar/212: [Fix basho/rebar#388](https://github.com/rebar/rebar/pull/212)
+* rebar/214: [Document compile_only=true](https://github.com/rebar/rebar/pull/214)
+* rebar/215: [Remove experimental flags](https://github.com/rebar/rebar/pull/215)
diff -Nru rebar-2.0.0/src/getopt.erl rebar-2.6.0/src/getopt.erl
--- rebar-2.0.0/src/getopt.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/getopt.erl 1970-01-01 00:00:00.000000000 +0000
@@ -1,621 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @author Juan Jose Comellas
-%%% @copyright (C) 2009 Juan Jose Comellas
-%%% @doc Parses command line options with a format similar to that of GNU getopt.
-%%% @end
-%%%
-%%% This source file is subject to the New BSD License. You should have received
-%%% a copy of the New BSD license with this software. If not, it can be
-%%% retrieved from: http://www.opensource.org/licenses/bsd-license.php
-%%%-------------------------------------------------------------------
--module(getopt).
--author('juanjo@comellas.org').
-
--export([parse/2, usage/2, usage/3, usage/4]).
-
--export_type([arg_type/0,
- arg_value/0,
- arg_spec/0,
- simple_option/0,
- compound_option/0,
- option/0,
- option_spec/0]).
-
--define(TAB_LENGTH, 8).
-%% Indentation of the help messages in number of tabs.
--define(INDENTATION, 3).
-
-%% Position of each field in the option specification tuple.
--define(OPT_NAME, 1).
--define(OPT_SHORT, 2).
--define(OPT_LONG, 3).
--define(OPT_ARG, 4).
--define(OPT_HELP, 5).
-
--define(IS_OPT_SPEC(Opt), (tuple_size(Opt) =:= ?OPT_HELP)).
-
-
-%% Atom indicating the data type that an argument can be converted to.
--type arg_type() :: 'atom' | 'binary' | 'boolean' | 'float' | 'integer' | 'string'.
-%% Data type that an argument can be converted to.
--type arg_value() :: atom() | binary() | boolean() | float() | integer() | string().
-%% Argument specification.
--type arg_spec() :: arg_type() | {arg_type(), arg_value()} | undefined.
-%% Option type and optional default argument.
--type simple_option() :: atom().
--type compound_option() :: {atom(), arg_value()}.
--type option() :: simple_option() | compound_option().
-%% Command line option specification.
--type option_spec() :: {
- Name :: atom(),
- Short :: char() | undefined,
- Long :: string() | undefined,
- ArgSpec :: arg_spec(),
- Help :: string() | undefined
- }.
-%% Output streams
--type output_stream() :: 'standard_io' | 'standard_error'.
-
-
-%% @doc Parse the command line options and arguments returning a list of tuples
-%% and/or atoms using the Erlang convention for sending options to a
-%% function.
--spec parse([option_spec()], string() | [string()]) ->
- {ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data :: any()}}.
-parse(OptSpecList, CmdLine) ->
- try
- Args = if
- is_integer(hd(CmdLine)) ->
- string:tokens(CmdLine, " \t\n");
- true ->
- CmdLine
- end,
- parse(OptSpecList, [], [], 0, Args)
- catch
- throw: {error, {_Reason, _Data}} = Error ->
- Error
- end.
-
-
--spec parse([option_spec()], [option()], [string()], integer(), [string()]) ->
- {ok, {[option()], [string()]}}.
-%% Process the option terminator.
-parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, ["--" | Tail]) ->
- %% Any argument present after the terminator is not considered an option.
- {ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc, Tail)}};
-%% Process long options.
-parse(OptSpecList, OptAcc, ArgAcc, ArgPos, ["--" ++ OptArg = OptStr | Tail]) ->
- parse_long_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg);
-%% Process short options.
-parse(OptSpecList, OptAcc, ArgAcc, ArgPos, ["-" ++ ([_Char | _] = OptArg) = OptStr | Tail]) ->
- parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg);
-%% Process non-option arguments.
-parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [Arg | Tail]) ->
- case find_non_option_arg(OptSpecList, ArgPos) of
- {value, OptSpec} when ?IS_OPT_SPEC(OptSpec) ->
- parse(OptSpecList, add_option_with_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos + 1, Tail);
- false ->
- parse(OptSpecList, OptAcc, [Arg | ArgAcc], ArgPos, Tail)
- end;
-parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, []) ->
- %% Once we have completed gathering the options we add the ones that were
- %% not present but had default arguments in the specification.
- {ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc)}}.
-
-
-%% @doc Parse a long option, add it to the option accumulator and continue
-%% parsing the rest of the arguments recursively.
-%% A long option can have the following syntax:
-%% --foo Single option 'foo', no argument
-%% --foo=bar Single option 'foo', argument "bar"
-%% --foo bar Single option 'foo', argument "bar"
--spec parse_long_option([option_spec()], [option()], [string()], integer(), [string()], string(), string()) ->
- {ok, {[option()], [string()]}}.
-parse_long_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
- case split_assigned_arg(OptArg) of
- {Long, Arg} ->
- %% Get option that has its argument within the same string
- %% separated by an equal ('=') character (e.g. "--port=1000").
- parse_long_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg);
-
- Long ->
- case lists:keyfind(Long, ?OPT_LONG, OptSpecList) of
- {Name, _Short, Long, undefined, _Help} ->
- parse(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args);
-
- {_Name, _Short, Long, _ArgSpec, _Help} = OptSpec ->
- %% The option argument string is empty, but the option requires
- %% an argument, so we look into the next string in the list.
- %% e.g ["--port", "1000"]
- parse_long_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec);
- false ->
- throw({error, {invalid_option, OptStr}})
- end
- end.
-
-
-%% @doc Parse an option where the argument is 'assigned' in the same string using
-%% the '=' character, add it to the option accumulator and continue parsing the
-%% rest of the arguments recursively. This syntax is only valid for long options.
--spec parse_long_option_assigned_arg([option_spec()], [option()], [string()], integer(),
- [string()], string(), string(), string()) ->
- {ok, {[option()], [string()]}}.
-parse_long_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg) ->
- case lists:keyfind(Long, ?OPT_LONG, OptSpecList) of
- {_Name, _Short, Long, ArgSpec, _Help} = OptSpec ->
- case ArgSpec of
- undefined ->
- throw({error, {invalid_option_arg, OptStr}});
- _ ->
- parse(OptSpecList, add_option_with_assigned_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos, Args)
- end;
- false ->
- throw({error, {invalid_option, OptStr}})
- end.
-
-
-%% @doc Split an option string that may contain an option with its argument
-%% separated by an equal ('=') character (e.g. "port=1000").
--spec split_assigned_arg(string()) -> {Name :: string(), Arg :: string()} | string().
-split_assigned_arg(OptStr) ->
- split_assigned_arg(OptStr, OptStr, []).
-
-split_assigned_arg(_OptStr, "=" ++ Tail, Acc) ->
- {lists:reverse(Acc), Tail};
-split_assigned_arg(OptStr, [Char | Tail], Acc) ->
- split_assigned_arg(OptStr, Tail, [Char | Acc]);
-split_assigned_arg(OptStr, [], _Acc) ->
- OptStr.
-
-
-%% @doc Retrieve the argument for an option from the next string in the list of
-%% command-line parameters or set the value of the argument from the argument
-%% specification (for boolean and integer arguments), if possible.
-parse_long_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec) ->
- ArgSpecType = arg_spec_type(ArgSpec),
- case Args =:= [] orelse is_implicit_arg(ArgSpecType, hd(Args)) of
- true ->
- parse(OptSpecList, add_option_with_implicit_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args);
- false ->
- [Arg | Tail] = Args,
- try
- parse(OptSpecList, [{Name, to_type(ArgSpecType, Arg)} | OptAcc], ArgAcc, ArgPos, Tail)
- catch
- error:_ ->
- throw({error, {invalid_option_arg, {Name, Arg}}})
- end
- end.
-
-
-%% @doc Parse a short option, add it to the option accumulator and continue
-%% parsing the rest of the arguments recursively.
-%% A short option can have the following syntax:
-%% -a Single option 'a', no argument or implicit boolean argument
-%% -a foo Single option 'a', argument "foo"
-%% -afoo Single option 'a', argument "foo"
-%% -abc Multiple options: 'a'; 'b'; 'c'
-%% -bcafoo Multiple options: 'b'; 'c'; 'a' with argument "foo"
-%% -aaa Multiple repetitions of option 'a' (only valid for options with integer arguments)
--spec parse_short_option([option_spec()], [option()], [string()], integer(), [string()], string(), string()) ->
- {ok, {[option()], [string()]}}.
-parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
- parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, first, OptArg).
-
-parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptPos, [Short | Arg]) ->
- case lists:keyfind(Short, ?OPT_SHORT, OptSpecList) of
- {Name, Short, _Long, undefined, _Help} ->
- parse_short_option(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args, OptStr, first, Arg);
-
- {_Name, Short, _Long, ArgSpec, _Help} = OptSpec ->
- %% The option has a specification, so it requires an argument.
- case Arg of
- [] ->
- %% The option argument string is empty, but the option requires
- %% an argument, so we look into the next string in the list.
- parse_short_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec, OptPos);
-
- _ ->
- case is_valid_arg(ArgSpec, Arg) of
- true ->
- parse(OptSpecList, add_option_with_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos, Args);
- _ ->
- NewOptAcc = case OptPos of
- first -> add_option_with_implicit_arg(OptSpec, OptAcc);
- _ -> add_option_with_implicit_incrementable_arg(OptSpec, OptAcc)
- end,
- parse_short_option(OptSpecList, NewOptAcc, ArgAcc, ArgPos, Args, OptStr, next, Arg)
- end
- end;
-
- false ->
- throw({error, {invalid_option, OptStr}})
- end;
-parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, _OptStr, _OptPos, []) ->
- parse(OptSpecList, OptAcc, ArgAcc, ArgPos, Args).
-
-
-%% @doc Retrieve the argument for an option from the next string in the list of
-%% command-line parameters or set the value of the argument from the argument
-%% specification (for boolean and integer arguments), if possible.
-parse_short_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec, OptPos) ->
- case Args =:= [] orelse is_implicit_arg(ArgSpec, hd(Args)) of
- true when OptPos =:= first ->
- parse(OptSpecList, add_option_with_implicit_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args);
- true ->
- parse(OptSpecList, add_option_with_implicit_incrementable_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args);
- false ->
- [Arg | Tail] = Args,
- try
- parse(OptSpecList, [{Name, to_type(ArgSpec, Arg)} | OptAcc], ArgAcc, ArgPos, Tail)
- catch
- error:_ ->
- throw({error, {invalid_option_arg, {Name, Arg}}})
- end
- end.
-
-
-%% @doc Find the option for the discrete argument in position specified in the
-%% Pos argument.
--spec find_non_option_arg([option_spec()], integer()) -> {value, option_spec()} | false.
-find_non_option_arg([{_Name, undefined, undefined, _ArgSpec, _Help} = OptSpec | _Tail], 0) ->
- {value, OptSpec};
-find_non_option_arg([{_Name, undefined, undefined, _ArgSpec, _Help} | Tail], Pos) ->
- find_non_option_arg(Tail, Pos - 1);
-find_non_option_arg([_Head | Tail], Pos) ->
- find_non_option_arg(Tail, Pos);
-find_non_option_arg([], _Pos) ->
- false.
-
-
-%% @doc Append options that were not present in the command line arguments with
-%% their default arguments.
--spec append_default_options([option_spec()], [option()]) -> [option()].
-append_default_options([{Name, _Short, _Long, {_Type, DefaultArg}, _Help} | Tail], OptAcc) ->
- append_default_options(Tail,
- case lists:keymember(Name, 1, OptAcc) of
- false ->
- [{Name, DefaultArg} | OptAcc];
- _ ->
- OptAcc
- end);
-%% For options with no default argument.
-append_default_options([_Head | Tail], OptAcc) ->
- append_default_options(Tail, OptAcc);
-append_default_options([], OptAcc) ->
- OptAcc.
-
-
-%% @doc Add an option with argument converting it to the data type indicated by the
-%% argument specification.
--spec add_option_with_arg(option_spec(), string(), [option()]) -> [option()].
-add_option_with_arg({Name, _Short, _Long, ArgSpec, _Help} = OptSpec, Arg, OptAcc) ->
- case is_valid_arg(ArgSpec, Arg) of
- true ->
- try
- [{Name, to_type(ArgSpec, Arg)} | OptAcc]
- catch
- error:_ ->
- throw({error, {invalid_option_arg, {Name, Arg}}})
- end;
- false ->
- add_option_with_implicit_arg(OptSpec, OptAcc)
- end.
-
-
-%% @doc Add an option with argument that was part of an assignment expression
-%% (e.g. "--verbose=3") converting it to the data type indicated by the
-%% argument specification.
--spec add_option_with_assigned_arg(option_spec(), string(), [option()]) -> [option()].
-add_option_with_assigned_arg({Name, _Short, _Long, ArgSpec, _Help}, Arg, OptAcc) ->
- try
- [{Name, to_type(ArgSpec, Arg)} | OptAcc]
- catch
- error:_ ->
- throw({error, {invalid_option_arg, {Name, Arg}}})
- end.
-
-
-%% @doc Add an option that required an argument but did not have one. Some data
-%% types (boolean, integer) allow implicit or assumed arguments.
--spec add_option_with_implicit_arg(option_spec(), [option()]) -> [option()].
-add_option_with_implicit_arg({Name, _Short, _Long, ArgSpec, _Help}, OptAcc) ->
- case arg_spec_type(ArgSpec) of
- boolean ->
- %% Special case for boolean arguments: if there is no argument we
- %% set the value to 'true'.
- [{Name, true} | OptAcc];
- integer ->
- %% Special case for integer arguments: if the option had not been set
- %% before we set the value to 1. This is needed to support options like
- %% "-v" to return something like {verbose, 1}.
- [{Name, 1} | OptAcc];
- _ ->
- throw({error, {missing_option_arg, Name}})
- end.
-
-
-%% @doc Add an option with an implicit or assumed argument.
--spec add_option_with_implicit_incrementable_arg(option_spec() | arg_spec(), [option()]) -> [option()].
-add_option_with_implicit_incrementable_arg({Name, _Short, _Long, ArgSpec, _Help}, OptAcc) ->
- case arg_spec_type(ArgSpec) of
- boolean ->
- %% Special case for boolean arguments: if there is no argument we
- %% set the value to 'true'.
- [{Name, true} | OptAcc];
- integer ->
- %% Special case for integer arguments: if the option had not been set
- %% before we set the value to 1; if not we increment the previous value
- %% the option had. This is needed to support options like "-vvv" to
- %% return something like {verbose, 3}.
- case OptAcc of
- [{Name, Count} | Tail] ->
- [{Name, Count + 1} | Tail];
- _ ->
- [{Name, 1} | OptAcc]
- end;
- _ ->
- throw({error, {missing_option_arg, Name}})
- end.
-
-
-%% @doc Retrieve the data type form an argument specification.
--spec arg_spec_type(arg_spec()) -> arg_type() | undefined.
-arg_spec_type({Type, _DefaultArg}) ->
- Type;
-arg_spec_type(Type) when is_atom(Type) ->
- Type.
-
-
-%% @doc Convert an argument string to its corresponding data type.
--spec to_type(arg_spec() | arg_type(), string()) -> arg_value().
-to_type({Type, _DefaultArg}, Arg) ->
- to_type(Type, Arg);
-to_type(binary, Arg) ->
- list_to_binary(Arg);
-to_type(atom, Arg) ->
- list_to_atom(Arg);
-to_type(integer, Arg) ->
- list_to_integer(Arg);
-to_type(float, Arg) ->
- list_to_float(Arg);
-to_type(boolean, Arg) ->
- LowerArg = string:to_lower(Arg),
- case is_arg_true(LowerArg) of
- true ->
- true;
- _ ->
- case is_arg_false(LowerArg) of
- true ->
- false;
- false ->
- erlang:error(badarg)
- end
- end;
-to_type(_Type, Arg) ->
- Arg.
-
-
--spec is_arg_true(string()) -> boolean().
-is_arg_true(Arg) ->
- (Arg =:= "true") orelse (Arg =:= "t") orelse
- (Arg =:= "yes") orelse (Arg =:= "y") orelse
- (Arg =:= "on") orelse (Arg =:= "enabled") orelse
- (Arg =:= "1").
-
-
--spec is_arg_false(string()) -> boolean().
-is_arg_false(Arg) ->
- (Arg =:= "false") orelse (Arg =:= "f") orelse
- (Arg =:= "no") orelse (Arg =:= "n") orelse
- (Arg =:= "off") orelse (Arg =:= "disabled") orelse
- (Arg =:= "0").
-
-
--spec is_valid_arg(arg_spec(), nonempty_string()) -> boolean().
-is_valid_arg({Type, _DefaultArg}, Arg) ->
- is_valid_arg(Type, Arg);
-is_valid_arg(boolean, Arg) ->
- is_boolean_arg(Arg);
-is_valid_arg(integer, Arg) ->
- is_non_neg_integer_arg(Arg);
-is_valid_arg(float, Arg) ->
- is_non_neg_float_arg(Arg);
-is_valid_arg(_Type, _Arg) ->
- true.
-
-
--spec is_implicit_arg(arg_spec(), nonempty_string()) -> boolean().
-is_implicit_arg({Type, _DefaultArg}, Arg) ->
- is_implicit_arg(Type, Arg);
-is_implicit_arg(boolean, Arg) ->
- not is_boolean_arg(Arg);
-is_implicit_arg(integer, Arg) ->
- not is_integer_arg(Arg);
-is_implicit_arg(_Type, _Arg) ->
- false.
-
-
--spec is_boolean_arg(string()) -> boolean().
-is_boolean_arg(Arg) ->
- LowerArg = string:to_lower(Arg),
- is_arg_true(LowerArg) orelse is_arg_false(LowerArg).
-
-
--spec is_integer_arg(string()) -> boolean().
-is_integer_arg("-" ++ Tail) ->
- is_non_neg_integer_arg(Tail);
-is_integer_arg(Arg) ->
- is_non_neg_integer_arg(Arg).
-
-
--spec is_non_neg_integer_arg(string()) -> boolean().
-is_non_neg_integer_arg([Head | Tail]) when Head >= $0, Head =< $9 ->
- is_non_neg_integer_arg(Tail);
-is_non_neg_integer_arg([_Head | _Tail]) ->
- false;
-is_non_neg_integer_arg([]) ->
- true.
-
-
--spec is_non_neg_float_arg(string()) -> boolean().
-is_non_neg_float_arg([Head | Tail]) when (Head >= $0 andalso Head =< $9) orelse Head =:= $. ->
- is_non_neg_float_arg(Tail);
-is_non_neg_float_arg([_Head | _Tail]) ->
- false;
-is_non_neg_float_arg([]) ->
- true.
-
-
-%% @doc Show a message on standard_error indicating the command line options and
-%% arguments that are supported by the program.
--spec usage([option_spec()], string()) -> ok.
-usage(OptSpecList, ProgramName) ->
- usage(OptSpecList, ProgramName, standard_error).
-
-
-%% @doc Show a message on standard_error or standard_io indicating the command line options and
-%% arguments that are supported by the program.
--spec usage([option_spec()], string(), output_stream() | string()) -> ok.
-usage(OptSpecList, ProgramName, OutputStream) when is_atom(OutputStream) ->
- io:format(OutputStream, "Usage: ~s~s~n~n~s~n",
- [ProgramName, usage_cmd_line(OptSpecList), usage_options(OptSpecList)]);
-%% @doc Show a message on standard_error indicating the command line options and
-%% arguments that are supported by the program. The CmdLineTail argument
-%% is a string that is added to the end of the usage command line.
-usage(OptSpecList, ProgramName, CmdLineTail) ->
- usage(OptSpecList, ProgramName, CmdLineTail, standard_error).
-
-
-%% @doc Show a message on standard_error or standard_io indicating the command line options and
-%% arguments that are supported by the program. The CmdLineTail argument
-%% is a string that is added to the end of the usage command line.
--spec usage([option_spec()], string(), string(), output_stream() | [{string(), string()}]) -> ok.
-usage(OptSpecList, ProgramName, CmdLineTail, OutputStream) when is_atom(OutputStream) ->
- io:format(OutputStream, "Usage: ~s~s ~s~n~n~s~n",
- [ProgramName, usage_cmd_line(OptSpecList), CmdLineTail, usage_options(OptSpecList)]);
-%% @doc Show a message on standard_error indicating the command line options and
-%% arguments that are supported by the program. The CmdLineTail and OptionsTail
-%% arguments are a string that is added to the end of the usage command line
-%% and a list of tuples that are added to the end of the options' help lines.
-usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail) ->
- usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail, standard_error).
-
-
-%% @doc Show a message on standard_error or standard_io indicating the command line options and
-%% arguments that are supported by the program. The CmdLineTail and OptionsTail
-%% arguments are a string that is added to the end of the usage command line
-%% and a list of tuples that are added to the end of the options' help lines.
--spec usage([option_spec()], string(), string(), [{string(), string()}], output_stream()) -> ok.
-usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail, OutputStream) ->
- UsageOptions = lists:foldl(
- fun ({Prefix, Help}, Acc) ->
- add_option_help(Prefix, Help, Acc)
- end, usage_options_reverse(OptSpecList, []), OptionsTail),
- io:format(OutputStream, "Usage: ~s~s ~s~n~n~s~n",
- [ProgramName, usage_cmd_line(OptSpecList), CmdLineTail,
- lists:flatten(lists:reverse(UsageOptions))]).
-
-
-%% @doc Return a string with the syntax for the command line options and
-%% arguments.
--spec usage_cmd_line([option_spec()]) -> string().
-usage_cmd_line(OptSpecList) ->
- usage_cmd_line(OptSpecList, []).
-
-usage_cmd_line([{Name, Short, Long, ArgSpec, _Help} | Tail], Acc) ->
- CmdLine =
- case ArgSpec of
- undefined ->
- if
- %% For options with short form and no argument.
- Short =/= undefined ->
- [$\s, $[, $-, Short, $]];
- %% For options with only long form and no argument.
- Long =/= undefined ->
- [$\s, $[, $-, $-, Long, $]];
- true ->
- []
- end;
- _ ->
- if
- %% For options with short form and argument.
- Short =/= undefined ->
- [$\s, $[, $-, Short, $\s, $<, atom_to_list(Name), $>, $]];
- %% For options with only long form and argument.
- Long =/= undefined ->
- [$\s, $[, $-, $-, Long, $\s, $<, atom_to_list(Name), $>, $]];
- %% For options with neither short nor long form and argument.
- true ->
- [$\s, $<, atom_to_list(Name), $>]
- end
- end,
- usage_cmd_line(Tail, [CmdLine | Acc]);
-usage_cmd_line([], Acc) ->
- lists:flatten(lists:reverse(Acc)).
-
-
-%% @doc Return a string with the help message for each of the options and
-%% arguments.
--spec usage_options([option_spec()]) -> string().
-usage_options(OptSpecList) ->
- lists:flatten(lists:reverse(usage_options_reverse(OptSpecList, []))).
-
-usage_options_reverse([{Name, Short, Long, _ArgSpec, Help} | Tail], Acc) ->
- Prefix =
- case Long of
- undefined ->
- case Short of
- %% Neither short nor long form (non-option argument).
- undefined ->
- [$<, atom_to_list(Name), $>];
- %% Only short form.
- _ ->
- [$-, Short]
- end;
- _ ->
- case Short of
- %% Only long form.
- undefined ->
- [$-, $- | Long];
- %% Both short and long form.
- _ ->
- [$-, Short, $,, $\s, $-, $- | Long]
- end
- end,
- usage_options_reverse(Tail, add_option_help(Prefix, Help, Acc));
-usage_options_reverse([], Acc) ->
- Acc.
-
-
-%% @doc Add the help message corresponding to an option specification to a list
-%% with the correct indentation.
--spec add_option_help(Prefix :: string(), Help :: string(), Acc :: string()) -> string().
-add_option_help(Prefix, Help, Acc) when is_list(Help), Help =/= [] ->
- FlatPrefix = lists:flatten(Prefix),
- case ((?INDENTATION * ?TAB_LENGTH) - 2 - length(FlatPrefix)) of
- TabSize when TabSize > 0 ->
- Tab = lists:duplicate(ceiling(TabSize / ?TAB_LENGTH), $\t),
- [[$\s, $\s, FlatPrefix, Tab, Help, $\n] | Acc];
- _ ->
- % The indentation for the option description is 3 tabs (i.e. 24 characters)
- % IMPORTANT: Change the number of tabs below if you change the
- % value of the INDENTATION macro.
- [[$\t, $\t, $\t, Help, $\n], [$\s, $\s, FlatPrefix, $\n] | Acc]
- end;
-add_option_help(_Opt, _Prefix, Acc) ->
- Acc.
-
-
-
-%% @doc Return the smallest integral value not less than the argument.
--spec ceiling(float()) -> integer().
-ceiling(X) ->
- T = erlang:trunc(X),
- case (X - T) of
- % Neg when Neg < 0 ->
- % T;
- Pos when Pos > 0 ->
- T + 1;
- _ ->
- T
- end.
diff -Nru rebar-2.0.0/src/mustache.erl rebar-2.6.0/src/mustache.erl
--- rebar-2.0.0/src/mustache.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/mustache.erl 1970-01-01 00:00:00.000000000 +0000
@@ -1,234 +0,0 @@
-%% The MIT License
-%%
-%% Copyright (c) 2009 Tom Preston-Werner
-%%
-%% 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.
-
-%% See the README at http://github.com/mojombo/mustache.erl for additional
-%% documentation and usage examples.
-
--module(mustache). %% v0.1.0
--author("Tom Preston-Werner").
--export([compile/1, compile/2, render/1, render/2, render/3, get/2, get/3, escape/1, start/1]).
-
--record(mstate, {mod = undefined,
- section_re = undefined,
- tag_re = undefined}).
-
--ifdef(TEST).
--include_lib("eunit/include/eunit.hrl").
--endif.
-
-compile(Body) when is_list(Body) ->
- State = #mstate{},
- CompiledTemplate = pre_compile(Body, State),
- % io:format("~p~n~n", [CompiledTemplate]),
- % io:format(CompiledTemplate ++ "~n", []),
- {ok, Tokens, _} = erl_scan:string(CompiledTemplate),
- {ok, [Form]} = erl_parse:parse_exprs(Tokens),
- Bindings = erl_eval:new_bindings(),
- {value, Fun, _} = erl_eval:expr(Form, Bindings),
- Fun;
-compile(Mod) ->
- TemplatePath = template_path(Mod),
- compile(Mod, TemplatePath).
-
-compile(Mod, File) ->
- code:purge(Mod),
- {module, _} = code:load_file(Mod),
- {ok, TemplateBin} = file:read_file(File),
- Template = re:replace(TemplateBin, "\"", "\\\\\"", [global, {return,list}]),
- State = #mstate{mod = Mod},
- CompiledTemplate = pre_compile(Template, State),
- % io:format("~p~n~n", [CompiledTemplate]),
- % io:format(CompiledTemplate ++ "~n", []),
- {ok, Tokens, _} = erl_scan:string(CompiledTemplate),
- {ok, [Form]} = erl_parse:parse_exprs(Tokens),
- Bindings = erl_eval:new_bindings(),
- {value, Fun, _} = erl_eval:expr(Form, Bindings),
- Fun.
-
-render(Mod) ->
- TemplatePath = template_path(Mod),
- render(Mod, TemplatePath).
-
-render(Body, Ctx) when is_list(Body) ->
- TFun = compile(Body),
- render(undefined, TFun, Ctx);
-render(Mod, File) when is_list(File) ->
- render(Mod, File, dict:new());
-render(Mod, CompiledTemplate) ->
- render(Mod, CompiledTemplate, dict:new()).
-
-render(Mod, File, Ctx) when is_list(File) ->
- CompiledTemplate = compile(Mod, File),
- render(Mod, CompiledTemplate, Ctx);
-render(Mod, CompiledTemplate, Ctx) ->
- Ctx2 = dict:store('__mod__', Mod, Ctx),
- lists:flatten(CompiledTemplate(Ctx2)).
-
-pre_compile(T, State) ->
- SectionRE = "\{\{\#([^\}]*)}}\s*(.+?){{\/\\1\}\}\s*",
- {ok, CompiledSectionRE} = re:compile(SectionRE, [dotall]),
- TagRE = "\{\{(#|=|!|<|>|\{)?(.+?)\\1?\}\}+",
- {ok, CompiledTagRE} = re:compile(TagRE, [dotall]),
- State2 = State#mstate{section_re = CompiledSectionRE, tag_re = CompiledTagRE},
- "fun(Ctx) -> " ++
- "CFun = fun(A, B) -> A end, " ++
- compiler(T, State2) ++ " end.".
-
-compiler(T, State) ->
- Res = re:run(T, State#mstate.section_re),
- case Res of
- {match, [{M0, M1}, {N0, N1}, {C0, C1}]} ->
- Front = string:substr(T, 1, M0),
- Back = string:substr(T, M0 + M1 + 1),
- Name = string:substr(T, N0 + 1, N1),
- Content = string:substr(T, C0 + 1, C1),
- "[" ++ compile_tags(Front, State) ++
- " | [" ++ compile_section(Name, Content, State) ++
- " | [" ++ compiler(Back, State) ++ "]]]";
- nomatch ->
- compile_tags(T, State)
- end.
-
-compile_section(Name, Content, State) ->
- Mod = State#mstate.mod,
- Result = compiler(Content, State),
- "fun() -> " ++
- "case mustache:get(" ++ Name ++ ", Ctx, " ++ atom_to_list(Mod) ++ ") of " ++
- "true -> " ++
- Result ++ "; " ++
- "false -> " ++
- "[]; " ++
- "List when is_list(List) -> " ++
- "[fun(Ctx) -> " ++ Result ++ " end(dict:merge(CFun, SubCtx, Ctx)) || SubCtx <- List]; " ++
- "Else -> " ++
- "throw({template, io_lib:format(\"Bad context for ~p: ~p\", [" ++ Name ++ ", Else])}) " ++
- "end " ++
- "end()".
-
-compile_tags(T, State) ->
- Res = re:run(T, State#mstate.tag_re),
- case Res of
- {match, [{M0, M1}, K, {C0, C1}]} ->
- Front = string:substr(T, 1, M0),
- Back = string:substr(T, M0 + M1 + 1),
- Content = string:substr(T, C0 + 1, C1),
- Kind = tag_kind(T, K),
- Result = compile_tag(Kind, Content, State),
- "[\"" ++ Front ++
- "\" | [" ++ Result ++
- " | " ++ compile_tags(Back, State) ++ "]]";
- nomatch ->
- "[\"" ++ T ++ "\"]"
- end.
-
-tag_kind(_T, {-1, 0}) ->
- none;
-tag_kind(T, {K0, K1}) ->
- string:substr(T, K0 + 1, K1).
-
-compile_tag(none, Content, State) ->
- Mod = State#mstate.mod,
- "mustache:escape(mustache:get(" ++ Content ++ ", Ctx, " ++ atom_to_list(Mod) ++ "))";
-compile_tag("{", Content, State) ->
- Mod = State#mstate.mod,
- "mustache:get(" ++ Content ++ ", Ctx, " ++ atom_to_list(Mod) ++ ")";
-compile_tag("!", _Content, _State) ->
- "[]".
-
-template_path(Mod) ->
- ModPath = code:which(Mod),
- re:replace(ModPath, "\.beam$", ".mustache", [{return, list}]).
-
-get(Key, Ctx) when is_list(Key) ->
- {ok, Mod} = dict:find('__mod__', Ctx),
- get(list_to_atom(Key), Ctx, Mod);
-get(Key, Ctx) ->
- {ok, Mod} = dict:find('__mod__', Ctx),
- get(Key, Ctx, Mod).
-
-get(Key, Ctx, Mod) when is_list(Key) ->
- get(list_to_atom(Key), Ctx, Mod);
-get(Key, Ctx, Mod) ->
- case dict:find(Key, Ctx) of
- {ok, Val} ->
- % io:format("From Ctx {~p, ~p}~n", [Key, Val]),
- to_s(Val);
- error ->
- case erlang:function_exported(Mod, Key, 1) of
- true ->
- Val = to_s(Mod:Key(Ctx)),
- % io:format("From Mod/1 {~p, ~p}~n", [Key, Val]),
- Val;
- false ->
- case erlang:function_exported(Mod, Key, 0) of
- true ->
- Val = to_s(Mod:Key()),
- % io:format("From Mod/0 {~p, ~p}~n", [Key, Val]),
- Val;
- false ->
- []
- end
- end
- end.
-
-to_s(Val) when is_integer(Val) ->
- integer_to_list(Val);
-to_s(Val) when is_float(Val) ->
- io_lib:format("~.2f", [Val]);
-to_s(Val) when is_atom(Val) ->
- atom_to_list(Val);
-to_s(Val) ->
- Val.
-
-escape(HTML) ->
- escape(HTML, []).
-
-escape([], Acc) ->
- lists:reverse(Acc);
-escape(["<" | Rest], Acc) ->
- escape(Rest, lists:reverse("<", Acc));
-escape([">" | Rest], Acc) ->
- escape(Rest, lists:reverse(">", Acc));
-escape(["&" | Rest], Acc) ->
- escape(Rest, lists:reverse("&", Acc));
-escape([X | Rest], Acc) ->
- escape(Rest, [X | Acc]).
-
-%%---------------------------------------------------------------------------
-
-start([T]) ->
- Out = render(list_to_atom(T)),
- io:format(Out ++ "~n", []).
-
--ifdef(TEST).
-
-simple_test() ->
- Ctx = dict:from_list([{name, "world"}]),
- Result = render("Hello {{name}}!", Ctx),
- ?assertEqual("Hello world!", Result).
-
-integer_values_too_test() ->
- Ctx = dict:from_list([{name, "Chris"}, {value, 10000}]),
- Result = render("Hello {{name}}~nYou have just won ${{value}}!", Ctx),
- ?assertEqual("Hello Chris~nYou have just won $10000!", Result).
-
--endif.
diff -Nru rebar-2.0.0/src/rebar_abnfc_compiler.erl rebar-2.6.0/src/rebar_abnfc_compiler.erl
--- rebar-2.0.0/src/rebar_abnfc_compiler.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_abnfc_compiler.erl 2015-06-19 16:14:28.000000000 +0000
@@ -47,6 +47,9 @@
-export([compile/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -62,11 +65,23 @@
option(module_ext, DtlOpts) ++ ".erl",
fun compile_abnfc/3).
-
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ ?CONSOLE(
+ "Build ABNF (*.abnf) sources.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {abnfc_opts, [{doc_root, "src"},
+ {out_dir, "src"},
+ {source_ext, ".abnfc"},
+ {module_ext, ""}]}
+ ]).
+
abnfc_opts(Config) ->
rebar_config:get(Config, abnfc_opts, []).
diff -Nru rebar-2.0.0/src/rebar_appups.erl rebar-2.6.0/src/rebar_appups.erl
--- rebar-2.0.0/src/rebar_appups.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_appups.erl 2015-06-19 16:14:28.000000000 +0000
@@ -31,6 +31,9 @@
-export(['generate-appups'/2]).
+%% for internal use only
+-export([info/2]).
+
-define(APPUPFILEFORMAT, "%% appup generated for ~p by rebar (~p)~n"
"{~p, [{~p, ~p}], [{~p, []}]}.~n").
@@ -38,17 +41,20 @@
%% Public API
%% ====================================================================
-'generate-appups'(_Config, ReltoolFile) ->
+'generate-appups'(Config, ReltoolFile) ->
%% Get the old release path
- ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile),
- TargetParentDir = rebar_rel_utils:get_target_parent_dir(ReltoolConfig),
+ {Config1, ReltoolConfig} = rebar_rel_utils:load_config(Config, ReltoolFile),
+ TargetParentDir = rebar_rel_utils:get_target_parent_dir(Config,
+ ReltoolConfig),
+
+ PrevRelPath = rebar_rel_utils:get_previous_release_path(Config),
+ OldVerPath = filename:join([TargetParentDir, PrevRelPath]),
- OldVerPath = filename:join([TargetParentDir,
- rebar_rel_utils:get_previous_release_path()]),
+ ModDeps = rebar_config:get(Config, module_deps, []),
%% Get the new and old release name and versions
{Name, _Ver} = rebar_rel_utils:get_reltool_release_info(ReltoolConfig),
- NewVerPath = filename:join([TargetParentDir, Name]),
+ NewVerPath = rebar_rel_utils:get_target_dir(Config, ReltoolConfig),
{NewName, NewVer} = rebar_rel_utils:get_rel_release_info(Name, NewVerPath),
{OldName, OldVer} = rebar_rel_utils:get_rel_release_info(Name, OldVerPath),
@@ -63,8 +69,8 @@
{_Added, _Removed, Upgraded} = get_apps(Name, OldVerPath, NewVerPath),
%% Get a list of any appup files that exist in the new release
- NewAppUpFiles = rebar_utils:find_files(
- filename:join([NewVerPath, "lib"]), "^.*.appup$"),
+ NewAppUpFiles = rebar_utils:find_files_by_ext(
+ filename:join([NewVerPath, "lib"]), ".appup"),
%% Convert the list of appup files into app names
AppUpApps = [file_to_name(File) || File <- NewAppUpFiles],
@@ -73,14 +79,21 @@
UpgradeApps = genappup_which_apps(Upgraded, AppUpApps),
%% Generate appup files for upgraded apps
- generate_appup_files(NewVerPath, OldVerPath, UpgradeApps),
+ generate_appup_files(NewVerPath, OldVerPath, ModDeps, UpgradeApps),
- ok.
+ {ok, Config1}.
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, 'generate-appups') ->
+ ?CONSOLE("Generate appup files.~n"
+ "~n"
+ "Valid command line options:~n"
+ " previous_release=path~n",
+ []).
+
get_apps(Name, OldVerPath, NewVerPath) ->
OldApps = rebar_rel_utils:get_rel_apps(Name, OldVerPath),
?DEBUG("Old Version Apps: ~p~n", [OldApps]),
@@ -128,9 +141,9 @@
genappup_which_apps(Apps, []) ->
Apps.
-generate_appup_files(NewVerPath, OldVerPath, [{_App, {undefined, _}}|Rest]) ->
- generate_appup_files(NewVerPath, OldVerPath, Rest);
-generate_appup_files(NewVerPath, OldVerPath, [{App, {OldVer, NewVer}}|Rest]) ->
+generate_appup_files(NewVerPath, OldVerPath, ModDeps, [{_App, {undefined, _}}|Rest]) ->
+ generate_appup_files(NewVerPath, OldVerPath, ModDeps, Rest);
+generate_appup_files(NewVerPath, OldVerPath, ModDeps, [{App, {OldVer, NewVer}}|Rest]) ->
OldEbinDir = filename:join([OldVerPath, "lib",
atom_to_list(App) ++ "-" ++ OldVer, "ebin"]),
NewEbinDir = filename:join([NewVerPath, "lib",
@@ -139,9 +152,14 @@
{AddedFiles, DeletedFiles, ChangedFiles} = beam_lib:cmp_dirs(NewEbinDir,
OldEbinDir),
+ ChangedNames = [list_to_atom(file_to_name(F)) || {F, _} <- ChangedFiles],
+ ModDeps1 = [{N, [M1 || M1 <- M, lists:member(M1, ChangedNames)]}
+ || {N, M} <- ModDeps],
+
Added = [generate_instruction(added, File) || File <- AddedFiles],
Deleted = [generate_instruction(deleted, File) || File <- DeletedFiles],
- Changed = [generate_instruction(changed, File) || File <- ChangedFiles],
+ Changed = [generate_instruction(changed, ModDeps1, File)
+ || File <- ChangedFiles],
Inst = lists:append([Added, Deleted, Changed]),
@@ -153,8 +171,8 @@
OldVer, Inst, OldVer])),
?CONSOLE("Generated appup for ~p~n", [App]),
- generate_appup_files(NewVerPath, OldVerPath, Rest);
-generate_appup_files(_, _, []) ->
+ generate_appup_files(NewVerPath, OldVerPath, ModDeps, Rest);
+generate_appup_files(_, _, _, []) ->
?CONSOLE("Appup generation complete~n", []).
generate_instruction(added, File) ->
@@ -162,25 +180,27 @@
{add_module, Name};
generate_instruction(deleted, File) ->
Name = list_to_atom(file_to_name(File)),
- {delete_module, Name};
-generate_instruction(changed, {File, _}) ->
+ {delete_module, Name}.
+
+generate_instruction(changed, ModDeps, {File, _}) ->
{ok, {Name, List}} = beam_lib:chunks(File, [attributes, exports]),
Behavior = get_behavior(List),
CodeChange = is_code_change(List),
- generate_instruction_advanced(Name, Behavior, CodeChange).
+ Deps = proplists:get_value(Name, ModDeps, []),
+ generate_instruction_advanced(Name, Behavior, CodeChange, Deps).
-generate_instruction_advanced(Name, undefined, undefined) ->
+generate_instruction_advanced(Name, undefined, undefined, Deps) ->
%% Not a behavior or code change, assume purely functional
- {load_module, Name};
-generate_instruction_advanced(Name, [supervisor], _) ->
+ {load_module, Name, Deps};
+generate_instruction_advanced(Name, [supervisor], _, _) ->
%% Supervisor
{update, Name, supervisor};
-generate_instruction_advanced(Name, _, code_change) ->
+generate_instruction_advanced(Name, _, code_change, Deps) ->
%% Includes code_change export
- {update, Name, {advanced, []}};
-generate_instruction_advanced(Name, _, _) ->
+ {update, Name, {advanced, []}, Deps};
+generate_instruction_advanced(Name, _, _, Deps) ->
%% Anything else
- {load_module, Name}.
+ {load_module, Name, Deps}.
get_behavior(List) ->
Attributes = proplists:get_value(attributes, List),
diff -Nru rebar-2.0.0/src/rebar_app_utils.erl rebar-2.6.0/src/rebar_app_utils.erl
--- rebar-2.0.0/src/rebar_app_utils.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_app_utils.erl 2015-06-19 16:14:28.000000000 +0000
@@ -26,15 +26,16 @@
%% -------------------------------------------------------------------
-module(rebar_app_utils).
--export([is_app_dir/0, is_app_dir/1,
+-export([is_app_dir/0,
+ is_app_dir/1,
is_app_src/1,
app_src_to_app/1,
- app_name/1,
- app_applications/1,
- app_vsn/1,
- is_skipped_app/1]).
+ app_name/2,
+ app_applications/2,
+ app_vsn/2,
+ is_skipped_app/2]).
--export([load_app_file/1]). % TEMPORARY
+-export([load_app_file/2]). % TEMPORARY
-include("rebar.hrl").
@@ -46,106 +47,140 @@
is_app_dir(rebar_utils:get_cwd()).
is_app_dir(Dir) ->
- SrcDir = filename:join([Dir, "src"]),
- AppSrc = filename:join([SrcDir, "*.app.src"]),
- case filelib:wildcard(AppSrc) of
- [AppSrcFile] ->
- {true, AppSrcFile};
- [] ->
- EbinDir = filename:join([Dir, "ebin"]),
- App = filename:join([EbinDir, "*.app"]),
- case filelib:wildcard(App) of
- [AppFile] ->
- {true, AppFile};
- [] ->
- false;
- _ ->
- ?ERROR("More than one .app file in ~s~n", [EbinDir]),
- false
- end;
- _ ->
- ?ERROR("More than one .app.src file in ~s~n", [SrcDir]),
- false
- end.
+ SrcDir = filename:join([Dir, "src"]),
+ AppSrcScript = filename:join([SrcDir, "*.app.src.script"]),
+ AppSrc = filename:join([SrcDir, "*.app.src"]),
+ case {filelib:wildcard(AppSrcScript), filelib:wildcard(AppSrc)} of
+ {[AppSrcScriptFile], _} ->
+ {true, AppSrcScriptFile};
+ {[], [AppSrcFile]} ->
+ {true, AppSrcFile};
+ {[],[]} ->
+ EbinDir = filename:join([Dir, "ebin"]),
+ App = filename:join([EbinDir, "*.app"]),
+ case filelib:wildcard(App) of
+ [AppFile] ->
+ {true, AppFile};
+ [] ->
+ false;
+ _ ->
+ ?ERROR("More than one .app file in ~s~n", [EbinDir]),
+ false
+ end;
+ {_, _} ->
+ ?ERROR("More than one .app.src file in ~s~n", [SrcDir]),
+ false
+ end.
is_app_src(Filename) ->
%% If removing the extension .app.src yields a shorter name,
%% this is an .app.src file.
- Filename =/= filename:rootname(Filename, ".app.src").
+ Filename =/= filename:rootname(Filename, ".app.src") orelse
+ Filename =/= filename:rootname(Filename, ".app.src.script").
app_src_to_app(Filename) ->
- filename:join("ebin", filename:basename(Filename, ".app.src") ++ ".app").
-
-app_name(AppFile) ->
- case load_app_file(AppFile) of
- {ok, AppName, _} ->
- AppName;
+ Filebase = case filename:rootname(Filename, ".app.src") of
+ Filename ->
+ filename:basename(Filename, ".app.src.script");
+ _ ->
+ filename:basename(Filename, ".app.src")
+ end,
+ filename:join("ebin", Filebase ++ ".app").
+
+app_name(Config, AppFile) ->
+ case load_app_file(Config, AppFile) of
+ {ok, NewConfig, AppName, _} ->
+ {NewConfig, AppName};
{error, Reason} ->
?ABORT("Failed to extract name from ~s: ~p\n",
[AppFile, Reason])
end.
-app_applications(AppFile) ->
- case load_app_file(AppFile) of
- {ok, _, AppInfo} ->
- get_value(applications, AppInfo, AppFile);
+app_applications(Config, AppFile) ->
+ case load_app_file(Config, AppFile) of
+ {ok, NewConfig, _, AppInfo} ->
+ {NewConfig, get_value(applications, AppInfo, AppFile)};
{error, Reason} ->
?ABORT("Failed to extract applications from ~s: ~p\n",
[AppFile, Reason])
end.
-app_vsn(AppFile) ->
- case load_app_file(AppFile) of
- {ok, _, AppInfo} ->
+app_vsn(Config, AppFile) ->
+ case load_app_file(Config, AppFile) of
+ {ok, Config1, _, AppInfo} ->
AppDir = filename:dirname(filename:dirname(AppFile)),
- rebar_utils:vcs_vsn(get_value(vsn, AppInfo, AppFile), AppDir);
+ rebar_utils:vcs_vsn(Config1, get_value(vsn, AppInfo, AppFile),
+ AppDir);
{error, Reason} ->
?ABORT("Failed to extract vsn from ~s: ~p\n",
[AppFile, Reason])
end.
-is_skipped_app(AppFile) ->
- ThisApp = app_name(AppFile),
+is_skipped_app(Config, AppFile) ->
+ {Config1, ThisApp} = app_name(Config, AppFile),
%% Check for apps global parameter; this is a comma-delimited list
%% of apps on which we want to run commands
- case get_apps() of
- undefined ->
- %% No apps parameter specified, check the skip_apps list..
- case get_skip_apps() of
- undefined ->
- %% No skip_apps list, run everything..
- false;
- SkipApps ->
- TargetApps = [list_to_atom(A) ||
- A <- string:tokens(SkipApps, ",")],
- is_skipped_app(ThisApp, TargetApps)
- end;
- Apps ->
- %% run only selected apps
- TargetApps = [list_to_atom(A) || A <- string:tokens(Apps, ",")],
- is_selected_app(ThisApp, TargetApps)
- end.
+ Skipped =
+ case get_apps(Config) of
+ undefined ->
+ %% No apps parameter specified, check the skip_apps list..
+ case get_skip_apps(Config) of
+ undefined ->
+ %% No skip_apps list, run everything..
+ false;
+ SkipApps ->
+ TargetApps = [list_to_atom(A) ||
+ A <- string:tokens(SkipApps, ",")],
+ is_skipped(ThisApp, TargetApps)
+ end;
+ Apps ->
+ %% run only selected apps
+ TargetApps = [list_to_atom(A) || A <- string:tokens(Apps, ",")],
+ is_selected(ThisApp, TargetApps)
+ end,
+ {Config1, Skipped}.
%% ===================================================================
%% Internal functions
%% ===================================================================
-load_app_file(Filename) ->
+load_app_file(Config, Filename) ->
AppFile = {app_file, Filename},
- case erlang:get(AppFile) of
+ case rebar_config:get_xconf(Config, {appfile, AppFile}, undefined) of
undefined ->
- case file:consult(Filename) of
- {ok, [{application, AppName, AppData}]} ->
- erlang:put(AppFile, {AppName, AppData}),
- {ok, AppName, AppData};
+ case consult_app_file(Filename) of
+ {ok, {application, AppName, AppData}} ->
+ Config1 = rebar_config:set_xconf(Config,
+ {appfile, AppFile},
+ {AppName, AppData}),
+ {ok, Config1, AppName, AppData};
{error, _} = Error ->
- Error;
+ {error, {error, Error}};
Other ->
{error, {unexpected_terms, Other}}
end;
{AppName, AppData} ->
- {ok, AppName, AppData}
+ {ok, Config, AppName, AppData}
+ end.
+
+%% In the case of *.app.src we want to give the user the ability to
+%% dynamically script the application resource file (think dynamic version
+%% string, etc.), in a way similar to what can be done with the rebar
+%% config. However, in the case of *.app, rebar should not manipulate
+%% that file. This enforces that dichotomy between app and app.src.
+consult_app_file(Filename) ->
+ Result = case lists:suffix(".app", Filename) of
+ true ->
+ file:consult(Filename);
+ false ->
+ rebar_config:consult_file(Filename)
+ end,
+ case Result of
+ {ok, [Term]} ->
+ {ok, Term};
+ _ ->
+ Result
end.
get_value(Key, AppInfo, AppFile) ->
@@ -157,7 +192,7 @@
end.
%% apps= for selecting apps
-is_selected_app(ThisApp, TargetApps) ->
+is_selected(ThisApp, TargetApps) ->
case lists:member(ThisApp, TargetApps) of
false ->
{true, ThisApp};
@@ -166,7 +201,7 @@
end.
%% skip_apps= for filtering apps
-is_skipped_app(ThisApp, TargetApps) ->
+is_skipped(ThisApp, TargetApps) ->
case lists:member(ThisApp, TargetApps) of
false ->
false;
@@ -174,8 +209,8 @@
{true, ThisApp}
end.
-get_apps() ->
- rebar_utils:get_deprecated_global(app, apps, "soon").
+get_apps(Config) ->
+ rebar_config:get_global(Config, apps, undefined).
-get_skip_apps() ->
- rebar_utils:get_deprecated_global(skip_app, skip_apps, "soon").
+get_skip_apps(Config) ->
+ rebar_config:get_global(Config, skip_apps, undefined).
diff -Nru rebar-2.0.0/src/rebar_asn1_compiler.erl rebar-2.6.0/src/rebar_asn1_compiler.erl
--- rebar-2.0.0/src/rebar_asn1_compiler.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_asn1_compiler.erl 2015-06-19 16:14:28.000000000 +0000
@@ -30,24 +30,44 @@
-export([compile/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
%% Public API
%% ===================================================================
--spec compile(Config::rebar_config:config(), AppFile::file:filename()) -> 'ok'.
+-spec compile(rebar_config:config(), file:filename()) -> 'ok'.
compile(Config, _AppFile) ->
rebar_base_compiler:run(Config, filelib:wildcard("asn1/*.asn1"),
"asn1", ".asn1", "src", ".erl",
fun compile_asn1/3).
--spec clean(Config::rebar_config:config(), AppFile::file:filename()) -> 'ok'.
+-spec clean(rebar_config:config(), file:filename()) -> 'ok'.
clean(_Config, _AppFile) ->
GeneratedFiles = asn_generated_files("asn1", "src", "include"),
ok = rebar_file_utils:delete_each(GeneratedFiles),
ok.
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, compile) ->
+ info_help("Build ASN.1 (*.asn1) sources");
+info(help, clean) ->
+ info_help("Delete ASN.1 (*.asn1) results").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {asn1_opts, []} (see asn1ct:compile/2 documentation)~n",
+ [Description]).
+
-spec compile_asn1(file:filename(), file:filename(),
rebar_config:config()) -> ok.
compile_asn1(Source, Target, Config) ->
diff -Nru rebar-2.0.0/src/rebar_base_compiler.erl rebar-2.6.0/src/rebar_base_compiler.erl
--- rebar-2.0.0/src/rebar_base_compiler.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_base_compiler.erl 2015-06-19 16:14:28.000000000 +0000
@@ -28,8 +28,12 @@
-include("rebar.hrl").
--export([run/4, run/7, run/8]).
-
+-export([run/4,
+ run/7,
+ run/8,
+ run/5,
+ ok_tuple/3,
+ error_tuple/5]).
%% ===================================================================
%% Public API
@@ -46,10 +50,10 @@
_ ->
Self = self(),
F = fun() -> compile_worker(Self, Config, CompileFn) end,
- Jobs = rebar_config:get_jobs(),
+ Jobs = rebar:get_jobs(Config),
?DEBUG("Starting ~B compile worker(s)~n", [Jobs]),
Pids = [spawn_monitor(F) || _I <- lists:seq(1,Jobs)],
- compile_queue(Pids, RestFiles)
+ compile_queue(Config, Pids, RestFiles)
end.
run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt,
@@ -59,26 +63,40 @@
run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt,
Compile3Fn, Opts) ->
- %% Convert simple extension to proper regex
- SourceExtRe = ".*\\" ++ SourceExt ++ [$$],
%% Find all possible source files
- FoundFiles = rebar_utils:find_files(SourceDir, SourceExtRe),
+ Recursive = proplists:get_value(recursive, Opts, true),
+ FoundFiles = rebar_utils:find_files_by_ext(SourceDir, SourceExt, Recursive),
%% Remove first files from found files
RestFiles = [Source || Source <- FoundFiles,
not lists:member(Source, FirstFiles)],
+ FirstUnits = source_to_unit_each(FirstFiles,
+ SourceDir, SourceExt,
+ TargetDir, TargetExt),
+ RestUnits = source_to_unit_each(RestFiles,
+ SourceDir, SourceExt,
+ TargetDir, TargetExt),
+ run(Config, FirstUnits, RestUnits, Compile3Fn, Opts).
+
+%% FirstUnits and RestUnits are lists of tuples: {Source,Target}
+run(Config, FirstUnits, RestUnits, Compile3Fn, Opts) ->
+
%% Check opts for flag indicating that compile should check lastmod
CheckLastMod = proplists:get_bool(check_last_mod, Opts),
- run(Config, FirstFiles, RestFiles,
- fun(S, C) ->
- Target = target_file(S, SourceDir, SourceExt,
- TargetDir, TargetExt),
+ run(Config, FirstUnits, RestUnits,
+ fun({S, Target}, C) ->
simple_compile_wrapper(S, Target, Compile3Fn, C, CheckLastMod)
end).
+ok_tuple(Config, Source, Ws) ->
+ {ok, format_warnings(Config, Source, Ws)}.
+
+error_tuple(Config, Source, Es, Ws, Opts) ->
+ {error, format_errors(Config, Source, Es),
+ format_warnings(Config, Source, Ws, Opts)}.
%% ===================================================================
%% Internal functions
@@ -94,12 +112,13 @@
skipped
end.
+source_to_unit_each(Files, SourceDir, SourceExt, TargetDir, TargetExt) ->
+ [{File, target_file(File, SourceDir, SourceExt, TargetDir, TargetExt)}
+ || File <- Files].
+
target_file(SourceFile, SourceDir, SourceExt, TargetDir, TargetExt) ->
- %% Remove all leading components of the source dir from the file -- we want
- %% to maintain the deeper structure (if any) of the source file path
BaseFile = remove_common_path(SourceFile, SourceDir),
- filename:join([TargetDir, filename:dirname(BaseFile),
- filename:basename(BaseFile, SourceExt) ++ TargetExt]).
+ filename:join([TargetDir, filename:basename(BaseFile, SourceExt) ++ TargetExt]).
remove_common_path(Fname, Path) ->
@@ -110,59 +129,80 @@
remove_common_path1(FilenameParts, _) ->
filename:join(FilenameParts).
-
-compile(Source, Config, CompileFn) ->
- case CompileFn(Source, Config) of
- ok ->
- ok;
- skipped ->
- skipped
- end.
-
-
compile_each([], _Config, _CompileFn) ->
ok;
-compile_each([Source | Rest], Config, CompileFn) ->
- case compile(Source, Config, CompileFn) of
+compile_each([Unit | Rest], Config, CompileFn) ->
+ case CompileFn(Unit, Config) of
ok ->
- ?CONSOLE("Compiled ~s\n", [Source]);
+ ?CONSOLE("Compiled ~s\n", [unit_source(Unit)]);
+ {ok, Warnings} ->
+ report(Warnings),
+ ?CONSOLE("Compiled ~s\n", [unit_source(Unit)]);
skipped ->
- ?INFO("Skipped ~s\n", [Source])
+ ?INFO("Skipped ~s\n", [unit_source(Unit)]);
+ Error ->
+ maybe_report(Error),
+ ?CONSOLE("Compiling ~s failed:\n",
+ [maybe_absname(Config, unit_source(Unit))]),
+ ?DEBUG("Compilation failed: ~p\n", [Error]),
+ case rebar_config:get_xconf(Config, keep_going, false) of
+ false ->
+ ?FAIL;
+ true ->
+ ?WARN("Continuing after build error\n", [])
+ end
end,
compile_each(Rest, Config, CompileFn).
+unit_source({Source, _Target}) ->
+ Source;
+unit_source(Source) ->
+ Source.
-
-compile_queue([], []) ->
+compile_queue(_Config, [], []) ->
ok;
-compile_queue(Pids, Targets) ->
+compile_queue(Config, Pids, Targets) ->
receive
{next, Worker} ->
case Targets of
[] ->
Worker ! empty,
- compile_queue(Pids, Targets);
+ compile_queue(Config, Pids, Targets);
[Source | Rest] ->
Worker ! {compile, Source},
- compile_queue(Pids, Rest)
+ compile_queue(Config, Pids, Rest)
end;
- {fail, Error} ->
+ {fail, {_, {source, Unit}}=Error} ->
+ maybe_report(Error),
+ ?CONSOLE("Compiling ~s failed:\n",
+ [maybe_absname(Config, unit_source(Unit))]),
?DEBUG("Worker compilation failed: ~p\n", [Error]),
- ?FAIL;
+ case rebar_config:get_xconf(Config, keep_going, false) of
+ false ->
+ ?FAIL;
+ true ->
+ ?WARN("Continuing after build error\n", []),
+ compile_queue(Config, Pids, Targets)
+ end;
- {compiled, Source} ->
- ?CONSOLE("Compiled ~s\n", [Source]),
- compile_queue(Pids, Targets);
-
- {skipped, Source} ->
- ?INFO("Skipped ~s\n", [Source]),
- compile_queue(Pids, Targets);
+ {compiled, Unit, Warnings} ->
+ report(Warnings),
+ ?CONSOLE("Compiled ~s\n", [unit_source(Unit)]),
+ compile_queue(Config, Pids, Targets);
+
+ {compiled, Unit} ->
+ ?CONSOLE("Compiled ~s\n", [unit_source(Unit)]),
+ compile_queue(Config, Pids, Targets);
+
+ {skipped, Unit} ->
+ ?INFO("Skipped ~s\n", [unit_source(Unit)]),
+ compile_queue(Config, Pids, Targets);
{'DOWN', Mref, _, Pid, normal} ->
?DEBUG("Worker exited cleanly\n", []),
Pids2 = lists:delete({Pid, Mref}, Pids),
- compile_queue(Pids2, Targets);
+ compile_queue(Config, Pids2, Targets);
{'DOWN', _Mref, _, _Pid, Info} ->
?DEBUG("Worker failed: ~p\n", [Info]),
@@ -173,7 +213,10 @@
QueuePid ! {next, self()},
receive
{compile, Source} ->
- case catch(compile(Source, Config, CompileFn)) of
+ case catch(CompileFn(Source, Config)) of
+ {ok, Ws} ->
+ QueuePid ! {compiled, Source, Ws},
+ compile_worker(QueuePid, Config, CompileFn);
ok ->
QueuePid ! {compiled, Source},
compile_worker(QueuePid, Config, CompileFn);
@@ -181,11 +224,66 @@
QueuePid ! {skipped, Source},
compile_worker(QueuePid, Config, CompileFn);
Error ->
- QueuePid ! {fail, [{error, Error},
- {source, Source}]},
- ok
+ QueuePid ! {fail, {{error, Error}, {source, Source}}},
+ case rebar_config:get_xconf(Config, keep_going, false) of
+ false ->
+ ok;
+ true ->
+ compile_worker(QueuePid, Config, CompileFn)
+ end
end;
empty ->
ok
end.
+
+format_errors(Config, Source, Errors) ->
+ format_errors(Config, Source, "", Errors).
+
+format_warnings(Config, Source, Warnings) ->
+ format_warnings(Config, Source, Warnings, []).
+
+format_warnings(Config, Source, Warnings, Opts) ->
+ Prefix = case lists:member(warnings_as_errors, Opts) of
+ true -> "";
+ false -> "Warning: "
+ end,
+ format_errors(Config, Source, Prefix, Warnings).
+
+maybe_report({{error, {error, _Es, _Ws}=ErrorsAndWarnings}, {source, _}}) ->
+ maybe_report(ErrorsAndWarnings);
+maybe_report([{error, E}, {source, S}]) ->
+ report(["unexpected error compiling " ++ S, io_lib:fwrite("~n~p~n", [E])]);
+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(Config, _MainSource, Extra, Errors) ->
+ [begin
+ AbsSource = maybe_absname(Config, Source),
+ [format_error(AbsSource, Extra, Desc) || Desc <- Descs]
+ end
+ || {Source, 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]).
+
+maybe_absname(Config, Filename) ->
+ case rebar_utils:processing_base_dir(Config) of
+ true ->
+ Filename;
+ false ->
+ filename:absname(Filename)
+ end.
diff -Nru rebar-2.0.0/src/rebar_cleaner.erl rebar-2.6.0/src/rebar_cleaner.erl
--- rebar-2.0.0/src/rebar_cleaner.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_cleaner.erl 2015-06-19 16:14:28.000000000 +0000
@@ -28,6 +28,9 @@
-export([clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -37,3 +40,17 @@
%% Get a list of files to delete from config and remove them
FilesToClean = rebar_config:get(Config, clean_files, []),
lists:foreach(fun (F) -> rebar_file_utils:rm_rf(F) end, FilesToClean).
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, clean) ->
+ ?CONSOLE(
+ "Delete list of files.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {clean_files, ["file", "file2"]}
+ ]).
diff -Nru rebar-2.0.0/src/rebar_config.erl rebar-2.6.0/src/rebar_config.erl
--- rebar-2.0.0/src/rebar_config.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_config.erl 2015-06-19 16:14:28.000000000 +0000
@@ -26,37 +26,70 @@
%% -------------------------------------------------------------------
-module(rebar_config).
--export([new/0, new/1, base_config/1, consult_file/1,
- get/3, get_local/3, get_list/3,
+-export([new/0,
+ new/1,
+ base_config/1,
+ consult_file/1,
+ get/3,
+ get_local/3,
+ get_list/3,
get_all/2,
set/3,
- set_global/2, get_global/2,
- is_verbose/0, get_jobs/0,
- set_env/3, get_env/2]).
+ set_global/3,
+ get_global/3,
+ is_recursive/1,
+ save_env/3,
+ get_env/2,
+ reset_envs/1,
+ set_skip_dir/2,
+ is_skip_dir/2,
+ reset_skip_dirs/1,
+ clean_config/2,
+ set_xconf/3,
+ get_xconf/2,
+ get_xconf/3,
+ erase_xconf/2]).
-include("rebar.hrl").
+-ifdef(namespaced_types).
+%% dict:dict() exists starting from Erlang 17.
+-type rebar_dict() :: dict:dict(term(), term()).
+-else.
+%% dict() has been obsoleted in Erlang 17 and deprecated in 18.
+-type rebar_dict() :: dict().
+-endif.
+
+-type key() :: atom().
+
-record(config, { dir :: file:filename(),
opts = [] :: list(),
- envs = new_env() :: dict() }).
+ globals = new_globals() :: rebar_dict(),
+ envs = new_env() :: rebar_dict(),
+ %% cross-directory/-command config
+ skip_dirs = new_skip_dirs() :: rebar_dict(),
+ xconf = new_xconf() :: rebar_dict() }).
-%% Types that can be used from other modules -- alphabetically ordered.
-export_type([config/0]).
-%% data types
-opaque config() :: #config{}.
+-define(DEFAULT_NAME, "rebar.config").
+
%% ===================================================================
%% Public API
%% ===================================================================
-base_config(#config{opts=Opts0}) ->
- ConfName = rebar_config:get_global(config, "rebar.config"),
- new(Opts0, ConfName).
+-spec base_config(config()) -> config().
+base_config(GlobalConfig) ->
+ ConfName = rebar_config:get_global(GlobalConfig, config, ?DEFAULT_NAME),
+ new(GlobalConfig, ConfName).
+-spec new() -> config().
new() ->
#config{dir = rebar_utils:get_cwd()}.
+-spec new(file:filename() | config()) -> config().
new(ConfigFile) when is_list(ConfigFile) ->
case consult_file(ConfigFile) of
{ok, Opts} ->
@@ -65,70 +98,56 @@
Other ->
?ABORT("Failed to load ~s: ~p~n", [ConfigFile, Other])
end;
-new(_ParentConfig=#config{opts=Opts0})->
- new(Opts0, "rebar.config").
-
-new(Opts0, ConfName) ->
- %% Load terms from rebar.config, if it exists
- Dir = rebar_utils:get_cwd(),
- ConfigFile = filename:join([Dir, ConfName]),
- Opts = case consult_file(ConfigFile) of
- {ok, Terms} ->
- %% Found a config file with some terms. We need to
- %% be able to distinguish between local definitions
- %% (i.e. from the file in the cwd) and inherited
- %% definitions. To accomplish this, we use a marker
- %% in the proplist (since order matters) between
- %% the new and old defs.
- Terms ++ [local] ++
- [Opt || Opt <- Opts0, Opt /= local];
- {error, enoent} ->
- [local] ++
- [Opt || Opt <- Opts0, Opt /= local];
- Other ->
- ?ABORT("Failed to load ~s: ~p\n", [ConfigFile, Other])
- end,
-
- #config{dir = Dir, opts = Opts}.
+new(_ParentConfig=#config{opts=Opts0, globals=Globals, skip_dirs=SkipDirs,
+ xconf=Xconf}) ->
+ new(#config{opts=Opts0, globals=Globals, skip_dirs=SkipDirs, xconf=Xconf},
+ ?DEFAULT_NAME).
+-spec get(config(), key(), term()) -> term().
get(Config, Key, Default) ->
proplists:get_value(Key, Config#config.opts, Default).
+-spec get_list(config(), key(), term()) -> term().
get_list(Config, Key, Default) ->
get(Config, Key, Default).
+-spec get_local(config(), key(), term()) -> term().
get_local(Config, Key, Default) ->
proplists:get_value(Key, local_opts(Config#config.opts, []), Default).
+-spec get_all(config(), key()) -> list(term()).
get_all(Config, Key) ->
proplists:get_all_values(Key, Config#config.opts).
+-spec set(config(), key(), term()) -> config().
set(Config, Key, Value) ->
Opts = proplists:delete(Key, Config#config.opts),
Config#config { opts = [{Key, Value} | Opts] }.
-set_global(jobs=Key, Value) when is_list(Value) ->
- set_global(Key, list_to_integer(Value));
-set_global(jobs=Key, Value) when is_integer(Value) ->
- application:set_env(rebar_global, Key, erlang:max(1, Value));
-set_global(Key, Value) ->
- application:set_env(rebar_global, Key, Value).
-
-get_global(Key, Default) ->
- case application:get_env(rebar_global, Key) of
- undefined ->
+-spec set_global(config(), key(), term()) -> config().
+set_global(Config, jobs=Key, Value) when is_list(Value) ->
+ set_global(Config, Key, list_to_integer(Value));
+set_global(Config, jobs=Key, Value) when is_integer(Value) ->
+ NewGlobals = dict:store(Key, erlang:max(1, Value), Config#config.globals),
+ Config#config{globals = NewGlobals};
+set_global(Config, Key, Value) ->
+ NewGlobals = dict:store(Key, Value, Config#config.globals),
+ Config#config{globals = NewGlobals}.
+
+-spec get_global(config(), key(), term()) -> term().
+get_global(Config, Key, Default) ->
+ case dict:find(Key, Config#config.globals) of
+ error ->
Default;
{ok, Value} ->
Value
end.
-is_verbose() ->
- DefaulLevel = rebar_log:default_level(),
- get_global(verbose, DefaulLevel) > DefaulLevel.
-
-get_jobs() ->
- get_global(jobs, 3).
+-spec is_recursive(config()) -> boolean().
+is_recursive(Config) ->
+ get_xconf(Config, recursive, false).
+-spec consult_file(file:filename()) -> term().
consult_file(File) ->
case filename:extension(File) of
".script" ->
@@ -144,43 +163,128 @@
end
end.
-set_env(Config, Mod, Env) ->
- OldEnvs = Config#config.envs,
- NewEnvs = dict:store(Mod, Env, OldEnvs),
- Config#config{envs=NewEnvs}.
+-spec save_env(config(), module(), nonempty_list()) -> config().
+save_env(Config, Mod, Env) ->
+ NewEnvs = dict:store(Mod, Env, Config#config.envs),
+ Config#config{envs = NewEnvs}.
+-spec get_env(config(), module()) -> term().
get_env(Config, Mod) ->
dict:fetch(Mod, Config#config.envs).
+-spec reset_envs(config()) -> config().
+reset_envs(Config) ->
+ Config#config{envs = new_env()}.
+
+-spec set_skip_dir(config(), file:filename()) -> config().
+set_skip_dir(Config, Dir) ->
+ OldSkipDirs = Config#config.skip_dirs,
+ NewSkipDirs = case is_skip_dir(Config, Dir) of
+ false ->
+ ?DEBUG("Adding skip dir: ~s\n", [Dir]),
+ dict:store(Dir, true, OldSkipDirs);
+ true ->
+ OldSkipDirs
+ end,
+ Config#config{skip_dirs = NewSkipDirs}.
+
+-spec is_skip_dir(config(), file:filename()) -> boolean().
+is_skip_dir(Config, Dir) ->
+ dict:is_key(Dir, Config#config.skip_dirs).
+
+-spec reset_skip_dirs(config()) -> config().
+reset_skip_dirs(Config) ->
+ Config#config{skip_dirs = new_skip_dirs()}.
+
+-spec set_xconf(config(), term(), term()) -> config().
+set_xconf(Config, Key, Value) ->
+ NewXconf = dict:store(Key, Value, Config#config.xconf),
+ Config#config{xconf=NewXconf}.
+
+-spec get_xconf(config(), term()) -> term().
+get_xconf(Config, Key) ->
+ {ok, Value} = dict:find(Key, Config#config.xconf),
+ Value.
+
+-spec get_xconf(config(), term(), term()) -> term().
+get_xconf(Config, Key, Default) ->
+ case dict:find(Key, Config#config.xconf) of
+ error ->
+ Default;
+ {ok, Value} ->
+ Value
+ end.
+
+-spec erase_xconf(config(), term()) -> config().
+erase_xconf(Config, Key) ->
+ NewXconf = dict:erase(Key, Config#config.xconf),
+ Config#config{xconf = NewXconf}.
+
+%% TODO: reconsider after config inheritance removal/redesign
+-spec clean_config(config(), config()) -> config().
+clean_config(Old, New) ->
+ New#config{opts=Old#config.opts}.
+
%% ===================================================================
%% Internal functions
%% ===================================================================
+-spec new(config(), file:filename()) -> config().
+new(ParentConfig, ConfName) ->
+ %% Load terms from rebar.config, if it exists
+ Dir = rebar_utils:get_cwd(),
+ ConfigFile = filename:join([Dir, ConfName]),
+ Opts0 = ParentConfig#config.opts,
+ Opts = case consult_file(ConfigFile) of
+ {ok, Terms} ->
+ %% Found a config file with some terms. We need to
+ %% be able to distinguish between local definitions
+ %% (i.e. from the file in the cwd) and inherited
+ %% definitions. To accomplish this, we use a marker
+ %% in the proplist (since order matters) between
+ %% the new and old defs.
+ Terms ++ [local] ++
+ [Opt || Opt <- Opts0, Opt /= local];
+ {error, enoent} ->
+ [local] ++
+ [Opt || Opt <- Opts0, Opt /= local];
+ Other ->
+ ?ABORT("Failed to load ~s: ~p\n", [ConfigFile, Other])
+ end,
+
+ ParentConfig#config{dir = Dir, opts = Opts}.
+
+-spec consult_and_eval(file:filename(), file:filename()) -> {ok, term()}.
consult_and_eval(File, Script) ->
?DEBUG("Evaluating config script ~p~n", [Script]),
ConfigData = try_consult(File),
file:script(Script, bs([{'CONFIG', ConfigData}, {'SCRIPT', Script}])).
-
+-spec remove_script_ext(file:filename()) -> file:filename().
remove_script_ext(F) ->
"tpircs." ++ Rev = lists:reverse(F),
lists:reverse(Rev).
+-spec try_consult(file:filename()) -> term().
try_consult(File) ->
case file:consult(File) of
{ok, Terms} ->
?DEBUG("Consult config file ~p~n", [File]),
Terms;
- {error, enoent} -> [];
+ {error, enoent} ->
+ [];
{error, Reason} ->
?ABORT("Failed to read config file ~s: ~p~n", [File, Reason])
end.
+-type bs_vars() :: [{term(), term()}].
+-spec bs(bs_vars()) -> bs_vars().
bs(Vars) ->
lists:foldl(fun({K,V}, Bs) ->
erl_eval:add_binding(K, V, Bs)
end, erl_eval:new_bindings(), Vars).
+-spec local_opts(list(), list()) -> list().
local_opts([], Acc) ->
lists:reverse(Acc);
local_opts([local | _Rest], Acc) ->
@@ -188,5 +292,14 @@
local_opts([Item | Rest], Acc) ->
local_opts(Rest, [Item | Acc]).
-new_env() ->
- dict:new().
+-spec new_globals() -> rebar_dict().
+new_globals() -> dict:new().
+
+-spec new_env() -> rebar_dict().
+new_env() -> dict:new().
+
+-spec new_skip_dirs() -> rebar_dict().
+new_skip_dirs() -> dict:new().
+
+-spec new_xconf() -> rebar_dict().
+new_xconf() -> dict:new().
diff -Nru rebar-2.0.0/src/rebar_core.erl rebar-2.6.0/src/rebar_core.erl
--- rebar-2.0.0/src/rebar_core.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_core.erl 2015-06-19 16:14:28.000000000 +0000
@@ -27,151 +27,203 @@
-module(rebar_core).
-export([process_commands/2,
- skip_dir/1,
- is_skip_dir/1,
- skip_dirs/0]).
+ help/2]).
-include("rebar.hrl").
-
-%% ===================================================================
-%% Public API
-%% ===================================================================
-
-skip_dir(Dir) ->
- SkipDir = {skip_dir, Dir},
- case erlang:get(SkipDir) of
- undefined ->
- ?DEBUG("Adding skip dir: ~s\n", [Dir]),
- erlang:put(SkipDir, true);
- true ->
- ok
- end.
-
-is_skip_dir(Dir) ->
- case erlang:get({skip_dir, Dir}) of
- undefined ->
- false;
- true ->
- true
- end.
-
-skip_dirs() ->
- [Dir || {{skip_dir, Dir}, true} <- erlang:get()].
-
%% ===================================================================
%% Internal functions
%% ===================================================================
-process_commands([], _ParentConfig) ->
- case erlang:get(operations) of
- 0 ->
- %% none of the commands had an effect
+-spec help(rebar_config:config(), [atom()]) -> ok.
+help(ParentConfig, Commands) ->
+ %% get all core modules
+ {ok, AnyDirModules} = application:get_env(rebar, any_dir_modules),
+ {ok, RawCoreModules} = application:get_env(rebar, modules),
+ AppDirModules = proplists:get_value(app_dir, RawCoreModules),
+ RelDirModules = proplists:get_value(rel_dir, RawCoreModules),
+ CoreModules = AnyDirModules ++ AppDirModules ++ RelDirModules,
+
+ %% get plugin modules
+ Predirs = [],
+ Dir = rebar_utils:get_cwd(),
+ PredirsAssoc = remember_cwd_predirs(Dir, Predirs),
+ Config = maybe_load_local_config(Dir, ParentConfig),
+ {ok, PluginModules} = plugin_modules(Config, PredirsAssoc),
+
+ AllModules = CoreModules ++ PluginModules,
+
+ lists:foreach(
+ fun(Cmd) ->
+ ?CONSOLE("==> help ~p~n~n", [Cmd]),
+ CmdModules = select_modules(AllModules, Cmd, []),
+ Modules = select_modules(CmdModules, info, []),
+ lists:foreach(fun(M) ->
+ ?CONSOLE("=== ~p:~p ===~n", [M, Cmd]),
+ M:info(help, Cmd),
+ ?CONSOLE("~n", [])
+ end, Modules)
+ end, Commands).
+
+-spec process_commands([atom()], rebar_config:config()) -> ok.
+process_commands([], ParentConfig) ->
+ AbortTrapped = rebar_config:get_xconf(ParentConfig, abort_trapped, false),
+ case {get_operations(ParentConfig), AbortTrapped} of
+ {0, _} ->
+ %% None of the commands had any effect
+ ?FAIL;
+ {_, true} ->
+ %% An abort was previously trapped
?FAIL;
_ ->
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
- end,
- %% Wipe out vsn cache to avoid invalid hits when
- %% dependencies are updated
- ets:delete_all_objects(rebar_vsn_cache),
- process_commands(Rest, ParentConfig).
+ ParentConfig1 = rebar_config:reset_skip_dirs(ParentConfig),
+ Operations = get_operations(ParentConfig1),
+ ParentConfig4 =
+ try
+ %% 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(),
+ {ParentConfig2, _DirSet} = process_dir(rebar_utils:get_cwd(),
+ Command, ParentConfig1,
+ sets:new()),
+ case get_operations(ParentConfig2) of
+ Operations ->
+ %% This command didn't do anything
+ ?CONSOLE("Command '~p' not understood or not applicable~n",
+ [Command]);
+ _ ->
+ ok
+ end,
+ %% TODO: reconsider after config inheritance removal/re-design
+ ParentConfig3 = rebar_config:clean_config(ParentConfig1,
+ ParentConfig2),
+ %% Wipe out vsn cache to avoid invalid hits when
+ %% dependencies are updated
+ rebar_config:set_xconf(ParentConfig3, vsn_cache, dict:new())
+ catch
+ throw:rebar_abort ->
+ case rebar_config:get_xconf(ParentConfig1, keep_going, false) of
+ false ->
+ ?FAIL;
+ true ->
+ ?WARN("Continuing on after abort: ~p\n", [Rest]),
+ rebar_config:set_xconf(ParentConfig1,
+ abort_trapped, true)
+ end
+ end,
+ process_commands(Rest, ParentConfig4).
-process_dir(Dir, ParentConfig, Command, DirSet) ->
+process_dir(Dir, Command, ParentConfig, DirSet) ->
case filelib:is_dir(Dir) of
false ->
?WARN("Skipping non-existent sub-dir: ~p\n", [Dir]),
- DirSet;
-
+ {ParentConfig, 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,
-
+ WouldCd = would_cd_into_dir(Dir, Command, ParentConfig),
ok = file:set_cwd(Dir),
Config = maybe_load_local_config(Dir, ParentConfig),
%% Save the current code path and then update it with
- %% lib_dirs. Children inherit parents code path, but we
- %% also want to ensure that we restore everything to pristine
+ %% lib_dirs. Children inherit parents code path, but we also
+ %% want to ensure that we restore everything to pristine
%% condition after processing this child
CurrentCodePath = update_code_path(Config),
- %% Get the list of processing modules and check each one against
- %% CWD to see if it's a fit -- if it is, use that set of modules
- %% to process this dir.
+ %% Get the list of processing modules and check each one
+ %% against CWD to see if it's a fit -- if it is, use that
+ %% set of modules 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,
+ skip_or_process_dir(Dir, Command, Config, DirSet, CurrentCodePath,
+ ModuleSet, WouldCd)
+ end.
- Res
+would_cd_into_dir(Dir, Command, Config) ->
+ case would_cd_into_dir1(Dir, Command, Config) of
+ true ->
+ would_cd;
+ false ->
+ would_not_cd
end.
-maybe_process_dir({[], undefined}=ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet) ->
- process_dir0(Dir, Command, DirSet, Config, CurrentCodePath, ModuleSet);
-maybe_process_dir({_, ModuleSetFile}=ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet) ->
- case lists:suffix(".app.src", ModuleSetFile)
- orelse lists:suffix(".app", ModuleSetFile) of
+would_cd_into_dir1(Dir, Command, Config) ->
+ rebar_utils:processing_base_dir(Config, Dir) orelse
+ rebar_config:is_recursive(Config) orelse
+ is_recursive_command(Command, Config) orelse
+ is_generate_in_rel_dir(Command, Dir).
+
+%% Check whether the command is part of the built-in (or extended via
+%% rebar.config) list of default-recursive commands.
+is_recursive_command(Command, Config) ->
+ {ok, AppCmds} = application:get_env(rebar, recursive_cmds),
+ ConfCmds = rebar_config:get_local(Config, recursive_cmds, []),
+ RecursiveCmds = AppCmds ++ ConfCmds,
+ lists:member(Command, RecursiveCmds).
+
+%% If the directory we're about to process contains
+%% reltool.config[.script] and the command to be applied is
+%% 'generate', then it's safe to process. We do this to retain the
+%% behavior of specifying {sub_dirs, ["rel"]} and have "rebar generate"
+%% pick up rel/reltool.config[.script]. Without this workaround you'd
+%% have to run "rebar -r generate" (which you don't want to do if you
+%% have deps or other sub_dirs) or "cd rel && rebar generate".
+is_generate_in_rel_dir(generate, Dir) ->
+ case rebar_rel_utils:is_rel_dir(Dir) of
+ {true, _} ->
+ true;
+ false ->
+ false
+ end;
+is_generate_in_rel_dir(_, _) ->
+ false.
+
+skip_or_process_dir(Dir, Command, Config, DirSet, CurrentCodePath,
+ {[], undefined}=ModuleSet, WouldCd) ->
+ process_dir1(Dir, Command, Config, DirSet, CurrentCodePath, ModuleSet,
+ WouldCd);
+skip_or_process_dir(Dir, Command, Config, DirSet, CurrentCodePath,
+ {_, File}=ModuleSet, WouldCd) ->
+ case lists:suffix(".app.src", File)
+ orelse lists:suffix(".app", File) of
true ->
%% .app or .app.src file, check if is_skipped_app
- maybe_process_dir0(ModuleSetFile, ModuleSet,
- Config, CurrentCodePath, Dir,
- Command, DirSet);
+ skip_or_process_dir1(Dir, Command, Config, DirSet, CurrentCodePath,
+ ModuleSet, WouldCd, File);
false ->
%% not an app dir, no need to consider apps=/skip_apps=
- process_dir0(Dir, Command, DirSet, Config,
- CurrentCodePath, ModuleSet)
+ process_dir1(Dir, Command, Config, DirSet, CurrentCodePath,
+ ModuleSet, WouldCd)
end.
-maybe_process_dir0(AppFile, ModuleSet, Config, CurrentCodePath,
- Dir, Command, DirSet) ->
- case rebar_app_utils:is_skipped_app(AppFile) of
- {true, SkippedApp} ->
+skip_or_process_dir1(Dir, Command, Config, DirSet, CurrentCodePath, ModuleSet,
+ WouldCd, AppFile) ->
+ case rebar_app_utils:is_skipped_app(Config, AppFile) of
+ {Config1, {true, _SkippedApp}} when Command == 'update-deps' ->
+ %% update-deps does its own app skipping. Unfortunately there's no
+ %% way to signal this to rebar_core, so we have to explicitly do it
+ %% here... Otherwise if you use app=, it'll skip the toplevel
+ %% directory and nothing will be updated.
+ process_dir1(Dir, Command, Config1, DirSet, CurrentCodePath,
+ ModuleSet, WouldCd);
+ {Config1, {true, SkippedApp}} ->
?DEBUG("Skipping app: ~p~n", [SkippedApp]),
- increment_operations(),
- DirSet;
- false ->
- process_dir0(Dir, Command, DirSet, Config,
- CurrentCodePath, ModuleSet)
+ {increment_operations(Config1), DirSet};
+ {Config1, false} ->
+ process_dir1(Dir, Command, Config1, DirSet, CurrentCodePath,
+ ModuleSet, WouldCd)
end.
-process_dir0(Dir, Command, DirSet, Config0, CurrentCodePath,
- {DirModules, ModuleSetFile}) ->
+process_dir1(Dir, Command, Config, DirSet, CurrentCodePath,
+ {DirModules, File}, WouldCd) ->
+ Config0 = rebar_config:set_xconf(Config, current_command, Command),
+
%% Get the list of modules for "any dir". This is a catch-all list
%% of modules that are processed in addition to modules associated
%% with this directory type. These any_dir modules are processed
@@ -182,64 +234,41 @@
%% Invoke 'preprocess' on the modules -- this yields a list of other
%% directories that should be processed _before_ the current one.
- Predirs = acc_modules(Modules, preprocess, Config0, ModuleSetFile),
+ {Config1, Predirs} = acc_modules(Modules, preprocess, Config0, File),
- SubdirAssoc = remember_cwd_subdir(Dir, Predirs),
+ %% Remember associated pre-dirs (used for plugin lookup)
+ PredirsAssoc = remember_cwd_predirs(Dir, Predirs),
%% Get the list of plug-in modules from rebar.config. These
%% modules may participate in preprocess and postprocess.
- {ok, PluginModules} = plugin_modules(Config0, SubdirAssoc),
+ {ok, PluginModules} = plugin_modules(Config1, PredirsAssoc),
+ AllModules = Modules ++ PluginModules,
- PluginPredirs = acc_modules(PluginModules, preprocess,
- Config0, ModuleSetFile),
+ {Config2, PluginPredirs} = acc_modules(PluginModules, preprocess, Config1,
+ File),
AllPredirs = Predirs ++ PluginPredirs,
?DEBUG("Predirs: ~p\n", [AllPredirs]),
- DirSet2 = process_each(AllPredirs, Command, Config0,
- ModuleSetFile, DirSet),
+ {Config3, DirSet2} = process_each(AllPredirs, Command, Config2, DirSet,
+ File),
%% Make sure the CWD is reset properly; processing the dirs may have
%% caused it to change
ok = file:set_cwd(Dir),
- %% Check that this directory is not on the skip list
- Config = case is_skip_dir(Dir) of
- true ->
- %% Do not execute the command on the directory, as some
- %% module has requested a skip on it.
- ?INFO("Skipping ~s in ~s\n", [Command, Dir]),
- Config0;
-
- false ->
- %% Check for and get command specific environments
- {Config1, Env} = setup_envs(Config0, Modules),
-
- %% Execute any before_command plugins on this directory
- execute_pre(Command, PluginModules,
- Config1, ModuleSetFile, Env),
-
- %% Execute the current command on this directory
- execute(Command, Modules ++ PluginModules,
- Config1, ModuleSetFile, Env),
-
- %% Execute any after_command plugins on this directory
- execute_post(Command, PluginModules,
- Config1, ModuleSetFile, Env),
-
- Config1
- end,
+ %% Maybe apply command to Dir
+ Config4 = maybe_execute(Dir, Command, Config3, Modules, PluginModules,
+ AllModules, File, WouldCd),
%% Mark the current directory as processed
DirSet3 = sets:add_element(Dir, DirSet2),
%% Invoke 'postprocess' on the modules. This yields a list of other
%% directories that should be processed _after_ the current one.
- Postdirs = acc_modules(Modules ++ PluginModules, postprocess,
- Config, ModuleSetFile),
+ {Config5, Postdirs} = acc_modules(AllModules, postprocess, Config4, File),
?DEBUG("Postdirs: ~p\n", [Postdirs]),
- DirSet4 = process_each(Postdirs, Command, Config,
- ModuleSetFile, DirSet3),
+ Res = process_each(Postdirs, Command, Config5, DirSet3, File),
%% Make sure the CWD is reset properly; processing the dirs may have
%% caused it to change
@@ -249,55 +278,83 @@
%% the parent initialized it to
restore_code_path(CurrentCodePath),
- %% Return the updated dirset as our result
- DirSet4.
+ %% Return the updated {config, dirset} as result
+ Res.
+
+maybe_execute(Dir, Command, Config, Modules, PluginModules, AllModules, File,
+ would_cd) ->
+ %% Check that this directory is not on the skip list
+ case rebar_config:is_skip_dir(Config, Dir) of
+ true ->
+ %% Do not execute the command on the directory, as some
+ %% module has requested a skip on it.
+ ?INFO("Skipping ~s in ~s\n", [Command, Dir]),
+ Config;
+
+ false ->
+ %% Check for and get command specific environments
+ {Config1, Env} = setup_envs(Config, Modules),
+
+ %% Execute any before_command plugins on this directory
+ Config2 = execute_pre(Command, PluginModules, Config1, File, Env),
+
+ %% Execute the current command on this directory
+ Config3 = execute(Command, AllModules, Config2, File, Env),
+
+ %% Execute any after_command plugins on this directory
+ execute_post(Command, PluginModules, Config3, File, Env)
+ end;
+maybe_execute(_Dir, _Command, Config, _Modules, _PluginModules, _AllModules,
+ _File, would_not_cd) ->
+ Config.
-remember_cwd_subdir(Cwd, Subdirs) ->
+remember_cwd_predirs(Cwd, Predirs) ->
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"
"sub_dir ~s already associated with ~s.~n"
- "Duplicate sub_dirs or deps entries?",
- [Dir, Existing]),
- Dict
+ "Duplicate sub_dirs or deps entries?~n",
+ [Dir, Existing])
end
end,
- lists:foldl(Store, dict:new(), Subdirs).
+ lists:foldl(Store, dict:new(), Predirs).
maybe_load_local_config(Dir, ParentConfig) ->
%% We need to ensure we don't overwrite custom
%% config when we are dealing with base_dir.
- case processing_base_dir(Dir) of
+ case rebar_utils:processing_base_dir(ParentConfig, Dir) of
true ->
ParentConfig;
false ->
rebar_config:new(ParentConfig)
end.
-processing_base_dir(Dir) ->
- Dir == rebar_config:get_global(base_dir, undefined).
-
%%
%% Given a list of directories and a set of previously processed directories,
%% process each one we haven't seen yet
%%
-process_each([], _Command, _Config, _ModuleSetFile, DirSet) ->
- DirSet;
-process_each([Dir | Rest], Command, Config, ModuleSetFile, DirSet) ->
+process_each([], _Command, Config, DirSet, _File) ->
+ %% reset cached (setup_env) envs
+ Config1 = rebar_config:reset_envs(Config),
+ {Config1, DirSet};
+process_each([Dir | Rest], Command, Config, DirSet, File) ->
case sets:is_element(Dir, DirSet) of
true ->
?DEBUG("Skipping ~s; already processed!\n", [Dir]),
- process_each(Rest, Command, Config, ModuleSetFile, DirSet);
+ process_each(Rest, Command, Config, DirSet, File);
false ->
- DirSet2 = process_dir(Dir, Config, Command, DirSet),
- process_each(Rest, Command, Config, ModuleSetFile, DirSet2)
+ {Config1, DirSet2} = process_dir(Dir, Command, Config, DirSet),
+ Config2 = rebar_config:clean_config(Config, Config1),
+ %% reset cached (setup_env) envs
+ Config3 = rebar_config:reset_envs(Config2),
+ process_each(Rest, Command, Config3, DirSet2, File)
end.
-
%%
%% Given a list of module sets from rebar.app and a directory, find
%% the appropriate subset of modules for this directory
@@ -329,38 +386,40 @@
execute_plugin_hook(Hook, Command, Modules, Config, ModuleFile, Env) ->
HookFunction = list_to_atom(Hook ++ atom_to_list(Command)),
- execute(HookFunction, Modules, Config, ModuleFile, Env).
+ execute(HookFunction, hook, Modules, Config, ModuleFile, Env).
%%
%% Execute a command across all applicable modules
%%
execute(Command, Modules, Config, ModuleFile, Env) ->
+ execute(Command, not_a_hook, Modules, Config, ModuleFile, Env).
+
+execute(Command, Type, Modules, Config, ModuleFile, Env) ->
case select_modules(Modules, Command, []) of
[] ->
- Cmd = atom_to_list(Command),
- case lists:prefix("pre_", Cmd)
- orelse lists:prefix("post_", Cmd) of
- true ->
+ case Type of
+ hook ->
ok;
- false ->
+ not_a_hook ->
?WARN("'~p' command does not apply to directory ~s\n",
[Command, rebar_utils:get_cwd()])
- end;
+ end,
+ Config;
TargetModules ->
%% Provide some info on where we are
Dir = rebar_utils:get_cwd(),
?CONSOLE("==> ~s (~s)\n", [filename:basename(Dir), Command]),
- increment_operations(),
+ Config1 = increment_operations(Config),
%% Run the available modules
- apply_hooks(pre_hooks, Config, Command, Env),
+ apply_hooks(pre_hooks, Config1, Command, Env),
case catch(run_modules(TargetModules, Command,
- Config, ModuleFile)) of
- ok ->
- apply_hooks(post_hooks, Config, Command, Env),
- ok;
+ Config1, ModuleFile)) of
+ {ok, NewConfig} ->
+ apply_hooks(post_hooks, NewConfig, Command, Env),
+ NewConfig;
{error, failed} ->
?FAIL;
{Module, {error, _} = Other} ->
@@ -375,35 +434,44 @@
%% Increment the count of operations, since some module
%% responds to this command
-increment_operations() ->
- erlang:put(operations, erlang:get(operations) + 1).
+increment_operations(Config) ->
+ Operations = get_operations(Config),
+ rebar_config:set_xconf(Config, operations, Operations + 1).
+get_operations(Config) ->
+ rebar_config:get_xconf(Config, operations).
update_code_path(Config) ->
case rebar_config:get_local(Config, lib_dirs, []) of
[] ->
no_change;
Paths ->
- OldPath = code:get_path(),
LibPaths = expand_lib_dirs(Paths, rebar_utils:get_cwd(), []),
ok = code:add_pathsa(LibPaths),
- {old, OldPath}
+ %% track just the paths we added, so we can remove them without
+ %% removing other paths added by this dep
+ {added, LibPaths}
end.
restore_code_path(no_change) ->
ok;
-restore_code_path({old, Path}) ->
+restore_code_path({added, Paths}) ->
%% Verify that all of the paths still exist -- some dynamically
%% added paths can get blown away during clean.
- true = code:set_path([F || F <- Path, filelib:is_file(F)]),
+ _ = [code:del_path(F) || F <- Paths, erl_prim_loader_is_file(F)],
ok.
+erl_prim_loader_is_file(File) ->
+ erl_prim_loader:read_file_info(File) =/= error.
expand_lib_dirs([], _Root, Acc) ->
Acc;
expand_lib_dirs([Dir | Rest], Root, Acc) ->
Apps = filelib:wildcard(filename:join([Dir, "*", "ebin"])),
- FqApps = [filename:join([Root, A]) || A <- Apps],
+ FqApps = case filename:pathtype(Dir) of
+ absolute -> Apps;
+ _ -> [filename:join([Root, A]) || A <- Apps]
+ end,
expand_lib_dirs(Rest, Root, Acc ++ FqApps).
@@ -419,18 +487,21 @@
select_modules(Rest, Command, Acc)
end.
-run_modules([], _Command, _Config, _File) ->
- ok;
+run_modules([], _Command, Config, _File) ->
+ {ok, Config};
run_modules([Module | Rest], Command, Config, File) ->
case Module:Command(Config, File) of
ok ->
run_modules(Rest, Command, Config, File);
+ {ok, NewConfig} ->
+ run_modules(Rest, Command, NewConfig, File);
{error, _} = Error ->
{Module, Error}
end.
-apply_hooks(Mode, Config, Command, Env) ->
+apply_hooks(Mode, Config, Command, Env0) ->
Hooks = rebar_config:get_local(Config, Mode, []),
+ Env = rebar_utils:patch_env(Config, Env0),
lists:foreach(fun apply_hook/1,
[{Env, Hook} || Hook <- Hooks,
element(1, Hook) =:= Command orelse
@@ -452,7 +523,7 @@
case erlang:function_exported(M, setup_env, 1) of
true ->
Env = M:setup_env(C),
- C1 = rebar_config:set_env(C, M, Env),
+ C1 = rebar_config:save_env(C, M, Env),
{C1, E++Env};
false ->
T
@@ -463,18 +534,25 @@
acc_modules(select_modules(Modules, Command, []),
Command, Config, File, []).
-acc_modules([], _Command, _Config, _File, Acc) ->
- Acc;
+acc_modules([], _Command, Config, _File, Acc) ->
+ {Config, Acc};
acc_modules([Module | Rest], Command, Config, File, Acc) ->
- {ok, Dirs} = Module:Command(Config, File),
- acc_modules(Rest, Command, Config, File, Acc ++ Dirs).
+ {Config1, Dirs1} = case Module:Command(Config, File) of
+ {ok, Dirs} ->
+ {Config, Dirs};
+ {ok, NewConfig, Dirs} ->
+ {NewConfig, Dirs}
+ end,
+ acc_modules(Rest, Command, Config1, File, Acc ++ Dirs1).
%%
%% Return a flat list of rebar plugin modules.
%%
-plugin_modules(Config, SubdirAssoc) ->
+plugin_modules(Config, PredirsAssoc) ->
Modules = lists:flatten(rebar_config:get_all(Config, plugins)),
- plugin_modules(Config, SubdirAssoc, ulist(Modules)).
+ ?DEBUG("Plugins requested while processing ~s: ~p~n",
+ [rebar_utils:get_cwd(), Modules]),
+ plugin_modules(Config, PredirsAssoc, ulist(Modules)).
ulist(L) ->
ulist(L, []).
@@ -489,20 +567,22 @@
ulist(T, [H | Acc])
end.
-plugin_modules(_Config, _SubdirAssoc, []) ->
+plugin_modules(_Config, _PredirsAssoc, []) ->
{ok, []};
-plugin_modules(Config, SubdirAssoc, Modules) ->
+plugin_modules(Config, PredirsAssoc, Modules) ->
FoundModules = [M || M <- Modules, code:which(M) =/= non_existing],
- plugin_modules(Config, SubdirAssoc, FoundModules, Modules -- FoundModules).
+ plugin_modules(Config, PredirsAssoc, FoundModules, Modules -- FoundModules).
-plugin_modules(_Config, _SubdirAssoc, FoundModules, []) ->
+plugin_modules(_Config, _PredirsAssoc, FoundModules, []) ->
{ok, FoundModules};
-plugin_modules(Config, SubdirAssoc, FoundModules, MissingModules) ->
- {Loaded, NotLoaded} = load_plugin_modules(Config, SubdirAssoc, MissingModules),
+plugin_modules(Config, PredirsAssoc, FoundModules, MissingModules) ->
+ {Loaded, NotLoaded} = load_plugin_modules(Config, PredirsAssoc,
+ 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]),
@@ -510,37 +590,51 @@
end,
{ok, AllViablePlugins}.
-load_plugin_modules(Config, SubdirAssoc, Modules) ->
+load_plugin_modules(Config, PredirsAssoc, Modules) ->
Cwd = rebar_utils:get_cwd(),
- PluginDir = case rebar_config:get_local(Config, plugin_dir, undefined) of
- undefined ->
- filename:join(Cwd, "plugins");
- Dir ->
- Dir
- end,
+ PluginDirs = get_all_plugin_dirs(Config, Cwd, PredirsAssoc),
+ ?DEBUG("Plugin dirs for ~s:~n~p~n", [Cwd, PluginDirs]),
%% Find relevant sources in base_dir and plugin_dir
- Erls = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"),
- RE = "^" ++ Erls ++ "\$",
- BaseDir = get_plugin_base_dir(Cwd, SubdirAssoc),
+ RE = string:join([atom_to_list(M)++"\\.erl" || M <- Modules], "|"),
%% If a plugin is found both in base_dir and plugin_dir, the clash
%% will provoke an error and we'll abort.
- Sources = rebar_utils:find_files(PluginDir, RE, false)
- ++ rebar_utils:find_files(BaseDir, RE, false),
+ Sources = [rebar_utils:find_files(PD, RE, false) || PD <- PluginDirs],
%% Compile and load plugins
- Loaded = [load_plugin(Src) || Src <- Sources],
+ Loaded = [load_plugin(Src) || Src <- lists:append(Sources)],
FilterMissing = is_missing_plugin(Loaded),
NotLoaded = [V || V <- Modules, FilterMissing(V)],
{Loaded, NotLoaded}.
-get_plugin_base_dir(Cwd, SubdirAssoc) ->
- case dict:find(Cwd, SubdirAssoc) of
- {ok, BaseDir} ->
- BaseDir;
- error ->
- Cwd
- end.
+get_all_plugin_dirs(Config, Cwd, PredirsAssoc) ->
+ [rebar_utils:get_cwd()]
+ ++ get_plugin_dir(Config, Cwd)
+ ++ get_base_plugin_dirs(Cwd, PredirsAssoc).
+
+get_plugin_dir(Config, Cwd) ->
+ case rebar_config:get_local(Config, plugin_dir, undefined) of
+ undefined ->
+ %% Plugin can be in the project's "plugins" folder
+ [filename:join(Cwd, "plugins")];
+ Dir ->
+ [Dir]
+ end.
+
+%% We also want to include this case:
+%% Plugin can be in "plugins" directory of the plugin base directory.
+%% For example, Cwd depends on Plugin, and deps/Plugin/plugins/Plugin.erl
+%% is the plugin.
+get_base_plugin_dirs(Cwd, PredirsAssoc) ->
+ [filename:join(Dir, "plugins") ||
+ Dir <- get_plugin_base_dirs(Cwd, PredirsAssoc)].
+
+%% @doc PredirsAssoc is a dictionary of plugindir -> 'parent' pairs.
+%% 'parent' in this case depends on plugin; therefore we have to give
+%% all plugins that Cwd ('parent' in this case) depends on.
+get_plugin_base_dirs(Cwd, PredirsAssoc) ->
+ [PluginDir || {PluginDir, Master} <- dict:to_list(PredirsAssoc),
+ Master =:= Cwd].
is_missing_plugin(Loaded) ->
fun(Mod) -> not lists:member(Mod, Loaded) end.
diff -Nru rebar-2.0.0/src/rebar_cover_utils.erl rebar-2.6.0/src/rebar_cover_utils.erl
--- rebar-2.0.0/src/rebar_cover_utils.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/src/rebar_cover_utils.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,287 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
+%% Copyright (c) 2013 Andras Horvath (andras.horvath@erlang-solutions.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(rebar_cover_utils).
+
+%% for internal use only
+-export([init/3,
+ perform_cover/4,
+ close/1,
+ exit/0]).
+
+-include("rebar.hrl").
+
+%% ====================================================================
+%% Internal functions
+%% ====================================================================
+
+perform_cover(Config, BeamFiles, SrcModules, TargetDir) ->
+ perform_cover(rebar_config:get(Config, cover_enabled, false),
+ Config, BeamFiles, SrcModules, TargetDir).
+
+perform_cover(false, _Config, _BeamFiles, _SrcModules, _TargetDir) ->
+ ok;
+perform_cover(true, Config, BeamFiles, SrcModules, TargetDir) ->
+ analyze(Config, BeamFiles, SrcModules, TargetDir).
+
+close(not_enabled) ->
+ ok;
+close(F) ->
+ ok = file:close(F).
+
+exit() ->
+ cover:stop().
+
+init(false, _BeamFiles, _TargetDir) ->
+ {ok, not_enabled};
+init(true, BeamFiles, TargetDir) ->
+ %% Attempt to start the cover server, then set its group leader to
+ %% TargetDir/cover.log, so all cover log messages will go there instead of
+ %% to stdout. If the cover server is already started, we'll kill that
+ %% server and start a new one in order not to inherit a polluted
+ %% cover_server state.
+ {ok, CoverPid} = case whereis(cover_server) of
+ undefined ->
+ cover:start();
+ _ ->
+ cover:stop(),
+ cover:start()
+ end,
+
+ {ok, F} = OkOpen = file:open(
+ filename:join([TargetDir, "cover.log"]),
+ [write]),
+
+ group_leader(F, CoverPid),
+
+ ?INFO("Cover compiling ~s\n", [rebar_utils:get_cwd()]),
+
+ Compiled = [{Beam, cover:compile_beam(Beam)} || Beam <- BeamFiles],
+ case [Module || {_, {ok, Module}} <- Compiled] of
+ [] ->
+ %% No modules compiled successfully...fail
+ ?ERROR("Cover failed to compile any modules; aborting.~n", []),
+ ?FAIL;
+ _ ->
+ %% At least one module compiled successfully
+
+ %% It's not an error for cover compilation to fail partially,
+ %% but we do want to warn about them
+ PrintWarning =
+ fun(Beam, Desc) ->
+ ?CONSOLE("Cover compilation warning for ~p: ~p",
+ [Beam, Desc])
+ end,
+ _ = [PrintWarning(Beam, Desc) || {Beam, {error, Desc}} <- Compiled],
+ OkOpen
+ end;
+init(Config, BeamFiles, TargetDir) ->
+ init(rebar_config:get(Config, cover_enabled, false), BeamFiles, TargetDir).
+
+analyze(_Config, [], _SrcModules, _TargetDir) ->
+ ok;
+analyze(Config, FilteredModules, SrcModules, TargetDir) ->
+ %% Generate coverage info for all the cover-compiled modules
+ Coverage = lists:flatten([analyze_mod(M)
+ || M <- FilteredModules,
+ cover:is_compiled(M) =/= false]),
+
+ %% Write index of coverage info
+ write_index(lists:sort(Coverage), SrcModules, TargetDir),
+
+ %% Write coverage details for each file
+ lists:foreach(
+ fun({M, _, _}) ->
+ {ok, _} = cover:analyze_to_file(M,
+ cover_file(M, TargetDir),
+ [html])
+ end, Coverage),
+
+ Index = filename:join([rebar_utils:get_cwd(), TargetDir, "index.html"]),
+ ?CONSOLE("Cover analysis: ~s\n", [Index]),
+
+ %% Export coverage data, if configured
+ case rebar_config:get(Config, cover_export_enabled, false) of
+ true ->
+ export_coverdata(TargetDir);
+ false ->
+ ok
+ end,
+
+ %% Print coverage report, if configured
+ case rebar_config:get(Config, cover_print_enabled, false) of
+ true ->
+ print_coverage(lists:sort(Coverage));
+ false ->
+ ok
+ end,
+
+ %% Generate JSON Coverage Data, if configured
+ case rebar_config:get(Config, cover_export_json, false) of
+ true ->
+ export_json_coverage(TargetDir, lists:sort(Coverage));
+ false ->
+ ok
+ end.
+
+analyze_mod(Module) ->
+ case cover:analyze(Module, coverage, module) of
+ {ok, {Module, {Covered, NotCovered}}} ->
+ %% Modules that include the eunit header get an implicit
+ %% test/0 fun, which cover considers a runnable line, but
+ %% eunit:test(TestRepresentation) never calls. Decrement
+ %% NotCovered in this case.
+ [align_notcovered_count(Module, Covered, NotCovered,
+ is_eunitized(Module))];
+ {error, Reason} ->
+ ?ERROR("Cover analyze failed for ~p: ~p ~p\n",
+ [Module, Reason, code:which(Module)]),
+ []
+ end.
+
+is_eunitized(Mod) ->
+ has_eunit_test_fun(Mod) andalso
+ has_header(Mod, "include/eunit.hrl").
+
+has_eunit_test_fun(Mod) ->
+ [F || {exports, Funs} <- Mod:module_info(),
+ {F, 0} <- Funs, F =:= test] =/= [].
+
+has_header(Mod, Header) ->
+ Mod1 = case code:which(Mod) of
+ cover_compiled ->
+ {file, File} = cover:is_compiled(Mod),
+ File;
+ non_existing -> Mod;
+ preloaded -> Mod;
+ L -> L
+ end,
+ {ok, {_, [{abstract_code, {_, AC}}]}} =
+ beam_lib:chunks(Mod1, [abstract_code]),
+ [F || {attribute, 1, file, {F, 1}} <- AC,
+ string:str(F, Header) =/= 0] =/= [].
+
+align_notcovered_count(Module, Covered, NotCovered, false) ->
+ {Module, Covered, NotCovered};
+align_notcovered_count(Module, Covered, NotCovered, true) ->
+ {Module, Covered, NotCovered - 1}.
+
+write_index(Coverage, SrcModules, TargetDir) ->
+ {ok, F} = file:open(filename:join([TargetDir, "index.html"]), [write]),
+ ok = file:write(F, "\n"
+ ""
+ "Coverage Summary\n"
+ "\n"),
+ IsSrcCoverage = fun({Mod,_C,_N}) -> lists:member(Mod, SrcModules) end,
+ {SrcCoverage, TestCoverage} = lists:partition(IsSrcCoverage, Coverage),
+ write_index_section(F, "Source", SrcCoverage),
+ write_index_section(F, "Test", TestCoverage),
+ ok = file:write(F, ""),
+ ok = file:close(F).
+
+write_index_section(_F, _SectionName, []) ->
+ ok;
+write_index_section(F, SectionName, Coverage) ->
+ %% Calculate total coverage
+ {Covered, NotCovered} = lists:foldl(fun({_Mod, C, N}, {CAcc, NAcc}) ->
+ {CAcc + C, NAcc + N}
+ end, {0, 0}, Coverage),
+ TotalCoverage = percentage(Covered, NotCovered),
+
+ %% Write the report
+ ok = file:write(F, ?FMT("~s Summary
\n", [SectionName])),
+ ok = file:write(F, ?FMT("Total: ~s
\n", [TotalCoverage])),
+ ok = file:write(F, "Module | Coverage % |
\n"),
+
+ FmtLink =
+ fun(Module, Cov, NotCov) ->
+ ?FMT("~s | ~s | \n",
+ [Module, Module, percentage(Cov, NotCov)])
+ end,
+ lists:foreach(fun({Module, Cov, NotCov}) ->
+ ok = file:write(F, FmtLink(Module, Cov, NotCov))
+ end, Coverage),
+ ok = file:write(F, "
\n").
+
+print_coverage(Coverage) ->
+ {Covered, NotCovered} = lists:foldl(fun({_Mod, C, N}, {CAcc, NAcc}) ->
+ {CAcc + C, NAcc + N}
+ end, {0, 0}, Coverage),
+ TotalCoverage = percentage(Covered, NotCovered),
+
+ %% Determine the longest module name for right-padding
+ Width = lists:foldl(fun({Mod, _, _}, Acc) ->
+ case length(atom_to_list(Mod)) of
+ N when N > Acc ->
+ N;
+ _ ->
+ Acc
+ end
+ end, 0, Coverage) * -1,
+
+ %% Print the output the console
+ ?CONSOLE("~nCode Coverage:~n", []),
+ lists:foreach(fun({Mod, C, N}) ->
+ ?CONSOLE("~*s : ~4s~n",
+ [Width, Mod, percentage(C, N)])
+ end, Coverage),
+ ?CONSOLE("~n~*s : ~s~n", [Width, "Total", TotalCoverage]).
+
+export_json_coverage(TargetDir,Coverage) ->
+ ?CONSOLE("~nCode Coverage export to json~n", []),
+ lists:foreach(fun(ModuleCoverage) ->
+ export_json_coverage_to_file(
+ TargetDir,
+ ModuleCoverage)
+ end, Coverage).
+
+export_json_coverage_to_file(TargetDir, {Module, Covered, NotCovered}) ->
+ {ok, JsonFile} = file:open(json_file(TargetDir, Module), [write]),
+ io:format(JsonFile,
+ "{\"module\":~p,\"covered\":~p,\"not_covered\":~p}",
+ [atom_to_list(Module), Covered, NotCovered]),
+ ok = file:close(JsonFile).
+
+json_file(TargetDir, Module) ->
+ filename:join([TargetDir, atom_to_list(Module) ++ ".COVER.json"]).
+
+cover_file(Module, TargetDir) ->
+ filename:join([TargetDir, atom_to_list(Module) ++ ".COVER.html"]).
+
+export_coverdata(TargetDir) ->
+ ExportFile = filename:join(TargetDir, "cover.coverdata"),
+ case cover:export(ExportFile) of
+ ok ->
+ ?CONSOLE("Coverdata export: ~s~n", [ExportFile]);
+ {error, Reason} ->
+ ?ERROR("Coverdata export failed: ~p~n", [Reason])
+ end.
+
+percentage(0, 0) ->
+ "not executed";
+percentage(Cov, NotCov) ->
+ integer_to_list(trunc((Cov / (Cov + NotCov)) * 100)) ++ "%".
diff -Nru rebar-2.0.0/src/rebar_ct.erl rebar-2.6.0/src/rebar_ct.erl
--- rebar-2.0.0/src/rebar_ct.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_ct.erl 2015-06-19 16:14:28.000000000 +0000
@@ -26,19 +26,22 @@
%% -------------------------------------------------------------------
%%
%% Targets:
-%% test - runs common test suites in ./test
-%% int_test - runs suites in ./int_test
-%% perf_test - runs suites inm ./perf_test
+%% test - run common test suites in ./test
+%% int_test - run suites in ./int_test
+%% perf_test - run suites inm ./perf_test
%%
%% Global options:
%% verbose=1 - show output from the common_test run as it goes
-%% suites="foo,bar" - runs /foo_SUITE and /bar_SUITE
-%% case="mycase" - runs individual test case foo_SUITE:mycase
+%% suites="foo,bar" - run /foo_SUITE and /bar_SUITE
+%% case="mycase" - run individual test case foo_SUITE:mycase
%% -------------------------------------------------------------------
-module(rebar_ct).
-export([ct/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -47,36 +50,86 @@
ct(Config, File) ->
TestDir = rebar_config:get_local(Config, ct_dir, "test"),
- run_test_if_present(TestDir, Config, File).
+ LogDir = rebar_config:get_local(Config, ct_log_dir, "logs"),
+ run_test_if_present(TestDir, LogDir, Config, File).
%% ===================================================================
%% Internal functions
%% ===================================================================
-run_test_if_present(TestDir, Config, File) ->
+
+info(help, ct) ->
+ ?CONSOLE(
+ "Run common_test suites.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ "Valid command line options:~n"
+ " suites=Suite1,Suite2,...,SuiteN~n"
+ " - run Suite1_SUITE, Suite2_SUITE, ..., SuiteN_SUITE~n"
+ " in the test folder.~n"
+ " groups=Group1,Group2,...,GroupN~n"
+ " - run test groups Group1, Group2, ..., GroupN of specified suites.~n"
+ " cases=Case1,Case2,...,CaseM~n"
+ " - run test cases Case1, Case2, ..., CaseN of specified suites.~n"
+ " case=\"mycase\" - run individual test case Suite1_SUITE:mycase.~n"
+ " This option is deprecated and remains for backward compability.~n"
+ " It is recommended to use 'cases' instead.~n",
+ [
+ {ct_dir, "itest"},
+ {ct_log_dir, "test/logs"},
+ {ct_extra_params, "-boot start_sasl -s myapp"},
+ {ct_use_short_names, true}
+ ]).
+
+run_test_if_present(TestDir, LogDir, Config, File) ->
case filelib:is_dir(TestDir) of
false ->
?WARN("~s directory not present - skipping\n", [TestDir]),
ok;
true ->
- run_test(TestDir, Config, File)
+ case filelib:wildcard(TestDir ++ "/*_SUITE.{beam,erl}") of
+ [] ->
+ ?WARN("~s directory present, but no common_test"
+ ++ " SUITES - skipping\n", [TestDir]),
+ ok;
+ _ ->
+ try
+ run_test(TestDir, LogDir, Config, File)
+ catch
+ throw:skip ->
+ ok
+ end
+ end
end.
-run_test(TestDir, Config, _File) ->
- {Cmd, RawLog} = make_cmd(TestDir, Config),
- clear_log(RawLog),
- case rebar_config:is_verbose() of
- false ->
- Output = " >> " ++ RawLog ++ " 2>&1";
- true ->
- Output = " 2>&1 | tee -a " ++ RawLog
- end,
-
- rebar_utils:sh(Cmd ++ Output, [{env,[{"TESTDIR", TestDir}]}]),
- check_log(RawLog).
-
+run_test(TestDir, LogDir, Config, _File) ->
+ {Cmd, RawLog} = make_cmd(TestDir, LogDir, Config),
+ ?DEBUG("ct_run cmd:~n~p~n", [Cmd]),
+ clear_log(LogDir, RawLog),
+ Output = case rebar_log:is_verbose(Config) of
+ false ->
+ " >> " ++ RawLog ++ " 2>&1";
+ true ->
+ " 2>&1 | tee -a " ++ RawLog
+ end,
+
+ ShOpts = [{env,[{"TESTDIR", TestDir}]}, return_on_error],
+ case rebar_utils:sh(Cmd ++ Output, ShOpts) of
+ {ok,_} ->
+ %% in older versions of ct_run, this could have been a failure
+ %% that returned a non-0 code. Check for that!
+ check_success_log(Config, RawLog);
+ {error,Res} ->
+ %% In newer ct_run versions, this may be a sign of a good compile
+ %% that failed cases. In older version, it's a worse error.
+ check_fail_log(Config, RawLog, Cmd ++ Output, Res)
+ end.
-clear_log(RawLog) ->
- case filelib:ensure_dir("logs/index.html") of
+clear_log(LogDir, RawLog) ->
+ case filelib:ensure_dir(filename:join(LogDir, "index.html")) of
ok ->
NowStr = rebar_utils:now_str(),
LogHeader = "--- Test run on " ++ NowStr ++ " ---\n",
@@ -88,31 +141,46 @@
%% calling ct with erl does not return non-zero on failure - have to check
%% log results
-check_log(RawLog) ->
+check_success_log(Config, RawLog) ->
+ check_log(Config, RawLog, fun(Msg) -> ?CONSOLE("DONE.\n~s\n", [Msg]) end).
+
+-type err_handler() :: fun((string()) -> no_return()).
+-spec failure_logger(string(), {integer(), string()}) -> err_handler().
+failure_logger(Command, {Rc, Output}) ->
+ fun(_Msg) ->
+ ?ABORT("~s failed with error: ~w and output:~n~s~n",
+ [Command, Rc, Output])
+ end.
+
+check_fail_log(Config, RawLog, Command, Result) ->
+ check_log(Config, RawLog, failure_logger(Command, Result)).
+
+check_log(Config,RawLog,Fun) ->
{ok, Msg} =
- rebar_utils:sh("grep -e 'TEST COMPLETE' -e '{error,make_failed}' "
+ rebar_utils:sh("grep -e \"TEST COMPLETE\" -e \"{error,make_failed}\" "
++ RawLog, [{use_stdout, false}]),
MakeFailed = string:str(Msg, "{error,make_failed}") =/= 0,
RunFailed = string:str(Msg, ", 0 failed") =:= 0,
if
MakeFailed ->
- show_log(RawLog),
+ show_log(Config, RawLog),
?ERROR("Building tests failed\n",[]),
?FAIL;
RunFailed ->
- show_log(RawLog),
+ show_log(Config, RawLog),
?ERROR("One or more tests failed\n",[]),
?FAIL;
true ->
- ?CONSOLE("DONE.\n~s\n", [Msg])
+ Fun(Msg)
end.
+
%% Show the log if it hasn't already been shown because verbose was on
-show_log(RawLog) ->
+show_log(Config, RawLog) ->
?CONSOLE("Showing log\n", []),
- case rebar_config:is_verbose() of
+ case rebar_log:is_verbose(Config) of
false ->
{ok, Contents} = file:read_file(RawLog),
?CONSOLE("~s", [Contents]);
@@ -120,9 +188,9 @@
ok
end.
-make_cmd(TestDir, Config) ->
+make_cmd(TestDir, RawLogDir, Config) ->
Cwd = rebar_utils:get_cwd(),
- LogDir = filename:join(Cwd, "logs"),
+ LogDir = filename:join(Cwd, RawLogDir),
EbinDir = filename:absname(filename:join(Cwd, "ebin")),
IncludeDir = filename:join(Cwd, "include"),
Include = case filelib:is_dir(IncludeDir) of
@@ -132,6 +200,15 @@
""
end,
+ %% Check for the availability of ct_run; if we can't find it, generate a
+ %% warning and use the old school, less reliable approach to running CT.
+ BaseCmd = case os:find_executable("ct_run") of
+ false ->
+ "erl -noshell -s ct_run script_start -s erlang halt";
+ _ ->
+ "ct_run -noshell"
+ end,
+
%% Add the code path of the rebar process to the code path. This
%% includes the dependencies in the code path. The directories
%% that are part of the root Erlang install are filtered out to
@@ -141,50 +218,63 @@
CodeDirs = [io_lib:format("\"~s\"", [Dir]) ||
Dir <- [EbinDir|NonLibCodeDirs]],
CodePathString = string:join(CodeDirs, " "),
- Cmd = case get_ct_specs(Cwd) of
+ Cmd = case get_ct_specs(Config, Cwd) of
undefined ->
- ?FMT("erl " % should we expand ERL_PATH?
- " -noshell -pa ~s ~s"
- " -name test@~s"
- " -logdir \"~s\""
- " -env TEST_DIR \"~s\""
+ ?FMT("~s"
+ " -pa ~s"
" ~s"
- " -s ct_run script_start -s erlang halt",
- [CodePathString,
+ " ~s"
+ " -logdir \"~s\""
+ " -env TEST_DIR \"~s\"",
+ [BaseCmd,
+ CodePathString,
Include,
- net_adm:localhost(),
+ build_name(Config),
LogDir,
- filename:join(Cwd, TestDir),
- get_extra_params(Config)]) ++
+ filename:join(Cwd, TestDir)]) ++
get_cover_config(Config, Cwd) ++
get_ct_config_file(TestDir) ++
- get_config_file(TestDir) ++
- get_suite(TestDir) ++
- get_case();
+ get_suites(Config, TestDir) ++
+ get_groups(Config) ++
+ get_cases(Config) ++
+ get_extra_params(Config) ++
+ get_config_file(TestDir);
SpecFlags ->
- ?FMT("erl " % should we expand ERL_PATH?
- " -noshell -pa ~s ~s"
- " -name test@~s"
- " -logdir \"~s\""
- " -env TEST_DIR \"~s\""
+ ?FMT("~s"
+ " -pa ~s"
" ~s"
- " -s ct_run script_start -s erlang halt",
- [CodePathString,
+ " ~s"
+ " -logdir \"~s\""
+ " -env TEST_DIR \"~s\"",
+ [BaseCmd,
+ CodePathString,
Include,
- net_adm:localhost(),
+ build_name(Config),
LogDir,
- filename:join(Cwd, TestDir),
- get_extra_params(Config)]) ++
- SpecFlags ++ get_cover_config(Config, Cwd)
+ filename:join(Cwd, TestDir)]) ++
+ SpecFlags ++
+ get_cover_config(Config, Cwd) ++
+ get_extra_params(Config)
end,
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, "").
+ case rebar_config:get_local(Config, ct_extra_params, undefined) of
+ undefined ->
+ "";
+ Defined ->
+ " " ++ Defined
+ end.
-get_ct_specs(Cwd) ->
- case collect_glob(Cwd, ".*\.test\.spec\$") of
+get_ct_specs(Config, Cwd) ->
+ case collect_glob(Config, Cwd, ".*\.test\.spec\$") of
[] -> undefined;
[Spec] ->
" -spec " ++ Spec;
@@ -198,31 +288,46 @@
false ->
"";
true ->
- case collect_glob(Cwd, ".*cover\.spec\$") of
+ case collect_glob(Config, Cwd, ".*cover\.spec\$") of
[] ->
?DEBUG("No cover spec found: ~s~n", [Cwd]),
"";
[Spec] ->
- ?DEBUG("Found cover file ~w~n", [Spec]),
+ ?DEBUG("Found cover file ~s~n", [Spec]),
" -cover " ++ Spec;
Specs ->
?ABORT("Multiple cover specs found: ~p~n", [Specs])
end
end.
-collect_glob(Cwd, Glob) ->
- filelib:fold_files(Cwd, Glob, true, fun collect_files/2, []).
-
-collect_files(F, Acc) ->
- %% Ignore any specs under the deps/ directory. Do this pulling
- %% the dirname off the the F and then splitting it into a list.
- Parts = filename:split(filename:dirname(F)),
- case lists:member("deps", Parts) of
- true ->
- Acc; % There is a directory named "deps" in path
- false ->
- [F | Acc] % No "deps" directory in path
- end.
+collect_glob(Config, Cwd, Glob) ->
+ {true, Deps} = rebar_deps:get_deps_dir(Config),
+ DepsDir = filename:basename(Deps),
+ CwdParts = filename:split(Cwd),
+ filelib:fold_files(
+ Cwd,
+ Glob,
+ true,
+ fun(F, Acc) ->
+ %% Ignore any specs under the deps/ directory. Do this pulling
+ %% the dirname off the F and then splitting it into a list.
+ Parts = filename:split(filename:dirname(F)),
+ Parts2 = remove_common_prefix(Parts, CwdParts),
+ case lists:member(DepsDir, Parts2) of
+ true ->
+ %% There is a directory named "deps" in path
+ Acc;
+ false ->
+ %% No "deps" directory in path
+ [F | Acc]
+ end
+ end,
+ []).
+
+remove_common_prefix([H1|T1], [H1|T2]) ->
+ remove_common_prefix(T1, T2);
+remove_common_prefix(L1, _) ->
+ L1.
get_ct_config_file(TestDir) ->
Config = filename:join(TestDir, "test.config"),
@@ -239,33 +344,80 @@
false ->
" ";
true ->
- " -config " ++ Config
+ " -erl_args -config " ++ Config
end.
-get_suite(TestDir) ->
- case rebar_utils:get_deprecated_global(suite, suites, "soon") of
+get_suites(Config, TestDir) ->
+ case get_suites(Config) of
undefined ->
" -dir " ++ TestDir;
Suites ->
- Suites1 = string:tokens(Suites, ","),
- Suites2 = [find_suite_path(Suite, TestDir) || Suite <- Suites1],
- string:join([" -suite"] ++ Suites2, " ")
+ Suites1 = [find_suite_path(Suite, TestDir) || Suite <- Suites],
+ string:join([" -suite"] ++ Suites1, " ")
+ end.
+
+get_suites(Config) ->
+ case rebar_config:get_global(Config, suites, undefined) of
+ undefined ->
+ %% The option 'suite' is deprecated and remains
+ %% for backward compatibility.
+ %% It is recommended to use 'suites' instead.
+ case get_deprecated_global(Config, suite, suites) of
+ undefined ->
+ undefined;
+ Suite ->
+ [Suite]
+ end;
+ Suites ->
+ string:tokens(Suites, ",")
end.
find_suite_path(Suite, TestDir) ->
Path = filename:join(TestDir, Suite ++ "_SUITE.erl"),
case filelib:is_regular(Path) of
false ->
- ?ERROR("Suite ~s not found\n", [Suite]),
- ?FAIL;
+ ?WARN("Suite ~s not found\n", [Suite]),
+ %% Note - this throw is caught in run_test_if_present/3;
+ %% this solution was easier than refactoring the entire module.
+ throw(skip);
true ->
Path
end.
-get_case() ->
- case rebar_config:get_global('case', undefined) of
+get_groups(Config) ->
+ case rebar_config:get_global(Config, groups, undefined) of
undefined ->
- "";
- Case ->
- " -case " ++ Case
+ %% The option 'group' was added only for consistency
+ %% because there are options 'suite' and 'case'.
+ case get_deprecated_global(Config, group, groups) of
+ undefined ->
+ "";
+ Group ->
+ " -group " ++ Group
+ end;
+ Groups ->
+ Groups1 = string:tokens(Groups, ","),
+ string:join([" -group"] ++ Groups1, " ")
end.
+
+get_cases(Config) ->
+ case rebar_config:get_global(Config, cases, undefined) of
+ undefined ->
+ %% The option 'case' is deprecated and remains
+ %% for backward compatibility.
+ %% It is recommended to use 'cases' instead.
+ case get_deprecated_global(Config, 'case', cases) of
+ undefined ->
+ "";
+ Case ->
+ " -case " ++ Case
+ end;
+ Cases ->
+ Cases1 = string:tokens(Cases, ","),
+ string:join([" -case"] ++ Cases1, " ")
+ end.
+
+get_deprecated_global(Config, OldOpt, NewOpt) ->
+ rebar_utils:get_deprecated_global(
+ Config, OldOpt, NewOpt, undefined, "in the future").
+
diff -Nru rebar-2.0.0/src/rebar_deps.erl rebar-2.6.0/src/rebar_deps.erl
--- rebar-2.0.0/src/rebar_deps.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_deps.erl 2015-06-19 16:14:28.000000000 +0000
@@ -38,11 +38,15 @@
'delete-deps'/2,
'list-deps'/2]).
+%% for internal use only
+-export([info/2]).
+-export([get_deps_dir/1]).
-record(dep, { dir,
app,
vsn_regex,
- source }).
+ source,
+ is_raw }). %% is_raw = true means non-Erlang/OTP dependency
%% ===================================================================
%% Public API
@@ -52,50 +56,87 @@
%% Side effect to set deps_dir globally for all dependencies from
%% top level down. Means the root deps_dir is honoured or the default
%% used globally since it will be set on the first time through here
- set_global_deps_dir(Config, rebar_config:get_global(deps_dir, [])),
+ Config1 = set_shared_deps_dir(Config, get_shared_deps_dir(Config, [])),
%% Get the list of deps for the current working directory and identify those
%% deps that are available/present.
- Deps = rebar_config:get_local(Config, deps, []),
- {AvailableDeps, MissingDeps} = find_deps(find, Deps),
+ Deps = rebar_config:get_local(Config1, deps, []),
+ {Config2, {AvailableDeps, MissingDeps}} = find_deps(Config1, find, Deps),
?DEBUG("Available deps: ~p\n", [AvailableDeps]),
?DEBUG("Missing deps : ~p\n", [MissingDeps]),
%% Add available deps to code path
- update_deps_code_path(AvailableDeps),
+ Config3 = update_deps_code_path(Config2, AvailableDeps),
- %% If skip_deps=true, mark each dep dir as a skip_dir w/ the core so that
- %% the current command doesn't run on the dep dir. However, pre/postprocess
- %% WILL run (and we want it to) for transitivity purposes.
- case rebar_config:get_global(skip_deps, false) of
- "true" ->
- lists:foreach(fun (#dep{dir = Dir}) ->
- rebar_core:skip_dir(Dir)
- end, AvailableDeps);
+ %% Filtering out 'raw' dependencies so that no commands other than
+ %% deps-related can be executed on their directories.
+ NonRawAvailableDeps = [D || D <- AvailableDeps, not D#dep.is_raw],
+
+ case rebar_config:get_xconf(Config, current_command, undefined) of
+ 'update-deps' ->
+ %% Skip ALL of the dep folders, we do this because we don't want
+ %% any other calls to preprocess() for update-deps beyond the
+ %% toplevel directory. They aren't actually harmful, but they slow
+ %% things down unnecessarily.
+ NewConfig = lists:foldl(
+ fun(D, Acc) ->
+ rebar_config:set_skip_dir(Acc, D#dep.dir)
+ end,
+ Config3,
+ collect_deps(rebar_utils:get_cwd(), Config3)),
+ %% Return the empty list, as we don't want anything processed before
+ %% us.
+ {ok, NewConfig, []};
_ ->
- ok
- end,
-
- %% Return all the available dep directories for process
- {ok, [D#dep.dir || D <- AvailableDeps]}.
+ %% If skip_deps=true, mark each dep dir as a skip_dir w/ the core
+ %% so that the current command doesn't run on the dep dir.
+ %% However, pre/postprocess WILL run (and we want it to) for
+ %% transitivity purposes.
+ %%
+ %% Also, if skip_deps=comma,separated,app,list, then only the given
+ %% dependencies are skipped.
+ NewConfig =
+ case rebar_config:get_global(Config3, skip_deps, false) of
+ "true" ->
+ lists:foldl(
+ fun(#dep{dir = Dir}, C) ->
+ rebar_config:set_skip_dir(C, Dir)
+ end, Config3, AvailableDeps);
+ Apps when is_list(Apps) ->
+ SkipApps = [list_to_atom(App) ||
+ App <- string:tokens(Apps, ",")],
+ lists:foldl(
+ fun(#dep{dir = Dir, app = App}, C) ->
+ case lists:member(App, SkipApps) of
+ true -> rebar_config:set_skip_dir(C, Dir);
+ false -> C
+ end
+ end, Config3, AvailableDeps);
+ _ ->
+ Config3
+ end,
+ %% Return all the available dep directories for process
+ {ok, NewConfig, dep_dirs(NonRawAvailableDeps)}
+ end.
-postprocess(_Config, _) ->
- case erlang:get(?MODULE) of
+postprocess(Config, _) ->
+ case rebar_config:get_xconf(Config, ?MODULE, undefined) of
undefined ->
{ok, []};
Dirs ->
- erlang:erase(?MODULE),
- {ok, Dirs}
+ NewConfig = rebar_config:erase_xconf(Config, ?MODULE),
+ {ok, NewConfig, Dirs}
end.
-compile(Config, AppFile) ->
- 'check-deps'(Config, AppFile).
+compile(Config, _) ->
+ {Config1, _AvailDeps} = do_check_deps(Config),
+ {ok, Config1}.
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
-setup_env(_Config) ->
- {true, DepsDir} = get_deps_dir(),
+setup_env(Config) ->
+ {true, DepsDir} = get_deps_dir(Config),
%% include rebar's DepsDir in ERL_LIBS
Separator = case os:type() of
{win32, nt} ->
@@ -111,14 +152,15 @@
end,
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
-'check-deps'(Config, _) ->
+%% common function used by 'check-deps' and 'compile'
+do_check_deps(Config) ->
%% Get the list of immediate (i.e. non-transitive) deps that are missing
Deps = rebar_config:get_local(Config, deps, []),
- case find_deps(find, Deps) of
- {_, []} ->
+ case find_deps(Config, find, Deps) of
+ {Config1, {AvailDeps, []}} ->
%% No missing deps
- ok;
- {_, MissingDeps} ->
+ {Config1, AvailDeps};
+ {_Config1, {_, MissingDeps}} ->
lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) ->
?CONSOLE("Dependency not available: "
"~p-~s (~p)\n", [App, Vsn, Src])
@@ -126,70 +168,154 @@
?FAIL
end.
+'check-deps'(Config, _) ->
+ {Config1, AvailDeps} = do_check_deps(Config),
+ {ok, save_dep_dirs(Config1, AvailDeps)}.
+
'get-deps'(Config, _) ->
%% Determine what deps are available and missing
Deps = rebar_config:get_local(Config, deps, []),
- {_AvailableDeps, MissingDeps} = find_deps(find, Deps),
+ {Config1, {_AvailableDeps, MissingDeps}} = find_deps(Config, find, Deps),
+ MissingDeps1 = [D || D <- MissingDeps, D#dep.source =/= undefined],
%% For each missing dep with a specified source, try to pull it.
- PulledDeps = [use_source(D) || D <- MissingDeps, D#dep.source /= undefined],
+ {Config2, PulledDeps} =
+ lists:foldl(fun(D, {C, PulledDeps0}) ->
+ {C1, D1} = use_source(C, D),
+ {C1, [D1 | PulledDeps0]}
+ end, {Config1, []}, MissingDeps1),
%% Add each pulled dep to our list of dirs for post-processing. This yields
%% the necessary transitivity of the deps
- erlang:put(?MODULE, [D#dep.dir || D <- PulledDeps]),
- ok.
+ {ok, save_dep_dirs(Config2, lists:reverse(PulledDeps))}.
'update-deps'(Config, _) ->
- %% Determine what deps are available and missing
- Deps = rebar_config:get_local(Config, deps, []),
- UpdatedDeps = [update_source(D) || D <- find_deps(read, Deps),
- D#dep.source /= undefined],
+ Config1 = rebar_config:set_xconf(Config, depowner, dict:new()),
+ {Config2, UpdatedDeps} = update_deps_int(Config1, []),
+ DepOwners = rebar_config:get_xconf(Config2, depowner, dict:new()),
+
+ %% check for conflicting deps
+ _ = [?ERROR("Conflicting dependencies for ~p: ~p~n",
+ [K, [{"From: " ++ string:join(dict:fetch(D, DepOwners), ", "),
+ {D#dep.vsn_regex, D#dep.source}} || D <- V]])
+ || {K, V} <- dict:to_list(
+ lists:foldl(
+ fun(Dep, Acc) ->
+ dict:append(Dep#dep.app, Dep, Acc)
+ end, dict:new(), UpdatedDeps)),
+ length(V) > 1],
+
%% Add each updated dep to our list of dirs for post-processing. This yields
%% the necessary transitivity of the deps
- erlang:put(?MODULE, [D#dep.dir || D <- UpdatedDeps]),
- ok.
+ {ok, save_dep_dirs(Config, UpdatedDeps)}.
'delete-deps'(Config, _) ->
%% Delete all the available deps in our deps/ directory, if any
- {true, DepsDir} = get_deps_dir(),
+ {true, DepsDir} = get_deps_dir(Config),
Deps = rebar_config:get_local(Config, deps, []),
- {AvailableDeps, _} = find_deps(find, Deps),
+ {Config1, {AvailableDeps, _}} = find_deps(Config, find, Deps),
_ = [delete_dep(D)
|| D <- AvailableDeps,
lists:prefix(DepsDir, D#dep.dir)],
- ok.
+ {ok, Config1}.
'list-deps'(Config, _) ->
Deps = rebar_config:get_local(Config, deps, []),
- case find_deps(find, Deps) of
- {AvailDeps, []} ->
+ case find_deps(Config, find, Deps) of
+ {Config1, {AvailDeps, []}} ->
lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps),
- ok;
+ {ok, save_dep_dirs(Config1, AvailDeps)};
{_, MissingDeps} ->
?ABORT("Missing dependencies: ~p\n", [MissingDeps])
end.
-
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ info_help("Display to be fetched dependencies");
+info(help, 'check-deps') ->
+ info_help("Display to be fetched dependencies");
+info(help, 'get-deps') ->
+ info_help("Fetch dependencies");
+info(help, 'update-deps') ->
+ info_help("Update fetched dependencies");
+info(help, 'delete-deps') ->
+ info_help("Delete fetched dependencies");
+info(help, 'list-deps') ->
+ info_help("List dependencies").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ "Valid command line options:~n"
+ " deps_dir=\"deps\" (override default or rebar.config deps_dir)~n",
+ [
+ Description,
+ {deps_dir, "deps"},
+ {deps,
+ [app_name,
+ {rebar, "1.0.*"},
+ {rebar, ".*",
+ {git, "git://github.com/rebar/rebar.git"}},
+ {rebar, ".*",
+ {git, "git://github.com/rebar/rebar.git", "Rev"}},
+ {rebar, "1.0.*",
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
+ {rebar, "1.0.0",
+ {git, "git://github.com/rebar/rebar.git", {tag, "1.0.0"}}},
+ {rebar, "",
+ {git, "git://github.com/rebar/rebar.git", {branch, "master"}},
+ [raw]},
+ {app_name, ".*", {hg, "https://www.example.org/url"}},
+ {app_name, ".*", {rsync, "Url"}},
+ {app_name, ".*", {svn, "https://www.example.org/url"}},
+ {app_name, ".*", {svn, "svn://svn.example.org/url"}},
+ {app_name, ".*", {bzr, "https://www.example.org/url", "Rev"}},
+ {app_name, ".*", {fossil, "https://www.example.org/url"}},
+ {app_name, ".*", {fossil, "https://www.example.org/url", "Vsn"}},
+ {app_name, ".*", {p4, "//depot/subdir/app_dir"}}]}
+ ]).
+
%% Added because of trans deps,
%% need all deps in same dir and should be the one set by the root rebar.config
+%% In case one is given globally, it has higher priority
%% Sets a default if root config has no deps_dir set
-set_global_deps_dir(Config, []) ->
- rebar_config:set_global(deps_dir,
- rebar_config:get_local(Config, deps_dir, "deps"));
-set_global_deps_dir(_Config, _DepsDir) ->
- ok.
+set_shared_deps_dir(Config, []) ->
+ LocalDepsDir = rebar_config:get_local(Config, deps_dir, "deps"),
+ GlobalDepsDir = rebar_config:get_global(Config, deps_dir, LocalDepsDir),
+ DepsDir = case os:getenv("REBAR_DEPS_DIR") of
+ false ->
+ GlobalDepsDir;
+ Dir ->
+ Dir
+ end,
+ rebar_config:set_xconf(Config, deps_dir, DepsDir);
+set_shared_deps_dir(Config, _DepsDir) ->
+ Config.
+
+get_shared_deps_dir(Config, Default) ->
+ rebar_config:get_xconf(Config, deps_dir, Default).
+
+get_deps_dir(Config) ->
+ get_deps_dir(Config, "").
+
+get_deps_dir(Config, App) ->
+ BaseDir = rebar_utils:base_dir(Config),
+ DepsDir0 = get_shared_deps_dir(Config, "deps"),
+ DepsDir = filename:dirname(filename:join([BaseDir, DepsDir0, "dummy"])),
+ {true, filename:join([DepsDir, App])}.
-get_deps_dir() ->
- get_deps_dir("").
+dep_dirs(Deps) ->
+ [D#dep.dir || D <- Deps].
-get_deps_dir(App) ->
- BaseDir = rebar_config:get_global(base_dir, []),
- DepsDir = rebar_config:get_global(deps_dir, "deps"),
- {true, filename:join([BaseDir, DepsDir, App])}.
+save_dep_dirs(Config, Deps) ->
+ rebar_config:set_xconf(Config, ?MODULE, dep_dirs(Deps)).
get_lib_dir(App) ->
%% Find App amongst the reachable lib directories
@@ -200,72 +326,84 @@
Path -> {true, Path}
end.
-update_deps_code_path([]) ->
- ok;
-update_deps_code_path([Dep | Rest]) ->
- case is_app_available(Dep#dep.app, Dep#dep.vsn_regex, Dep#dep.dir) of
- {true, _} ->
- Dir = filename:join(Dep#dep.dir, "ebin"),
- ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
- ?DEBUG("Adding ~s to code path~n", [Dir]),
- true = code:add_patha(Dir);
- {false, _} ->
- true
- end,
- update_deps_code_path(Rest).
-
-
-find_deps(find=Mode, Deps) ->
- find_deps(Mode, Deps, {[], []});
-find_deps(read=Mode, Deps) ->
- find_deps(Mode, Deps, []).
-
-find_deps(find, [], {Avail, Missing}) ->
- {lists:reverse(Avail), lists:reverse(Missing)};
-find_deps(read, [], Deps) ->
- lists:reverse(Deps);
-find_deps(Mode, [App | Rest], Acc) when is_atom(App) ->
- find_deps(Mode, [{App, ".*", undefined} | Rest], Acc);
-find_deps(Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
- find_deps(Mode, [{App, VsnRegex, undefined} | Rest], Acc);
-find_deps(Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
+update_deps_code_path(Config, []) ->
+ Config;
+update_deps_code_path(Config, [Dep | Rest]) ->
+ Config2 =
+ case is_app_available(Config, Dep#dep.app,
+ Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
+ {Config1, {true, _}} ->
+ Dir = filename:join(Dep#dep.dir, "ebin"),
+ ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
+ ?DEBUG("Adding ~s to code path~n", [Dir]),
+ true = code:add_patha(Dir),
+ Config1;
+ {Config1, {false, _}} ->
+ Config1
+ end,
+ update_deps_code_path(Config2, Rest).
+
+find_deps(Config, find=Mode, Deps) ->
+ find_deps(Config, Mode, Deps, {[], []});
+find_deps(Config, read=Mode, Deps) ->
+ find_deps(Config, Mode, Deps, []).
+
+find_deps(Config, find, [], {Avail, Missing}) ->
+ {Config, {lists:reverse(Avail), lists:reverse(Missing)}};
+find_deps(Config, read, [], Deps) ->
+ {Config, lists:reverse(Deps)};
+find_deps(Config, Mode, [App | Rest], Acc) when is_atom(App) ->
+ find_deps(Config, Mode, [{App, ".*", undefined} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
+ find_deps(Config, Mode, [{App, VsnRegex, undefined} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
+ find_deps(Config, Mode, [{App, VsnRegex, Source, []} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex, Source, Opts} | Rest], Acc)
+ when is_list(Opts) ->
Dep = #dep { app = App,
vsn_regex = VsnRegex,
- source = Source },
- {Availability, FoundDir} = find_dep(Dep),
- find_deps(Mode, Rest, acc_deps(Mode, Availability, Dep, FoundDir, Acc));
-find_deps(_Mode, [Other | _Rest], _Acc) ->
+ source = Source,
+ %% dependency is considered raw (i.e. non-Erlang/OTP) when
+ %% 'raw' option is present
+ is_raw = proplists:get_value(raw, Opts, false) },
+ {Config1, {Availability, FoundDir}} = find_dep(Config, Dep),
+ find_deps(Config1, Mode, Rest,
+ acc_deps(Mode, Availability, Dep, FoundDir, Acc));
+find_deps(_Config, _Mode, [Other | _Rest], _Acc) ->
?ABORT("Invalid dependency specification ~p in ~s\n",
[Other, rebar_utils:get_cwd()]).
-find_dep(Dep) ->
+find_dep(Config, Dep) ->
%% Find a dep based on its source,
%% e.g. {git, "https://github.com/mochi/mochiweb.git", "HEAD"}
%% Deps with a source must be found (or fetched) locally.
%% Those without a source may be satisfied from lib dir (get_lib_dir).
- find_dep(Dep, Dep#dep.source).
+ find_dep(Config, Dep, Dep#dep.source).
-find_dep(Dep, undefined) ->
+find_dep(Config, Dep, undefined) ->
%% 'source' is undefined. If Dep is not satisfied locally,
%% go ahead and find it amongst the lib_dir's.
- case find_dep_in_dir(Dep, get_deps_dir(Dep#dep.app)) of
- {avail, _Dir} = Avail -> Avail;
- {missing, _} -> find_dep_in_dir(Dep, get_lib_dir(Dep#dep.app))
+ case find_dep_in_dir(Config, Dep, get_deps_dir(Config, Dep#dep.app)) of
+ {_Config1, {avail, _Dir}} = Avail ->
+ Avail;
+ {Config1, {missing, _}} ->
+ find_dep_in_dir(Config1, Dep, get_lib_dir(Dep#dep.app))
end;
-find_dep(Dep, _Source) ->
+find_dep(Config, Dep, _Source) ->
%% _Source is defined. Regardless of what it is, we must find it
%% locally satisfied or fetch it from the original source
%% into the project's deps
- find_dep_in_dir(Dep, get_deps_dir(Dep#dep.app)).
+ find_dep_in_dir(Config, Dep, get_deps_dir(Config, Dep#dep.app)).
-find_dep_in_dir(_Dep, {false, Dir}) ->
- {missing, Dir};
-find_dep_in_dir(Dep, {true, Dir}) ->
+find_dep_in_dir(Config, _Dep, {false, Dir}) ->
+ {Config, {missing, Dir}};
+find_dep_in_dir(Config, Dep, {true, Dir}) ->
App = Dep#dep.app,
VsnRegex = Dep#dep.vsn_regex,
- case is_app_available(App, VsnRegex, Dir) of
- {true, _AppFile} -> {avail, Dir};
- {false, _} -> {missing, Dir}
+ IsRaw = Dep#dep.is_raw,
+ case is_app_available(Config, App, VsnRegex, Dir, IsRaw) of
+ {Config1, {true, _AppFile}} -> {Config1, {avail, Dir}};
+ {Config1, {false, _}} -> {Config1, {missing, Dir}}
end.
acc_deps(find, avail, Dep, AppDir, {Avail, Missing}) ->
@@ -288,57 +426,88 @@
true = source_engine_avail(Source),
ok.
-is_app_available(App, VsnRegex, Path) ->
+%% IsRaw = false means regular Erlang/OTP dependency
+%%
+%% IsRaw = true means non-Erlang/OTP dependency, e.g. the one that does not
+%% have a proper .app file
+is_app_available(Config, App, VsnRegex, Path, _IsRaw = false) ->
?DEBUG("is_app_available, looking for App ~p with Path ~p~n", [App, Path]),
case rebar_app_utils:is_app_dir(Path) of
{true, AppFile} ->
- case rebar_app_utils:app_name(AppFile) of
- App ->
- Vsn = rebar_app_utils:app_vsn(AppFile),
+ case rebar_app_utils:app_name(Config, AppFile) of
+ {Config1, App} ->
+ {Config2, Vsn} = rebar_app_utils:app_vsn(Config1, AppFile),
?INFO("Looking for ~s-~s ; found ~s-~s at ~s\n",
[App, VsnRegex, App, Vsn, Path]),
case re:run(Vsn, VsnRegex, [{capture, none}]) of
match ->
- {true, Path};
+ {Config2, {true, Path}};
nomatch ->
?WARN("~s has version ~p; requested regex was ~s\n",
[AppFile, Vsn, VsnRegex]),
- {false, {version_mismatch,
- {AppFile,
- {expected, VsnRegex}, {has, Vsn}}}}
+ {Config2,
+ {false, {version_mismatch,
+ {AppFile,
+ {expected, VsnRegex}, {has, Vsn}}}}}
end;
- OtherApp ->
+ {Config1, OtherApp} ->
?WARN("~s has application id ~p; expected ~p\n",
[AppFile, OtherApp, App]),
- {false, {name_mismatch,
- {AppFile, {expected, App}, {has, OtherApp}}}}
+ {Config1,
+ {false, {name_mismatch,
+ {AppFile, {expected, App}, {has, OtherApp}}}}}
end;
false ->
- ?WARN("Expected ~s to be an app dir (containing ebin/*.app), "
- "but no .app found.\n", [Path]),
- {false, {missing_app_file, Path}}
+ case filelib:is_dir(Path) of
+ true ->
+ %% Path is a directory, but it's not an app dir.
+ ?WARN("Directory expected to be an app dir, but no "
+ "app file found ~n"
+ "in ebin/ or src/:~n~s~n",
+ [Path]);
+ false ->
+ %% Path is not a directory, so it cannot be an app dir.
+ %% TODO: maybe we can avoid checking non-existing dirs
+ ?DEBUG("Directory expected to be an app dir, "
+ "but it doesn't exist (yet?):~n~s~n", [Path])
+ end,
+ {Config, {false, {missing_app_file, Path}}}
+ end;
+is_app_available(Config, App, _VsnRegex, Path, _IsRaw = true) ->
+ ?DEBUG("is_app_available, looking for Raw Depencency ~p with Path ~p~n",
+ [App, Path]),
+ case filelib:is_dir(Path) of
+ true ->
+ %% TODO: look for version string in /VERSION file? Not clear
+ %% how to detect git/svn/hg/{cmd, ...} settings that can be passed
+ %% to rebar_utils:vcs_vsn/2 to obtain version dynamically
+ {Config, {true, Path}};
+ false ->
+ ?WARN("Expected ~s to be a raw dependency directory, "
+ "but no directory found.\n", [Path]),
+ {Config, {false, {missing_raw_dependency_directory, Path}}}
end.
-use_source(Dep) ->
- use_source(Dep, 3).
+use_source(Config, Dep) ->
+ use_source(Config, Dep, 3).
-use_source(Dep, 0) ->
+use_source(_Config, Dep, 0) ->
?ABORT("Failed to acquire source from ~p after 3 tries.\n",
[Dep#dep.source]);
-use_source(Dep, Count) ->
+use_source(Config, Dep, Count) ->
case filelib:is_dir(Dep#dep.dir) of
true ->
%% Already downloaded -- verify the versioning matches the regex
- case is_app_available(Dep#dep.app,
- Dep#dep.vsn_regex, Dep#dep.dir) of
- {true, _} ->
+ case is_app_available(Config, Dep#dep.app, Dep#dep.vsn_regex,
+ Dep#dep.dir, Dep#dep.is_raw) of
+ {Config1, {true, _}} ->
Dir = filename:join(Dep#dep.dir, "ebin"),
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
%% Available version matches up -- we're good to go;
%% add the app dir to our code path
true = code:add_patha(Dir),
- Dep;
- {false, Reason} ->
+ {Config1, Dep};
+ {_Config1, {false, Reason}} ->
%% The app that was downloaded doesn't match up (or had
%% errors or something). For the time being, abort.
?ABORT("Dependency dir ~s failed application validation "
@@ -347,11 +516,45 @@
false ->
?CONSOLE("Pulling ~p from ~p\n", [Dep#dep.app, Dep#dep.source]),
require_source_engine(Dep#dep.source),
- {true, TargetDir} = get_deps_dir(Dep#dep.app),
+ {true, TargetDir} = get_deps_dir(Config, Dep#dep.app),
download_source(TargetDir, Dep#dep.source),
- use_source(Dep#dep { dir = TargetDir }, Count-1)
+ use_source(Config, Dep#dep { dir = TargetDir }, Count-1)
end.
+-record(p4_settings, {
+ client=undefined,
+ transport="tcp4:perforce:1666",
+ username,
+ password
+ }).
+init_p4_settings(Basename) ->
+ #p4_settings{client =
+ case inet:gethostname() of
+ {ok,HostName} ->
+ HostName ++ "-"
+ ++ os:getenv("USER") ++ "-"
+ ++ Basename
+ ++ "-Rebar-automated-download"
+ end}.
+
+download_source(AppDir, {p4, Url}) ->
+ download_source(AppDir, {p4, Url, "#head"});
+download_source(AppDir, {p4, Url, Rev}) ->
+ download_source(AppDir, {p4, Url, Rev, init_p4_settings(filename:basename(AppDir))});
+download_source(AppDir, {p4, Url, _Rev, Settings}) ->
+ ok = filelib:ensure_dir(AppDir),
+ rebar_utils:sh_send("p4 client -i",
+ ?FMT("Client: ~s~n"
+ ++"Description: generated by Rebar~n"
+ ++"Root: ~s~n"
+ ++"View:~n"
+ ++" ~s/... //~s/...~n",
+ [Settings#p4_settings.client,
+ AppDir,
+ Url,
+ Settings#p4_settings.client]),
+ []),
+ rebar_utils:sh(?FMT("p4 -c ~s sync -f", [Settings#p4_settings.client]), []);
download_source(AppDir, {hg, Url, Rev}) ->
ok = filelib:ensure_dir(AppDir),
rebar_utils:sh(?FMT("hg clone -U ~s ~s", [Url, filename:basename(AppDir)]),
@@ -388,19 +591,29 @@
[{cd, filename:dirname(AppDir)}]);
download_source(AppDir, {rsync, Url}) ->
ok = filelib:ensure_dir(AppDir),
- rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s", [Url, AppDir]), []).
+ rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s", [Url, AppDir]), []);
+download_source(AppDir, {fossil, Url}) ->
+ download_source(AppDir, {fossil, Url, ""});
+download_source(AppDir, {fossil, Url, Version}) ->
+ Repository = filename:join(AppDir, filename:basename(AppDir) ++ ".fossil"),
+ ok = filelib:ensure_dir(Repository),
+ ok = file:set_cwd(AppDir),
+ rebar_utils:sh(?FMT("fossil clone ~s ~s", [Url, Repository]),
+ [{cd, AppDir}]),
+ rebar_utils:sh(?FMT("fossil open ~s ~s --nested", [Repository, Version]),
+ []).
-update_source(Dep) ->
+update_source(Config, Dep) ->
%% It's possible when updating a source, that a given dep does not have a
%% VCS directory, such as when a source archive is built of a project, with
%% all deps already downloaded/included. So, verify that the necessary VCS
%% directory exists before attempting to do the update.
- {true, AppDir} = get_deps_dir(Dep#dep.app),
+ {true, AppDir} = get_deps_dir(Config, Dep#dep.app),
case has_vcs_dir(element(1, Dep#dep.source), AppDir) of
true ->
?CONSOLE("Updating ~p from ~p\n", [Dep#dep.app, Dep#dep.source]),
require_source_engine(Dep#dep.source),
- update_source(AppDir, Dep#dep.source),
+ update_source1(AppDir, Dep#dep.source),
Dep;
false ->
?WARN("Skipping update for ~p: "
@@ -408,32 +621,119 @@
Dep
end.
-update_source(AppDir, {git, Url}) ->
- update_source(AppDir, {git, Url, {branch, "HEAD"}});
-update_source(AppDir, {git, Url, ""}) ->
- update_source(AppDir, {git, Url, {branch, "HEAD"}});
-update_source(AppDir, {git, _Url, {branch, Branch}}) ->
+update_source1(AppDir, Args) when element(1, Args) =:= p4 ->
+ download_source(AppDir, Args);
+update_source1(AppDir, {git, Url}) ->
+ update_source1(AppDir, {git, Url, {branch, "HEAD"}});
+update_source1(AppDir, {git, Url, ""}) ->
+ update_source1(AppDir, {git, Url, {branch, "HEAD"}});
+update_source1(AppDir, {git, _Url, {branch, Branch}}) ->
ShOpts = [{cd, AppDir}],
rebar_utils:sh("git fetch origin", ShOpts),
- rebar_utils:sh(?FMT("git checkout -q origin/~s", [Branch]), ShOpts);
-update_source(AppDir, {git, _Url, {tag, Tag}}) ->
+ rebar_utils:sh(?FMT("git checkout -q ~s", [Branch]), ShOpts),
+ rebar_utils:sh(
+ ?FMT("git pull --ff-only --no-rebase -q origin ~s", [Branch]),ShOpts);
+update_source1(AppDir, {git, _Url, {tag, Tag}}) ->
ShOpts = [{cd, AppDir}],
- rebar_utils:sh("git fetch --tags origin", ShOpts),
+ rebar_utils:sh("git fetch origin", ShOpts),
rebar_utils:sh(?FMT("git checkout -q ~s", [Tag]), ShOpts);
-update_source(AppDir, {git, _Url, Refspec}) ->
+update_source1(AppDir, {git, _Url, Refspec}) ->
ShOpts = [{cd, AppDir}],
rebar_utils:sh("git fetch origin", ShOpts),
rebar_utils:sh(?FMT("git checkout -q ~s", [Refspec]), ShOpts);
-update_source(AppDir, {svn, _Url, Rev}) ->
+update_source1(AppDir, {svn, _Url, Rev}) ->
rebar_utils:sh(?FMT("svn up -r ~s", [Rev]), [{cd, AppDir}]);
-update_source(AppDir, {hg, _Url, Rev}) ->
+update_source1(AppDir, {hg, _Url, Rev}) ->
rebar_utils:sh(?FMT("hg pull -u -r ~s", [Rev]), [{cd, AppDir}]);
-update_source(AppDir, {bzr, _Url, Rev}) ->
+update_source1(AppDir, {bzr, _Url, Rev}) ->
rebar_utils:sh(?FMT("bzr update -r ~s", [Rev]), [{cd, AppDir}]);
-update_source(AppDir, {rsync, Url}) ->
- rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s",[Url,AppDir]),[]).
-
-
+update_source1(AppDir, {rsync, Url}) ->
+ rebar_utils:sh(?FMT("rsync -az --delete ~s/ ~s",[Url,AppDir]),[]);
+update_source1(AppDir, {fossil, Url}) ->
+ update_source1(AppDir, {fossil, Url, ""});
+update_source1(AppDir, {fossil, _Url, Version}) ->
+ ok = file:set_cwd(AppDir),
+ rebar_utils:sh("fossil pull", [{cd, AppDir}]),
+ rebar_utils:sh(?FMT("fossil update ~s", [Version]), []).
+
+%% Recursively update deps, this is not done via rebar's usual dep traversal as
+%% that is the wrong order (tips are updated before branches). Instead we do a
+%% traverse the deps at each level completely before traversing *their* deps.
+%% This allows updates to actually propogate down the tree, rather than fail to
+%% flow up the tree, which was the previous behaviour.
+update_deps_int(Config0, UDD) ->
+ %% Determine what deps are required
+ ConfDir = filename:basename(rebar_utils:get_cwd()),
+ RawDeps = rebar_config:get_local(Config0, deps, []),
+ {Config1, Deps} = find_deps(Config0, read, RawDeps),
+
+ %% Update each dep
+ UpdatedDeps = [update_source(Config1, D)
+ || D <- Deps, D#dep.source =/= undefined,
+ not lists:member(D, UDD),
+ not should_skip_update_dep(Config1, D)
+ ],
+
+ lists:foldl(fun(Dep, {Config, Updated}) ->
+ {true, AppDir} = get_deps_dir(Config, Dep#dep.app),
+ Config2 = case has_vcs_dir(element(1, Dep#dep.source),
+ AppDir) of
+ false ->
+ %% If the dep did not exist (maybe it
+ %% was added), clone it.
+ %% We'll traverse ITS deps below and
+ %% clone them if needed.
+ {C1, _D1} = use_source(Config, Dep),
+ C1;
+ true ->
+ Config
+ end,
+ ok = file:set_cwd(AppDir),
+ Config3 = rebar_config:new(Config2),
+ %% track where a dep comes from...
+ DepOwner = dict:append(
+ Dep, ConfDir,
+ rebar_config:get_xconf(Config3, depowner,
+ dict:new())),
+ Config4 = rebar_config:set_xconf(Config3, depowner,
+ DepOwner),
+
+ {Config5, Res} = update_deps_int(Config4, Updated),
+ {Config5, lists:umerge(lists:sort(Res),
+ lists:sort(Updated))}
+ end, {Config1, lists:umerge(lists:sort(UpdatedDeps),
+ lists:sort(UDD))}, UpdatedDeps).
+
+should_skip_update_dep(Config, Dep) ->
+ {true, AppDir} = get_deps_dir(Config, Dep#dep.app),
+ case rebar_app_utils:is_app_dir(AppDir) of
+ false ->
+ false;
+ {true, AppFile} ->
+ case rebar_app_utils:is_skipped_app(Config, AppFile) of
+ {_Config, {true, _SkippedApp}} ->
+ true;
+ _ ->
+ false
+ end
+ end.
+
+%% Recursively walk the deps and build a list of them.
+collect_deps(Dir, C) ->
+ case file:set_cwd(Dir) of
+ ok ->
+ Config = rebar_config:new(C),
+ RawDeps = rebar_config:get_local(Config, deps, []),
+ {Config1, Deps} = find_deps(Config, read, RawDeps),
+
+ lists:flatten(Deps ++ [begin
+ {true, AppDir} = get_deps_dir(
+ Config1, Dep#dep.app),
+ collect_deps(AppDir, C)
+ end || Dep <- Deps]);
+ _ ->
+ []
+ end.
%% ===================================================================
@@ -445,7 +745,8 @@
source_engine_avail(Name, Source).
source_engine_avail(Name, Source)
- when Name == hg; Name == git; Name == svn; Name == bzr; Name == rsync ->
+ when Name == hg; Name == git; Name == svn; Name == bzr; Name == rsync;
+ Name == fossil; Name == p4 ->
case vcs_client_vsn(Name) >= required_vcs_client_vsn(Name) of
true ->
true;
@@ -466,12 +767,17 @@
false
end.
-required_vcs_client_vsn(hg) -> {1, 1};
-required_vcs_client_vsn(git) -> {1, 5};
-required_vcs_client_vsn(bzr) -> {2, 0};
-required_vcs_client_vsn(svn) -> {1, 6};
-required_vcs_client_vsn(rsync) -> {2, 0}.
-
+required_vcs_client_vsn(p4) -> {2013, 1};
+required_vcs_client_vsn(hg) -> {1, 1};
+required_vcs_client_vsn(git) -> {1, 5};
+required_vcs_client_vsn(bzr) -> {2, 0};
+required_vcs_client_vsn(svn) -> {1, 6};
+required_vcs_client_vsn(rsync) -> {2, 0};
+required_vcs_client_vsn(fossil) -> {1, 0}.
+
+vcs_client_vsn(p4) ->
+ vcs_client_vsn(rebar_utils:find_executable("p4"), " -V",
+ "Rev\\. .*/(\\d+)\\.(\\d)/");
vcs_client_vsn(hg) ->
vcs_client_vsn(rebar_utils:find_executable("hg"), " --version",
"version (\\d+).(\\d+)");
@@ -486,8 +792,13 @@
"svn, version (\\d+).(\\d+)");
vcs_client_vsn(rsync) ->
vcs_client_vsn(rebar_utils:find_executable("rsync"), " --version",
- "rsync version (\\d+).(\\d+)").
+ "rsync version (\\d+).(\\d+)");
+vcs_client_vsn(fossil) ->
+ vcs_client_vsn(rebar_utils:find_executable("fossil"), " version",
+ "version (\\d+).(\\d+)").
+has_vcs_dir(p4, _) ->
+ true;
has_vcs_dir(git, Dir) ->
filelib:is_dir(filename:join(Dir, ".git"));
has_vcs_dir(hg, Dir) ->
@@ -505,6 +816,8 @@
print_source(#dep{app=App, source=Source}) ->
?CONSOLE("~s~n", [format_source(App, Source)]).
+format_source(App, {p4, Url}) ->
+ format_source(App, {p4, Url, "#head"});
format_source(App, {git, Url}) ->
?FMT("~p BRANCH ~s ~s", [App, "HEAD", Url]);
format_source(App, {git, Url, ""}) ->
@@ -515,5 +828,7 @@
?FMT("~p TAG ~s ~s", [App, Tag, Url]);
format_source(App, {_, Url, Rev}) ->
?FMT("~p REV ~s ~s", [App, Rev, Url]);
+format_source(App, {SrcType, Url}) ->
+ ?FMT("~p ~p ~s", [App, SrcType, Url]);
format_source(App, undefined) ->
?FMT("~p", [App]).
diff -Nru rebar-2.0.0/src/rebar_dia_compiler.erl rebar-2.6.0/src/rebar_dia_compiler.erl
--- rebar-2.0.0/src/rebar_dia_compiler.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/src/rebar_dia_compiler.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,138 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2009, 2010 Dave Smith (dizzyd@dizzyd.com)
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(rebar_dia_compiler).
+
+-export([compile/2,
+ clean/2]).
+
+%% for internal use only
+-export([info/2]).
+
+-include("rebar.hrl").
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+
+-spec compile(rebar_config:config(), file:filename()) -> 'ok'.
+compile(Config, _AppFile) ->
+ DiaOpts = rebar_config:get(Config, dia_opts, []),
+ IncludeEbin = proplists:get_value(include, DiaOpts, []),
+ DiaFiles = filelib:wildcard("dia/*.dia"),
+ code:add_pathsz(["ebin" | IncludeEbin]),
+ FileSequence = case rebar_config:get(Config, dia_first_files, []) of
+ [] ->
+ DiaFiles;
+ CompileFirst ->
+ CompileFirst ++
+ [F || F <- DiaFiles, not lists:member(F, CompileFirst)]
+ end,
+ rebar_base_compiler:run(Config, FileSequence,
+ "dia", ".dia", "src", ".erl",
+ fun compile_dia/3).
+
+-spec clean(rebar_config:config(), file:filename()) -> 'ok'.
+clean(Config, _AppFile) ->
+ DiaOpts = rebar_config:get(Config, dia_opts, []),
+ IncludeEbin = proplists:get_value(include, DiaOpts, []),
+ code:add_pathsz(["ebin" | IncludeEbin]),
+ GeneratedFiles = dia_generated_files("dia", "src", "include"),
+ ok = rebar_file_utils:delete_each(GeneratedFiles),
+ ok.
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, compile) ->
+ info_help("Build Diameter (*.dia) sources");
+info(help, clean) ->
+ info_help("Delete generated Diameter files").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {dia_opts, []} (options from diameter_make:codec/2 supported with~n"
+ " exception of inherits)~n"
+ " {dia_first_files, []} (files in sequence to compile first)~n",
+ [Description]).
+
+-spec compile_dia(file:filename(), file:filename(),
+ rebar_config:config()) -> ok.
+compile_dia(Source, Target, Config) ->
+ ok = filelib:ensure_dir(Target),
+ ok = filelib:ensure_dir(filename:join("include", "dummy.hrl")),
+ Opts = [{outdir, "src"}] ++ rebar_config:get(Config, dia_opts, []),
+ case diameter_dict_util:parse({path, Source}, []) of
+ {ok, Spec} ->
+ FileName = dia_filename(Source, Spec),
+ _ = diameter_codegen:from_dict(FileName, Spec, Opts, erl),
+ _ = diameter_codegen:from_dict(FileName, Spec, Opts, hrl),
+ HrlFile = filename:join("src", FileName ++ ".hrl"),
+ ErlFile = filename:join("src", FileName ++ ".erl"),
+ ErlCOpts = [{outdir, "ebin"}] ++
+ rebar_config:get(Config, erl_opts, []),
+ _ = compile:file(ErlFile, ErlCOpts),
+ case filelib:is_regular(HrlFile) of
+ true ->
+ ok = rebar_file_utils:mv(HrlFile, "include");
+ false ->
+ ok
+ end;
+ {error, Reason} ->
+ ?ABORT(
+ "Compiling ~s failed: ~s~n",
+ [Source, diameter_dict_util:format_error(Reason)]
+ )
+ end.
+
+dia_generated_files(DiaDir, SrcDir, IncDir) ->
+ F = fun(File, Acc) ->
+ case catch diameter_dict_util:parse({path, File}, []) of
+ {ok, Spec} ->
+ FileName = dia_filename(File, Spec),
+ [
+ filename:join([IncDir, FileName ++ ".hrl"]) |
+ filelib:wildcard(
+ filename:join([SrcDir, FileName ++ ".*"])
+ )
+ ] ++ Acc;
+ _ ->
+ Acc
+ end
+ end,
+ lists:foldl(F, [], filelib:wildcard(filename:join([DiaDir, "*.dia"]))).
+
+dia_filename(File, Spec) ->
+ case proplists:get_value(name, Spec) of
+ undefined ->
+ filename:rootname(filename:basename(File));
+ Name ->
+ Name
+ end.
diff -Nru rebar-2.0.0/src/rebar_dialyzer.erl rebar-2.6.0/src/rebar_dialyzer.erl
--- rebar-2.0.0/src/rebar_dialyzer.erl 1970-01-01 00:00:00.000000000 +0000
+++ rebar-2.6.0/src/rebar_dialyzer.erl 2015-06-19 16:14:28.000000000 +0000
@@ -0,0 +1,246 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2014-2015 Tuncer Ayaz
+%%
+%% Permission is hereby granted, free of charge, to any person obtaining a copy
+%% of this software and associated documentation files (the "Software"), to deal
+%% in the Software without restriction, including without limitation the rights
+%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+%% copies of the Software, and to permit persons to whom the Software is
+%% furnished to do so, subject to the following conditions:
+%%
+%% The above copyright notice and this permission notice shall be included in
+%% all copies or substantial portions of the Software.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+%% THE SOFTWARE.
+%% -------------------------------------------------------------------
+-module(rebar_dialyzer).
+
+-export([
+ dialyze/2,
+ 'build-plt'/2,
+ 'check-plt'/2,
+ 'delete-plt'/2
+ ]).
+
+%% for internal use only
+-export([info/2]).
+
+-include("rebar.hrl").
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+
+dialyze(Config, AppFile) ->
+ Opts = opts(Config),
+ {NewConfig, Plt} = plt(Config, AppFile, Opts),
+ ok = check_plt_existence(Plt),
+
+ Args = [
+ {analysis_type, succ_typings},
+ %% http://erlang.org/pipermail/erlang-bugs/2015-February/004781.html
+ %% TODO: remove once the minimum required Erlang/OTP release
+ %% includes a Dialyzer version without the bug, or alternatively
+ %% add a config option to always check the PLT, as this may be
+ %% needed by some users.
+ {check_plt, false},
+ {init_plt, Plt},
+ {files_rec, ["ebin"]},
+ {warnings, warnings(Opts)}
+ ],
+ ?DEBUG("dialyze opts:~n~p~n", [Args]),
+ case run(Args) of
+ [] ->
+ {ok, NewConfig};
+ Ws ->
+ print_warnings(Ws, fullpath),
+ ?FAIL
+ end.
+
+'build-plt'(Config, AppFile) ->
+ Opts = opts(Config),
+ {Config1, AppDirs} = app_dirs(Config, AppFile, Opts),
+ {NewConfig, Plt} = plt(Config1, AppFile, Opts),
+
+ Args = [
+ {analysis_type, plt_build},
+ {output_plt, Plt},
+ {files_rec, AppDirs}
+ ],
+ ?DEBUG("build-plt opts:~n~p~n", [Args]),
+ case run(Args) of
+ [] ->
+ {ok, NewConfig};
+ Ws ->
+ %% As plt_build may raise warnings but still successfully
+ %% create the PLT, we cannot interpret this as failure,
+ %% and therefore all we can do is report warnings.
+ print_warnings(Ws, basename)
+ end.
+
+'check-plt'(Config, AppFile) ->
+ Opts = opts(Config),
+ {NewConfig, Plt} = plt(Config, AppFile, Opts),
+ ok = check_plt_existence(Plt),
+
+ Args = [
+ {analysis_type, plt_check},
+ %% http://erlang.org/pipermail/erlang-bugs/2015-February/004781.html
+ %% Without this, the PLT will be checked twice.
+ %% TODO: remove once the minimum required Erlang/OTP release
+ %% includes a Dialyzer version without the bug.
+ {check_plt, false},
+ {init_plt, Plt}
+ ],
+ ?DEBUG("build-plt opts:~n~p~n", [Args]),
+ case run(Args) of
+ [] ->
+ {ok, NewConfig};
+ Ws ->
+ print_warnings(Ws, basename),
+ ?FAIL
+ end.
+
+'delete-plt'(Config, AppFile) ->
+ Opts = opts(Config),
+ {NewConfig, Plt} = plt(Config, AppFile, Opts),
+ ?DEBUG("Delete PLT '~s'~n", [Plt]),
+ ok = rebar_file_utils:delete_each([Plt]),
+ {ok, NewConfig}.
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+info(help, dialyze) ->
+ info_help("Analyze the code for discrepancies");
+info(help, 'build-plt') ->
+ info_help("Build project-specific PLT");
+info(help, 'check-plt') ->
+ info_help("Check the PLT for consistency and rebuild it if it"
+ " is not up-to-date");
+info(help, 'delete-plt') ->
+ info_help("Delete project-specific PLT").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ Description,
+ {dialyzer,
+ [
+ {plt_location, local},
+ {plt_location, "custom_dir"},
+ {plt_extra_apps, [app1, app2]},
+ {warnings, [unmatched_returns, error_handling]}
+ ]}
+ ]).
+
+opts(Config) ->
+ rebar_config:get_local(Config, dialyzer, []).
+
+plt(Config, AppFile, Opts) ->
+ PltDir = plt_dir(Config, Opts),
+ {NewConfig, RawAppName} = rebar_app_utils:app_name(Config, AppFile),
+ AppName = atom_to_list(RawAppName),
+ OtpRel = rebar_utils:otp_release(),
+ Plt = filename:join([PltDir, AppName ++ "_" ++ OtpRel ++ "_plt"]),
+ ok = filelib:ensure_dir(Plt),
+ {NewConfig, Plt}.
+
+plt_dir(Config, Opts) ->
+ Location = proplists:get_value(plt_location, Opts, local),
+ plt_dir1(Config, Location).
+
+plt_dir1(_Config, Location) when is_list(Location) ->
+ case filelib:is_dir(Location) of
+ false ->
+ ?ABORT("PLT directory does not exist: ~s~n", [Location]);
+ true ->
+ Location
+ end;
+plt_dir1(Config, local) ->
+ BaseDir = rebar_utils:base_dir(Config),
+ filename:join([BaseDir, ".rebar"]).
+
+check_plt_existence(Plt) ->
+ case filelib:is_regular(Plt) of
+ true ->
+ ok;
+ false ->
+ ?ABORT("PLT '~s' does not exist.~n"
+ "Please run 'rebar build-plt' first.~n", [Plt])
+ end.
+
+%% dialyzer:run/1 wrapper to gracefully fail in case of Dialyzer errors
+run(Opts) ->
+ try dialyzer:run(Opts) of
+ Ws -> Ws
+ catch
+ throw:{dialyzer_error, Reason} ->
+ ?ABORT("Dialyzer error:~n~s~n", [Reason])
+ end.
+
+warnings(Opts) ->
+ proplists:get_value(warnings, Opts, []).
+
+print_warnings(Ws, Option) ->
+ lists:foreach(
+ fun(W) ->
+ ?CONSOLE("~s~n", [format_warning(W, Option)])
+ end,
+ Ws).
+
+format_warning(W, Option) ->
+ case dialyzer:format_warning(W, Option) of
+ ":0: " ++ Unknown ->
+ strip_newline(Unknown);
+ Warning ->
+ strip_newline(Warning)
+ end.
+
+%% Warning may or may not have trailing \n.
+strip_newline(Warning) ->
+ string:strip(Warning, right, $\n).
+
+app_dirs(Config, AppFile, Opts) ->
+ {NewConfig, AppFileApps} = app_file_apps(Config, AppFile),
+ ?DEBUG("app file apps:~n~p~n", [AppFileApps]),
+ Deps = deps_apps(Config),
+ ?DEBUG("deps apps:~n~p~n", [Deps]),
+ ExtraApps = proplists:get_value(plt_extra_apps, Opts, []),
+ ?DEBUG("extra apps:~n~p~n", [ExtraApps]),
+ %% erts is assumed, and has to be present unconditionally.
+ Erts = [erts],
+ Apps = ordsets:from_list(Erts ++ AppFileApps ++ Deps ++ ExtraApps),
+ AppDirs = [app_lib_dir(App) || App <- ordsets:to_list(Apps)],
+ ?DEBUG("app dirs:~n~p~n", [AppDirs]),
+ {NewConfig, AppDirs}.
+
+app_file_apps(Config, AppFile) ->
+ rebar_app_utils:app_applications(Config, AppFile).
+
+deps_apps(Config) ->
+ [element(1, Dep) || Dep <- rebar_config:get_local(Config, deps, [])].
+
+app_lib_dir(App) ->
+ case code:lib_dir(App, ebin) of
+ {error, _}=Err ->
+ ?ABORT("Failed to get ebin dir for app: ~p~n~p~n", [App, Err]);
+ Dir ->
+ Dir
+ end.
diff -Nru rebar-2.0.0/src/rebar_edoc.erl rebar-2.6.0/src/rebar_edoc.erl
--- rebar-2.0.0/src/rebar_edoc.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_edoc.erl 2015-06-19 16:14:28.000000000 +0000
@@ -39,35 +39,92 @@
-export([doc/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
%% Public API
%% ===================================================================
-%% @doc Generate Erlang program documentation.
--spec doc(Config::rebar_config:config(), File::file:filename()) -> ok.
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, Config1, AppName, _AppData} =
+ rebar_app_utils:load_app_file(Config, File),
+
+ case needs_regen(EDocOpts) of
+ true ->
+ ?INFO("Regenerating edocs for ~p\n", [AppName]),
+ ok = edoc:application(AppName, ".", EDocOpts);
+ false ->
+ ?INFO("Skipping regeneration of edocs for ~p\n", [AppName]),
+ ok
+ end,
+
%% Restore code path
- true = code:set_path(CodePath),
- ok.
+ true = rebar_utils:cleanup_code_path(CodePath),
+ {ok, Config1}.
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, doc) ->
+ ?CONSOLE(
+ "Generate Erlang program documentation.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " {edoc_opts, []} (see edoc:application/3 documentation)~n",
+ []).
+
setup_code_path() ->
%% Setup code path prior to calling edoc so that edown, asciiedoc,
%% and the like can work properly when generating their own
%% documentation.
CodePath = code:get_path(),
- true = code:add_patha(ebin_dir()),
+ _ = code:add_patha(rebar_utils:ebin_dir()),
CodePath.
-ebin_dir() ->
- filename:join(rebar_utils:get_cwd(), "ebin").
+-type path_spec() :: {'file', file:filename()} | file:filename().
+-spec newer_file_exists(Paths::[path_spec()], OldFile::string()) -> boolean().
+newer_file_exists(Paths, OldFile) ->
+ OldModTime = filelib:last_modified(OldFile),
+
+ ThrowIfNewer = fun(Fn, _Acc) ->
+ FModTime = filelib:last_modified(Fn),
+ (FModTime > OldModTime) andalso
+ throw({newer_file_exists, {Fn, FModTime}})
+ end,
+
+ try
+ lists:foldl(fun({file, F}, _) ->
+ ThrowIfNewer(F, false);
+ (P, _) ->
+ filelib:fold_files(P, ".*.erl", true,
+ ThrowIfNewer, false)
+ end, undefined, Paths)
+ catch
+ throw:{newer_file_exists, {Filename, FMod}} ->
+ ?DEBUG("~p is more recent than ~p: "
+ "~120p > ~120p\n",
+ [Filename, OldFile, FMod, OldModTime]),
+ true
+ end.
+
+%% Needs regen if any dependent file is changed since the last
+%% edoc run. Dependent files are the erlang source files,
+%% and the overview file, if it exists.
+-spec needs_regen(proplists:proplist()) -> boolean().
+needs_regen(EDocOpts) ->
+ DocDir = proplists:get_value(dir, EDocOpts, "doc"),
+ EDocInfoName = filename:join(DocDir, "edoc-info"),
+ OverviewFile = proplists:get_value(overview, EDocOpts, "overview.edoc"),
+ EDocOverviewName = filename:join(DocDir, OverviewFile),
+ SrcPaths = proplists:get_value(source_path, EDocOpts, ["src"]),
+
+ newer_file_exists([{file, EDocOverviewName} | SrcPaths], EDocInfoName).
diff -Nru rebar-2.0.0/src/rebar.erl rebar-2.6.0/src/rebar.erl
--- rebar-2.0.0/src/rebar.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar.erl 2015-06-19 16:14:28.000000000 +0000
@@ -27,9 +27,11 @@
-module(rebar).
-export([main/1,
+ run/2,
help/0,
parse_args/1,
- version/0]).
+ version/0,
+ get_jobs/1]).
-include("rebar.hrl").
@@ -45,79 +47,74 @@
-define(OTP_INFO, "undefined").
-endif.
+-define(DEFAULT_JOBS, 3).
+
%% ====================================================================
%% Public API
%% ====================================================================
+%% escript Entry point
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.
+%% Erlang-API entry point
+run(BaseConfig, Commands) ->
+ _ = application:load(rebar),
+ run_aux(BaseConfig, Commands).
+
%% ====================================================================
%% Internal functions
%% ====================================================================
+run(["help"|RawCmds]) when RawCmds =/= [] ->
+ ok = load_rebar_app(),
+ Cmds = unabbreviate_command_names(RawCmds),
+ Args = parse_args(Cmds),
+ BaseConfig = init_config(Args),
+ {BaseConfig1, _} = save_options(BaseConfig, Args),
+ BaseConfig2 = init_config1(BaseConfig1),
+ rebar_core:help(BaseConfig2, [list_to_atom(C) || C <- Cmds]);
+run(["help"]) ->
+ help();
+run(["info"|_]) ->
+ %% Catch calls to 'rebar info' to avoid treating plugins' info/2 functions
+ %% as commands.
+ ?CONSOLE("Command 'info' not understood or not applicable~n", []);
+run(["version"]) ->
+ ok = load_rebar_app(),
+ %% Display vsn and build time info
+ version();
run(RawArgs) ->
- %% Pre-load the rebar app so that we get default configuration
- ok = application:load(rebar),
+ ok = load_rebar_app(),
%% Parse out command line arguments -- what's left is a list of commands to
%% run -- and start running commands
Args = parse_args(RawArgs),
+ BaseConfig = init_config(Args),
+ {BaseConfig1, Cmds} = save_options(BaseConfig, Args),
- case rebar_config:get_global(enable_profiling, false) of
+ case rebar_config:get_xconf(BaseConfig1, enable_profiling, false) of
true ->
- io:format("Profiling!\n"),
- try
- fprof:apply(fun(A) -> run_aux(A) end, [Args])
- after
- fprof:profile(),
- fprof:analyse([{dest, "fprof.analysis"}])
- end;
- _ ->
- run_aux(Args)
+ ?CONSOLE("Profiling!\n", []),
+ profile(BaseConfig1, Cmds);
+ false ->
+ run_aux(BaseConfig1, Cmds)
end.
-run_aux(["help"]) ->
- help(),
- ok;
-run_aux(["version"]) ->
- %% Display vsn and build time info
- version(),
- ok;
-run_aux(Commands) ->
- %% Make sure crypto is running
- ok = crypto:start(),
-
- %% Initialize logging system
- rebar_log:init(),
-
- %% Initialize vsn cache
- _VsnCacheTab = ets:new(rebar_vsn_cache,[named_table, public]),
-
- %% Convert command strings to atoms
- CommandAtoms = [list_to_atom(C) || C <- Commands],
-
- %% Determine the location of the rebar executable; important for pulling
- %% resources out of the escript
- rebar_config:set_global(escript, filename:absname(escript:script_name())),
- ?DEBUG("Rebar location: ~p\n",
- [rebar_config:get_global(escript, undefined)]),
-
- %% Note the top-level directory for reference
- rebar_config:set_global(base_dir, filename:absname(rebar_utils:get_cwd())),
-
- %% Keep track of how many operations we do, so we can detect bad commands
- erlang:put(operations, 0),
+load_rebar_app() ->
+ %% Pre-load the rebar app so that we get default configuration
+ ok = application:load(rebar).
+init_config({Options, _NonOptArgs}) ->
%% If $HOME/.rebar/config exists load and use as global config
GlobalConfigFile = filename:join([os:getenv("HOME"), ".rebar", "config"]),
GlobalConfig = case filelib:is_regular(GlobalConfigFile) of
@@ -128,78 +125,242 @@
false ->
rebar_config:new()
end,
- BaseConfig = rebar_config:base_config(GlobalConfig),
+
+ %% Set the rebar config to use
+ GlobalConfig1 = case proplists:get_value(config, Options) of
+ undefined ->
+ GlobalConfig;
+ Conf ->
+ rebar_config:set_global(GlobalConfig, config, Conf)
+ end,
+
+ GlobalConfig2 = set_log_level(GlobalConfig1, Options),
+ %% Initialize logging system
+ ok = rebar_log:init(GlobalConfig2),
+
+ BaseConfig = rebar_config:base_config(GlobalConfig2),
+
+ %% Keep track of how many operations we do, so we can detect bad commands
+ BaseConfig1 = rebar_config:set_xconf(BaseConfig, operations, 0),
+ %% Initialize vsn cache
+ rebar_config:set_xconf(BaseConfig1, vsn_cache, dict:new()).
+
+init_config1(BaseConfig) ->
+ %% Determine the location of the rebar executable; important for pulling
+ %% resources out of the escript
+ ScriptName = filename:absname(escript:script_name()),
+ BaseConfig1 = rebar_config:set_xconf(BaseConfig, escript, ScriptName),
+ ?DEBUG("Rebar location: ~p\n", [ScriptName]),
+ %% Note the top-level directory for reference
+ AbsCwd = filename:absname(rebar_utils:get_cwd()),
+ rebar_config:set_xconf(BaseConfig1, base_dir, AbsCwd).
+
+profile(BaseConfig1, Commands) ->
+ ?CONSOLE("Please take note that profiler=[fprof|eflame] is preliminary"
+ " and will be~nreplaced with a different command line flag"
+ " in the next release.~n", []),
+ Profiler = rebar_config:get_global(BaseConfig1, profiler, "fprof"),
+ profile(BaseConfig1, Commands, list_to_atom(Profiler)).
+
+profile(Config, Commands, fprof) ->
+ try
+ fprof:apply(fun run_aux/2, [Config, Commands])
+ after
+ ok = fprof:profile(),
+ ok = fprof:analyse([{dest, "fprof.analysis"}]),
+ case rebar_utils:find_executable("erlgrind") of
+ false ->
+ ?CONSOLE(
+ "See fprof.analysis (generated from fprof.trace)~n", []),
+ ok;
+ ErlGrind ->
+ Cmd = ?FMT("~s fprof.analysis fprof.cgrind", [ErlGrind]),
+ {ok, []} = rebar_utils:sh(Cmd, [{use_stdout, false},
+ abort_on_error]),
+ ?CONSOLE("See fprof.analysis (generated from fprof.trace)"
+ " and fprof.cgrind~n", []),
+ ok
+ end
+ end;
+profile(Config, Commands, eflame) ->
+ case code:lib_dir(eflame) of
+ {error, bad_name} ->
+ ?ABORT("eflame not found in code path~n", []),
+ ok;
+ EflameDir ->
+ Trace = "eflame.trace",
+ try
+ eflame:apply(normal_with_children, Trace,
+ rebar, run, [Config, Commands])
+ after
+ %% generate flame graph
+ Script = filename:join(EflameDir, "stack_to_flame.sh"),
+ Svg = "eflame.svg",
+ %% stack_to_flame.sh < eflame.trace > eflame.png
+ Cmd = ?FMT("~s < ~s > ~s", [Script, Trace, Svg]),
+ {ok, []} = rebar_utils:sh(Cmd, [{use_stdout, false},
+ abort_on_error]),
+ ?CONSOLE("See eflame.svg (generated from eflame.trace)~n", []),
+ ok
+ end
+ end;
+profile(_Config, _Commands, Profiler) ->
+ ?ABORT("Unsupported profiler: ~s~n", [Profiler]).
+
+run_aux(BaseConfig, Commands) ->
+ %% Make sure crypto is running
+ case crypto:start() of
+ ok -> ok;
+ {error,{already_started,crypto}} -> ok
+ end,
+
+ %% Make sure memoization server is running
+ case rmemo:start() of
+ {ok, _} -> ok;
+ {error, {already_started, _}} -> ok
+ end,
+
+ %% Convert command strings to atoms
+ CommandAtoms = [list_to_atom(C) || C <- Commands],
+
+ BaseConfig1 = init_config1(BaseConfig),
%% Process each command, resetting any state between each one
- rebar_core:process_commands(CommandAtoms, BaseConfig).
+ rebar_core:process_commands(CommandAtoms, BaseConfig1).
%%
%% print help/usage string
%%
help() ->
OptSpecList = option_spec_list(),
- getopt:usage(OptSpecList, "rebar",
- "[var=value,...] ",
- [{"var=value", "rebar global variables (e.g. force=1)"},
- {"command", "Command to run (e.g. compile)"}]).
+ rebar_getopt:usage(OptSpecList, "rebar",
+ "[var=value,...] ",
+ [{"var=value", "rebar global variables (e.g. force=1)"},
+ {"command", "Command to run (e.g. compile)"}]),
+
+ ?CONSOLE("To see a list of built-in commands, execute rebar -c.~n~n", []),
+ ?CONSOLE(
+ "Type 'rebar help ' for help on specific commands."
+ "~n~n", []),
+ ?CONSOLE(
+ "rebar allows you to abbreviate the command to run:~n"
+ "$ rebar co # same as rebar compile~n"
+ "$ rebar eu # same as rebar eunit~n"
+ "$ rebar g-d # same as rebar get-deps~n"
+ "$ rebar x eu # same as rebar xref eunit~n"
+ "$ rebar l-d # same as rebar list-deps~n"
+ "$ rebar l-d l-t # same as rebar list-deps list-templates~n"
+ "$ rebar list-d l-te # same as rebar list-deps list-templates~n"
+ "~n", []),
+ ?CONSOLE(
+ "Core rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ "Core command line options:~n"
+ " apps=app1,app2 (specify apps to process)~n"
+ " skip_apps=app1,app2 (specify apps to skip)~n",
+ [
+ {recursive_cmds, []},
+ {require_erts_vsn, ".*"},
+ {require_otp_vsn, ".*"},
+ {require_min_otp_vsn, ".*"},
+ {lib_dirs, []},
+ {sub_dirs, ["dir1", "dir2"]},
+ {plugins, [plugin1, plugin2]},
+ {plugin_dir, "some_other_directory"},
+ {pre_hooks, [{clean, "./prepare_package_files.sh"},
+ {"linux", compile, "c_src/build_linux.sh"},
+ {compile, "escript generate_headers"},
+ {compile, "escript check_headers"}]},
+ {post_hooks, [{clean, "touch file1.out"},
+ {"freebsd", compile, "c_src/freebsd_tweaks.sh"},
+ {eunit, "touch file2.out"},
+ {compile, "touch postcompile.out"}]}
+ ]).
%%
%% Parse command line arguments using getopt and also filtering out any
%% key=value pairs. What's left is the list of commands to run
%%
-parse_args(Args) ->
+parse_args(RawArgs) ->
%% Parse getopt options
OptSpecList = option_spec_list(),
- case getopt:parse(OptSpecList, Args) of
- {ok, {Options, NonOptArgs}} ->
- %% Check options and maybe halt execution
- ok = show_info_maybe_halt(Options, NonOptArgs),
-
- GlobalDefines = proplists:get_all_values(defines, Options),
- rebar_config:set_global(defines, GlobalDefines),
-
- %% Setup profiling flag
- rebar_config:set_global(enable_profiling,
- proplists:get_bool(profile, Options)),
-
- %% Set global variables based on getopt options
- set_log_level(Options),
- set_global_flag(Options, force),
- DefJobs = rebar_config:get_jobs(),
- case proplists:get_value(jobs, Options, DefJobs) of
- DefJobs ->
- ok;
- Jobs ->
- rebar_config:set_global(jobs, Jobs)
- end,
-
- %% Set the rebar config to use
- case proplists:get_value(config, Options) of
- undefined -> ok;
- Conf -> rebar_config:set_global(config, Conf)
- end,
-
- %% Filter all the flags (i.e. strings of form key=value) from the
- %% command line arguments. What's left will be the commands to run.
- unabbreviate_command_names(filter_flags(NonOptArgs, []));
-
+ case rebar_getopt:parse(OptSpecList, RawArgs) of
+ {ok, Args} ->
+ Args;
{error, {Reason, Data}} ->
?ERROR("~s ~p~n~n", [Reason, Data]),
help(),
- halt(1)
+ rebar_utils:delayed_halt(1)
end.
+save_options(Config, {Options, NonOptArgs}) ->
+ %% Check options and maybe halt execution
+ ok = show_info_maybe_halt(Options, NonOptArgs),
+
+ GlobalDefines = proplists:get_all_values(defines, Options),
+
+ Config1 = rebar_config:set_xconf(Config, defines, GlobalDefines),
+
+ %% Setup profiling flag
+ Config2 = rebar_config:set_xconf(Config1, enable_profiling,
+ proplists:get_bool(profile, Options)),
+
+ %% Setup flag to keep running after a single command fails
+ Config3 = rebar_config:set_xconf(Config2, keep_going,
+ proplists:get_bool(keep_going, Options)),
+
+ %% Setup flag to enable recursive application of commands
+ Config4 = rebar_config:set_xconf(Config3, recursive,
+ proplists:get_bool(recursive, Options)),
+
+ %% Set global variables based on getopt options
+ Config5 = set_global_flag(Config4, Options, force),
+ Config6 = case proplists:get_value(jobs, Options, ?DEFAULT_JOBS) of
+ ?DEFAULT_JOBS ->
+ Config5;
+ Jobs ->
+ rebar_config:set_global(Config5, jobs, Jobs)
+ end,
+
+ %% Filter all the flags (i.e. strings of form key=value) from the
+ %% command line arguments. What's left will be the commands to run.
+ {Config7, RawCmds} = filter_flags(Config6, NonOptArgs, []),
+ {Config7, unabbreviate_command_names(RawCmds)}.
+
%%
%% set log level based on getopt option
%%
-set_log_level(Options) ->
- LogLevel = case proplists:get_all_values(verbose, Options) of
- [] ->
- rebar_log:default_level();
- Verbosities ->
- lists:last(Verbosities)
- end,
- rebar_config:set_global(verbose, LogLevel).
+set_log_level(Config, Options) ->
+ {IsVerbose, Level} =
+ case proplists:get_bool(quiet, Options) of
+ true ->
+ {false, rebar_log:error_level()};
+ false ->
+ DefaultLevel = rebar_log:default_level(),
+ case proplists:get_all_values(verbose, Options) of
+ [] ->
+ {false, DefaultLevel};
+ Verbosities ->
+ {true, DefaultLevel + lists:last(Verbosities)}
+ end
+ end,
+
+ case IsVerbose of
+ true ->
+ Config1 = rebar_config:set_xconf(Config, is_verbose, true),
+ rebar_config:set_global(Config1, verbose, Level);
+ false ->
+ rebar_config:set_global(Config, verbose, Level)
+ end.
%%
%% show version information and halt
@@ -213,14 +374,14 @@
%%
%% set global flag based on getopt option boolean value
%%
-set_global_flag(Options, Flag) ->
+set_global_flag(Config, Options, Flag) ->
Value = case proplists:get_bool(Flag, Options) of
true ->
"1";
false ->
"0"
end,
- rebar_config:set_global(Flag, Value).
+ rebar_config:set_global(Config, Flag, Value).
%%
%% show info and maybe halt execution
@@ -233,7 +394,7 @@
[] ->
?CONSOLE("No command to run specified!~n",[]),
help(),
- halt(1);
+ rebar_utils:delayed_halt(1);
_ ->
ok
end.
@@ -252,71 +413,115 @@
%%
commands() ->
S = <<"
-clean Clean
-compile Compile sources
+clean Clean
+compile Compile sources
+
+escriptize Generate escript archive
-create template= [var=foo,...] Create skel based on template and vars
-create-app [appid=myapp] Create simple app skel
-create-node [nodeid=mynode] Create simple node skel
-list-templates List available templates
-
-doc Generate Erlang program documentation
-
-check-deps Display to be fetched dependencies
-get-deps Fetch dependencies
-update-deps Update fetched dependencies
-delete-deps Delete fetched dependencies
-list-deps List dependencies
+create template= [var=foo,...] Create skel based on template and vars
+create-app [appid=myapp] Create simple app skel
+create-lib [libid=mylib] Create simple lib skel
+create-node [nodeid=mynode] Create simple node skel
+list-templates List available templates
+
+doc Generate Erlang program documentation
+
+prepare-deps Run 'rebar -r get-deps compile'
+refresh-deps Run 'rebar -r update-deps compile'
+
+check-deps Display to be fetched dependencies
+get-deps Fetch dependencies
+update-deps Update fetched dependencies
+delete-deps Delete fetched dependencies
+list-deps List dependencies
-generate [dump_spec=0/1] Build release with reltool
-overlay Run reltool overlays only
+generate [dump_spec=0/1] Build release with reltool
+overlay Run reltool overlays only
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 [suite[s]=foo] Run EUnit tests in foo.erl and
+ test/foo_tests.erl
+ [suite[s]=foo] [test[s]=bar] Run specific EUnit tests [first test
+ name starting with 'bar' in foo.erl
+ and test/foo_tests.erl]
+ [test[s]=bar] For every existing suite, run the first
+ test whose name starts with bar and, if
+ no such test exists, run the test whose
+ name starts with bar in the suite's
+ _tests module.
+ [random_suite_order=true] Run tests in a random order, either
+ [random_suite_order=Seed] with a random seed for the PRNG, or a
+ specific one.
+
+ct [suite[s]= [group[s]= [case[s]=]]] Run common_test suites
+
+qc Test QuickCheck properties
+
+xref Run cross reference analysis
+
+dialyze Analyze the code for discrepancies
+build-plt Build project-specific PLT
+check-plt Check the PLT for consistency and
+ rebuild it if it is not up-to-date
+delete-plt Delete project-specific PLT
-xref Run cross reference analysis
+shell Start a shell similar to
+ 'erl -pa ebin -pa deps/*/ebin'
-help Show the program options
-version Show version information
+help Show the program options
+version Show version information
">>,
io:put_chars(S).
+get_jobs(Config) ->
+ rebar_config:get_global(Config, jobs, ?DEFAULT_JOBS).
+
%%
%% options accepted via getopt
%%
option_spec_list() ->
- Jobs = rebar_config:get_jobs(),
+ Jobs = ?DEFAULT_JOBS,
JobsHelp = io_lib:format(
"Number of concurrent workers a command may use. Default: ~B",
[Jobs]),
- VerboseHelp = "Verbosity level (-v, -vv, -vvv, --verbose 3). Default: 0",
[
%% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg}
{help, $h, "help", undefined, "Show the program options"},
{commands, $c, "commands", undefined, "Show available commands"},
- {verbose, $v, "verbose", integer, VerboseHelp},
+ {verbose, $v, "verbose", integer, "Verbosity level (-v, -vv)"},
+ {quiet, $q, "quiet", boolean, "Quiet, only print error messages"},
{version, $V, "version", undefined, "Show version information"},
{force, $f, "force", undefined, "Force"},
{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. Via profiler= you can optionally select "
+ "either fprof (default) or eflame. The result can be found in "
+ "fprof.analysis or eflame.svg."},
+ {keep_going, $k, "keep-going", undefined,
+ "Keep running after a command fails"},
+ {recursive, $r, "recursive", boolean,
+ "Apply all commands recursively. Alternatively, you can selectively"
+ " configure what other commands in addition to the always-recursive"
+ " ones (compile, *-deps) should also be applied recursively."
+ " For example, to make 'eunit' recursive, add {recursive_cmds, [eunit]}"
+ " to rebar.config."}
].
%%
%% Seperate all commands (single-words) from flags (key=value) and store
%% values into the rebar_config global storage.
%%
-filter_flags([], Commands) ->
- lists:reverse(Commands);
-filter_flags([Item | Rest], Commands) ->
+filter_flags(Config, [], Commands) ->
+ {Config, lists:reverse(Commands)};
+filter_flags(Config, [Item | Rest], Commands) ->
case string:tokens(Item, "=") of
[Command] ->
- filter_flags(Rest, [Command | Commands]);
+ filter_flags(Config, Rest, [Command | Commands]);
[KeyStr, RawValue] ->
Key = list_to_atom(KeyStr),
Value = case Key of
@@ -325,18 +530,47 @@
_ ->
RawValue
end,
- rebar_config:set_global(Key, Value),
- filter_flags(Rest, Commands);
+ Config1 = rebar_config:set_global(Config, Key, Value),
+ filter_flags(Config1, Rest, Commands);
Other ->
?CONSOLE("Ignoring command line argument: ~p\n", [Other]),
- filter_flags(Rest, Commands)
+ filter_flags(Config, Rest, Commands)
end.
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"].
+ [
+ "build-plt",
+ "check-deps",
+ "check-plt",
+ "clean",
+ "compile",
+ "create",
+ "create-app",
+ "create-lib",
+ "create-node",
+ "ct",
+ "delete-plt",
+ "delete-deps",
+ "dialyze",
+ "doc",
+ "eunit",
+ "escriptize",
+ "generate",
+ "generate-appups",
+ "generate-upgrade",
+ "get-deps",
+ "help",
+ "list-deps",
+ "list-templates",
+ "prepare-deps",
+ "qc",
+ "refresh-deps",
+ "update-deps",
+ "overlay",
+ "shell",
+ "version",
+ "xref"
+ ].
unabbreviate_command_names([]) ->
[];
diff -Nru rebar-2.0.0/src/rebar_erlc_compiler.erl rebar-2.6.0/src/rebar_erlc_compiler.erl
--- rebar-2.0.0/src/rebar_erlc_compiler.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_erlc_compiler.erl 2015-06-19 16:14:28.000000000 +0000
@@ -29,10 +29,23 @@
-export([compile/2,
clean/2]).
--export([doterl_compile/2,
- doterl_compile/3]).
+%% for internal use only
+-export([test_compile/3,
+ info/2]).
-include("rebar.hrl").
+-include_lib("stdlib/include/erl_compile.hrl").
+
+-define(ERLCINFO_VSN, 2).
+-define(ERLCINFO_FILE, "erlcinfo").
+-type erlc_info_v() :: {digraph:vertex(), term()} | 'false'.
+-type erlc_info_e() :: {digraph:vertex(), digraph:vertex()}.
+-type erlc_info() :: {list(erlc_info_v()), list(erlc_info_e()), list(string())}.
+-record(erlcinfo,
+ {
+ vsn = ?ERLCINFO_VSN :: pos_integer(),
+ info = {[], [], []} :: erlc_info()
+ }).
%% ===================================================================
%% Public API
@@ -68,7 +81,7 @@
%% 'old_inets'}]}.
%%
--spec compile(Config::rebar_config:config(), AppFile::file:filename()) -> 'ok'.
+-spec compile(rebar_config:config(), file:filename()) -> 'ok'.
compile(Config, _AppFile) ->
rebar_base_compiler:run(Config,
check_files(rebar_config:get_local(
@@ -87,188 +100,444 @@
fun compile_mib/3),
doterl_compile(Config, "ebin").
--spec clean(Config::rebar_config:config(), AppFile::file:filename()) -> 'ok'.
+-spec clean(rebar_config:config(), file:filename()) -> 'ok'.
clean(_Config, _AppFile) ->
- MibFiles = rebar_utils:find_files("mibs", "^.*\\.mib\$"),
+ MibFiles = rebar_utils:find_files_by_ext("mibs", ".mib"),
MIBs = [filename:rootname(filename:basename(MIB)) || MIB <- MibFiles],
rebar_file_utils:delete_each(
[filename:join(["include",MIB++".hrl"]) || MIB <- MIBs]),
lists:foreach(fun(F) -> ok = rebar_file_utils:rm_rf(F) end,
["ebin/*.beam", "priv/mibs/*.bin"]),
- YrlFiles = rebar_utils:find_files("src", "^.*\\.[x|y]rl\$"),
+ YrlFiles = rebar_utils:find_files_by_ext("src", ".[x|y]rl"),
rebar_file_utils:delete_each(
[ binary_to_list(iolist_to_binary(re:replace(F, "\\.[x|y]rl$", ".erl")))
|| F <- YrlFiles ]),
+ %% Delete the build graph, if any
+ rebar_file_utils:rm_rf(erlcinfo_file()),
+
%% Erlang compilation is recursive, so it's possible that we have a nested
%% directory structure in ebin with .beam files within. As such, we want
%% to scan whatever is left in the ebin/ directory for sub-dirs which
%% satisfy our criteria.
- BeamFiles = rebar_utils:find_files("ebin", "^.*\\.beam\$"),
+ BeamFiles = rebar_utils:find_files_by_ext("ebin", ".beam"),
rebar_file_utils:delete_each(BeamFiles),
lists:foreach(fun(Dir) -> delete_dir(Dir, dirs(Dir)) end, dirs("ebin")),
ok.
+%% ===================================================================
+%% .erl Compilation API (externally used by only eunit and qc)
+%% ===================================================================
+
+test_compile(Config, Cmd, OutDir) ->
+ %% Obtain all the test modules for inclusion in the compile stage.
+ TestErls = rebar_utils:find_files_by_ext("test", ".erl"),
+
+ ErlOpts = rebar_utils:erl_opts(Config),
+ {Config1, ErlOpts1} = test_compile_config_and_opts(Config, ErlOpts, Cmd),
+
+ %% 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. Also copy files from src_dirs.
+ SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts1)),
+ SrcErls = lists:foldl(
+ fun(Dir, Acc) ->
+ Files = rebar_utils:find_files_by_ext(Dir, ".erl"),
+ lists:append(Acc, Files)
+ end, [], SrcDirs),
+
+ %% If it is not the first time rebar eunit or rebar qc is executed,
+ %% there will be source files already present in OutDir. Since some
+ %% SCMs (like Perforce) set the source files as being read only (unless
+ %% they are checked out), we need to be sure that the files already
+ %% present in OutDir are writable before doing the copy. This is done
+ %% here by removing any file that was already present before calling
+ %% rebar_file_utils:cp_r.
+
+ %% Get the full path to a file that was previously copied in OutDir
+ ToCleanUp = fun(F, Acc) ->
+ F2 = filename:basename(F),
+ F3 = filename:join([OutDir, F2]),
+ case filelib:is_regular(F3) of
+ true -> [F3|Acc];
+ false -> Acc
+ end
+ end,
+
+ ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], TestErls)),
+ ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], SrcErls)),
+
+ ok = rebar_file_utils:cp_r(SrcErls ++ TestErls, OutDir),
+
+ %% Compile erlang code to OutDir, using a tweaked config
+ %% with appropriate defines for eunit, and include all the test modules
+ %% as well.
+ ok = doterl_compile(Config1, OutDir, TestErls, ErlOpts1),
+
+ {ok, SrcErls}.
%% ===================================================================
-%% .erl Compilation API (externally used by only eunit)
+%% Internal functions
%% ===================================================================
--spec doterl_compile(Config::rebar_config:config(),
- OutDir::file:filename()) -> 'ok'.
+info(help, compile) ->
+ info_help("Build *.erl, *.yrl, *.xrl, and *.mib sources");
+info(help, clean) ->
+ info_help("Delete *.erl, *.yrl, *.xrl, and *.mib build results").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ Description,
+ {erl_opts, [no_debug_info,
+ {i, "myinclude"},
+ {src_dirs, ["src", "src2", "src3"]},
+ {platform_define,
+ "(linux|solaris|freebsd|darwin)", 'HAVE_SENDFILE'},
+ {platform_define, "(linux|freebsd)", 'BACKLOG', 128},
+ {platform_define, "R13", 'old_inets'}]},
+ {erl_first_files, ["src/mymib1.erl", "src/mymib2.erl"]},
+ {mib_opts, []},
+ {mib_first_files, []},
+ {xrl_opts, []},
+ {xrl_first_files, []},
+ {yrl_opts, []},
+ {yrl_first_files, []}
+ ]).
+
+test_compile_config_and_opts(Config, ErlOpts, Cmd) ->
+ {Config1, TriqOpts} = triq_opts(Config),
+ {Config2, PropErOpts} = proper_opts(Config1),
+ {Config3, EqcOpts} = eqc_opts(Config2),
+
+ %% NOTE: For consistency, all *_first_files lists should be
+ %% retrieved via rebar_config:get_local. Right now
+ %% erl_first_files, eunit_first_files, and qc_first_files use
+ %% rebar_config:get_list and are inherited, but xrl_first_files
+ %% and yrl_first_files use rebar_config:get_local. Inheritance of
+ %% *_first_files is questionable as the file would need to exist
+ %% in all project directories for it to work.
+ OptsAtom = list_to_atom(Cmd ++ "_compile_opts"),
+ TestOpts = rebar_config:get_list(Config3, OptsAtom, []),
+ Opts0 = [{d, 'TEST'}] ++
+ ErlOpts ++ TestOpts ++ TriqOpts ++ PropErOpts ++ EqcOpts,
+ Opts = [O || O <- Opts0, O =/= no_debug_info],
+ Config4 = rebar_config:set(Config3, erl_opts, Opts),
+
+ FirstFilesAtom = list_to_atom(Cmd ++ "_first_files"),
+ FirstErls = rebar_config:get_list(Config4, FirstFilesAtom, []),
+ Config5 = rebar_config:set(Config4, erl_first_files, FirstErls),
+ {Config5, Opts}.
+
+triq_opts(Config) ->
+ {NewConfig, IsAvail} = is_lib_avail(Config, is_triq_avail, triq,
+ "triq.hrl", "Triq"),
+ Opts = define_if('TRIQ', IsAvail),
+ {NewConfig, Opts}.
+
+proper_opts(Config) ->
+ {NewConfig, IsAvail} = is_lib_avail(Config, is_proper_avail, proper,
+ "proper.hrl", "PropEr"),
+ Opts = define_if('PROPER', IsAvail),
+ {NewConfig, Opts}.
+
+eqc_opts(Config) ->
+ {NewConfig, IsAvail} = is_lib_avail(Config, is_eqc_avail, eqc,
+ "eqc.hrl", "QuickCheck"),
+ Opts = define_if('EQC', IsAvail),
+ {NewConfig, Opts}.
+
+define_if(Def, true) -> [{d, Def}];
+define_if(_Def, false) -> [].
+
+is_lib_avail(Config, DictKey, Mod, Hrl, Name) ->
+ case rebar_config:get_xconf(Config, DictKey, undefined) of
+ undefined ->
+ IsAvail = case code:lib_dir(Mod, include) of
+ {error, bad_name} ->
+ false;
+ Dir ->
+ filelib:is_regular(filename:join(Dir, Hrl))
+ end,
+ NewConfig = rebar_config:set_xconf(Config, DictKey, IsAvail),
+ ?DEBUG("~s availability: ~p\n", [Name, IsAvail]),
+ {NewConfig, IsAvail};
+ IsAvail ->
+ {Config, IsAvail}
+ end.
+
+-spec doterl_compile(rebar_config:config(), file:filename()) -> 'ok'.
doterl_compile(Config, OutDir) ->
- doterl_compile(Config, OutDir, []).
+ ErlOpts = rebar_utils:erl_opts(Config),
+ doterl_compile(Config, OutDir, [], ErlOpts).
-doterl_compile(Config, OutDir, MoreSources) ->
- FirstErls = rebar_config:get_list(Config, erl_first_files, []),
- ErlOpts = erl_opts(Config),
+doterl_compile(Config, OutDir, MoreSources, ErlOpts) ->
?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)),
- RestErls = [Source || Source <- gather_src(SrcDirs, []) ++ MoreSources,
- not lists:member(Source, FirstErls)],
-
- %% Split RestErls so that parse_transforms and behaviours are instead added
- %% to erl_first_files, parse transforms first.
- %% This should probably be somewhat combined with inspect_epp
- [ParseTransforms, Behaviours, OtherErls] =
- lists:foldl(fun(F, [A, B, C]) ->
- case compile_priority(F) of
- parse_transform ->
- [[F | A], B, C];
- behaviour ->
- [A, [F | B], C];
- callback ->
- [A, [F | B], C];
- _ ->
- [A, B, [F | C]]
- end
- end, [[], [], []], RestErls),
-
- NewFirstErls = FirstErls ++ ParseTransforms ++ Behaviours,
+ SrcDirs = rebar_utils:src_dirs(proplists:append_values(src_dirs, ErlOpts)),
+ AllErlFiles = gather_src(SrcDirs, []) ++ MoreSources,
%% Make sure that ebin/ exists and is on the path
ok = filelib:ensure_dir(filename:join("ebin", "dummy.beam")),
CurrPath = code:get_path(),
true = code:add_path(filename:absname("ebin")),
- rebar_base_compiler:run(Config, NewFirstErls, OtherErls,
- fun(S, C) ->
- internal_erl_compile(S, C, OutDir, ErlOpts)
- end),
- true = code:set_path(CurrPath),
- ok.
+ OutDir1 = proplists:get_value(outdir, ErlOpts, OutDir),
+ G = init_erlcinfo(proplists:get_all_values(i, ErlOpts), AllErlFiles),
+ NeededErlFiles = needed_files(G, OutDir1, AllErlFiles),
+ {ErlFirstFiles, ErlOptsFirst} = erl_first_files(Config,
+ ErlOpts,
+ NeededErlFiles),
+ {DepErls, OtherErls} =
+ lists:partition(
+ fun(Source) ->
+ digraph:in_degree(G, Source) > 0
+ end,
+ [F || F <- NeededErlFiles, not lists:member(F, ErlFirstFiles)]),
+ DepErlsOrdered = digraph_utils:topsort(digraph_utils:subgraph(G, DepErls)),
+ FirstErls = ErlFirstFiles ++ lists:reverse(DepErlsOrdered),
+ ?DEBUG("Files to compile first: ~p~n", [FirstErls]),
+
+ rebar_base_compiler:run(
+ Config, FirstErls, OtherErls,
+ fun(S, C) ->
+ ErlOpts1 = case lists:member(S, ErlFirstFiles) of
+ true -> ErlOptsFirst;
+ false -> ErlOpts
+ end,
+ internal_erl_compile(C, S, OutDir1, ErlOpts1)
+ end),
+ true = rebar_utils:cleanup_code_path(CurrPath),
+ ok.
-%% ===================================================================
-%% 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) ->
- ErlOpts = rebar_config:get(Config, erl_opts, []),
- ["include", filename:dirname(Source)]
- ++ proplists:get_all_values(i, ErlOpts).
-
--spec inspect(Source::file:filename(),
- IncludePath::[file:filename(), ...]) -> {string(), [string()]}.
-inspect(Source, IncludePath) ->
- ModuleDefault = filename:basename(Source, ".erl"),
- case epp:open(Source, IncludePath) of
- {ok, Epp} ->
- inspect_epp(Epp, Source, ModuleDefault, []);
- {error, Reason} ->
- ?DEBUG("Failed to inspect ~s: ~p\n", [Source, Reason]),
- {ModuleDefault, []}
- end.
-
--spec inspect_epp(Epp::pid(), Source::file:filename(), Module::file:filename(),
- Includes::[string()]) -> {string(), [string()]}.
-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], ".")
+%% Get files which need to be compiled first, i.e. those specified in
+%% erl_first_files and parse_transform options. Also produce specific
+%% erl_opts for these first files, so that yet to be compiled parse
+%% transformations are excluded from it.
+erl_first_files(Config, ErlOpts, NeededErlFiles) ->
+ %% NOTE: rebar_config:get_local perhaps?
+ ErlFirstFilesConf = rebar_config:get_list(Config, erl_first_files, []),
+ NeededSrcDirs = lists:usort(
+ lists:map(fun filename:dirname/1, NeededErlFiles)),
+ %% NOTE: order of files here is important!
+ ErlFirstFiles = lists:filter(
+ fun(File) -> lists:member(File, NeededErlFiles) end,
+ ErlFirstFilesConf),
+ {ParseTransforms, ParseTransformsErls} =
+ lists:unzip(
+ lists:flatmap(
+ fun(PT) ->
+ PTerls = [filename:join(Dir, module_to_erl(PT))
+ || Dir <- NeededSrcDirs],
+ [{PT, PTerl} || PTerl <- PTerls,
+ lists:member(PTerl, NeededErlFiles)]
end,
- inspect_epp(Epp, Source, ActualModuleStr, Includes);
- {ok, {attribute, 1, file, {Module, 1}}} ->
- inspect_epp(Epp, Source, Module, Includes);
- {ok, {attribute, 1, file, {Source, 1}}} ->
- inspect_epp(Epp, Source, Module, Includes);
- {ok, {attribute, 1, file, {IncFile, 1}}} ->
- inspect_epp(Epp, Source, Module, [IncFile | Includes]);
- {eof, _} ->
- epp:close(Epp),
- {Module, Includes};
- _ ->
- inspect_epp(Epp, Source, Module, Includes)
+ proplists:get_all_values(parse_transform, ErlOpts))),
+ ErlOptsFirst = lists:filter(
+ fun ({parse_transform, PT}) ->
+ not lists:member(PT, ParseTransforms);
+ (_) -> true
+ end,
+ ErlOpts),
+ {ErlFirstFiles ++ ParseTransformsErls, ErlOptsFirst}.
+
+%% Get subset of SourceFiles which need to be recompiled, respecting
+%% dependencies induced by given graph G.
+needed_files(G, OutDir, SourceFiles) ->
+ lists:filter(
+ fun(Source) ->
+ Target = target_base(OutDir, Source) ++ ".beam",
+ digraph:vertex(G, Source) >
+ {Source, filelib:last_modified(Target)}
+ end, SourceFiles).
+
+target_base(OutDir, Source) ->
+ filename:join(OutDir, filename:basename(Source, ".erl")).
+
+erlcinfo_file() ->
+ filename:join([rebar_utils:get_cwd(), ".rebar", ?ERLCINFO_FILE]).
+
+%% Get dependency graph of given Erls files and their dependencies
+%% (header files, parse transforms, behaviours etc.) located in their
+%% directories or given InclDirs. Note that last modification times
+%% stored in vertices already respect
+%% dependencies induced by given graph G.
+init_erlcinfo(InclDirs, Erls) ->
+ G = digraph:new([acyclic]),
+ try restore_erlcinfo(G, InclDirs)
+ catch
+ _:_ ->
+ ?WARN("Failed to restore ~s file. Discarding it.~n",
+ [erlcinfo_file()]),
+ ok = file:delete(erlcinfo_file())
+ end,
+ Dirs = source_and_include_dirs(InclDirs, Erls),
+ Modified = lists:foldl(update_erlcinfo_fun(G, Dirs), false, Erls),
+ if Modified -> store_erlcinfo(G, InclDirs); not Modified -> ok end,
+ G.
+
+source_and_include_dirs(InclDirs, Erls) ->
+ SourceDirs = lists:map(fun filename:dirname/1, Erls),
+ lists:usort(["include" | InclDirs ++ SourceDirs]).
+
+update_erlcinfo_fun(G, Dirs) ->
+ fun(Erl, Modified) ->
+ case update_erlcinfo(G, Dirs, Erl) of
+ modified -> true;
+ unmodified -> Modified
+ end
end.
--spec needs_compile(Source::file:filename(), Target::file:filename(),
- Hrls::[string()]) -> boolean().
-needs_compile(Source, Target, Hrls) ->
- TargetLastMod = filelib:last_modified(Target),
- lists:any(fun(I) -> TargetLastMod < filelib:last_modified(I) end,
- [Source] ++ Hrls).
-
--spec internal_erl_compile(Source::file:filename(),
- Config::rebar_config:config(),
- Outdir::file:filename(),
- ErlOpts::list()) -> 'ok' | 'skipped'.
-internal_erl_compile(Source, Config, Outdir, ErlOpts) ->
- %% Determine the target name and includes list by inspecting the source file
- {Module, Hrls} = inspect(Source, include_path(Source, Config)),
-
- %% Construct the target filename
- Target = filename:join([Outdir | string:tokens(Module, ".")]) ++ ".beam",
- ok = filelib:ensure_dir(Target),
-
- %% If the file needs compilation, based on last mod date of includes or
- %% the target
- case needs_compile(Source, Target, Hrls) of
- true ->
- Opts = [{outdir, filename:dirname(Target)}] ++
- ErlOpts ++ [{i, "include"}, report],
- case compile:file(Source, Opts) of
- {ok, _} ->
- ok;
+update_erlcinfo(G, Dirs, Source) ->
+ case digraph:vertex(G, Source) of
+ {_, LastUpdated} ->
+ case filelib:last_modified(Source) of
+ 0 ->
+ %% The file doesn't exist anymore,
+ %% erase it from the graph.
+ %% All the edges will be erased automatically.
+ ?WARN("File missing. Remove from dep graph:~n~s~n",
+ [Source]),
+ digraph:del_vertex(G, Source),
+ modified;
+ LastModified when LastUpdated < LastModified ->
+ modify_erlcinfo(G, Source, LastModified, Dirs);
_ ->
- ?FAIL
+ Modified = lists:foldl(
+ update_erlcinfo_fun(G, Dirs),
+ false, digraph:out_neighbours(G, Source)),
+ MaxModified = update_max_modified_deps(G, Source),
+ case Modified orelse MaxModified > LastUpdated of
+ true -> modified;
+ false -> unmodified
+ end
end;
false ->
- skipped
+ modify_erlcinfo(G, Source, filelib:last_modified(Source), Dirs)
+ end.
+
+update_max_modified_deps(G, Source) ->
+ MaxModified = lists:max(
+ lists:map(
+ fun(File) ->
+ {_, MaxModified} = digraph:vertex(G, File),
+ MaxModified
+ end,
+ [Source|digraph:out_neighbours(G, Source)])),
+ digraph:add_vertex(G, Source, MaxModified),
+ MaxModified.
+
+modify_erlcinfo(_G, Source, 0, _Dirs) ->
+ ?WARN("modify_erlcinfo: failed to open file:~n~s~n", [Source]),
+ unmodified;
+modify_erlcinfo(G, Source, LastModified, Dirs) ->
+ {ok, Fd} = file:open(Source, [read]),
+ Incls = parse_attrs(Fd, []),
+ AbsIncls = expand_file_names(Incls, Dirs),
+ ok = file:close(Fd),
+ digraph:add_vertex(G, Source, LastModified),
+ digraph:del_edges(G, digraph:out_edges(G, Source)),
+ lists:foreach(
+ fun(Incl) ->
+ update_erlcinfo(G, Dirs, Incl),
+ digraph:add_edge(G, Source, Incl)
+ end, AbsIncls),
+ modified.
+
+restore_erlcinfo(G, InclDirs) ->
+ case file:read_file(erlcinfo_file()) of
+ {ok, Data} ->
+ %% Since externally passed InclDirs can influence erlcinfo
+ %% graph (see modify_erlcinfo), we have to check here that
+ %% they didn't change.
+ #erlcinfo{vsn=?ERLCINFO_VSN, info={Vs, Es, InclDirs}} =
+ binary_to_term(Data),
+ lists:foreach(
+ fun({V, LastUpdated}) ->
+ digraph:add_vertex(G, V, LastUpdated)
+ end, Vs),
+ lists:foreach(
+ fun({_, V1, V2, _}) ->
+ digraph:add_edge(G, V1, V2)
+ end, Es);
+ {error, _} ->
+ ok
+ end.
+
+store_erlcinfo(G, InclDirs) ->
+ Vs = lists:map(fun(V) -> digraph:vertex(G, V) end, digraph:vertices(G)),
+ Es = lists:map(fun(E) -> digraph:edge(G, E) end, digraph:edges(G)),
+ File = erlcinfo_file(),
+ ok = filelib:ensure_dir(File),
+ Info = #erlcinfo{info={Vs, Es, InclDirs}},
+ Data = term_to_binary(Info, [{compressed, 2}]),
+ ok = file:write_file(File, Data).
+
+%% NOTE: If, for example, one of the entries in Files refers to
+%% gen_server.erl, that entry will be dropped. It is dropped because
+%% such an entry usually refers to the beam file, and we don't pass a
+%% list of OTP src dirs for finding gen_server.erl's full path. Also,
+%% if gen_server.erl was modified, it's not rebar's task to compile a
+%% new version of the beam file. Therefore, it's reasonable to drop
+%% such entries. Also see process_attr(behaviour, Form, Includes).
+-spec expand_file_names([file:filename()],
+ [file:filename()]) -> [file:filename()].
+expand_file_names(Files, Dirs) ->
+ %% We check if Files exist by itself or within the directories
+ %% listed in Dirs.
+ %% Return the list of files matched.
+ lists:flatmap(
+ fun(Incl) ->
+ case filelib:is_regular(Incl) of
+ true ->
+ [Incl];
+ false ->
+ lists:flatmap(
+ fun(Dir) ->
+ FullPath = filename:join(Dir, Incl),
+ case filelib:is_regular(FullPath) of
+ true ->
+ [FullPath];
+ false ->
+ []
+ end
+ end, Dirs)
+ end
+ end, Files).
+
+-spec internal_erl_compile(
+ rebar_config:config(),
+ file:filename(),
+ file:filename(),
+ list()) -> ok | {ok, any()} | {error, any(), any()}.
+internal_erl_compile(Config, Source, OutDir, ErlOpts) ->
+ ok = filelib:ensure_dir(OutDir),
+ Opts = [{outdir, OutDir}] ++ ErlOpts ++ [{i, "include"}, return],
+ case compile:file(Source, Opts) of
+ {ok, _Mod} ->
+ ok;
+ {ok, _Mod, Ws} ->
+ rebar_base_compiler:ok_tuple(Config, Source, Ws);
+ {error, Es, Ws} ->
+ rebar_base_compiler:error_tuple(Config, Source, Es, Ws, Opts)
end.
--spec compile_mib(Source::file:filename(), Target::file:filename(),
- Config::rebar_config:config()) -> 'ok'.
+-spec compile_mib(file:filename(), file:filename(),
+ rebar_config:config()) -> 'ok'.
compile_mib(Source, Target, Config) ->
ok = rebar_utils:ensure_dir(Target),
ok = rebar_utils:ensure_dir(filename:join("include", "dummy.hrl")),
@@ -277,7 +546,14 @@
case snmpc:compile(Source, Opts) of
{ok, _} ->
Mib = filename:rootname(Target),
- ok = snmpc:mib_to_hrl(Mib),
+ MibToHrlOpts =
+ case proplists:get_value(verbosity, Opts, undefined) of
+ undefined ->
+ #options{specific = []};
+ Verbosity ->
+ #options{specific = [{verbosity, Verbosity}]}
+ end,
+ ok = snmpc:mib_to_hrl(Mib, Mib, MibToHrlOpts),
Hrl_filename = Mib ++ ".hrl",
rebar_file_utils:mv(Hrl_filename, "include"),
ok;
@@ -285,118 +561,157 @@
?FAIL
end.
--spec compile_xrl(Source::file:filename(), Target::file:filename(),
- Config::rebar_config:config()) -> 'ok'.
+-spec compile_xrl(file:filename(), file:filename(),
+ rebar_config:config()) -> 'ok'.
compile_xrl(Source, Target, Config) ->
Opts = [{scannerfile, Target} | rebar_config:get(Config, xrl_opts, [])],
- compile_xrl_yrl(Source, Target, Opts, leex).
+ compile_xrl_yrl(Config, Source, Target, Opts, leex).
--spec compile_yrl(Source::file:filename(), Target::file:filename(),
- Config::rebar_config:config()) -> 'ok'.
+-spec compile_yrl(file:filename(), file:filename(),
+ rebar_config:config()) -> 'ok'.
compile_yrl(Source, Target, Config) ->
Opts = [{parserfile, Target} | rebar_config:get(Config, yrl_opts, [])],
- compile_xrl_yrl(Source, Target, Opts, yecc).
+ compile_xrl_yrl(Config, Source, Target, Opts, yecc).
--spec compile_xrl_yrl(Source::file:filename(), Target::file:filename(),
- Opts::list(), Mod::atom()) -> 'ok'.
-compile_xrl_yrl(Source, Target, Opts, Mod) ->
- case needs_compile(Source, Target, []) of
+-spec compile_xrl_yrl(rebar_config:config(), file:filename(),
+ file:filename(), list(), module()) -> 'ok'.
+compile_xrl_yrl(Config, 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(Config, Source, Ws);
+ {error, Es, Ws} ->
+ rebar_base_compiler:error_tuple(Config, Source,
+ Es, Ws, Opts)
end;
false ->
skipped
end.
+needs_compile(Source, Target) ->
+ filelib:last_modified(Source) > filelib:last_modified(Target).
+
gather_src([], Srcs) ->
Srcs;
gather_src([Dir|Rest], Srcs) ->
- gather_src(Rest, Srcs ++ rebar_utils:find_files(Dir, ".*\\.erl\$")).
+ gather_src(
+ Rest, Srcs ++ rebar_utils:find_files_by_ext(Dir, ".erl")).
--spec src_dirs(SrcDirs::[string()]) -> [file:filename(), ...].
-src_dirs([]) ->
- ["src"];
-src_dirs(SrcDirs) ->
- SrcDirs.
-
--spec dirs(Dir::file:filename()) -> [file:filename()].
+-spec dirs(file:filename()) -> [file:filename()].
dirs(Dir) ->
[F || F <- filelib:wildcard(filename:join([Dir, "*"])), filelib:is_dir(F)].
--spec delete_dir(Dir::file:filename(),
- Subdirs::[string()]) -> 'ok' | {'error', atom()}.
+-spec delete_dir(file:filename(), [string()]) -> 'ok' | {'error', atom()}.
delete_dir(Dir, []) ->
file:del_dir(Dir);
delete_dir(Dir, Subdirs) ->
lists:foreach(fun(D) -> delete_dir(D, dirs(D)) end, Subdirs),
file:del_dir(Dir).
--spec compile_priority(File::file:filename()) -> 'normal' | 'behaviour' |
- 'callback' |
- 'parse_transform'.
-compile_priority(File) ->
- case epp_dodger:parse_file(File) of
- {error, _} ->
- normal; % couldn't parse the file, default priority
- {ok, Trees} ->
- F2 = fun({tree,arity_qualifier,_,
- {arity_qualifier,{tree,atom,_,behaviour_info},
- {tree,integer,_,1}}}, _) ->
- behaviour;
- ({tree,arity_qualifier,_,
- {arity_qualifier,{tree,atom,_,parse_transform},
- {tree,integer,_,2}}}, _) ->
- parse_transform;
- (_, Acc) ->
- Acc
- end,
-
- F = fun({tree, attribute, _,
- {attribute, {tree, atom, _, export},
- [{tree, list, _, {list, List, none}}]}}, Acc) ->
- lists:foldl(F2, Acc, List);
- ({tree, attribute, _,
- {attribute, {tree, atom, _, callback},_}}, _Acc) ->
- callback;
- (_, Acc) ->
- Acc
- end,
-
- lists:foldl(F, normal, Trees)
+parse_attrs(Fd, Includes) ->
+ case io:parse_erl_form(Fd, "") of
+ {ok, Form, _Line} ->
+ case erl_syntax:type(Form) of
+ attribute ->
+ NewIncludes = process_attr(Form, Includes),
+ parse_attrs(Fd, NewIncludes);
+ _ ->
+ parse_attrs(Fd, Includes)
+ end;
+ {eof, _} ->
+ Includes;
+ _Err ->
+ parse_attrs(Fd, Includes)
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)
+process_attr(Form, Includes) ->
+ AttrName = erl_syntax:atom_value(erl_syntax:attribute_name(Form)),
+ process_attr(AttrName, Form, Includes).
+
+process_attr(import, Form, Includes) ->
+ case erl_syntax_lib:analyze_import_attribute(Form) of
+ {Mod, _Funs} ->
+ [module_to_erl(Mod)|Includes];
+ Mod ->
+ [module_to_erl(Mod)|Includes]
+ end;
+process_attr(file, Form, Includes) ->
+ {File, _} = erl_syntax_lib:analyze_file_attribute(Form),
+ [File|Includes];
+process_attr(include, Form, Includes) ->
+ [FileNode] = erl_syntax:attribute_arguments(Form),
+ File = erl_syntax:string_value(FileNode),
+ [File|Includes];
+process_attr(include_lib, Form, Includes) ->
+ [FileNode] = erl_syntax:attribute_arguments(Form),
+ RawFile = erl_syntax:string_value(FileNode),
+ maybe_expand_include_lib_path(RawFile) ++ Includes;
+process_attr(behaviour, Form, Includes) ->
+ [FileNode] = erl_syntax:attribute_arguments(Form),
+ File = module_to_erl(erl_syntax:atom_value(FileNode)),
+ [File|Includes];
+process_attr(compile, Form, Includes) ->
+ [Arg] = erl_syntax:attribute_arguments(Form),
+ case erl_syntax:concrete(Arg) of
+ {parse_transform, Mod} ->
+ [module_to_erl(Mod)|Includes];
+ {core_transform, Mod} ->
+ [module_to_erl(Mod)|Includes];
+ L when is_list(L) ->
+ lists:foldl(
+ fun({parse_transform, Mod}, Acc) ->
+ [module_to_erl(Mod)|Acc];
+ ({core_transform, Mod}, Acc) ->
+ [module_to_erl(Mod)|Acc];
+ (_, Acc) ->
+ Acc
+ end, Includes, L);
+ _ ->
+ Includes
end;
-filter_defines([{platform_define, ArchRegex, Key, Value} | Rest], Acc) ->
- case rebar_utils:is_arch(ArchRegex) of
+process_attr(_, _Form, Includes) ->
+ Includes.
+
+module_to_erl(Mod) ->
+ atom_to_list(Mod) ++ ".erl".
+
+%% Given the filename from an include_lib attribute, if the path
+%% exists, return unmodified, or else get the absolute ERL_LIBS
+%% path.
+maybe_expand_include_lib_path(File) ->
+ case filelib:is_regular(File) of
true ->
- filter_defines(Rest, [{d, Key, Value} | Acc]);
+ [File];
false ->
- filter_defines(Rest, Acc)
- end;
-filter_defines([Opt | Rest], Acc) ->
- filter_defines(Rest, [Opt | Acc]).
+ expand_include_lib_path(File)
+ end.
+
+%% Given a path like "stdlib/include/erl_compile.hrl", return
+%% "OTP_INSTALL_DIR/lib/erlang/lib/stdlib-x.y.z/include/erl_compile.hrl".
+%% Usually a simple [Lib, SubDir, File1] = filename:split(File) should
+%% work, but to not crash when an unusual include_lib path is used,
+%% utilize more elaborate logic.
+expand_include_lib_path(File) ->
+ File1 = filename:basename(File),
+ [Lib | Parts] = filename:split(filename:dirname(File)),
+ SubDir = case Parts of
+ [] -> % prevent function clause error
+ [];
+ _ ->
+ filename:join(Parts)
+ end,
+ case code:lib_dir(list_to_atom(Lib), list_to_atom(SubDir)) of
+ {error, bad_name} -> [];
+ Dir -> [filename:join(Dir, File1)]
+ end.
%%
%% Ensure all files in a list are present and abort if one is missing
%%
--spec check_files(FileList::[file:filename()]) -> [file:filename()].
+-spec check_files([file:filename()]) -> [file:filename()].
check_files(FileList) ->
[check_file(F) || F <- FileList].
diff -Nru rebar-2.0.0/src/rebar_erlydtl_compiler.erl rebar-2.6.0/src/rebar_erlydtl_compiler.erl
--- rebar-2.0.0/src/rebar_erlydtl_compiler.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_erlydtl_compiler.erl 2015-06-19 16:14:28.000000000 +0000
@@ -31,7 +31,11 @@
%% to ebin/*_dtl.beam.
%%
%% Configuration options should be placed in rebar.config under
-%% 'erlydtl_opts'. Available options include:
+%% 'erlydtl_opts'. It can be a list of name-value tuples or a list of
+%% lists of name-value tuples if you have multiple template directories
+%% that need to have different settings (see example below).
+%%
+%% Available options include:
%%
%% doc_root: where to find templates to compile
%% "templates" by default
@@ -45,6 +49,9 @@
%% module_ext: characters to append to the template's module name
%% "_dtl" by default
%%
+%% recursive: boolean that determines if doc_root(s) need to be
+%% scanned recursively for matching template file names
+%% (default: true).
%% For example, if you had:
%% /t_src/
%% base.html
@@ -70,10 +77,28 @@
%% {source_ext, ".dtl"},
%% {module_ext, "_dtl"}
%% ]}.
+%%
+%% The following example will compile the following templates:
+%% "src/*.dtl" files into "ebin/*_dtl.beam" and
+%% "templates/*.html" into "ebin/*.beam". Note that any tuple option
+%% (such as 'out_dir') in the outer list is added to each inner list:
+%% {erlydtl_opts, [
+%% {out_dir, "ebin"},
+%% {recursive, false},
+%% [
+%% {doc_root, "src"}, {module_ext, "_dtl"}
+%% ],
+%% [
+%% {doc_root, "templates"}, {module_ext, ""}, {source_ext, ".html"}
+%% ]
+%% ]}.
-module(rebar_erlydtl_compiler).
-export([compile/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
%% ===================================================================
@@ -81,26 +106,60 @@
%% ===================================================================
compile(Config, _AppFile) ->
- DtlOpts = erlydtl_opts(Config),
+ MultiDtlOpts = erlydtl_opts(Config),
OrigPath = code:get_path(),
- true = code:add_path(filename:join(rebar_utils:get_cwd(), "ebin")),
- Result = rebar_base_compiler:run(Config, [],
+ true = code:add_path(rebar_utils:ebin_dir()),
+
+ Result = lists:foldl(fun(DtlOpts, _) ->
+ rebar_base_compiler:run(Config, [],
option(doc_root, DtlOpts),
option(source_ext, DtlOpts),
option(out_dir, DtlOpts),
option(module_ext, DtlOpts) ++ ".beam",
- fun compile_dtl/3,
- [{check_last_mod, false}]),
- true = code:set_path(OrigPath),
- Result.
+ fun(S, T, C) ->
+ compile_dtl(C, S, T, DtlOpts)
+ end,
+ [{check_last_mod, false},
+ {recursive, option(recursive, DtlOpts)}])
+ end, ok, MultiDtlOpts),
+ true = rebar_utils:cleanup_code_path(OrigPath),
+ Result.
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, compile) ->
+ ?CONSOLE(
+ "Build ErlyDtl (*.dtl) sources.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n",
+ [
+ {erlydtl_opts, [{doc_root, "templates"},
+ {out_dir, "ebin"},
+ {source_ext, ".dtl"},
+ {module_ext, "_dtl"},
+ {recursive, true}]}
+ ]).
+
erlydtl_opts(Config) ->
- rebar_config:get(Config, erlydtl_opts, []).
+ Opts = rebar_config:get(Config, erlydtl_opts, []),
+ Tuples = [{K,V} || {K,V} <- Opts],
+ case [L || L <- Opts, is_list(L), not io_lib:printable_list(L)] of
+ [] ->
+ [lists:keysort(1, Tuples)];
+ Lists ->
+ lists:map(
+ fun(L) ->
+ lists:keysort(1,
+ lists:foldl(
+ fun({K,T}, Acc) ->
+ lists:keystore(K, 1, Acc, {K, T})
+ end, Tuples, L))
+ end, Lists)
+ end.
option(Opt, DtlOpts) ->
proplists:get_value(Opt, DtlOpts, default(Opt)).
@@ -109,63 +168,90 @@
default(out_dir) -> "ebin";
default(source_ext) -> ".dtl";
default(module_ext) -> "_dtl";
-default(custom_tags_dir) -> "".
+default(custom_tags_dir) -> "";
+default(compiler_options) -> [return];
+default(recursive) -> true.
-compile_dtl(Source, Target, Config) ->
+compile_dtl(Config, Source, Target, DtlOpts) ->
case code:which(erlydtl) of
non_existing ->
?ERROR("~n===============================================~n"
" You need to install erlydtl to compile DTL templates~n"
" Download the latest tarball release from github~n"
- " http://code.google.com/p/erlydtl/~n"
+ " https://github.com/erlydtl/erlydtl/releases~n"
" and install it into your erlang library dir~n"
"===============================================~n~n", []),
?FAIL;
_ ->
- case needs_compile(Source, Target, Config) of
+ case needs_compile(Source, Target, DtlOpts) of
true ->
- do_compile(Source, Target, Config);
+ do_compile(Config, Source, Target, DtlOpts);
false ->
skipped
end
end.
-do_compile(Source, Target, Config) ->
+do_compile(Config, Source, Target, DtlOpts) ->
%% TODO: Check last mod on target and referenced DTLs here..
- DtlOpts = erlydtl_opts(Config),
+
+ %% erlydtl >= 0.8.1 does not use the extra indirection using the
+ %% compiler_options. Kept for backward compatibility with older
+ %% versions of erlydtl.
+ CompilerOptions = option(compiler_options, DtlOpts),
+
+ Sorted = proplists:unfold(
+ lists:sort(
+ [{out_dir, option(out_dir, DtlOpts)},
+ {doc_root, option(doc_root, DtlOpts)},
+ {custom_tags_dir, option(custom_tags_dir, DtlOpts)},
+ {compiler_options, CompilerOptions}
+ |CompilerOptions])),
+
%% ensure that doc_root and out_dir are defined,
%% using defaults if necessary
- Opts = [{out_dir, option(out_dir, DtlOpts)},
- {doc_root, option(doc_root, DtlOpts)},
- {custom_tags_dir, option(custom_tags_dir, DtlOpts)},
- report, return],
+ Opts = lists:ukeymerge(1, DtlOpts, Sorted),
+ ?INFO("Compiling \"~s\" -> \"~s\" with options:~n ~s~n",
+ [Source, Target, io_lib:format("~p", [Opts])]),
case erlydtl:compile(Source,
module_name(Target),
- Opts++DtlOpts) of
- ok -> ok;
- Reason ->
- ?ERROR("Compiling template ~s failed:~n ~p~n",
- [Source, Reason]),
- ?FAIL
+ Opts) of
+ ok ->
+ ok;
+ {ok, _Mod} ->
+ ok;
+ {ok, _Mod, Ws} ->
+ rebar_base_compiler:ok_tuple(Config, Source, Ws);
+ {ok, _Mod, _Bin, Ws} ->
+ rebar_base_compiler:ok_tuple(Config, Source, Ws);
+ error ->
+ rebar_base_compiler:error_tuple(Config, Source, [], [], Opts);
+ {error, {_File, _Msgs} = Error} ->
+ rebar_base_compiler:error_tuple(Config, Source, [Error], [], Opts);
+ {error, Msg} ->
+ Es = [{Source, [{erlydtl_parser, Msg}]}],
+ rebar_base_compiler:error_tuple(Config, Source, Es, [], Opts);
+ {error, Es, Ws} ->
+ rebar_base_compiler:error_tuple(Config, Source, Es, Ws, Opts)
end.
module_name(Target) ->
F = filename:basename(Target),
string:substr(F, 1, length(F)-length(".beam")).
-needs_compile(Source, Target, Config) ->
+needs_compile(Source, Target, DtlOpts) ->
LM = filelib:last_modified(Target),
LM < filelib:last_modified(Source) orelse
lists:any(fun(D) -> LM < filelib:last_modified(D) end,
- referenced_dtls(Source, Config)).
+ referenced_dtls(Source, DtlOpts)).
-referenced_dtls(Source, Config) ->
- Set = referenced_dtls1([Source], Config,
+referenced_dtls(Source, DtlOpts) ->
+ DtlOpts1 = lists:keyreplace(doc_root, 1, DtlOpts,
+ {doc_root, filename:dirname(Source)}),
+ Set = referenced_dtls1([Source], DtlOpts1,
sets:add_element(Source, sets:new())),
sets:to_list(sets:del_element(Source, Set)).
-referenced_dtls1(Step, Config, Seen) ->
- DtlOpts = erlydtl_opts(Config),
+referenced_dtls1(Step, DtlOpts, Seen) ->
ExtMatch = re:replace(option(source_ext, DtlOpts), "\.", "\\\\\\\\.",
[{return, list}]),
@@ -173,8 +259,8 @@
AllRefs =
lists:append(
[begin
- Cmd = lists:flatten(["grep -o [^\\\"]*",
- ExtMatch, " ", F]),
+ Cmd = lists:flatten(["grep -o [^\\\"]*\\",
+ ExtMatch, "[^\\\"]* ", F]),
case rebar_utils:sh(Cmd, ShOpts) of
{ok, Res} ->
string:tokens(Res, "\n");
@@ -184,10 +270,11 @@
end || F <- Step]),
DocRoot = option(doc_root, DtlOpts),
WithPaths = [ filename:join([DocRoot, F]) || F <- AllRefs ],
+ ?DEBUG("All deps: ~p\n", [WithPaths]),
Existing = [F || F <- WithPaths, filelib:is_regular(F)],
New = sets:subtract(sets:from_list(Existing), Seen),
case sets:size(New) of
0 -> Seen;
- _ -> referenced_dtls1(sets:to_list(New), Config,
+ _ -> referenced_dtls1(sets:to_list(New), DtlOpts,
sets:union(New, Seen))
end.
diff -Nru rebar-2.0.0/src/rebar_escripter.erl rebar-2.6.0/src/rebar_escripter.erl
--- rebar-2.0.0/src/rebar_escripter.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_escripter.erl 2015-06-19 16:14:28.000000000 +0000
@@ -29,6 +29,9 @@
-export([escriptize/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
-include("rebar.hrl").
-include_lib("kernel/include/file.hrl").
@@ -36,10 +39,11 @@
%% Public API
%% ===================================================================
-escriptize(Config, AppFile) ->
+escriptize(Config0, AppFile) ->
%% Extract the application name from the archive -- this is the default
%% name of the generated script
- AppName = rebar_app_utils:app_name(AppFile),
+ {Config, AppName} = rebar_app_utils:app_name(Config0, AppFile),
+ AppNameStr = atom_to_list(AppName),
%% Get the output filename for the escript -- this may include dirs
Filename = rebar_config:get_local(Config, escript_name, AppName),
@@ -51,9 +55,17 @@
InclBeams = get_app_beams(
rebar_config:get_local(Config, escript_incl_apps, []), []),
+ %% Look for a list of 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,
+ EbinPrefix = filename:join(AppNameStr, "ebin"),
+ EbinFiles = usort(load_files(EbinPrefix, "*", "ebin")),
+ ExtraFiles = usort(InclBeams ++ InclExtra),
+ Files = EbinFiles ++ ExtraFiles,
+
case zip:create("mem", Files, [memory]) of
{ok, {"mem", ZipBin}} ->
%% Archive was successfully created. Prefix that binary with our
@@ -61,7 +73,10 @@
Shebang = rebar_config:get(Config, escript_shebang,
"#!/usr/bin/env escript\n"),
Comment = rebar_config:get(Config, escript_comment, "%%\n"),
- EmuArgs = rebar_config:get(Config, escript_emu_args, "%%!\n"),
+ DefaultEmuArgs = ?FMT("%%! -pa ~s/~s/ebin\n",
+ [AppNameStr, AppNameStr]),
+ EmuArgs = rebar_config:get(Config, escript_emu_args,
+ DefaultEmuArgs),
Script = iolist_to_binary([Shebang, Comment, EmuArgs, ZipBin]),
case file:write_file(Filename, Script) of
ok ->
@@ -79,23 +94,47 @@
%% 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.
+ ok = file:change_mode(Filename, Mode bor 8#00111),
+ {ok, Config}.
-clean(Config, AppFile) ->
+clean(Config0, AppFile) ->
%% Extract the application name from the archive -- this is the default
%% name of the generated script
- AppName = rebar_app_utils:app_name(AppFile),
+ {Config, AppName} = rebar_app_utils:app_name(Config0, AppFile),
%% Get the output filename for the escript -- this may include dirs
Filename = rebar_config:get_local(Config, escript_name, AppName),
- rebar_file_utils:delete_each([Filename]).
-
+ rebar_file_utils:delete_each([Filename]),
+ {ok, Config}.
%% ===================================================================
%% Internal functions
%% ===================================================================
+info(help, escriptize) ->
+ info_help("Generate escript archive");
+info(help, clean) ->
+ info_help("Delete generated escript archive").
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n",
+ [
+ Description,
+ {escript_name, "application"},
+ {escript_incl_apps, []},
+ {escript_shebang, "#!/usr/bin/env escript\n"},
+ {escript_comment, "%%\n"},
+ {escript_emu_args, "%%! -pa application/application/ebin\n"}
+ ]).
+
get_app_beams([], Acc) ->
Acc;
get_app_beams([App | Rest], Acc) ->
@@ -104,18 +143,55 @@
?ABORT("Failed to get ebin/ directory for "
"~p escript_incl_apps.", [App]);
Path ->
- Acc2 = [{filename:join([App, ebin, F]),
- file_contents(filename:join(Path, F))} ||
- F <- filelib:wildcard("*", Path)],
+ Prefix = filename:join(atom_to_list(App), "ebin"),
+ Acc2 = load_files(Prefix, "*", Path),
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)].
+ load_files("", Wildcard, Dir).
-read_file(Filename, Dir) ->
- {Filename, file_contents(filename:join(Dir, Filename))}.
+load_files(Prefix, Wildcard, Dir) ->
+ [read_file(Prefix, Filename, Dir)
+ || Filename <- filelib:wildcard(Wildcard, Dir)].
+
+read_file(Prefix, Filename, Dir) ->
+ Filename1 = case Prefix of
+ "" ->
+ Filename;
+ _ ->
+ filename:join([Prefix, Filename])
+ end,
+ [dir_entries(filename:dirname(Filename1)),
+ {Filename1, file_contents(filename:join(Dir, Filename))}].
file_contents(Filename) ->
{ok, Bin} = file:read_file(Filename),
Bin.
+
+%% Given a filename, return zip archive dir entries for each sub-dir.
+%% Required to work around issues fixed in OTP-10071.
+dir_entries(File) ->
+ Dirs = dirs(File),
+ [{Dir ++ "/", <<>>} || Dir <- Dirs].
+
+%% Given "foo/bar/baz", return ["foo", "foo/bar", "foo/bar/baz"].
+dirs(Dir) ->
+ dirs1(filename:split(Dir), "", []).
+
+dirs1([], _, Acc) ->
+ lists:reverse(Acc);
+dirs1([H|T], "", []) ->
+ dirs1(T, H, [H]);
+dirs1([H|T], Last, Acc) ->
+ Dir = filename:join(Last, H),
+ dirs1(T, Dir, [Dir|Acc]).
+
+usort(List) ->
+ lists:ukeysort(1, lists:flatten(List)).
diff -Nru rebar-2.0.0/src/rebar_eunit.erl rebar-2.6.0/src/rebar_eunit.erl
--- rebar-2.0.0/src/rebar_eunit.erl 2012-06-04 14:56:51.000000000 +0000
+++ rebar-2.6.0/src/rebar_eunit.erl 2015-06-19 16:14:28.000000000 +0000
@@ -28,7 +28,7 @@
%% @doc rebar_eunit supports the following commands:
%%
%% - eunit - runs eunit tests
-%% - clean - remove .eunit directory
+%% - clean - remove ?EUNIT_DIR directory
%% - reset_after_eunit::boolean() - default = true.
%% If true, try to "reset" VM state to approximate state prior to
%% running the EUnit tests:
@@ -43,12 +43,25 @@
%% The following Global options are supported:
%%
%% - verbose=1 - show extra output from the eunit test
-%% - suite="foo"" - runs test/foo_tests.erl
+%% -
+%% suites="foo,bar" - runs tests in foo.erl, test/foo_tests.erl and
+%% tests in bar.erl, test/bar_tests.erl
+%%
+%% -
+%% suites="foo,bar" tests="baz"- runs first test with name starting
+%% with 'baz' in foo.erl, test/foo_tests.erl and tests in bar.erl,
+%% test/bar_tests.erl
+%%
+%% -
+%% tests="baz"- For every existing suite, run the first test whose
+%% name starts with bar and, if no such test exists, run the test
+%% whose name starts with bar in the suite's _tests module
+%%
%%
%% Additionally, for projects that have separate folders for the core
%% implementation, and for the unit tests, then the following
%% rebar.config
option can be provided:
-%% {eunit_compile_opts, [{src_dirs, ["dir"]}]}.
.
+%% {eunit_compile_opts, [{src_dirs, ["src", "dir"]}]}.
.
%% @copyright 2009, 2010 Dave Smith
%% -------------------------------------------------------------------
-module(rebar_eunit).
@@ -56,6 +69,11 @@
-export([eunit/2,
clean/2]).
+%% for internal use only
+-export([info/2]).
+
+-dialyzer({no_missing_calls, pre15b02_eunit_primitive/3}).
+
-include("rebar.hrl").
-define(EUNIT_DIR, ".eunit").
@@ -65,81 +83,96 @@
%% ===================================================================
eunit(Config, _AppFile) ->
- %% Make sure ?EUNIT_DIR/ and ebin/ directory exists (tack on dummy module)
- ok = filelib:ensure_dir(eunit_dir() ++ "/foo"),
- ok = filelib:ensure_dir(ebin_dir() ++ "/foo"),
-
- %% Setup code path prior to compilation so that parse_transforms
- %% and the like work properly. Also, be sure to add ebin_dir()
- %% to the END of the code path so that we don't have to jump
- %% through hoops to access the .app file
- CodePath = code:get_path(),
- true = code:add_patha(eunit_dir()),
- true = code:add_pathz(ebin_dir()),
-
- %% Obtain all the test modules for inclusion in the compile stage.
- %% Notice: this could also be achieved with the following
- %% rebar.config option: {eunit_compile_opts, [{src_dirs, ["test"]}]}
- TestErls = rebar_utils:find_files("test", ".*\\.erl\$"),
-
- %% 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\$"),
-
- %% 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
- %% the source files as being read only (unless they are checked out), we
- %% need to be sure that the files already present in ?EUNIT_DIR are writable
- %% before doing the copy. This is done here by removing any file that was
- %% already present before calling rebar_file_utils:cp_r.
-
- %% Get the full path to a file that was previously copied in ?EUNIT_DIR
- ToCleanUp = fun(F, Acc) ->
- F2 = filename:basename(F),
- F3 = filename:join([?EUNIT_DIR, F2]),
- case filelib:is_regular(F3) of
- true -> [F3|Acc];
- false -> Acc
- end
- end,
+ ok = ensure_dirs(),
+ %% Save code path
+ CodePath = setup_code_path(),
+ CompileOnly = rebar_config:get_global(Config, compile_only, false),
+ {ok, SrcErls} = rebar_erlc_compiler:test_compile(Config, "eunit",
+ ?EUNIT_DIR),
+ case CompileOnly of
+ "true" ->
+ true = rebar_utils:cleanup_code_path(CodePath),
+ ?CONSOLE("Compiled modules for eunit~n", []);
+ false ->
+ run_eunit(Config, CodePath, SrcErls)
+ end.
- ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], TestErls)),
- ok = rebar_file_utils:delete_each(lists:foldl(ToCleanUp, [], SrcErls)),
+clean(_Config, _File) ->
+ rebar_file_utils:rm_rf(?EUNIT_DIR).
- ok = rebar_file_utils:cp_r(SrcErls ++ TestErls, ?EUNIT_DIR),
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
- %% Compile erlang code to ?EUNIT_DIR, using a tweaked config
- %% with appropriate defines for eunit, and include all the test modules
- %% as well.
- rebar_erlc_compiler:doterl_compile(eunit_config(Config),
- ?EUNIT_DIR, TestErls),
+info(help, eunit) ->
+ info_help("Run eunit tests");
+info(help, clean) ->
+ Description = ?FMT("Delete eunit test dir (~s)", [?EUNIT_DIR]),
+ info_help(Description).
+
+info_help(Description) ->
+ ?CONSOLE(
+ "~s.~n"
+ "~n"
+ "Valid rebar.config options:~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ " ~p~n"
+ "Valid command line options:~n"
+ " suite[s]=\"foo,bar\" (Run tests in foo.erl, test/foo_tests.erl and~n"
+ " tests in bar.erl, test/bar_tests.erl)~n"
+ " test[s]=\"baz\" (For every existing suite, run the first test whose~n"
+ " name starts with bar and, if no such test exists,~n"
+ " run the test whose name starts with bar in the~n"
+ " suite's _tests module)~n"
+ " random_suite_order=true (Run tests in random order)~n"
+ " random_suite_order=Seed (Run tests in random order,~n"
+ " with the PRNG seeded with Seed)~n"
+ " compile_only=true (Compile but do not run tests)",
+ [
+ Description,
+ {eunit_opts, []},
+ {eunit_compile_opts, []},
+ {eunit_first_files, []},
+ {cover_enabled, false},
+ {cover_print_enabled, false},
+ {cover_export_enabled, false}
+ ]).
+run_eunit(Config, CodePath, SrcErls) ->
%% Build a list of all the .beams in ?EUNIT_DIR -- use this for
%% cover and eunit testing. Normally you can just tell cover
%% and/or eunit to scan the directory for you, but eunit does a
%% code:purge in conjunction with that scan and causes any cover
- %% compilation info to be lost. Filter out "*_tests" modules so
- %% eunit won't doubly run them and so cover only calculates
- %% coverage on production code. However, keep "*_tests" modules
- %% that are not automatically included by eunit.
+ %% compilation info to be lost.
+
AllBeamFiles = rebar_utils:beams(?EUNIT_DIR),
{BeamFiles, TestBeamFiles} =
lists:partition(fun(N) -> string:str(N, "_tests.beam") =:= 0 end,
AllBeamFiles),
OtherBeamFiles = TestBeamFiles --
[filename:rootname(N) ++ "_tests.beam" || N <- AllBeamFiles],
- ModuleBeamFiles = BeamFiles ++ OtherBeamFiles,
- Modules = [rebar_utils:beam_to_mod(?EUNIT_DIR, N) || N <- ModuleBeamFiles],
+ ModuleBeamFiles = randomize_suites(Config, BeamFiles ++ OtherBeamFiles),
+
+ %% Get matching tests and modules
+ AllModules = [rebar_utils:beam_to_mod(?EUNIT_DIR, N) || N <- AllBeamFiles],
+ {Tests, FilteredModules} =
+ get_tests_and_modules(Config, ModuleBeamFiles, AllModules),
+
SrcModules = [rebar_utils:erl_to_mod(M) || M <- SrcErls],
- {ok, CoverLog} = cover_init(Config, ModuleBeamFiles),
+ {ok, CoverLog} = rebar_cover_utils:init(Config, ModuleBeamFiles,
+ eunit_dir()),
StatusBefore = status_before_eunit(),
- EunitResult = perform_eunit(Config, Modules),
- perform_cover(Config, Modules, SrcModules),
+ EunitResult = perform_eunit(Config, Tests),
- cover_close(CoverLog),
+ rebar_cover_utils:perform_cover(Config, FilteredModules, SrcModules,
+ eunit_dir()),
+ rebar_cover_utils:close(CoverLog),
case proplists:get_value(reset_after_eunit, get_eunit_opts(Config),
true) of
@@ -149,6 +182,10 @@
ok
end,
+ %% Stop cover to clean the cover_server state. This is important if we want
+ %% eunit+cover to not slow down when analyzing many Erlang modules.
+ ok = rebar_cover_utils:exit(),
+
case EunitResult of
ok ->
ok;
@@ -157,26 +194,289 @@
end,
%% Restore code path
- true = code:set_path(CodePath),
+ true = rebar_utils:cleanup_code_path(CodePath),
ok.
-clean(_Config, _File) ->
- rebar_file_utils:rm_rf(?EUNIT_DIR).
-
-%% ===================================================================
-%% Internal functions
-%% ===================================================================
+ensure_dirs() ->
+ %% Make sure ?EUNIT_DIR/ and ebin/ directory exists (append dummy module)
+ ok = filelib:ensure_dir(filename:join(eunit_dir(), "dummy")),
+ ok = filelib:ensure_dir(filename:join(rebar_utils:ebin_dir(), "dummy")).
eunit_dir() ->
filename:join(rebar_utils:get_cwd(), ?EUNIT_DIR).
-ebin_dir() ->
- filename:join(rebar_utils:get_cwd(), "ebin").
+setup_code_path() ->
+ %% Setup code path prior to compilation so that parse_transforms
+ %% and the like work properly. Also, be sure to add ebin_dir()
+ %% to the END of the code path so that we don't have to jump
+ %% through hoops to access the .app file
+ CodePath = code:get_path(),
+ true = code:add_patha(eunit_dir()),
+ true = code:add_pathz(rebar_utils:ebin_dir()),
+ CodePath.
+
+%%
+%% == get matching tests ==
+%%
+get_tests_and_modules(Config, ModuleBeamFiles, AllModules) ->
+ SelectedSuites = get_selected_suites(Config, AllModules),
+ {Tests, QualifiedTests} = get_qualified_and_unqualified_tests(Config),
+ Modules = get_test_modules(SelectedSuites, Tests,
+ QualifiedTests, ModuleBeamFiles),
+ FilteredModules = get_matching_modules(AllModules, Modules, QualifiedTests),
+ MatchedTests = get_matching_tests(Modules, Tests, QualifiedTests),
+ {MatchedTests, FilteredModules}.
+
+%%
+%% == get suites specified via 'suites' option ==
+%%
+get_selected_suites(Config, Modules) ->
+ RawSuites = get_suites(Config),
+ Suites = [list_to_atom(Suite) || Suite <- string:tokens(RawSuites, ",")],
+ [M || M <- Suites, lists:member(M, Modules)].
+
+get_suites(Config) ->
+ case rebar_config:get_global(Config, suites, "") of
+ "" ->
+ rebar_config:get_global(Config, suite, "");
+ Suites ->
+ Suites
+ end.
+
+get_qualified_and_unqualified_tests(Config) ->
+ RawFunctions = rebar_config:get_global(Config, tests, ""),
+ FunctionNames = [FunctionName ||
+ FunctionName <- string:tokens(RawFunctions, ",")],
+ get_qualified_and_unqualified_tests1(FunctionNames, [], []).
+
+get_qualified_and_unqualified_tests1([], Functions, QualifiedFunctions) ->
+ {Functions, QualifiedFunctions};
+get_qualified_and_unqualified_tests1([TestName|TestNames], Functions,
+ QualifiedFunctions) ->
+ case string:tokens(TestName, ":") of
+ [TestName] ->
+ Function = list_to_atom(TestName),
+ get_qualified_and_unqualified_tests1(
+ TestNames, [Function|Functions], QualifiedFunctions);
+ [ModuleName, FunctionName] ->
+ M = list_to_atom(ModuleName),
+ F = list_to_atom(FunctionName),
+ get_qualified_and_unqualified_tests1(TestNames, Functions,
+ [{M, F}|QualifiedFunctions]);
+ _ ->
+ ?ABORT("Unsupported test function specification: ~s~n", [TestName])
+ end.
+
+%% Provide modules which are to be searched for tests.
+%% Several scenarios are possible:
+%%
+%% == randomize suites ==
+%%
+
+randomize_suites(Config, Modules) ->
+ case rebar_config:get_global(Config, random_suite_order, undefined) of
+ undefined ->
+ Modules;
+ "true" ->
+ Seed = crypto:rand_uniform(1, 65535),
+ randomize_suites1(Modules, Seed);
+ String ->
+ try list_to_integer(String) of
+ Seed ->
+ randomize_suites1(Modules, Seed)
+ catch
+ error:badarg ->
+ ?ERROR("Bad random seed provided: ~p~n", [String]),
+ ?FAIL
+ end
+ end.
+
+randomize_suites1(Modules, Seed) ->
+ _ = random:seed(35, Seed, 1337),
+ ?CONSOLE("Randomizing suite order with seed ~b~n", [Seed]),
+ [X||{_,X} <- lists:sort([{random:uniform(), M} || M <- Modules])].
+
+%%
+%% == get matching tests ==
+%% 1) Specific tests have been provided and/or
+%% no unqualified tests have been specified and
+%% there were some qualified tests, then we can search for
+%% functions in specified suites (or in empty set of suites).
+%%
+%% 2) Neither specific suites nor qualified test names have been
+%% provided use ModuleBeamFiles which filters out "*_tests"
+%% modules so EUnit won't doubly run them and cover only
+%% calculates coverage on production code. However,
+%% keep "*_tests" modules that are not automatically
+%% included by EUnit.
+%%
+%% From 'Primitives' in the EUnit User's Guide
+%% http://www.erlang.org/doc/apps/eunit/chapter.html
+%% "In addition, EUnit will also look for another
+%% module whose name is ModuleName plus the suffix
+%% _tests, and if it exists, all the tests from that
+%% module will also be added. (If ModuleName already
+%% contains the suffix _tests, this is not done.) E.g.,
+%% the specification {module, mymodule} will run all
+%% tests in the modules mymodule and mymodule_tests.
+%% Typically, the _tests module should only contain
+%% test cases that use the public interface of the main
+%% module (and no other code)."
+get_test_modules(SelectedSuites, Tests, QualifiedTests, ModuleBeamFiles) ->
+ SuitesProvided = SelectedSuites =/= [],
+ OnlyQualifiedTestsProvided = QualifiedTests =/= [] andalso Tests =:= [],
+ if
+ SuitesProvided orelse OnlyQualifiedTestsProvided ->
+ SelectedSuites;
+ true ->
+ [rebar_utils:beam_to_mod(?EUNIT_DIR, N) ||
+ N <- ModuleBeamFiles]
+ end.
+
+get_matching_modules(AllModules, Modules, QualifiedTests) ->
+ ModuleFilterMapper =
+ fun({M, _}) ->
+ case lists:member(M, AllModules) of
+ true -> {true, M};
+ _-> false
+ end
+ end,
+ ModulesFromQualifiedTests = lists:zf(ModuleFilterMapper, QualifiedTests),
+ lists:usort(Modules ++ ModulesFromQualifiedTests).
+
+get_matching_tests(Modules, [], []) ->
+ Modules;
+get_matching_tests(Modules, [], QualifiedTests) ->
+ FilteredQualifiedTests = filter_qualified_tests(Modules, QualifiedTests),
+ lists:merge(Modules, make_test_primitives(FilteredQualifiedTests));
+get_matching_tests(Modules, Tests, QualifiedTests) ->
+ AllTests = lists:merge(QualifiedTests,
+ get_matching_tests1(Modules, Tests, [])),
+ make_test_primitives(AllTests).
+
+filter_qualified_tests(Modules, QualifiedTests) ->
+ TestsFilter = fun({Module, _Function}) ->
+ lists:all(fun(M) -> M =/= Module end, Modules) end,
+ lists:filter(TestsFilter, QualifiedTests).
+
+get_matching_tests1([], _Functions, TestFunctions) ->
+ TestFunctions;
+
+get_matching_tests1([Module|TModules], Functions, TestFunctions) ->
+ %% Get module exports
+ ModuleStr = atom_to_list(Module),
+ ModuleExports = get_beam_test_exports(ModuleStr),
+ %% Get module _tests exports
+ TestModuleStr = string:concat(ModuleStr, "_tests"),
+ TestModuleExports = get_beam_test_exports(TestModuleStr),
+ %% Build tests {M, F} list
+ Tests = get_matching_tests2(Functions, {Module, ModuleExports},
+ {list_to_atom(TestModuleStr),
+ TestModuleExports}),
+ get_matching_tests1(TModules, Functions,
+ lists:merge([TestFunctions, Tests])).
+
+get_matching_tests2(Functions, {Mod, ModExports}, {TestMod, TestModExports}) ->
+ %% Look for matching functions into ModExports
+ ModExportsStr = [atom_to_list(E1) || E1 <- ModExports],
+ TestModExportsStr = [atom_to_list(E2) || E2 <- TestModExports],
+ get_matching_exports(Functions, {Mod, ModExportsStr},
+ {TestMod, TestModExportsStr}, []).
+
+get_matching_exports([], _, _, Matched) ->
+ Matched;
+get_matching_exports([Function|TFunctions], {Mod, ModExportsStr},
+ {TestMod, TestModExportsStr}, Matched) ->
+
+ FunctionStr = atom_to_list(Function),
+ %% Get matching Function in module, otherwise look in _tests module
+ NewMatch = case get_matching_export(FunctionStr, ModExportsStr) of
+ [] ->
+ {TestMod, get_matching_export(FunctionStr,
+ TestModExportsStr)};
+ MatchingExport ->
+ {Mod, MatchingExport}
+ end,
+ case NewMatch of
+ {_, []} ->
+ get_matching_exports(TFunctions, {Mod, ModExportsStr},
+ {TestMod, TestModExportsStr}, Matched);
+ _ ->
+ get_matching_exports(TFunctions, {Mod, ModExportsStr},
+ {TestMod, TestModExportsStr},
+ [NewMatch|Matched])
+ end.
+
+get_matching_export(_FunctionStr, []) ->
+ [];
+get_matching_export(FunctionStr, [ExportStr|TExportsStr]) ->
+ case string:str(ExportStr, FunctionStr) of
+ 1 ->
+ list_to_atom(ExportStr);
+ _ ->
+ get_matching_export(FunctionStr, TExportsStr)
+ end.
+
+get_beam_test_exports(ModuleStr) ->
+ FilePath = filename:join(eunit_dir(),
+ string:concat(ModuleStr, ".beam")),
+ case filelib:is_regular(FilePath) of
+ true ->
+ {beam_file, _, Exports0, _, _, _} = beam_disasm:file(FilePath),
+ Exports1 = [FunName || {FunName, FunArity, _} <- Exports0,
+ FunArity =:= 0],
+ F = fun(FName) ->
+ FNameStr = atom_to_list(FName),
+ re:run(FNameStr, "_test(_)?") =/= nomatch
+ end,
+ lists:filter(F, Exports1);
+ _ ->
+ []
+ end.
+
+make_test_primitives(RawTests) ->
+ %% Use {test,M,F} and {generator,M,F} if at least R15B02. Otherwise,
+ %% use eunit_test:function_wrapper/2 fallback.
+ %% eunit_test:function_wrapper/2 was renamed to eunit_test:mf_wrapper/2
+ %% in R15B02; use that as >= R15B02 check.
+ %% TODO: remove fallback and use only {test,M,F} and {generator,M,F}
+ %% primitives once at least R15B02 is required.
+ {module, eunit_test} = code:ensure_loaded(eunit_test),
+ MakePrimitive = case erlang:function_exported(eunit_test, mf_wrapper, 2) of
+ true -> fun eunit_primitive/3;
+ false -> fun pre15b02_eunit_primitive/3
+ end,
+
+ ?CONSOLE(" Running test function(s):~n", []),
+ F = fun({M, F2}, Acc) ->
+ ?CONSOLE(" ~p:~p/0~n", [M, F2]),
+ FNameStr = atom_to_list(F2),
+ NewFunction =
+ case re:run(FNameStr, "_test_") of
+ nomatch ->
+ %% Normal test
+ MakePrimitive(test, M, F2);
+ _ ->
+ %% Generator
+ MakePrimitive(generator, M, F2)
+ end,
+ [NewFunction|Acc]
+ end,
+ lists:foldl(F, [], RawTests).
+
+eunit_primitive(Type, M, F) ->
+ {Type, M, F}.
+
+pre15b02_eunit_primitive(test, M, F) ->
+ eunit_test:function_wrapper(M, F);
+pre15b02_eunit_primitive(generator, M, F) ->
+ {generator, eunit_test:function_wrapper(M, F)}.
-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),
+%%
+%% == run tests ==
+%%
+
+perform_eunit(Config, Tests) ->
EunitOpts = get_eunit_opts(Config),
%% Move down into ?EUNIT_DIR while we run tests so any generated files
@@ -184,22 +484,16 @@
Cwd = rebar_utils:get_cwd(),
ok = file:set_cwd(?EUNIT_DIR),
- EunitResult = perform_eunit(EunitOpts, Modules, Suite),
+ EunitResult = (catch eunit:test(Tests, 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
+ BaseOpts = case rebar_log:is_verbose(Config) of
true ->
[verbose];
false ->
@@ -208,260 +502,18 @@
BaseOpts ++ rebar_config:get_list(Config, eunit_opts, []).
-eunit_config(Config) ->
- EqcOpts = eqc_opts(),
- PropErOpts = proper_opts(),
-
- ErlOpts = rebar_config:get_list(Config, erl_opts, []),
- EunitOpts = rebar_config:get_list(Config, eunit_compile_opts, []),
- Opts0 = [{d, 'TEST'}] ++
- ErlOpts ++ EunitOpts ++ EqcOpts ++ PropErOpts,
- Opts = [O || O <- Opts0, O =/= no_debug_info],
- Config1 = rebar_config:set(Config, erl_opts, Opts),
-
- FirstErls = rebar_config:get_list(Config1, eunit_first_files, []),
- rebar_config:set(Config1, erl_first_files, FirstErls).
-
-eqc_opts() ->
- define_if('EQC', is_lib_avail(is_eqc_avail, eqc,
- "eqc.hrl", "QuickCheck")).
-
-proper_opts() ->
- define_if('PROPER', is_lib_avail(is_proper_avail, proper,
- "proper.hrl", "PropEr")).
-
-define_if(Def, true) -> [{d, Def}];
-define_if(_Def, false) -> [].
-
-is_lib_avail(DictKey, Mod, Hrl, Name) ->
- case erlang:get(DictKey) of
- undefined ->
- IsAvail = case code:lib_dir(Mod, include) of
- {error, bad_name} ->
- false;
- Dir ->
- filelib:is_regular(filename:join(Dir, Hrl))
- end,
- erlang:put(DictKey, IsAvail),
- ?DEBUG("~s availability: ~p\n", [Name, IsAvail]),
- IsAvail;
- IsAvail ->
- IsAvail
- end.
-
-perform_cover(Config, BeamFiles, SrcModules) ->
- perform_cover(rebar_config:get(Config, cover_enabled, false),
- Config, BeamFiles, SrcModules).
-
-perform_cover(false, _Config, _BeamFiles, _SrcModules) ->
- ok;
-perform_cover(true, Config, BeamFiles, SrcModules) ->
- cover_analyze(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,
-
- %% Generate coverage info for all the cover-compiled modules
- Coverage = lists:flatten([cover_analyze_mod(M) || M <- FilteredModules]),
-
- %% Write index of coverage info
- cover_write_index(lists:sort(Coverage), SrcModules),
-
- %% Write coverage details for each file
- lists:foreach(fun({M, _, _}) ->
- {ok, _} = cover:analyze_to_file(M, cover_file(M),
- [html])
- end, Coverage),
-
- Index = filename:join([rebar_utils:get_cwd(), ?EUNIT_DIR, "index.html"]),
- ?CONSOLE("Cover analysis: ~s\n", [Index]),
-
- %% Print coverage report, if configured
- case rebar_config:get(Config, cover_print_enabled, false) of
- true ->
- cover_print_coverage(lists:sort(Coverage));
- false ->
- ok
- end.
-
-cover_close(not_enabled) ->
- ok;
-cover_close(F) ->
- ok = file:close(F).
-
-cover_init(false, _BeamFiles) ->
- {ok, not_enabled};
-cover_init(true, BeamFiles) ->
- %% Attempt to start the cover server, then set it's group leader to
- %% .eunit/cover.log, so all cover log messages will go there instead of
- %% to stdout. If the cover server is already started we'll reuse that
- %% pid.
- {ok, CoverPid} = case cover:start() of
- {ok, _P} = OkStart ->
- OkStart;
- {error,{already_started, P}} ->
- {ok, P};
- {error, _Reason} = ErrorStart ->
- ErrorStart
- end,
-
- {ok, F} = OkOpen = file:open(
- filename:join([?EUNIT_DIR, "cover.log"]),
- [write]),
-
- group_leader(F, CoverPid),
-
- %% Make sure any previous runs of cover don't unduly influence
- cover:reset(),
-
- ?INFO("Cover compiling ~s\n", [rebar_utils:get_cwd()]),
-
- Compiled = [{Beam, cover:compile_beam(Beam)} || Beam <- BeamFiles],
- case [Module || {_, {ok, Module}} <- Compiled] of
- [] ->
- %% No modules compiled successfully...fail
- ?ERROR("Cover failed to compile any modules; aborting.~n", []),
- ?FAIL;
- _ ->
- %% At least one module compiled successfully
-
- %% It's not an error for cover compilation to fail partially,
- %% but we do want to warn about them
- PrintWarning =
- fun(Beam, Desc) ->
- ?CONSOLE("Cover compilation warning for ~p: ~p",
- [Beam, Desc])
- end,
- _ = [PrintWarning(Beam, Desc) || {Beam, {error, Desc}} <- Compiled],
- OkOpen
- end;
-cover_init(Config, BeamFiles) ->
- cover_init(rebar_config:get(Config, cover_enabled, false), BeamFiles).
-
-cover_analyze_mod(Module) ->
- case cover:analyze(Module, coverage, module) of
- {ok, {Module, {Covered, NotCovered}}} ->
- %% Modules that include the eunit header get an implicit
- %% test/0 fun, which cover considers a runnable line, but
- %% eunit:test(TestRepresentation) never calls. Decrement
- %% NotCovered in this case.
- [align_notcovered_count(Module, Covered, NotCovered,
- is_eunitized(Module))];
- {error, Reason} ->
- ?ERROR("Cover analyze failed for ~p: ~p ~p\n",
- [Module, Reason, code:which(Module)]),
- []
- end.
-
-is_eunitized(Mod) ->
- has_eunit_test_fun(Mod) andalso
- has_header(Mod, "include/eunit.hrl").
-
-has_eunit_test_fun(Mod) ->
- [F || {exports, Funs} <- Mod:module_info(),
- {F, 0} <- Funs, F =:= test] =/= [].
-
-has_header(Mod, Header) ->
- Mod1 = case code:which(Mod) of
- cover_compiled ->
- {file, File} = cover:is_compiled(Mod),
- File;
- non_existing -> Mod;
- preloaded -> Mod;
- L -> L
- end,
- {ok, {_, [{abstract_code, {_, AC}}]}} = beam_lib:chunks(Mod1,
- [abstract_code]),
- [F || {attribute, 1, file, {F, 1}} <- AC,
- string:str(F, Header) =/= 0] =/= [].
-
-align_notcovered_count(Module, Covered, NotCovered, false) ->
- {Module, Covered, NotCovered};
-align_notcovered_count(Module, Covered, NotCovered, true) ->
- {Module, Covered, NotCovered - 1}.
-
-cover_write_index(Coverage, SrcModules) ->
- {ok, F} = file:open(filename:join([?EUNIT_DIR, "index.html"]), [write]),
- ok = file:write(F, "Coverage Summary\n"),
- IsSrcCoverage = fun({Mod,_C,_N}) -> lists:member(Mod, SrcModules) end,
- {SrcCoverage, TestCoverage} = lists:partition(IsSrcCoverage, Coverage),
- cover_write_index_section(F, "Source", SrcCoverage),
- cover_write_index_section(F, "Test", TestCoverage),
- ok = file:write(F, "