summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/rebar.erl7
-rw-r--r--src/rebar_base_compiler.erl20
-rw-r--r--src/rebar_ct.erl13
-rw-r--r--src/rebar_deps.erl88
-rw-r--r--src/rebar_require_vsn.erl29
-rw-r--r--src/rebar_utils.erl7
-rw-r--r--src/rebar_xref.erl19
7 files changed, 139 insertions, 44 deletions
diff --git a/src/rebar.erl b/src/rebar.erl
index cd0bed5..82e3fac 100644
--- a/src/rebar.erl
+++ b/src/rebar.erl
@@ -27,6 +27,7 @@
-module(rebar).
-export([main/1,
+ run/2,
help/0,
parse_args/1,
version/0,
@@ -52,6 +53,7 @@
%% Public API
%% ====================================================================
+%% escript Entry point
main(Args) ->
case catch(run(Args)) of
ok ->
@@ -65,6 +67,11 @@ main(Args) ->
rebar_utils:delayed_halt(1)
end.
+%% Erlang-API entry point
+run(BaseConfig, Commands) ->
+ application:load(rebar),
+ run_aux(BaseConfig, Commands).
+
%% ====================================================================
%% Internal functions
%% ====================================================================
diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl
index 0721725..260cdaf 100644
--- a/src/rebar_base_compiler.erl
+++ b/src/rebar_base_compiler.erl
@@ -235,15 +235,17 @@ maybe_report(_) ->
report(Messages) ->
lists:foreach(fun(Msg) -> io:format("~s", [Msg]) end, Messages).
-format_errors(Config, Source, Extra, Errors) ->
- AbsSource = case rebar_utils:processing_base_dir(Config) of
- true ->
- Source;
- false ->
- filename:absname(Source)
- end,
- [[format_error(AbsSource, Extra, Desc) || Desc <- Descs]
- || {_, Descs} <- Errors].
+format_errors(Config, _MainSource, Extra, Errors) ->
+ [begin
+ AbsSource = case rebar_utils:processing_base_dir(Config) of
+ true ->
+ Source;
+ false ->
+ filename:absname(Source)
+ end,
+ [format_error(AbsSource, Extra, Desc) || Desc <- Descs]
+ end
+ || {Source, Descs} <- Errors].
format_error(AbsSource, Extra, {{Line, Column}, Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
diff --git a/src/rebar_ct.erl b/src/rebar_ct.erl
index 6fd5bc7..e33c6c9 100644
--- a/src/rebar_ct.erl
+++ b/src/rebar_ct.erl
@@ -65,7 +65,12 @@ run_test_if_present(TestDir, LogDir, Config, File) ->
++ " SUITES - skipping\n", [TestDir]),
ok;
_ ->
- run_test(TestDir, LogDir, Config, File)
+ try
+ run_test(TestDir, LogDir, Config, File)
+ catch
+ throw:skip ->
+ ok
+ end
end
end.
@@ -270,8 +275,10 @@ find_suite_path(Suite, TestDir) ->
Path = filename:join(TestDir, Suite ++ "_SUITE.erl"),
case filelib:is_regular(Path) of
false ->
- ?ERROR("Suite ~s not found\n", [Suite]),
- ?FAIL;
+ ?WARN("Suite ~s not found\n", [Suite]),
+ %% Note - this throw is caught in run_test_if_present/3;
+ %% this solution was easier than refactoring the entire module.
+ throw(skip);
true ->
Path
end.
diff --git a/src/rebar_deps.erl b/src/rebar_deps.erl
index cac4188..074e929 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -42,7 +42,8 @@
-record(dep, { dir,
app,
vsn_regex,
- source }).
+ source,
+ is_raw }). %% is_raw = true means non-Erlang/OTP dependency
%% ===================================================================
%% Public API
@@ -68,18 +69,34 @@ preprocess(Config, _) ->
%% If skip_deps=true, mark each dep dir as a skip_dir w/ the core so that
%% the current command doesn't run on the dep dir. However, pre/postprocess
%% WILL run (and we want it to) for transitivity purposes.
+ %%
+ %% Also, if skip_deps=comma,separated,app,list, then only the given
+ %% dependencies are skipped.
NewConfig = case rebar_config:get_global(Config3, skip_deps, false) of
- "true" ->
- lists:foldl(
- fun(#dep{dir = Dir}, C) ->
- rebar_config:set_skip_dir(C, Dir)
- end, Config3, AvailableDeps);
- _ ->
- Config3
- end,
+ "true" ->
+ lists:foldl(
+ fun(#dep{dir = Dir}, C) ->
+ rebar_config:set_skip_dir(C, Dir)
+ end, Config3, AvailableDeps);
+ Apps when is_list(Apps) ->
+ SkipApps = [list_to_atom(App) || App <- string:tokens(Apps, ",")],
+ lists:foldl(
+ fun(#dep{dir = Dir, app = App}, C) ->
+ case lists:member(App, SkipApps) of
+ true -> rebar_config:set_skip_dir(C, Dir);
+ false -> C
+ end
+ end, Config3, AvailableDeps);
+ _ ->
+ Config3
+ end,
+
+ %% Filtering out 'raw' dependencies so that no commands other than
+ %% deps-related can be executed on their directories.
+ NonRawAvailableDeps = [D || D <- AvailableDeps, not D#dep.is_raw],
%% Return all the available dep directories for process
- {ok, NewConfig, dep_dirs(AvailableDeps)}.
+ {ok, NewConfig, dep_dirs(NonRawAvailableDeps)}.
postprocess(Config, _) ->
case rebar_config:get_xconf(Config, ?MODULE, undefined) of
@@ -90,8 +107,9 @@ postprocess(Config, _) ->
{ok, NewConfig, Dirs}
end.
-compile(Config, AppFile) ->
- 'check-deps'(Config, AppFile).
+compile(Config, _) ->
+ {Config1, _AvailDeps} = do_check_deps(Config),
+ {ok, Config1}.
%% set REBAR_DEPS_DIR and ERL_LIBS environment variables
setup_env(Config) ->
@@ -111,13 +129,14 @@ setup_env(Config) ->
end,
[{"REBAR_DEPS_DIR", DepsDir}, ERL_LIBS].
-'check-deps'(Config, _) ->
+%% common function used by 'check-deps' and 'compile'
+do_check_deps(Config) ->
%% Get the list of immediate (i.e. non-transitive) deps that are missing
Deps = rebar_config:get_local(Config, deps, []),
case find_deps(Config, find, Deps) of
- {Config1, {_, []}} ->
+ {Config1, {AvailDeps, []}} ->
%% No missing deps
- {ok, Config1};
+ {Config1, AvailDeps};
{_Config1, {_, MissingDeps}} ->
lists:foreach(fun (#dep{app=App, vsn_regex=Vsn, source=Src}) ->
?CONSOLE("Dependency not available: "
@@ -126,6 +145,10 @@ setup_env(Config) ->
?FAIL
end.
+'check-deps'(Config, _) ->
+ {Config1, AvailDeps} = do_check_deps(Config),
+ {ok, save_dep_dirs(Config1, AvailDeps)}.
+
'get-deps'(Config, _) ->
%% Determine what deps are available and missing
Deps = rebar_config:get_local(Config, deps, []),
@@ -171,7 +194,7 @@ setup_env(Config) ->
case find_deps(Config, find, Deps) of
{Config1, {AvailDeps, []}} ->
lists:foreach(fun(Dep) -> print_source(Dep) end, AvailDeps),
- {ok, Config1};
+ {ok, save_dep_dirs(Config1, AvailDeps)};
{_, MissingDeps} ->
?ABORT("Missing dependencies: ~p\n", [MissingDeps])
end.
@@ -221,7 +244,7 @@ update_deps_code_path(Config, []) ->
update_deps_code_path(Config, [Dep | Rest]) ->
Config2 =
case is_app_available(Config, Dep#dep.app,
- Dep#dep.vsn_regex, Dep#dep.dir) of
+ Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
{Config1, {true, _}} ->
Dir = filename:join(Dep#dep.dir, "ebin"),
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
@@ -247,9 +270,14 @@ find_deps(Config, Mode, [App | Rest], Acc) when is_atom(App) ->
find_deps(Config, Mode, [{App, VsnRegex} | Rest], Acc) when is_atom(App) ->
find_deps(Config, Mode, [{App, VsnRegex, undefined} | Rest], Acc);
find_deps(Config, Mode, [{App, VsnRegex, Source} | Rest], Acc) ->
+ find_deps(Config, Mode, [{App, VsnRegex, Source, []} | Rest], Acc);
+find_deps(Config, Mode, [{App, VsnRegex, Source, Opts} | Rest], Acc) when is_list(Opts) ->
Dep = #dep { app = App,
vsn_regex = VsnRegex,
- source = Source },
+ source = Source,
+ %% dependency is considered raw (i.e. non-Erlang/OTP) when
+ %% 'raw' option is present
+ is_raw = proplists:get_value(raw, Opts, false) },
{Config1, {Availability, FoundDir}} = find_dep(Config, Dep),
find_deps(Config1, Mode, Rest,
acc_deps(Mode, Availability, Dep, FoundDir, Acc));
@@ -284,7 +312,8 @@ find_dep_in_dir(Config, _Dep, {false, Dir}) ->
find_dep_in_dir(Config, Dep, {true, Dir}) ->
App = Dep#dep.app,
VsnRegex = Dep#dep.vsn_regex,
- case is_app_available(Config, App, VsnRegex, Dir) of
+ IsRaw = Dep#dep.is_raw,
+ case is_app_available(Config, App, VsnRegex, Dir, IsRaw) of
{Config1, {true, _AppFile}} -> {Config1, {avail, Dir}};
{Config1, {false, _}} -> {Config1, {missing, Dir}}
end.
@@ -309,7 +338,11 @@ require_source_engine(Source) ->
true = source_engine_avail(Source),
ok.
-is_app_available(Config, App, VsnRegex, Path) ->
+%% IsRaw = false means regular Erlang/OTP dependency
+%%
+%% IsRaw = true means non-Erlang/OTP dependency, e.g. the one that does not
+%% have a proper .app file
+is_app_available(Config, App, VsnRegex, Path, _IsRaw = false) ->
?DEBUG("is_app_available, looking for App ~p with Path ~p~n", [App, Path]),
case rebar_app_utils:is_app_dir(Path) of
{true, AppFile} ->
@@ -340,6 +373,19 @@ is_app_available(Config, App, VsnRegex, Path) ->
?WARN("Expected ~s to be an app dir (containing ebin/*.app), "
"but no .app found.\n", [Path]),
{Config, {false, {missing_app_file, Path}}}
+ end;
+is_app_available(Config, App, _VsnRegex, Path, _IsRaw = true) ->
+ ?DEBUG("is_app_available, looking for Raw Depencency ~p with Path ~p~n", [App, Path]),
+ case filelib:is_dir(Path) of
+ true ->
+ %% TODO: look for version string in <Path>/VERSION file? Not clear
+ %% how to detect git/svn/hg/{cmd, ...} settings that can be passed
+ %% to rebar_utils:vcs_vsn/2 to obtain version dynamically
+ {Config, {true, Path}};
+ false ->
+ ?WARN("Expected ~s to be a raw dependency directory, "
+ "but no directory found.\n", [Path]),
+ {Config, {false, {missing_raw_dependency_directory, Path}}}
end.
use_source(Config, Dep) ->
@@ -353,7 +399,7 @@ use_source(Config, Dep, Count) ->
true ->
%% Already downloaded -- verify the versioning matches the regex
case is_app_available(Config, Dep#dep.app,
- Dep#dep.vsn_regex, Dep#dep.dir) of
+ Dep#dep.vsn_regex, Dep#dep.dir, Dep#dep.is_raw) of
{Config1, {true, _}} ->
Dir = filename:join(Dep#dep.dir, "ebin"),
ok = filelib:ensure_dir(filename:join(Dir, "dummy")),
diff --git a/src/rebar_require_vsn.erl b/src/rebar_require_vsn.erl
index 327f75c..83cb79d 100644
--- a/src/rebar_require_vsn.erl
+++ b/src/rebar_require_vsn.erl
@@ -67,4 +67,33 @@ check_versions(Config) ->
nomatch ->
?ABORT("OTP release ~s does not match required regex ~s\n",
[erlang:system_info(otp_release), OtpRegex])
+ end,
+
+ case rebar_config:get(Config, require_min_otp_vsn, undefined) of
+ undefined -> ?DEBUG("Min OTP version unconfigured~n", []);
+ MinOtpVsn ->
+ {MinMaj, MinMin} = version_tuple(MinOtpVsn, "configured"),
+ {OtpMaj, OtpMin} = version_tuple(erlang:system_info(otp_release),
+ "OTP Release"),
+ case {OtpMaj, OtpMin} >= {MinMaj, MinMin} of
+ true ->
+ ?DEBUG("~s satisfies the requirement for vsn ~s~n",
+ [erlang:system_info(otp_release),
+ MinOtpVsn]);
+ false ->
+ ?ABORT("OTP release ~s or later is required, you have: ~s~n",
+ [MinOtpVsn,
+ erlang:system_info(otp_release)])
+ end
+ end.
+
+version_tuple(OtpRelease, Type) ->
+ case re:run(OtpRelease, "R(\\d+)B?-?(\\d+)?", [{capture, all, list}]) of
+ {match, [_Full, Maj, Min]} ->
+ {list_to_integer(Maj), list_to_integer(Min)};
+ {match, [_Full, Maj]} ->
+ {list_to_integer(Maj), 0};
+ nomatch ->
+ ?ABORT("Cannot parse ~s version string: ~s~n",
+ [Type, OtpRelease])
end.
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index 1049c1d..bb58460 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -75,8 +75,7 @@ is_arch(ArchRegex) ->
get_arch() ->
Words = wordsize(),
erlang:system_info(otp_release) ++ "-"
- ++ erlang:system_info(system_architecture) ++ "-" ++ Words
- ++ "-" ++ os_family().
+ ++ erlang:system_info(system_architecture) ++ "-" ++ Words.
wordsize() ->
try erlang:system_info({wordsize, external}) of
@@ -318,10 +317,6 @@ processing_base_dir(Config, Dir) ->
%% Internal functions
%% ====================================================================
-os_family() ->
- {OsFamily, _} = os:type(),
- atom_to_list(OsFamily).
-
get_deprecated_3(Get, Config, OldOpt, NewOpt, Default, When) ->
case Get(Config, NewOpt, Default) of
Default ->
diff --git a/src/rebar_xref.erl b/src/rebar_xref.erl
index 84b59f6..a55d71d 100644
--- a/src/rebar_xref.erl
+++ b/src/rebar_xref.erl
@@ -28,7 +28,8 @@
%% -------------------------------------------------------------------
%% This module borrows heavily from http://github.com/etnt/exrefcheck project as
-%% written by Torbjorn Tornkvist <tobbe@kreditor.se>, Daniel Luna and others.
+%% written by Torbjorn Tornkvist <tobbe@kreditor.se>, Daniel Luna
+%% <daniel@lunas.se> and others.
%% -------------------------------------------------------------------
-module(rebar_xref).
@@ -43,7 +44,7 @@
xref(Config, _) ->
%% Spin up xref
{ok, _} = xref:start(xref),
- ok = xref:set_library_path(xref, code_path()),
+ ok = xref:set_library_path(xref, code_path(Config)),
xref:set_default(xref, [{warnings,
rebar_config:get(Config, xref_warnings, false)},
@@ -131,9 +132,17 @@ check_query({Query, Value}) ->
true
end.
-code_path() ->
- [P || P <- code:get_path(),
- filelib:is_dir(P)] ++ [filename:join(rebar_utils:get_cwd(), "ebin")].
+code_path(Config) ->
+ %% Slight hack to ensure that sub_dirs get properly included
+ %% in code path for xref -- otherwise one gets a lot of undefined
+ %% functions, even though those functions are present as part
+ %% of compilation. H/t to @dluna. Long term we should tie more
+ %% properly into the overall compile code path if possible.
+ BaseDir = rebar_config:get_xconf(Config, base_dir),
+ [P || P <- code:get_path() ++
+ [filename:join(BaseDir, filename:join(SubDir, "ebin"))
+ || SubDir <- rebar_config:get(Config, sub_dirs, [])],
+ filelib:is_dir(P)].
%%
%% Ignore behaviour functions, and explicitly marked functions