summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml7
-rw-r--r--CONTRIBUTING.md110
-rw-r--r--README.md40
-rw-r--r--THANKS4
-rwxr-xr-xbootstrap79
-rw-r--r--priv/shell-completion/bash/rebar326
-rw-r--r--priv/shell-completion/zsh/_rebar332
-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.config67
-rw-r--r--rebar.config.sample10
-rw-r--r--rebar.lock25
-rw-r--r--src/rebar.app.src4
-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.erl14
-rw-r--r--src/rebar_digraph.erl4
-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.erl77
-rw-r--r--src/rebar_pkg_resource.erl3
-rw-r--r--src/rebar_plugins.erl29
-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_do.erl12
-rw-r--r--src/rebar_prv_help.erl8
-rw-r--r--src/rebar_prv_install_deps.erl263
-rw-r--r--src/rebar_prv_packages.erl23
-rw-r--r--src/rebar_prv_plugins_upgrade.erl41
-rw-r--r--src/rebar_prv_release.erl30
-rw-r--r--src/rebar_prv_relup.erl40
-rw-r--r--src/rebar_prv_shell.erl12
-rw-r--r--src/rebar_prv_tar.erl27
-rw-r--r--src/rebar_prv_update.erl3
-rw-r--r--src/rebar_relx.erl69
-rw-r--r--src/rebar_state.erl14
-rw-r--r--src/rebar_templater.erl2
-rw-r--r--src/rebar_utils.erl59
-rw-r--r--test/rebar_compile_SUITE.erl100
-rw-r--r--test/rebar_cover_SUITE.erl21
-rw-r--r--test/rebar_deps_SUITE.erl68
-rw-r--r--test/rebar_hooks_SUITE.erl4
-rw-r--r--test/rebar_install_deps_SUITE.erl86
-rw-r--r--test/rebar_pkg_SUITE.erl8
-rw-r--r--test/rebar_release_SUITE.erl21
-rw-r--r--test/rebar_test_utils.erl30
-rw-r--r--test/rebar_upgrade_SUITE.erl34
-rw-r--r--test/rebar_utils_SUITE.erl17
56 files changed, 1243 insertions, 624 deletions
diff --git a/.travis.yml b/.travis.yml
index b0729f8..d1163c4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,8 @@
+sudo: false
language: erlang
otp_release:
- - 17.0
+ - 18.0
+ - 17.5
- R16B03-1
- R15B03
before_script: "./bootstrap"
@@ -8,6 +10,9 @@ script: "./rebar3 ct"
branches:
only:
- master
+cache:
+ directories:
+ - $HOME/.cache/rebar3/hex/com/amazonaws/s3/s3.hex.pm/tarballs/packages/
before_deploy: "rm -rf !(rebar3)"
deploy:
on:
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 efcecfd..a060ec0 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,32 +27,47 @@ 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 |
-| eunit | Run eunit tests |
| escriptize | Generate escript of project |
+| eunit | Run eunit tests |
| help | Print help for rebar or task |
| new | Create new rebar project from templates |
| pkgs | List available packages |
+| plugins | List or upgrade plugins |
| release | Build release of project |
+| relup | Creates relup from 2 releases |
| report | Report on environment and versions for bug reports |
| shell | Run shell with project apps in path |
| tar | Package release into tarball |
+| unlock | Unlock dependencies |
| update | Update package index |
| upgrade | Fetch latest version of dep |
| 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
@@ -141,7 +148,6 @@ $ ./rebar3 escriptize
$ _build/default/bin/rebar3
```
-
Contributing to rebar
=====================
@@ -159,15 +165,15 @@ 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
+[documentation](http://www.rebar3.org/v3.0/docs) 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/rebar/rebar/issues).
+page](https://github.com/rebar/rebar3/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/rebar/rebar/wiki)
-- [issues](https://github.com/rebar/rebar/issues)
+- [issues](https://github.com/rebar/rebar3/issues)
+- [Documentation](http://www.rebar3.org/v3.0/docs)
diff --git a/THANKS b/THANKS
index 983d883..d813970 100644
--- a/THANKS
+++ b/THANKS
@@ -132,4 +132,6 @@ Tristan Sloughter
Kelly McLaughlin
Martin Karlsson
Pierre Fenoll
-David Kubecka \ No newline at end of file
+David Kubecka
+Stefan Grundmann
+Carlos Eduardo de Paula
diff --git a/bootstrap b/bootstrap
index 1a3999b..71c44da 100755
--- a/bootstrap
+++ b/bootstrap
@@ -4,6 +4,14 @@
main(_Args) ->
+ application:start(crypto),
+ application:start(asn1),
+ 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, []}
,{getopt, []}
@@ -24,6 +32,7 @@ main(_Args) ->
setup_env(),
os:putenv("REBAR_PROFILE", "bootstrap"),
+ rebar3:run(["update"]),
{ok, State} = rebar3:run(["compile"]),
reset_env(),
os:putenv("REBAR_PROFILE", ""),
@@ -56,28 +65,58 @@ fetch_and_compile({Name, ErlFirstFiles}, Deps) ->
ok = fetch(Repo, Name),
compile(Name, ErlFirstFiles).
-fetch({git, Url, Source}, App) ->
+fetch({pkg, Name, Vsn}, App) ->
Dir = filename:join([filename:absname("_build/default/lib/"), App]),
- case filelib:is_dir(Dir) of
- true ->
- true = code:add_path(filename:join(Dir, "ebin")),
- ok;
- false ->
- fetch_source(Dir, Url, Source),
- ok
+ CDN = "https://s3.amazonaws.com/s3.hex.pm/tarballs",
+ Package = binary_to_list(<<Name/binary, "-", Vsn/binary, ".tar">>),
+ Url = string:join([CDN, Package], "/"),
+ case request(Url) of
+ {ok, Binary} ->
+ {ok, Contents} = extract(Binary),
+ ok = erl_tar:extract({binary, Contents}, [{cwd, Dir}, compressed]);
+ _ ->
+ io:format("Error: Unable to fetch package ~p ~p~n", [Name, Vsn])
+ end.
+
+extract(Binary) ->
+ {ok, Files} = erl_tar:extract({binary, Binary}, [memory]),
+ {"contents.tar.gz", Contents} = lists:keyfind("contents.tar.gz", 1, Files),
+ {ok, Contents}.
+
+request(Url) ->
+ case httpc:request(get, {Url, []},
+ [{relaxed, true}],
+ [{body_format, binary}],
+ rebar) of
+ {ok, {{_Version, 200, _Reason}, _Headers, Body}} ->
+ {ok, Body};
+ Error ->
+ Error
end.
-fetch_source(Dir, Url, {ref, Ref}) ->
- ok = filelib:ensure_dir(Dir),
- os:cmd(io_lib:format("git clone ~s ~s", [Url, Dir])),
- {ok, Cwd} = file:get_cwd(),
- file:set_cwd(Dir),
- os:cmd(io_lib:format("git checkout -q ~s", [Ref])),
- file:set_cwd(Cwd);
-fetch_source(Dir, Url, {_, Branch}) ->
- ok = filelib:ensure_dir(Dir),
- os:cmd(io_lib:format("git clone ~s ~s -b ~s --single-branch",
- [Url, Dir, Branch])).
+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),
@@ -86,6 +125,7 @@ compile(App, FirstFiles) ->
FirstFilesPaths = [filename:join([Dir, "src", Module]) || Module <- FirstFiles],
Sources = FirstFilesPaths ++ filelib:wildcard(filename:join([Dir, "src", "*.erl"])),
[compile_file(X, [{i, filename:join(Dir, "include")}
+ ,debug_info
,{outdir, filename:join(Dir, "ebin")}
,return | additional_defines()]) || X <- Sources].
@@ -219,6 +259,7 @@ setup_env() ->
application:load(rebar),
{ok, Providers} = application:get_env(rebar, providers),
Providers1 = Providers -- [rebar_prv_release,
+ rebar_prv_relup,
rebar_prv_tar],
application:set_env(rebar, providers, Providers1).
diff --git a/priv/shell-completion/bash/rebar3 b/priv/shell-completion/bash/rebar3
index b6d3de2..4e28d3d 100644
--- a/priv/shell-completion/bash/rebar3
+++ b/priv/shell-completion/bash/rebar3
@@ -23,7 +23,9 @@ _rebar3()
help \
new \
pkgs \
+ plugins \
release \
+ relup \
report \
shell \
tar \
@@ -94,6 +96,8 @@ _rebar3()
lopts="--force"
elif [[ ${prev} == pkgs ]] ; then
:
+ elif [[ ${prev} == plugins ]] ; then
+ :
elif [[ ${prev} == release ]] ; then
sopts="-n -v -g -u -o -h -l -p -V -d -i -a -c -r"
lopts="--relname \
@@ -116,6 +120,28 @@ _rebar3()
--system_libs \
--version \
--root"
+ elif [[ ${prev} == relup ]] ; then
+ sopts="-n -v -g -u -o -h -l -p -V -d -i -a -c -r"
+ lopts="--relname \
+ --relvsn \
+ --goal \
+ --upfrom \
+ --output-dir \
+ --help \
+ --lib-dir \
+ --path \
+ --default-libs \
+ --verbose \
+ --dev-mode \
+ --include-erts \
+ --override \
+ --config \
+ --overlay_vars \
+ --vm_args \
+ --sys_config \
+ --system_libs \
+ --version \
+ --root"
elif [[ ${prev} == report ]] ; then
:
elif [[ ${prev} == shell ]] ; then
diff --git a/priv/shell-completion/zsh/_rebar3 b/priv/shell-completion/zsh/_rebar3
index 5fcdd91..b03b7c9 100644
--- a/priv/shell-completion/zsh/_rebar3
+++ b/priv/shell-completion/zsh/_rebar3
@@ -111,6 +111,11 @@ _rebar3 () {
(pkgs)
_message 'List available packages.' && ret=0
;;
+ (plugins)
+ _arguments \
+ '1:type:(list upgrade)' \
+ && ret=0
+ ;;
(release)
_arguments \
'(-n --relname)'{-n,--relname}'[Specify the name for the release that will be generated.]:relname' \
@@ -134,6 +139,29 @@ _rebar3 () {
'(-r --root)'{-r,--root}'[The project root directory]:system libs:_files -/' \
&& ret=0
;;
+ (relup)
+ _arguments \
+ '(-n --relname)'{-n,--relname}'[Specify the name for the release that will be generated.]:relname' \
+ '(-v --relvsn)'{-n,--relname}'[Specify the version for the release.]:relvsn' \
+ '(-g --goal)'{-g,--goal}'[Specify a target constraint on the system. These are usually the OTP.]:goal' \
+ '(-u --upfrom)'{-u,--upfrom}'[Only valid with relup target, specify the release to upgrade from.]:upfrom' \
+ '(-o --output-dir)'{-o,--output-dir}'[The output directory for the release. This is ./ by default.]:out directory:_files -/' \
+ '(-l --lib-dir)'{-l,--output-dir}'[Additional dir that should be searched for OTP Apps]:lib directory:_files -/' \
+ '(-p --path)'{-p,--path}'[Additional dir to add to the code path]:path directory:_files -/' \
+ '(--default-libs)--default-libs[Whether to use the default system added lib dirs]:default libs:(true false)' \
+ '(-V --verbose)'{-V,--verbose}'[Verbosity level, maybe between 0 and 3 ,default: 2]:verbosity level:(0 1 2 3)' \
+ '(-d --dev-mode)'{-d,--dev-mode}'[Symlink the applications and configuration into the release instead of copying]' \
+ '(-i --include-erts)'{-i,--dev-mode}'[If true include a copy of erts used to build with, if a path include erts at that path. If false, do not include erts]' \
+ '(-a --override)'{-a,--override}'[Provide an app name and a directory to override in the form <appname>:<app directory>]:override' \
+ '(-c --config)'{-c,--config}'[The path to a config file]:config file:_files ' \
+ '(--overlay_vars)--overlay_vars[Path to a file of overlay variables]:overlay variables file:_files' \
+ '(--vm_args)--vm_args[Path to a file to use for vm.args]:vm args file:_files' \
+ '(--sys_config)--sys_config[Path to a file to use for sys.config]:sys config file:_files' \
+ '(--system_libs)--system_libs[Path to dir of Erlang system libs]:system libs:_files -/' \
+ '(--version)--version[Print relx version]' \
+ '(-r --root)'{-r,--root}'[The project root directory]:system libs:_files -/' \
+ && ret=0
+ ;;
(report)
_arguments '1: :_rebar3_tasks' && ret=0
;;
@@ -202,11 +230,13 @@ _rebar3_tasks() {
'help:Display a list of tasks or help for a given task or subtask.'
'new:Create new project from templates.'
'pkgs:List available packages.'
+ 'plugins:List or upgrade plugins.'
'release:Build release of project.'
+ 'relup:Create relup from 2 releases.'
'report:Provide a crash report to be sent to the rebar3 issues page.'
'shell:Run shell with project apps and deps in path.'
'tar:Tar archive of release built of project.'
- 'unlock:Unlock dependencies..'
+ 'unlock:Unlock dependencies.'
'update:Update package index.'
'upgrade:Upgrade dependencies.'
'version:Print version for rebar and current Erlang.'
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 d68f195..16b57d8 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,22 +1,11 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 ft=erlang et
-{deps, [
- {erlware_commons, "",
- {git, "https://github.com/erlware/erlware_commons.git",
- {branch, "master"}}},
- {providers, "",
- {git, "https://github.com/tsloughter/providers.git",
- {tag, "v1.4.0"}}},
- {relx, "",
- {git, "https://github.com/erlware/relx.git",
- {branch, "master"}}},
- {mustache, ".*",
- {git, "https://github.com/soranoba/mustache.git",
- {tag, "v0.3.0"}}},
- {getopt, "",
- {git, "https://github.com/jcomellas/getopt.git",
- {branch, "master"}}}]}.
+{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"}.
@@ -26,23 +15,22 @@
{"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]}
+ ]
+ },
- %% We don't want erlydtl to attempt to run on the first compile pass to bootstrap
- {bootstrap, []}
+ {bootstrap, []},
+
+ {dialyze, [{erl_opts, [debug_info]}]}
]}.
%% Overrides
@@ -51,16 +39,23 @@
{platform_define, "^R1[4|5]", deprecated_crypto},
no_debug_info,
warnings_as_errors]},
- {deps, []}, {plugins, []}
+ {deps, []}, {plugins, []},
+ {profiles, [{dialyze, [{erl_opts, [debug_info]}]}]}
]},
- {override, mustache, [
- {erl_opts, [{platform_define, "^[0-9]+", namespaced_types},
- no_debug_info]},
- {deps, []}, {plugins, []}]},
- {override, getopt, [{erl_opts, [no_debug_info]}]},
- {override, providers, [{erl_opts, [no_debug_info]}]},
+ {override, bbmustache, [
+ {erl_opts, [no_debug_info,
+ {platform_define, "^[0-9]+", namespaced_types}]},
+ {deps, []}, {plugins, []},
+ {profiles, [{dialyze, [{erl_opts, [debug_info]}]}]}
+ ]},
+ {override, getopt, [{erl_opts, [no_debug_info]},
+ {profiles, [{dialyze, [{erl_opts, [debug_info]}]}]}]},
+ {override, providers, [{erl_opts, [no_debug_info]},
+ {profiles, [{dialyze, [{erl_opts, [debug_info]}]}]}]},
{override, relx, [{erl_opts, [{platform_define, "^[0-9]+", namespaced_types},
{platform_define, "^R1[4|5]", deprecated_crypto},
no_debug_info,
- warnings_as_errors]}]}
+ warnings_as_errors]},
+ {profiles, [{dialyze, [{erl_opts, [debug_info]}]}]}
+ ]}
]}.
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 20c120f..1ff26f3 100644
--- a/rebar.lock
+++ b/rebar.lock
@@ -1,20 +1,5 @@
-[{<<"relx">>,
- {git,"https://github.com/erlware/relx.git",
- {ref,"74fec3455ba6dbb7d9e369137c1b15ab10804993"}},
- 0},
- {<<"providers">>,
- {git,"https://github.com/tsloughter/providers.git",
- {ref,"adc0af0a3f5de2049419a753777686b94f4e2c90"}},
- 0},
- {<<"mustache">>,
- {git,"https://github.com/soranoba/mustache.git",
- {ref,"e5401042c66039eef20ee81abc1537ced1f22bc7"}},
- 0},
- {<<"getopt">>,
- {git,"https://github.com/jcomellas/getopt.git",
- {ref,"626698975e63866156159661d100785d65eab6f9"}},
- 0},
- {<<"erlware_commons">>,
- {git,"https://github.com/erlware/erlware_commons.git",
- {ref,"ef0d252b11c863f9c228af2fe93a4e42fba2f7f3"}},
- 0}].
+[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.0.3">>},0},
+ {<<"providers">>,{pkg,<<"providers">>,<<"1.4.1">>},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 6d081a2..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,
@@ -17,6 +17,7 @@
common_test,
erlware_commons,
providers,
+ bbmustache,
relx,
inets]},
{env, [
@@ -47,6 +48,7 @@
rebar_prv_plugins,
rebar_prv_plugins_upgrade,
rebar_prv_release,
+ rebar_prv_relup,
rebar_prv_report,
rebar_prv_shell,
rebar_prv_tar,
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 7439cff..f097429 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -128,9 +128,17 @@ 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.
format_error({bad_provider_namespace, {Namespace, Name}}) ->
diff --git a/src/rebar_digraph.erl b/src/rebar_digraph.erl
index d52a811..a9c1cbb 100644
--- a/src/rebar_digraph.erl
+++ b/src/rebar_digraph.erl
@@ -91,9 +91,9 @@ cull_deps(Graph, Vertices, Level, Levels, Solution, Discarded) ->
lists:foldl(fun({Key, _}=N, {NewVertices1, SolutionAcc1, LevelsAcc1, DiscardedAcc1}) ->
case dict:find(Key, SolutionAcc1) of
{ok, N} -> % already seen
- {NewVertices1, SolutionAcc1, LevelsAcc, DiscardedAcc1};
+ {NewVertices1, SolutionAcc1, LevelsAcc1, DiscardedAcc1};
{ok, _} -> % conflict resolution!
- {NewVertices1, SolutionAcc1, LevelsAcc, [N|DiscardedAcc1]};
+ {NewVertices1, SolutionAcc1, LevelsAcc1, [N|DiscardedAcc1]};
error ->
{[N | NewVertices1],
dict:store(Key, N, SolutionAcc1),
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 9518542..857336c 100644
--- a/src/rebar_hooks.erl
+++ b/src/rebar_hooks.erl
@@ -1,6 +1,10 @@
-module(rebar_hooks).
--export([run_all_hooks/5]).
+-export([run_all_hooks/5
+ ,format_error/1]).
+
+-include("rebar.hrl").
+-include_lib("providers/include/providers.hrl").
-spec run_all_hooks(file:filename_all(), pre | post,
atom() | {atom(), atom()} | string(),
@@ -10,21 +14,39 @@ 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),
- State2 = rebar_core:do(HookProviders, State1),
- rebar_utils:remove_from_code_path(PluginDepsPaths),
- State2.
+ case rebar_core:do(HookProviders, State1) of
+ {error, ProviderName} ->
+ ?DEBUG(format_error({bad_provider, Type, Command, ProviderName}), []),
+ throw(?PRV_ERROR({bad_provider, Type, Command, ProviderName}));
+ {ok, _} ->
+ rebar_utils:remove_from_code_path(PluginDepsPaths)
+ end.
+
+format_error({bad_provider, Type, Command, {Name, Namespace}}) ->
+ io_lib:format("Unable to run ~s hooks for '~p', command '~p' in namespace '~p' not found.", [Type, Command, Namespace, Name]);
+format_error({bad_provider, Type, Command, Name}) ->
+ io_lib:format("Unable to run ~s hooks for '~p', command '~p' not found.", [Type, Command, Name]).
%% @doc The following environment variables are exported when running
%% a hook (absolute paths):
-%%
+%%
%% REBAR_DEPS_DIR = rebar_dir:deps_dir/1
%% REBAR_BUILD_DIR = rebar_dir:base_dir/1
%% REBAR_ROOT_DIR = rebar_dir:root_dir/1
@@ -36,7 +58,7 @@ run_provider_hooks(Dir, Type, Command, Providers, State) ->
%% REBAR_APP_DIRS = rebar_dir:lib_dirs/1
%% REBAR_SRC_DIRS = rebar_dir:src_dirs/1
%%
-%% autoconf compatible variables
+%% autoconf compatible variables
%% (see: http://www.gnu.org/software/autoconf/manual/autoconf.html#Erlang-Libraries):
%% ERLANG_ERTS_VER = erlang:system_info(version)
%% ERLANG_ROOT_DIR = code:root_dir/0
@@ -45,23 +67,24 @@ run_provider_hooks(Dir, Type, Command, Providers, State) ->
%% 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
@@ -100,8 +123,6 @@ join_dirs(BaseDir, Dirs) ->
re_version(Path) ->
case re:run(Path, "^.*-(?<VER>[^/-]*)$", [{capture, [1], list}]) of
- nomatch -> "";
- {match, [Ver]} -> Ver
+ nomatch -> "";
+ {match, [Ver]} -> Ver
end.
-
-
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 a267b9d..3e855de 100644
--- a/src/rebar_plugins.erl
+++ b/src/rebar_plugins.erl
@@ -21,14 +21,15 @@ project_apps_install(State) ->
lists:foldl(fun(Profile, StateAcc) ->
Plugins = rebar_state:get(State, {plugins, Profile}, []),
- handle_plugins(Profile, Plugins, StateAcc),
- lists:foldl(fun(App, StateAcc1) ->
+ StateAcc1 = handle_plugins(Profile, Plugins, StateAcc),
+
+ lists:foldl(fun(App, StateAcc2) ->
AppDir = rebar_app_info:dir(App),
C = rebar_config:consult(AppDir),
S = rebar_state:new(rebar_state:new(), C, AppDir),
Plugins2 = rebar_state:get(S, {plugins, Profile}, []),
- handle_plugins(Profile, Plugins2, StateAcc1)
- end, StateAcc, ProjectApps)
+ handle_plugins(Profile, Plugins2, StateAcc2)
+ end, StateAcc1, ProjectApps)
end, State, Profiles).
-spec install(rebar_state:t()) -> rebar_state:t().
@@ -49,21 +50,20 @@ handle_plugins(Profile, Plugins, State, Upgrade) ->
State1 = rebar_state:set(State, deps_dir, ?DEFAULT_PLUGINS_DIR),
%% Install each plugin individually so if one fails to install it doesn't effect the others
- {PluginProviders, State2} =
+ {_PluginProviders, State2} =
lists:foldl(fun(Plugin, {PluginAcc, StateAcc}) ->
{NewPlugins, NewState} = handle_plugin(Profile, Plugin, StateAcc, Upgrade),
- {PluginAcc++NewPlugins, NewState}
+ NewState1 = rebar_state:create_logic_providers(NewPlugins, NewState),
+ {PluginAcc++NewPlugins, NewState1}
end, {[], State1}, Plugins),
%% reset deps dir
State3 = rebar_state:set(State2, deps_dir, DepsDir),
- State4 = rebar_state:lock(State3, Locks),
-
- rebar_state:create_logic_providers(PluginProviders, State4).
+ rebar_state:lock(State3, Locks).
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, []),
@@ -72,7 +72,7 @@ handle_plugin(Profile, Plugin, State, Upgrade) ->
code:add_pathsa(CodePaths),
%% Build plugin and its deps
- [build_plugin(AppInfo, Apps, State) || AppInfo <- ToBuild],
+ [build_plugin(AppInfo, Apps, State2) || AppInfo <- ToBuild],
%% Add newly built deps and plugin to code path
State3 = rebar_state:update_all_plugin_deps(State2, Apps),
@@ -92,10 +92,9 @@ handle_plugin(Profile, Plugin, State, Upgrade) ->
build_plugin(AppInfo, Apps, State) ->
Providers = rebar_state:providers(State),
- AppDir = rebar_app_info:dir(AppInfo),
- C = rebar_config:consult(AppDir),
- S = rebar_state:new(rebar_state:all_deps(rebar_state:new(), Apps), C, AppDir),
- rebar_prv_compile:compile(S, Providers, AppInfo).
+ Providers1 = rebar_state:providers(rebar_app_info:state(AppInfo)),
+ S = rebar_state:all_deps(rebar_app_info:state_or_new(State, AppInfo), Apps),
+ rebar_prv_compile:compile(S, Providers++Providers1, AppInfo).
plugin_providers({Plugin, _, _, _}) when is_atom(Plugin) ->
validate_plugin(Plugin);
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_do.erl b/src/rebar_prv_do.erl
index 35e85c2..f850135 100644
--- a/src/rebar_prv_do.erl
+++ b/src/rebar_prv_do.erl
@@ -33,8 +33,16 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- Tasks = rebar_utils:args_to_tasks(rebar_state:command_args(State)),
- do_tasks(Tasks, State).
+ case rebar_utils:args_to_tasks(rebar_state:command_args(State)) of
+ [] ->
+ AllProviders = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ Providers = providers:get_providers_by_namespace(Namespace, AllProviders),
+ providers:help(Providers),
+ {ok, State};
+ Tasks ->
+ do_tasks(Tasks, State)
+ end.
do_tasks([], State) ->
{ok, State};
diff --git a/src/rebar_prv_help.erl b/src/rebar_prv_help.erl
index 4bc259a..c028264 100644
--- a/src/rebar_prv_help.erl
+++ b/src/rebar_prv_help.erl
@@ -65,7 +65,13 @@ task_help(Namespace, Name, State) ->
Providers = rebar_state:providers(State),
case providers:get_provider(Name, Providers, Namespace) of
not_found ->
- {error, io_lib:format("Unknown task ~p", [Name])};
+ case providers:get_providers_by_namespace(Name, Providers) of
+ [] ->
+ {error, io_lib:format("Unknown task ~p", [Name])};
+ NSProviders ->
+ providers:help(NSProviders),
+ {ok, State}
+ end;
Provider ->
providers:help(Provider),
{ok, State}
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index 806293b..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
@@ -224,28 +235,13 @@ update_pkg_deps(Profile, Pkgs, Packages, Upgrade, Seen, State, Locks) ->
handle_pkg_dep(Profile, Pkg, Packages, Upgrade, DepsDir, Fetched, Seen, Locks, State) ->
IsLock = pkg_locked(Pkg, Locks),
AppInfo = package_to_app(DepsDir, Packages, Pkg, IsLock, State),
+ Deps = rebar_app_info:deps(AppInfo),
Level = rebar_app_info:dep_level(AppInfo),
{NewSeen, NewState} = maybe_lock(Profile, AppInfo, Seen, State, Level),
{_, AppInfo1} = maybe_fetch(AppInfo, Profile, Upgrade, Seen, NewState),
-
- Profiles = rebar_state:current_profiles(State),
- Name = rebar_app_info:name(AppInfo1),
- C = rebar_config:consult(rebar_app_info:dir(AppInfo1)),
- BaseDir = rebar_state:get(State, base_dir, []),
- S1 = rebar_state:new(rebar_state:set(rebar_state:new(), base_dir, BaseDir),
- C, rebar_app_info:dir(AppInfo1)),
- S2 = rebar_state:apply_overrides(S1, Name),
-
- Plugins = rebar_state:get(S2, plugins, []),
- S3 = rebar_state:set(S2, {plugins, Profile}, Plugins),
-
- S4 = rebar_state:apply_profiles(S3, Profiles),
- AppInfo2 = rebar_app_info:state(AppInfo1, S4),
-
- %% Dep may have plugins to install. Find and install here.
- S5 = rebar_plugins:install(S4),
- AppInfo3 = rebar_app_info:state(AppInfo2, S5),
-
+ {AppInfo2, _, _, _, _} =
+ handle_dep(NewState, Profile, DepsDir, AppInfo1, Locks, Level),
+ AppInfo3 = rebar_app_info:deps(AppInfo2, Deps),
{[AppInfo3 | Fetched], NewSeen, NewState}.
maybe_lock(Profile, AppInfo, Seen, State, Level) ->
@@ -284,29 +280,25 @@ package_to_app(DepsDir, Packages, {Name, Vsn, Level}, IsLock, State) ->
throw(?PRV_ERROR({missing_package, Name, Vsn}))
end;
{ok, PkgDeps} ->
- {ok, AppInfo} = rebar_app_info:new(Name, Vsn),
- AppInfo1 = rebar_app_info:deps(AppInfo, PkgDeps),
- AppInfo2 = rebar_app_info:dir(AppInfo1, filename:join([DepsDir, Name])),
- AppInfo3 = rebar_app_info:dep_level(AppInfo2, Level),
- AppInfo4 = rebar_app_info:is_lock(AppInfo3, IsLock),
- rebar_app_info:source(AppInfo4, {pkg, Name, Vsn})
+ Source = {pkg, Name, Vsn},
+ AppInfo = new_dep(DepsDir, Name, Vsn, Source, IsLock, State),
+ AppInfo1 = rebar_app_info:dep_level(rebar_app_info:deps(AppInfo, PkgDeps), Level),
+ BaseDir = rebar_state:get(State, base_dir, []),
+ AppState1 = rebar_state:set(rebar_app_info:state(AppInfo1), base_dir, BaseDir),
+ rebar_app_info:state(AppInfo1, AppState1)
end.
-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
@@ -329,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
@@ -338,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) ->
@@ -401,10 +381,9 @@ handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) ->
S1 = rebar_state:new(S, C, rebar_app_info:dir(AppInfo)),
S2 = rebar_state:apply_overrides(S1, Name),
- Plugins = rebar_state:get(S2, plugins, []),
- S3 = rebar_state:set(S2, {plugins, Profile}, Plugins),
-
- S4 = rebar_state:apply_profiles(S3, Profiles),
+ S3 = rebar_state:apply_profiles(S2, Profiles),
+ Plugins = rebar_state:get(S3, plugins, []),
+ S4 = rebar_state:set(S3, {plugins, Profile}, Plugins),
AppInfo1 = rebar_app_info:state(AppInfo, S4),
%% Dep may have plugins to install. Find and install here.
@@ -430,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} ->
@@ -520,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} ->
@@ -530,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_packages.erl b/src/rebar_prv_packages.erl
index 43e3080..8ba66de 100644
--- a/src/rebar_prv_packages.erl
+++ b/src/rebar_prv_packages.erl
@@ -27,9 +27,9 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- case rebar_packages:registry(State) of
- {ok, Registry} ->
- print_packages(Registry),
+ case rebar_packages:get_packages(State) of
+ {Dict, _} ->
+ print_packages(Dict),
{ok, State};
error ->
?PRV_ERROR(load_registry_fail)
@@ -39,13 +39,16 @@ do(State) ->
format_error(load_registry_fail) ->
"Failed to load package regsitry. Try running 'rebar3 update' to fix".
-print_packages(Table) ->
- MS = ets:fun2ms(fun({Key, [Value]}) when is_binary(Key) -> {Key, Value} end),
- Pkgs = ets:select(Table, MS),
- lists:foreach(fun({Name, Vsns}) ->
- VsnStr = join(Vsns, <<", ">>),
- io:format("~s:~n Versions: ~s~n~n", [Name, VsnStr])
- end, Pkgs).
+print_packages(Dict) ->
+ Pkgs = lists:keysort(1, dict:fetch_keys(Dict)),
+ SortedPkgs = lists:foldl(fun({Pkg, Vsn}, Acc) ->
+ orddict:append_list(Pkg, [Vsn], Acc)
+ end, orddict:new(), Pkgs),
+
+ orddict:map(fun(Name, Vsns) ->
+ VsnStr = join(Vsns, <<", ">>),
+ io:format("~s:~n Versions: ~s~n~n", [Name, VsnStr])
+ end, SortedPkgs).
-spec join([binary()], binary()) -> binary().
join([Bin], _Sep) ->
diff --git a/src/rebar_prv_plugins_upgrade.erl b/src/rebar_prv_plugins_upgrade.erl
index fbd8365..02c185f 100644
--- a/src/rebar_prv_plugins_upgrade.erl
+++ b/src/rebar_prv_plugins_upgrade.erl
@@ -33,10 +33,16 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
{Args, _} = rebar_state:command_parsed_args(State),
- Plugin = proplists:get_value(plugin, Args, <<"">>),
- upgrade(Plugin, State).
+ case proplists:get_value(plugin, Args, none) of
+ none ->
+ ?PRV_ERROR(no_plugin_arg);
+ Plugin ->
+ upgrade(Plugin, State)
+ end.
-spec format_error(any()) -> iolist().
+format_error(no_plugin_arg) ->
+ io_lib:format("Must give an installed plugin to upgrade as an argument", []);
format_error({not_found, Plugin}) ->
io_lib:format("Plugin to upgrade not found: ~s", [Plugin]);
format_error(Reason) ->
@@ -44,25 +50,19 @@ format_error(Reason) ->
upgrade(Plugin, State) ->
Profiles = rebar_state:current_profiles(State),
- Dep = ec_lists:search(fun(Profile) ->
- Plugins = rebar_state:get(State, {plugins, Profile}, []),
- case find(list_to_atom(Plugin), Plugins) of
- false ->
- not_found;
- P ->
- {ok, P}
- end
- end, Profiles),
+ case find_plugin(Plugin, Profiles, State) of
+ not_found ->
+ Dep = find_plugin(Plugin, [global], State);
+ Dep ->
+ Dep
+ end,
case Dep of
not_found ->
?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, []),
@@ -76,6 +76,17 @@ upgrade(Plugin, State) ->
{ok, State}
end.
+find_plugin(Plugin, Profiles, State) ->
+ ec_lists:search(fun(Profile) ->
+ Plugins = rebar_state:get(State, {plugins, Profile}, []),
+ case find(list_to_atom(Plugin), Plugins) of
+ false ->
+ not_found;
+ P ->
+ {ok, P}
+ end
+ end, Profiles).
+
find(_Plugin, []) ->
false;
find(Plugin, [Plugin | _Plugins]) ->
diff --git a/src/rebar_prv_release.erl b/src/rebar_prv_release.erl
index 982b392..2cf9b23 100644
--- a/src/rebar_prv_release.erl
+++ b/src/rebar_prv_release.erl
@@ -32,35 +32,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- Caller = rebar_state:get(State, caller, api),
- 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, Caller}], AllOptions);
- Config ->
- relx:main([{lib_dirs, LibDirs}
- ,{config, lists:reverse(Config)}
- ,{output_dir, OutputDir}
- ,{caller, Caller}], 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
new file mode 100644
index 0000000..a4cd8ae
--- /dev/null
+++ b/src/rebar_prv_relup.erl
@@ -0,0 +1,40 @@
+%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 et
+
+-module(rebar_prv_relup).
+
+-behaviour(provider).
+
+-export([init/1,
+ do/1,
+ format_error/1]).
+
+-include("rebar.hrl").
+
+-define(PROVIDER, relup).
+-define(DEPS, [release]).
+
+%% ===================================================================
+%% Public API
+%% ===================================================================
+
+-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
+init(State) ->
+ Provider = providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, true},
+ {deps, ?DEPS},
+ {example, "rebar3 relup"},
+ {short_desc, "Create relup of releases."},
+ {desc, "Create relup of releases."},
+ {opts, relx:opt_spec_list()}]),
+ State1 = rebar_state:add_provider(State, Provider),
+ {ok, State1}.
+
+-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
+do(State) ->
+ rebar_relx:do(rlx_prv_release, "relup", ?PROVIDER, State).
+
+-spec format_error(any()) -> iolist().
+format_error(Reason) ->
+ io_lib:format("~p", [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 0c04d72..b3a12c0 100644
--- a/src/rebar_prv_tar.erl
+++ b/src/rebar_prv_tar.erl
@@ -12,7 +12,7 @@
-include("rebar.hrl").
-define(PROVIDER, tar).
--define(DEPS, [compile]).
+-define(DEPS, [release]).
%% ===================================================================
%% Public API
@@ -32,30 +32,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
- Caller = rebar_state:get(State, caller, api),
- 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", "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, Caller}], AllOptions);
- Config ->
- relx:main([{lib_dirs, LibDirs}
- ,{config, lists:reverse(Config)}
- ,{output_dir, OutputDir}
- ,{caller, Caller}], 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_state.erl b/src/rebar_state.erl
index 8125026..d0b28de 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -4,6 +4,8 @@
get/2, get/3, set/3,
+ format_error/1,
+
has_all_artifacts/1,
code_paths/2, code_paths/3, update_code_paths/3,
@@ -166,6 +168,9 @@ default(#state_t{default=Opts}) ->
default(State, Opts) ->
State#state_t{default=Opts}.
+format_error({profile_not_list, Profile, Other}) ->
+ io_lib:format("Profile config must be a list but for profile '~p' config given as:~n~p", [Profile, Other]).
+
-spec has_all_artifacts(rebar_app_info:t()) -> true | providers:error().
has_all_artifacts(State) ->
Artifacts = rebar_state:get(State, artifacts, []),
@@ -291,8 +296,13 @@ apply_profiles(State=#state_t{default = Defaults, current_profiles=CurrentProfil
lists:foldl(fun(default, OptsAcc) ->
OptsAcc;
(Profile, OptsAcc) ->
- ProfileOpts = dict:from_list(proplists:get_value(Profile, ConfigProfiles, [])),
- merge_opts(Profile, ProfileOpts, OptsAcc)
+ case proplists:get_value(Profile, ConfigProfiles, []) of
+ OptsList when is_list(OptsList) ->
+ ProfileOpts = dict:from_list(OptsList),
+ merge_opts(Profile, ProfileOpts, OptsAcc);
+ Other ->
+ throw(?PRV_ERROR({profile_not_list, Profile, Other}))
+ end
end, Defaults, AppliedProfiles),
State#state_t{current_profiles = AppliedProfiles, opts=NewOpts}.
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl
index 353fa36..3aa6e90 100644
--- a/src/rebar_templater.erl
+++ b/src/rebar_templater.erl
@@ -380,4 +380,4 @@ write_file(Output, Data, Force) ->
%% Render a binary to a string, using mustache and the specified context
%%
render(Bin, Context) ->
- mustache:render(ec_cnv:to_binary(Bin), Context, [{key_type, atom}]).
+ bbmustache:render(ec_cnv:to_binary(Bin), Context, [{key_type, atom}]).
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 7e72404..3f95e4f 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -19,7 +19,9 @@
delete_beam_if_source_deleted/1,
checkout_priority/1,
highest_version_of_pkg_dep/1,
- parse_transform_test/1]).
+ parse_transform_test/1,
+ erl_first_files_test/1,
+ mib_test/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -46,7 +48,8 @@ all() ->
build_all_srcdirs, recompile_when_hrl_changes,
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].
+ deps_in_path, checkout_priority, highest_version_of_pkg_dep,
+ parse_transform_test, erl_first_files_test, mib_test].
build_basic_app(Config) ->
AppDir = ?config(apps, Config),
@@ -161,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}]}),
@@ -272,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}]}),
@@ -305,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
@@ -441,3 +446,88 @@ parse_transform_test(Config) ->
EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
true = filelib:is_file(filename:join([EbinDir, "pascal.beam"])).
+
+erl_first_files_test(Config) ->
+ AppDir = ?config(apps, Config),
+ RebarConfig = [{erl_opts, [{parse_transform, mark_time}]},
+ {erl_first_files, ["src/mark_time.erl",
+ "src/b.erl",
+ "src/d.erl",
+ "src/a.erl"]}],
+
+ 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]),
+ rebar_test_utils:write_src_file(AppDir, "a.erl"),
+ rebar_test_utils:write_src_file(AppDir, "b.erl"),
+ rebar_test_utils:write_src_file(AppDir, "d.erl"),
+ rebar_test_utils:write_src_file(AppDir, "e.erl"),
+
+ ExtraSrc = <<"-module(mark_time). "
+ "-export([parse_transform/2]). "
+ "parse_transform([Form={attribute,_,module,Mod}|Forms], Options) -> "
+ " [Form, {attribute,1,number, os:timestamp()} | Forms];"
+ "parse_transform([Form|Forms], Options) -> "
+ " [Form | parse_transform(Forms, Options)].">>,
+
+ ok = file:write_file(filename:join([AppDir, "src", "mark_time.erl"]), ExtraSrc),
+
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name}]}),
+
+ EbinDir = filename:join([AppDir, "_build", "default", "lib", Name, "ebin"]),
+ true = filelib:is_file(filename:join([EbinDir, "mark_time.beam"])),
+
+ code:load_abs(filename:join([EbinDir, "a"])),
+ code:load_abs(filename:join([EbinDir, "b"])),
+ code:load_abs(filename:join([EbinDir, "d"])),
+ code:load_abs(filename:join([EbinDir, "e"])),
+ A = proplists:get_value(number, a:module_info(attributes)),
+ B = proplists:get_value(number, b:module_info(attributes)),
+ 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 3908ca1..85ca0e5 100644
--- a/test/rebar_hooks_SUITE.erl
+++ b/test/rebar_hooks_SUITE.erl
@@ -62,7 +62,7 @@ escriptize_artifacts(Config) ->
]),
{ok, RConf} = file:consult(RConfFile),
- try rebar_test_utils:run_and_check(Config, RConf, ["compile"], [])
+ try rebar_test_utils:run_and_check(Config, RConf, ["compile"], return)
catch
{error,
{rebar_prv_compile,
@@ -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 d1a1118..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}]}].
@@ -48,10 +49,10 @@ end_per_testcase(_, Config) ->
Config.
format_expected_deps(Deps) ->
- [case Dep of
- {N,V} -> {dep, N, V};
- N -> {dep, N}
- end || Dep <- Deps].
+ lists:append([case Dep of
+ {N,V} -> [{dep, N, V}, {lock, N, V}];
+ N -> [{dep, N}, {lock, N}]
+ end || Dep <- Deps]).
%% format:
%% {Spec,
@@ -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(
@@ -200,7 +232,7 @@ circular_skip(Config) -> run(Config).
fail_conflict(Config) ->
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
rebar_test_utils:run_and_check(
- Config, RebarConfig, ["install_deps"], ?config(expect, Config)
+ Config, RebarConfig, ["lock"], ?config(expect, Config)
),
check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
@@ -209,7 +241,7 @@ default_profile(Config) ->
AppDir = ?config(apps, Config),
{ok, Apps} = Expect = ?config(expect, Config),
rebar_test_utils:run_and_check(
- Config, RebarConfig, ["as", "profile", "install_deps"], Expect
+ Config, RebarConfig, ["as", "profile", "lock"], Expect
),
check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)),
BuildDir = filename:join([AppDir, "_build"]),
@@ -221,18 +253,30 @@ default_profile(Config) ->
|| {dep, App} <- Apps],
%% A second run to another profile also links default to the right spot
rebar_test_utils:run_and_check(
- Config, RebarConfig, ["as", "other", "install_deps"], Expect
+ Config, RebarConfig, ["as", "other", "lock"], Expect
),
[?assertMatch({ok, #file_info{type=directory}}, % somehow symlinks return dirs
file:read_file_info(filename:join([BuildDir, "other", "lib", App])))
|| {dep, App} <- Apps].
nondefault_profile(Config) ->
+ %% The dependencies here are saved directly to the
{ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
AppDir = ?config(apps, Config),
- {ok, Apps} = Expect = ?config(expect, Config),
+ {ok, AppLocks} = ?config(expect, Config),
+ try
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["as", "nondef", "lock"], {ok, AppLocks}
+ ),
+ error(generated_locks)
+ catch
+ error:generated_locks -> error(generated_locks);
+ _:_ -> ok
+ end,
+ Apps = [App || App = {dep, _} <- AppLocks],
+ Expect = {ok, Apps},
rebar_test_utils:run_and_check(
- Config, RebarConfig, ["as", "nondef", "install_deps"], Expect
+ Config, RebarConfig, ["as", "nondef", "lock"], Expect
),
check_warnings(error_calls(), ?config(warnings, Config), ?config(deps_type, Config)),
BuildDir = filename:join([AppDir, "_build"]),
@@ -244,17 +288,32 @@ nondefault_profile(Config) ->
|| {dep, App} <- Apps],
%% A second run to another profile doesn't link dependencies
rebar_test_utils:run_and_check(
- Config, RebarConfig, ["as", "other", "install_deps"], Expect
+ Config, RebarConfig, ["as", "other", "lock"], Expect
),
[?assertMatch({error, enoent},
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)),
rebar_test_utils:run_and_check(
- Config, RebarConfig, ["install_deps"], ?config(expect, Config)
+ Config, RebarConfig, ["lock"], ?config(expect, Config)
),
check_warnings(warning_calls(), ?config(warnings, Config), ?config(deps_type, Config)).
@@ -282,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 9c181d8..4a13e03 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -4,7 +4,7 @@
-export([init_rebar_state/1, init_rebar_state/2, run_and_check/4]).
-export([expand_deps/2, flat_deps/1, flat_pkgdeps/1, top_level_deps/1]).
-export([create_app/4, create_eunit_app/4, create_empty_app/4, create_config/2]).
--export([create_random_name/1, create_random_vsn/0]).
+-export([create_random_name/1, create_random_vsn/0, write_src_file/2]).
%%%%%%%%%%%%%%
%%% Public %%%
@@ -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.