diff options
-rw-r--r-- | .travis.yml | 3 | ||||
-rw-r--r-- | README.md | 86 | ||||
-rw-r--r-- | THANKS | 2 | ||||
-rw-r--r-- | dialyzer_reference | 2 | ||||
-rw-r--r-- | inttest/t_custom_config/t_custom_config_rt.erl | 2 | ||||
-rw-r--r-- | priv/shell-completion/zsh/_rebar | 79 | ||||
-rw-r--r-- | rebar.config.sample | 15 | ||||
-rw-r--r-- | src/rebar.erl | 7 | ||||
-rw-r--r-- | src/rebar_base_compiler.erl | 20 | ||||
-rw-r--r-- | src/rebar_ct.erl | 13 | ||||
-rw-r--r-- | src/rebar_deps.erl | 88 | ||||
-rw-r--r-- | src/rebar_require_vsn.erl | 29 | ||||
-rw-r--r-- | src/rebar_utils.erl | 7 | ||||
-rw-r--r-- | src/rebar_xref.erl | 19 |
14 files changed, 277 insertions, 95 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 @@ -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) @@ -107,3 +107,5 @@ Dmitriy Kargapolov Ryan Zezeski Daniel White Martin Schut +Serge Aleynikov +Magnus Henoch 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/inttest/t_custom_config/t_custom_config_rt.erl b/inttest/t_custom_config/t_custom_config_rt.erl index 0609abb..864ce5e 100644 --- a/inttest/t_custom_config/t_custom_config_rt.erl +++ b/inttest/t_custom_config/t_custom_config_rt.erl @@ -20,7 +20,7 @@ run(Dir) -> {ok, Missing} = retest:sh_expect(Ref, "DEBUG: Missing deps : \\[\\{dep,bad_name," - "boo,\"\\.\",undefined\\}\\]", + "boo,\"\\.\",undefined,false\\}\\]", [{capture, all, list}]), retest_log:log(debug, "[CAPTURED]: ~s~n", [Captured]), retest_log:log(debug, "[Missing]: ~s~n", [Missing]), 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/rebar.config.sample b/rebar.config.sample index 4ed815a..fac55af 100644 --- a/rebar.config.sample +++ b/rebar.config.sample @@ -138,7 +138,20 @@ {deps, [application_name, {application_name, "1.0.*"}, {application_name, "1.0.*", - {git, "git://github.com/basho/rebar.git", {branch, "master"}}}]}. + {git, "git://github.com/basho/rebar.git", {branch, "master"}}}, + +%% Dependencies can be marked as 'raw'. Rebar does not require such dependencies +%% to have a standard Erlang/OTP layout which assumes the presence of either +%% "src/dependency_name.app.src" or "ebin/dependency_name.app" files. +%% +%% 'raw' dependencies can still contain 'rebar.config' and even can have the +%% proper OTP directory layout, but they won't be compiled. +%% +%% Only a subset of rebar commands will be executed on the 'raw' subdirectories: +%% get-deps, update-deps, check-deps, list-deps and delete-deps. + {application_name, "", + {git, "git://github.com/basho/rebar.git", {branch, "master"}}, + [raw]}]}. %% == Subdirectories == 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 |