summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md110
-rw-r--r--README.md28
-rw-r--r--THANKS1
-rwxr-xr-xbootstrap29
-rw-r--r--priv/templates/otp_app.app.src6
-rw-r--r--priv/templates/otp_lib.app.src6
-rw-r--r--priv/templates/plugin.erl31
-rw-r--r--priv/templates/plugin.template1
-rw-r--r--priv/templates/provider.erl32
-rw-r--r--rebar.config29
-rw-r--r--rebar.config.sample10
-rw-r--r--rebar.lock6
-rw-r--r--src/rebar.app.src2
-rw-r--r--src/rebar3.erl5
-rw-r--r--src/rebar_agent.erl22
-rw-r--r--src/rebar_app_discover.erl2
-rw-r--r--src/rebar_core.erl12
-rw-r--r--src/rebar_dir.erl6
-rw-r--r--src/rebar_erlc_compiler.erl7
-rw-r--r--src/rebar_file_utils.erl113
-rw-r--r--src/rebar_git_resource.erl29
-rw-r--r--src/rebar_hooks.erl47
-rw-r--r--src/rebar_pkg_resource.erl3
-rw-r--r--src/rebar_plugins.erl2
-rw-r--r--src/rebar_prv_common_test.erl41
-rw-r--r--src/rebar_prv_compile.erl13
-rw-r--r--src/rebar_prv_cover.erl20
-rw-r--r--src/rebar_prv_dialyzer.erl10
-rw-r--r--src/rebar_prv_install_deps.erl221
-rw-r--r--src/rebar_prv_plugins_upgrade.erl5
-rw-r--r--src/rebar_prv_release.erl29
-rw-r--r--src/rebar_prv_relup.erl29
-rw-r--r--src/rebar_prv_shell.erl12
-rw-r--r--src/rebar_prv_tar.erl24
-rw-r--r--src/rebar_prv_update.erl3
-rw-r--r--src/rebar_relx.erl69
-rw-r--r--src/rebar_utils.erl59
-rw-r--r--test/rebar_compile_SUITE.erl58
-rw-r--r--test/rebar_cover_SUITE.erl21
-rw-r--r--test/rebar_deps_SUITE.erl68
-rw-r--r--test/rebar_hooks_SUITE.erl2
-rw-r--r--test/rebar_install_deps_SUITE.erl54
-rw-r--r--test/rebar_pkg_SUITE.erl8
-rw-r--r--test/rebar_release_SUITE.erl21
-rw-r--r--test/rebar_test_utils.erl28
-rw-r--r--test/rebar_upgrade_SUITE.erl34
-rw-r--r--test/rebar_utils_SUITE.erl17
47 files changed, 892 insertions, 493 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e0de0eb..0ce1e93 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,7 +1,7 @@
Contributing to rebar
---------------------
-Before implementing a new feature, please submit a ticket to discuss your plans.
+Before implementing a new feature, please submit a ticket to discuss your plans.
The feature might have been rejected already, or the implementation might already be decided.
See [Community and Resources](README.md#community-and-resources).
@@ -9,95 +9,99 @@ See [Community and Resources](README.md#community-and-resources).
Code style
----------
-The following rules must be followed:
+The following rules apply:
* Do not introduce trailing whitespace
- * Do not mix spaces and tabs
- * Do not introduce lines longer than 80 characters
-
-The following rules should be followed:
+ * We use spaces for indenting only
+ * Try not to introduce lines longer than 80 characters
* Write small functions whenever possible
- * Avoid having too many clauses containing clauses containing clauses.
+ * Avoid having too many clauses containing clauses containing clauses.
Basically, avoid deeply nested functions.
-[erlang-mode (emacs)](http://www.erlang.org/doc/man/erlang.el.html)
-indentation is preferred. This will keep the code base consistent.
-vi users are encouraged to give [Vim emulation](http://emacswiki.org/emacs/Evil) ([more
-info](https://gitorious.org/evil/pages/Home)) a try.
+Follow the indentation style of existing files. The [erlang-mode for
+(emacs)](http://www.erlang.org/doc/man/erlang.el.html) indentation is going to
+always work. Other users may want to use 4-width spaces and make sure things
+align mostly the way they would with Emacs code, or with the rest of the
+project.
+
+Where possible, include type specifications for your code so type analysis
+will be as accurate as possible.
+
+Please add comments around tricky fixes or workarounds so that we can
+easily know why they're there at a glance.
Pull requests and branching
---------------------------
-Use one topic branch per pull request. If you do that, you can add extra commits or fix up
-buggy commits via `git rebase -i`, and update the branch. The updated branch will be
-visible in the same pull request. Therefore, you should not open a new pull request when
-you have to fix your changes.
+All fixes to rebar end up requiring a +1 from one or more of the project's
+maintainers. When opening a pull request, explain what the patch is doing
+and if it makes sense, why the proposed implementation was chosen.
+
+Try to use well-defined commits (one feature per commit) so that reading
+them and testing them is easier for reviewers and while bissecting the code
+base for issues.
+
+During the review process, you may be asked to correct or edit a few things
+before a final rebase to merge things.
-Do not commit to master in your fork.
+Please work in feature branches, and do not commit to `master` in your fork.
Provide a clean branch without merge commits.
Tests
-----
-As a general rule, any behavioral change to rebar requires a test to go with it. If there's
-already a test case, you may have to modify that one. If there isn't a test case or a test
-suite, add a new test case or suite in `inttest/`. [retest](https://github.com/dizzyd/retest) based tests are preferred, but
-we also have EUnit tests in `test/`.
+As a general rule, any behavioral change to rebar requires a test to go with
+it. If there's already a test case, you may have to modify that one. If there
+isn't a test case or a test suite, add a new test case or suite in `test/`.
-Say you've added a new test case in `inttest/erlc`. To only execute the modified suite,
-you would do the following:
-```sh
-# First we build rebar and its deps to also get `deps/retest/retest`
-$ make debug deps
-# Now we can test the modified erlc suite
-$ deps/retest/retest -v inttest/erlc
-```
+To run the tests:
-To test EUnit tests, you would do:
```sh
-$ make debug
-$ ./rebar -v eunit
+$ ./bootstrap
+$ ./rebar3 ct
```
-You can also run `make test` to execute both EUnit and [retest](https://github.com/dizzyd/retest) tests as `make check` does.
+The rebar3 test suite is written using Common Test. As many of the tests as
+possible are written by using the programmatic rebar3 API rather than
+by running the escriptized project directly. The tests should be restricted
+to their `priv_dir` and leave the system clean after a run.
+
+ If such tests prove hard to write, you can ask for help doing that in your
+pull request.
+
+For tests having a lot to do with I/O and terminal interaction, consider
+adding them to https://github.com/tsloughter/rebar3_tests
+
Credit
------
-To give everyone proper credit in addition to the git history, please feel free to append
+To give everyone proper credit in addition to the git history, please feel free to append
your name to `THANKS` in your first contribution.
Committing your changes
-----------------------
-Please ensure that all commits pass all tests, and do not have extra Dialyzer warnings.
-To do that run `make check`. If you didn't build via `make debug` at first, the beam files in
-`ebin/` might be missing debug_info required for [xref](http://www.erlang.org/doc/man/xref.html)
-and [Dialyzer](http://www.erlang.org/doc/man/dialyzer.html), causing a test
-failure.
-If that happens, running `make clean` before running `make check` could solve the problem.
-If you change any of the files with known but safe to ignore Dialyzer warnings, you may
-have to adapt the line number(s) in [dialyzer_reference](dialyzer_reference). If you do that,
-do not remove the
-leading blank line.
+Please ensure that all commits pass all tests, and do not have extra Dialyzer warnings.
+To do that run `./rebar3 ct` and `./rebar3 as dialyze dialyzer`.
#### Structuring your commits
-Fixing a bug is one commit.
-Adding a feature is one commit.
-Adding two features is two commits.
-Two unrelated changes is two commits.
+- Fixing a bug is one commit.
+- Adding a feature is one commit.
+- Adding two features is two commits.
+- Two unrelated changes is two commits (and likely two Pull requests)
-If you fix a (buggy) commit, squash (`git rebase -i`) the changes as a fixup commit into
+If you fix a (buggy) commit, squash (`git rebase -i`) the changes as a fixup commit into
the original commit.
#### Writing Commit Messages
-It's important to write a proper commit title and description. The commit title must be
-at most 50 characters; it is the first line of the commit text. The second line of the
-commit text must be left blank. The third line and beyond is the commit message. You
-should write a commit message. If you do, wrap all lines at 72 characters. You should
-explain what the commit does, what references you used, and any other information
+It's important to write a proper commit title and description. The commit title must be
+at most 50 characters; it is the first line of the commit text. The second line of the
+commit text must be left blank. The third line and beyond is the commit message. You
+should write a commit message. If you do, wrap all lines at 72 characters. You should
+explain what the commit does, what references you used, and any other information
that helps understanding your changes.
Basically, structure your commit message like this:
diff --git a/README.md b/README.md
index 075b841..e2bb9ac 100644
--- a/README.md
+++ b/README.md
@@ -11,21 +11,13 @@ 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).
+locations ([hex.pm](http://hex.pm), git, hg, and so on).
-3.0 Alpha-6
+3.0 Beta-1
====
[DOCUMENTATION](http://www.rebar3.org/v3.0/docs)
-This is a preliminary branch, considered to be alpha, and still
-very unstable. Use at your own risk, but please do report bugs
-and issues encountered and we'll try to resolve problems as
-soon as possible.
-
-Compatibility with rebar 2.0 has been broken, and features removed to
-limit scope.
-
### Commands
| Command | Description |
@@ -35,6 +27,7 @@ limit scope.
| clean | Remove project apps beam files |
| cover | Generate coverage info from data compiled by `eunit --cover` or `ct --cover` |
| ct | Run Common Test suites |
+| deps | Lists dependencies currently in use |
| do | Higher-order provider to run multiple tasks in sequence |
| dialyzer | Run the Dialyzer analyzer on the project |
| edoc | Generate documentation using edoc |
@@ -55,15 +48,26 @@ limit scope.
| version | Print current version of Erlang/OTP and rebar |
| xref | Run cross reference analysis on the project |
+A more complete list can be found on the [docs page](http://www.rebar3.org/v3.0/docs/commands)
+
### Changes
+#### Since Rebar 2.x
+
* Fetches and builds deps if missing when running any command that relies on them
* Automatically recognizes `apps` and `lib` directory structure
-* Relx for releases
+* Relx for releases and relups
+* deterministic builds and conflict resolution
+* New plugin handling mechanism
+* New hook mechanism
+* Support for packages
+* A ton more
### Gone
* Reltool integeration
+* Quickcheck integration (moved to [a plugin](http://www.rebar3.org/v3.0/docs/using-available-plugins#quickcheck))
+* C code compiling (moved to [a plugin](http://www.rebar3.org/v3.0/docs/using-available-plugins#port-compiler) or hooks)
### Providers
@@ -144,7 +148,6 @@ $ ./rebar3 escriptize
$ _build/default/bin/rebar3
```
-
Contributing to rebar
=====================
@@ -174,3 +177,4 @@ General rebar community resources and links:
- #rebar on [irc.freenode.net](http://freenode.net/)
- [wiki](https://github.com/rebar/rebar/wiki)
- [issues](https://github.com/rebar/rebar/issues)
+- [Documentation](http://www.rebar3.org/v3.0/docs)
diff --git a/THANKS b/THANKS
index a6562ed..d813970 100644
--- a/THANKS
+++ b/THANKS
@@ -134,3 +134,4 @@ Martin Karlsson
Pierre Fenoll
David Kubecka
Stefan Grundmann
+Carlos Eduardo de Paula
diff --git a/bootstrap b/bootstrap
index 41d9725..71c44da 100755
--- a/bootstrap
+++ b/bootstrap
@@ -9,6 +9,8 @@ main(_Args) ->
application:start(public_key),
application:start(ssl),
inets:start(),
+ inets:start(httpc, [{profile, rebar}]),
+ set_httpc_options(),
%% Fetch and build deps required to build rebar3
BaseDeps = [{providers, []}
@@ -84,13 +86,38 @@ extract(Binary) ->
request(Url) ->
case httpc:request(get, {Url, []},
[{relaxed, true}],
- [{body_format, binary}]) of
+ [{body_format, binary}],
+ rebar) of
{ok, {{_Version, 200, _Reason}, _Headers, Body}} ->
{ok, Body};
Error ->
Error
end.
+get_rebar_config() ->
+ {ok, [[Home]]} = init:get_argument(home),
+ ConfDir = filename:join(Home, ".config/rebar3"),
+ case file:consult(filename:join(ConfDir, "rebar.config")) of
+ {ok, Config} ->
+ Config;
+ _ ->
+ []
+ end.
+
+get_http_vars(Scheme) ->
+ proplists:get_value(Scheme, get_rebar_config(), []).
+
+set_httpc_options() ->
+ set_httpc_options(https_proxy, get_http_vars(https_proxy)),
+ set_httpc_options(proxy, get_http_vars(http_proxy)).
+
+set_httpc_options(_, []) ->
+ ok;
+
+set_httpc_options(Scheme, Proxy) ->
+ {ok, {_, _, Host, Port, _, _}} = http_uri:parse(Proxy),
+ httpc:set_options([{Scheme, {{Host, Port}, []}}], rebar).
+
compile(App, FirstFiles) ->
Dir = filename:join(filename:absname("_build/default/lib/"), App),
filelib:ensure_dir(filename:join([Dir, "ebin", "dummy.beam"])),
diff --git a/priv/templates/otp_app.app.src b/priv/templates/otp_app.app.src
index 9ad7478..09e4a48 100644
--- a/priv/templates/otp_app.app.src
+++ b/priv/templates/otp_app.app.src
@@ -8,5 +8,9 @@
stdlib
]},
{env,[]},
- {modules, []}
+ {modules, []},
+
+ {contributors, []},
+ {licenses, []},
+ {links, []}
]}.
diff --git a/priv/templates/otp_lib.app.src b/priv/templates/otp_lib.app.src
index 3f4b56b..f07293e 100644
--- a/priv/templates/otp_lib.app.src
+++ b/priv/templates/otp_lib.app.src
@@ -7,5 +7,9 @@
stdlib
]},
{env,[]},
- {modules, []}
+ {modules, []},
+
+ {contributors, []},
+ {licenses, []},
+ {links, []}
]}.
diff --git a/priv/templates/plugin.erl b/priv/templates/plugin.erl
index 018dd0e..c6e5e40 100644
--- a/priv/templates/plugin.erl
+++ b/priv/templates/plugin.erl
@@ -1,33 +1,8 @@
-module('{{name}}').
--behaviour(provider).
--export([init/1, do/1, format_error/1]).
+-export([init/1]).
--define(PROVIDER, '{{name}}').
--define(DEPS, [app_discovery]).
-
-%% ===================================================================
-%% Public API
-%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
- Provider = providers:create([
- {name, ?PROVIDER}, % The 'user friendly' name of the task
- {module, ?MODULE}, % The module implementation of the task
- {bare, true}, % The task can be run by the user, always true
- {deps, ?DEPS}, % The list of dependencies
- {example, "rebar3 {{name}}"}, % How to use the plugin
- {opts, []}, % list of options understood by the plugin
- {short_desc, "{{desc}}"},
- {desc, "{{desc}}"}
- ]),
- {ok, rebar_state:add_provider(State, Provider)}.
-
-
--spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
-do(State) ->
- {ok, State}.
-
--spec format_error(any()) -> iolist().
-format_error(Reason) ->
- io_lib:format("~p", [Reason]).
+ {ok, State1} = '{{name}}_prv':init(State),
+ {ok, State1}.
diff --git a/priv/templates/plugin.template b/priv/templates/plugin.template
index 811be0b..c0e36de 100644
--- a/priv/templates/plugin.template
+++ b/priv/templates/plugin.template
@@ -4,6 +4,7 @@
{desc, "A rebar plugin", "Short description of the plugin's purpose"}
]}.
{template, "plugin.erl", "{{name}}/src/{{name}}.erl"}.
+{template, "provider.erl", "{{name}}/src/prv_{{name}}_prv.erl"}.
{template, "otp_lib.app.src", "{{name}}/src/{{name}}.app.src"}.
{template, "rebar.config", "{{name}}/rebar.config"}.
{template, "gitignore", "{{name}}/.gitignore"}.
diff --git a/priv/templates/provider.erl b/priv/templates/provider.erl
new file mode 100644
index 0000000..669df83
--- /dev/null
+++ b/priv/templates/provider.erl
@@ -0,0 +1,32 @@
+-module('{{name}}_prv').
+
+-export([init/1, do/1, format_error/1]).
+
+-define(PROVIDER, '{{name}}').
+-define(DEPS, [app_discovery]).
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
+init(State) ->
+ Provider = providers:create([
+ {name, ?PROVIDER}, % The 'user friendly' name of the task
+ {module, ?MODULE}, % The module implementation of the task
+ {bare, true}, % The task can be run by the user, always true
+ {deps, ?DEPS}, % The list of dependencies
+ {example, "rebar3 {{name}}"}, % How to use the plugin
+ {opts, []}, % list of options understood by the plugin
+ {short_desc, "{{desc}}"},
+ {desc, "{{desc}}"}
+ ]),
+ {ok, rebar_state:add_provider(State, Provider)}.
+
+
+-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+do(State) ->
+ {ok, State}.
+
+-spec format_error(any()) -> iolist().
+format_error(Reason) ->
+ io_lib:format("~p", [Reason]).
diff --git a/rebar.config b/rebar.config
index bd0f517..16b57d8 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,12 +1,11 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-{deps, [
- {erlware_commons, "0.12.0"},
- {providers, "1.4.1"},
- {getopt, "0.8.2"},
- {bbmustache, "1.0.1"},
- {relx, "3.0.0"}]}.
+{deps, [{erlware_commons, "0.13.0"},
+ {providers, "1.4.1"},
+ {getopt, "0.8.2"},
+ {bbmustache, "1.0.3"},
+ {relx, "3.3.0"}]}.
{escript_name, rebar3}.
{escript_emu_args, "%%! +sbtu +A0\n"}.
@@ -16,20 +15,18 @@
{"priv/templates/*", "."},
{"rebar/include/*", "."}]}.
-{erl_opts,
- [{platform_define, "^[0-9]+", namespaced_types},
- no_debug_info,
- warnings_as_errors]}.
+{erl_opts, [{platform_define, "^[0-9]+", namespaced_types},
+ no_debug_info,
+ warnings_as_errors]}.
{dialyzer_plt_apps, [common_test, dialyzer, eunit, snmp]}.
%% Profiles
-{profiles, [{test,
- [{deps, [
- {meck, "", {git, "https://github.com/eproxus/meck.git", {tag, "0.8.2"}}}
- ]},
- {erl_opts, [debug_info]}
- ]},
+{profiles, [{test, [
+ {deps, [{meck, "0.8.2"}]},
+ {erl_opts, [debug_info]}
+ ]
+ },
{bootstrap, []},
diff --git a/rebar.config.sample b/rebar.config.sample
index f6d27c8..1bd5e0c 100644
--- a/rebar.config.sample
+++ b/rebar.config.sample
@@ -83,14 +83,14 @@
%% == Cover ==
-%% Whether to enable coverage reporting. Default is `false'
+%% Whether to enable coverage reporting where commands support cover. Default
+%% is `false'
{cover_enabled, false}.
-%% Whether to print coverage report to console. Default is `false'
-{cover_print_enabled, false}.
+%% Options to pass to cover provider
+{cover_opts, [verbose]}.
-%% Directory to store collected cover data
-{cover_data_dir, "cover"}.
+%% == Dependencies ==
%% What dependencies we have, dependencies can be of 3 forms, an application
%% name as an atom, eg. mochiweb, a name and a version (from the .app file), or
diff --git a/rebar.lock b/rebar.lock
index 3452cea..1ff26f3 100644
--- a/rebar.lock
+++ b/rebar.lock
@@ -1,5 +1,5 @@
-[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.0.1">>},0},
+[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.0.3">>},0},
{<<"providers">>,{pkg,<<"providers">>,<<"1.4.1">>},0},
- {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"0.12.0">>},0},
- {<<"relx">>,{pkg,<<"relx">>,<<"3.0.0">>},0},
+ {<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"0.13.0">>},0},
+ {<<"relx">>,{pkg,<<"relx">>,<<"3.3.0">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},0}].
diff --git a/src/rebar.app.src b/src/rebar.app.src
index 5abb643..e5d56bb 100644
--- a/src/rebar.app.src
+++ b/src/rebar.app.src
@@ -3,7 +3,7 @@
{application, rebar,
[{description, "Rebar: Erlang Build Tool"},
- {vsn, "3.0.0-alpha-6"},
+ {vsn, "3.0.0-beta-1"},
{modules, []},
{registered, []},
{applications, [kernel,
diff --git a/src/rebar3.erl b/src/rebar3.erl
index 5c0559f..a797c46 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -272,4 +272,7 @@ start_and_load_apps() ->
application:start(asn1),
application:start(public_key),
application:start(ssl),
- inets:start().
+ inets:start(),
+ inets:start(httpc, [{profile, rebar}]),
+ rebar_utils:set_httpc_options().
+
diff --git a/src/rebar_agent.erl b/src/rebar_agent.erl
index 0432fb8..dc45dcf 100644
--- a/src/rebar_agent.erl
+++ b/src/rebar_agent.erl
@@ -20,17 +20,17 @@ do(Namespace, Command) when is_atom(Namespace), is_atom(Command) ->
gen_server:call(?MODULE, {cmd, Namespace, Command}, infinity).
init(State) ->
- {ok, Cwd} = file:get_cwd(),
+ Cwd = rebar_dir:get_cwd(),
{ok, #state{state=State, cwd=Cwd}}.
handle_call({cmd, Command}, _From, State=#state{state=RState, cwd=Cwd}) ->
MidState = maybe_show_warning(State),
{Res, NewRState} = run(default, Command, RState, Cwd),
- {reply, Res, MidState#state{state=NewRState}};
+ {reply, Res, MidState#state{state=NewRState}, hibernate};
handle_call({cmd, Namespace, Command}, _From, State = #state{state=RState, cwd=Cwd}) ->
MidState = maybe_show_warning(State),
{Res, NewRState} = run(Namespace, Command, RState, Cwd),
- {reply, Res, MidState#state{state=NewRState}};
+ {reply, Res, MidState#state{state=NewRState}, hibernate};
handle_call(_Call, _From, State) ->
{noreply, State}.
@@ -48,8 +48,8 @@ terminate(_Reason, _State) ->
run(Namespace, Command, RState, Cwd) ->
try
- case file:get_cwd() of
- {ok, Cwd} ->
+ case rebar_dir:get_cwd() of
+ Cwd ->
Args = [atom_to_list(Namespace), atom_to_list(Command)],
CmdState0 = refresh_state(RState, Cwd),
CmdState1 = rebar_state:set(CmdState0, task, atom_to_list(Command)),
@@ -87,16 +87,22 @@ refresh_paths(RState) ->
%% make sure to never reload self; halt()s the VM
) -- [filename:dirname(code:which(?MODULE))],
%% Similar to rebar_utils:update_code/1, but also forces a reload
- %% of used modules.
+ %% of used modules. Also forces to reload all of ebin/ instead
+ %% of just the modules in the .app file, because 'extra_src_dirs'
+ %% allows to load and compile files that are not to be kept
+ %% in the app file.
lists:foreach(fun(Path) ->
Name = filename:basename(Path, "/ebin"),
+ Files = filelib:wildcard(filename:join([Path, "*.beam"])),
+ Modules = [list_to_atom(filename:basename(F, ".beam"))
+ || F <- Files],
App = list_to_atom(Name),
application:load(App),
case application:get_key(App, modules) of
undefined ->
code:add_patha(Path),
ok;
- {ok, Modules} ->
+ {ok, _} ->
?DEBUG("reloading ~p from ~s", [Modules, Path]),
code:replace_path(Name, Path),
[begin code:purge(M), code:delete(M), code:load_file(M) end
@@ -108,5 +114,5 @@ refresh_state(RState, _Dir) ->
lists:foldl(
fun(F, State) -> F(State) end,
rebar3:init_config(),
- [fun(S) -> rebar_state:current_profiles(S, rebar_state:current_profiles(RState)) end]
+ [fun(S) -> rebar_state:apply_profiles(S, rebar_state:current_profiles(RState)) end]
).
diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl
index 2eb9d91..9c4a5ff 100644
--- a/src/rebar_app_discover.erl
+++ b/src/rebar_app_discover.erl
@@ -139,7 +139,7 @@ app_dir(AppFile) ->
-spec create_app_info(file:name(), file:name()) -> rebar_app_info:t() | {error, term()}.
create_app_info(AppDir, AppFile) ->
- [{application, AppName, AppDetails}] = rebar_file_utils:try_consult(AppFile),
+ [{application, AppName, AppDetails}] = rebar_config:consult_app_file(AppFile),
AppVsn = proplists:get_value(vsn, AppDetails),
Applications = proplists:get_value(applications, AppDetails, []),
IncludedApplications = proplists:get_value(included_applications, AppDetails, []),
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index b1647f0..f097429 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -128,9 +128,15 @@ do([ProviderName | Rest], State) ->
{error, Error}
catch
error:undef ->
- %% This should really only happen if a plugin provider doesn't export do/1
- ?DEBUG("Undefined call to provider's do function:~n~p", [erlang:get_stacktrace()]),
- ?PRV_ERROR({bad_provider_namespace, ProviderName});
+ Stack = erlang:get_stacktrace(),
+ case Stack of
+ [{ProviderName, do, [_], _}|_] ->
+ %% This should really only happen if a plugin provider doesn't export do/1
+ ?DEBUG("Undefined call to provider's do/1 function:~n~p", [Stack]),
+ ?PRV_ERROR({bad_provider_namespace, ProviderName});
+ _ -> % re-raise
+ erlang:raise(error, undef, Stack)
+ end;
error:{badrecord,provider} ->
{error, ProviderName}
end.
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl
index e226633..7af94ea 100644
--- a/src/rebar_dir.erl
+++ b/src/rebar_dir.erl
@@ -100,7 +100,11 @@ local_cache_dir(Dir) ->
get_cwd() ->
{ok, Dir} = file:get_cwd(),
- Dir.
+ %% On windows cwd may return capital letter for drive,
+ %% for example C:/foobar. But as said in http://www.erlang.org/doc/man/filename.html#join-1
+ %% filename:join/1,2 anyway will convert drive-letter to lowercase, so we have to "internalize"
+ %% cwd as soon as it possible.
+ filename:join([Dir]).
template_globals(State) ->
filename:join([global_config_dir(State), "templates", "globals"]).
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index b9072a3..87cf352 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -404,10 +404,13 @@ target_base(OutDir, Source) ->
-spec compile_mib(file:filename(), file:filename(),
rebar_state:t()) -> 'ok'.
compile_mib(Source, Target, Config) ->
+ Dir = rebar_state:dir(Config),
ok = filelib:ensure_dir(Target),
- ok = filelib:ensure_dir(filename:join("include", "dummy.hrl")),
- Opts = [{outdir, "priv/mibs"}, {i, ["priv/mibs"]}] ++
+ ok = filelib:ensure_dir(filename:join([Dir, "include", "dummy.hrl"])),
+ Opts = [{outdir, filename:join([Dir, "priv", "mibs"])}
+ ,{i, [filename:join([Dir, "priv", "mibs"])]}] ++
rebar_state:get(Config, mib_opts, []),
+
case snmpc:compile(Source, Opts) of
{ok, _} ->
Mib = filename:rootname(Target),
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index ad30172..b4cdc27 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -36,10 +36,14 @@
write_file_if_contents_differ/2,
system_tmpdir/0,
system_tmpdir/1,
- reset_dir/1]).
+ reset_dir/1,
+ touch/1]).
-include("rebar.hrl").
+
-include_lib("providers/include/providers.hrl").
+-include_lib("kernel/include/file.hrl").
+
%% ===================================================================
%% Public API
@@ -71,9 +75,40 @@ symlink_or_copy(Source, Target) ->
{error, eexist} ->
ok;
{error, _} ->
- cp_r([Source], Target)
+ case os:type() of
+ {win32, _} ->
+ S = unicode:characters_to_list(Source),
+ T = unicode:characters_to_list(Target),
+ case filelib:is_dir(S) of
+ true ->
+ win32_symlink(S, T);
+ false ->
+ cp_r([S], T)
+ end;
+ _ ->
+ case filelib:is_dir(Target) of
+ true ->
+ ok;
+ false ->
+ cp_r([Source], Target)
+ end
+ end
+ end.
+
+win32_symlink(Source, Target) ->
+ Res = rebar_utils:sh(
+ ?FMT("cmd /c mklink /j \"~s\" \"~s\"",
+ [filename:nativename(Target), filename:nativename(Source)]),
+ [{use_stdout, false}, return_on_error]),
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
+ {error, lists:flatten(
+ io_lib:format("Failed to symlink ~s to ~s~n",
+ [Source, Target]))}
end.
+
%% @doc Remove files and directories.
%% Target is a single filename, directoryname or wildcard expression.
-spec rm_rf(string()) -> 'ok'.
@@ -120,21 +155,32 @@ mv(Source, Dest) ->
[{use_stdout, false}, abort_on_error]),
ok;
{win32, _} ->
- {ok, R} = rebar_utils:sh(
- ?FMT("move /y \"~s\" \"~s\" 1> nul",
- [filename:nativename(Source),
- filename:nativename(Dest)]),
+ Cmd = case filelib:is_dir(Source) of
+ true ->
+ ?FMT("robocopy /move /s \"~s\" \"~s\" 1> nul",
+ [filename:nativename(Source),
+ filename:nativename(Dest)]);
+ false ->
+ ?FMT("robocopy /move /s \"~s\" \"~s\" \"~s\" 1> nul",
+ [filename:nativename(filename:dirname(Source)),
+ filename:nativename(Dest),
+ filename:basename(Source)])
+ end,
+ Res = rebar_utils:sh(Cmd,
[{use_stdout, false}, return_on_error]),
- case R of
- [] ->
- ok;
- _ ->
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
{error, lists:flatten(
io_lib:format("Failed to move ~s to ~s~n",
[Source, Dest]))}
end
end.
+win32_ok({ok, _}) -> true;
+win32_ok({error, {Rc, _}}) when Rc<9; Rc=:=16 -> true;
+win32_ok(_) -> false.
+
delete_each([]) ->
ok;
delete_each([File | Rest]) ->
@@ -186,6 +232,17 @@ reset_dir(Path) ->
%% recreate the directory
filelib:ensure_dir(filename:join([Path, "dummy.beam"])).
+
+%% Linux touch but using erlang functions to work in bot *nix os and
+%% windows
+-spec touch(Path) -> ok | {error, Reason} when
+ Path :: file:name(),
+ Reason :: file:posix().
+touch(Path) ->
+ {ok, A} = file:read_file_info(Path),
+ ok = file:write_file_info(Path, A#file_info{mtime = calendar:local_time(),
+ atime = calendar:local_time()}).
+
%% ===================================================================
%% Internal functions
%% ===================================================================
@@ -198,28 +255,36 @@ delete_each_dir_win32([Dir | Rest]) ->
delete_each_dir_win32(Rest).
xcopy_win32(Source,Dest)->
- {ok, R} = rebar_utils:sh(
- ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
- [filename:nativename(Source), filename:nativename(Dest)]),
+ %% "xcopy \"~s\" \"~s\" /q /y /e 2> nul", Chanegd to robocopy to
+ %% handle long names. May have issues with older windows.
+ Cmd = case filelib:is_dir(Source) of
+ true ->
+ ?FMT("robocopy \"~s\" \"~s\" /e /is 1> nul",
+ [filename:nativename(Source),
+ filename:nativename(Dest)]);
+ false ->
+ ?FMT("robocopy \"~s\" \"~s\" \"~s\" /e /is 1> nul",
+ [filename:nativename(filename:dirname(Source)),
+ filename:nativename(Dest),
+ filename:basename(Source)])
+ end,
+ Res = rebar_utils:sh(Cmd,
[{use_stdout, false}, return_on_error]),
- case length(R) > 0 of
- %% when xcopy fails, stdout is empty and and error message is printed
- %% to stderr (which is redirected to nul)
- true -> ok;
- false ->
- {error, lists:flatten(
- io_lib:format("Failed to xcopy from ~s to ~s~n",
- [Source, Dest]))}
+ case win32_ok(Res) of
+ true -> ok;
+ false ->
+ {error, lists:flatten(
+ io_lib:format("Failed to copy ~s to ~s~n",
+ [Source, Dest]))}
end.
cp_r_win32({true, SourceDir}, {true, DestDir}) ->
%% from directory to directory
- SourceBase = filename:basename(SourceDir),
- ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
+ ok = case file:make_dir(DestDir) of
{error, eexist} -> ok;
Other -> Other
end,
- ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
+ ok = xcopy_win32(SourceDir, DestDir);
cp_r_win32({false, Source} = S,{true, DestDir}) ->
%% from file to directory
cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl
index 2d83579..e2f3f69 100644
--- a/src/rebar_git_resource.erl
+++ b/src/rebar_git_resource.erl
@@ -68,6 +68,7 @@ compare_url(Dir, Url) ->
CurrentUrl1 = string:strip(string:strip(CurrentUrl, both, $\n), both, $\r),
ParsedUrl = parse_git_url(Url),
ParsedCurrentUrl = parse_git_url(CurrentUrl1),
+ ?DEBUG("Comparing git url ~p with ~p", [ParsedUrl, ParsedCurrentUrl]),
ParsedCurrentUrl =:= ParsedUrl.
parse_git_url("git@" ++ HostPath) ->
@@ -76,6 +77,9 @@ parse_git_url("git@" ++ HostPath) ->
parse_git_url("git://" ++ HostPath) ->
[Host | Path] = string:tokens(HostPath, "/"),
{Host, filename:rootname(filename:join(Path), ".git")};
+parse_git_url("http://" ++ HostPath) ->
+ [Host | Path] = string:tokens(HostPath, "/"),
+ {Host, filename:rootname(filename:join(Path), ".git")};
parse_git_url("https://" ++ HostPath) ->
[Host | Path] = string:tokens(HostPath, "/"),
{Host, filename:rootname(filename:join(Path), ".git")}.
@@ -109,28 +113,23 @@ download(Dir, {git, Url, Rev}, _State) ->
rebar_utils:sh(?FMT("git checkout -q ~s", [Rev]), [{cd, Dir}]).
make_vsn(Dir) ->
- {ok, Cwd} = file:get_cwd(),
- try
- ok = file:set_cwd(Dir),
- {Vsn, RawRef, RawCount} = collect_default_refcount(),
- {plain, build_vsn_string(Vsn, RawRef, RawCount)}
- after
- file:set_cwd(Cwd)
- end.
+ {Vsn, RawRef, RawCount} = collect_default_refcount(Dir),
+ {plain, build_vsn_string(Vsn, RawRef, RawCount)}.
%% Internal functions
-collect_default_refcount() ->
+collect_default_refcount(Dir) ->
%% Get the tag timestamp and minimal ref from the system. The
%% timestamp is really important from an ordering perspective.
AbortMsg1 = "Getting log of git dependency failed in " ++ rebar_dir:get_cwd(),
{ok, String} =
rebar_utils:sh("git log -n 1 --pretty=format:\"%h\n\" ",
[{use_stdout, false},
+ {cd, Dir},
{debug_abort_on_error, AbortMsg1}]),
RawRef = string:strip(String, both, $\n),
- {Tag, TagVsn} = parse_tags(),
+ {Tag, TagVsn} = parse_tags(Dir),
{ok, RawCount} =
case Tag of
undefined ->
@@ -140,7 +139,7 @@ collect_default_refcount() ->
{debug_abort_on_error, AbortMsg2}]),
rebar_utils:line_count(PatchLines);
_ ->
- get_patch_count(Tag)
+ get_patch_count(Dir, Tag)
end,
{TagVsn, RawRef, RawCount}.
@@ -158,8 +157,8 @@ build_vsn_string(Vsn, RawRef, Count) ->
integer_to_list(Count), RefTag]))
end.
-get_patch_count(RawRef) ->
- AbortMsg = "Getting rev-list of git dep failed in " ++ rebar_dir:get_cwd(),
+get_patch_count(Dir, RawRef) ->
+ AbortMsg = "Getting rev-list of git dep failed in " ++ Dir,
Ref = re:replace(RawRef, "\\s", "", [global]),
Cmd = io_lib:format("git rev-list ~s..HEAD",
[Ref]),
@@ -169,10 +168,10 @@ get_patch_count(RawRef) ->
rebar_utils:line_count(PatchLines).
-parse_tags() ->
+parse_tags(Dir) ->
%% Don't abort on error, we want the bad return to be turned into 0.0.0
case rebar_utils:sh("git log --oneline --no-walk --tags --decorate",
- [{use_stdout, false}, return_on_error]) of
+ [{use_stdout, false}, return_on_error, {cd, Dir}]) of
{error, _} ->
{undefined, "0.0.0"};
{ok, Line} ->
diff --git a/src/rebar_hooks.erl b/src/rebar_hooks.erl
index 56c4e91..857336c 100644
--- a/src/rebar_hooks.erl
+++ b/src/rebar_hooks.erl
@@ -14,12 +14,21 @@ run_all_hooks(Dir, Type, Command, Providers, State) ->
run_hooks(Dir, Type, Command, State).
run_provider_hooks(Dir, Type, Command, Providers, State) ->
+ case rebar_state:get(State, provider_hooks, []) of
+ [] ->
+ ok;
+ AllHooks ->
+ TypeHooks = proplists:get_value(Type, AllHooks, []),
+ run_provider_hooks(Dir, Type, Command, Providers, TypeHooks, State)
+ end.
+
+run_provider_hooks(_Dir, _Type, _Command, _Providers, [], _State) ->
+ ok;
+run_provider_hooks(Dir, Type, Command, Providers, TypeHooks, State) ->
PluginDepsPaths = rebar_state:code_paths(State, all_plugin_deps),
code:add_pathsa(PluginDepsPaths),
Providers1 = rebar_state:providers(State),
State1 = rebar_state:providers(rebar_state:dir(State, Dir), Providers++Providers1),
- AllHooks = rebar_state:get(State1, provider_hooks, []),
- TypeHooks = proplists:get_value(Type, AllHooks, []),
HookProviders = proplists:get_all_values(Command, TypeHooks),
case rebar_core:do(HookProviders, State1) of
@@ -58,24 +67,24 @@ format_error({bad_provider, Type, Command, Name}) ->
%% ERL = ERLANG_ROOT_DIR/bin/erl
%% ERLC = ERLANG_ROOT_DIR/bin/erl
%%
+run_hooks(Dir, pre, Command, State) ->
+ run_hooks(Dir, pre_hooks, Command, State);
+run_hooks(Dir, post, Command, State) ->
+ run_hooks(Dir, post_hooks, Command, State);
run_hooks(Dir, Type, Command, State) ->
- Hooks = case Type of
- pre ->
- rebar_state:get(State, pre_hooks, []);
- post ->
- rebar_state:get(State, post_hooks, []);
- _ ->
- []
- end,
-
- Env = create_env(State),
- lists:foreach(fun({_, C, _}=Hook) when C =:= Command ->
- apply_hook(Dir, Env, Hook);
- ({C, _}=Hook) when C =:= Command ->
- apply_hook(Dir, Env, Hook);
- (_) ->
- continue
- end, Hooks).
+ case rebar_state:get(State, Type, []) of
+ [] ->
+ ok;
+ Hooks ->
+ Env = create_env(State),
+ lists:foreach(fun({_, C, _}=Hook) when C =:= Command ->
+ apply_hook(Dir, Env, Hook);
+ ({C, _}=Hook) when C =:= Command ->
+ apply_hook(Dir, Env, Hook);
+ (_) ->
+ continue
+ end, Hooks)
+ end.
apply_hook(Dir, Env, {Arch, Command, Hook}) ->
case rebar_utils:is_arch(Arch) of
diff --git a/src/rebar_pkg_resource.erl b/src/rebar_pkg_resource.erl
index 59ce0dc..450ff1e 100644
--- a/src/rebar_pkg_resource.erl
+++ b/src/rebar_pkg_resource.erl
@@ -95,7 +95,8 @@ make_vsn(_) ->
request(Url, ETag) ->
case httpc:request(get, {Url, [{"if-none-match", ETag} || ETag =/= false]},
[{relaxed, true}],
- [{body_format, binary}]) of
+ [{body_format, binary}],
+ rebar) of
{ok, {{_Version, 200, _Reason}, Headers, Body}} ->
?DEBUG("Successfully downloaded ~s", [Url]),
{"etag", ETag1} = lists:keyfind("etag", 1, Headers),
diff --git a/src/rebar_plugins.erl b/src/rebar_plugins.erl
index 7e12324..3e855de 100644
--- a/src/rebar_plugins.erl
+++ b/src/rebar_plugins.erl
@@ -63,7 +63,7 @@ handle_plugins(Profile, Plugins, State, Upgrade) ->
handle_plugin(Profile, Plugin, State, Upgrade) ->
try
- {ok, Apps, State2} = rebar_prv_install_deps:handle_deps(Profile, State, [Plugin], Upgrade),
+ {Apps, State2} = rebar_prv_install_deps:handle_deps_as_profile(Profile, State, [Plugin], Upgrade),
{no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps),
ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []),
diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl
index 710922a..2b024cf 100644
--- a/src/rebar_prv_common_test.erl
+++ b/src/rebar_prv_common_test.erl
@@ -105,14 +105,18 @@ run_test_verbose(Opts) -> handle_results(ct:run_test(Opts)).
run_test_quiet(Opts) ->
Pid = self(),
+ Ref = erlang:make_ref(),
LogDir = proplists:get_value(logdir, Opts),
- erlang:spawn_monitor(fun() ->
+ {_, Monitor} = erlang:spawn_monitor(fun() ->
{ok, F} = file:open(filename:join([LogDir, "ct.latest.log"]),
[write]),
true = group_leader(F, self()),
- Pid ! ct:run_test(Opts)
+ Pid ! {Ref, ct:run_test(Opts)}
end),
- receive Result -> handle_quiet_results(Opts, Result) end.
+ receive
+ {Ref, Result} -> handle_quiet_results(Opts, Result);
+ {'DOWN', Monitor, _, _, Reason} -> handle_results(?PRV_ERROR(Reason))
+ end.
handle_results(Results) when is_list(Results) ->
Result = lists:foldl(fun sum_results/2, {0, 0, {0,0}}, Results),
@@ -132,8 +136,6 @@ sum_results({Passed, Failed, {UserSkipped, AutoSkipped}},
handle_quiet_results(_, {error, _} = Result) ->
handle_results(Result);
-handle_quiet_results(_, {'DOWN', _, _, _, Reason}) ->
- handle_results(?PRV_ERROR(Reason));
handle_quiet_results(CTOpts, Results) when is_list(Results) ->
_ = [format_result(Result) || Result <- Results],
case handle_results(Results) of
@@ -345,23 +347,26 @@ reduce_path([_|Acc], [".."|Rest]) -> reduce_path(Acc, Rest);
reduce_path([], [".."|Rest]) -> reduce_path([], Rest);
reduce_path(Acc, [Component|Rest]) -> reduce_path([Component|Acc], Rest).
-remove_links(Path) ->
- case ec_file:is_dir(Path) of
- false -> ok;
- true -> remove_links1(Path)
- end.
-remove_links1(Path) ->
+remove_links(Path) ->
+ IsDir = ec_file:is_dir(Path),
case ec_file:is_symlink(Path) of
- true ->
- file:delete(Path);
- false ->
- lists:foreach(fun(ChildPath) ->
- remove_links(ChildPath)
- end, sub_dirs(Path))
+ true when IsDir ->
+ delete_dir_link(Path);
+ false when IsDir ->
+ lists:foreach(fun(ChildPath) ->
+ remove_links(ChildPath)
+ end, dir_entries(Path));
+ _ -> file:delete(Path)
end.
-sub_dirs(Path) ->
+delete_dir_link(Path) ->
+ case os:type() of
+ {unix, _} -> file:delete(Path);
+ {win32, _} -> file:del_dir(Path)
+ end.
+
+dir_entries(Path) ->
{ok, SubDirs} = file:list_dir(Path),
[filename:join(Path, SubDir) || SubDir <- SubDirs].
diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl
index 6eb8a4f..25d5193 100644
--- a/src/rebar_prv_compile.erl
+++ b/src/rebar_prv_compile.erl
@@ -126,7 +126,20 @@ copy_app_dirs(State, OldAppDir, AppDir) ->
false ->
ok
end,
+
filelib:ensure_dir(filename:join(AppDir, "dummy")),
+
+ %% link or copy mibs if it exists
+ case filelib:is_dir(filename:join(OldAppDir, "mibs")) of
+ true ->
+ %% If mibs exist it means we must ensure priv exists.
+ %% mibs files are compiled to priv/mibs/
+ filelib:ensure_dir(filename:join([OldAppDir, "priv", "dummy"])),
+ symlink_or_copy(OldAppDir, AppDir, "mibs");
+ false ->
+ ok
+ end,
+
%% link to src_dirs to be adjacent to ebin is needed for R15 use of cover/xref
SrcDirs = rebar_dir:all_src_dirs(State, ["src"], ["test"]),
[symlink_or_copy(OldAppDir, AppDir, Dir) || Dir <- ["priv", "include"] ++ SrcDirs];
diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl
index 6c115b6..8c26521 100644
--- a/src/rebar_prv_cover.erl
+++ b/src/rebar_prv_cover.erl
@@ -337,16 +337,24 @@ write_coverdata(State, Task) ->
?WARN("Cover data export failed: ~p", [Reason])
end.
-verbose(State) ->
+command_line_opts(State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
- case proplists:get_value(verbose, Opts, missing) of
- missing -> rebar_state:get(State, cover_print_enabled, false);
- Else -> Else
+ Opts.
+
+config_opts(State) ->
+ rebar_state:get(State, cover_opts, []).
+
+verbose(State) ->
+ Command = proplists:get_value(verbose, command_line_opts(State), undefined),
+ Config = proplists:get_value(verbose, config_opts(State), undefined),
+ case {Command, Config} of
+ {undefined, undefined} -> false;
+ {undefined, Verbose} -> Verbose;
+ {Verbose, _} -> Verbose
end.
cover_dir(State) ->
- rebar_state:get(State, cover_data_dir, filename:join([rebar_dir:base_dir(State),
- "cover"])).
+ filename:join([rebar_dir:base_dir(State), "cover"]).
cover_opts(_State) ->
[{reset, $r, "reset", boolean, help(reset)},
diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl
index 15f1dac..1cf7b71 100644
--- a/src/rebar_prv_dialyzer.erl
+++ b/src/rebar_prv_dialyzer.erl
@@ -72,6 +72,7 @@ short_desc() ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
+ maybe_fix_env(),
?INFO("Dialyzer starting, this may take a while...", []),
code:add_pathsa(rebar_state:code_paths(State, all_deps)),
Plt = get_plt(State),
@@ -91,6 +92,13 @@ do(State) ->
rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default))
end.
+%% This is used to workaround dialyzer quirk discussed here
+%% https://github.com/rebar/rebar3/pull/489#issuecomment-107953541
+%% Dialyzer gets default plt location wrong way by peeking HOME environment
+%% variable which usually is not defined on Windows.
+maybe_fix_env() ->
+ os:putenv("DIALYZER_PLT", filename:join(rebar_dir:home_dir(), ".dialyzer_plt")).
+
-spec format_error(any()) -> iolist().
format_error({error_processing_apps, Error}) ->
io_lib:format("Error in dialyzing apps: ~s", [Error]);
@@ -380,7 +388,7 @@ run_dialyzer(State, Opts, Output) ->
{check_plt, false} |
Opts],
?DEBUG("Running dialyzer with options: ~p~n", [Opts2]),
- _ = dialyzer:run(Opts2),
+ dialyzer:run(Opts2),
{0, State}
end.
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 768d41a..105bbb1 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -35,10 +35,7 @@
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
--export([handle_deps/3,
- handle_deps/4,
- handle_deps/5,
-
+-export([handle_deps_as_profile/4,
find_cycles/1,
cull_compile/2]).
@@ -76,8 +73,8 @@ do(State) ->
Profiles = rebar_state:current_profiles(State),
ProjectApps = rebar_state:project_apps(State),
- {Apps, State1} =
- lists:foldl(fun deps_per_profile/2, {[], State}, lists:reverse(Profiles)),
+ Upgrade = rebar_state:get(State, upgrade, false),
+ {Apps, State1} = deps_per_profile(Profiles, Upgrade, State),
State2 = rebar_state:update_all_deps(State1, Apps),
CodePaths = [rebar_app_info:ebin_dir(A) || A <- Apps],
@@ -119,63 +116,77 @@ format_error({cycles, Cycles}) ->
format_error(Reason) ->
io_lib:format("~p", [Reason]).
--spec handle_deps(atom(), rebar_state:t(), list()) ->
- {ok, [rebar_app_info:t()], rebar_state:t()} | {error, string()}.
-handle_deps(Profile, State, Deps) ->
- handle_deps(Profile, State, Deps, false, []).
-
--spec handle_deps(atom(), rebar_state:t(), list(), list() | boolean()) ->
- {ok, [rebar_app_info:t()], rebar_state:t()} | {error, string()}.
-handle_deps(Profile, State, Deps, Upgrade) when is_boolean(Upgrade) ->
- handle_deps(Profile, State, Deps, Upgrade, []);
-handle_deps(Profile, State, Deps, Locks) when is_list(Locks) ->
- Upgrade = rebar_state:get(State, upgrade, false),
- handle_deps(Profile, State, Deps, Upgrade, Locks).
-
--spec handle_deps(atom(), rebar_state:t(), list(), boolean() | {true, binary(), integer()}, list())
- -> {ok, [rebar_app_info:t()], rebar_state:t()} | {error, string()}.
-handle_deps(_Profile, State, [], _, _) ->
- {ok, [], State};
-handle_deps(Profile, State0, Deps, Upgrade, Locks) ->
- %% Split source deps from pkg deps, needed to keep backwards compatibility
- DepsDir = profile_dep_dir(State0, Profile),
-
- {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State0, Locks, 0),
-
- %% Fetch transitive src deps
- {State1, SrcApps, PkgDeps1, Seen} = update_src_deps(Profile, 0, SrcDeps, PkgDeps, []
- ,State0, Upgrade, sets:new(), Locks),
-
- {Solved, State4} =
- case PkgDeps1 of
- [] ->
- {[], State1};
- _ ->
- %% Read in package index and dep graph
- {Packages, Graph} = rebar_state:packages(State1),
- Registry = rebar_packages:registry(State1),
- State2 = rebar_state:packages(rebar_state:registry(State1, Registry)
- ,{Packages, Graph}),
-
- update_pkg_deps(Profile, Packages, PkgDeps1
- ,Graph, Upgrade, Seen, State2, Locks)
- end,
-
- AllDeps = lists:ukeymerge(2
- ,lists:ukeysort(2, SrcApps)
- ,lists:ukeysort(2, Solved)),
-
- {ok, AllDeps, State4}.
+%% Allows other providers to install deps in a given profile
+%% manually, outside of what is provided by rebar3's deps tuple.
+handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
+ Locks = [],
+ Level = 0,
+ DepsDir = profile_dep_dir(State, Profile),
+
+ {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State, Locks, Level),
+ AllSrcProfileDeps = [{Profile, SrcDeps, Locks, Level}],
+ AllPkgProfileDeps = [{Profile, Locks, PkgDeps}],
+ {AllApps, PkgDeps1, Seen, State1} = handle_profile_level(AllSrcProfileDeps, AllPkgProfileDeps, Locks, sets:new(), Upgrade, State),
+
+ handle_profile_pkg_level(PkgDeps1, AllApps, Seen, Upgrade, State1).
+
%% ===================================================================
%% Internal functions
%% ===================================================================
-deps_per_profile(Profile, {Apps, State}) ->
+%% finds all the deps in `{deps, ...}` for each profile provided.
+deps_per_profile(Profiles, Upgrade, State) ->
+ Level = 0,
+ {AllProfileDeps, PkgDeps} = lists:foldl(fun(Profile, {SrcAcc, PkgAcc}) ->
+ {Src, Pkg} = parse_profile_deps(State, Profile, Level),
+ {[Src | SrcAcc], [Pkg | PkgAcc]}
+ end, {[], []}, Profiles),
+ {AllApps, PkgDeps1, Seen, State1} = handle_profile_level(AllProfileDeps, PkgDeps, [], sets:new(), Upgrade, State),
+
+ handle_profile_pkg_level(PkgDeps1, AllApps, Seen, Upgrade, State1).
+
+parse_profile_deps(State, Profile, Level) ->
+ DepsDir = profile_dep_dir(State, Profile),
Locks = rebar_state:get(State, {locks, Profile}, []),
- ProfileDeps = rebar_state:get(State, {deps, Profile}, []),
- {ok, NewApps, NewState} = handle_deps(Profile, State, ProfileDeps, Locks),
- {NewApps++Apps, NewState}.
+ Deps = rebar_state:get(State, {deps, Profile}, []),
+ {SrcDeps, PkgDeps} = parse_deps(DepsDir, Deps, State, Locks, Level),
+ {{Profile, SrcDeps, Locks, Level}, {Profile, Locks, PkgDeps}}.
+
+%% Level-order traversal of all dependencies, across profiles.
+%% If profiles x,y,z are present, then the traversal will go:
+%% x0, y0, z0, x1, y1, z1, ..., xN, yN, zN.
+handle_profile_level([], PkgDeps, SrcApps, Seen, _Upgrade, State) ->
+ {SrcApps, PkgDeps, Seen, State};
+handle_profile_level([{Profile, SrcDeps, Locks, Level} | Rest], PkgDeps, SrcApps, Seen, Upgrade, State) ->
+ {SrcDeps1, PkgDeps1, SrcApps1, State1, Seen1, Locks1} =
+ update_src_deps(Profile, Level, SrcDeps, [], SrcApps
+ ,State, Upgrade, Seen, Locks),
+ SrcDeps2 = case SrcDeps1 of
+ [] -> Rest;
+ _ -> Rest ++ [{Profile, SrcDeps1, Locks1, Level+1}]
+ end,
+ handle_profile_level(SrcDeps2, [{Profile, Locks1, PkgDeps1} | PkgDeps], SrcApps1++SrcApps, sets:union(Seen, Seen1), Upgrade, State1).
+
+handle_profile_pkg_level(PkgDeps, AllApps, Seen, Upgrade, State) ->
+ %% Read in package index and dep graph
+ {Packages, Graph} = rebar_state:packages(State),
+ Registry = rebar_packages:registry(State),
+ State1 = rebar_state:packages(rebar_state:registry(State, Registry)
+ ,{Packages, Graph}),
+
+ lists:foldl(fun({_Profile, _, []}, {AllAcc, StateAcc}) ->
+ {AllAcc, StateAcc};
+ ({Profile1, Locks, PkgDeps2}, {AllAcc, StateAcc}) ->
+ {Solved, StateAcc2} = update_pkg_deps(Profile1, Packages, PkgDeps2
+ ,Graph, Upgrade, Seen, StateAcc, Locks),
+
+ AllDeps = lists:ukeymerge(2
+ ,lists:ukeysort(2, AllAcc)
+ ,lists:ukeysort(2, Solved)),
+
+ {AllDeps, StateAcc2}
+ end, {AllApps, State1}, PkgDeps).
find_cycles(Apps) ->
case rebar_digraph:compile_order(Apps) of
@@ -279,19 +290,15 @@ package_to_app(DepsDir, Packages, {Name, Vsn, Level}, IsLock, State) ->
-spec update_src_deps(atom(), non_neg_integer(), list(), list(), list(), rebar_state:t(), boolean(), sets:set(binary()), list()) -> {rebar_state:t(), list(), list(), sets:set(binary())}.
update_src_deps(Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, Locks) ->
- case lists:foldl(
- fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc}) ->
- update_src_dep(AppInfo, Profile, Level,
- SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc,
- Upgrade, SeenAcc, Locks, LocksAcc)
- end,
- {[], PkgDeps, SrcApps, State, Seen, Locks},
- rebar_utils:sort_deps(SrcDeps)) of
- {[], NewPkgDeps, NewSrcApps, State1, Seen1, _NewLocks} ->
- {State1, NewSrcApps, NewPkgDeps, Seen1};
- {NewSrcDeps, NewPkgDeps, NewSrcApps, State1, Seen1, NewLocks} ->
- update_src_deps(Profile, Level+1, NewSrcDeps, NewPkgDeps, NewSrcApps, State1, Upgrade, Seen1, NewLocks)
- end.
+ lists:foldl(
+ fun(AppInfo, {SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc, SeenAcc, LocksAcc}) ->
+ update_src_dep(AppInfo, Profile, Level,
+ SrcDepsAcc, PkgDepsAcc, SrcAppsAcc, StateAcc,
+ Upgrade, SeenAcc, Locks, LocksAcc)
+ end,
+ {[], PkgDeps, SrcApps, State, Seen, Locks},
+ rebar_utils:sort_deps(SrcDeps)).
+
update_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) ->
%% If not seen, add to list of locks to write out
@@ -314,7 +321,7 @@ profile_dep_dir(State, Profile) ->
_ -> rebar_dir:deps_dir(State)
end.
-update_seen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) ->
+update_seen_src_dep(AppInfo, _Profile, _Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, BaseLocks, Locks) ->
Name = rebar_app_info:name(AppInfo),
%% If seen from lock file or user requested an upgrade
%% don't print warning about skipping
@@ -323,44 +330,32 @@ update_seen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, U
false when not Upgrade -> warn_skip_deps(AppInfo, State);
true -> ok
end,
- %% scan for app children here if upgrading
- case Upgrade of
- false ->
- {SrcDeps, PkgDeps, SrcApps, State, Seen, Locks};
- true ->
- {NewSrcDeps, NewPkgDeps, NewSrcApps, NewState, NewLocks}
- = handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps,
- Level, State, Locks),
- {NewSrcDeps, NewPkgDeps, NewSrcApps, NewState, Seen, NewLocks}
- end.
+ {SrcDeps, PkgDeps, SrcApps, State, Seen, Locks}.
update_unseen_src_dep(AppInfo, Profile, Level, SrcDeps, PkgDeps, SrcApps, State, Upgrade, Seen, Locks) ->
{NewSeen, State1} = maybe_lock(Profile, AppInfo, Seen, State, Level),
{NewSrcDeps, NewPkgDeps, NewSrcApps, State2, NewLocks}
= case Upgrade of
- true ->
- handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps,
- Level, State1, Locks);
- _ ->
- {_, AppInfo1} = maybe_fetch(AppInfo, Profile, false, Seen, State1),
- handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps,
- Level, State1, Locks)
- end,
+ true ->
+ handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps,
+ Level, State1, Seen, Locks);
+ _ ->
+ {_, AppInfo1} = maybe_fetch(AppInfo, Profile, false, Seen, State1),
+ handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps,
+ Level, State1, Locks)
+ end,
{NewSrcDeps, NewPkgDeps, NewSrcApps, State2, NewSeen, NewLocks}.
-handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
+handle_upgrade(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Seen, Locks) ->
Name = rebar_app_info:name(AppInfo),
case lists:keyfind(Name, 1, Locks) of
false ->
- case maybe_fetch(AppInfo, Profile, true, sets:new(), State) of
- {true, AppInfo1} ->
- handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps,
- Level, State, Locks);
- {false, AppInfo1} ->
- {[AppInfo1|SrcDeps], PkgDeps, SrcApps, State, Locks}
- end;
+ {_, AppInfo1} = maybe_fetch(AppInfo, Profile, true, Seen, State),
+ handle_dep(AppInfo1, Profile, SrcDeps, PkgDeps, SrcApps,
+ Level, State, Locks);
_StillLocked ->
- {[AppInfo|SrcDeps], PkgDeps, SrcApps, State, Locks}
+ handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps,
+ Level, State, Locks)
end.
handle_dep(AppInfo, Profile, SrcDeps, PkgDeps, SrcApps, Level, State, Locks) ->
@@ -414,41 +409,27 @@ maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) ->
false ->
case rebar_app_discover:find_app(AppDir, all) of
false ->
- case already_in_default(AppInfo, State) of
- false ->
- case fetch_app(AppInfo, AppDir, State) of
- true ->
- maybe_symlink_default(State, Profile, AppDir, AppInfo),
- {true, update_app_info(AppDir, AppInfo)};
- Other ->
- {Other, AppInfo}
- end;
- {true, FoundApp} ->
- %% Preserve the state we created with overrides
- AppState = rebar_app_info:state(AppInfo),
- FoundApp1 = rebar_app_info:state(FoundApp, AppState),
- symlink_dep(rebar_app_info:dir(FoundApp1), AppDir),
- {true, FoundApp1}
+ case fetch_app(AppInfo, AppDir, State) of
+ true ->
+ maybe_symlink_default(State, Profile, AppDir, AppInfo),
+ {true, update_app_info(AppDir, AppInfo)};
+ Other ->
+ {Other, AppInfo}
end;
{true, AppInfo1} ->
%% Preserve the state we created with overrides
AppState = rebar_app_info:state(AppInfo),
AppInfo2 = rebar_app_info:state(AppInfo1, AppState),
- maybe_symlink_default(State, Profile, AppDir, AppInfo2),
case sets:is_element(rebar_app_info:name(AppInfo), Seen) of
true ->
{false, AppInfo2};
false ->
+ maybe_symlink_default(State, Profile, AppDir, AppInfo2),
{maybe_upgrade(AppInfo, AppDir, Upgrade, State), AppInfo2}
end
end
end.
-already_in_default(AppInfo, State) ->
- Name = ec_cnv:to_list(rebar_app_info:name(AppInfo)),
- DefaultAppDir = filename:join([rebar_state:get(State, base_dir, []), "default", "lib", Name]),
- rebar_app_discover:find_app(DefaultAppDir, all).
-
needs_symlinking(State, Profile) ->
case {rebar_state:current_profiles(State), Profile} of
{[default], default} ->
@@ -504,6 +485,7 @@ parse_deps(DepsDir, Deps, State, Locks, Level) ->
end, {[], []}, Deps).
parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_list(Vsn) ->
+ %% Versioned Package dependency
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
{ok, _App} ->
@@ -514,6 +496,7 @@ parse_dep({Name, Vsn}, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is
,ec_cnv:to_binary(Vsn)) | PkgDepsAcc]}
end;
parse_dep(Name, {SrcDepsAcc, PkgDepsAcc}, DepsDir, IsLock, State) when is_atom(Name) ->
+ %% Unversioned package dependency
{PkgName, PkgVsn} = get_package(ec_cnv:to_binary(Name), State),
CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
case rebar_app_info:discover(CheckoutsDir) of
diff --git a/src/rebar_prv_plugins_upgrade.erl b/src/rebar_prv_plugins_upgrade.erl
index 5ccd054..02c185f 100644
--- a/src/rebar_prv_plugins_upgrade.erl
+++ b/src/rebar_prv_plugins_upgrade.erl
@@ -62,10 +62,7 @@ upgrade(Plugin, State) ->
?PRV_ERROR({not_found, Plugin});
{ok, P, Profile} ->
State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
- {ok, Apps, _State2} = rebar_prv_install_deps:handle_deps(Profile
- ,State1
- ,[P]
- ,true),
+ {Apps, _State2} = rebar_prv_install_deps:handle_deps_as_profile(Profile, State1, [P], true),
{no_cycle, Sorted} = rebar_prv_install_deps:find_cycles(Apps),
ToBuild = rebar_prv_install_deps:cull_compile(Sorted, []),
diff --git a/src/rebar_prv_release.erl b/src/rebar_prv_release.erl
index dc58047..2cf9b23 100644
--- a/src/rebar_prv_release.erl
+++ b/src/rebar_prv_release.erl
@@ -32,34 +32,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- Options = rebar_state:command_args(State),
- DepsDir = rebar_dir:deps_dir(State),
- ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS),
- LibDirs = rebar_utils:filtermap(fun ec_file:exists/1,
- [?DEFAULT_CHECKOUTS_DIR, DepsDir | ProjectAppDirs]),
- OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR),
- AllOptions = string:join(["release" | Options], " "),
- Cwd = rebar_state:dir(State),
- Providers = rebar_state:providers(State),
- rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
- try
- case rebar_state:get(State, relx, []) of
- [] ->
- relx:main([{lib_dirs, LibDirs}
- ,{output_dir, OutputDir}
- ,{caller, api}], AllOptions);
- Config ->
- relx:main([{lib_dirs, LibDirs}
- ,{config, lists:reverse(Config)}
- ,{output_dir, OutputDir}
- ,{caller, api}], AllOptions)
- end,
- rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
- {ok, State}
- catch
- throw:T ->
- {error, {rlx_prv_release, T}}
- end.
+ rebar_relx:do(rlx_prv_release, "release", ?PROVIDER, State).
-spec format_error(any()) -> iolist().
format_error(Reason) ->
diff --git a/src/rebar_prv_relup.erl b/src/rebar_prv_relup.erl
index aed12a6..a4cd8ae 100644
--- a/src/rebar_prv_relup.erl
+++ b/src/rebar_prv_relup.erl
@@ -33,34 +33,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- Options = rebar_state:command_args(State),
- DepsDir = rebar_dir:deps_dir(State),
- ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS),
- LibDirs = rebar_utils:filtermap(fun ec_file:exists/1,
- [?DEFAULT_CHECKOUTS_DIR, DepsDir | ProjectAppDirs]),
- OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR),
- AllOptions = string:join(["relup" | Options], " "),
- Cwd = rebar_state:dir(State),
- Providers = rebar_state:providers(State),
- rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
- try
- case rebar_state:get(State, relx, []) of
- [] ->
- relx:main([{lib_dirs, LibDirs}
- ,{output_dir, OutputDir}
- ,{caller, api}], AllOptions);
- Config ->
- relx:main([{lib_dirs, LibDirs}
- ,{config, lists:reverse(Config)}
- ,{output_dir, OutputDir}
- ,{caller, api}], AllOptions)
- end,
- rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
- {ok, State}
- catch
- throw:T ->
- {error, {rlx_prv_release, T}}
- end.
+ rebar_relx:do(rlx_prv_release, "relup", ?PROVIDER, State).
-spec format_error(any()) -> iolist().
format_error(Reason) ->
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index 84ad723..3c6369a 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -90,9 +90,10 @@ shell(State) ->
%% their application masters never gets the new group leader (held in
%% their internal state)
maybe_boot_apps(State),
- rebar_agent:start_link(State),
- %% this call never returns (until user quits shell)
- timer:sleep(infinity).
+ simulate_proc_lib(),
+ true = register(rebar_agent, self()),
+ {ok, GenState} = rebar_agent:init(State),
+ gen_server:enter_loop(rebar_agent, [], GenState, {local, rebar_agent}, hibernate).
info() ->
"Start a shell with project and deps preloaded similar to~n'erl -pa ebin -pa deps/*/ebin'.~n".
@@ -145,6 +146,11 @@ maybe_boot_apps(State) ->
boot_apps(Apps)
end.
+simulate_proc_lib() ->
+ FakeParent = spawn_link(fun() -> timer:sleep(infinity) end),
+ put('$ancestors', [FakeParent]),
+ put('$initial_call', {rebar_agent, init, 1}).
+
setup_name(State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
case {proplists:get_value(name, Opts), proplists:get_value(sname, Opts)} of
diff --git a/src/rebar_prv_tar.erl b/src/rebar_prv_tar.erl
index 17d7b0b..b3a12c0 100644
--- a/src/rebar_prv_tar.erl
+++ b/src/rebar_prv_tar.erl
@@ -32,29 +32,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- Options = rebar_state:command_args(State),
- DepsDir = rebar_dir:deps_dir(State),
- ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS),
- LibDirs = rebar_utils:filtermap(fun ec_file:exists/1,
- [?DEFAULT_CHECKOUTS_DIR, DepsDir | ProjectAppDirs]),
- OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR),
- AllOptions = string:join(["tar" | Options], " "),
- Cwd = rebar_state:dir(State),
- Providers = rebar_state:providers(State),
- rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, State),
- case rebar_state:get(State, relx, []) of
- [] ->
- relx:main([{lib_dirs, LibDirs}
- ,{output_dir, OutputDir}
- ,{caller, api}], AllOptions);
- Config ->
- relx:main([{lib_dirs, LibDirs}
- ,{config, lists:reverse(Config)}
- ,{output_dir, OutputDir}
- ,{caller, api}], AllOptions)
- end,
- rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, State),
- {ok, State}.
+ rebar_relx:do(rlx_prv_release, "tar", ?PROVIDER, State).
-spec format_error(any()) -> iolist().
format_error(Reason) ->
diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl
index 6838bab..64fe65e 100644
--- a/src/rebar_prv_update.erl
+++ b/src/rebar_prv_update.erl
@@ -43,7 +43,8 @@ do(State) ->
Url = rebar_state:get(State, rebar_packages_cdn, "https://s3.amazonaws.com/s3.hex.pm/registry.ets.gz"),
{ok, _RequestId} = httpc:request(get, {Url, []},
- [], [{stream, TmpFile}, {sync, true}]),
+ [], [{stream, TmpFile}, {sync, true}],
+ rebar),
{ok, Data} = file:read_file(TmpFile),
Unzipped = zlib:gunzip(Data),
ok = file:write_file(HexFile, Unzipped),
diff --git a/src/rebar_relx.erl b/src/rebar_relx.erl
new file mode 100644
index 0000000..a3adedd
--- /dev/null
+++ b/src/rebar_relx.erl
@@ -0,0 +1,69 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+
+-module(rebar_relx).
+
+-export([do/4,
+ format_error/1]).
+
+-include("rebar.hrl").
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+
+-spec do(atom(), string(), atom(), rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+do(Module, Command, Provider, State) ->
+ Options = rebar_state:command_args(State),
+ DepsDir = rebar_dir:deps_dir(State),
+ ProjectAppDirs = lists:delete(".", ?DEFAULT_PROJECT_APP_DIRS),
+ LibDirs = rebar_utils:filtermap(fun ec_file:exists/1,
+ [?DEFAULT_CHECKOUTS_DIR, DepsDir | ProjectAppDirs]),
+ OutputDir = filename:join(rebar_dir:base_dir(State), ?DEFAULT_RELEASE_DIR),
+ AllOptions = string:join([Command | Options], " "),
+ Cwd = rebar_state:dir(State),
+ Providers = rebar_state:providers(State),
+ rebar_hooks:run_all_hooks(Cwd, pre, Provider, Providers, State),
+ try
+ case rebar_state:get(State, relx, []) of
+ [] ->
+ relx:main([{lib_dirs, LibDirs}
+ ,{output_dir, OutputDir}
+ ,{caller, api}], AllOptions);
+ Config ->
+ Config1 = update_config(Config),
+ relx:main([{lib_dirs, LibDirs}
+ ,{config, Config1}
+ ,{output_dir, OutputDir}
+ ,{caller, api}], AllOptions)
+ end,
+ rebar_hooks:run_all_hooks(Cwd, post, Provider, Providers, State),
+ {ok, State}
+ catch
+ throw:T ->
+ {error, {Module, T}}
+ end.
+
+-spec format_error(any()) -> iolist().
+format_error(Reason) ->
+ io_lib:format("~p", [Reason]).
+
+%% To handle profiles rebar3 expects the provider to use the first entry
+%% in a configuration key-value list as the value of a key if dups exist.
+%% This does not work with relx. Some config options must not lose their
+%% order (release which has an extends option is one). So here we pull out
+%% options that are special so we can reverse the rest so what we expect
+%% from a rebar3 profile is what we get on the relx side.
+-define(SPECIAL_KEYS, [release, vm_args, sys_config, overlay_vars, lib_dirs]).
+
+update_config(Config) ->
+ {Special, Other} =
+ lists:foldl(fun(Tuple, {SpecialAcc, OtherAcc}) when is_tuple(Tuple) ->
+ case lists:member(element(1, Tuple), ?SPECIAL_KEYS) of
+ true ->
+ {[Tuple | SpecialAcc], OtherAcc};
+ false ->
+ {SpecialAcc, [Tuple | OtherAcc]}
+ end
+ end, {[], []}, Config),
+ lists:reverse(Special) ++ Other.
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index cc59ed0..ebdf0fe 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -56,7 +56,8 @@
wordsize/0,
tup_umerge/2,
tup_sort/1,
- line_count/1]).
+ line_count/1,
+ set_httpc_options/0]).
%% for internal use only
-export([otp_release/0]).
@@ -127,11 +128,13 @@ sh_send(Command0, String, Options0) ->
PortSettings = proplists:get_all_values(port_settings, Options) ++
[exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
Port = open_port({spawn, Command}, PortSettings),
-
- %% allow us to send some data to the shell command's STDIN
- %% Erlang doesn't let us get any reply after sending an EOF, though...
- Port ! {self(), {command, String}},
- port_close(Port).
+ try
+ %% allow us to send some data to the shell command's STDIN
+ %% Erlang doesn't let us get any reply after sending an EOF, though...
+ Port ! {self(), {command, String}}
+ after
+ port_close(Port)
+ end.
%%
%% Options = [Option] -- defaults to [use_stdout, abort_on_error]
@@ -154,15 +157,19 @@ sh(Command0, Options0) ->
Command = lists:flatten(patch_on_windows(Command0, proplists:get_value(env, Options, []))),
PortSettings = proplists:get_all_values(port_settings, Options) ++
- [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
+ [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide, eof],
?DEBUG("Port Cmd: ~s\nPort Opts: ~p\n", [Command, PortSettings]),
Port = open_port({spawn, Command}, PortSettings),
- case sh_loop(Port, OutputHandler, []) of
- {ok, _Output} = Ok ->
- Ok;
- {error, {_Rc, _Output}=Err} ->
- ErrorHandler(Command, Err)
+ try
+ case sh_loop(Port, OutputHandler, []) of
+ {ok, _Output} = Ok ->
+ Ok;
+ {error, {_Rc, _Output}=Err} ->
+ ErrorHandler(Command, Err)
+ end
+ after
+ port_close(Port)
end.
find_files(Dir, Regex) ->
@@ -435,10 +442,14 @@ sh_loop(Port, Fun, Acc) ->
sh_loop(Port, Fun, Fun(Line ++ "\n", Acc));
{Port, {data, {noeol, Line}}} ->
sh_loop(Port, Fun, Fun(Line, Acc));
- {Port, {exit_status, 0}} ->
- {ok, lists:flatten(lists:reverse(Acc))};
- {Port, {exit_status, Rc}} ->
- {error, {Rc, lists:flatten(lists:reverse(Acc))}}
+ {Port, eof} ->
+ Data = lists:flatten(lists:reverse(Acc)),
+ receive
+ {Port, {exit_status, 0}} ->
+ {ok, Data};
+ {Port, {exit_status, Rc}} ->
+ {error, {Rc, Data}}
+ end
end.
beam_to_mod(Dir, Filename) ->
@@ -657,3 +668,19 @@ maybe_ends_in_comma(H) ->
"," ++ Flag -> lists:reverse(Flag);
_ -> false
end.
+
+get_http_vars(Scheme) ->
+ GlobalConfigFile = rebar_dir:global_config(),
+ Config = rebar_config:consult_file(GlobalConfigFile),
+ proplists:get_value(Scheme, Config, []).
+
+set_httpc_options() ->
+ set_httpc_options(https_proxy, get_http_vars(https_proxy)),
+ set_httpc_options(proxy, get_http_vars(http_proxy)).
+
+set_httpc_options(_, []) ->
+ ok;
+
+set_httpc_options(Scheme, Proxy) ->
+ {ok, {_, _, Host, Port, _, _}} = http_uri:parse(Proxy),
+ httpc:set_options([{Scheme, {{Host, Port}, []}}], rebar).
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 8ee8af4..3f95e4f 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -20,7 +20,8 @@
checkout_priority/1,
highest_version_of_pkg_dep/1,
parse_transform_test/1,
- erl_first_files_test/1]).
+ erl_first_files_test/1,
+ mib_test/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -48,7 +49,7 @@ all() ->
recompile_when_opts_change, dont_recompile_when_opts_dont_change,
dont_recompile_yrl_or_xrl, delete_beam_if_source_deleted,
deps_in_path, checkout_priority, highest_version_of_pkg_dep,
- parse_transform_test, erl_first_files_test].
+ parse_transform_test, erl_first_files_test, mib_test].
build_basic_app(Config) ->
AppDir = ?config(apps, Config),
@@ -163,9 +164,10 @@ recompile_when_hrl_changes(Config) ->
ModTime = [filelib:last_modified(filename:join([EbinDir, F]))
|| F <- Files, filename:extension(F) == ".beam"],
+
timer:sleep(1000),
- os:cmd("touch " ++ HeaderFile),
+ rebar_file_utils:touch(HeaderFile),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
@@ -274,9 +276,9 @@ delete_beam_if_source_deleted(Config) ->
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
- SrcDir = filename:join([AppDir, "_build", "default", "lib", Name, "src"]),
+ _SrcDir = filename:join([AppDir, "_build", "default", "lib", Name, "src"]),
?assert(filelib:is_regular(filename:join(EbinDir, "not_a_real_src_" ++ Name ++ ".beam"))),
- file:delete(filename:join(SrcDir, "not_a_real_src_" ++ Name ++ ".erl")),
+ file:delete(filename:join([AppDir, "src", "not_a_real_src_" ++ Name ++ ".erl"])),
rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, [{app, Name}]}),
@@ -307,6 +309,7 @@ deps_in_path(Config) ->
?assertEqual([], [Path || Path <- code:get_path(),
{match, _} <- [re:run(Path, DepName)]]),
%% Hope not to find pkg name in there
+
?assertEqual([], [Path || Path <- code:get_path(),
{match, _} <- [re:run(Path, PkgName)]]),
%% Build things
@@ -483,3 +486,48 @@ erl_first_files_test(Config) ->
D = proplists:get_value(number, d:module_info(attributes)),
E = proplists:get_value(number, e:module_info(attributes)),
?assertEqual([B,D,A,E], lists:sort([A,B,D,E])).
+
+mib_test(Config) ->
+ AppDir = ?config(apps, Config),
+
+ RebarConfig = [],
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ MibsSrc = <<"-- SIMPLE-MIB.\n"
+"-- This is just a simple MIB used for testing!\n"
+"--\n"
+"SIMPLE-MIB DEFINITIONS ::= BEGIN\n"
+"IMPORTS\n"
+" MODULE-IDENTITY, enterprises\n"
+" FROM SNMPv2-SMI;\n"
+"\n"
+"ericsson MODULE-IDENTITY\n"
+" LAST-UPDATED\n"
+" \"201403060000Z\"\n"
+" ORGANIZATION\n"
+" \"rebar\"\n"
+" CONTACT-INFO\n"
+" \"rebar <rebar@example.com>\n"
+" or\n"
+" whoever is currently responsible for the SIMPLE\n"
+" enterprise MIB tree branch (enterprises.999).\"\n"
+" DESCRIPTION\n"
+" \"This very small module is made available\n"
+" for mib-compilation testing.\"\n"
+" ::= { enterprises 999 }\n"
+"END\n">>,
+
+ ok = filelib:ensure_dir(filename:join([AppDir, "mibs", "dummy"])),
+ ok = file:write_file(filename:join([AppDir, "mibs", "SIMPLE-MIB.mib"]), MibsSrc),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ %% check a beam corresponding to the src in the extra src_dir exists in ebin
+ PrivMibsDir = filename:join([AppDir, "_build", "default", "lib", Name, "priv", "mibs"]),
+ true = filelib:is_file(filename:join([PrivMibsDir, "SIMPLE-MIB.bin"])),
+
+ %% check the extra src_dir was linked into the _build dir
+ true = filelib:is_dir(filename:join([AppDir, "_build", "default", "lib", Name, "mibs"])).
diff --git a/test/rebar_cover_SUITE.erl b/test/rebar_cover_SUITE.erl
index 0bead99..1fae92c 100644
--- a/test/rebar_cover_SUITE.erl
+++ b/test/rebar_cover_SUITE.erl
@@ -8,7 +8,6 @@
flag_coverdata_written/1,
config_coverdata_written/1,
index_written/1,
- config_alt_coverdir/1,
flag_verbose/1,
config_verbose/1]).
@@ -31,7 +30,6 @@ init_per_testcase(_, Config) ->
all() ->
[flag_coverdata_written, config_coverdata_written,
index_written,
- config_alt_coverdir,
flag_verbose, config_verbose].
flag_coverdata_written(Config) ->
@@ -79,23 +77,6 @@ index_written(Config) ->
true = filelib:is_file(filename:join([AppDir, "_build", "test", "cover", "index.html"])).
-config_alt_coverdir(Config) ->
- AppDir = ?config(apps, Config),
-
- Name = rebar_test_utils:create_random_name("cover_"),
- Vsn = rebar_test_utils:create_random_vsn(),
- rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
-
- CoverDir = filename:join(["coverage", "goes", "here"]),
-
- RebarConfig = [{erl_opts, [{d, some_define}]}, {cover_data_dir, CoverDir}],
- rebar_test_utils:run_and_check(Config,
- RebarConfig,
- ["do", "eunit", "--cover", ",", "cover"],
- {ok, [{app, Name}]}),
-
- true = filelib:is_file(filename:join([CoverDir, "index.html"])).
-
flag_verbose(Config) ->
AppDir = ?config(apps, Config),
@@ -118,7 +99,7 @@ config_verbose(Config) ->
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_eunit_app(AppDir, Name, Vsn, [kernel, stdlib]),
- RebarConfig = [{erl_opts, [{d, some_define}]}, {cover_print_enabled, true}],
+ RebarConfig = [{erl_opts, [{d, some_define}]}, {cover_opts, [verbose]}],
rebar_test_utils:run_and_check(Config,
RebarConfig,
["do", "eunit", "--cover", ",", "cover"],
diff --git a/test/rebar_deps_SUITE.erl b/test/rebar_deps_SUITE.erl
index afd487e..73c4980 100644
--- a/test/rebar_deps_SUITE.erl
+++ b/test/rebar_deps_SUITE.erl
@@ -3,7 +3,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-all() -> [sub_app_deps, newly_added_dep, {group, git}, {group, pkg}].
+all() -> [sub_app_deps, newly_added_dep, http_proxy_settings, https_proxy_settings, {group, git}, {group, pkg}].
groups() ->
[{all, [], [flat, pick_highest_left, pick_highest_right,
@@ -33,6 +33,47 @@ init_per_testcase(newly_added_dep, Config) ->
rebar_test_utils:init_rebar_state(Config);
init_per_testcase(sub_app_deps, Config) ->
rebar_test_utils:init_rebar_state(Config);
+init_per_testcase(http_proxy_settings, Config) ->
+ %% Create private rebar.config
+ Priv = ?config(priv_dir, Config),
+ GlobalDir = filename:join(Priv, "global"),
+ GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
+ GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
+
+ meck:new(rebar_dir, [passthrough]),
+ meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
+ meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
+
+ %% Insert proxy variables into config
+ rebar_test_utils:create_config(GlobalConfigDir,
+ [{http_proxy, "http://localhost:1234"}
+ ]),
+ rebar_test_utils:init_rebar_state(Config);
+init_per_testcase(https_proxy_settings, Config) ->
+ SupportsHttpsProxy = case erlang:system_info(otp_release) of
+ "R16"++_ -> true;
+ "R"++_ -> false;
+ _ -> true % 17 and up don't have a "R" in the version
+ end,
+ if not SupportsHttpsProxy ->
+ {skip, https_proxy_unsupported_before_R16};
+ SupportsHttpsProxy ->
+ %% Create private rebar.config
+ Priv = ?config(priv_dir, Config),
+ GlobalDir = filename:join(Priv, "global"),
+ GlobalConfigDir = filename:join([GlobalDir, ".config", "rebar3"]),
+ GlobalConfig = filename:join([GlobalDir, ".config", "rebar3", "rebar.config"]),
+
+ meck:new(rebar_dir, [passthrough]),
+ meck:expect(rebar_dir, global_config, fun() -> GlobalConfig end),
+ meck:expect(rebar_dir, global_cache_dir, fun(_) -> GlobalDir end),
+
+ %% Insert proxy variables into config
+ rebar_test_utils:create_config(GlobalConfigDir,
+ [{https_proxy, "http://localhost:1234"}
+ ]),
+ rebar_test_utils:init_rebar_state(Config)
+ end;
init_per_testcase(Case, Config) ->
{Deps, Warnings, Expect} = deps(Case),
Expected = case Expect of
@@ -45,6 +86,12 @@ init_per_testcase(Case, Config) ->
{warnings, Warnings}
| setup_project(Case, Config, rebar_test_utils:expand_deps(DepsType, Deps))].
+end_per_testcase(https_proxy_settings, Config) ->
+ meck:unload(rebar_dir),
+ Config;
+end_per_testcase(http_proxy_settings, Config) ->
+ meck:unload(rebar_dir),
+ Config;
end_per_testcase(_, Config) ->
meck:unload(),
Config.
@@ -223,6 +270,25 @@ newly_added_dep(Config) ->
{ok, [{app, Name}, {dep, "a"}, {dep, "b", "1.0.0"}, {dep, "c", "1.0.0"}]}).
+http_proxy_settings(_Config) ->
+ %% Load config
+ rebar_utils:set_httpc_options(),
+ rebar3:init_config(),
+
+ %% Assert variable is right
+ ?assertEqual({ok,{{"localhost", 1234}, []}},
+ httpc:get_option(proxy, rebar)).
+
+https_proxy_settings(_Config) ->
+ %% Load config
+ rebar_utils:set_httpc_options(),
+ rebar3:init_config(),
+
+ %% Assert variable is right
+ ?assertEqual({ok,{{"localhost", 1234}, []}},
+ httpc:get_option(https_proxy, rebar)).
+
+
run(Config) ->
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
rebar_test_utils:run_and_check(
diff --git a/test/rebar_hooks_SUITE.erl b/test/rebar_hooks_SUITE.erl
index ec5cc9a..85ca0e5 100644
--- a/test/rebar_hooks_SUITE.erl
+++ b/test/rebar_hooks_SUITE.erl
@@ -114,7 +114,7 @@ run_hooks_for_plugins(Config) ->
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
PluginName = rebar_test_utils:create_random_name("plugin1_"),
- mock_git_resource:mock([{config, [{pre_hooks, [{compile, "touch randomfile"}]}]}]),
+ mock_git_resource:mock([{config, [{pre_hooks, [{compile, "echo whatsup > randomfile"}]}]}]),
RConfFile = rebar_test_utils:create_config(AppDir,
[{plugins, [
diff --git a/test/rebar_install_deps_SUITE.erl b/test/rebar_install_deps_SUITE.erl
index dca6308..be42e68 100644
--- a/test/rebar_install_deps_SUITE.erl
+++ b/test/rebar_install_deps_SUITE.erl
@@ -10,7 +10,8 @@ groups() ->
[{all, [], [flat, pick_highest_left, pick_highest_right,
pick_smallest1, pick_smallest2,
circular1, circular2, circular_skip,
- fail_conflict, default_profile, nondefault_profile]},
+ fail_conflict, default_profile, nondefault_profile,
+ nondefault_pick_highest]},
{git, [], [{group, all}]},
{pkg, [], [{group, all}]}].
@@ -125,7 +126,10 @@ deps(nondefault_profile) ->
{[{"B", []},
{"C", []}],
[],
- {ok, ["B", "C"]}}.
+ {ok, ["B", "C"]}};
+deps(nondefault_pick_highest) ->
+ %% This is all handled in setup_project
+ {[],[],{ok,[]}}.
setup_project(fail_conflict, Config0, Deps) ->
DepsType = ?config(deps_type, Config0),
@@ -164,6 +168,34 @@ setup_project(nondefault_profile, Config0, Deps) ->
mock_pkg_resource:mock([{pkgdeps, rebar_test_utils:flat_pkgdeps(Deps)}])
end,
[{rebarconfig, RebarConf} | Config];
+setup_project(nondefault_pick_highest, Config0, _) ->
+ DepsType = ?config(deps_type, Config0),
+ Config = rebar_test_utils:init_rebar_state(
+ Config0,
+ "nondefault_pick_highest_"++atom_to_list(DepsType)++"_"
+ ),
+ AppDir = ?config(apps, Config),
+ rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
+ DefaultDeps = rebar_test_utils:expand_deps(DepsType, [{"B", [{"C", "1", []}]}]),
+ ProfileDeps = rebar_test_utils:expand_deps(DepsType, [{"C", "2", []}]),
+ DefaultTop = rebar_test_utils:top_level_deps(DefaultDeps),
+ ProfileTop = rebar_test_utils:top_level_deps(ProfileDeps),
+ RebarConf = rebar_test_utils:create_config(
+ AppDir,
+ [{deps, DefaultTop},
+ {profiles, [{nondef, [{deps, ProfileTop}]}]}]
+ ),
+ case DepsType of
+ git ->
+ mock_git_resource:mock(
+ [{deps, rebar_test_utils:flat_deps(DefaultDeps ++ ProfileDeps)}]
+ );
+ pkg ->
+ mock_pkg_resource:mock(
+ [{pkgdeps, rebar_test_utils:flat_pkgdeps(DefaultDeps ++ ProfileDeps)}]
+ )
+ end,
+ [{rebarconfig, RebarConf} | Config];
setup_project(Case, Config0, Deps) ->
DepsType = ?config(deps_type, Config0),
Config = rebar_test_utils:init_rebar_state(
@@ -228,7 +260,7 @@ default_profile(Config) ->
|| {dep, App} <- Apps].
nondefault_profile(Config) ->
- %% The dependencies here are saved directly to the
+ %% The dependencies here are saved directly to the
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
AppDir = ?config(apps, Config),
{ok, AppLocks} = ?config(expect, Config),
@@ -262,6 +294,21 @@ nondefault_profile(Config) ->
file:read_file_info(filename:join([BuildDir, "default", "lib", App])))
|| {dep, App} <- Apps].
+nondefault_pick_highest(Config) ->
+ {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
+ %AppDir = ?config(apps, Config),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "nondef", "lock"],
+ {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "2"}], "nondef"}
+ ),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["lock"],
+ {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "1"}, {lock, "C", "1"}], "default"}
+ ),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "nondef", "lock"],
+ {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "2"}], "nondef"}
+ ).
run(Config) ->
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
@@ -294,4 +341,3 @@ in_warnings(pkg, Warns, NameRaw, VsnRaw) ->
Vsn = iolist_to_binary(VsnRaw),
1 =< length([1 || {_, [AppName, AppVsn]} <- Warns,
AppName =:= Name, AppVsn =:= Vsn]).
-
diff --git a/test/rebar_pkg_SUITE.erl b/test/rebar_pkg_SUITE.erl
index 95eb6f6..85bd6f0 100644
--- a/test/rebar_pkg_SUITE.erl
+++ b/test/rebar_pkg_SUITE.erl
@@ -61,7 +61,7 @@ init_per_testcase(good_disconnect=Name, Config0) ->
copy_to_cache(Pkg, Config),
meck:unload(httpc),
meck:new(httpc, [passthrough, unsticky]),
- meck:expect(httpc, request, fun(_, _, _, _) -> {error, econnrefused} end),
+ meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end),
Config;
init_per_testcase(bad_disconnect=Name, Config0) ->
Pkg = {<<"goodpkg">>, <<"1.0.0">>},
@@ -71,7 +71,7 @@ init_per_testcase(bad_disconnect=Name, Config0) ->
Config = mock_config(Name, Config1),
meck:unload(httpc),
meck:new(httpc, [passthrough, unsticky]),
- meck:expect(httpc, request, fun(_, _, _, _) -> {error, econnrefused} end),
+ meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end),
Config.
end_per_testcase(_, Config) ->
@@ -186,9 +186,9 @@ mock_config(Name, Config) ->
{ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)),
meck:new(httpc, [passthrough, unsticky]),
meck:expect(httpc, request,
- fun(get, {_Url, _Opts}, _, _) when GoodCache ->
+ fun(get, {_Url, _Opts}, _, _, _) when GoodCache ->
{ok, {{Vsn, 304, <<"Not Modified">>}, [{"etag", ?good_etag}], <<>>}};
- (get, {_Url, _Opts}, _, _) ->
+ (get, {_Url, _Opts}, _, _, _) ->
{ok, {{Vsn, 200, <<"OK">>}, [{"etag", ?good_etag}], PkgContents}}
end),
[{cache_root, CacheRoot},
diff --git a/test/rebar_release_SUITE.erl b/test/rebar_release_SUITE.erl
index 3809106..1ef0771 100644
--- a/test/rebar_release_SUITE.erl
+++ b/test/rebar_release_SUITE.erl
@@ -6,7 +6,8 @@
all() -> [release,
dev_mode_release,
profile_dev_mode_override_release,
- tar].
+ tar,
+ extend_release].
init_per_testcase(Case, Config0) ->
Config = rebar_test_utils:init_rebar_state(Config0),
@@ -90,3 +91,21 @@ tar(Config) ->
["tar"],
{ok, [{release, list_to_atom(Name), Vsn, false}, {tar, Name, Vsn}]}
).
+
+%% Test that the order of release config args is not lost. If it is extend would fail.
+extend_release(Config) ->
+ AppDir = ?config(apps, Config),
+ Name = ?config(name, Config),
+ Vsn = "1.0.0",
+ {ok, RebarConfig} =
+ file:consult(rebar_test_utils:create_config(AppDir,
+ [{relx, [{release, {list_to_atom(Name), Vsn},
+ [list_to_atom(Name)]},
+ {release, {extended, Vsn, {extend, list_to_atom(Name)}},
+ []},
+ {lib_dirs, [AppDir]}]}])),
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig,
+ ["release", "-n", "extended"],
+ {ok, [{release, extended, Vsn, false}]}
+ ).
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index e5de0a6..4a13e03 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -56,7 +56,11 @@ run_and_check(Config, RebarConfig, Command, Expect) ->
?assertEqual({error, Reason}, Res);
{ok, Expected} ->
{ok, _} = Res,
- check_results(AppDir, Expected),
+ check_results(AppDir, Expected, "*"),
+ Res;
+ {ok, Expected, ProfileRun} ->
+ {ok, _} = Res,
+ check_results(AppDir, Expected, ProfileRun),
Res;
return ->
Res
@@ -105,16 +109,22 @@ create_config(AppDir, Contents) ->
%% @doc Util to create a random variation of a given name.
create_random_name(Name) ->
- random:seed(os:timestamp()),
+ random_seed(),
Name ++ erlang:integer_to_list(random:uniform(1000000)).
%% @doc Util to create a random variation of a given version.
create_random_vsn() ->
- random:seed(os:timestamp()),
+ random_seed(),
lists:flatten([erlang:integer_to_list(random:uniform(100)),
".", erlang:integer_to_list(random:uniform(100)),
".", erlang:integer_to_list(random:uniform(100))]).
+random_seed() ->
+ <<A:32, B:32, C:32>> = crypto:rand_bytes(12),
+ random:seed({A,B,C}).
+
+
+
expand_deps(_, []) -> [];
expand_deps(git, [{Name, Deps} | Rest]) ->
Dep = {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}},
@@ -158,9 +168,9 @@ top_level_deps([{{Name, Vsn, Ref}, _} | Deps]) ->
%%%%%%%%%%%%%%%
%%% Helpers %%%
%%%%%%%%%%%%%%%
-check_results(AppDir, Expected) ->
- BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", "*", "lib"])),
- PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", "*", "plugins"])),
+check_results(AppDir, Expected, ProfileRun) ->
+ BuildDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "lib"])),
+ PluginDirs = filelib:wildcard(filename:join([AppDir, "_build", ProfileRun, "plugins"])),
GlobalPluginDirs = filelib:wildcard(filename:join([AppDir, "global", "plugins"])),
CheckoutsDir = filename:join([AppDir, "_checkouts"]),
LockFile = filename:join([AppDir, "rebar.lock"]),
@@ -323,12 +333,12 @@ write_app_src_file(Dir, Name, Version, Deps) ->
ok = ec_file:write_term(Filename, get_app_metadata(ec_cnv:to_list(Name), Version, Deps)).
erl_src_file(Name) ->
- io_lib:format("-module(~s).\n"
+ io_lib:format("-module('~s').\n"
"-export([main/0]).\n"
"main() -> ok.\n", [filename:basename(Name, ".erl")]).
erl_eunitized_src_file(Name) ->
- io_lib:format("-module(~s).\n"
+ io_lib:format("-module('~s').\n"
"-export([main/0]).\n"
"main() -> ok.\n"
"-ifdef(TEST).\n"
@@ -338,7 +348,7 @@ erl_eunitized_src_file(Name) ->
erl_eunit_suite_file(Name) ->
BaseName = filename:basename(Name, ".erl"),
- io_lib:format("-module(~s_tests).\n"
+ io_lib:format("-module('~s_tests').\n"
"-compile(export_all).\n"
"-ifndef(some_define).\n"
"-define(some_define, false).\n"
diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl
index 79cf29e..f2d4133 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -10,7 +10,8 @@ groups() ->
pair_a, pair_b, pair_ab, pair_c, pair_all,
triplet_a, triplet_b, triplet_c,
tree_a, tree_b, tree_c, tree_c2, tree_ac, tree_all,
- delete_d, promote, stable_lock, fwd_lock]},
+ delete_d, promote, stable_lock, fwd_lock,
+ compile_upgrade_parity]},
{git, [], [{group, all}]},
{pkg, [], [{group, all}]}].
@@ -404,7 +405,20 @@ upgrades(fwd_lock) ->
%% file to include the result post-upgrade, and then
%% run a regular lock to see that the lock file is respected
%% in deps.
- {"any", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}}.
+ {"any", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}};
+upgrades(compile_upgrade_parity) ->
+ {[{"A", "1", [{"D",[{"J",[]}]},
+ {"E",[{"I","1",[]}]}]},
+ {"B", "1", [{"F",[]},
+ {"G",[]}]},
+ {"C", "1", [{"H",[]},
+ {"I","2",[]}]}
+ ],
+ [],
+ [],
+ {"", [{"A","1"}, "D", "J", "E", {"I","1"},
+ {"B","1"}, "F", "G",
+ {"C","1"}, "H"]}}.
%% TODO: add a test that verifies that unlocking files and then
%% running the upgrade code is enough to properly upgrade things.
@@ -518,6 +532,22 @@ fwd_lock(Config) ->
Config, NewRebarConfig, ["lock", App], Expectation
).
+compile_upgrade_parity(Config) ->
+ AppDir = ?config(apps, Config),
+ apply(?config(mock, Config), []),
+ {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
+ %% compiling and upgrading should generate the same lockfiles when
+ %% deps are identical
+ Lockfile = filename:join([AppDir, "rebar.lock"]),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, []}),
+ {ok, CompileLockData1} = file:read_file(Lockfile),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["upgrade"], {ok, []}),
+ {ok, UpgradeLockData} = file:read_file(Lockfile),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, []}),
+ {ok, CompileLockData2} = file:read_file(Lockfile),
+ ?assertEqual(CompileLockData1, CompileLockData2),
+ ?assertEqual(CompileLockData1, UpgradeLockData).
+
run(Config) ->
apply(?config(mock, Config), []),
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
diff --git a/test/rebar_utils_SUITE.erl b/test/rebar_utils_SUITE.erl
index e9b32e2..f04ab63 100644
--- a/test/rebar_utils_SUITE.erl
+++ b/test/rebar_utils_SUITE.erl
@@ -21,7 +21,8 @@
task_with_flag_with_trailing_comma/1,
task_with_flag_with_commas/1,
task_with_multiple_flags/1,
- special_task_do/1]).
+ special_task_do/1,
+ sh_does_not_miss_messages/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -29,7 +30,8 @@
all() ->
- [{group, args_to_tasks}].
+ [{group, args_to_tasks},
+ sh_does_not_miss_messages].
groups() ->
[{args_to_tasks, [], [empty_arglist,
@@ -118,3 +120,14 @@ special_task_do(_Config) ->
"do",
"bar,",
"baz"]).
+sh_does_not_miss_messages(_Config) ->
+ Source = "~nmain(_) ->~n io:format(\"donotmissme\").~n",
+ file:write_file("do_not_miss_messages", io_lib:format(Source,[])),
+ {ok, "donotmissme"} = rebar_utils:sh("escript do_not_miss_messages", []),
+ AnyMessageRemained =
+ receive
+ What -> What
+ after 100 ->
+ false
+ end,
+ AnyMessageRemained = false.