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.erl4
-rw-r--r--src/rebar_ct.erl13
-rw-r--r--src/rebar_deps.erl28
-rw-r--r--src/rebar_erlydtl_compiler.erl103
-rw-r--r--src/rebar_require_vsn.erl29
-rw-r--r--src/rebar_utils.erl7
-rw-r--r--src/rebar_xref.erl19
8 files changed, 162 insertions, 48 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 63e408b..260cdaf 100644
--- a/src/rebar_base_compiler.erl
+++ b/src/rebar_base_compiler.erl
@@ -62,9 +62,9 @@ run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt,
%% Convert simple extension to proper regex
SourceExtRe = ".*\\" ++ SourceExt ++ [$$],
+ Recursive = proplists:get_value(recursive, Opts, true),
%% Find all possible source files
- FoundFiles = rebar_utils:find_files(SourceDir, SourceExtRe),
-
+ FoundFiles = rebar_utils:find_files(SourceDir, SourceExtRe, Recursive),
%% Remove first files from found files
RestFiles = [Source || Source <- FoundFiles,
not lists:member(Source, FirstFiles)],
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 cd49343..074e929 100644
--- a/src/rebar_deps.erl
+++ b/src/rebar_deps.erl
@@ -69,15 +69,27 @@ 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.
diff --git a/src/rebar_erlydtl_compiler.erl b/src/rebar_erlydtl_compiler.erl
index 958b976..25981b2 100644
--- a/src/rebar_erlydtl_compiler.erl
+++ b/src/rebar_erlydtl_compiler.erl
@@ -31,7 +31,11 @@
%% to ebin/*_dtl.beam.
%%
%% Configuration options should be placed in rebar.config under
-%% 'erlydtl_opts'. Available options include:
+%% 'erlydtl_opts'. It can be a list of name-value tuples or a list of
+%% lists of name-value tuples if you have multiple template directories
+%% that need to have different settings (see example below).
+%%
+%% Available options include:
%%
%% doc_root: where to find templates to compile
%% "templates" by default
@@ -45,6 +49,9 @@
%% module_ext: characters to append to the template's module name
%% "_dtl" by default
%%
+%% recursive: boolean that determines if doc_root(s) need to be
+%% scanned recursively for matching template file names
+%% (default: true).
%% For example, if you had:
%% /t_src/
%% base.html
@@ -70,6 +77,21 @@
%% {source_ext, ".dtl"},
%% {module_ext, "_dtl"}
%% ]}.
+%%
+%% The following example will compile the following templates:
+%% "src/*.dtl" files into "ebin/*_dtl.beam" and
+%% "templates/*.html" into "ebin/*.beam". Note that any tuple option
+%% (such as 'out_dir') in the outer list is added to each inner list:
+%% {erlydtl_opts, [
+%% {out_dir, "ebin"},
+%% {recursive, false},
+%% [
+%% {doc_root, "src"}, {module_ext, "_dtl"}
+%% ],
+%% [
+%% {doc_root, "templates", {module_ext, ""}, {source_ext, ".html"}
+%% ]
+%% ]}.
-module(rebar_erlydtl_compiler).
-export([compile/2]).
@@ -81,16 +103,23 @@
%% ===================================================================
compile(Config, _AppFile) ->
- DtlOpts = erlydtl_opts(Config),
+ MultiDtlOpts = erlydtl_opts(Config),
OrigPath = code:get_path(),
true = code:add_path(rebar_utils:ebin_dir()),
- Result = rebar_base_compiler:run(Config, [],
+
+ Result = lists:foldl(fun(DtlOpts, _) ->
+ rebar_base_compiler:run(Config, [],
option(doc_root, DtlOpts),
option(source_ext, DtlOpts),
option(out_dir, DtlOpts),
option(module_ext, DtlOpts) ++ ".beam",
- fun compile_dtl/3,
- [{check_last_mod, false}]),
+ fun(S, T, _C) ->
+ compile_dtl(S, T, DtlOpts)
+ end,
+ [{check_last_mod, false},
+ {recursive, option(recursive, DtlOpts)}])
+ end, ok, MultiDtlOpts),
+
true = code:set_path(OrigPath),
Result.
@@ -100,7 +129,18 @@ compile(Config, _AppFile) ->
%% ===================================================================
erlydtl_opts(Config) ->
- rebar_config:get(Config, erlydtl_opts, []).
+ Opts = rebar_config:get(Config, erlydtl_opts, []),
+ Tuples = [{K,V} || {K,V} <- Opts],
+ case [L || L <- Opts, is_list(L), not io_lib:printable_list(L)] of
+ [] ->
+ lists:keysort(1, [Tuples]);
+ Lists ->
+ lists:map(fun(L) ->
+ lists:keysort(1, lists:foldl(fun({K,T}, Acc) ->
+ lists:keystore(K, 1, Acc, {K, T})
+ end, Tuples, L))
+ end, Lists)
+ end.
option(Opt, DtlOpts) ->
proplists:get_value(Opt, DtlOpts, default(Opt)).
@@ -109,9 +149,11 @@ default(doc_root) -> "templates";
default(out_dir) -> "ebin";
default(source_ext) -> ".dtl";
default(module_ext) -> "_dtl";
-default(custom_tags_dir) -> "".
+default(custom_tags_dir) -> "";
+default(compiler_options) -> [report, return];
+default(recursive) -> true.
-compile_dtl(Source, Target, Config) ->
+compile_dtl(Source, Target, DtlOpts) ->
case code:which(erlydtl) of
non_existing ->
?ERROR("~n===============================================~n"
@@ -122,50 +164,62 @@ compile_dtl(Source, Target, Config) ->
"===============================================~n~n", []),
?FAIL;
_ ->
- case needs_compile(Source, Target, Config) of
+ case needs_compile(Source, Target, DtlOpts) of
true ->
- do_compile(Source, Target, Config);
+ do_compile(Source, Target, DtlOpts);
false ->
skipped
end
end.
-do_compile(Source, Target, Config) ->
+do_compile(Source, Target, DtlOpts) ->
%% TODO: Check last mod on target and referenced DTLs here..
- DtlOpts = erlydtl_opts(Config),
+
%% ensure that doc_root and out_dir are defined,
%% using defaults if necessary
- Opts = [{out_dir, option(out_dir, DtlOpts)},
- {doc_root, option(doc_root, DtlOpts)},
- {custom_tags_dir, option(custom_tags_dir, DtlOpts)},
- report, return],
+ Opts = lists:ukeymerge(1,
+ DtlOpts,
+ lists:sort(
+ [{out_dir, option(out_dir, DtlOpts)},
+ {doc_root, option(doc_root, DtlOpts)},
+ {custom_tags_dir, option(custom_tags_dir, DtlOpts)},
+ {compiler_options, option(compiler_options, DtlOpts)}])),
+ ?INFO("Compiling \"~s\" -> \"~s\" with options:~n ~s~n",
+ [Source, Target, io_lib:format("~p", [Opts])]),
case erlydtl:compile(Source,
module_name(Target),
- Opts++DtlOpts) of
+ Opts) of
ok -> ok;
+ {error, {File, [{Pos, _Mod, Err}]}} ->
+ ?ERROR("Compiling template ~p failed:~n (~s): ~p~n",
+ [File, err_location(Pos), Err]);
Reason ->
?ERROR("Compiling template ~s failed:~n ~p~n",
[Source, Reason]),
?FAIL
end.
+err_location({L,C}) -> io_lib:format("line:~w, col:~w", [L, C]);
+err_location(L) -> io_lib:format("line:~w", [L]).
+
module_name(Target) ->
F = filename:basename(Target),
string:substr(F, 1, length(F)-length(".beam")).
-needs_compile(Source, Target, Config) ->
+needs_compile(Source, Target, DtlOpts) ->
LM = filelib:last_modified(Target),
LM < filelib:last_modified(Source) orelse
lists:any(fun(D) -> LM < filelib:last_modified(D) end,
- referenced_dtls(Source, Config)).
+ referenced_dtls(Source, DtlOpts)).
-referenced_dtls(Source, Config) ->
- Set = referenced_dtls1([Source], Config,
+referenced_dtls(Source, DtlOpts) ->
+ DtlOpts1 = lists:keyreplace(doc_root, 1, DtlOpts,
+ {doc_root, filename:dirname(Source)}),
+ Set = referenced_dtls1([Source], DtlOpts1,
sets:add_element(Source, sets:new())),
sets:to_list(sets:del_element(Source, Set)).
-referenced_dtls1(Step, Config, Seen) ->
- DtlOpts = erlydtl_opts(Config),
+referenced_dtls1(Step, DtlOpts, Seen) ->
ExtMatch = re:replace(option(source_ext, DtlOpts), "\.", "\\\\\\\\.",
[{return, list}]),
@@ -184,10 +238,11 @@ referenced_dtls1(Step, Config, Seen) ->
end || F <- Step]),
DocRoot = option(doc_root, DtlOpts),
WithPaths = [ filename:join([DocRoot, F]) || F <- AllRefs ],
+ ?DEBUG("All deps: ~p\n", [WithPaths]),
Existing = [F || F <- WithPaths, filelib:is_regular(F)],
New = sets:subtract(sets:from_list(Existing), Seen),
case sets:size(New) of
0 -> Seen;
- _ -> referenced_dtls1(sets:to_list(New), Config,
+ _ -> referenced_dtls1(sets:to_list(New), DtlOpts,
sets:union(New, Seen))
end.
diff --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