File rebar-2.6.1-git.patch of Package rebar
diff --git a/.travis.yml b/.travis.yml
index 9494ca9..e4a3149 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,7 @@ otp_release:
- R14B04
- R14B03
- 17.0
+ - 18.0
before_script:
- hostname -f
- cc -v
diff --git a/README.md b/README.md
index ec65693..54e6ad1 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
+**rebar is deprecated and will receive only bug fixes. We encourage you to move to [rebar3](https://github.com/erlang/rebar3).**
+
+----
+
rebar
=====
@@ -5,6 +9,7 @@ rebar is an Erlang build tool that makes it easy to compile and test Erlang
applications, port drivers and releases.
[](http://travis-ci.org/rebar/rebar)
+[](https://ci.appveyor.com/project/rebar-win-ci/rebar-t0g71)
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
diff --git a/THANKS b/THANKS
index 582a153..ab7935c 100644
--- a/THANKS
+++ b/THANKS
@@ -145,3 +145,8 @@ James Fish
Tony Rogvall
Andrey Teplyashin
Duncan McGreggor
+Sebastien Serre
+John Daily
+Yury Gargay
+Frank Hunleth
+Matwey Kornilov
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..59b9570
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,24 @@
+version: 2.6.1.{build}
+clone_depth: 1
+build_script:
+- cmd: >-
+ bootstrap.bat
+
+ set REBAR_EXTRA_DEPS=1
+
+ .\rebar get-deps
+
+ copy rebar deps\retest
+
+ copy rebar.cmd deps\retest
+
+ cd deps\retest & .\rebar compile escriptize
+test_script:
+- cmd: >-
+ rebar eunit
+
+ "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
+
+ cd deps\retest & retest -l debug -t 120000 ..\..\inttest
+artifacts:
+- path: rebar
diff --git a/inttest/app_src/app_src_rt.erl b/inttest/app_src/app_src_rt.erl
index d71f03e..2b5a87e 100644
--- a/inttest/app_src/app_src_rt.erl
+++ b/inttest/app_src/app_src_rt.erl
@@ -30,9 +30,14 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
- {create, "src/app_src.app.src", app(app_src)}].
+ [
+ {create, "src/app_src.app.src", app(app_src)}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/app_src_script/app_src_script_rt.erl b/inttest/app_src_script/app_src_script_rt.erl
index 4c00ec8..c0de128 100644
--- a/inttest/app_src_script/app_src_script_rt.erl
+++ b/inttest/app_src_script/app_src_script_rt.erl
@@ -30,9 +30,14 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
- {create, "src/app_src_script.app.src.script", app_script(app_src_script)}].
+ [
+ {create, "src/app_src_script.app.src.script", app_script(app_src_script)}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/app_src_script_2/app_src_script_2_rt.erl b/inttest/app_src_script_2/app_src_script_2_rt.erl
index 1bf59d1..613e3f9 100644
--- a/inttest/app_src_script_2/app_src_script_2_rt.erl
+++ b/inttest/app_src_script_2/app_src_script_2_rt.erl
@@ -30,10 +30,15 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
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)}].
+ {create, "src/app_src_script_2.app.src", app(app_src_script_2)}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/appup_src/appup_src_rt.erl b/inttest/appup_src/appup_src_rt.erl
index 2ca6788..7530aa4 100644
--- a/inttest/appup_src/appup_src_rt.erl
+++ b/inttest/appup_src/appup_src_rt.erl
@@ -30,9 +30,14 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
- {copy, "src", "src"}].
+ [
+ {copy, "src", "src"}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/appup_src_2/appup_src_2_rt.erl b/inttest/appup_src_2/appup_src_2_rt.erl
index 09d2503..99e6248 100644
--- a/inttest/appup_src_2/appup_src_2_rt.erl
+++ b/inttest/appup_src_2/appup_src_2_rt.erl
@@ -30,9 +30,14 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
- {copy, "src", "src"}].
+ [
+ {copy, "src", "src"}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/appup_src_2/appup_src_rt_2.erl b/inttest/appup_src_2/appup_src_rt_2.erl
index d662183..fff6f62 100644
--- a/inttest/appup_src_2/appup_src_rt_2.erl
+++ b/inttest/appup_src_2/appup_src_rt_2.erl
@@ -30,9 +30,13 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
- {copy, "src", "src"}].
+ [{copy, "src", "src"}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/appup_src_script/appup_src_script_rt.erl b/inttest/appup_src_script/appup_src_script_rt.erl
index c98e54e..1aeb680 100644
--- a/inttest/appup_src_script/appup_src_script_rt.erl
+++ b/inttest/appup_src_script/appup_src_script_rt.erl
@@ -30,9 +30,14 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
- {copy, "src", "src"}].
+ [
+ {copy, "src", "src"}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/bug_5_rt.erl b/inttest/bug_5_rt.erl
index 8894cb5..f198d40 100644
--- a/inttest/bug_5_rt.erl
+++ b/inttest/bug_5_rt.erl
@@ -4,20 +4,21 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
files() ->
[{create, "ebin/a1.app", app(a1)},
{create, "deps/d1/src/d1.app.src", app(d1)},
{create, "rebar.config",
- <<"{deps, [{d1, \"1\", {hg, \"http://example.com\", \"tip\"}}]}.\n">>},
- {copy, "../rebar", "rebar"}].
+ <<"{deps, [{d1, \"1\", {hg, \"http://example.com\", \"tip\"}}]}.\n">>}
+ ] ++ inttest_utils:rebar_setup("..").
run(_Dir) ->
{ok, _} = retest:sh("./rebar compile"),
ok.
-
-
%%
%% Generate the contents of a simple .app file
%%
diff --git a/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl b/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl
index 74d035e..a2ca980 100644
--- a/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl
+++ b/inttest/code_path_no_recurse/code_path_no_recurse_rt.erl
@@ -28,14 +28,17 @@
-export([files/0,
run/1]).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "src", "src"},
{copy, "test", "test"},
{copy, "deps", "deps"}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
retest:log(info, "Compile project~n"),
diff --git a/inttest/cover/cover_rt.erl b/inttest/cover/cover_rt.erl
index a9f3f08..3f5e485 100644
--- a/inttest/cover/cover_rt.erl
+++ b/inttest/cover/cover_rt.erl
@@ -30,13 +30,18 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{create, "ebin/foo.app", app(foo)},
- {copy, "../../rebar","rebar"},
+ [
+ {create, "ebin/foo.app", app(foo)},
{copy, "src", "src"},
{copy,
"rebar-cover_export_json.config",
- "rebar-cover_export_json.config"}].
+ "rebar-cover_export_json.config"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
ifdef_test(),
diff --git a/inttest/cross1/c_src/test1.c b/inttest/cross1/c_src/test1.c
new file mode 100644
index 0000000..4073ed6
--- /dev/null
+++ b/inttest/cross1/c_src/test1.c
@@ -0,0 +1 @@
+#include "test1.h"
diff --git a/inttest/cross1/c_src/test1.h b/inttest/cross1/c_src/test1.h
new file mode 100644
index 0000000..e69de29
diff --git a/inttest/cross1/cross1_rt.erl b/inttest/cross1/cross1_rt.erl
new file mode 100644
index 0000000..297f353
--- /dev/null
+++ b/inttest/cross1/cross1_rt.erl
@@ -0,0 +1,66 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2016 Luis Rascao
+%%
+%% 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(cross1_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+files() ->
+ [
+ {copy, "c_src", "c_src"},
+ {create, "ebin/foo.app", app(foo, [])}
+ ] ++ inttest_utils:rebar_setup().
+
+run(_Dir) ->
+ %% we will now determine where gcc is located
+ %% create a symlink to it in the cwd and change the
+ %% rebar arch so that rebar is fooled into believing
+ %% it's doing cross compilation.
+ {ok, [_, GccLocation]} = retest_sh:run("which gcc", []),
+ {ok, _} = retest_sh:run(io_lib:format("ln -s ~s unknown-unknown-linux-gnu-gcc", [GccLocation]),
+ []),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar compile -vvv",
+ [{env, [{"PATH", "./:" ++ os:getenv("PATH")},
+ {"REBAR_TARGET_ARCH", "unknown-unknown-linux-gnu"}]}])).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/ct1/ct1_rt.erl b/inttest/ct1/ct1_rt.erl
index dc83095..03b4ed8 100644
--- a/inttest/ct1/ct1_rt.erl
+++ b/inttest/ct1/ct1_rt.erl
@@ -4,21 +4,23 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
files() ->
- [{create, "ebin/a1.app", app(a1)},
- {copy, "../../rebar", "rebar"},
+ [
+ {create, "ebin/a1.app", app(a1)},
{copy, "rebar.config", "rebar.config"},
{copy, "app.config", "app.config"},
- {copy, "test_SUITE.erl", "itest/test_SUITE.erl"}].
+ {copy, "test_SUITE.erl", "itest/test_SUITE.erl"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
{ok, _} = retest:sh("./rebar compile ct"),
{ok, _} = retest:sh("./rebar compile ct -v"),
ok.
-
-
%%
%% Generate the contents of a simple .app file
%%
diff --git a/inttest/ct2/ct2_rt.erl b/inttest/ct2/ct2_rt.erl
index f9d2b19..b3138d4 100644
--- a/inttest/ct2/ct2_rt.erl
+++ b/inttest/ct2/ct2_rt.erl
@@ -4,13 +4,17 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
files() ->
- [{create, "ebin/foo.app", app(foo)},
- {copy, "../../rebar", "rebar"},
+ [
+ {create, "ebin/foo.app", app(foo)},
{copy, "foo.test.spec", "foo.test.spec"},
{copy, "deps/bar.test.spec", "deps/bar.test.spec"},
- {copy, "foo_SUITE.erl", "test/foo_SUITE.erl"}].
+ {copy, "foo_SUITE.erl", "test/foo_SUITE.erl"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
Ref = retest:sh("./rebar compile ct -vvv", [async]),
diff --git a/inttest/ct3/ct3_rt.erl b/inttest/ct3/ct3_rt.erl
index a87cf21..b5739db 100644
--- a/inttest/ct3/ct3_rt.erl
+++ b/inttest/ct3/ct3_rt.erl
@@ -28,19 +28,23 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
files() ->
- [{create, "ebin/a1.app", app(a1)},
- {copy, "../../rebar", "rebar"},
+ [
+ {create, "ebin/a1.app", app(a1)},
{copy, "rebar.config", "rebar.config"},
{copy, "app.config", "itest/app.config"},
{copy, "test_SUITE.erl", "itest/test_SUITE.erl"},
{copy, "converted"},
- {copy, "unconverted"}].
+ {copy, "unconverted"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
{ok, _} = retest:sh("./rebar compile ct -v",
- [{env, [{"ERL_FLAGS", "-name ct_rt3"}]}]),
+ [{env, [{"ERL_FLAGS", "-name ct_rt3@localhost"}]}]),
ok.
%%
diff --git a/inttest/ct4/ct4_rt.erl b/inttest/ct4/ct4_rt.erl
new file mode 100644
index 0000000..bc010e8
--- /dev/null
+++ b/inttest/ct4/ct4_rt.erl
@@ -0,0 +1,44 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(ct4_rt).
+
+-compile(export_all).
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+files() ->
+ [
+ {create, "ebin/foo.app", app(foo)},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "foo.test.spec", "test/foo.test.spec"},
+ {copy, "deps/bar.test.spec", "deps/bar.test.spec"},
+ {copy, "deps/bar.test.spec", "baz.test.spec"},
+ {copy, "foo_SUITE.erl", "test/foo_SUITE.erl"}
+ ] ++ inttest_utils:rebar_setup().
+
+run(_Dir) ->
+ 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]),
+ %% baz.test.spec should be also ignored by rebar_ct:collect_glob/3
+ %% since we specified in rebar.config that we want to search for
+ %% ct specs from the test dir
+ nomatch = re:run(CTRunCmd, "baz.test.spec", [global]),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/ct4/deps/bar.test.spec b/inttest/ct4/deps/bar.test.spec
new file mode 100644
index 0000000..a16610c
--- /dev/null
+++ b/inttest/ct4/deps/bar.test.spec
@@ -0,0 +1 @@
+%% this test spec should be ignored
diff --git a/inttest/ct4/foo.test.spec b/inttest/ct4/foo.test.spec
new file mode 100644
index 0000000..1850410
--- /dev/null
+++ b/inttest/ct4/foo.test.spec
@@ -0,0 +1 @@
+{suites, "../", [foo_SUITE]}.
diff --git a/inttest/ct4/foo_SUITE.erl b/inttest/ct4/foo_SUITE.erl
new file mode 100644
index 0000000..fb4f56a
--- /dev/null
+++ b/inttest/ct4/foo_SUITE.erl
@@ -0,0 +1,11 @@
+-module(foo_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+all() -> [simple].
+
+simple(Config) ->
+ io:format("Test: ~p\n", [Config]),
+ ok.
diff --git a/inttest/ct4/rebar.config b/inttest/ct4/rebar.config
new file mode 100644
index 0000000..387f8c3
--- /dev/null
+++ b/inttest/ct4/rebar.config
@@ -0,0 +1,2 @@
+{ct_dir, "test"}.
+{ct_search_specs_from_test_dir, true}.
diff --git a/inttest/ct_cover/ct_cover_rt.erl b/inttest/ct_cover/ct_cover_rt.erl
index c7f8776..361d85b 100644
--- a/inttest/ct_cover/ct_cover_rt.erl
+++ b/inttest/ct_cover/ct_cover_rt.erl
@@ -4,14 +4,19 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{create, "ebin/a1.app", app(a1)},
- {copy, "../../rebar", "rebar"},
+ [
+ {create, "ebin/a1.app", app(a1)},
{copy, "rebar.config", "rebar.config"},
{copy, "app.config", "app.config"},
{copy, "cover.spec", "cover.spec"},
{copy, "test_SUITE.erl", "itest/test_SUITE.erl"},
- {copy, "mock", "deps"}].
+ {copy, "mock", "deps"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
{ok, _} = retest:sh("./rebar compile ct"),
diff --git a/inttest/ct_make_fails/app.config b/inttest/ct_make_fails/app.config
new file mode 100644
index 0000000..bb718b2
--- /dev/null
+++ b/inttest/ct_make_fails/app.config
@@ -0,0 +1,2 @@
+%% This file is an application config file, not a CT test config file
+[{a1, [{foo, bar}]}].
diff --git a/inttest/ct_make_fails/ct_make_fails_rt.erl b/inttest/ct_make_fails/ct_make_fails_rt.erl
new file mode 100644
index 0000000..a7959a7
--- /dev/null
+++ b/inttest/ct_make_fails/ct_make_fails_rt.erl
@@ -0,0 +1,31 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(ct_make_fails_rt).
+
+-compile(export_all).
+
+
+files() ->
+ [{create, "ebin/a1.app", app(a1)},
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "app.config", "app.config"},
+ {copy, "test_SUITE.erl", "itest/test_SUITE.erl"}].
+
+run(_Dir) ->
+ ok = case catch retest:sh("./rebar compile ct -v") of
+ {error, {stopped, _}} -> ok;
+ _ -> expected_to_fail
+ end.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/ct_make_fails/rebar.config b/inttest/ct_make_fails/rebar.config
new file mode 100644
index 0000000..58047ba
--- /dev/null
+++ b/inttest/ct_make_fails/rebar.config
@@ -0,0 +1,2 @@
+{ct_dir, "itest"}.
+{ct_extra_params, "-repeat 2 -erl_args -config app"}.
diff --git a/inttest/ct_make_fails/test_SUITE.erl b/inttest/ct_make_fails/test_SUITE.erl
new file mode 100644
index 0000000..343aa5a
--- /dev/null
+++ b/inttest/ct_make_fails/test_SUITE.erl
@@ -0,0 +1,17 @@
+-module(test_SUITE).
+
+-compile(export_all).
+
+-include_lib("ct.hrl").
+
+all() ->
+ [simple_test,
+ app_config_file_test].
+
+simple_test(Config) ->
+ io:format("Test: ~p\n" [Config]).
+
+app_config_file_test(_Config) ->
+ application:start(a1),
+ {ok, bar} = application:get_env(a1, foo),
+ application:stop(a1).
diff --git a/inttest/ct_test_fails/app.config b/inttest/ct_test_fails/app.config
new file mode 100644
index 0000000..bb718b2
--- /dev/null
+++ b/inttest/ct_test_fails/app.config
@@ -0,0 +1,2 @@
+%% This file is an application config file, not a CT test config file
+[{a1, [{foo, bar}]}].
diff --git a/inttest/ct_test_fails/ct_test_fails.test.spec b/inttest/ct_test_fails/ct_test_fails.test.spec
new file mode 100644
index 0000000..7bba687
--- /dev/null
+++ b/inttest/ct_test_fails/ct_test_fails.test.spec
@@ -0,0 +1 @@
+{suites,"../itest",[test_SUITE, test2_SUITE]}.
diff --git a/inttest/ct_test_fails/ct_test_fails_rt.erl b/inttest/ct_test_fails/ct_test_fails_rt.erl
new file mode 100644
index 0000000..a556891
--- /dev/null
+++ b/inttest/ct_test_fails/ct_test_fails_rt.erl
@@ -0,0 +1,33 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(ct_test_fails_rt).
+
+-compile(export_all).
+
+
+files() ->
+ [{create, "ebin/a1.app", app(a1)},
+ {copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "app.config", "app.config"},
+ {copy, "ct_test_fails.test.spec", "itest/ct_test_fails.test.spec"},
+ {copy, "test_SUITE.erl", "itest/test_SUITE.erl"},
+ {copy, "test2_SUITE.erl", "itest/test2_SUITE.erl"}].
+
+run(Dir) ->
+ ok = case catch retest:sh("./rebar compile ct -v 3") of
+ {error, {stopped, _}} -> ok;
+ _ -> expected_to_fail
+ end.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/ct_test_fails/rebar.config b/inttest/ct_test_fails/rebar.config
new file mode 100644
index 0000000..84c23ef
--- /dev/null
+++ b/inttest/ct_test_fails/rebar.config
@@ -0,0 +1,13 @@
+{ct_dir, ["itest"]}.
+{ct_extra_params, "-erl_args -config app"}.
+
+%% http://erlang.org/doc/apps/common_test/run_test_chapter.html#id77160
+%% Any relative paths specified in the test specification, will be relative to the
+%% directory which contains the test specification file, if ct_run -spec TestSpecFile ...
+%% or ct:run:test([{spec,TestSpecFile},...]) executes the test. The path will be
+%% relative to the top level log directory, if ct:run:testspec(TestSpec) executes the test.
+%% however for versions older than R16 what counts is the project root path and not the path
+%% of the location of the test spec. This will cause the test to fail since R15/14 can't find the
+%% test.spec file. Since we can't change the file we have no choice but to bypass the test
+%% completely
+{require_min_otp_vsn, "R16B"}.
diff --git a/inttest/ct_test_fails/test2_SUITE.erl b/inttest/ct_test_fails/test2_SUITE.erl
new file mode 100644
index 0000000..4b9299f
--- /dev/null
+++ b/inttest/ct_test_fails/test2_SUITE.erl
@@ -0,0 +1,9 @@
+-module(test2_SUITE).
+
+-compile(export_all).
+
+all() ->
+ [simple_test].
+
+simple_test(Config) ->
+ io:format("Test: ~p\n", [Config]).
diff --git a/inttest/ct_test_fails/test_SUITE.erl b/inttest/ct_test_fails/test_SUITE.erl
new file mode 100644
index 0000000..124fbe8
--- /dev/null
+++ b/inttest/ct_test_fails/test_SUITE.erl
@@ -0,0 +1,10 @@
+-module(test_SUITE).
+
+-compile(export_all).
+
+all() ->
+ [simple_test].
+
+simple_test(Config) ->
+ io:format("Test: ~p\n", [Config]),
+ ok = not_ok.
diff --git a/inttest/depplugins/depplugins_rt.erl b/inttest/depplugins/depplugins_rt.erl
index 7bcfe86..fc72dec 100644
--- a/inttest/depplugins/depplugins_rt.erl
+++ b/inttest/depplugins/depplugins_rt.erl
@@ -21,9 +21,12 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
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, [])},
@@ -38,7 +41,7 @@ files() ->
"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, [])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
diff --git a/inttest/erlc/erlc_rt.erl b/inttest/erlc/erlc_rt.erl
index 0c1f25d..3ac5956 100644
--- a/inttest/erlc/erlc_rt.erl
+++ b/inttest/erlc/erlc_rt.erl
@@ -54,9 +54,12 @@
"foo_worker.beam",
"SIMPLE-ASN.beam"]).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "rebar-no_debug_info.config", "rebar-no_debug_info.config"},
{copy, "include", "include"},
@@ -73,7 +76,7 @@ files() ->
%% deps
{create, "deps/foobar/ebin/foobar.app", app(foobar, [foobar])},
{copy, "foobar.erl", "deps/foobar/src/foobar.erl"}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
diff --git a/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl b/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl
index 384ce87..72c6928 100644
--- a/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl
+++ b/inttest/erlc_dep_graph/erlc_dep_graph_rt.erl
@@ -30,39 +30,57 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
+ [
{copy, "rebar.config", "rebar.config"},
{copy, "src", "src"},
{copy, "include", "include"},
- {copy, "extra_include", "extra_include"}].
+ {copy, "extra_include", "extra_include"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
+ retest_log:log(debug, "compiling all...\n\n", []),
compile_all(ok, ""),
+ retest_log:log(debug, "checking beams integrity...\n\n", []),
check_beams_ok(),
check_beams_untouched(filelib:wildcard("ebin/*.beam")),
+ retest_log:log(debug, "modifying lisp.erl and recompiling...\n\n", []),
modify_and_recompile_ok("src/lisp.erl", "ebin/lisp.beam"),
+ retest_log:log(debug, "cleaning all...\n\n", []),
clean_all_ok(),
+ retest_log:log(debug, "compiling all (expect fail)...\n\n", []),
compile_all(error, "-C rebar.config.non-existing"),
+ retest_log:log(debug, "compiling all...\n\n", []),
compile_all(ok, ""),
+ retest_log:log(debug, "modifying extra_include/extra.hrl and recompiling...\n\n", []),
modify_and_recompile_ok("extra_include/extra.hrl", "ebin/java.beam"),
+ retest_log:log(debug, "rewriting src/java.erl...\n\n", []),
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]),
+ retest_log:log(debug, "compiling all...\n\n", []),
compile_all(ok, ""),
%% Modify that header file
+ retest_log:log(debug, "again modifying extra_include/extra.hrl and recompiling...\n\n", []),
touch(["extra_include/extra.hrl"]),
%% Ensure we don't have to recompile anything
+ retest_log:log(debug, "ensure ebin/java.beam was untouched...\n\n", []),
check_beams_untouched(["ebin/java.beam"]),
%% Clean up
+ retest_log:log(debug, "modifying src/java.erl...\n\n", []),
ok = file:write_file(Java, OrigContent),
%% Check that changes propagate deeply through the dependency tree
+ retest_log:log(debug, "modifying include/lambda.hrl...\n\n", []),
modify_and_recompile_ok("include/lambda.hrl", "ebin/perl.beam"),
ok.
@@ -82,7 +100,9 @@ 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,
+ lists:zipwith(fun(Before, After) ->
+ ?assert(Cmp(Before, After))
+ end,
BeamsModifiedBefore, BeamsModifiedAfter).
with_erl_beams(F) ->
@@ -95,13 +115,13 @@ with_erl_beams(F) ->
filelib:wildcard("src/*.erl")).
mtime_ns(Files) ->
- [os:cmd("stat -c%y " ++ File) || File <- Files].
+ [calendar:datetime_to_gregorian_seconds(filelib:last_modified(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].
+ [file:change_time(File, calendar:local_time()) || File <- Files].
compile_all(Result, Opts) ->
?assertMatch({Result, _},
diff --git a/inttest/eunit/eunit_rt.erl b/inttest/eunit/eunit_rt.erl
index 1d71404..bc24b26 100644
--- a/inttest/eunit/eunit_rt.erl
+++ b/inttest/eunit/eunit_rt.erl
@@ -5,14 +5,19 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{create, "ebin/foo.app", app(foo)},
- {copy, "../../rebar", "rebar"},
+ [
+ {create, "ebin/foo.app", app(foo)},
{copy, "src", "src"},
{copy, "eunit_src", "eunit_src"},
{copy,
"rebar-eunit_compile_opts.config",
- "rebar-eunit_compile_opts.config"}].
+ "rebar-eunit_compile_opts.config"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
ifdef_test(),
diff --git a/inttest/eunit_surefire/eunit_src/bar.erl b/inttest/eunit_surefire/eunit_src/bar.erl
new file mode 100644
index 0000000..6a80dac
--- /dev/null
+++ b/inttest/eunit_surefire/eunit_src/bar.erl
@@ -0,0 +1,6 @@
+-module(bar).
+
+-include_lib("eunit/include/eunit.hrl").
+
+bar_test() ->
+ ?assert(true).
diff --git a/inttest/eunit_surefire/eunit_surefire_rt.erl b/inttest/eunit_surefire/eunit_surefire_rt.erl
new file mode 100644
index 0000000..fd26d4b
--- /dev/null
+++ b/inttest/eunit_surefire/eunit_surefire_rt.erl
@@ -0,0 +1,40 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(eunit_surefire_rt).
+-export([files/0, run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+files() ->
+ [
+ {create, "ebin/foo.app", app(foo)},
+ {copy, "src", "src"},
+ {copy, "eunit_src", "eunit_src"},
+ {copy, "rebar.config"}
+ ] ++ inttest_utils:rebar_setup().
+
+run(_Dir) ->
+ {ok, Output} = retest:sh("./rebar -v eunit tests=bar"),
+ ?assert(check_output(Output, "bar_test")),
+ ok.
+
+check_output(Output, Target) ->
+ lists:any(fun(Line) ->
+ string:str(Line, Target) > 0
+ end, Output).
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/eunit_surefire/rebar.config b/inttest/eunit_surefire/rebar.config
new file mode 100644
index 0000000..0172560
--- /dev/null
+++ b/inttest/eunit_surefire/rebar.config
@@ -0,0 +1,7 @@
+{eunit_compile_opts, [
+ {src_dirs, ["eunit_src"]}
+]}.
+
+{eunit_opts, [
+ {report, {eunit_surefire, [{dir, "."}]}}
+]}.
diff --git a/inttest/eunit_surefire/src/foo.erl b/inttest/eunit_surefire/src/foo.erl
new file mode 100644
index 0000000..a4c91ba
--- /dev/null
+++ b/inttest/eunit_surefire/src/foo.erl
@@ -0,0 +1,10 @@
+-module(foo).
+
+-ifdef(TEST).
+
+-include_lib("eunit/include/eunit.hrl").
+
+foo_test() ->
+ ?assert(true).
+
+-endif.
diff --git a/inttest/inttest_utils.erl b/inttest/inttest_utils.erl
new file mode 100644
index 0000000..d896f4d
--- /dev/null
+++ b/inttest/inttest_utils.erl
@@ -0,0 +1,16 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(inttest_utils).
+
+-compile(export_all).
+
+rebar_setup({win32, nt}, Dir) ->
+ [{copy, filename:join(Dir, "rebar.cmd"), "rebar.cmd"}];
+rebar_setup({_, _}, _) -> [].
+
+rebar_setup(Dir) ->
+ [{copy,
+ filename:join(Dir, "rebar"), "rebar"}] ++ rebar_setup(os:type(), Dir).
+
+rebar_setup() ->
+ rebar_setup("../..").
diff --git a/inttest/logging/logging_rt.erl b/inttest/logging/logging_rt.erl
index 2709a84..f774376 100644
--- a/inttest/logging/logging_rt.erl
+++ b/inttest/logging/logging_rt.erl
@@ -30,11 +30,14 @@
-define(APP_FILE, "ebin/logging.app").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{create, ?APP_FILE, app(invalid_name, [])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
SharedExpected = "==> logging_rt \\(compile\\)",
diff --git a/inttest/neotoma1/mock/neotoma/priv/peg_includes.hrl b/inttest/neotoma1/mock/neotoma/priv/peg_includes.hrl
new file mode 100644
index 0000000..183b98c
--- /dev/null
+++ b/inttest/neotoma1/mock/neotoma/priv/peg_includes.hrl
@@ -0,0 +1,253 @@
+-file("peg_includes.hrl", 1).
+-type index() :: {{line, pos_integer()}, {column, pos_integer()}}.
+-type input() :: binary().
+-type parse_failure() :: {fail, term()}.
+-type parse_success() :: {term(), input(), index()}.
+-type parse_result() :: parse_failure() | parse_success().
+-type parse_fun() :: fun((input(), index()) -> parse_result()).
+-type xform_fun() :: fun((input(), index()) -> term()).
+
+-spec p(input(), index(), atom(), parse_fun(), xform_fun()) -> parse_result().
+p(Inp, StartIndex, Name, ParseFun, TransformFun) ->
+ case get_memo(StartIndex, Name) of % See if the current reduction is memoized
+ {ok, Memo} -> %Memo; % If it is, return the stored result
+ Memo;
+ _ -> % If not, attempt to parse
+ Result = case ParseFun(Inp, StartIndex) of
+ {fail,_} = Failure -> % If it fails, memoize the failure
+ Failure;
+ {Match, InpRem, NewIndex} -> % If it passes, transform and memoize the result.
+ Transformed = TransformFun(Match, StartIndex),
+ {Transformed, InpRem, NewIndex}
+ end,
+ memoize(StartIndex, Name, Result),
+ Result
+ end.
+
+-spec setup_memo() -> ets:tid().
+setup_memo() ->
+ put({parse_memo_table, ?MODULE}, ets:new(?MODULE, [set])).
+
+-spec release_memo() -> true.
+release_memo() ->
+ ets:delete(memo_table_name()).
+
+-spec memoize(index(), atom(), parse_result()) -> true.
+memoize(Index, Name, Result) ->
+ Memo = case ets:lookup(memo_table_name(), Index) of
+ [] -> [];
+ [{Index, Plist}] -> Plist
+ end,
+ ets:insert(memo_table_name(), {Index, [{Name, Result}|Memo]}).
+
+-spec get_memo(index(), atom()) -> {ok, term()} | {error, not_found}.
+get_memo(Index, Name) ->
+ case ets:lookup(memo_table_name(), Index) of
+ [] -> {error, not_found};
+ [{Index, Plist}] ->
+ case proplists:lookup(Name, Plist) of
+ {Name, Result} -> {ok, Result};
+ _ -> {error, not_found}
+ end
+ end.
+
+-spec memo_table_name() -> ets:tid().
+memo_table_name() ->
+ get({parse_memo_table, ?MODULE}).
+
+-ifdef(p_eof).
+-spec p_eof() -> parse_fun().
+p_eof() ->
+ fun(<<>>, Index) -> {eof, [], Index};
+ (_, Index) -> {fail, {expected, eof, Index}} end.
+-endif.
+
+-ifdef(p_optional).
+-spec p_optional(parse_fun()) -> parse_fun().
+p_optional(P) ->
+ fun(Input, Index) ->
+ case P(Input, Index) of
+ {fail,_} -> {[], Input, Index};
+ {_, _, _} = Success -> Success
+ end
+ end.
+-endif.
+
+-ifdef(p_not).
+-spec p_not(parse_fun()) -> parse_fun().
+p_not(P) ->
+ fun(Input, Index)->
+ case P(Input,Index) of
+ {fail,_} ->
+ {[], Input, Index};
+ {Result, _, _} -> {fail, {expected, {no_match, Result},Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_assert).
+-spec p_assert(parse_fun()) -> parse_fun().
+p_assert(P) ->
+ fun(Input,Index) ->
+ case P(Input,Index) of
+ {fail,_} = Failure-> Failure;
+ _ -> {[], Input, Index}
+ end
+ end.
+-endif.
+
+-ifdef(p_seq).
+-spec p_seq([parse_fun()]) -> parse_fun().
+p_seq(P) ->
+ fun(Input, Index) ->
+ p_all(P, Input, Index, [])
+ end.
+
+-spec p_all([parse_fun()], input(), index(), [term()]) -> parse_result().
+p_all([], Inp, Index, Accum ) -> {lists:reverse( Accum ), Inp, Index};
+p_all([P|Parsers], Inp, Index, Accum) ->
+ case P(Inp, Index) of
+ {fail, _} = Failure -> Failure;
+ {Result, InpRem, NewIndex} -> p_all(Parsers, InpRem, NewIndex, [Result|Accum])
+ end.
+-endif.
+
+-ifdef(p_choose).
+-spec p_choose([parse_fun()]) -> parse_fun().
+p_choose(Parsers) ->
+ fun(Input, Index) ->
+ p_attempt(Parsers, Input, Index, none)
+ end.
+
+-spec p_attempt([parse_fun()], input(), index(), none | parse_failure()) -> parse_result().
+p_attempt([], _Input, _Index, Failure) -> Failure;
+p_attempt([P|Parsers], Input, Index, FirstFailure)->
+ case P(Input, Index) of
+ {fail, _} = Failure ->
+ case FirstFailure of
+ none -> p_attempt(Parsers, Input, Index, Failure);
+ _ -> p_attempt(Parsers, Input, Index, FirstFailure)
+ end;
+ Result -> Result
+ end.
+-endif.
+
+-ifdef(p_zero_or_more).
+-spec p_zero_or_more(parse_fun()) -> parse_fun().
+p_zero_or_more(P) ->
+ fun(Input, Index) ->
+ p_scan(P, Input, Index, [])
+ end.
+-endif.
+
+-ifdef(p_one_or_more).
+-spec p_one_or_more(parse_fun()) -> parse_fun().
+p_one_or_more(P) ->
+ fun(Input, Index)->
+ Result = p_scan(P, Input, Index, []),
+ case Result of
+ {[_|_], _, _} ->
+ Result;
+ _ ->
+ {fail, {expected, Failure, _}} = P(Input,Index),
+ {fail, {expected, {at_least_one, Failure}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_label).
+-spec p_label(atom(), parse_fun()) -> parse_fun().
+p_label(Tag, P) ->
+ fun(Input, Index) ->
+ case P(Input, Index) of
+ {fail,_} = Failure ->
+ Failure;
+ {Result, InpRem, NewIndex} ->
+ {{Tag, Result}, InpRem, NewIndex}
+ end
+ end.
+-endif.
+
+-ifdef(p_scan).
+-spec p_scan(parse_fun(), input(), index(), [term()]) -> {[term()], input(), index()}.
+p_scan(_, <<>>, Index, Accum) -> {lists:reverse(Accum), <<>>, Index};
+p_scan(P, Inp, Index, Accum) ->
+ case P(Inp, Index) of
+ {fail,_} -> {lists:reverse(Accum), Inp, Index};
+ {Result, InpRem, NewIndex} -> p_scan(P, InpRem, NewIndex, [Result | Accum])
+ end.
+-endif.
+
+-ifdef(p_string).
+-spec p_string(binary()) -> parse_fun().
+p_string(S) ->
+ Length = erlang:byte_size(S),
+ fun(Input, Index) ->
+ try
+ <<S:Length/binary, Rest/binary>> = Input,
+ {S, Rest, p_advance_index(S, Index)}
+ catch
+ error:{badmatch,_} -> {fail, {expected, {string, S}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_anything).
+-spec p_anything() -> parse_fun().
+p_anything() ->
+ fun(<<>>, Index) -> {fail, {expected, any_character, Index}};
+ (Input, Index) when is_binary(Input) ->
+ <<C/utf8, Rest/binary>> = Input,
+ {<<C/utf8>>, Rest, p_advance_index(<<C/utf8>>, Index)}
+ end.
+-endif.
+
+-ifdef(p_charclass).
+-spec p_charclass(string() | binary()) -> parse_fun().
+p_charclass(Class) ->
+ {ok, RE} = re:compile(Class, [unicode, dotall]),
+ fun(Inp, Index) ->
+ case re:run(Inp, RE, [anchored]) of
+ {match, [{0, Length}|_]} ->
+ {Head, Tail} = erlang:split_binary(Inp, Length),
+ {Head, Tail, p_advance_index(Head, Index)};
+ _ -> {fail, {expected, {character_class, binary_to_list(Class)}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_regexp).
+-spec p_regexp(binary()) -> parse_fun().
+p_regexp(Regexp) ->
+ {ok, RE} = re:compile(Regexp, [unicode, dotall, anchored]),
+ fun(Inp, Index) ->
+ case re:run(Inp, RE) of
+ {match, [{0, Length}|_]} ->
+ {Head, Tail} = erlang:split_binary(Inp, Length),
+ {Head, Tail, p_advance_index(Head, Index)};
+ _ -> {fail, {expected, {regexp, binary_to_list(Regexp)}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(line).
+-spec line(index() | term()) -> pos_integer() | undefined.
+line({{line,L},_}) -> L;
+line(_) -> undefined.
+-endif.
+
+-ifdef(column).
+-spec column(index() | term()) -> pos_integer() | undefined.
+column({_,{column,C}}) -> C;
+column(_) -> undefined.
+-endif.
+
+-spec p_advance_index(input() | unicode:charlist() | pos_integer(), index()) -> index().
+p_advance_index(MatchedInput, Index) when is_list(MatchedInput) orelse is_binary(MatchedInput)-> % strings
+ lists:foldl(fun p_advance_index/2, Index, unicode:characters_to_list(MatchedInput));
+p_advance_index(MatchedInput, Index) when is_integer(MatchedInput) -> % single characters
+ {{line, Line}, {column, Col}} = Index,
+ case MatchedInput of
+ $\n -> {{line, Line+1}, {column, 1}};
+ _ -> {{line, Line}, {column, Col+1}}
+ end.
diff --git a/inttest/neotoma1/mock/neotoma/src/neotoma.app.src b/inttest/neotoma1/mock/neotoma/src/neotoma.app.src
new file mode 100644
index 0000000..dff6cef
--- /dev/null
+++ b/inttest/neotoma1/mock/neotoma/src/neotoma.app.src
@@ -0,0 +1,10 @@
+{application, neotoma,
+ [
+ {description, "PEG/Packrat toolkit and parser-generator."},
+ {vsn, "1.7.3"},
+ {applications, [kernel, stdlib]},
+ {contributors, ["Sean Cribbs"]},
+ {licenses, ["MIT"]},
+ {links, [{"Github", "https://github.com/seancribbs/neotoma"}]}
+ ]
+}.
diff --git a/inttest/neotoma1/mock/neotoma/src/neotoma.erl b/inttest/neotoma1/mock/neotoma/src/neotoma.erl
new file mode 100644
index 0000000..f4102f6
--- /dev/null
+++ b/inttest/neotoma1/mock/neotoma/src/neotoma.erl
@@ -0,0 +1,145 @@
+-module(neotoma).
+-author("Sean Cribbs <seancribbs@gmail.com>").
+-export([file/1, file/2, bootstrap/0]).
+-export([main/1]).
+
+-define(ALL_COMBINATORS, [p_eof, p_optional, p_not, p_assert, p_seq,
+ p_choose, p_zero_or_more, p_one_or_more, p_label, p_scan,
+ p_string, p_anything, p_charclass, p_regexp, line, column]).
+
+-type option() :: {module, atom()} | {output, file:filename()} | {transform_module, atom()} |
+ {neotoma_priv_dir, file:filename()}.
+
+%% @doc Handler function for escript.
+-spec main(list()) -> ok | no_return().
+main([]) ->
+ io:format("Usage: neotoma filename [-module output_module] [-output output_dir] [-transform_module transform_module]\n");
+main([Filename | Args]) ->
+ %% code:priv_dir is unreliable when called in escript context, but
+ %% escript:script_name does what we want.
+ PrivDir = filename:join([filename:dirname(escript:script_name()), "priv"]),
+ file(Filename, [{neotoma_priv_dir, PrivDir} | parse_options(Args)]).
+
+%% @doc Generates a parser from the specified file.
+%% @equiv file(Filename, [])
+-spec file(file:filename()) -> ok | {error, atom()}.
+file(InputGrammar) ->
+ file(InputGrammar, []).
+
+%% @doc Generates a parser from the specified file with the given options.
+-spec file(file:filename(), [option()]) -> ok | {error, atom()}.
+file(InputGrammar, Options) ->
+ Basename = filename:basename(InputGrammar, ".peg"),
+ InputDir = filename:dirname(InputGrammar),
+ ModuleName = proplists:get_value(module, Options, list_to_atom(Basename)),
+ OutputDir = proplists:get_value(output, Options, InputDir),
+ OutputFilename = filename:join(OutputDir, atom_to_list(ModuleName) ++ ".erl"),
+ TransformModule = proplists:get_value(transform_module, Options, false),
+ validate_params(filename:absname(InputGrammar),
+ ModuleName,
+ TransformModule,
+ filename:absname(OutputFilename)),
+ Parsed = parse_grammar(InputGrammar),
+ Rules = proplists:get_value(rules, Parsed),
+ Root = proplists:get_value(root, Parsed),
+ Code = proplists:get_value(code, Parsed),
+ GenTransform = proplists:get_value(transform, Parsed),
+ Combinators = proplists:get_value(combinators, Parsed, ?ALL_COMBINATORS),
+ ModuleAttrs = generate_module_attrs(ModuleName, Combinators),
+ EntryFuns = generate_entry_functions(Root),
+ TransformFun = create_transform(TransformModule, OutputDir, GenTransform),
+ PrivDir = proplists:get_value(neotoma_priv_dir, Options, code:priv_dir(neotoma)),
+ {ok, PegIncludes} = file:read_file(filename:join([PrivDir, "peg_includes.hrl"])),
+ file:write_file(OutputFilename, [ModuleAttrs, "\n", Code, "\n", EntryFuns, "\n", Rules, "\n", TransformFun, "\n", PegIncludes]).
+
+-spec validate_params(file:filename(),atom(),atom(),file:filename()) -> 'ok'.
+validate_params(InputGrammar, _, _, OutputFile) when InputGrammar =:= OutputFile ->
+ throw({badarg, "Input and output file are the same!"});
+validate_params(_,_, false, _) -> ok;
+validate_params(_,_, TransformModule, _) when not is_atom(TransformModule) ->
+ throw({badarg, "transform_module option must be an atom"});
+validate_params(_,Basename, TransformModule, _) when Basename =:= TransformModule ->
+ throw({badarg, "Transform module named same as parser module!"});
+validate_params(_,_, TransformModule, OutputFile) ->
+ OutMod = list_to_atom(filename:basename(OutputFile, ".erl")),
+ case OutMod of
+ TransformModule -> throw({badarg, "Transform module file same as parser output file!"});
+ _ -> ok
+ end.
+
+-spec generate_module_attrs(atom(), [atom()]) -> iolist().
+generate_module_attrs(ModName, Combinators) ->
+ ["-module(", atom_to_list(ModName) ,").\n",
+ "-export([parse/1,file/1]).\n",
+ [ generate_combinator_macro(C) || Combinators /= undefined, C <- Combinators ],
+ "\n"
+ ].
+
+generate_combinator_macro(C) ->
+ ["-define(", atom_to_list(C), ",true).\n"].
+
+-spec generate_entry_functions({iodata(),_}) -> iolist().
+generate_entry_functions(Root) ->
+ {RootRule,_} = Root,
+ ["-spec file(file:name()) -> any().\n",
+ "file(Filename) -> case file:read_file(Filename) of {ok,Bin} -> parse(Bin); Err -> Err end.\n\n",
+ "-spec parse(binary() | list()) -> any().\n",
+ "parse(List) when is_list(List) -> parse(unicode:characters_to_binary(List));\n",
+ "parse(Input) when is_binary(Input) ->\n",
+ " _ = setup_memo(),\n",
+ " Result = case '",RootRule,"'(Input,{{line,1},{column,1}}) of\n",
+ " {AST, <<>>, _Index} -> AST;\n",
+ " Any -> Any\n"
+ " end,\n",
+ " release_memo(), Result.\n"].
+
+-spec parse_grammar(file:filename()) -> any().
+parse_grammar(InputFile) ->
+ case neotoma_parse:file(InputFile) of
+ {fail, Index} ->
+ throw({grammar_error, {fail, Index}});
+ {Parsed, Remainder, Index} ->
+ io:format("WARNING: Grammar parse ended unexpectedly at ~p, generated parser may be incorrect.~nRemainder:~n~p",
+ [Index, Remainder]),
+ Parsed;
+ L when is_list(L) -> L;
+ _ -> throw({error, {unknown, grammar, InputFile}})
+ end.
+
+-spec create_transform(atom() | boolean(),file:filename(),_) -> iolist().
+create_transform(_,_,[]) -> [];
+create_transform(false,_,_) ->
+ "transform(_,Node,_Index) -> Node.";
+create_transform(ModName,Dir,_) when is_atom(ModName) ->
+ XfFile = filename:join(Dir, atom_to_list(ModName) ++ ".erl"),
+ case filelib:is_regular(XfFile) of
+ true -> io:format("'~s' already exists, skipping generation.~n", [XfFile]);
+ false -> generate_transform_stub(XfFile, ModName)
+ end,
+ ["transform(Symbol,Node,Index) -> ",atom_to_list(ModName),":transform(Symbol, Node, Index)."].
+
+-spec generate_transform_stub(file:filename(), atom()) -> 'ok' | {'error',atom()}.
+generate_transform_stub(XfFile,ModName) ->
+ Data = ["-module(",atom_to_list(ModName),").\n",
+ "-export([transform/3]).\n\n",
+ "%% Add clauses to this function to transform syntax nodes\n",
+ "%% from the parser into semantic output.\n",
+ "transform(Symbol, Node, _Index) when is_atom(Symbol) ->\n Node."],
+ file:write_file(XfFile, Data).
+
+%% @doc Bootstraps the neotoma metagrammar. Intended only for internal development!
+%% @equiv file("src/neotoma_parse.peg")
+-spec bootstrap() -> 'ok'.
+bootstrap() ->
+ file("priv/neotoma_parse.peg", [{output, "src/"}, {neotoma_priv_dir, "priv"}]).
+
+%% @doc Parses arguments passed to escript
+-spec parse_options(list()) -> list().
+parse_options(["-module", ModName | Rest]) ->
+ [{module, list_to_atom(ModName)} | parse_options(Rest)];
+parse_options(["-output", Dir | Rest]) ->
+ [{output, Dir} | parse_options(Rest)];
+parse_options(["-transform_module", ModName | Rest]) ->
+ [{transform_module, list_to_atom(ModName)} | parse_options(Rest)];
+parse_options([]) ->
+ [].
diff --git a/inttest/neotoma1/mock/neotoma/src/neotoma_parse.erl b/inttest/neotoma1/mock/neotoma/src/neotoma_parse.erl
new file mode 100644
index 0000000..1bffaf8
--- /dev/null
+++ b/inttest/neotoma1/mock/neotoma/src/neotoma_parse.erl
@@ -0,0 +1,625 @@
+-module(neotoma_parse).
+-export([parse/1,file/1]).
+-define(p_anything,true).
+-define(p_charclass,true).
+-define(p_choose,true).
+-define(p_label,true).
+-define(p_not,true).
+-define(p_one_or_more,true).
+-define(p_optional,true).
+-define(p_scan,true).
+-define(p_seq,true).
+-define(p_string,true).
+-define(p_zero_or_more,true).
+
+
+
+% insert escapes into a string
+-spec escape_string(string()) -> string().
+escape_string(String) -> escape_string(String, []).
+
+-spec escape_string(string(), string()) -> string().
+escape_string([], Output) ->
+ lists:reverse(Output);
+escape_string([H|T], Output) ->
+ escape_string(T,
+ case H of
+ $/ -> [$/,$\\|Output];
+ $\" -> [$\",$\\|Output]; % " comment inserted to help some editors with highlighting the generated parser
+ $\' -> [$\',$\\|Output]; % ' comment inserted to help some editors with highlighting the generated parser
+ $\b -> [$b,$\\|Output];
+ $\d -> [$d,$\\|Output];
+ $\e -> [$e,$\\|Output];
+ $\f -> [$f,$\\|Output];
+ $\n -> [$n,$\\|Output];
+ $\r -> [$r,$\\|Output];
+ $\s -> [$s,$\\|Output];
+ $\t -> [$t,$\\|Output];
+ $\v -> [$v,$\\|Output];
+ _ -> [H|Output]
+ end).
+
+-spec add_lhs(binary(), index()) -> true.
+add_lhs(Symbol, Index) ->
+ case ets:lookup(memo_table_name(), lhs) of
+ [] ->
+ ets:insert(memo_table_name(), {lhs, [{Symbol,Index}]});
+ [{lhs, L}] when is_list(L) ->
+ ets:insert(memo_table_name(), {lhs, [{Symbol,Index}|L]})
+ end.
+
+-spec add_nt(binary(), index()) -> true | ok.
+add_nt(Symbol, Index) ->
+ case ets:lookup(memo_table_name(), nts) of
+ [] ->
+ ets:insert(memo_table_name(), {nts, [{Symbol,Index}]});
+ [{nts, L}] when is_list(L) ->
+ case proplists:is_defined(Symbol, L) of
+ true ->
+ ok;
+ _ ->
+ ets:insert(memo_table_name(), {nts, [{Symbol,Index}|L]})
+ end
+ end.
+
+-spec verify_rules() -> ok | no_return().
+verify_rules() ->
+ [{lhs, LHS}] = ets:lookup(memo_table_name(), lhs),
+ [{nts, NTs}] = ets:lookup(memo_table_name(), nts),
+ [Root|NonRoots] = lists:reverse(LHS),
+ lists:foreach(fun({Sym,Idx}) ->
+ case proplists:is_defined(Sym, NTs) of
+ true ->
+ ok;
+ _ ->
+ io:format("neotoma warning: rule '~s' is unused. ~p~n", [Sym,Idx])
+ end
+ end, NonRoots),
+ lists:foreach(fun({S,I}) ->
+ case proplists:is_defined(S, LHS) of
+ true ->
+ ok;
+ _ ->
+ io:format("neotoma error: nonterminal '~s' has no reduction. (found at ~p) No parser will be generated!~n", [S,I]),
+ exit({neotoma, {no_reduction, list_to_atom(binary_to_list(S))}})
+ end
+ end, NTs),
+ Root.
+
+-spec used_combinator(atom()) -> true.
+used_combinator(C) ->
+ case ets:lookup(memo_table_name(), combinators) of
+ [] ->
+ ets:insert(memo_table_name(), {combinators, ordsets:from_list([C])});
+ [{combinators, Cs}] ->
+ ets:insert(memo_table_name(), {combinators, ordsets:add_element(C, Cs)})
+ end.
+
+-spec used_transform_variables(binary()) -> [ 'Node' | 'Idx' ].
+used_transform_variables(Transform) ->
+ Code = unicode:characters_to_list(Transform),
+ {ok, Tokens, _} = erl_scan:string(Code),
+ used_transform_variables(Tokens, []).
+
+used_transform_variables([{var, _, Name}|Tokens], Acc) ->
+ used_transform_variables(Tokens, case Name of
+ 'Node' -> [Name | Acc];
+ 'Idx' -> [Name | Acc];
+ _ -> Acc
+ end);
+used_transform_variables([_|Tokens], Acc) ->
+ used_transform_variables(Tokens, Acc);
+used_transform_variables([], Acc) ->
+ lists:usort(Acc).
+
+-spec file(file:name()) -> any().
+file(Filename) -> case file:read_file(Filename) of {ok,Bin} -> parse(Bin); Err -> Err end.
+
+-spec parse(binary() | list()) -> any().
+parse(List) when is_list(List) -> parse(unicode:characters_to_binary(List));
+parse(Input) when is_binary(Input) ->
+ _ = setup_memo(),
+ Result = case 'rules'(Input,{{line,1},{column,1}}) of
+ {AST, <<>>, _Index} -> AST;
+ Any -> Any
+ end,
+ release_memo(), Result.
+
+-spec 'rules'(input(), index()) -> parse_result().
+'rules'(Input, Index) ->
+ p(Input, Index, 'rules', fun(I,D) -> (p_seq([p_optional(fun 'space'/2), fun 'declaration_sequence'/2, p_optional(fun 'space'/2), p_optional(fun 'code_block'/2), p_optional(fun 'space'/2)]))(I,D) end, fun(Node, _Idx) ->
+ RootRule = verify_rules(),
+ Rules = unicode:characters_to_binary(lists:map(fun(R) -> [R, "\n\n"] end, lists:nth(2, Node))),
+ Code = case lists:nth(4, Node) of
+ {code, Block} -> Block;
+ _ -> []
+ end,
+ [{rules, Rules},
+ {code, Code},
+ {root, RootRule},
+ {transform, ets:lookup(memo_table_name(),gen_transform)},
+ {combinators, ets:lookup_element(memo_table_name(), combinators, 2)}]
+
+ end).
+
+-spec 'declaration_sequence'(input(), index()) -> parse_result().
+'declaration_sequence'(Input, Index) ->
+ p(Input, Index, 'declaration_sequence', fun(I,D) -> (p_seq([p_label('head', fun 'declaration'/2), p_label('tail', p_zero_or_more(p_seq([fun 'space'/2, fun 'declaration'/2])))]))(I,D) end, fun(Node, _Idx) ->
+ FirstRule = proplists:get_value(head, Node),
+ OtherRules = [I || [_,I] <- proplists:get_value(tail, Node, [])],
+ [FirstRule|OtherRules]
+ end).
+
+-spec 'declaration'(input(), index()) -> parse_result().
+'declaration'(Input, Index) ->
+ p(Input, Index, 'declaration', fun(I,D) -> (p_seq([fun 'nonterminal'/2, p_zero_or_more(fun 'space'/2), p_string(<<"<-">>), p_zero_or_more(fun 'space'/2), fun 'parsing_expression'/2, p_optional(fun 'space'/2), p_optional(fun 'code_block'/2), p_optional(fun 'space'/2), p_string(<<";">>)]))(I,D) end, fun(Node, _Idx) ->
+ [{nonterminal,Symbol}|Tail] = Node,
+ add_lhs(Symbol, Index),
+ Transform = case lists:nth(6,Tail) of
+ {code, CodeBlock} -> CodeBlock;
+ _ ->
+ ets:insert_new(memo_table_name(),{gen_transform, true}),
+ ["transform('",Symbol,"', Node, Idx)"]
+ end,
+ TransformArgs = case used_transform_variables(Transform) of
+ [] -> "_Node, _Idx";
+ ['Idx'] -> "_Node, Idx";
+ ['Node'] -> "Node, _Idx";
+ ['Idx', 'Node'] -> "Node, Idx"
+ end,
+ ["-spec '", Symbol, "'(input(), index()) -> parse_result().\n",
+ "'",Symbol,"'","(Input, Index) ->\n ",
+ "p(Input, Index, '",Symbol,"', fun(I,D) -> (",
+ lists:nth(4, Tail),
+ ")(I,D) end, fun(", TransformArgs, ") ->",Transform," end)."]
+ end).
+
+-spec 'parsing_expression'(input(), index()) -> parse_result().
+'parsing_expression'(Input, Index) ->
+ p(Input, Index, 'parsing_expression', fun(I,D) -> (p_choose([fun 'choice'/2, fun 'sequence'/2, fun 'primary'/2]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'choice'(input(), index()) -> parse_result().
+'choice'(Input, Index) ->
+ p(Input, Index, 'choice', fun(I,D) -> (p_seq([p_label('head', fun 'alternative'/2), p_label('tail', p_one_or_more(p_seq([fun 'space'/2, p_string(<<"\/">>), fun 'space'/2, fun 'alternative'/2])))]))(I,D) end, fun(Node, _Idx) ->
+ Tail = [lists:last(S) || S <- proplists:get_value(tail, Node)],
+ Head = proplists:get_value(head, Node),
+ Statements = [[", ", TS] || TS <- Tail],
+ used_combinator(p_choose),
+ ["p_choose([", Head, Statements, "])"]
+ end).
+
+-spec 'alternative'(input(), index()) -> parse_result().
+'alternative'(Input, Index) ->
+ p(Input, Index, 'alternative', fun(I,D) -> (p_choose([fun 'sequence'/2, fun 'labeled_primary'/2]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'primary'(input(), index()) -> parse_result().
+'primary'(Input, Index) ->
+ p(Input, Index, 'primary', fun(I,D) -> (p_choose([p_seq([fun 'prefix'/2, fun 'atomic'/2]), p_seq([fun 'atomic'/2, fun 'suffix'/2]), fun 'atomic'/2]))(I,D) end, fun(Node, _Idx) ->
+case Node of
+ [Atomic, one_or_more] ->
+ used_combinator(p_one_or_more),
+ used_combinator(p_scan),
+ ["p_one_or_more(", Atomic, ")"];
+ [Atomic, zero_or_more] ->
+ used_combinator(p_zero_or_more),
+ used_combinator(p_scan),
+ ["p_zero_or_more(", Atomic, ")"];
+ [Atomic, optional] ->
+ used_combinator(p_optional),
+ ["p_optional(", Atomic, ")"];
+ [assert, Atomic] ->
+ used_combinator(p_assert),
+ ["p_assert(", Atomic, ")"];
+ [not_, Atomic] ->
+ used_combinator(p_not),
+ ["p_not(", Atomic, ")"];
+ _ -> Node
+end
+ end).
+
+-spec 'sequence'(input(), index()) -> parse_result().
+'sequence'(Input, Index) ->
+ p(Input, Index, 'sequence', fun(I,D) -> (p_seq([p_label('head', fun 'labeled_primary'/2), p_label('tail', p_one_or_more(p_seq([fun 'space'/2, fun 'labeled_primary'/2])))]))(I,D) end, fun(Node, _Idx) ->
+ Tail = [lists:nth(2, S) || S <- proplists:get_value(tail, Node)],
+ Head = proplists:get_value(head, Node),
+ Statements = [[", ", TS] || TS <- Tail],
+ used_combinator(p_seq),
+ ["p_seq([", Head, Statements, "])"]
+ end).
+
+-spec 'labeled_primary'(input(), index()) -> parse_result().
+'labeled_primary'(Input, Index) ->
+ p(Input, Index, 'labeled_primary', fun(I,D) -> (p_seq([p_optional(fun 'label'/2), fun 'primary'/2]))(I,D) end, fun(Node, _Idx) ->
+ case hd(Node) of
+ [] -> lists:nth(2, Node);
+ Label ->
+ used_combinator(p_label),
+ ["p_label('", Label, "', ", lists:nth(2, Node), ")"]
+ end
+ end).
+
+-spec 'label'(input(), index()) -> parse_result().
+'label'(Input, Index) ->
+ p(Input, Index, 'label', fun(I,D) -> (p_seq([fun 'alpha_char'/2, p_zero_or_more(fun 'alphanumeric_char'/2), p_string(<<":">>)]))(I,D) end, fun(Node, _Idx) ->
+ lists:sublist(Node, length(Node)-1)
+ end).
+
+-spec 'suffix'(input(), index()) -> parse_result().
+'suffix'(Input, Index) ->
+ p(Input, Index, 'suffix', fun(I,D) -> (p_choose([fun 'repetition_suffix'/2, fun 'optional_suffix'/2]))(I,D) end, fun(Node, _Idx) ->
+ case Node of
+ <<"*">> -> zero_or_more;
+ <<"+">> -> one_or_more;
+ <<"?">> -> optional
+ end
+ end).
+
+-spec 'optional_suffix'(input(), index()) -> parse_result().
+'optional_suffix'(Input, Index) ->
+ p(Input, Index, 'optional_suffix', fun(I,D) -> (p_string(<<"?">>))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'repetition_suffix'(input(), index()) -> parse_result().
+'repetition_suffix'(Input, Index) ->
+ p(Input, Index, 'repetition_suffix', fun(I,D) -> (p_choose([p_string(<<"+">>), p_string(<<"*">>)]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'prefix'(input(), index()) -> parse_result().
+'prefix'(Input, Index) ->
+ p(Input, Index, 'prefix', fun(I,D) -> (p_choose([p_string(<<"&">>), p_string(<<"!">>)]))(I,D) end, fun(Node, _Idx) ->
+ case Node of
+ <<"&">> -> assert;
+ <<"!">> -> not_
+ end
+ end).
+
+-spec 'atomic'(input(), index()) -> parse_result().
+'atomic'(Input, Index) ->
+ p(Input, Index, 'atomic', fun(I,D) -> (p_choose([fun 'terminal'/2, fun 'nonterminal'/2, fun 'parenthesized_expression'/2]))(I,D) end, fun(Node, _Idx) ->
+case Node of
+ {nonterminal, Symbol} ->
+ [<<"fun '">>, Symbol, <<"'/2">>];
+ _ -> Node
+end
+ end).
+
+-spec 'parenthesized_expression'(input(), index()) -> parse_result().
+'parenthesized_expression'(Input, Index) ->
+ p(Input, Index, 'parenthesized_expression', fun(I,D) -> (p_seq([p_string(<<"(">>), p_optional(fun 'space'/2), fun 'parsing_expression'/2, p_optional(fun 'space'/2), p_string(<<")">>)]))(I,D) end, fun(Node, _Idx) ->lists:nth(3, Node) end).
+
+-spec 'nonterminal'(input(), index()) -> parse_result().
+'nonterminal'(Input, Index) ->
+ p(Input, Index, 'nonterminal', fun(I,D) -> (p_seq([fun 'alpha_char'/2, p_zero_or_more(fun 'alphanumeric_char'/2)]))(I,D) end, fun(Node, Idx) ->
+ Symbol = unicode:characters_to_binary(Node),
+ add_nt(Symbol, Idx),
+ {nonterminal, Symbol}
+ end).
+
+-spec 'terminal'(input(), index()) -> parse_result().
+'terminal'(Input, Index) ->
+ p(Input, Index, 'terminal', fun(I,D) -> (p_choose([fun 'regexp_string'/2, fun 'quoted_string'/2, fun 'character_class'/2, fun 'anything_symbol'/2]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'regexp_string'(input(), index()) -> parse_result().
+'regexp_string'(Input, Index) ->
+ p(Input, Index, 'regexp_string', fun(I,D) -> (p_seq([p_string(<<"#">>), p_label('string', p_one_or_more(p_seq([p_not(p_string(<<"#">>)), p_choose([p_string(<<"\\#">>), p_anything()])]))), p_string(<<"#">>)]))(I,D) end, fun(Node, _Idx) ->
+ used_combinator(p_regexp),
+ ["p_regexp(<<\"",
+ % Escape \ and " as they are used in erlang string. Other sumbol stay as is.
+ % \ -> \\
+ % " -> \"
+ re:replace(proplists:get_value(string, Node), "\"|\\\\", "\\\\&", [{return, binary}, global]),
+ "\">>)"]
+ end).
+
+-spec 'quoted_string'(input(), index()) -> parse_result().
+'quoted_string'(Input, Index) ->
+ p(Input, Index, 'quoted_string', fun(I,D) -> (p_choose([fun 'single_quoted_string'/2, fun 'double_quoted_string'/2]))(I,D) end, fun(Node, _Idx) ->
+ used_combinator(p_string),
+ lists:flatten(["p_string(<<\"",
+ escape_string(unicode:characters_to_list(proplists:get_value(string, Node))),
+ "\">>)"])
+ end).
+
+-spec 'double_quoted_string'(input(), index()) -> parse_result().
+'double_quoted_string'(Input, Index) ->
+ p(Input, Index, 'double_quoted_string', fun(I,D) -> (p_seq([p_string(<<"\"">>), p_label('string', p_zero_or_more(p_seq([p_not(p_string(<<"\"">>)), p_choose([p_string(<<"\\\\">>), p_string(<<"\\\"">>), p_anything()])]))), p_string(<<"\"">>)]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'single_quoted_string'(input(), index()) -> parse_result().
+'single_quoted_string'(Input, Index) ->
+ p(Input, Index, 'single_quoted_string', fun(I,D) -> (p_seq([p_string(<<"\'">>), p_label('string', p_zero_or_more(p_seq([p_not(p_string(<<"\'">>)), p_choose([p_string(<<"\\\\">>), p_string(<<"\\\'">>), p_anything()])]))), p_string(<<"\'">>)]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'character_class'(input(), index()) -> parse_result().
+'character_class'(Input, Index) ->
+ p(Input, Index, 'character_class', fun(I,D) -> (p_seq([p_string(<<"[">>), p_label('characters', p_one_or_more(p_seq([p_not(p_string(<<"]">>)), p_choose([p_seq([p_string(<<"\\\\">>), p_anything()]), p_seq([p_not(p_string(<<"\\\\">>)), p_anything()])])]))), p_string(<<"]">>)]))(I,D) end, fun(Node, _Idx) ->
+ used_combinator(p_charclass),
+ ["p_charclass(<<\"[",
+ escape_string(unicode:characters_to_list(proplists:get_value(characters, Node))),
+ "]\">>)"]
+ end).
+
+-spec 'anything_symbol'(input(), index()) -> parse_result().
+'anything_symbol'(Input, Index) ->
+ p(Input, Index, 'anything_symbol', fun(I,D) -> (p_string(<<".">>))(I,D) end, fun(_Node, _Idx) -> used_combinator(p_anything), <<"p_anything()">> end).
+
+-spec 'alpha_char'(input(), index()) -> parse_result().
+'alpha_char'(Input, Index) ->
+ p(Input, Index, 'alpha_char', fun(I,D) -> (p_charclass(<<"[A-Za-z_]">>))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'alphanumeric_char'(input(), index()) -> parse_result().
+'alphanumeric_char'(Input, Index) ->
+ p(Input, Index, 'alphanumeric_char', fun(I,D) -> (p_choose([fun 'alpha_char'/2, p_charclass(<<"[0-9]">>)]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'space'(input(), index()) -> parse_result().
+'space'(Input, Index) ->
+ p(Input, Index, 'space', fun(I,D) -> (p_one_or_more(p_choose([fun 'white'/2, fun 'comment_to_eol'/2])))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'comment_to_eol'(input(), index()) -> parse_result().
+'comment_to_eol'(Input, Index) ->
+ p(Input, Index, 'comment_to_eol', fun(I,D) -> (p_seq([p_not(p_string(<<"%{">>)), p_string(<<"%">>), p_zero_or_more(p_seq([p_not(p_string(<<"\n">>)), p_anything()]))]))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'white'(input(), index()) -> parse_result().
+'white'(Input, Index) ->
+ p(Input, Index, 'white', fun(I,D) -> (p_charclass(<<"[\s\t\n\r]">>))(I,D) end, fun(Node, _Idx) ->Node end).
+
+-spec 'code_block'(input(), index()) -> parse_result().
+'code_block'(Input, Index) ->
+ p(Input, Index, 'code_block', fun(I,D) -> (p_choose([p_seq([p_string(<<"%{">>), p_label('code', p_one_or_more(p_choose([p_string(<<"\\%">>), p_string(<<"$%">>), p_seq([p_not(p_string(<<"%}">>)), p_anything()])]))), p_string(<<"%}">>)]), p_seq([p_string(<<"`">>), p_label('code', p_one_or_more(p_choose([p_string(<<"\\`">>), p_string(<<"$`">>), p_seq([p_not(p_string(<<"`">>)), p_anything()])]))), p_string(<<"`">>)]), p_string(<<"~">>)]))(I,D) end, fun(Node, _Idx) ->
+ case Node of
+ <<"~">> -> {code, <<"Node">>};
+ _ -> {code, proplists:get_value('code', Node)}
+ end
+ end).
+
+
+
+-file("peg_includes.hrl", 1).
+-type index() :: {{line, pos_integer()}, {column, pos_integer()}}.
+-type input() :: binary().
+-type parse_failure() :: {fail, term()}.
+-type parse_success() :: {term(), input(), index()}.
+-type parse_result() :: parse_failure() | parse_success().
+-type parse_fun() :: fun((input(), index()) -> parse_result()).
+-type xform_fun() :: fun((input(), index()) -> term()).
+
+-spec p(input(), index(), atom(), parse_fun(), xform_fun()) -> parse_result().
+p(Inp, StartIndex, Name, ParseFun, TransformFun) ->
+ case get_memo(StartIndex, Name) of % See if the current reduction is memoized
+ {ok, Memo} -> %Memo; % If it is, return the stored result
+ Memo;
+ _ -> % If not, attempt to parse
+ Result = case ParseFun(Inp, StartIndex) of
+ {fail,_} = Failure -> % If it fails, memoize the failure
+ Failure;
+ {Match, InpRem, NewIndex} -> % If it passes, transform and memoize the result.
+ Transformed = TransformFun(Match, StartIndex),
+ {Transformed, InpRem, NewIndex}
+ end,
+ memoize(StartIndex, Name, Result),
+ Result
+ end.
+
+-spec setup_memo() -> ets:tid().
+setup_memo() ->
+ put({parse_memo_table, ?MODULE}, ets:new(?MODULE, [set])).
+
+-spec release_memo() -> true.
+release_memo() ->
+ ets:delete(memo_table_name()).
+
+-spec memoize(index(), atom(), parse_result()) -> true.
+memoize(Index, Name, Result) ->
+ Memo = case ets:lookup(memo_table_name(), Index) of
+ [] -> [];
+ [{Index, Plist}] -> Plist
+ end,
+ ets:insert(memo_table_name(), {Index, [{Name, Result}|Memo]}).
+
+-spec get_memo(index(), atom()) -> {ok, term()} | {error, not_found}.
+get_memo(Index, Name) ->
+ case ets:lookup(memo_table_name(), Index) of
+ [] -> {error, not_found};
+ [{Index, Plist}] ->
+ case proplists:lookup(Name, Plist) of
+ {Name, Result} -> {ok, Result};
+ _ -> {error, not_found}
+ end
+ end.
+
+-spec memo_table_name() -> ets:tid().
+memo_table_name() ->
+ get({parse_memo_table, ?MODULE}).
+
+-ifdef(p_eof).
+-spec p_eof() -> parse_fun().
+p_eof() ->
+ fun(<<>>, Index) -> {eof, [], Index};
+ (_, Index) -> {fail, {expected, eof, Index}} end.
+-endif.
+
+-ifdef(p_optional).
+-spec p_optional(parse_fun()) -> parse_fun().
+p_optional(P) ->
+ fun(Input, Index) ->
+ case P(Input, Index) of
+ {fail,_} -> {[], Input, Index};
+ {_, _, _} = Success -> Success
+ end
+ end.
+-endif.
+
+-ifdef(p_not).
+-spec p_not(parse_fun()) -> parse_fun().
+p_not(P) ->
+ fun(Input, Index)->
+ case P(Input,Index) of
+ {fail,_} ->
+ {[], Input, Index};
+ {Result, _, _} -> {fail, {expected, {no_match, Result},Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_assert).
+-spec p_assert(parse_fun()) -> parse_fun().
+p_assert(P) ->
+ fun(Input,Index) ->
+ case P(Input,Index) of
+ {fail,_} = Failure-> Failure;
+ _ -> {[], Input, Index}
+ end
+ end.
+-endif.
+
+-ifdef(p_seq).
+-spec p_seq([parse_fun()]) -> parse_fun().
+p_seq(P) ->
+ fun(Input, Index) ->
+ p_all(P, Input, Index, [])
+ end.
+
+-spec p_all([parse_fun()], input(), index(), [term()]) -> parse_result().
+p_all([], Inp, Index, Accum ) -> {lists:reverse( Accum ), Inp, Index};
+p_all([P|Parsers], Inp, Index, Accum) ->
+ case P(Inp, Index) of
+ {fail, _} = Failure -> Failure;
+ {Result, InpRem, NewIndex} -> p_all(Parsers, InpRem, NewIndex, [Result|Accum])
+ end.
+-endif.
+
+-ifdef(p_choose).
+-spec p_choose([parse_fun()]) -> parse_fun().
+p_choose(Parsers) ->
+ fun(Input, Index) ->
+ p_attempt(Parsers, Input, Index, none)
+ end.
+
+-spec p_attempt([parse_fun()], input(), index(), none | parse_failure()) -> parse_result().
+p_attempt([], _Input, _Index, Failure) -> Failure;
+p_attempt([P|Parsers], Input, Index, FirstFailure)->
+ case P(Input, Index) of
+ {fail, _} = Failure ->
+ case FirstFailure of
+ none -> p_attempt(Parsers, Input, Index, Failure);
+ _ -> p_attempt(Parsers, Input, Index, FirstFailure)
+ end;
+ Result -> Result
+ end.
+-endif.
+
+-ifdef(p_zero_or_more).
+-spec p_zero_or_more(parse_fun()) -> parse_fun().
+p_zero_or_more(P) ->
+ fun(Input, Index) ->
+ p_scan(P, Input, Index, [])
+ end.
+-endif.
+
+-ifdef(p_one_or_more).
+-spec p_one_or_more(parse_fun()) -> parse_fun().
+p_one_or_more(P) ->
+ fun(Input, Index)->
+ Result = p_scan(P, Input, Index, []),
+ case Result of
+ {[_|_], _, _} ->
+ Result;
+ _ ->
+ {fail, {expected, Failure, _}} = P(Input,Index),
+ {fail, {expected, {at_least_one, Failure}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_label).
+-spec p_label(atom(), parse_fun()) -> parse_fun().
+p_label(Tag, P) ->
+ fun(Input, Index) ->
+ case P(Input, Index) of
+ {fail,_} = Failure ->
+ Failure;
+ {Result, InpRem, NewIndex} ->
+ {{Tag, Result}, InpRem, NewIndex}
+ end
+ end.
+-endif.
+
+-ifdef(p_scan).
+-spec p_scan(parse_fun(), input(), index(), [term()]) -> {[term()], input(), index()}.
+p_scan(_, <<>>, Index, Accum) -> {lists:reverse(Accum), <<>>, Index};
+p_scan(P, Inp, Index, Accum) ->
+ case P(Inp, Index) of
+ {fail,_} -> {lists:reverse(Accum), Inp, Index};
+ {Result, InpRem, NewIndex} -> p_scan(P, InpRem, NewIndex, [Result | Accum])
+ end.
+-endif.
+
+-ifdef(p_string).
+-spec p_string(binary()) -> parse_fun().
+p_string(S) ->
+ Length = erlang:byte_size(S),
+ fun(Input, Index) ->
+ try
+ <<S:Length/binary, Rest/binary>> = Input,
+ {S, Rest, p_advance_index(S, Index)}
+ catch
+ error:{badmatch,_} -> {fail, {expected, {string, S}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_anything).
+-spec p_anything() -> parse_fun().
+p_anything() ->
+ fun(<<>>, Index) -> {fail, {expected, any_character, Index}};
+ (Input, Index) when is_binary(Input) ->
+ <<C/utf8, Rest/binary>> = Input,
+ {<<C/utf8>>, Rest, p_advance_index(<<C/utf8>>, Index)}
+ end.
+-endif.
+
+-ifdef(p_charclass).
+-spec p_charclass(string() | binary()) -> parse_fun().
+p_charclass(Class) ->
+ {ok, RE} = re:compile(Class, [unicode, dotall]),
+ fun(Inp, Index) ->
+ case re:run(Inp, RE, [anchored]) of
+ {match, [{0, Length}|_]} ->
+ {Head, Tail} = erlang:split_binary(Inp, Length),
+ {Head, Tail, p_advance_index(Head, Index)};
+ _ -> {fail, {expected, {character_class, binary_to_list(Class)}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(p_regexp).
+-spec p_regexp(binary()) -> parse_fun().
+p_regexp(Regexp) ->
+ {ok, RE} = re:compile(Regexp, [unicode, dotall, anchored]),
+ fun(Inp, Index) ->
+ case re:run(Inp, RE) of
+ {match, [{0, Length}|_]} ->
+ {Head, Tail} = erlang:split_binary(Inp, Length),
+ {Head, Tail, p_advance_index(Head, Index)};
+ _ -> {fail, {expected, {regexp, binary_to_list(Regexp)}, Index}}
+ end
+ end.
+-endif.
+
+-ifdef(line).
+-spec line(index() | term()) -> pos_integer() | undefined.
+line({{line,L},_}) -> L;
+line(_) -> undefined.
+-endif.
+
+-ifdef(column).
+-spec column(index() | term()) -> pos_integer() | undefined.
+column({_,{column,C}}) -> C;
+column(_) -> undefined.
+-endif.
+
+-spec p_advance_index(input() | unicode:charlist() | pos_integer(), index()) -> index().
+p_advance_index(MatchedInput, Index) when is_list(MatchedInput) orelse is_binary(MatchedInput)-> % strings
+ lists:foldl(fun p_advance_index/2, Index, unicode:characters_to_list(MatchedInput));
+p_advance_index(MatchedInput, Index) when is_integer(MatchedInput) -> % single characters
+ {{line, Line}, {column, Col}} = Index,
+ case MatchedInput of
+ $\n -> {{line, Line+1}, {column, 1}};
+ _ -> {{line, Line}, {column, Col+1}}
+ end.
diff --git a/inttest/neotoma1/neotoma_src_rt.erl b/inttest/neotoma1/neotoma_src_rt.erl
new file mode 100644
index 0000000..6f7c6ff
--- /dev/null
+++ b/inttest/neotoma1/neotoma_src_rt.erl
@@ -0,0 +1,81 @@
+%% -*- 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(neotoma_src_rt).
+
+-compile(export_all).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("deps/retest/include/retest.hrl").
+
+-define(GENERATED_MODULES,
+ [csv_peg]).
+
+files() ->
+ [{copy, "../../rebar", "rebar"},
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "mock", "deps"},
+ {copy, "src", "src"}].
+
+run(Dir) ->
+ retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
+ ?assertMatch({ok, _}, retest:sh("./rebar compile",
+ [{async, false}])),
+
+ ok = check_files_generated(),
+
+ retest_log:log(debug, "Verify cleanup~n", []),
+ ?assertMatch({ok, _}, retest_sh:run("./rebar clean",
+ [])),
+ ok = check_files_deleted(),
+ ok.
+
+check_files_generated() ->
+ check(fun filelib:is_regular/1,
+ generated_erl_files()).
+
+check_files_deleted() ->
+ check(fun file_does_not_exist/1,
+ generated_erl_files()).
+
+generated_erl_files() ->
+ add_dir("src", add_ext(?GENERATED_MODULES, ".erl")).
+
+add_ext(Modules, Ext) ->
+ [lists:concat([Module, Ext]) || Module <- Modules].
+
+add_dir(Dir, Files) ->
+ [filename:join(Dir, File) || File <- Files].
+
+file_does_not_exist(F) ->
+ not filelib:is_regular(F).
+
+check(Check, Files) ->
+ lists:foreach(
+ fun(F) ->
+ ?assertMatch({true, _}, {Check(F), F})
+ end,
+ Files).
diff --git a/inttest/neotoma1/rebar.config b/inttest/neotoma1/rebar.config
new file mode 100644
index 0000000..8757da8
--- /dev/null
+++ b/inttest/neotoma1/rebar.config
@@ -0,0 +1,15 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
+{deps,
+ [
+ %% The dependency below to neotoma is needed for "rebar compile" to
+ %% work, thus for the inttest to work, but the neotoma that is actually
+ %% used in inttest is brought in from the inttest/neotoma1/mock
+ %% subdirectory.
+ {neotoma, ".*"}
+ ]}.
+
+{neotoma_opts, [
+ {module_ext, "_peg"}
+]}.
diff --git a/inttest/neotoma1/src/csv.peg b/inttest/neotoma1/src/csv.peg
new file mode 100644
index 0000000..000c00f
--- /dev/null
+++ b/inttest/neotoma1/src/csv.peg
@@ -0,0 +1,31 @@
+rows <- head:row tail:(crlf row)* / ''
+`
+case Node of
+ [] -> [];
+ [""] -> [];
+ _ ->
+ Head = proplists:get_value(head, Node),
+ Tail = [R || [_,R] <- proplists:get_value(tail, Node)],
+ [Head|Tail]
+end
+`;
+
+row <- head:field tail:(field_sep field)* / ''
+`
+case Node of
+ [] -> [];
+ [""] -> [];
+ _ ->
+ Head = proplists:get_value(head, Node),
+ Tail = [F || [_,F] <- proplists:get_value(tail, Node)],
+ [Head|Tail]
+end
+`;
+field <- quoted_field / (!field_sep !crlf .)* `iolist_to_binary(Node)`;
+quoted_field <- '"' string:('""' / (!'"' .))* '"'
+`
+ String = proplists:get_value(string, Node),
+ re:replace(String, "[\"]{2}", "\"",[global, {return, binary}])
+`;
+field_sep <- ',' ~;
+crlf <- [\r]? [\n] ~;
diff --git a/inttest/neotoma1/src/neotoma1.app.src b/inttest/neotoma1/src/neotoma1.app.src
new file mode 100644
index 0000000..96a50e5
--- /dev/null
+++ b/inttest/neotoma1/src/neotoma1.app.src
@@ -0,0 +1,6 @@
+{application, neotoma1,
+ [{vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
+
diff --git a/inttest/port/port_rt.erl b/inttest/port/port_rt.erl
index 90ecbdc..c910e0e 100644
--- a/inttest/port/port_rt.erl
+++ b/inttest/port/port_rt.erl
@@ -31,13 +31,16 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "c_src", "c_src"},
{create, "ebin/foo.app", app(foo, [])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
%% wait a bit for new files to have different timestamps
@@ -45,48 +48,76 @@ run(_Dir) ->
%% 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"),
+ TestSo1 = filelib:last_modified("priv/test" ++
+ shared_library_file_extension(os:type())),
?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"),
+ TestSo2 = filelib:last_modified("priv/test" ++
+ shared_library_file_extension(os:type())),
+ Test1o2 = filelib:last_modified("c_src/test1" ++
+ object_file_extension(os:type())),
+ Test2o2 = filelib:last_modified("c_src/test2" ++
+ object_file_extension(os:type())),
?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:run({touch, "c_src/test2.c"}, [{dir, "."}])),
?assertMatch({ok, _}, retest_sh:run("./rebar compile", [])),
- TestSo3 = filelib:last_modified("priv/test.so"),
- Test2o3 = filelib:last_modified("c_src/test2.o"),
+ TestSo3 = filelib:last_modified("priv/test" ++
+ shared_library_file_extension(os:type())),
+ Test2o3 = filelib:last_modified("c_src/test2" ++
+ object_file_extension(os:type())),
?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.
+ %% detecting the a full recompile is needed when changing a .h file is a feature attained
+ %% by using the -MMD gcc flag which sadly is not available in Windows, so this part of the
+ %% test is only executed in Unix
+ case os:type() of
+ {win32, _} -> ok;
+ _ ->
+ wait(),
+ %% when test2.h changes, at least test2.o and test.so are rebuilt
+ ?assertMatch({ok, _},
+ retest:run({touch, "c_src/test2.h"}, [{dir, "."}])),
+ ?assertMatch({ok, _},
+ retest_sh:run("./rebar compile", [])),
+ TestSo4 = filelib:last_modified("priv/test" ++
+ shared_library_file_extension(os:type())),
+ Test2o4 = filelib:last_modified("c_src/test2" ++
+ object_file_extension(os:type())),
+ ?assert(TestSo4 > TestSo3),
+ ?assert(Test2o4 > TestSo3),
+ wait(),
+ %% when test1.h changes, everything is rebuilt
+ ?assertMatch({ok, _},
+ retest:run({touch, "c_src/test1.h"}, [{dir, "."}])),
+ ?assertMatch({ok, _},
+ retest_sh:run("./rebar compile", [])),
+ TestSo5 = filelib:last_modified("priv/test" ++
+ shared_library_file_extension(os:type())),
+ Test1o5 = filelib:last_modified("c_src/test1" ++
+ object_file_extension(os:type())),
+ Test2o5 = filelib:last_modified("c_src/test2" ++
+ object_file_extension(os:type())),
+ ?assert(TestSo5 > TestSo4),
+ ?assert(Test1o5 > TestSo4),
+ ?assert(Test2o5 > TestSo4),
+ ok
+ end.
wait() ->
timer:sleep(1000).
+object_file_extension({win32, nt}) -> ".o";
+object_file_extension(_) -> ".o".
+
+shared_library_file_extension({win32, nt}) -> ".dll";
+shared_library_file_extension(_) -> ".so".
+
%%
%% Generate the contents of a simple .app file
%%
diff --git a/inttest/port/rebar.config b/inttest/port/rebar.config
index a941218..efab1af 100644
--- a/inttest/port/rebar.config
+++ b/inttest/port/rebar.config
@@ -1 +1,2 @@
-{port_specs, [{"priv/test.so", ["c_src/*.c"]}]}.
+{port_specs, [{"win32", "priv/test.dll", ["c_src/*.c"]},
+ {"priv/test.so", ["c_src/*.c"]}]}.
diff --git a/inttest/port2/c_src/test1.c b/inttest/port2/c_src/test1.c
new file mode 100644
index 0000000..f1c8ef8
--- /dev/null
+++ b/inttest/port2/c_src/test1.c
@@ -0,0 +1,13 @@
+#include "test1.h"
+
+#ifndef TEST1
+#error TEST1 is not defined!
+#endif
+
+#ifndef TEST2
+#error TEST2 is not defined!
+#endif
+
+#ifndef TEST3
+#error TEST3 is not defined!
+#endif
diff --git a/inttest/port2/c_src/test1.h b/inttest/port2/c_src/test1.h
new file mode 100644
index 0000000..e69de29
diff --git a/inttest/port2/port2_rt.erl b/inttest/port2/port2_rt.erl
new file mode 100644
index 0000000..ffe8f23
--- /dev/null
+++ b/inttest/port2/port2_rt.erl
@@ -0,0 +1,75 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+%% -------------------------------------------------------------------
+%%
+%% rebar: Erlang Build Tools
+%%
+%% Copyright (c) 2016 Luis Rascao
+%%
+%% 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(port2_rt).
+-export([files/0,
+ run/1]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+files() ->
+ [
+ {copy, "rebar.config", "rebar.config"},
+ {copy, "c_src", "c_src"},
+ {create, "ebin/foo.app", app(foo, [])}
+ ] ++ inttest_utils:rebar_setup().
+
+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",
+ [{env, [{"ERL_CFLAGS", "-DTEST3=test3"}]}])),
+ TestSo1 = filelib:last_modified("priv/test" ++
+ shared_library_file_extension(os:type())),
+ ?assert(TestSo1 > 0).
+
+wait() ->
+ timer:sleep(1000).
+
+object_file_extension({win32, nt}) -> ".o";
+object_file_extension(_) -> ".o".
+
+shared_library_file_extension({win32, nt}) -> ".dll";
+shared_library_file_extension(_) -> ".so".
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/port2/rebar.config b/inttest/port2/rebar.config
new file mode 100644
index 0000000..3527ee5
--- /dev/null
+++ b/inttest/port2/rebar.config
@@ -0,0 +1,9 @@
+{port_specs, [
+ {"(darwin|linux|freebsd)", "priv/test.so",
+ ["c_src/*.c"], [
+ {env, [
+ {"CFLAGS", "$CFLAGS -DTEST1=test1"},
+ {"ERL_CFLAGS", "$ERL_CFLAGS -DTEST2=test2"}
+ ]}
+ ]}
+]}.
diff --git a/inttest/profile/profile_rt.erl b/inttest/profile/profile_rt.erl
index b128517..b8a9e09 100644
--- a/inttest/profile/profile_rt.erl
+++ b/inttest/profile/profile_rt.erl
@@ -30,10 +30,12 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [
- {copy, "../../rebar", "rebar"}
- ].
+ inttest_utils:rebar_setup().
run(_Dir) ->
Cmd = "./rebar list-deps",
diff --git a/inttest/proto_gpb/proto_gpb_rt.erl b/inttest/proto_gpb/proto_gpb_rt.erl
index 8a7cacf..307aca0 100644
--- a/inttest/proto_gpb/proto_gpb_rt.erl
+++ b/inttest/proto_gpb/proto_gpb_rt.erl
@@ -30,7 +30,6 @@
-include_lib("eunit/include/eunit.hrl").
-include_lib("kernel/include/file.hrl").
--include_lib("deps/retest/include/retest.hrl").
-define(MODULES,
[foo,
@@ -51,9 +50,12 @@
"c/test4.proto",
"c/d/test5.proto"]).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "rebar2.config", "rebar2.config"},
{copy, "rebar.bad.config", "rebar.bad.config"},
@@ -63,7 +65,7 @@ files() ->
{copy, "proto.bad", "proto.bad"},
{copy, "mock", "deps"},
{create, "ebin/foo.app", app(foo, ?MODULES ++ ?GENERATED_MODULES)}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
% perform test obtaining the .proto files from src dir
@@ -99,7 +101,7 @@ run_from_dir(success_expected, ProtoDir, ConfigFile) ->
%% the .hrl file was generated before foo was compiled.
ok = check_beams_generated(),
- ?DEBUG("Verifying recompilation~n", []),
+ retest_log:log(debug, "Verifying recompilation~n", []),
TestErl = hd(generated_erl_files()),
TestProto = hd(source_proto_files(ProtoDir)),
make_proto_newer_than_erl(TestProto, TestErl),
@@ -111,7 +113,7 @@ run_from_dir(success_expected, ProtoDir, ConfigFile) ->
TestMTime2 = read_mtime(TestErl),
?assert(TestMTime2 > TestMTime1),
- ?DEBUG("Verifying recompilation with no changes~n", []),
+ retest_log:log(debug, "Verifying recompilation with no changes~n", []),
TestMTime3 = read_mtime(TestErl),
?assertMatch({ok, _}, retest_sh:run("./rebar --config "
++ ConfigFile
@@ -120,7 +122,7 @@ run_from_dir(success_expected, ProtoDir, ConfigFile) ->
TestMTime4 = read_mtime(TestErl),
?assert(TestMTime3 =:= TestMTime4),
- ?DEBUG("Verify cleanup~n", []),
+ retest_log:log(debug, "Verify cleanup~n", []),
?assertMatch({ok, _}, retest_sh:run("./rebar --config "
++ ConfigFile
++ " clean",
diff --git a/inttest/proto_protobuffs/proto_protobuffs_rt.erl b/inttest/proto_protobuffs/proto_protobuffs_rt.erl
index 1bb7b5e..ee4c294 100644
--- a/inttest/proto_protobuffs/proto_protobuffs_rt.erl
+++ b/inttest/proto_protobuffs/proto_protobuffs_rt.erl
@@ -42,15 +42,18 @@
"foo_sup.beam",
"test_pb.beam"]).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
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)}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
?assertMatch({ok, _}, retest_sh:run("./rebar clean", [])),
diff --git a/inttest/rebar3_deps1/a.erl b/inttest/rebar3_deps1/a.erl
new file mode 100644
index 0000000..835522a
--- /dev/null
+++ b/inttest/rebar3_deps1/a.erl
@@ -0,0 +1,8 @@
+-module(a).
+
+-compile(export_all).
+
+-include_lib("b/include/b.hrl").
+
+hello() ->
+ io:format("~s\n", [?HELLO]).
diff --git a/inttest/rebar3_deps1/a.rebar.config b/inttest/rebar3_deps1/a.rebar.config
new file mode 100644
index 0000000..de3abe3
--- /dev/null
+++ b/inttest/rebar3_deps1/a.rebar.config
@@ -0,0 +1,4 @@
+{deps, [
+ {b, {git, "../repo/b"}},
+ {c, {git, "../repo/c"}, [raw]}
+]}.
diff --git a/inttest/rebar3_deps1/b.hrl b/inttest/rebar3_deps1/b.hrl
new file mode 100644
index 0000000..25dfeda
--- /dev/null
+++ b/inttest/rebar3_deps1/b.hrl
@@ -0,0 +1 @@
+-define(HELLO, "Hi From B").
diff --git a/inttest/rebar3_deps1/c.txt b/inttest/rebar3_deps1/c.txt
new file mode 100644
index 0000000..5adcd3d
--- /dev/null
+++ b/inttest/rebar3_deps1/c.txt
@@ -0,0 +1 @@
+This is a text file.
diff --git a/inttest/rebar3_deps1/rebar3_deps1_rt.erl b/inttest/rebar3_deps1/rebar3_deps1_rt.erl
new file mode 100644
index 0000000..e84b6ba
--- /dev/null
+++ b/inttest/rebar3_deps1/rebar3_deps1_rt.erl
@@ -0,0 +1,63 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar3_deps1_rt).
+
+-compile(export_all).
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+%% Test deps with rebar3-type dependencies (that is, dependencies without Regexes)
+%% Example: {git, {appname, "git://something/something", {branch, master}}}
+files() ->
+ [
+ %% A application
+ {create, "ebin/a.app", app(a, [a])},
+ {copy, "a.rebar.config", "rebar.config"},
+ {copy, "a.erl", "src/a.erl"},
+
+ %% B application
+ {create, "repo/b/ebin/b.app", app(b, [])},
+ {copy, "b.hrl", "repo/b/include/b.hrl"},
+
+ {copy, "c.txt", "repo/c/c.txt"}
+
+ ] ++ inttest_utils:rebar_setup().
+
+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 dep app as git repos so that dependencies pull
+ %% properly
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'tdeps@example.com'",
+ "git config user.name 'tdeps'",
+ "git commit -a -m \"Initial Commit\""],
+ apply_cmds(GitCmds, [{dir, "repo/b"}]),
+ apply_cmds(GitCmds, [{dir, "repo/c"}]),
+
+ {ok, _} = retest_sh:run("./rebar get-deps", []),
+ {ok, _} = retest_sh:run("./rebar compile", []),
+
+ true = filelib:is_regular("ebin/a.beam"),
+ true = filelib:is_regular("deps/c/c.txt"),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/require_vsn/require_vsn_rt.erl b/inttest/require_vsn/require_vsn_rt.erl
index 0b947c5..8ff87f7 100644
--- a/inttest/require_vsn/require_vsn_rt.erl
+++ b/inttest/require_vsn/require_vsn_rt.erl
@@ -28,12 +28,15 @@
-export([files/0,
run/1]).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{create, "ebin/require_vsn.app", app(require_vsn, [])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
SharedExpected = "==> require_vsn_rt \\(compile\\)",
diff --git a/inttest/rgen1/retest.config b/inttest/rgen1/retest.config
index b569f14..244096d 100644
--- a/inttest/rgen1/retest.config
+++ b/inttest/rgen1/retest.config
@@ -1 +1 @@
-{timeout, 120000}.
+{timeout, 240000}.
diff --git a/inttest/rgen1/rgen1_rt.erl b/inttest/rgen1/rgen1_rt.erl
index 1bf36c2..5847f4a 100644
--- a/inttest/rgen1/rgen1_rt.erl
+++ b/inttest/rgen1/rgen1_rt.erl
@@ -6,13 +6,16 @@
%% Exercise release generation w/ templating
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
{copy, "reltool.config"},
{copy, "test.config"},
- {copy, "vars.config"},
- {copy, "../../rebar"}
- ].
+ {copy, "vars.config"}
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
{ok, _} = retest_sh:run("./rebar -v generate", []),
diff --git a/inttest/t_custom_config/t_custom_config_rt.erl b/inttest/t_custom_config/t_custom_config_rt.erl
index a373b32..1f21927 100644
--- a/inttest/t_custom_config/t_custom_config_rt.erl
+++ b/inttest/t_custom_config/t_custom_config_rt.erl
@@ -6,10 +6,15 @@
-include_lib("eunit/include/eunit.hrl").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
- [{copy, "../../rebar", "rebar"},
+ [
{copy, "custom.config", "custom.config"},
- {create, "ebin/custom_config.app", app(custom_config, [custom_config])}].
+ {create, "ebin/custom_config.app", app(custom_config, [custom_config])}
+ ] ++ inttest_utils:rebar_setup().
run(Dir) ->
retest_log:log(debug, "Running in Dir: ~s~n", [Dir]),
diff --git a/inttest/tdeps1/tdeps1_rt.erl b/inttest/tdeps1/tdeps1_rt.erl
index 3591ec0..849403b 100644
--- a/inttest/tdeps1/tdeps1_rt.erl
+++ b/inttest/tdeps1/tdeps1_rt.erl
@@ -4,16 +4,18 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
%% Exercise transitive dependencies
%% A -> B -> C, where A includes a .hrl from B which includes .hrl from C
-
files() ->
[
%% A application
{create, "ebin/a.app", app(a, [a])},
{copy, "a.rebar.config", "rebar.config"},
{copy, "a.erl", "src/a.erl"},
- {copy, "../../rebar", "rebar"},
%% B application
{create, "repo/b/ebin/b.app", app(b, [])},
@@ -23,7 +25,7 @@ files() ->
%% C application
{create, "repo/c/ebin/c.app", app(c, [])},
{copy, "c.hrl", "repo/c/include/c.hrl"}
- ].
+ ] ++ inttest_utils:rebar_setup().
apply_cmds([], _Params) ->
ok;
@@ -39,7 +41,7 @@ run(_Dir) ->
"git add -A",
"git config user.email 'tdeps@example.com'",
"git config user.name 'tdeps'",
- "git commit -a -m 'Initial Commit'"],
+ "git commit -a -m \"Initial Commit\""],
apply_cmds(GitCmds, [{dir, "repo/b"}]),
apply_cmds(GitCmds, [{dir, "repo/c"}]),
diff --git a/inttest/tdeps2/tdeps2_rt.erl b/inttest/tdeps2/tdeps2_rt.erl
index 97a24ce..a5665ad 100644
--- a/inttest/tdeps2/tdeps2_rt.erl
+++ b/inttest/tdeps2/tdeps2_rt.erl
@@ -4,10 +4,13 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
%% Exercise transitive dependencies where there are multiple files
%% depending on the same set of deps
%% [A1, A2] -> B -> C ; A1 and A2 includes B.hrl which includes C.hrl
-
files() ->
[
%% A1 application
@@ -21,7 +24,6 @@ files() ->
{template, "a.erl", "apps/a2/src/a2.erl", dict:from_list([{module, a2}])},
{copy, "root.rebar.config", "rebar.config"},
- {copy, "../../rebar", "rebar"},
%% B application
{create, "repo/b/ebin/b.app", app(b, [])},
@@ -31,7 +33,7 @@ files() ->
%% C application
{create, "repo/c/ebin/c.app", app(c, [])},
{copy, "c.hrl", "repo/c/include/c.hrl"}
- ].
+ ] ++ inttest_utils:rebar_setup().
apply_cmds([], _Params) ->
ok;
@@ -47,7 +49,7 @@ run(_Dir) ->
"git add -A",
"git config user.email 'tdeps@example.com'",
"git config user.name 'tdeps'",
- "git commit -a -m 'Initial Commit'"],
+ "git commit -a -m \"Initial Commit\""],
ok = apply_cmds(GitCmds, [{dir, "repo/b"}]),
ok = apply_cmds(GitCmds, [{dir, "repo/c"}]),
diff --git a/inttest/tdeps3/tdeps3_rt.erl b/inttest/tdeps3/tdeps3_rt.erl
index f56b3ca..bc47772 100644
--- a/inttest/tdeps3/tdeps3_rt.erl
+++ b/inttest/tdeps3/tdeps3_rt.erl
@@ -4,12 +4,15 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
%% 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
@@ -17,7 +20,6 @@ files() ->
{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])},
@@ -52,7 +54,7 @@ files() ->
{create, "repo/b/apps/g/ebin/g.app", app(g, [])},
{copy, "e.hrl", "repo/b/apps/g/include/g.hrl"}
- ].
+ ] ++ inttest_utils:rebar_setup().
apply_cmds([], _Params) ->
ok;
@@ -68,7 +70,7 @@ run(_Dir) ->
"git add -A",
"git config user.email 'tdeps@example.com'",
"git config user.name 'tdeps'",
- "git commit -a -m 'Initial Commit'"],
+ "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"}]),
diff --git a/inttest/tdeps_prefer/a.erl b/inttest/tdeps_prefer/a.erl
new file mode 100644
index 0000000..bf413a6
--- /dev/null
+++ b/inttest/tdeps_prefer/a.erl
@@ -0,0 +1,4 @@
+-module({{module}}).
+
+-include_lib("b/include/b.hrl").
+-include_lib("c/include/c.hrl").
diff --git a/inttest/tdeps_prefer/a.rebar.config b/inttest/tdeps_prefer/a.rebar.config
new file mode 100644
index 0000000..41fe9bc
--- /dev/null
+++ b/inttest/tdeps_prefer/a.rebar.config
@@ -0,0 +1,4 @@
+{deps, [
+ {c, "1", {git, "../repo/c"}},
+ {b, "1", {git, "../repo/b"}}
+]}.
diff --git a/inttest/tdeps_prefer/b.hrl b/inttest/tdeps_prefer/b.hrl
new file mode 100644
index 0000000..9f02fab
--- /dev/null
+++ b/inttest/tdeps_prefer/b.hrl
@@ -0,0 +1 @@
+-define(HELLO, hello).
diff --git a/inttest/tdeps_prefer/c.hrl b/inttest/tdeps_prefer/c.hrl
new file mode 100644
index 0000000..152a99f
--- /dev/null
+++ b/inttest/tdeps_prefer/c.hrl
@@ -0,0 +1 @@
+-define(WORLD, world).
diff --git a/inttest/tdeps_prefer/root.rebar.config b/inttest/tdeps_prefer/root.rebar.config
new file mode 100644
index 0000000..d1c3793
--- /dev/null
+++ b/inttest/tdeps_prefer/root.rebar.config
@@ -0,0 +1 @@
+{sub_dirs, ["apps/a"]}.
diff --git a/inttest/tdeps_prefer/tdeps_prefer_rt.erl b/inttest/tdeps_prefer/tdeps_prefer_rt.erl
new file mode 100644
index 0000000..94c9b8f
--- /dev/null
+++ b/inttest/tdeps_prefer/tdeps_prefer_rt.erl
@@ -0,0 +1,68 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(tdeps_prefer_rt).
+
+-compile(export_all).
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+%% Test REBAR_DEPS_FORCE_LIB
+%% A -> [B, C]
+%% where B should be found globally and C should be found locally
+files() ->
+ [
+ %% A application
+ {create, "apps/a/ebin/a.app", app(a, [a])},
+ {copy, "a.rebar.config", "apps/a/rebar.config"},
+ {template, "a.erl", "apps/a/src/a.erl", dict:from_list([{module, a}])},
+
+ %% B application
+ {create, "libs/b-1/ebin/b.app", app(b, [])},
+ {copy, "b.hrl", "libs/b-1/include/b.hrl"},
+
+ %% C application
+ {create, "repo/c/ebin/c.app", app(c, [])},
+ {copy, "c.hrl", "repo/c/include/c.hrl"},
+
+ {copy, "root.rebar.config", "rebar.config"}
+ ] ++ inttest_utils:rebar_setup().
+
+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 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\""],
+ ErlLibs = filename:join(Dir, "libs"),
+ ok = apply_cmds(GitCmds, [{dir, "repo/c"}]),
+ Env = [
+ {"REBAR_DEPS_PREFER_LIBS", "1"},
+ {"ERL_LIBS", ErlLibs}
+ ],
+
+ {ok, _} = retest_sh:run("./rebar -v get-deps", [{env, Env}]),
+ {ok, _} = retest_sh:run("./rebar -v compile", [{env, Env}]),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, "1"},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
diff --git a/inttest/tdeps_update/tdeps_update_rt.erl b/inttest/tdeps_update/tdeps_update_rt.erl
index c53e253..b4919c5 100644
--- a/inttest/tdeps_update/tdeps_update_rt.erl
+++ b/inttest/tdeps_update/tdeps_update_rt.erl
@@ -4,6 +4,10 @@
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
%% Exercises update deps, with recursive dependency updates.
%% Initially:
%% A(v0.5) -> B(v0.2.3) -> C(v1.0)
@@ -25,7 +29,6 @@ files() ->
{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")},
@@ -64,57 +67,62 @@ files() ->
{copy, "c.rebar.config", "c.rebar.config"},
{copy, "c2.rebar.config", "c2.rebar.config"},
{copy, "c3.rebar.config", "c3.rebar.config"}
- ].
+ ] ++ inttest_utils:rebar_setup().
apply_cmds([], _Params) ->
ok;
apply_cmds([Cmd | Rest], Params) ->
- io:format("Running: ~s (~p)\n", [Cmd, Params]),
- {ok, _} = retest_sh:run(Cmd, Params),
+ io:format("Running: ~p (~p)\n", [Cmd, Params]),
+ {ok, _} = retest:run(Cmd, Params),
apply_cmds(Rest, Params).
-run(_Dir) ->
+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'"],
+ "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'",
+ {copy, "../../b2.rebar.config", "rebar.config"},
+ {copy, "../../b2.app", "ebin/b.app"},
+ {touch, "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'",
+ {copy, "../../b3.rebar.config", "rebar.config"},
+ {copy, "../../b3.app", "ebin/b.app"},
+ {touch, "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'",
+ {copy, "../../b4.rebar.config", "rebar.config"},
+ {copy, "../../b4.app", "ebin/b.app"},
+ {touch, "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",
+ {copy, "../../c2.hrl", "include/c.hrl"},
+ {copy, "../../c2.app", "ebin/c.app"},
+ {copy, "../../c.rebar.config", "rebar.config"},
"git add rebar.config",
- "git commit -a -m 'update to 1.1'",
+ "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'",
+ {copy, "../../c3.app", "ebin/c.app"},
+ {copy, "../../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'",
+ {copy, "../../c4.app", "ebin/c.app"},
+ {copy, "../../c3.rebar.config", "rebar.config"},
+ {touch, "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'",
+ {copy, "../../e2.app", "ebin/e.app"},
+ {touch, "ebin/e.app"},
+ "git commit -a -m \"update to 2.1\"",
"git tag 2.1"],
FCmds = ["git tag 0.1"],
@@ -126,13 +134,16 @@ run(_Dir) ->
{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"),
+ retest:run({copy, "a2.rebar.config", "apps/a1/rebar.config"},
+ [{dir, Dir}]),
{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"),
+ retest:run({copy, "a3.rebar.config", "apps/a1/rebar.config"},
+ [{dir, Dir}]),
{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"),
+ retest:run({copy, "a4.rebar.config", "apps/a1/rebar.config"},
+ [{dir, Dir}]),
{ok, _} = retest_sh:run("./rebar -v update-deps", []),
{ok, _} = retest_sh:run("./rebar -v compile", []),
ok.
diff --git a/inttest/thooks/thooks_rt.erl b/inttest/thooks/thooks_rt.erl
index 3cca6bb..f1e7fa4 100644
--- a/inttest/thooks/thooks_rt.erl
+++ b/inttest/thooks/thooks_rt.erl
@@ -5,14 +5,17 @@
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
%% dummy lfe files
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "fish.erl", "src/fish.erl"},
{create, "ebin/fish.app", app(fish, [fish])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
?assertMatch({ok, _}, retest_sh:run("./rebar -v clean compile", [])),
@@ -27,7 +30,13 @@ ensure_command_ran_only_once(Command) ->
?assert(filelib:is_regular(File)),
%% ensure that this command only ran once (not for each module)
{ok, Content} = file:read_file(File),
- ?assertEqual(Command ++ "\n", binary_to_list(Content)).
+ %% echo behaves differently in windows and unix
+ case os:type() of
+ {win32, nt} ->
+ ?assertEqual(Command ++ " \r\n", binary_to_list(Content));
+ _ ->
+ ?assertEqual(Command ++ "\n", binary_to_list(Content))
+ end.
%%
%% Generate the contents of a simple .app file
diff --git a/inttest/tplugins/tplugins_rt.erl b/inttest/tplugins/tplugins_rt.erl
index 01d296e..d36afdd 100644
--- a/inttest/tplugins/tplugins_rt.erl
+++ b/inttest/tplugins/tplugins_rt.erl
@@ -8,9 +8,12 @@
-define(COMPILE_ERROR,
"ERROR: Plugin bad_plugin contains compilation errors:").
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "bad.config", "bad.config"},
{copy, "fish.erl", "src/fish.erl"},
@@ -18,7 +21,7 @@ files() ->
{copy, "bad_plugin.erl", "bad_plugins/bad_plugin.erl"},
{create, "fwibble.test", <<"fwibble">>},
{create, "ebin/fish.app", app(fish, [fish])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
?assertMatch({ok, _}, retest_sh:run("./rebar fwibble -v", [])),
diff --git a/inttest/vsn_cache/main.erl b/inttest/vsn_cache/main.erl
new file mode 100644
index 0000000..67b6465
--- /dev/null
+++ b/inttest/vsn_cache/main.erl
@@ -0,0 +1,13 @@
+-module(main).
+-behaviour(application).
+
+-export([start/0,start/1,start/2,stop/1]).
+
+start() ->
+ start(permanent).
+start(_Restart) ->
+ ok.
+start(_Type,_Args) ->
+ ok.
+stop(_State) ->
+ ok.
diff --git a/inttest/vsn_cache/vsn_cache_rt.erl b/inttest/vsn_cache/vsn_cache_rt.erl
new file mode 100644
index 0000000..b482888
--- /dev/null
+++ b/inttest/vsn_cache/vsn_cache_rt.erl
@@ -0,0 +1,90 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(vsn_cache_rt).
+
+-compile(export_all).
+
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
+files() ->
+ [
+ %% Cache save check
+ {create, "save/src/save.app.src", app(save, [main])},
+ {create, "save/vsn_cache_file", ""},
+ {copy, "main.erl", "save/src/main.erl"},
+
+ %% Cache load check
+ {create, "load/src/load.app.src", app(load, [main])},
+ {copy, "main.erl", "load/src/main.erl"}
+ ] ++ inttest_utils:rebar_setup().
+
+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_save(Dir) ->
+ GitCmds = ["git init",
+ "git add -A",
+ "git config user.email 'vsn_cache@example.com'",
+ "git config user.name 'vsn_cache'",
+ "git commit -a -m \"Initial Commit\""],
+ AppDir = filename:join(Dir, "save"),
+ EbinDir = filename:join(AppDir, "ebin"),
+ AppFile = filename:join(EbinDir, "save.app"),
+ VsnCacheFile = filename:join(AppDir, "vsn_cache_file"),
+ Env = [{"REBAR_VSN_CACHE_FILE", VsnCacheFile}],
+
+ %% Initialize test git repository
+ ok = apply_cmds(GitCmds, [{dir, AppDir}]),
+ %% Compile test project with vsn cache enabled
+ {ok, _} = retest_sh:run("../rebar -v compile", [{env, Env}, {dir, AppDir}]),
+ %% Vsn cache file has an entry
+ {ok, [{{git, AppDir}, Hash}]} = file:consult(VsnCacheFile),
+ %% This vsn entry must coincide with entry from ebin/save.app
+ {ok, [{application, save, PropList}]} = file:consult(AppFile),
+ Hash = proplists:get_value(vsn, PropList),
+ ok.
+
+run_load(Dir) ->
+ AppDir = filename:join(Dir, "load"),
+ EbinDir = filename:join(AppDir, "ebin"),
+ AppFile = filename:join(EbinDir, "load.app"),
+ VsnCacheFile = filename:join(AppDir, "vsn_cache_file"),
+ Hash = "deadbeef",
+ CacheEntries = [{{git, AppDir}, Hash}],
+ Env = [{"REBAR_VSN_CACHE_FILE", VsnCacheFile}],
+
+ %% Initialize dummy vsn cache file
+ vsn_cache_file(VsnCacheFile, CacheEntries),
+ %% Compile test project with vsn cache enabled
+ {ok, _} = retest_sh:run("../rebar -v compile", [{env, Env}, {dir, AppDir}]),
+ %% This vsn entry in cache file must coincide with entry in ebin/load.app
+ {ok, [{application, load, PropList}]} = file:consult(AppFile),
+ Hash = proplists:get_value(vsn, PropList),
+ ok.
+
+run(Dir) ->
+ run_save(Dir),
+ run_load(Dir),
+ ok.
+
+%%
+%% Generate the contents of a simple .app file
+%%
+app(Name, Modules) ->
+ App = {application, Name,
+ [{description, atom_to_list(Name)},
+ {vsn, git},
+ {modules, Modules},
+ {registered, []},
+ {applications, [kernel, stdlib]}]},
+ io_lib:format("~p.\n", [App]).
+
+vsn_cache_file(Name, Entries) ->
+ file:write_file(Name,
+ [io_lib:format("~p.~n", [X]) || X <- Entries]).
diff --git a/inttest/xref_behavior/xref_behavior_rt.erl b/inttest/xref_behavior/xref_behavior_rt.erl
index 8536710..f6d5ff8 100644
--- a/inttest/xref_behavior/xref_behavior_rt.erl
+++ b/inttest/xref_behavior/xref_behavior_rt.erl
@@ -2,16 +2,19 @@
-export([files/0, run/1]).
+setup([Target]) ->
+ retest_utils:load_module(filename:join(Target, "inttest_utils.erl")),
+ ok.
+
files() ->
[
- {copy, "../../rebar", "rebar"},
{copy, "rebar.config", "rebar.config"},
{copy, "xref_behavior.erl", "src/xref_behavior.erl"},
{copy, "gen_xref_behavior.erl", "src/gen_xref_behavior.erl"},
{create, "ebin/xref_behavior.app", app(xref_behavior,
[xref_behavior,
gen_xref_behavior])}
- ].
+ ] ++ inttest_utils:rebar_setup().
run(_Dir) ->
{ok, _} = retest_sh:run("./rebar compile", []),
diff --git a/priv/templates/simplenode.windows.runner.cmd b/priv/templates/simplenode.windows.runner.cmd
index d71a8c7..1e3a3f3 100644
--- a/priv/templates/simplenode.windows.runner.cmd
+++ b/priv/templates/simplenode.windows.runner.cmd
@@ -17,8 +17,18 @@
@call :set_trim release_version %%J
)
-@set vm_args=%releases_dir%\%release_version%\vm.args
-@set sys_config=%releases_dir%\%release_version%\sys.config
+@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"
+)
+
+@if exist "%releases_dir%\%release_version%\sys.config" (
+ @set sys_config="%releases_dir%\%release_version%\sys.config"
+) else (
+ @set sys_config="%node_root%\etc\app.config"
+)
+
@set node_boot_script=%releases_dir%\%release_version%\%node_name%
@set clean_boot_script=%releases_dir%\%release_version%\start_clean
diff --git a/rebar.config.sample b/rebar.config.sample
index 916e47c..224c85c 100644
--- a/rebar.config.sample
+++ b/rebar.config.sample
@@ -148,6 +148,10 @@
%% Option to use short names (i.e., -sname test) when starting ct
{ct_use_short_names, true}.
+%% Recursively search for .spec files from the test dir, default
+%% is false (ie. the search will be from the current working directory)
+{ct_search_specs_from_test_dir, true}.
+
%% == QuickCheck ==
%% If qc_mod is unspecified, rebar tries to detect Triq or EQC
diff --git a/rebar.config.script b/rebar.config.script
index 6735645..eacd510 100644
--- a/rebar.config.script
+++ b/rebar.config.script
@@ -1,7 +1,8 @@
%% -*- 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"}}],
+ExtraDeps = [{retest, ".*", {git, "git://github.com/rebar/retest.git",
+ {tag, "1.1.0"}}}],
case os:getenv("REBAR_EXTRA_DEPS") of
false ->
diff --git a/src/rebar.erl b/src/rebar.erl
index dcfb353..5a809d2 100644
--- a/src/rebar.erl
+++ b/src/rebar.erl
@@ -143,7 +143,7 @@ init_config({Options, _NonOptArgs}) ->
%% 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()).
+ rebar_utils:init_vsn_cache(BaseConfig1).
init_config1(BaseConfig) ->
%% Determine the location of the rebar executable; important for pulling
@@ -284,7 +284,12 @@ help() ->
{"freebsd", compile, "c_src/freebsd_tweaks.sh"},
{eunit, "touch file2.out"},
{compile, "touch postcompile.out"}]}
- ]).
+ ]),
+ ?CONSOLE(
+ "Environment variables:~n"
+ " REBAR_DEPS_PREFER_LIBS to look for dependecies in system libs prior fetching.~n"
+ " REBAR_VSN_CACHE_FILE to load vsn cache from and save to specified file.~n"
+ "~n", []).
%%
%% Parse command line arguments using getopt and also filtering out any
@@ -501,7 +506,9 @@ option_spec_list() ->
{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."},
+ "fprof.analysis or eflame.svg. Additionally, in fprof mode, if "
+ "erlgrind can be found in $PATH, a Cachegrind file (fprof.cgrind) "
+ "will be generated as well."},
{keep_going, $k, "keep-going", undefined,
"Keep running after a command fails"},
{recursive, $r, "recursive", boolean,
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 0650430..6cc8d38 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -106,7 +106,7 @@ process_commands([Command | Rest], ParentConfig) ->
ParentConfig2),
%% Wipe out vsn cache to avoid invalid hits when
%% dependencies are updated
- rebar_config:set_xconf(ParentConfig3, vsn_cache, dict:new())
+ rebar_utils:init_vsn_cache(ParentConfig3)
catch
throw:rebar_abort ->
case rebar_config:get_xconf(ParentConfig1, keep_going, false) of
diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl
index 022dfc4..b27f661 100644
--- a/src/rebar_ct.erl
+++ b/src/rebar_ct.erl
@@ -66,6 +66,7 @@ info(help, ct) ->
" ~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"
@@ -81,7 +82,8 @@ info(help, ct) ->
{ct_dir, "itest"},
{ct_log_dir, "test/logs"},
{ct_extra_params, "-boot start_sasl -s myapp"},
- {ct_use_short_names, true}
+ {ct_use_short_names, true},
+ {ct_search_specs_from_test_dir, false}
]).
run_test_if_present(TestDir, LogDir, Config, File) ->
@@ -113,7 +115,12 @@ run_test(TestDir, LogDir, Config, _File) ->
false ->
" >> " ++ RawLog ++ " 2>&1";
true ->
+ case os:type() of
+ {win32, nt} ->
+ " >> " ++ RawLog ++ " 2>&1";
+ _ ->
" 2>&1 | tee -a " ++ RawLog
+ end
end,
ShOpts = [{env,[{"TESTDIR", TestDir}]}, return_on_error],
@@ -155,14 +162,27 @@ failure_logger(Command, {Rc, Output}) ->
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}\" "
- ++ RawLog, [{use_stdout, false}]),
- MakeFailed = string:str(Msg, "{error,make_failed}") =/= 0,
- RunFailed = string:str(Msg, ", 0 failed") =:= 0,
+check_log(Config,RawLogFilename,Fun) ->
+ %% read the file and split into a list separated by newlines
+ {ok, RawLog} = file:read_file(RawLogFilename),
+ Msg = string:tokens(binary_to_list(RawLog), "\n"),
+ %% now filter out all the list entries that do not have test
+ %% completion strings
+ CompleteRuns = lists:filter(fun(M) ->
+ string:str(M, "TEST COMPLETE") =/= 0
+ end, Msg),
+ MakeFailed = lists:filter(fun(M) ->
+ string:str(M, "{error,make_failed}") =/= 0
+ end, Msg),
+ %% the run has failed if at least one of the tests failed
+ RunFailed = lists:foldl(fun(M, Acc) ->
+ %% the "0 failed" string must be present for
+ %% the test to be considered successful
+ TestFailed = string:str(M, "0 failed") =:= 0,
+ TestFailed orelse Acc
+ end, false, CompleteRuns),
if
- MakeFailed ->
+ MakeFailed =/= [] ->
show_log(Config, RawLog),
?ERROR("Building tests failed\n",[]),
?FAIL;
@@ -182,8 +202,7 @@ show_log(Config, RawLog) ->
?CONSOLE("Showing log\n", []),
case rebar_log:is_verbose(Config) of
false ->
- {ok, Contents} = file:read_file(RawLog),
- ?CONSOLE("~s", [Contents]);
+ ?CONSOLE("~s", [RawLog]);
true ->
ok
end.
@@ -218,7 +237,7 @@ make_cmd(TestDir, RawLogDir, Config) ->
CodeDirs = [io_lib:format("\"~s\"", [Dir]) ||
Dir <- [EbinDir|NonLibCodeDirs]],
CodePathString = string:join(CodeDirs, " "),
- Cmd = case get_ct_specs(Config, Cwd) of
+ Cmd = case get_ct_specs(Config, search_ct_specs_from(Cwd, TestDir, Config)) of
undefined ->
?FMT("~s"
" -pa ~s"
@@ -259,10 +278,20 @@ make_cmd(TestDir, RawLogDir, Config) ->
RawLog = filename:join(LogDir, "raw.log"),
{Cmd, RawLog}.
+search_ct_specs_from(Cwd, TestDir, Config) ->
+ case rebar_config:get_local(Config, ct_search_specs_from_test_dir, false) of
+ true -> filename:join(Cwd, TestDir);
+ false ->
+ Cwd
+ end.
+
build_name(Config) ->
+ %% generate a unique name for our test node, we want
+ %% to make sure the odds of name clashing are low
+ Random = integer_to_list(crypto:rand_uniform(0, 10000)),
case rebar_config:get_local(Config, ct_use_short_names, false) of
- true -> "-sname test";
- false -> " -name test@" ++ net_adm:localhost()
+ true -> "-sname test" ++ Random;
+ false -> " -name test" ++ Random ++ "@" ++ net_adm:localhost()
end.
get_extra_params(Config) ->
diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl
index a6e5b27..251bdee 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -58,16 +58,19 @@ preprocess(Config, _) ->
%% used globally since it will be set on the first time through here
Config1 = set_shared_deps_dir(Config, get_shared_deps_dir(Config, [])),
+ %% Check whether user forced deps resolution via system wide libs
+ Config2 = set_deps_prefer_libs(Config1, get_deps_prefer_libs(Config1, undefined)),
+
%% Get the list of deps for the current working directory and identify those
%% deps that are available/present.
- Deps = rebar_config:get_local(Config1, deps, []),
- {Config2, {AvailableDeps, MissingDeps}} = find_deps(Config1, find, Deps),
+ Deps = rebar_config:get_local(Config2, deps, []),
+ {Config3, {AvailableDeps, MissingDeps}} = find_deps(Config2, find, Deps),
?DEBUG("Available deps: ~p\n", [AvailableDeps]),
?DEBUG("Missing deps : ~p\n", [MissingDeps]),
%% Add available deps to code path
- Config3 = update_deps_code_path(Config2, AvailableDeps),
+ Config4 = update_deps_code_path(Config3, AvailableDeps),
%% Filtering out 'raw' dependencies so that no commands other than
%% deps-related can be executed on their directories.
@@ -83,8 +86,8 @@ preprocess(Config, _) ->
fun(D, Acc) ->
rebar_config:set_skip_dir(Acc, D#dep.dir)
end,
- Config3,
- collect_deps(rebar_utils:get_cwd(), Config3)),
+ Config4,
+ collect_deps(rebar_utils:get_cwd(), Config4)),
%% Return the empty list, as we don't want anything processed before
%% us.
{ok, NewConfig, []};
@@ -97,12 +100,12 @@ preprocess(Config, _) ->
%% 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
+ case rebar_config:get_global(Config4, skip_deps, false) of
"true" ->
lists:foldl(
fun(#dep{dir = Dir}, C) ->
rebar_config:set_skip_dir(C, Dir)
- end, Config3, AvailableDeps);
+ end, Config4, AvailableDeps);
Apps when is_list(Apps) ->
SkipApps = [list_to_atom(App) ||
App <- string:tokens(Apps, ",")],
@@ -112,9 +115,9 @@ preprocess(Config, _) ->
true -> rebar_config:set_skip_dir(C, Dir);
false -> C
end
- end, Config3, AvailableDeps);
+ end, Config4, AvailableDeps);
_ ->
- Config3
+ Config4
end,
%% Return all the available dep directories for process
@@ -254,7 +257,9 @@ info_help(Description) ->
" ~p~n"
" ~p~n"
"Valid command line options:~n"
- " deps_dir=\"deps\" (override default or rebar.config deps_dir)~n",
+ " deps_dir=\"deps\" (override default or rebar.config deps_dir)~n"
+ "Environment variables:~n"
+ " REBAR_DEPS_PREFER_LIBS to look for dependecies in system libs prior fetching.~n",
[
Description,
{deps_dir, "deps"},
@@ -263,15 +268,24 @@ info_help(Description) ->
{rebar, "1.0.*"},
{rebar, ".*",
{git, "git://github.com/rebar/rebar.git"}},
+ {rebar,
+ {git, "git://github.com/rebar/rebar.git"}},
{rebar, ".*",
{git, "git://github.com/rebar/rebar.git", "Rev"}},
+ {rebar,
+ {git, "git://github.com/rebar/rebar.git", "Rev"}},
{rebar, "1.0.*",
{git, "git://github.com/rebar/rebar.git", {branch, "master"}}},
+ {rebar,
+ {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]},
+ {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"}},
@@ -302,6 +316,18 @@ set_shared_deps_dir(Config, _DepsDir) ->
get_shared_deps_dir(Config, Default) ->
rebar_config:get_xconf(Config, deps_dir, Default).
+set_deps_prefer_libs(Config, undefined) ->
+ DepsPreferLibs = case os:getenv("REBAR_DEPS_PREFER_LIBS") of
+ false -> false;
+ _ -> true
+ end,
+ rebar_config:set_xconf(Config, deps_prefer_libs, DepsPreferLibs);
+set_deps_prefer_libs(Config, _DepsPreferLibs) ->
+ Config.
+
+get_deps_prefer_libs(Config, Default) ->
+ rebar_config:get_xconf(Config, deps_prefer_libs, Default).
+
get_deps_dir(Config) ->
get_deps_dir(Config, "").
@@ -354,8 +380,12 @@ 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, Source} | Rest], Acc) when is_tuple(Source) ->
+ find_deps(Config, Mode, [{App, ".*", Source} | 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, Source, Opts} | Rest], Acc) when is_tuple(Source) ->
+ find_deps(Config, Mode, [{App, ".*", Source, Opts} | 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)
@@ -378,9 +408,15 @@ find_dep(Config, Dep) ->
%% 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(Config, Dep, Dep#dep.source).
-
-find_dep(Config, Dep, undefined) ->
+ DepsPreferLibs = get_deps_prefer_libs(Config, false),
+ Mode = case {Dep#dep.source, DepsPreferLibs} of
+ {undefined, _DepsPreferLibs} -> maybe_in_lib;
+ {_DepSource, true} -> maybe_in_lib;
+ {_DepSource, false} -> local_only
+ end,
+ find_dep(Config, Dep, Mode).
+
+find_dep(Config, Dep, maybe_in_lib) ->
%% 'source' is undefined. If Dep is not satisfied locally,
%% go ahead and find it amongst the lib_dir's.
case find_dep_in_dir(Config, Dep, get_deps_dir(Config, Dep#dep.app)) of
@@ -389,7 +425,7 @@ find_dep(Config, Dep, undefined) ->
{Config1, {missing, _}} ->
find_dep_in_dir(Config1, Dep, get_lib_dir(Dep#dep.app))
end;
-find_dep(Config, Dep, _Source) ->
+find_dep(Config, Dep, local_only) ->
%% _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
diff --git a/src/rebar_dia_compiler.erl b/src/rebar_dia_compiler.erl
index 56d5189..a45cd55 100644
--- a/src/rebar_dia_compiler.erl
+++ b/src/rebar_dia_compiler.erl
@@ -88,6 +88,8 @@ info_help(Description) ->
compile_dia(Source, Target, Config) ->
ok = filelib:ensure_dir(Target),
ok = filelib:ensure_dir(filename:join("include", "dummy.hrl")),
+ ok = filelib:ensure_dir(filename:join("ebin", "dummy.beam")),
+ true = code:add_path(filename:absname("ebin")),
Opts = [{outdir, "src"}] ++ rebar_config:get(Config, dia_opts, []),
case diameter_dict_util:parse({path, Source}, []) of
{ok, Spec} ->
diff --git a/src/rebar_eunit.erl b/src/rebar_eunit.erl
index 913f2f9..6026740 100644
--- a/src/rebar_eunit.erl
+++ b/src/rebar_eunit.erl
@@ -128,6 +128,7 @@ info_help(Description) ->
" 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"
+ " test[s]=\"foo:bar_test\" (Run bar_test located in module foo)~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"
@@ -460,7 +461,7 @@ make_test_primitives(RawTests) ->
%% Generator
MakePrimitive(generator, M, F2)
end,
- [NewFunction|Acc]
+ [eunit_module_suite(M, NewFunction)|Acc]
end,
lists:foldl(F, [], RawTests).
@@ -472,6 +473,11 @@ pre15b02_eunit_primitive(test, M, F) ->
pre15b02_eunit_primitive(generator, M, F) ->
{generator, eunit_test:function_wrapper(M, F)}.
+% Add a test group for eunit_surefire to be able to deduce the testsuite.
+% Calling eunit:test({module, M}) does exactly this as well.
+eunit_module_suite(M, X) ->
+ {"module '" ++ atom_to_list(M) ++ "'", X}.
+
%%
%% == run tests ==
%%
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index 0fc1403..a4d3be7 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -88,7 +88,7 @@ mv(Source, Dest) ->
?FMT("move /y \"~s\" \"~s\" 1> nul",
[filename:nativename(Source),
filename:nativename(Dest)]),
- [{use_stdout, false}, return_on_error]),
+ [{use_stdout, false}, abort_on_error]),
case R of
[] ->
ok;
@@ -131,14 +131,14 @@ delete_each_dir_win32([]) -> ok;
delete_each_dir_win32([Dir | Rest]) ->
{ok, []} = rebar_utils:sh(?FMT("rd /q /s \"~s\"",
[filename:nativename(Dir)]),
- [{use_stdout, false}, return_on_error]),
+ [{use_stdout, false}, abort_on_error]),
delete_each_dir_win32(Rest).
xcopy_win32(Source,Dest)->
{ok, R} = rebar_utils:sh(
?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
[filename:nativename(Source), filename:nativename(Dest)]),
- [{use_stdout, false}, return_on_error]),
+ [{use_stdout, false}, abort_on_error]),
case length(R) > 0 of
%% when xcopy fails, stdout is empty and and error message is printed
%% to stderr (which is redirected to nul)
@@ -162,8 +162,10 @@ cp_r_win32({false, Source} = S,{true, DestDir}) ->
cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
cp_r_win32({false, Source},{false, Dest}) ->
%% from file to file
- {ok,_} = file:copy(Source, Dest),
- ok;
+ case file:copy(Source, Dest) of
+ {ok,_} -> ok;
+ _ -> throw(rebar_abort)
+ end;
cp_r_win32({true, SourceDir}, {false, DestDir}) ->
case filelib:is_regular(DestDir) of
true ->
diff --git a/src/rebar_neotoma_compiler.erl b/src/rebar_neotoma_compiler.erl
index 5549dc4..f93d492 100644
--- a/src/rebar_neotoma_compiler.erl
+++ b/src/rebar_neotoma_compiler.erl
@@ -40,7 +40,7 @@
%% source_ext: extension of peg source files
-module(rebar_neotoma_compiler).
--export([compile/2]).
+-export([compile/2, clean/2]).
%% for internal use only
-export([info/2]).
@@ -59,6 +59,20 @@ compile(Config, _AppFile) ->
option(module_ext, NeoOpts) ++ ".erl",
fun compile_neo/3, [{check_last_mod, true}]).
+-spec clean(rebar_config:config(), file:filename()) -> 'ok'.
+clean(Config, _AppFile) ->
+ NeoOpts = neotoma_opts(Config),
+ GeneratedFiles = neotoma_generated_files(
+ option(out_dir, NeoOpts),
+ option(module_ext, NeoOpts),
+ neotoma_source_files(
+ option(doc_root, NeoOpts),
+ option(source_ext, NeoOpts)
+ )
+ ),
+ ok = rebar_file_utils:delete_each(GeneratedFiles),
+ ok.
+
%% ============================================================================
%% Internal functions
%% ============================================================================
@@ -161,3 +175,20 @@ referenced_pegs1(Step, Config, Seen) ->
_ -> referenced_pegs1(sets:to_list(New), Config,
sets:union(New, Seen))
end.
+
+neotoma_source_files(SrcDir, Ext) ->
+ lists:map(
+ fun filename:basename/1,
+ filelib:wildcard(filename:join([SrcDir, "*" ++ Ext]))
+ ).
+
+
+neotoma_generated_files(OutDir, ModExt, SourceFiles) ->
+ lists:map(
+ fun(PegFile) ->
+ Base = filename:rootname(PegFile),
+ NewName = Base ++ ModExt ++ ".erl",
+ filename:join(OutDir, NewName)
+ end,
+ SourceFiles
+ ).
diff --git a/src/rebar_port_compiler.erl b/src/rebar_port_compiler.erl
index 906bcb0..50093c9 100644
--- a/src/rebar_port_compiler.erl
+++ b/src/rebar_port_compiler.erl
@@ -624,12 +624,17 @@ default_env() ->
%% OS X Leopard flags for 64-bit
{"darwin9.*-64$", "CFLAGS", "-m64 $CFLAGS"},
{"darwin9.*-64$", "CXXFLAGS", "-m64 $CXXFLAGS"},
- {"darwin9.*-64$", "LDFLAGS", "-arch x86_64 $LDFLAGS"},
+ {"darwin9.*-64$", "LDFLAGS", "-arch x86_64 -flat_namespace -undefined suppress $LDFLAGS"},
+
+ %% OS X Lion onwards flags for 64-bit
+ {"darwin1[0-4].*-64$", "CFLAGS", "-m64 $CFLAGS"},
+ {"darwin1[0-4].*-64$", "CXXFLAGS", "-m64 $CXXFLAGS"},
+ {"darwin1[0-4].*-64$", "LDFLAGS", "-arch x86_64 -flat_namespace -undefined suppress $LDFLAGS"},
%% OS X Snow Leopard, Lion, and Mountain Lion flags for 32-bit
{"darwin1[0-2].*-32", "CFLAGS", "-m32 $CFLAGS"},
{"darwin1[0-2].*-32", "CXXFLAGS", "-m32 $CXXFLAGS"},
- {"darwin1[0-2].*-32", "LDFLAGS", "-arch i386 $LDFLAGS"},
+ {"darwin1[0-2].*-32", "LDFLAGS", "-arch i386 -flat_namespace -undefined suppress $LDFLAGS"},
%% Windows specific flags
%% add MS Visual C++ support to rebar on Windows
diff --git a/src/rebar_require_vsn.erl b/src/rebar_require_vsn.erl
index 5eecf74..684578a 100644
--- a/src/rebar_require_vsn.erl
+++ b/src/rebar_require_vsn.erl
@@ -31,7 +31,8 @@
-include("rebar.hrl").
-export([compile/2,
- eunit/2]).
+ eunit/2,
+ version_tuple/1]).
%% for internal use only
-export([info/2,
@@ -103,12 +104,12 @@ check_versions(Config) ->
case rebar_config:get(Config, require_min_otp_vsn, undefined) of
undefined -> ?DEBUG("Min OTP version unconfigured~n", []);
MinOtpVsn ->
- {MinMaj, MinMin} = version_tuple(ShouldAbort, MinOtpVsn,
+ {MinMaj, MinMin, MinPatch} = version_tuple(ShouldAbort, MinOtpVsn,
"configured"),
- {OtpMaj, OtpMin} = version_tuple(ShouldAbort,
+ {OtpMaj, OtpMin, OtpPatch} = version_tuple(ShouldAbort,
erlang:system_info(otp_release),
"OTP Release"),
- case {OtpMaj, OtpMin} >= {MinMaj, MinMin} of
+ case {OtpMaj, OtpMin, OtpPatch} >= {MinMaj, MinMin, MinPatch} of
true ->
?DEBUG("~s satisfies the requirement for vsn ~s~n",
[erlang:system_info(otp_release),
@@ -122,12 +123,17 @@ check_versions(Config) ->
end
end.
+version_tuple(OtpRelease) ->
+ version_tuple(keep_going, OtpRelease, "").
+
version_tuple(ShouldAbort, OtpRelease, Type) ->
- case re:run(OtpRelease, "R?(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of
+ case re:run(OtpRelease, "R?(\\d+)B?\.?(\\d+)?\.?-?(\\d+)?", [{capture, all, list}]) of
+ {match, [_Full, Maj, Min, Patch]} ->
+ {list_to_integer(Maj), list_to_integer(Min), list_to_integer(Patch)};
{match, [_Full, Maj, Min]} ->
- {list_to_integer(Maj), list_to_integer(Min)};
+ {list_to_integer(Maj), list_to_integer(Min), 0};
{match, [_Full, Maj]} ->
- {list_to_integer(Maj), 0};
+ {list_to_integer(Maj), 0, 0};
nomatch ->
maybe_abort(ShouldAbort,
"Cannot parse ~s version string: ~s~n",
diff --git a/src/rebar_upgrade.erl b/src/rebar_upgrade.erl
index 23da5a3..01edbd2 100644
--- a/src/rebar_upgrade.erl
+++ b/src/rebar_upgrade.erl
@@ -44,18 +44,24 @@
'generate-upgrade'(Config0, ReltoolFile) ->
%% Get the old release path
{Config, ReltoolConfig} = rebar_rel_utils:load_config(Config0, ReltoolFile),
+ ?DEBUG("reltool.config: ~p~n", [ReltoolConfig]),
TargetParentDir = rebar_rel_utils:get_target_parent_dir(Config,
ReltoolConfig),
TargetDir = rebar_rel_utils:get_target_dir(Config, ReltoolConfig),
+ ?DEBUG("target dir: ~p~n", [TargetDir]),
PrevRelPath = rebar_rel_utils:get_previous_release_path(Config),
OldVerPath = filename:join([TargetParentDir, PrevRelPath]),
+ ?DEBUG("old version path: ~p~n", [OldVerPath]),
%% Run checks to make sure that building a package is possible
{NewVerPath, NewName, NewVer, OldVer} = run_checks(Config, OldVerPath,
ReltoolConfig),
+ ?DEBUG("old version: ~p~n", [OldVer]),
NameVer = NewName ++ "_" ++ NewVer,
OldRelName = get_old_rel_name(OldVerPath, OldVer, NewName),
+ ?DEBUG("new version path: ~p~n", [NewVerPath]),
+ ?DEBUG("old version: ~p~n", [NewVer]),
%% Save the code path prior to doing anything
OrigPath = code:get_path(),
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 64595a2..c3ebfe5 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -67,7 +67,9 @@
processing_base_dir/1,
processing_base_dir/2,
patch_env/2,
- cleanup_code_path/1
+ cleanup_code_path/1,
+ init_vsn_cache/1,
+ save_vsn_cache/1
]).
%% for internal use only
@@ -268,6 +270,23 @@ expand_env_variable(InStr, VarName, RawVarValue) ->
re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
end.
+init_vsn_cache(Config) ->
+ init_vsn_cache(Config, os:getenv("REBAR_VSN_CACHE_FILE")).
+init_vsn_cache(Config, false) ->
+ rebar_config:set_xconf(Config, vsn_cache, dict:new());
+init_vsn_cache(Config, CacheFile) ->
+ {ok, CacheList} = file:consult(CacheFile),
+ CacheDict = dict:from_list(CacheList),
+ rebar_config:set_xconf(Config, vsn_cache, CacheDict).
+
+save_vsn_cache(Config) ->
+ save_vsn_cache(Config, os:getenv("REBAR_VSN_CACHE_FILE")).
+save_vsn_cache(_Config, false) ->
+ ok;
+save_vsn_cache(Config, CacheFile) ->
+ file:write_file(CacheFile,
+ [io_lib:format("~p.~n", [X]) || X <- dict:to_list(rebar_config:get_xconf(Config, vsn_cache))]).
+
vcs_vsn(Config, Vsn, Dir) ->
Key = {Vsn, Dir},
Cache = rebar_config:get_xconf(Config, vsn_cache),
@@ -276,6 +295,7 @@ vcs_vsn(Config, Vsn, Dir) ->
VsnString = vcs_vsn_1(Vsn, Dir),
Cache1 = dict:store(Key, VsnString, Cache),
Config1 = rebar_config:set_xconf(Config, vsn_cache, Cache1),
+ save_vsn_cache(Config1),
{Config1, VsnString};
{ok, VsnString} ->
{Config, VsnString}
@@ -760,7 +780,7 @@ cross_sizeof(Arch, Type) ->
>>),
Cmd = Compiler ++ " -DTYPE=\""++Type++"\" " ++ TempFile,
ShOpts = [{use_stdout, false}, return_on_error],
- {ok, Res} = sh(Cmd, ShOpts),
+ {error, {_,Res}} = sh(Cmd, ShOpts),
ok = file:delete(TempFile),
case string:tokens(Res, ":") of
[_, Ln | _] ->
diff --git a/src/rebar_xref.erl b/src/rebar_xref.erl
index fdce75e..ee3414d 100644
--- a/src/rebar_xref.erl
+++ b/src/rebar_xref.erl
@@ -60,9 +60,9 @@ xref(Config, _) ->
true = code:add_path(rebar_utils:ebin_dir()),
%% Add extra paths to code path to, for example, be used
- %% when behaviour modules are defined
- [code:add_path(Path)
- || Path <- rebar_config:get(Config, xref_extra_paths, [])],
+ %% when behaviour modules are defined.
+ lists:foreach(fun(P) -> true = code:add_path(P) end,
+ rebar_config:get(Config, xref_extra_paths, [])),
%% Get list of xref checks we want to run
ConfXrefChecks = rebar_config:get(Config, xref_checks,
diff --git a/test/rebar_compiler_tests.erl b/test/rebar_compiler_tests.erl
index 3ed600b..104a7d8 100644
--- a/test/rebar_compiler_tests.erl
+++ b/test/rebar_compiler_tests.erl
@@ -84,11 +84,11 @@ not_keep_going_test_() ->
setup,
fun() ->
setup_basic_project(),
- setup_rebar_config(),
- rebar("compile")
+ setup_rebar_config()
end,
fun teardown/1,
- fun(RebarOut)->
+ fun()->
+ RebarOut = rebar("compile"),
[
{"Exit after error",
?_assert(string:str(RebarOut, "ERROR: compile failed") =/= 0)}
diff --git a/test/rebar_dia_tests.erl b/test/rebar_dia_tests.erl
new file mode 100644
index 0000000..556a552
--- /dev/null
+++ b/test/rebar_dia_tests.erl
@@ -0,0 +1,116 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+-module(rebar_dia_tests).
+
+-compile([export_all]).
+
+-include_lib("eunit/include/eunit.hrl").
+
+-define(REBAR_SCRIPT, "../rebar").
+
+-define(TMP_DIR, "dia_project/").
+
+dia_test_() ->
+ case supported_otp_version() of
+ true ->
+ {"Test the dia compiler",
+ setup, fun() -> setup_project(), rebar("compile") end,
+ fun teardown/1,
+ fun(RebarOut) ->
+ [{"Check ebin is created",
+ ?_assert(filelib:is_dir("ebin") =:= true)},
+
+ {"Check include is created",
+ ?_assert(filelib:is_dir("include") =:= true)},
+
+ {"Check dia/a.dia is compiled",
+ ?_assert(string:str(RebarOut, "Compiled dia/a.dia") /= 0)},
+
+ {"Check dia/b.dia is compiled",
+ ?_assert(string:str(RebarOut, "Compiled dia/b.dia") /= 0)}
+ ]
+ end};
+ false -> {setup, fun() -> ok end, []}
+ end.
+
+
+%% ====================================================================
+%% Setup and Teardown
+%% ====================================================================
+
+-define(myapp_dia_a,
+ ["@id 0\n",
+ "@name a\n",
+ "@vendor 1 ABC\n",
+ "@avp_types\n",
+ " IMSI 1 UTF8String V"
+ ]).
+
+-define(myapp_dia_b,
+ ["@id 2\n",
+ "@name b\n",
+ "@vendor 2 ABC\n",
+ "@inherits a\n",
+ "@avp_types\n",
+ " IMEIV 900 OctetString MV"
+ ]).
+
+-define(myapp_rebarconfig,
+ ["{dia_first_files, [\"dia/a.dia\"]}.\n",
+ "{dia_opts, []}.\n"
+ ]).
+
+supported_otp_version() ->
+ Min = rebar_require_vsn:version_tuple(keep_going, "15", "configured"),
+ Otp = rebar_require_vsn:version_tuple(keep_going,
+ erlang:system_info(otp_release),
+ "OTP Release"),
+ Otp >= Min.
+
+
+setup_environment() ->
+ ok = file:make_dir(?TMP_DIR),
+ prepare_rebar_script(),
+ ok = file:set_cwd(?TMP_DIR).
+
+prepare_project() ->
+ setup_environment(),
+ rebar("create-app appid=myapp").
+
+
+setup_project() ->
+ prepare_project(),
+ ok = file:make_dir("dia"),
+ ok = file:write_file("dia/a.dia", ?myapp_dia_a),
+ ok = file:write_file("dia/b.dia", ?myapp_dia_b),
+ ok = file:write_file("rebar.config", ?myapp_rebarconfig).
+
+
+teardown(_) ->
+ ok = file:set_cwd(".."),
+ ok = remove_tmp_dir().
+
+remove_tmp_dir() ->
+ ok = rebar_file_utils:rm_rf(?TMP_DIR).
+
+%% ====================================================================
+%% Helper Functions
+%% ====================================================================
+
+prepare_rebar_script() ->
+ Rebar = ?TMP_DIR ++ "rebar",
+ {ok, _} = file:copy(?REBAR_SCRIPT, Rebar),
+ case os:type() of
+ {unix, _} ->
+ [] = os:cmd("chmod u+x " ++ Rebar);
+ {win32, _} ->
+ {ok, _} = file:copy(?REBAR_SCRIPT ++ ".cmd",
+ ?TMP_DIR ++ "rebar.cmd")
+ end.
+
+rebar() ->
+ rebar([]).
+
+rebar(Args) when is_list(Args) ->
+ Out = os:cmd(filename:nativename("./rebar") ++ " " ++ Args),
+ Out.
diff --git a/test/rebar_eunit_tests.erl b/test/rebar_eunit_tests.erl
index cb331a4..d481dae 100644
--- a/test/rebar_eunit_tests.erl
+++ b/test/rebar_eunit_tests.erl
@@ -56,7 +56,7 @@ eunit_test_() ->
?_assert(string:str(RebarOut, "myapp_mymod:") =/= 0)},
{"Tests are only run once",
- ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}]
+ ?_assert(string:str(RebarOut, "2 tests passed") =/= 0)}]
end}.
eunit_with_suites_and_tests_test_() ->
@@ -80,7 +80,7 @@ eunit_with_suites_and_tests_test_() ->
?_assert(string:str(RebarOut, "myapp_mymod:") =:= 0)},
{"Selected suite tests are only run once",
- ?_assert(string:str(RebarOut, "All 4 tests passed") =/= 0)}]
+ ?_assert(string:str(RebarOut, "4 tests passed") =/= 0)}]
end},
{"Ensure EUnit runs selected _tests suites",
setup, fun() ->
@@ -102,7 +102,7 @@ eunit_with_suites_and_tests_test_() ->
?_assert(string:str(RebarOut, "myapp_mymod:") =:= 0)},
{"Selected suite tests are only run once",
- ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}]
+ ?_assert(string:str(RebarOut, "2 tests passed") =/= 0)}]
end},
{"Ensure EUnit runs a specific test defined in a selected suite",
setup, fun() ->
@@ -154,7 +154,7 @@ eunit_with_suites_and_tests_test_() ->
"myapp_mymod2_tests:myfunc2_test/0") =/= 0)]},
{"Selected suite tests are run once",
- ?_assert(string:str(RebarOut, "All 3 tests passed") =/= 0)}]
+ ?_assert(string:str(RebarOut, "3 tests passed") =/= 0)}]
end},
{"Ensure EUnit runs specific test in a _tests suite",
setup,
@@ -190,7 +190,7 @@ eunit_with_suites_and_tests_test_() ->
=/= 0)]},
{"Selected suite tests is run once",
- ?_assert(string:str(RebarOut, "All 2 tests passed") =/= 0)}]
+ ?_assert(string:str(RebarOut, "2 tests passed") =/= 0)}]
end},
{"Ensure EUnit runs a specific test by qualified function name",
setup,
@@ -325,7 +325,11 @@ environment_test_() ->
assert_rebar_runs() ->
prepare_rebar_script(),
- ?assert(string:str(os:cmd(filename:nativename("./" ++ ?TMP_DIR ++ "rebar")),
+ {ok, Cwd} = file:get_cwd(),
+ ok = file:set_cwd(?TMP_DIR),
+ RebarOut = os:cmd(filename:nativename("./rebar")),
+ ok = file:set_cwd(Cwd),
+ ?assert(string:str(RebarOut,
"No command to run specified!") =/= 0).
basic_setup_test_() ->
diff --git a/test/rebar_file_utils_tests.erl b/test/rebar_file_utils_tests.erl
index fc76d58..c9b4192 100644
--- a/test/rebar_file_utils_tests.erl
+++ b/test/rebar_file_utils_tests.erl
@@ -36,7 +36,7 @@
-define(TMP_DIR, "tmp_file_utils").
--define(SRC, "source dir?").
+-define(SRC, "source dir").
-define(DST, "dest (dir)").
-define(FILE1, "file 1").
-define(FILE2, "file(2)").
diff --git a/test/rebar_require_vsn_tests.erl b/test/rebar_require_vsn_tests.erl
index a487586..a934e8e 100644
--- a/test/rebar_require_vsn_tests.erl
+++ b/test/rebar_require_vsn_tests.erl
@@ -8,17 +8,32 @@
version_tuple_test_() ->
[%% typical cases
- ?_assert(check("R15B", "eunit") =:= {15, 0}),
- ?_assert(check("R15B01", "eunit") =:= {15, 1}),
- ?_assert(check("R15B02", "eunit") =:= {15, 2}),
- ?_assert(check("R15B03-1", "eunit") =:= {15, 3}),
- ?_assert(check("R15B03", "eunit") =:= {15, 3}),
- ?_assert(check("R16B", "eunit") =:= {16, 0}),
- ?_assert(check("R16B01", "eunit") =:= {16, 1}),
- ?_assert(check("R16B02", "eunit") =:= {16, 2}),
- ?_assert(check("R16B03", "eunit") =:= {16, 3}),
- ?_assert(check("R16B03-1", "eunit") =:= {16, 3}),
- ?_assert(check("17", "eunit") =:= {17, 0}),
+ ?_assert(check("R14A", "eunit") =:= {14, 0, 0}),
+ ?_assert(check("R14B", "eunit") =:= {14, 0, 0}),
+ ?_assert(check("R14B01", "eunit") =:= {14, 1, 0}),
+ ?_assert(check("R14B02", "eunit") =:= {14, 2, 0}),
+ ?_assert(check("R14B03", "eunit") =:= {14, 3, 0}),
+ ?_assert(check("R14B04", "eunit") =:= {14, 4, 0}),
+ ?_assert(check("R15B", "eunit") =:= {15, 0, 0}),
+ ?_assert(check("R15B01", "eunit") =:= {15, 1, 0}),
+ ?_assert(check("R15B02", "eunit") =:= {15, 2, 0}),
+ ?_assert(check("R15B03-1", "eunit") =:= {15, 3, 1}),
+ ?_assert(check("R15B03", "eunit") =:= {15, 3, 0}),
+ ?_assert(check("R16B", "eunit") =:= {16, 0, 0}),
+ ?_assert(check("R16B01", "eunit") =:= {16, 1, 0}),
+ ?_assert(check("R16B02", "eunit") =:= {16, 2, 0}),
+ ?_assert(check("R16B03", "eunit") =:= {16, 3, 0}),
+ ?_assert(check("R16B03-1", "eunit") =:= {16, 3, 1}),
+ ?_assert(check("17", "eunit") =:= {17, 0, 0}),
+ ?_assert(check("17.0", "eunit") =:= {17, 0, 0}),
+ ?_assert(check("17.1", "eunit") =:= {17, 1, 0}),
+ ?_assert(check("17.3", "eunit") =:= {17, 3, 0}),
+ ?_assert(check("17.4", "eunit") =:= {17, 4, 0}),
+ ?_assert(check("17.5", "eunit") =:= {17, 5, 0}),
+ ?_assert(check("18.0", "eunit") =:= {18, 0, 0}),
+ ?_assert(check("18.1", "eunit") =:= {18, 1, 0}),
+ ?_assert(check("18.2", "eunit") =:= {18, 2, 0}),
+ ?_assert(check("18.2.1", "eunit") =:= {18, 2, 1}),
%% error cases
?_assertException(throw, rebar_abort, check("", "eunit")),
?_assertException(throw, rebar_abort, check("abc", "eunit"))
diff --git a/test/rebar_xref_eunit.erl b/test/rebar_xref_eunit.erl
index 341fe2e..f32ea46 100644
--- a/test/rebar_xref_eunit.erl
+++ b/test/rebar_xref_eunit.erl
@@ -192,8 +192,8 @@ prepare_rebar_script() ->
{unix, _} ->
[] = os:cmd("chmod u+x " ++ Rebar);
{win32, _} ->
- {ok, _} = file:copy(?REBAR_SCRIPT ++ ".bat",
- ?TMP_DIR ++ "rebar.bat")
+ {ok, _} = file:copy(?REBAR_SCRIPT ++ ".cmd",
+ ?TMP_DIR ++ "rebar.cmd")
end.
rebar() ->