Merge pull request #588 from lrascao/fix/look_for_ct_spec_files_only_in_test_dir
Look for ct .spec files in the ct_dir that was specified
diff --git a/THANKS b/THANKS
index 630502a..ab7935c 100644
--- a/THANKS
+++ b/THANKS
@@ -148,3 +148,5 @@
Sebastien Serre
John Daily
Yury Gargay
+Frank Hunleth
+Matwey Kornilov
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
--- /dev/null
+++ b/inttest/cross1/c_src/test1.h
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/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/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/src/rebar.erl b/src/rebar.erl
index 2fceb19..5a809d2 100644
--- a/src/rebar.erl
+++ b/src/rebar.erl
@@ -143,7 +143,7 @@
%% 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 @@
{"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
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 @@
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_deps.erl b/src/rebar_deps.erl
index a6e5b27..995ce97 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -58,16 +58,19 @@
%% 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 @@
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 @@
%% 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 @@
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 @@
" ~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"},
@@ -302,6 +307,18 @@
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, "").
@@ -378,9 +395,15 @@
%% 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).
+ 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, undefined) ->
+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 +412,7 @@
{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_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 @@
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 @@
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 @@
>>),
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 | _] ->