summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--README.md86
-rw-r--r--dialyzer_reference2
-rw-r--r--priv/shell-completion/zsh/_rebar79
-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
12 files changed, 283 insertions, 97 deletions
diff --git a/.travis.yml b/.travis.yml
index fc9c771..f5e3d99 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,4 @@
language: erlang
-notifications:
- webhooks: http://basho-engbot.herokuapp.com/travis?key=a0e66154af272adba328195454cfdc10ff5f33f5
- email: eng@basho.com
otp_release:
- R15B01
- R15B
diff --git a/README.md b/README.md
index 68236e1..3be5091 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,28 @@
rebar
=====
-rebar is an Erlang build tool that makes it easy to compile and
-test Erlang applications, port drivers and releases.
+rebar is an Erlang build tool that makes it easy to compile and test Erlang
+applications, port drivers and releases.
-[![Build Status](https://secure.travis-ci.org/basho/rebar.png?branch=master)](http://travis-ci.org/basho/rebar)
+[![Build Status](https://secure.travis-ci.org/rebar/rebar.png?branch=master)](http://travis-ci.org/rebar/rebar)
-rebar is a self-contained Erlang script, so it's easy to distribute or even
-embed directly in a project. Where possible, rebar uses standard Erlang/OTP
-conventions for project structures, thus minimizing the amount of build
-configuration work. rebar also provides dependency management, enabling
-application writers to easily re-use common libraries from a variety of
+rebar is a self-contained Erlang script, so it's easy to distribute or even
+embed directly in a project. Where possible, rebar uses standard Erlang/OTP
+conventions for project structures, thus minimizing the amount of build
+configuration work. rebar also provides dependency management, enabling
+application writers to easily re-use common libraries from a variety of
locations (git, hg, etc).
Building
--------
-Information on building and installing [Erlang/OTP](http://www.erlang.org)
-can be found [here](https://github.com/erlang/otp/wiki/Installation)
-([more info](https://github.com/erlang/otp/blob/master/INSTALL.md)).
+Information on building and installing [Erlang/OTP](http://www.erlang.org) can
+be found [here](https://github.com/erlang/otp/wiki/Installation) ([more
+info](https://github.com/erlang/otp/blob/master/INSTALL.md)).
### Dependencies
-To build rebar you will need a working installation of Erlang R13B03 (or
-later).
+To build rebar you will need a working installation of Erlang R13B03 (or later).
Should you want to clone the rebar repository, you will also require git.
@@ -31,12 +30,12 @@ Should you want to clone the rebar repository, you will also require git.
You can download a pre-built binary version of rebar from:
-https://github.com/basho/rebar/wiki/rebar
+https://github.com/rebar/rebar/wiki/rebar
#### Building rebar
```sh
-$ git clone git://github.com/basho/rebar.git
+$ git clone git://github.com/rebar/rebar.git
$ cd rebar
$ ./bootstrap
Recompile: src/getopt
@@ -72,9 +71,10 @@ Do not mix spaces and tabs.
Do not introduce lines longer than 80 characters.
-[erlang-mode (emacs)](http://www.erlang.org/doc/man/erlang.el.html) indentation is preferred.
-vi-only users are encouraged to
-give [Vim emulation](http://emacswiki.org/emacs/Evil) ([more info](https://gitorious.org/evil/pages/Home)) a try.
+[erlang-mode (emacs)](http://www.erlang.org/doc/man/erlang.el.html) indentation
+is preferred. vi-only users are encouraged to give [Vim
+emulation](http://emacswiki.org/emacs/Evil) ([more
+info](https://gitorious.org/evil/pages/Home)) a try.
Writing Commit Messages
-----------------------
@@ -111,43 +111,39 @@ Longer description (wrap at 72 characters)
Run checks
----------
-Before you submit a patch, run ``make check`` to execute
-the test suite and check for
-[xref](http://www.erlang.org/doc/man/xref.html) and
-[Dialyzer](http://www.erlang.org/doc/man/dialyzer.html)
-warnings. You may have to run ``make clean`` first.
+Before you submit a patch, run ``make check`` to execute the test suite and
+check for [xref](http://www.erlang.org/doc/man/xref.html) and
+[Dialyzer](http://www.erlang.org/doc/man/dialyzer.html) warnings. You may have
+to run ``make clean`` first.
[Dialyzer](http://www.erlang.org/doc/man/dialyzer.html) warnings are compared
-against a set of safe-to-ignore warnings found in
-[dialyzer_reference](https://raw.github.com/basho/rebar/master/dialyzer_reference).
-[xref](http://www.erlang.org/doc/man/xref.html) is run with
-[custom queries](https://raw.github.com/basho/rebar/master/rebar.config)
-to suppress safe-to-ignore warnings.
-
-It is **strongly recommended** to check the code with
-[Tidier](http://tidier.softlab.ntua.gr:20000/tidier/getstarted).
-Select all transformation
-options and enable **automatic** transformation. If Tidier suggests a transformation,
-apply the changes **manually** to the source code. Do not use the code from
-the
-tarball (*out.tgz*) as it will have white-space changes applied by Erlang's pretty-printer.
+against a set of safe-to-ignore warnings found in
+[dialyzer_reference](https://raw.github.com/rebar/rebar/master/dialyzer_reference).
+[xref](http://www.erlang.org/doc/man/xref.html) is run with [custom
+queries](https://raw.github.com/rebar/rebar/master/rebar.config) to suppress
+safe-to-ignore warnings.
Community and Resources
-----------------------
-In case of problems that cannot be solved through documentation or examples, you may
-want to try to contact members of the community for help. The community is also where
-you want to go for questions about how to extend rebar, fill in bug reports, and so on.
+In case of problems that cannot be solved through documentation or examples, you
+may want to try to contact members of the community for help. The community is
+also where you want to go for questions about how to extend rebar, fill in bug
+reports, and so on.
-The main place to go for questions is the [rebar mailing list](http://lists.basho.com/pipermail/rebar_lists.basho.com/). If you need quick feedback,
-you can try the #rebar channel on [irc.freenode.net](http://freenode.net). Be sure to check the [wiki](https://github.com/basho/rebar/wiki) first,
-just to be sure you're not asking about things with well known answers.
+The main place to go for questions is the [rebar mailing
+list](http://lists.basho.com/pipermail/rebar_lists.basho.com/). If you need
+quick feedback, you can try the #rebar channel on
+[irc.freenode.net](http://freenode.net). Be sure to check the
+[wiki](https://github.com/rebar/rebar/wiki) first, just to be sure you're not
+asking about things with well known answers.
-For bug reports, roadmaps, and issues, visit the [github issues page](https://github.com/basho/rebar/issues).
+For bug reports, roadmaps, and issues, visit the [github issues
+page](https://github.com/rebar/rebar/issues).
General rebar community resources and links:
- [Rebar Mailing List](http://lists.basho.com/pipermail/rebar_lists.basho.com/)
- #rebar on [irc.freenode.net](http://freenode.net/)
-- [wiki](https://github.com/basho/rebar/wiki)
-- [issues](https://github.com/basho/rebar/issues)
+- [wiki](https://github.com/rebar/rebar/wiki)
+- [issues](https://github.com/rebar/rebar/issues)
diff --git a/dialyzer_reference b/dialyzer_reference
index ff3dc50..a50bb88 100644
--- a/dialyzer_reference
+++ b/dialyzer_reference
@@ -1,3 +1,3 @@
rebar_eunit.erl:351: Call to missing or unexported function eunit_test:function_wrapper/2
-rebar_utils.erl:163: Call to missing or unexported function escript:foldl/3
+rebar_utils.erl:162: Call to missing or unexported function escript:foldl/3
diff --git a/priv/shell-completion/zsh/_rebar b/priv/shell-completion/zsh/_rebar
new file mode 100644
index 0000000..7ac5a51
--- /dev/null
+++ b/priv/shell-completion/zsh/_rebar
@@ -0,0 +1,79 @@
+#compdef rebar
+
+local curcontext=$curcontext state ret=1
+typeset -ga _rebar_global_opts
+
+_rebar_global_opts=(
+ '(--help -h)'{--help,-h}'[Show the program options]'
+ '(--commands -c)'{--commands,-c}'[Show available commands]'
+ '(--version -V)'{--version,-V}'[Show version information]'
+ '(-vvv -vv -v)'--verbose+'[Verbosity level. Default: 0]:verbosity level:(0 1 2 3)'
+ '(-vvv)-v[Slightly more verbose output]'
+ '(-vvv)-vv[More verbose output]'
+ '(-v -vv)-vvv[Most verbose output]'
+ '(--force -f)'{--force,-f}'[Force]'
+ '-D+[Define compiler macro]'
+ '(--jobs -j)'{--jobs+,-j+}'[Number of concurrent workers a command may use. Default: 3]:workers:(1 2 3 4 5 6 7 8 9)'
+ '(--config -C)'{--config,-C}'[Rebar config file to use]:files:_files'
+ '(--profile -p)'{--profile,-p}'[Profile this run of rebar]'
+ '(--keep-going -k)'{--keep-going,-k}'[Keep running after a command fails]'
+)
+
+_rebar () {
+ _arguments -C $_rebar_global_opts \
+ '*::command and variable:->cmd_and_var' \
+ && return
+
+ case $state in
+ cmd_and_var)
+ _values -S = 'variables' \
+ 'clean[Clean]' \
+ 'compile[Compile sources]' \
+ 'create[Create skel based on template and vars]' \
+ 'create-app[Create simple app skel]' \
+ 'create-node[Create simple node skel]' \
+ 'list-template[List avaiavle templates]' \
+ 'doc[Generate Erlang program documentation]' \
+ 'check-deps[Display to be fetched dependencies]' \
+ 'get-deps[Fetch dependencies]' \
+ 'update-deps[Update fetched dependencies]' \
+ 'delete-deps[Delete fetched dependencies]' \
+ 'list-deps[List dependencies]' \
+ 'generate[Build release with reltool]' \
+ 'overlay[Run reltool overlays only]' \
+ 'generate-appups[Generate appup files]' \
+ 'generate-upgrade[Build an upgrade package]' \
+ 'eunit[Run eunit tests]' \
+ 'ct[Run common_test suites]' \
+ 'qc[Test QuickCheck properties]' \
+ 'xref[Run cross reference analysis]' \
+ 'help[Show the program options]' \
+ 'version[Show version information]' \
+ 'apps[Application names to process]:' \
+ 'case[Common Test case]:' \
+ 'dump_spec[Dump reltool spec]:' \
+ 'jobs[Number of workers]::workers:(0 1 2 3 4 5 6 7 8 9)' \
+ 'suites[Common Test suites]::suite name:_path_files -W "(src test)" -g "*.erl(:r)"' \
+ 'verbose[Verbosity level]::verbosity level:(0 1 2 3)' \
+ 'appid[Application id]:' \
+ 'previous_release[Previous release path]:' \
+ 'nodeid[Node id]:' \
+ 'root_dir[Reltool config root directory]::directory:_files -/' \
+ 'skip_deps[Skip deps]::flag:(true false)' \
+ 'skip_apps[Application names to not process]::flag:(true false)' \
+ 'template[Template name]:' \
+ 'template_dir[Template directory]::directory:_files -/' \
+ && ret=0
+ ;;
+ esac
+}
+
+_rebar
+
+# Local variables:
+# mode: shell-script
+# sh-basic-offset: 2
+# sh-indent-comment: t
+# indent-tabs-mode: nil
+# End:
+# ex: sw=2 ts=2 et filetype=sh
diff --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