summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml29
-rwxr-xr-xbootstrap28
-rw-r--r--manpages/rebar3.12
-rw-r--r--priv/shell-completion/fish/rebar3.fish2
-rw-r--r--priv/shell-completion/zsh/_rebar32
-rw-r--r--priv/templates/LICENSE220
-rw-r--r--priv/templates/Makefile6
-rw-r--r--priv/templates/gitignore1
-rw-r--r--priv/templates/otp_app.app.src2
-rw-r--r--priv/templates/otp_lib.app.src2
-rw-r--r--rebar.config19
-rw-r--r--rebar.lock16
-rw-r--r--src/r3.erl5
-rw-r--r--src/rebar3.erl14
-rw-r--r--src/rebar_agent.erl33
-rw-r--r--src/rebar_app_discover.erl158
-rw-r--r--src/rebar_app_info.erl65
-rw-r--r--src/rebar_app_utils.erl34
-rw-r--r--src/rebar_base_compiler.erl16
-rw-r--r--src/rebar_config.erl18
-rw-r--r--src/rebar_core.erl10
-rw-r--r--src/rebar_dialyzer_format.erl228
-rw-r--r--src/rebar_digraph.erl4
-rw-r--r--src/rebar_dir.erl4
-rw-r--r--src/rebar_dist_utils.erl25
-rw-r--r--src/rebar_erlc_compiler.erl29
-rw-r--r--src/rebar_fetch.erl22
-rw-r--r--src/rebar_file_utils.erl45
-rw-r--r--src/rebar_git_resource.erl61
-rw-r--r--src/rebar_hg_resource.erl23
-rw-r--r--src/rebar_hooks.erl6
-rw-r--r--src/rebar_log.erl4
-rw-r--r--src/rebar_opts.erl4
-rw-r--r--src/rebar_otp_app.erl8
-rw-r--r--src/rebar_packages.erl12
-rw-r--r--src/rebar_pkg_resource.erl18
-rw-r--r--src/rebar_prv_app_discovery.erl12
-rw-r--r--src/rebar_prv_as.erl6
-rw-r--r--src/rebar_prv_bare_compile.erl8
-rw-r--r--src/rebar_prv_clean.erl5
-rw-r--r--src/rebar_prv_common_test.erl71
-rw-r--r--src/rebar_prv_compile.erl8
-rw-r--r--src/rebar_prv_cover.erl14
-rw-r--r--src/rebar_prv_deps.erl20
-rw-r--r--src/rebar_prv_deps_tree.erl4
-rw-r--r--src/rebar_prv_dialyzer.erl18
-rw-r--r--src/rebar_prv_edoc.erl8
-rw-r--r--src/rebar_prv_escriptize.erl37
-rw-r--r--src/rebar_prv_eunit.erl17
-rw-r--r--src/rebar_prv_install_deps.erl52
-rw-r--r--src/rebar_prv_local_install.erl8
-rw-r--r--src/rebar_prv_new.erl20
-rw-r--r--src/rebar_prv_packages.erl6
-rw-r--r--src/rebar_prv_path.erl22
-rw-r--r--src/rebar_prv_plugins.erl21
-rw-r--r--src/rebar_prv_plugins_upgrade.erl2
-rw-r--r--src/rebar_prv_report.erl14
-rw-r--r--src/rebar_prv_shell.erl5
-rw-r--r--src/rebar_prv_unlock.erl4
-rw-r--r--src/rebar_prv_update.erl10
-rw-r--r--src/rebar_prv_upgrade.erl60
-rw-r--r--src/rebar_prv_xref.erl62
-rw-r--r--src/rebar_relx.erl12
-rw-r--r--src/rebar_state.erl6
-rw-r--r--src/rebar_templater.erl29
-rw-r--r--src/rebar_utils.erl69
-rw-r--r--test/rebar_as_SUITE.erl2
-rw-r--r--test/rebar_compile_SUITE.erl46
-rw-r--r--test/rebar_ct_SUITE.erl63
-rw-r--r--test/rebar_deps_SUITE.erl30
-rw-r--r--test/rebar_eunit_SUITE.erl5
-rw-r--r--test/rebar_hooks_SUITE.erl18
-rw-r--r--test/rebar_pkg_SUITE.erl2
-rw-r--r--test/rebar_profiles_SUITE.erl25
-rw-r--r--test/rebar_release_SUITE.erl25
-rw-r--r--test/rebar_src_dirs_SUITE.erl98
-rw-r--r--test/rebar_test_utils.erl12
-rw-r--r--test/rebar_upgrade_SUITE.erl93
-rw-r--r--test/rebar_xref_SUITE.erl59
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config12
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src16
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl26
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl35
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src17
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl26
-rw-r--r--test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl35
87 files changed, 1726 insertions, 725 deletions
diff --git a/.gitignore b/.gitignore
index 34b6ef0..129c935 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
_checkouts
.rebar3
rebar3
+rebar3.cmd
_build
.depsolver_plt
*.beam
diff --git a/.travis.yml b/.travis.yml
index ff4a252..b18dc76 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,22 @@
-sudo: false
language: erlang
-install: 'true'
-otp_release:
-- 19.1
-- 18.0
-- 17.5
-- R16B03-1
-- R15B03
-before_script: "./bootstrap"
-script: "./rebar3 ct"
+matrix:
+ include:
+ - os: linux
+ otp_release: R16B03-1
+ - os: linux
+ otp_release: 17.5
+ - os: linux
+ otp_release: 18.3
+ - os: linux
+ otp_release: 19.3
+ - os: osx
+ language: generic
+before_script:
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
+ ## should eventually use a tap that has previous erlang versions here
+ ## as this only uses the latest erlang available via brew
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install erlang; fi
+script: "./bootstrap && ./rebar3 ct"
branches:
only:
- master
@@ -23,7 +31,6 @@ deploy:
on:
repo: erlang/rebar3
tags: true
-
- provider: s3
access_key_id: AKIAJAPYAQEFYCYSNL7Q
secret_access_key:
diff --git a/bootstrap b/bootstrap
index 8b9b001..1bf1972 100755
--- a/bootstrap
+++ b/bootstrap
@@ -16,7 +16,7 @@ main(_) ->
,{getopt, []}
,{cf, []}
,{erlware_commons, ["ec_dictionary.erl", "ec_vsn.erl"]}
- ,{certifi, []}],
+ ,{certifi, ["certifi_pt.erl"]}],
Deps = get_deps(),
[fetch_and_compile(Dep, Deps) || Dep <- BaseDeps],
@@ -24,7 +24,7 @@ main(_) ->
bootstrap_rebar3(),
%% Build rebar.app from rebar.app.src
- {ok, App} = rebar_app_info:new(rebar, "3.3.5", filename:absname("_build/default/lib/rebar/")),
+ {ok, App} = rebar_app_info:new(rebar, "3.4.2", filename:absname("_build/default/lib/rebar/")),
rebar_otp_app:compile(rebar_state:new(), App),
%% Because we are compiling files that are loaded already we want to silence
@@ -52,21 +52,7 @@ main(_) ->
rebar3:run(["escriptize"]),
%% Done with compile, can turn back on error logger
- error_logger:tty(true),
-
- %% Finally, update executable perms for our script on *nix,
- %% or write out script files on win32.
- ec_file:copy("_build/default/bin/rebar3", "./rebar3"),
- case os:type() of
- {unix,_} ->
- [] = os:cmd("chmod u+x rebar3"),
- ok;
- {win32,_} ->
- write_windows_scripts(),
- ok;
- _ ->
- ok
- end.
+ error_logger:tty(true).
default_registry_file() ->
{ok, [[Home]]} = init:get_argument(home),
@@ -305,14 +291,6 @@ reset_env() ->
application:unload(rebar),
application:load(rebar).
-write_windows_scripts() ->
- CmdScript=
- "@echo off\r\n"
- "setlocal\r\n"
- "set rebarscript=%~f0\r\n"
- "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
- ok = file:write_file("rebar3.cmd", CmdScript).
-
get_deps() ->
case file:consult("rebar.lock") of
{ok, [[]]} ->
diff --git a/manpages/rebar3.1 b/manpages/rebar3.1
index 450e006..5c42f21 100644
--- a/manpages/rebar3.1
+++ b/manpages/rebar3.1
@@ -197,7 +197,7 @@ Create new project from templates.
\fBpath\fR [\fI--app\fR] [\fI--base\fR] [\fI--bin\fR] [\fI--ebin\fR] [\fI--lib\fR] [\fI--priv\fR] [\fI-s\fR|\fI--separator\fR] [\fI--src\fR] [\fI--rel\fR]
Print paths to build dirs in current profile.
.IP
-\fI--app\fR: Comma seperated list of applications to return paths for.
+\fI--app\fR: Comma separated list of applications to return paths for.
.IP
\fI--base\fR: Return the `base' path of the current profile.
.IP
diff --git a/priv/shell-completion/fish/rebar3.fish b/priv/shell-completion/fish/rebar3.fish
index fd28c97..9cd2c82 100644
--- a/priv/shell-completion/fish/rebar3.fish
+++ b/priv/shell-completion/fish/rebar3.fish
@@ -147,7 +147,7 @@ complete -f -c 'rebar3' -n '__fish_rebar3_using_command new' -s f -l force -d "O
complete -f -c 'rebar3' -n '__fish_rebar3_using_command new' -a help -d "Display all variables and arguments for each template"
complete -f -c 'rebar3' -n '__fish_rebar3_needs_command' -a paths -d "Print paths to build dirs in current profile."
-complete -f -c 'rebar3' -n '__fish_rebar3_needs_command paths' -l app -d "Comma seperated list of applications to return paths for."
+complete -f -c 'rebar3' -n '__fish_rebar3_needs_command paths' -l app -d "Comma separated list of applications to return paths for."
complete -f -c 'rebar3' -n '__fish_rebar3_needs_command paths' -l base -d "Return the `base` path of the current profile."
complete -f -c 'rebar3' -n '__fish_rebar3_needs_command paths' -l bin -d "Return the `bin` path of the current profile."
complete -f -c 'rebar3' -n '__fish_rebar3_needs_command paths' -l ebin -d "Return all `ebin` paths of the current profile`s applications."
diff --git a/priv/shell-completion/zsh/_rebar3 b/priv/shell-completion/zsh/_rebar3
index 0abc340..490a824 100644
--- a/priv/shell-completion/zsh/_rebar3
+++ b/priv/shell-completion/zsh/_rebar3
@@ -110,7 +110,7 @@ _rebar3 () {
;;
(path)
_arguments \
- '(--app)--app[Comma seperated list of applications to return paths for.]:apps' \
+ '(--app)--app[Comma separated list of applications to return paths for.]:apps' \
'(--base)--base[Return the `base` path of the current profile.]' \
'(--bin)--bin[Return the `bin` path of the current profile.]' \
'(--ebin)--ebin[Return all `ebin` paths of the current profile`s applications.]' \
diff --git a/priv/templates/LICENSE b/priv/templates/LICENSE
index 41588ab..59e1345 100644
--- a/priv/templates/LICENSE
+++ b/priv/templates/LICENSE
@@ -1,29 +1,191 @@
-Copyright (c) {{copyright_year}}, {{author_name}} <{{author_email}}>.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-* Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-* The names of its contributors may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright {{copyright_year}}, {{author_name}} <{{author_email}}>.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/priv/templates/Makefile b/priv/templates/Makefile
index d3c3767..5d490fd 100644
--- a/priv/templates/Makefile
+++ b/priv/templates/Makefile
@@ -6,9 +6,9 @@ BASEDIR := $(abspath $(CURDIR)/..)
PROJECT ?= $(notdir $(BASEDIR))
PROJECT := $(strip $(PROJECT))
-ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s/erts-~s/include/\", [code:root_dir(), erlang:system_info(version)]).")
-ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, include)]).")
-ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~s\", [code:lib_dir(erl_interface, lib)]).")
+ERTS_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts/erts-~ts/include/\", [code:root_dir(), erlang:system_info(version)]).")
+ERL_INTERFACE_INCLUDE_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts\", [code:lib_dir(erl_interface, include)]).")
+ERL_INTERFACE_LIB_DIR ?= $(shell erl -noshell -s init stop -eval "io:format(\"~ts\", [code:lib_dir(erl_interface, lib)]).")
C_SRC_DIR = $(CURDIR)
C_SRC_OUTPUT ?= $(CURDIR)/../priv/$(PROJECT).so
diff --git a/priv/templates/gitignore b/priv/templates/gitignore
index 468614d..40ca652 100644
--- a/priv/templates/gitignore
+++ b/priv/templates/gitignore
@@ -14,4 +14,5 @@ erl_crash.dump
logs
_build
.idea
+*.iml
rebar3.crashdump
diff --git a/priv/templates/otp_app.app.src b/priv/templates/otp_app.app.src
index c18f82c..d694d87 100644
--- a/priv/templates/otp_app.app.src
+++ b/priv/templates/otp_app.app.src
@@ -11,6 +11,6 @@
{modules, []},
{maintainers, []},
- {licenses, []},
+ {licenses, ["Apache 2.0"]},
{links, []}
]}.
diff --git a/priv/templates/otp_lib.app.src b/priv/templates/otp_lib.app.src
index 5b98a51..aa31966 100644
--- a/priv/templates/otp_lib.app.src
+++ b/priv/templates/otp_lib.app.src
@@ -10,6 +10,6 @@
{modules, []},
{maintainers, []},
- {licenses, []},
+ {licenses, ["Apache 2.0"]},
{links, []}
]}.
diff --git a/rebar.config b/rebar.config
index 1d853c4..2fe37ee 100644
--- a/rebar.config
+++ b/rebar.config
@@ -2,19 +2,24 @@
%% ex: ts=4 sw=4 ft=erlang et
{deps, [{erlware_commons, "1.0.0"},
- {ssl_verify_fun, "1.1.1"},
- {certifi, "0.4.0"},
+ {ssl_verify_fun, "1.1.2"},
+ {certifi, "2.0.0"},
{providers, "1.6.0"},
{getopt, "0.8.2"},
{bbmustache, "1.3.0"},
- {relx, "3.22.2"},
+ {relx, "3.23.1"},
{cf, "0.2.2"},
- {cth_readable, "1.2.3"},
+ {cth_readable, "1.3.0"},
{eunit_formatters, "0.3.1"}]}.
{post_hooks, [{"(linux|darwin|solaris|freebsd|netbsd|openbsd)",
escriptize,
- "cp $REBAR_BUILD_DIR/bin/rebar3 ./rebar3 && chmod u+x rebar3"}]}.
+ "cp \"$REBAR_BUILD_DIR/bin/rebar3\" ./rebar3"},
+ {"win32",
+ escriptize,
+ "robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ rebar3* "
+ "/njs /njh /nfl /ndl & exit /b 0"} % silence things
+ ]}.
{escript_name, rebar3}.
{escript_emu_args, "%%! +sbtu +A0\n"}.
@@ -33,8 +38,8 @@
%% Profiles
{profiles, [{test, [
- {deps, [{meck, "0.8.2"}]},
- {erl_opts, [debug_info]}
+ {deps, [{meck, "0.8.7"}]},
+ {erl_opts, [debug_info, nowarn_export_all]}
]
},
diff --git a/rebar.lock b/rebar.lock
index abcee59..7bf64e0 100644
--- a/rebar.lock
+++ b/rebar.lock
@@ -1,24 +1,24 @@
{"1.1.0",
[{<<"bbmustache">>,{pkg,<<"bbmustache">>,<<"1.3.0">>},0},
- {<<"certifi">>,{pkg,<<"certifi">>,<<"0.4.0">>},0},
+ {<<"certifi">>,{pkg,<<"certifi">>,<<"2.0.0">>},0},
{<<"cf">>,{pkg,<<"cf">>,<<"0.2.2">>},0},
- {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.2.3">>},0},
+ {<<"cth_readable">>,{pkg,<<"cth_readable">>,<<"1.3.0">>},0},
{<<"erlware_commons">>,{pkg,<<"erlware_commons">>,<<"1.0.0">>},0},
{<<"eunit_formatters">>,{pkg,<<"eunit_formatters">>,<<"0.3.1">>},0},
{<<"getopt">>,{pkg,<<"getopt">>,<<"0.8.2">>},0},
{<<"providers">>,{pkg,<<"providers">>,<<"1.6.0">>},0},
- {<<"relx">>,{pkg,<<"relx">>,<<"3.22.2">>},0},
- {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.1">>},0}]}.
+ {<<"relx">>,{pkg,<<"relx">>,<<"3.23.1">>},0},
+ {<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.2">>},0}]}.
[
{pkg_hash,[
{<<"bbmustache">>, <<"2010ADAE78830992A4C69680115ECD7D475DD03A72C076BBADDCCBF2D4B32035">>},
- {<<"certifi">>, <<"A7966EFB868B179023618D29A407548F70C52466BF1849B9E8EBD0E34B7EA11F">>},
+ {<<"certifi">>, <<"A0C0E475107135F76B8C1D5BC7EFB33CD3815CB3CF3DEA7AEFDD174DABEAD064">>},
{<<"cf">>, <<"7F2913FFF90ABCABD0F489896CFEB0B0674F6C8DF6C10B17A83175448029896C">>},
- {<<"cth_readable">>, <<"293120673DFF82F0768612C5282E35C40CACC1B6F94FE99077438FD3749D0E27">>},
+ {<<"cth_readable">>, <<"3F3B4C9CA1C96D5986557A033647A0D7072E25C241AE5EACD894D490EB656706">>},
{<<"erlware_commons">>, <<"087467DE5833C0BB5B3CCDD387F9E9C1FB816A75B7A709629BF24B5ED3246C51">>},
{<<"eunit_formatters">>, <<"7A6FC351EB5B873E2356B8852EB751E20C13A72FBCA03393CF682B8483509573">>},
{<<"getopt">>, <<"B17556DB683000BA50370B16C0619DF1337E7AF7ECBF7D64FBF8D1D6BCE3109B">>},
{<<"providers">>, <<"DB0E2F9043AE60C0155205FCD238D68516331D0E5146155E33D1E79DC452964A">>},
- {<<"relx">>, <<"AEE2EF6E9AC6D21D6661133B7A0BE6E81424DE9CDCA0012FC008BC677297C469">>},
- {<<"ssl_verify_fun">>, <<"28A4D65B7F59893BC2C7DE786DEC1E1555BD742D336043FE644AE956C3497FBE">>}]}
+ {<<"relx">>, <<"8AF4433934D9BB664E8282D2E45AC5DEAFF44859DDAABBE50CD7D885581CD24D">>},
+ {<<"ssl_verify_fun">>, <<"01289CAD67B280B7F8F7E87117966995FAD19236367386BE2A9D7716E92CE7FF">>}]}
].
diff --git a/src/r3.erl b/src/r3.erl
index d0d6c47..bbf9eea 100644
--- a/src/r3.erl
+++ b/src/r3.erl
@@ -2,6 +2,7 @@
%%% calls from a shell.
-module(r3).
-export([do/1, do/2]).
+-export(['$handle_undefined_function'/2]).
%% @doc alias for `rebar_agent:do/1'
-spec do(atom()) -> ok | {error, term()}.
@@ -10,3 +11,7 @@ do(Command) -> rebar_agent:do(Command).
%% @doc alias for `rebar_agent:do/2'
-spec do(atom(), atom()) -> ok | {error, term()}.
do(Namespace, Command) -> rebar_agent:do(Namespace, Command).
+
+%% @private defer to rebar_agent
+'$handle_undefined_function'(Cmd, Args) ->
+ rebar_agent:'$handle_undefined_function'(Cmd, Args).
diff --git a/src/rebar3.erl b/src/rebar3.erl
index 56bf3e8..eec8968 100644
--- a/src/rebar3.erl
+++ b/src/rebar3.erl
@@ -176,18 +176,18 @@ init_config() ->
Verbosity = log_level(),
ok = rebar_log:init(command_line, Verbosity),
- Config = rebar_config:consult(),
+ Config = rebar_config:consult_root(),
Config1 = rebar_config:merge_locks(Config, rebar_config:consult_lock_file(?LOCK_FILE)),
%% If $HOME/.config/rebar3/rebar.config exists load and use as global config
GlobalConfigFile = rebar_dir:global_config(),
State = case filelib:is_regular(GlobalConfigFile) of
true ->
- ?DEBUG("Load global config file ~s", [GlobalConfigFile]),
+ ?DEBUG("Load global config file ~ts", [GlobalConfigFile]),
try state_from_global_config(Config1, GlobalConfigFile)
catch
_:_ ->
- ?WARN("Global config ~s exists but can not be read. Ignoring global config values.", [GlobalConfigFile]),
+ ?WARN("Global config ~ts exists but can not be read. Ignoring global config values.", [GlobalConfigFile]),
rebar_state:new(Config1)
end;
false ->
@@ -270,7 +270,7 @@ log_level() ->
-spec version() -> ok.
version() ->
{ok, Vsn} = application:get_key(rebar, vsn),
- ?CONSOLE("rebar ~s on Erlang/OTP ~s Erts ~s",
+ ?CONSOLE("rebar ~ts on Erlang/OTP ~ts Erts ~ts",
[Vsn, erlang:system_info(otp_release), erlang:system_info(version)]).
%% @private set global flag based on getopt option boolean value
@@ -311,11 +311,11 @@ handle_error({error, {Module, Reason}}) ->
?DEBUG("Uncaught error: ~p ~p", [Module, Reason]),
?INFO("When submitting a bug report, please include the output of `rebar3 report \"your command\"`", []);
_ ->
- ?ERROR("~s", [Module:format_error(Reason)])
+ ?ERROR("~ts", [Module:format_error(Reason)])
end,
erlang:halt(1);
handle_error({error, Error}) when is_list(Error) ->
- ?ERROR("~s", [Error]),
+ ?ERROR("~ts", [Error]),
erlang:halt(1);
handle_error(Error) ->
%% Nothing should percolate up from rebar_core;
@@ -344,7 +344,7 @@ start_and_load_apps(Caller) ->
ensure_running(asn1, Caller),
ensure_running(public_key, Caller),
ensure_running(ssl, Caller),
- inets:start(),
+ ensure_running(inets, Caller),
inets:start(httpc, [{profile, rebar}]).
%% @doc Make sure a required app is running, or display an error message
diff --git a/src/rebar_agent.erl b/src/rebar_agent.erl
index ed9e45d..b5dcfcf 100644
--- a/src/rebar_agent.erl
+++ b/src/rebar_agent.erl
@@ -2,6 +2,7 @@
%%% to statefully maintain loaded project state into a running VM.
-module(rebar_agent).
-export([start_link/1, do/1, do/2]).
+-export(['$handle_undefined_function'/2]).
-export([init/1,
handle_call/3, handle_cast/2, handle_info/2,
code_change/3, terminate/2]).
@@ -22,13 +23,24 @@ start_link(State) ->
%% @doc runs a given command in the agent's context.
-spec do(atom()) -> ok | {error, term()}.
do(Command) when is_atom(Command) ->
- gen_server:call(?MODULE, {cmd, Command}, infinity).
+ gen_server:call(?MODULE, {cmd, Command}, infinity);
+do(Args) when is_list(Args) ->
+ gen_server:call(?MODULE, {cmd, default, do, Args}, infinity).
%% @doc runs a given command in the agent's context, under a given
%% namespace.
-spec do(atom(), atom()) -> ok | {error, term()}.
do(Namespace, Command) when is_atom(Namespace), is_atom(Command) ->
- gen_server:call(?MODULE, {cmd, Namespace, Command}, infinity).
+ gen_server:call(?MODULE, {cmd, Namespace, Command}, infinity);
+do(Namespace, Args) when is_atom(Namespace), is_list(Args) ->
+ gen_server:call(?MODULE, {cmd, Namespace, do, Args}, infinity).
+
+'$handle_undefined_function'(Cmd, [Namespace, Args]) ->
+ gen_server:call(?MODULE, {cmd, Namespace, Cmd, Args}, infinity);
+'$handle_undefined_function'(Cmd, [Args]) ->
+ gen_server:call(?MODULE, {cmd, default, Cmd, Args}, infinity);
+'$handle_undefined_function'(Cmd, []) ->
+ gen_server:call(?MODULE, {cmd, default, Cmd}, infinity).
%%%%%%%%%%%%%%%%%
%%% CALLBACKS %%%
@@ -42,11 +54,15 @@ init(State) ->
%% @private
handle_call({cmd, Command}, _From, State=#state{state=RState, cwd=Cwd}) ->
MidState = maybe_show_warning(State),
- {Res, NewRState} = run(default, Command, RState, Cwd),
+ {Res, NewRState} = run(default, Command, "", RState, Cwd),
{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),
+ {Res, NewRState} = run(Namespace, Command, "", RState, Cwd),
+ {reply, Res, MidState#state{state=NewRState}, hibernate};
+handle_call({cmd, Namespace, Command, Args}, _From, State = #state{state=RState, cwd=Cwd}) ->
+ MidState = maybe_show_warning(State),
+ {Res, NewRState} = run(Namespace, Command, Args, RState, Cwd),
{reply, Res, MidState#state{state=NewRState}, hibernate};
handle_call(_Call, _From, State) ->
{noreply, State}.
@@ -72,13 +88,14 @@ terminate(_Reason, _State) ->
%%%%%%%%%%%%%%%
%% @private runs the actual command and maintains the state changes
--spec run(atom(), atom(), rebar_state:t(), file:filename()) ->
+-spec run(atom(), atom(), string(), rebar_state:t(), file:filename()) ->
{ok, rebar_state:t()} | {{error, term()}, rebar_state:t()}.
-run(Namespace, Command, RState, Cwd) ->
+run(Namespace, Command, StrArgs, RState, Cwd) ->
try
case rebar_dir:get_cwd() of
Cwd ->
- Args = [atom_to_list(Namespace), atom_to_list(Command)],
+ PArgs = getopt:tokenize(StrArgs),
+ Args = [atom_to_list(Namespace), atom_to_list(Command)] ++ PArgs,
CmdState0 = refresh_state(RState, Cwd),
CmdState1 = rebar_state:set(CmdState0, task, atom_to_list(Command)),
CmdState = rebar_state:set(CmdState1, caller, api),
@@ -140,7 +157,7 @@ refresh_paths(RState) ->
{ok, Mods} ->
case {length(Mods), length(Mods -- Blacklist)} of
{X,X} ->
- ?DEBUG("reloading ~p from ~s", [Modules, Path]),
+ ?DEBUG("reloading ~p from ~ts", [Modules, Path]),
code:replace_path(App, Path),
reload_modules(Modules);
{_,_} ->
diff --git a/src/rebar_app_discover.erl b/src/rebar_app_discover.erl
index fd55960..cdd183c 100644
--- a/src/rebar_app_discover.erl
+++ b/src/rebar_app_discover.erl
@@ -7,8 +7,10 @@
find_unbuilt_apps/1,
find_apps/1,
find_apps/2,
+ find_apps/3,
find_app/2,
- find_app/3]).
+ find_app/3,
+ find_app/4]).
-include("rebar.hrl").
-include_lib("providers/include/providers.hrl").
@@ -20,7 +22,9 @@
do(State, LibDirs) ->
BaseDir = rebar_state:dir(State),
Dirs = [filename:join(BaseDir, LibDir) || LibDir <- LibDirs],
- Apps = find_apps(Dirs, all),
+ RebarOpts = rebar_state:opts(State),
+ SrcDirs = rebar_dir:src_dirs(RebarOpts, ["src"]),
+ Apps = find_apps(Dirs, SrcDirs, all),
ProjectDeps = rebar_state:deps_names(State),
DepsDir = rebar_dir:deps_dir(State),
CurrentProfiles = rebar_state:current_profiles(State),
@@ -56,7 +60,7 @@ do(State, LibDirs) ->
rebar_state:project_apps(StateAcc1
,rebar_app_info:deps(AppInfo2, ProjectDeps1));
false ->
- ?INFO("Ignoring ~s", [Name]),
+ ?INFO("Ignoring ~ts", [Name]),
StateAcc
end
end, State1, SortedApps).
@@ -93,11 +97,11 @@ merge_deps(AppInfo, State) ->
%% the application they are defined at. If an umbrella structure is used and
%% they are deifned at the top level they will instead run in the context of
%% the State and at the top level, not as part of an application.
- Default = reset_hooks(rebar_state:default(State)),
+ CurrentProfiles = rebar_state:current_profiles(State),
+ Default = reset_hooks(rebar_state:default(State), CurrentProfiles),
{C, State1} = project_app_config(AppInfo, State),
AppInfo0 = rebar_app_info:update_opts(AppInfo, Default, C),
- CurrentProfiles = rebar_state:current_profiles(State1),
Name = rebar_app_info:name(AppInfo0),
%% We reset the opts here to default so no profiles are applied multiple times
@@ -167,44 +171,72 @@ project_app_config(AppInfo, State) ->
maybe_reset_hooks(Dir, Opts, State) ->
case ec_file:real_dir_path(rebar_dir:root_dir(State)) of
Dir ->
- reset_hooks(Opts);
+ CurrentProfiles = rebar_state:current_profiles(State),
+ reset_hooks(Opts, CurrentProfiles);
_ ->
Opts
end.
%% @doc make the hooks empty for a given set of options
--spec reset_hooks(Opts) -> Opts when Opts :: rebar_dict().
-reset_hooks(Opts) ->
- lists:foldl(fun(Key, OptsAcc) ->
- rebar_opts:set(OptsAcc, Key, [])
- end, Opts, [post_hooks, pre_hooks, provider_hooks, artifacts]).
-
-%% @doc find the directories for all apps
--spec all_app_dirs([file:name()]) -> [file:name()].
+-spec reset_hooks(Opts, Profiles) ->
+ Opts when
+ Opts :: rebar_dict(),
+ Profiles :: [atom()].
+reset_hooks(Opts, CurrentProfiles) ->
+ AllHooks = [post_hooks, pre_hooks, provider_hooks, artifacts],
+ Opts1 = lists:foldl(fun(Key, OptsAcc) ->
+ rebar_opts:set(OptsAcc, Key, [])
+ end, Opts, AllHooks),
+ Profiles = rebar_opts:get(Opts1, profiles, []),
+ Profiles1 = lists:map(fun({P, ProfileOpts}) ->
+ case lists:member(P, CurrentProfiles) of
+ true ->
+ {P, [X || X={Key, _} <- ProfileOpts,
+ not lists:member(Key, AllHooks)]};
+ false ->
+ {P, ProfileOpts}
+ end
+ end, Profiles),
+ rebar_opts:set(Opts1, profiles, Profiles1).
+
+%% @private find the directories for all apps, while detecting their source dirs
+%% Returns the app dir with the respective src_dirs for them, in that order,
+%% for every app found.
+-spec all_app_dirs([file:name()]) -> [{file:name(), [file:name()]}].
all_app_dirs(LibDirs) ->
lists:flatmap(fun(LibDir) ->
- app_dirs(LibDir)
+ SrcDirs = find_config_src(LibDir, ["src"]),
+ app_dirs(LibDir, SrcDirs)
end, LibDirs).
-%% @doc find the directories based on the library directories
--spec app_dirs([file:name()]) -> [file:name()].
-app_dirs(LibDir) ->
- Path1 = filename:join([LibDir,
- "src",
- "*.app.src"]),
-
- Path2 = filename:join([LibDir,
- "src",
- "*.app.src.script"]),
-
- Path3 = filename:join([LibDir,
- "ebin",
- "*.app"]),
+%% @private find the directories for all apps based on their source dirs
+%% Returns the app dir with the respective src_dirs for them, in that order,
+%% for every app found.
+-spec all_app_dirs([file:name()], [file:name()]) -> [{file:name(), [file:name()]}].
+all_app_dirs(LibDirs, SrcDirs) ->
+ lists:flatmap(fun(LibDir) -> app_dirs(LibDir, SrcDirs) end, LibDirs).
+
+%% @private find the directories based on the library directories.
+%% Returns the app dir with the respective src_dirs for them, in that order,
+%% for every app found.
+%%
+%% The function returns the src directories since they might have been
+%% detected in a top-level loop and we want to skip further detection
+%% starting now.
+-spec app_dirs([file:name()], [file:name()]) -> [{file:name(), [file:name()]}].
+app_dirs(LibDir, SrcDirs) ->
+ Paths = lists:append([
+ [filename:join([LibDir, SrcDir, "*.app.src"]),
+ filename:join([LibDir, SrcDir, "*.app.src.script"])]
+ || SrcDir <- SrcDirs
+ ]),
+ EbinPath = filename:join([LibDir, "ebin", "*.app"]),
lists:usort(lists:foldl(fun(Path, Acc) ->
- Files = filelib:wildcard(ec_cnv:to_list(Path)),
- [app_dir(File) || File <- Files] ++ Acc
- end, [], [Path1, Path2, Path3])).
+ Files = filelib:wildcard(rebar_utils:to_list(Path)),
+ [{app_dir(File), SrcDirs}
+ || File <- Files] ++ Acc
+ end, [], [EbinPath | Paths])).
%% @doc find all apps that haven't been built in a list of directories
-spec find_unbuilt_apps([file:filename_all()]) -> [rebar_app_info:t()].
@@ -222,16 +254,32 @@ find_apps(LibDirs) ->
%% app info records.
-spec find_apps([file:filename_all()], valid | invalid | all) -> [rebar_app_info:t()].
find_apps(LibDirs, Validate) ->
- rebar_utils:filtermap(fun(AppDir) ->
- find_app(AppDir, Validate)
- end, all_app_dirs(LibDirs)).
+ rebar_utils:filtermap(
+ fun({AppDir, AppSrcDirs}) ->
+ find_app(rebar_app_info:new(), AppDir, AppSrcDirs, Validate)
+ end,
+ all_app_dirs(LibDirs)
+ ).
+
+%% @doc for each directory passed, with the configured source directories,
+%% find all apps according to the validity rule passed in.
+%% Returns all the related app info records.
+-spec find_apps([file:filename_all()], [file:filename_all()], valid | invalid | all) -> [rebar_app_info:t()].
+find_apps(LibDirs, SrcDirs, Validate) ->
+ rebar_utils:filtermap(
+ fun({AppDir, AppSrcDirs}) ->
+ find_app(rebar_app_info:new(), AppDir, AppSrcDirs, Validate)
+ end,
+ all_app_dirs(LibDirs, SrcDirs)
+ ).
%% @doc check that a given app in a directory is there, and whether it's
%% valid or not based on the second argument. Returns the related
%% app info record.
-spec find_app(file:filename_all(), valid | invalid | all) -> {true, rebar_app_info:t()} | false.
find_app(AppDir, Validate) ->
- find_app(rebar_app_info:new(), AppDir, Validate).
+ SrcDirs = find_config_src(AppDir, ["src"]),
+ find_app(rebar_app_info:new(), AppDir, SrcDirs, Validate).
%% @doc check that a given app in a directory is there, and whether it's
%% valid or not based on the second argument. Returns the related
@@ -239,9 +287,29 @@ find_app(AppDir, Validate) ->
-spec find_app(rebar_app_info:t(), file:filename_all(), valid | invalid | all) ->
{true, rebar_app_info:t()} | false.
find_app(AppInfo, AppDir, Validate) ->
+ %% if no src dir is passed, figure it out from the app info, with a default
+ %% of src/
+ AppOpts = rebar_app_info:opts(AppInfo),
+ SrcDirs = rebar_dir:src_dirs(AppOpts, ["src"]),
+ find_app(AppInfo, AppDir, SrcDirs, Validate).
+
+%% @doc check that a given app in a directory is there, and whether it's
+%% valid or not based on the second argument. The third argument includes
+%% the directories where source files can be located. Returns the related
+%% app info record.
+-spec find_app(rebar_app_info:t(), file:filename_all(),
+ [file:filename_all()], valid | invalid | all) ->
+ {true, rebar_app_info:t()} | false.
+find_app(AppInfo, AppDir, SrcDirs, Validate) ->
AppFile = filelib:wildcard(filename:join([AppDir, "ebin", "*.app"])),
- AppSrcFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src"])),
- AppSrcScriptFile = filelib:wildcard(filename:join([AppDir, "src", "*.app.src.script"])),
+ AppSrcFile = lists:append(
+ [filelib:wildcard(filename:join([AppDir, SrcDir, "*.app.src"]))
+ || SrcDir <- SrcDirs]
+ ),
+ AppSrcScriptFile = lists:append(
+ [filelib:wildcard(filename:join([AppDir, SrcDir, "*.app.src.script"]))
+ || SrcDir <- SrcDirs]
+ ),
try_handle_app_file(AppInfo, AppFile, AppDir, AppSrcFile, AppSrcScriptFile, Validate).
%% @doc find the directory that an appfile has
@@ -318,7 +386,7 @@ try_handle_app_file(AppInfo0, [File], AppDir, AppSrcFile, _, Validate) ->
end
catch
throw:{error, {Module, Reason}} ->
- ?DEBUG("Falling back to app.src file because .app failed: ~s", [Module:format_error(Reason)]),
+ ?DEBUG("Falling back to app.src file because .app failed: ~ts", [Module:format_error(Reason)]),
try_handle_app_src_file(AppInfo0, File, AppDir, AppSrcFile, Validate)
end;
try_handle_app_file(_AppInfo, Other, _AppDir, _AppSrcFile, _, _Validate) ->
@@ -358,3 +426,15 @@ enable(State, AppInfo) ->
-spec to_atom(binary()) -> atom().
to_atom(Bin) ->
list_to_atom(binary_to_list(Bin)).
+
+%% @private when looking for unknown apps, it's possible they have a
+%% rebar.config file specifying non-standard src_dirs. Check for a
+%% possible config file and extract src_dirs from it.
+find_config_src(AppDir, Default) ->
+ case rebar_config:consult(AppDir) of
+ [] ->
+ Default;
+ Terms ->
+ %% TODO: handle profiles I guess, but we don't have that info
+ proplists:get_value(src_dirs, Terms, Default)
+ end.
diff --git a/src/rebar_app_info.erl b/src/rebar_app_info.erl
index fdaadb8..050ccc1 100644
--- a/src/rebar_app_info.erl
+++ b/src/rebar_app_info.erl
@@ -107,43 +107,43 @@ new() ->
-spec new(atom() | binary() | string()) ->
{ok, t()}.
new(AppName) ->
- {ok, #app_info_t{name=ec_cnv:to_binary(AppName)}}.
+ {ok, #app_info_t{name=rebar_utils:to_binary(AppName)}}.
%% @doc Build a new app info value with only the name and version set.
-spec new(atom() | binary() | string(), binary() | string()) ->
{ok, t()}.
new(AppName, Vsn) ->
- {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
+ {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
original_vsn=Vsn}}.
%% @doc build a complete version of the app info with all fields set.
-spec new(atom() | binary() | string(), binary() | string(), file:name()) ->
{ok, t()}.
new(AppName, Vsn, Dir) ->
- {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
+ {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
original_vsn=Vsn,
- dir=ec_cnv:to_list(Dir),
- out_dir=ec_cnv:to_list(Dir)}}.
+ dir=rebar_utils:to_list(Dir),
+ out_dir=rebar_utils:to_list(Dir)}}.
%% @doc build a complete version of the app info with all fields set.
-spec new(atom() | binary() | string(), binary() | string(), file:name(), list()) ->
{ok, t()}.
new(AppName, Vsn, Dir, Deps) ->
- {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
+ {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
original_vsn=Vsn,
- dir=ec_cnv:to_list(Dir),
- out_dir=ec_cnv:to_list(Dir),
+ dir=rebar_utils:to_list(Dir),
+ out_dir=rebar_utils:to_list(Dir),
deps=Deps}}.
%% @doc build a complete version of the app info with all fields set.
-spec new(atom() | binary(), atom() | binary() | string(), binary() | string(), file:name(), list()) ->
{ok, t()}.
new(Parent, AppName, Vsn, Dir, Deps) ->
- {ok, #app_info_t{name=ec_cnv:to_binary(AppName),
+ {ok, #app_info_t{name=rebar_utils:to_binary(AppName),
parent=Parent,
original_vsn=Vsn,
- dir=ec_cnv:to_list(Dir),
- out_dir=ec_cnv:to_list(Dir),
+ dir=rebar_utils:to_list(Dir),
+ out_dir=rebar_utils:to_list(Dir),
deps=Deps}}.
%% @doc update the opts based on the contents of a config
@@ -199,7 +199,7 @@ name(#app_info_t{name=Name}) ->
%% @doc set the name of the app.
-spec name(t(), atom() | binary() | string()) -> t().
name(AppInfo=#app_info_t{}, AppName) ->
- AppInfo#app_info_t{name=ec_cnv:to_binary(AppName)}.
+ AppInfo#app_info_t{name=rebar_utils:to_binary(AppName)}.
%% @doc get the dictionary of options for the app.
-spec opts(t()) -> rebar_dict().
@@ -248,16 +248,15 @@ set(AppInfo=#app_info_t{opts=Opts}, Key, Value) ->
%% @doc finds the .app.src file for an app, if any.
-spec app_file_src(t()) -> file:filename_all() | undefined.
-app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name}) ->
- AppFileSrc = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src"]),
- case filelib:is_file(AppFileSrc) of
- true ->
- AppFileSrc;
- false ->
- undefined
+app_file_src(#app_info_t{app_file_src=undefined, dir=Dir, name=Name, opts=Opts}) ->
+ CandidatePaths = [filename:join([rebar_utils:to_list(Dir), Src, rebar_utils:to_list(Name)++".app.src"])
+ || Src <- rebar_opts:get(Opts, src_dirs, ["src"])],
+ case lists:dropwhile(fun(Path) -> not filelib:is_file(Path) end, CandidatePaths) of
+ [] -> undefined;
+ [AppFileSrc|_] -> AppFileSrc
end;
app_file_src(#app_info_t{app_file_src=AppFileSrc}) ->
- ec_cnv:to_list(AppFileSrc).
+ rebar_utils:to_list(AppFileSrc).
%% @doc sets the .app.src file for an app. An app without such a file
%% can explicitly be set with `undefined'.
@@ -265,12 +264,12 @@ app_file_src(#app_info_t{app_file_src=AppFileSrc}) ->
app_file_src(AppInfo=#app_info_t{}, undefined) ->
AppInfo#app_info_t{app_file_src=undefined};
app_file_src(AppInfo=#app_info_t{}, AppFileSrc) ->
- AppInfo#app_info_t{app_file_src=ec_cnv:to_list(AppFileSrc)}.
+ AppInfo#app_info_t{app_file_src=rebar_utils:to_list(AppFileSrc)}.
%% @doc finds the .app.src.script file for an app, if any.
-spec app_file_src_script(t()) -> file:filename_all() | undefined.
app_file_src_script(#app_info_t{app_file_src_script=undefined, dir=Dir, name=Name}) ->
- AppFileSrcScript = filename:join([ec_cnv:to_list(Dir), "src", ec_cnv:to_list(Name)++".app.src.script"]),
+ AppFileSrcScript = filename:join([rebar_utils:to_list(Dir), "src", rebar_utils:to_list(Name)++".app.src.script"]),
case filelib:is_file(AppFileSrcScript) of
true ->
AppFileSrcScript;
@@ -278,7 +277,7 @@ app_file_src_script(#app_info_t{app_file_src_script=undefined, dir=Dir, name=Nam
undefined
end;
app_file_src_script(#app_info_t{app_file_src_script=AppFileSrcScript}) ->
- ec_cnv:to_list(AppFileSrcScript).
+ rebar_utils:to_list(AppFileSrcScript).
%% @doc sets the .app.src.script file for an app. An app without such a file
%% can explicitly be set with `undefined'.
@@ -286,12 +285,12 @@ app_file_src_script(#app_info_t{app_file_src_script=AppFileSrcScript}) ->
app_file_src_script(AppInfo=#app_info_t{}, undefined) ->
AppInfo#app_info_t{app_file_src_script=undefined};
app_file_src_script(AppInfo=#app_info_t{}, AppFileSrcScript) ->
- AppInfo#app_info_t{app_file_src_script=ec_cnv:to_list(AppFileSrcScript)}.
+ AppInfo#app_info_t{app_file_src_script=rebar_utils:to_list(AppFileSrcScript)}.
%% @doc finds the .app file for an app, if any.
-spec app_file(t()) -> file:filename_all() | undefined.
app_file(#app_info_t{app_file=undefined, out_dir=Dir, name=Name}) ->
- AppFile = filename:join([ec_cnv:to_list(Dir), "ebin", ec_cnv:to_list(Name)++".app"]),
+ AppFile = filename:join([rebar_utils:to_list(Dir), "ebin", rebar_utils:to_list(Name)++".app"]),
case filelib:is_file(AppFile) of
true ->
AppFile;
@@ -318,7 +317,7 @@ app_details(AppInfo=#app_info_t{app_details=[]}) ->
rebar_file_utils:try_consult(AppFile)
catch
throw:{error, {Module, Reason}} ->
- ?DEBUG("Warning, falling back to .app.src because of: ~s",
+ ?DEBUG("Warning, falling back to .app.src because of: ~ts",
[Module:format_error(Reason)]),
rebar_file_utils:try_consult(app_file_src(AppInfo))
end
@@ -405,10 +404,10 @@ dir(#app_info_t{dir=Dir}) ->
%% @doc sets the directory that contains the app.
-spec dir(t(), file:name()) -> t().
dir(AppInfo=#app_info_t{out_dir=undefined}, Dir) ->
- AppInfo#app_info_t{dir=ec_cnv:to_list(Dir),
- out_dir=ec_cnv:to_list(Dir)};
+ AppInfo#app_info_t{dir=rebar_utils:to_list(Dir),
+ out_dir=rebar_utils:to_list(Dir)};
dir(AppInfo=#app_info_t{}, Dir) ->
- AppInfo#app_info_t{dir=ec_cnv:to_list(Dir)}.
+ AppInfo#app_info_t{dir=rebar_utils:to_list(Dir)}.
%% @doc returns the directory where build artifacts for the app
%% should go
@@ -420,17 +419,17 @@ out_dir(#app_info_t{out_dir=OutDir}) ->
%% should go
-spec out_dir(t(), file:name()) -> t().
out_dir(AppInfo=#app_info_t{}, OutDir) ->
- AppInfo#app_info_t{out_dir=ec_cnv:to_list(OutDir)}.
+ AppInfo#app_info_t{out_dir=rebar_utils:to_list(OutDir)}.
%% @doc gets the directory where ebin files for the app should go
-spec ebin_dir(t()) -> file:name().
ebin_dir(#app_info_t{out_dir=OutDir}) ->
- ec_cnv:to_list(filename:join(OutDir, "ebin")).
+ rebar_utils:to_list(filename:join(OutDir, "ebin")).
%% @doc gets the directory where private files for the app should go
-spec priv_dir(t()) -> file:name().
priv_dir(#app_info_t{out_dir=OutDir}) ->
- ec_cnv:to_list(filename:join(OutDir, "priv")).
+ rebar_utils:to_list(filename:join(OutDir, "priv")).
%% @doc returns whether the app is source app or a package app.
-spec resource_type(t()) -> pkg | src.
@@ -520,7 +519,7 @@ all(Dir, Context, [File|Artifacts]) ->
FilePath = filename:join(Dir, rebar_templater:render(File, Context)),
case filelib:is_regular(FilePath) of
false ->
- ?DEBUG("Missing artifact ~s", [FilePath]),
+ ?DEBUG("Missing artifact ~ts", [FilePath]),
{false, File};
true ->
all(Dir, Context, Artifacts)
diff --git a/src/rebar_app_utils.erl b/src/rebar_app_utils.erl
index 7154999..1d7ef5b 100644
--- a/src/rebar_app_utils.erl
+++ b/src/rebar_app_utils.erl
@@ -34,6 +34,7 @@
validate_application_info/2,
parse_deps/5,
parse_deps/6,
+ expand_deps_sources/2,
dep_to_app/7,
format_error/1]).
@@ -145,7 +146,7 @@ parse_dep(Dep, Parent, DepsDir, State, Locks, Level) ->
Dep ->
Dep
end,
- case lists:keyfind(ec_cnv:to_binary(Name), 1, Locks) of
+ case lists:keyfind(rebar_utils:to_binary(Name), 1, Locks) of
false ->
parse_dep(Parent, Dep, DepsDir, false, State);
LockedDep ->
@@ -167,18 +168,20 @@ parse_dep(Dep, Parent, DepsDir, State, Locks, Level) ->
IsLock :: boolean(),
State :: rebar_state:t().
parse_dep(Parent, {Name, Vsn, {pkg, PkgName}}, DepsDir, IsLock, State) ->
- {PkgName1, PkgVsn} = {ec_cnv:to_binary(PkgName), ec_cnv:to_binary(Vsn)},
+ {PkgName1, PkgVsn} = {rebar_utils:to_binary(PkgName),
+ rebar_utils:to_binary(Vsn)},
dep_to_app(Parent, DepsDir, Name, PkgVsn, {pkg, PkgName1, PkgVsn, undefined}, IsLock, State);
parse_dep(Parent, {Name, {pkg, PkgName}}, DepsDir, IsLock, State) ->
%% Package dependency with different package name from app name
- dep_to_app(Parent, DepsDir, Name, undefined, {pkg, ec_cnv:to_binary(PkgName), undefined, undefined}, IsLock, State);
+ dep_to_app(Parent, DepsDir, Name, undefined, {pkg, rebar_utils:to_binary(PkgName), undefined, undefined}, IsLock, State);
parse_dep(Parent, {Name, Vsn}, DepsDir, IsLock, State) when is_list(Vsn); is_binary(Vsn) ->
%% Versioned Package dependency
- {PkgName, PkgVsn} = {ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)},
+ {PkgName, PkgVsn} = {rebar_utils:to_binary(Name),
+ rebar_utils:to_binary(Vsn)},
dep_to_app(Parent, DepsDir, PkgName, PkgVsn, {pkg, PkgName, PkgVsn, undefined}, IsLock, State);
parse_dep(Parent, Name, DepsDir, IsLock, State) when is_atom(Name); is_binary(Name) ->
%% Unversioned package dependency
- dep_to_app(Parent, DepsDir, ec_cnv:to_binary(Name), undefined, {pkg, ec_cnv:to_binary(Name), undefined, undefined}, IsLock, State);
+ dep_to_app(Parent, DepsDir, rebar_utils:to_binary(Name), undefined, {pkg, rebar_utils:to_binary(Name), undefined, undefined}, IsLock, State);
parse_dep(Parent, {Name, Source}, DepsDir, IsLock, State) when is_tuple(Source) ->
dep_to_app(Parent, DepsDir, Name, [], Source, IsLock, State);
parse_dep(Parent, {Name, _Vsn, Source}, DepsDir, IsLock, State) when is_tuple(Source) ->
@@ -212,12 +215,12 @@ parse_dep(_, Dep, _, _, _) ->
IsLock :: boolean(),
State :: rebar_state:t().
dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State) ->
- CheckoutsDir = ec_cnv:to_list(rebar_dir:checkouts_dir(State, Name)),
+ CheckoutsDir = rebar_utils:to_list(rebar_dir:checkouts_dir(State, Name)),
AppInfo = case rebar_app_info:discover(CheckoutsDir) of
{ok, App} ->
rebar_app_info:source(rebar_app_info:is_checkout(App, true), checkout);
not_found ->
- Dir = ec_cnv:to_list(filename:join(DepsDir, Name)),
+ Dir = rebar_utils:to_list(filename:join(DepsDir, Name)),
{ok, AppInfo0} =
case rebar_app_info:discover(Dir) of
{ok, App} ->
@@ -225,7 +228,7 @@ dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State) ->
not_found ->
rebar_app_info:new(Parent, Name, Vsn, Dir, [])
end,
- update_source(AppInfo0, Source, State)
+ rebar_app_info:source(AppInfo0, Source)
end,
C = rebar_config:consult(rebar_app_info:dir(AppInfo)),
AppInfo1 = rebar_app_info:update_opts(AppInfo, rebar_app_info:opts(AppInfo), C),
@@ -236,6 +239,13 @@ dep_to_app(Parent, DepsDir, Name, Vsn, Source, IsLock, State) ->
AppInfo5 = rebar_app_info:profiles(AppInfo4, [default]),
rebar_app_info:is_lock(AppInfo5, IsLock).
+%% @doc Takes a given application app_info record along with the project.
+%% If the app is a package, resolve and expand the package definition.
+-spec expand_deps_sources(rebar_app_info:t(), rebar_state:t()) ->
+ rebar_app_info:t().
+expand_deps_sources(Dep, State) ->
+ update_source(Dep, rebar_app_info:source(Dep), State).
+
%% @doc sets the source for a given dependency or app along with metadata
%% around version if required.
-spec update_source(rebar_app_info:t(), Source, rebar_state:t()) ->
@@ -275,7 +285,7 @@ fetch_checksum(PkgName, PkgVsn, Hash, State) ->
rebar_packages:registry_checksum({pkg, PkgName, PkgVsn, Hash}, State)
catch
_:_ ->
- ?INFO("Package ~s-~s not found. Fetching registry updates and trying again...", [PkgName, PkgVsn]),
+ ?INFO("Package ~ts-~ts not found. Fetching registry updates and trying again...", [PkgName, PkgVsn]),
{ok, _} = rebar_prv_update:do(State),
rebar_packages:registry_checksum({pkg, PkgName, PkgVsn, Hash}, State)
end.
@@ -283,7 +293,7 @@ fetch_checksum(PkgName, PkgVsn, Hash, State) ->
%% @doc convert a given exception's payload into an io description.
-spec format_error(any()) -> iolist().
format_error({missing_package, Package}) ->
- io_lib:format("Package not found in registry: ~s", [Package]);
+ io_lib:format("Package not found in registry: ~ts", [Package]);
format_error({parse_dep, Dep}) ->
io_lib:format("Failed parsing dep ~p", [Dep]);
format_error(Error) ->
@@ -302,7 +312,7 @@ get_package(Dep, Vsn, State) ->
{ok, HighestDepVsn} ->
{Dep, HighestDepVsn};
none ->
- throw(?PRV_ERROR({missing_package, ec_cnv:to_binary(Dep)}))
+ throw(?PRV_ERROR({missing_package, rebar_utils:to_binary(Dep)}))
end.
%% @private checks that all the beam files have been properly
@@ -310,7 +320,7 @@ get_package(Dep, Vsn, State) ->
-spec has_all_beams(file:filename_all(), [module()]) ->
true | ?PRV_ERROR({missing_module, module()}).
has_all_beams(EbinDir, [Module | ModuleList]) ->
- BeamFile = filename:join([EbinDir, ec_cnv:to_list(Module) ++ ".beam"]),
+ BeamFile = filename:join([EbinDir, rebar_utils:to_list(Module) ++ ".beam"]),
case filelib:is_file(BeamFile) of
true ->
has_all_beams(EbinDir, ModuleList);
diff --git a/src/rebar_base_compiler.erl b/src/rebar_base_compiler.erl
index 480e49c..3f273f1 100644
--- a/src/rebar_base_compiler.erl
+++ b/src/rebar_base_compiler.erl
@@ -199,15 +199,15 @@ compile_each([], _Config, _CompileFn) ->
compile_each([Source | Rest], Config, CompileFn) ->
case CompileFn(Source, Config) of
ok ->
- ?DEBUG("~sCompiled ~s", [rebar_utils:indent(1), filename:basename(Source)]);
+ ?DEBUG("~tsCompiled ~ts", [rebar_utils:indent(1), filename:basename(Source)]);
{ok, Warnings} ->
report(Warnings),
- ?DEBUG("~sCompiled ~s", [rebar_utils:indent(1), filename:basename(Source)]);
+ ?DEBUG("~tsCompiled ~ts", [rebar_utils:indent(1), filename:basename(Source)]);
skipped ->
- ?DEBUG("~sSkipped ~s", [rebar_utils:indent(1), filename:basename(Source)]);
+ ?DEBUG("~tsSkipped ~ts", [rebar_utils:indent(1), filename:basename(Source)]);
Error ->
NewSource = format_error_source(Source, Config),
- ?ERROR("Compiling ~s failed", [NewSource]),
+ ?ERROR("Compiling ~ts failed", [NewSource]),
maybe_report(Error),
?DEBUG("Compilation failed: ~p", [Error]),
?FAIL
@@ -258,7 +258,7 @@ maybe_report(_) ->
%% @private Outputs a bunch of strings, including a newline
-spec report([string()]) -> ok.
report(Messages) ->
- lists:foreach(fun(Msg) -> io:format("~s~n", [Msg]) end, Messages).
+ lists:foreach(fun(Msg) -> io:format("~ts~n", [Msg]) end, Messages).
%% private format compiler errors into proper outputtable strings
-spec format_errors(_, Extra, [err_or_warn()]) -> [string()] when
@@ -274,10 +274,10 @@ format_errors(_MainSource, Extra, Errors) ->
Extra :: string().
format_error(Source, Extra, {{Line, Column}, Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
- ?FMT("~s:~w:~w: ~s~s~n", [Source, Line, Column, Extra, ErrorDesc]);
+ ?FMT("~ts:~w:~w: ~ts~ts~n", [Source, Line, Column, Extra, ErrorDesc]);
format_error(Source, Extra, {Line, Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
- ?FMT("~s:~w: ~s~s~n", [Source, Line, Extra, ErrorDesc]);
+ ?FMT("~ts:~w: ~ts~ts~n", [Source, Line, Extra, ErrorDesc]);
format_error(Source, Extra, {Mod, Desc}) ->
ErrorDesc = Mod:format_error(Desc),
- ?FMT("~s: ~s~s~n", [Source, Extra, ErrorDesc]).
+ ?FMT("~ts: ~ts~ts~n", [Source, Extra, ErrorDesc]).
diff --git a/src/rebar_config.erl b/src/rebar_config.erl
index 97e27ab..7316d83 100644
--- a/src/rebar_config.erl
+++ b/src/rebar_config.erl
@@ -26,7 +26,7 @@
%% -------------------------------------------------------------------
-module(rebar_config).
--export([consult/0
+-export([consult_root/0
,consult/1
,consult_app_file/1
,consult_file/1
@@ -46,15 +46,15 @@
%% Public API
%% ===================================================================
-%% @doc reads the default config file.
--spec consult() -> [any()].
-consult() ->
+%% @doc reads the default config file at the top of a full project
+-spec consult_root() -> [any()].
+consult_root() ->
consult_file(config_file()).
%% @doc reads the default config file in a given directory.
-spec consult(file:name()) -> [any()].
consult(Dir) ->
- consult_file(filename:join(Dir, config_file())).
+ consult_file(filename:join(Dir, ?DEFAULT_CONFIG_FILE)).
%% @doc reads a given app file, including the `.script' variations,
%% if any can be found.
@@ -120,7 +120,7 @@ write_lock_file(LockFile, Locks) ->
file:write_file(LockFile, io_lib:format("~p.~n", [NewLocks]));
_ ->
file:write_file(LockFile,
- io_lib:format("{~p,~n~p}.~n[~n~s~n].~n",
+ io_lib:format("{~p,~n~p}.~n[~n~ts~n].~n",
[?CONFIG_VERSION, NewLocks,
format_attrs(Attrs)]))
end.
@@ -359,7 +359,7 @@ check_newly_added_({Name, Source}, LockedDeps) ->
false
end;
check_newly_added_(Dep, LockedDeps) when is_atom(Dep) ->
- Name = ec_cnv:to_binary(Dep),
+ Name = rebar_utils:to_binary(Dep),
case lists:keyfind(Name, 1, LockedDeps) of
false ->
{true, Name};
@@ -368,8 +368,8 @@ check_newly_added_(Dep, LockedDeps) when is_atom(Dep) ->
0 ->
{true, Name};
_ ->
- ?WARN("Newly added dep ~s is locked at a lower level. "
- "If you really want to unlock it, use 'rebar3 upgrade ~s'",
+ ?WARN("Newly added dep ~ts is locked at a lower level. "
+ "If you really want to unlock it, use 'rebar3 upgrade ~ts'",
[Name, Name]),
false
end
diff --git a/src/rebar_core.erl b/src/rebar_core.erl
index 14c4906..3ef7a0d 100644
--- a/src/rebar_core.erl
+++ b/src/rebar_core.erl
@@ -119,11 +119,11 @@ process_command(State, Command) ->
State2 = rebar_state:command_parsed_args(State1, Args),
do(TargetProviders, State2);
{error, {invalid_option, Option}} ->
- {error, io_lib:format("Invalid option ~s on task ~p", [Option, Command])};
+ {error, io_lib:format("Invalid option ~ts on task ~p", [Option, Command])};
{error, {invalid_option_arg, {Option, Arg}}} ->
- {error, io_lib:format("Invalid argument ~s to option ~s", [Arg, Option])};
+ {error, io_lib:format("Invalid argument ~ts to option ~ts", [Arg, Option])};
{error, {missing_option_arg, Option}} ->
- {error, io_lib:format("Missing argument to option ~s", [Option])}
+ {error, io_lib:format("Missing argument to option ~ts", [Option])}
end
end
end.
@@ -173,6 +173,6 @@ do([ProviderName | Rest], State) ->
%% @doc convert a given exception's payload into an io description.
-spec format_error(any()) -> iolist().
format_error({bad_provider_namespace, {Namespace, Name}}) ->
- io_lib:format("Undefined command ~s in namespace ~s", [Name, Namespace]);
+ io_lib:format("Undefined command ~ts in namespace ~ts", [Name, Namespace]);
format_error({bad_provider_namespace, Name}) ->
- io_lib:format("Undefined command ~s", [Name]).
+ io_lib:format("Undefined command ~ts", [Name]).
diff --git a/src/rebar_dialyzer_format.erl b/src/rebar_dialyzer_format.erl
index 1d234c3..7cf4e63 100644
--- a/src/rebar_dialyzer_format.erl
+++ b/src/rebar_dialyzer_format.erl
@@ -31,7 +31,7 @@ format_warnings(Opts, Warnings) ->
format_warning_(_Opts, Warning = {_Tag, {File, Line}, Msg}, {File, Acc}) ->
try
String = message_to_string(Msg),
- {File, [lists:flatten(fmt("~!c~4w~!!: ~s", [Line, String])) | Acc]}
+ {File, [lists:flatten(fmt("~!c~4w~!!: ~ts", [Line, String])) | Acc]}
catch
Error:Reason ->
?DEBUG("Failed to pretty format warning: ~p:~p",
@@ -47,11 +47,11 @@ format_warning_(Opts, Warning = {_Tag, {SrcFile, Line}, Msg}, {_LastFile, Acc})
Dir = filename:dirname(File),
Root = filename:rootname(Base),
Ext = filename:extension(Base),
- Path = re:replace(Dir, "^.*/_build/", "_build/", [{return, list}]),
- Base1 = fmt("~!_c~s~!!~!__~s", [Root, Ext]),
- F = fmt("~!__~s", [filename:join(Path, Base1)]),
+ Path = re:replace(Dir, "^.*/_build/", "_build/", [{return, list}, unicode]),
+ Base1 = fmt("~!_c~ts~!!~!__~ts", [Root, Ext]),
+ F = fmt("~!__~ts", [filename:join(Path, Base1)]),
String = message_to_string(Msg),
- {SrcFile, [lists:flatten(fmt("~n~s~n~!c~4w~!!: ~s", [F, Line, String])) | Acc]}
+ {SrcFile, [lists:flatten(fmt("~n~ts~n~!c~4w~!!: ~ts", [F, Line, String])) | Acc]}
catch
Error:Reason ->
?DEBUG("Failed to pretty format warning: ~p:~p~n~p",
@@ -72,53 +72,53 @@ fmt(Fmt, Args) ->
%%----- Warnings for general discrepancies ----------------
message_to_string({apply, [Args, ArgNs, FailReason,
SigArgs, SigRet, Contract]}) ->
- fmt("~!^Fun application with arguments ~!!~s ",
+ fmt("~!^Fun application with arguments ~!!~ts ",
[bad_arg(ArgNs, Args)]) ++
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
message_to_string({app_call, [M, F, Args, Culprit, ExpectedType, FoundType]}) ->
- fmt("~!^The call~!! ~s:~s~s ~!^requires that"
- "~!! ~s ~!^is of type ~!g~s~!^ not ~!r~s",
+ fmt("~!^The call~!! ~ts:~ts~ts ~!^requires that"
+ "~!! ~ts ~!^is of type ~!g~ts~!^ not ~!r~ts",
[M, F, Args, Culprit, ExpectedType, FoundType]);
message_to_string({bin_construction, [Culprit, Size, Seg, Type]}) ->
- fmt("~!^Binary construction will fail since the ~!b~s~!^ field~!!"
- " ~s~!^ in segment~!! ~s~!^ has type~!! ~s",
+ fmt("~!^Binary construction will fail since the ~!b~ts~!^ field~!!"
+ " ~ts~!^ in segment~!! ~ts~!^ has type~!! ~ts",
[Culprit, Size, Seg, Type]);
message_to_string({call, [M, F, Args, ArgNs, FailReason,
SigArgs, SigRet, Contract]}) ->
- fmt("~!^The call~!! ~w:~w~s ", [M, F, bad_arg(ArgNs, Args)]) ++
+ fmt("~!^The call~!! ~w:~w~ts ", [M, F, bad_arg(ArgNs, Args)]) ++
call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet, Contract);
message_to_string({call_to_missing, [M, F, A]}) ->
fmt("~!^Call to missing or unexported function ~!!~w:~w/~w",
[M, F, A]);
message_to_string({exact_eq, [Type1, Op, Type2]}) ->
- fmt("~!^The test ~!!~s ~s ~s~!^ can never evaluate to 'true'",
+ fmt("~!^The test ~!!~ts ~ts ~ts~!^ can never evaluate to 'true'",
[Type1, Op, Type2]);
message_to_string({fun_app_args, [Args, Type]}) ->
- fmt("~!^Fun application with arguments ~!!~s~!^ will fail"
- " since the function has type ~!!~s", [Args, Type]);
+ fmt("~!^Fun application with arguments ~!!~ts~!^ will fail"
+ " since the function has type ~!!~ts", [Args, Type]);
message_to_string({fun_app_no_fun, [Op, Type, Arity]}) ->
- fmt("~!^Fun application will fail since ~!!~s ~!^::~!! ~s"
+ fmt("~!^Fun application will fail since ~!!~ts ~!^::~!! ~ts"
" is not a function of arity ~!!~w", [Op, Type, Arity]);
message_to_string({guard_fail, []}) ->
"~!^Clause guard cannot succeed.~!!";
message_to_string({guard_fail, [Arg1, Infix, Arg2]}) ->
- fmt("~!^Guard test ~!!~s ~s ~s~!^ can never succeed",
+ fmt("~!^Guard test ~!!~ts ~ts ~ts~!^ can never succeed",
[Arg1, Infix, Arg2]);
message_to_string({neg_guard_fail, [Arg1, Infix, Arg2]}) ->
- fmt("~!^Guard test not(~!!~s ~s ~s~!^) can never succeed",
+ fmt("~!^Guard test not(~!!~ts ~ts ~ts~!^) can never succeed",
[Arg1, Infix, Arg2]);
message_to_string({guard_fail, [Guard, Args]}) ->
- fmt("~!^Guard test ~!!~w~s~!^ can never succeed",
+ fmt("~!^Guard test ~!!~w~ts~!^ can never succeed",
[Guard, Args]);
message_to_string({neg_guard_fail, [Guard, Args]}) ->
- fmt("~!^Guard test not(~!!~w~s~!^) can never succeed",
+ fmt("~!^Guard test not(~!!~w~ts~!^) can never succeed",
[Guard, Args]);
message_to_string({guard_fail_pat, [Pat, Type]}) ->
- fmt("~!^Clause guard cannot succeed. The ~!!~s~!^ was matched"
- " against the type ~!!~s", [Pat, Type]);
+ fmt("~!^Clause guard cannot succeed. The ~!!~ts~!^ was matched"
+ " against the type ~!!~ts", [Pat, Type]);
message_to_string({improper_list_constr, [TlType]}) ->
fmt("~!^Cons will produce an improper list"
- " since its ~!b2~!!nd~!^ argument is~!! ~s", [TlType]);
+ " since its ~!b2~!!nd~!^ argument is~!! ~ts", [TlType]);
message_to_string({no_return, [Type|Name]}) ->
NameString =
case Name of
@@ -126,59 +126,59 @@ message_to_string({no_return, [Type|Name]}) ->
[F, A] -> fmt("~!^Function ~!r~w/~w ", [F, A])
end,
case Type of
- no_match -> fmt("~s~!^has no clauses that will ever match",[NameString]);
- only_explicit -> fmt("~s~!^only terminates with explicit exception", [NameString]);
- only_normal -> fmt("~s~!^has no local return", [NameString]);
- both -> fmt("~s~!^has no local return", [NameString])
+ no_match -> fmt("~ts~!^has no clauses that will ever match",[NameString]);
+ only_explicit -> fmt("~ts~!^only terminates with explicit exception", [NameString]);
+ only_normal -> fmt("~ts~!^has no local return", [NameString]);
+ both -> fmt("~ts~!^has no local return", [NameString])
end;
message_to_string({record_constr, [RecConstr, FieldDiffs]}) ->
- fmt("~!^Record construction ~!!~s~!^ violates the"
- " declared type of field ~!!~s", [RecConstr, FieldDiffs]);
+ fmt("~!^Record construction ~!!~ts~!^ violates the"
+ " declared type of field ~!!~ts", [RecConstr, FieldDiffs]);
message_to_string({record_constr, [Name, Field, Type]}) ->
fmt("~!^Record construction violates the declared type for ~!!#~w{}~!^"
- " since ~!!~s~!^ cannot be of type ~!!~s",
+ " since ~!!~ts~!^ cannot be of type ~!!~ts",
[Name, Field, Type]);
message_to_string({record_matching, [String, Name]}) ->
- fmt("~!^The ~!!~s~!^ violates the"
+ fmt("~!^The ~!!~ts~!^ violates the"
" declared type for ~!!#~w{}", [String, Name]);
message_to_string({record_match, [Pat, Type]}) ->
- fmt("~!^Matching of ~!!~s~!^ tagged with a record name violates the"
- " declared type of ~!!~s", [Pat, Type]);
+ fmt("~!^Matching of ~!!~ts~!^ tagged with a record name violates the"
+ " declared type of ~!!~ts", [Pat, Type]);
message_to_string({pattern_match, [Pat, Type]}) ->
- fmt("~!^The ~s~!^ can never match the type ~!g~s",
+ fmt("~!^The ~ts~!^ can never match the type ~!g~ts",
[bad_pat(Pat), Type]);
message_to_string({pattern_match_cov, [Pat, Type]}) ->
- fmt("~!^The ~s~!^ can never match since previous"
- " clauses completely covered the type ~!g~s",
+ fmt("~!^The ~ts~!^ can never match since previous"
+ " clauses completely covered the type ~!g~ts",
[bad_pat(Pat), Type]);
message_to_string({unmatched_return, [Type]}) ->
- fmt("~!^Expression produces a value of type ~!!~s~!^,"
+ fmt("~!^Expression produces a value of type ~!!~ts~!^,"
" but this value is unmatched", [Type]);
message_to_string({unused_fun, [F, A]}) ->
fmt("~!^Function ~!r~w/~w~!!~!^ will never be called", [F, A]);
%%----- Warnings for specs and contracts -------------------
message_to_string({contract_diff, [M, F, _A, Contract, Sig]}) ->
- fmt("~!^Type specification ~!!~w:~w~s~!^"
- " is not equal to the success typing: ~!!~w:~w~s",
+ fmt("~!^Type specification ~!!~w:~w~ts~!^"
+ " is not equal to the success typing: ~!!~w:~w~ts",
[M, F, Contract, M, F, Sig]);
message_to_string({contract_subtype, [M, F, _A, Contract, Sig]}) ->
- fmt("~!^Type specification ~!!~w:~w~s~!^"
- " is a subtype of the success typing: ~!!~w:~w~s",
+ fmt("~!^Type specification ~!!~w:~w~ts~!^"
+ " is a subtype of the success typing: ~!!~w:~w~ts",
[M, F, Contract, M, F, Sig]);
message_to_string({contract_supertype, [M, F, _A, Contract, Sig]}) ->
- fmt("~!^Type specification ~!!~w:~w~s~!^"
- " is a supertype of the success typing: ~!!~w:~w~s",
+ fmt("~!^Type specification ~!!~w:~w~ts~!^"
+ " is a supertype of the success typing: ~!!~w:~w~ts",
[M, F, Contract, M, F, Sig]);
message_to_string({contract_range, [Contract, M, F, ArgStrings, Line, CRet]}) ->
- fmt("~!^The contract ~!!~w:~w~s~!^ cannot be right because the"
- " inferred return for ~!!~w~s~!^ on line ~!!~w~!^ is ~!!~s",
+ fmt("~!^The contract ~!!~w:~w~ts~!^ cannot be right because the"
+ " inferred return for ~!!~w~ts~!^ on line ~!!~w~!^ is ~!!~ts",
[M, F, Contract, F, ArgStrings, Line, CRet]);
message_to_string({invalid_contract, [M, F, A, Sig]}) ->
fmt("~!^Invalid type specification for function~!! ~w:~w/~w."
- "~!^ The success typing is~!! ~s", [M, F, A, Sig]);
+ "~!^ The success typing is~!! ~ts", [M, F, A, Sig]);
message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) ->
fmt("~!^The specification for ~!!~w:~w/~w~!^ states that the function"
- " might also return ~!!~s~!^ but the inferred return is ~!!~s",
+ " might also return ~!!~ts~!^ but the inferred return is ~!!~ts",
[M, F, A, ExtraRanges, SigRange]);
message_to_string({overlapping_contract, [M, F, A]}) ->
fmt("~!^Overloaded contract for ~!!~w:~w/~w~!^ has overlapping"
@@ -189,62 +189,62 @@ message_to_string({spec_missing_fun, [M, F, A]}) ->
[M, F, A]);
%%----- Warnings for opaque type violations -------------------
message_to_string({call_with_opaque, [M, F, Args, ArgNs, ExpArgs]}) ->
- fmt("~!^The call ~!!~w:~w~s~!^ contains ~!!~s~!^ when ~!!~s",
+ fmt("~!^The call ~!!~w:~w~ts~!^ contains ~!!~ts~!^ when ~!!~ts",
[M, F, bad_arg(ArgNs, Args), form_positions(ArgNs), form_expected(ExpArgs)]);
message_to_string({call_without_opaque, [M, F, Args, [{N,_,_}|_] = ExpectedTriples]}) ->
- fmt("~!^The call ~!!~w:~w~s ~!^does not have~!! ~s",
+ fmt("~!^The call ~!!~w:~w~ts ~!^does not have~!! ~ts",
[M, F, bad_arg(N, Args), form_expected_without_opaque(ExpectedTriples)]);
message_to_string({opaque_eq, [Type, _Op, OpaqueType]}) ->
- fmt("~!^Attempt to test for equality between a term of type ~!!~s~!^"
- " and a term of opaque type ~!!~s", [Type, OpaqueType]);
+ fmt("~!^Attempt to test for equality between a term of type ~!!~ts~!^"
+ " and a term of opaque type ~!!~ts", [Type, OpaqueType]);
message_to_string({opaque_guard, [Arg1, Infix, Arg2, ArgNs]}) ->
- fmt("~!^Guard test ~!!~s ~s ~s~!^ contains ~!!~s",
+ fmt("~!^Guard test ~!!~ts ~ts ~ts~!^ contains ~!!~ts",
[Arg1, Infix, Arg2, form_positions(ArgNs)]);
message_to_string({opaque_guard, [Guard, Args]}) ->
- fmt("~!^Guard test ~!!~w~s~!^ breaks the opaqueness of its"
+ fmt("~!^Guard test ~!!~w~ts~!^ breaks the opaqueness of its"
" argument", [Guard, Args]);
message_to_string({opaque_match, [Pat, OpaqueType, OpaqueTerm]}) ->
Term = if OpaqueType =:= OpaqueTerm -> "the term";
true -> OpaqueTerm
end,
- fmt("~!^The attempt to match a term of type ~!!~s~!^ against the"
- "~!! ~s~!^ breaks the opaqueness of ~!!~s",
+ fmt("~!^The attempt to match a term of type ~!!~ts~!^ against the"
+ "~!! ~ts~!^ breaks the opaqueness of ~!!~ts",
[OpaqueType, Pat, Term]);
message_to_string({opaque_neq, [Type, _Op, OpaqueType]}) ->
- fmt("~!^Attempt to test for inequality between a term of type ~!!~s"
- "~!^ and a term of opaque type ~!!~s", [Type, OpaqueType]);
+ fmt("~!^Attempt to test for inequality between a term of type ~!!~ts"
+ "~!^ and a term of opaque type ~!!~ts", [Type, OpaqueType]);
message_to_string({opaque_type_test, [Fun, Args, Arg, ArgType]}) ->
- fmt("~!^The type test ~!!~s~s~!^ breaks the opaqueness of the term "
- "~!!~s~s", [Fun, Args, Arg, ArgType]);
+ fmt("~!^The type test ~!!~ts~ts~!^ breaks the opaqueness of the term "
+ "~!!~ts~ts", [Fun, Args, Arg, ArgType]);
message_to_string({opaque_size, [SizeType, Size]}) ->
- fmt("~!^The size ~!!~s~!^ breaks the opaqueness of ~!!~s",
+ fmt("~!^The size ~!!~ts~!^ breaks the opaqueness of ~!!~ts",
[SizeType, Size]);
message_to_string({opaque_call, [M, F, Args, Culprit, OpaqueType]}) ->
- fmt("~!^The call ~!!~s:~s~s~!^ breaks the opaqueness of the term~!!"
- " ~s :: ~s", [M, F, Args, Culprit, OpaqueType]);
+ fmt("~!^The call ~!!~ts:~ts~ts~!^ breaks the opaqueness of the term~!!"
+ " ~ts :: ~ts", [M, F, Args, Culprit, OpaqueType]);
%%----- Warnings for concurrency errors --------------------
message_to_string({race_condition, [M, F, Args, Reason]}) ->
- fmt("~!^The call ~!!~w:~w~s ~s", [M, F, Args, Reason]);
+ fmt("~!^The call ~!!~w:~w~ts ~ts", [M, F, Args, Reason]);
%%----- Warnings for behaviour errors --------------------
message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}) ->
- fmt("~!^The inferred return type of~!! ~w/~w (~s) ~!^"
- "has nothing in common with~!! ~s, ~!^which is the expected"
+ fmt("~!^The inferred return type of~!! ~w/~w (~ts) ~!^"
+ "has nothing in common with~!! ~ts, ~!^which is the expected"
" return type for the callback of~!! ~w ~!^behaviour",
[F, A, ST, CT, B]);
message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
- fmt("~!^The inferred type for the~!! ~s ~!^argument of~!!"
- " ~w/~w (~s) ~!^is not a supertype of~!! ~s~!^, which is"
+ fmt("~!^The inferred type for the~!! ~ts ~!^argument of~!!"
+ " ~w/~w (~ts) ~!^is not a supertype of~!! ~ts~!^, which is"
"expected type for this argument in the callback of the~!! ~w "
"~!^behaviour",
[ordinal(N), F, A, ST, CT, B]);
message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}) ->
- fmt("~!^The return type ~!!~s~!^ in the specification of ~!!"
- "~w/~w~!^ is not a subtype of ~!!~s~!^, which is the expected"
+ fmt("~!^The return type ~!!~ts~!^ in the specification of ~!!"
+ "~w/~w~!^ is not a subtype of ~!!~ts~!^, which is the expected"
" return type for the callback of ~!!~w~!^ behaviour",
[ST, F, A, CT, B]);
message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
- fmt("~!^The specified type for the ~!!~s~!^ argument of ~!!"
- "~w/~w (~s)~!^ is not a supertype of ~!!~s~!^, which is"
+ fmt("~!^The specified type for the ~!!~ts~!^ argument of ~!!"
+ "~w/~w (~ts)~!^ is not a supertype of ~!!~ts~!^, which is"
" expected type for this argument in the callback of the ~!!~w"
"~!^ behaviour", [ordinal(N), F, A, ST, CT, B]);
message_to_string({callback_missing, [B, F, A]}) ->
@@ -274,26 +274,26 @@ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet,
true ->
%% We do not know which argument(s) caused the failure
fmt("~!^will never return since the success typing arguments"
- " are ~!!~s", [SigArgs]);
+ " are ~!!~ts", [SigArgs]);
false ->
fmt("~!^will never return since it differs in the~!!"
- " ~s ~!^argument from the success typing"
- " arguments:~!! ~s",
+ " ~ts ~!^argument from the success typing"
+ " arguments:~!! ~ts",
[PositionString, good_arg(ArgNs, SigArgs)])
end;
only_contract ->
case (ArgNs =:= []) orelse IsOverloaded of
true ->
%% We do not know which arguments caused the failure
- fmt("~!^breaks the contract~!! ~s", [good_arg(ArgNs, Contract)]);
+ fmt("~!^breaks the contract~!! ~ts", [good_arg(ArgNs, Contract)]);
false ->
- fmt("~!^breaks the contract~!! ~s ~!^in the~!!"
- " ~s ~!^argument",
+ fmt("~!^breaks the contract~!! ~ts ~!^in the~!!"
+ " ~ts ~!^argument",
[good_arg(ArgNs, Contract), PositionString])
end;
both ->
fmt("~!^will never return since the success typing is "
- "~!!~s ~!^->~!! ~s ~!^and the contract is ~!!~s",
+ "~!!~ts ~!^->~!! ~ts ~!^and the contract is ~!!~ts",
[good_arg(ArgNs, SigArgs), SigRet,
good_arg(ArgNs, Contract)])
end.
@@ -301,8 +301,8 @@ call_or_apply_to_string(ArgNs, FailReason, SigArgs, SigRet,
form_positions(ArgNs) ->
ArgS = form_position_string(ArgNs),
case ArgNs of
- [_] -> fmt("~!^an opaque term as ~!!~s~!^ argument", [ArgS]);
- [_,_|_] -> fmt("~!^opaque terms as ~!!~s~!^ arguments", [ArgS])
+ [_] -> fmt("~!^an opaque term as ~!!~ts~!^ argument", [ArgS]);
+ [_,_|_] -> fmt("~!^opaque terms as ~!!~ts~!^ arguments", [ArgS])
end.
%% We know which positions N are to blame;
@@ -310,9 +310,9 @@ form_positions(ArgNs) ->
form_expected_without_opaque([{N, T, TStr}]) ->
FStr = case erl_types:t_is_opaque(T) of
true ->
- "~!^an opaque term of type~!g ~s ~!^as ";
+ "~!^an opaque term of type~!g ~ts ~!^as ";
false ->
- "~!^a term of type ~!g~s ~!^(with opaque subterms) as "
+ "~!^a term of type ~!g~ts ~!^(with opaque subterms) as "
end ++ form_position_string([N]) ++ "~!^ argument",
fmt(FStr, [TStr]);
@@ -325,9 +325,9 @@ form_expected(ExpectedArgs) ->
[T] ->
TS = erl_types:t_to_string(T),
case erl_types:t_is_opaque(T) of
- true -> fmt("~!^an opaque term of type ~!!~s~!^ is"
+ true -> fmt("~!^an opaque term of type ~!!~ts~!^ is"
" expected", [TS]);
- false -> fmt("~!^a structured term of type ~!!~s~!^ is"
+ false -> fmt("~!^a structured term of type ~!!~ts~!^ is"
" expected", [TS])
end;
[_,_|_] -> fmt("~!^terms of different types are expected in these"
@@ -340,7 +340,7 @@ form_position_string(ArgNs) ->
[N1] -> ordinal(N1);
[_,_|_] ->
[Last|Prevs] = lists:reverse(ArgNs),
- ", " ++ Head = lists:flatten([fmt(", ~s",[ordinal(N)]) ||
+ ", " ++ Head = lists:flatten([fmt(", ~ts",[ordinal(N)]) ||
N <- lists:reverse(Prevs)]),
Head ++ " and " ++ ordinal(Last)
end.
@@ -352,11 +352,11 @@ ordinal(N) when is_integer(N) -> fmt("~!B~w~!!th", [N]).
%% Format a pattern ad highlight errorous part in red.
bad_pat("pattern " ++ P) ->
- fmt("pattern ~!r~s",[P]);
+ fmt("pattern ~!r~ts",[P]);
bad_pat("variable " ++ P) ->
- fmt("variable ~!r~s",[P]);
+ fmt("variable ~!r~ts",[P]);
bad_pat(P) ->
- fmt("~!r~s",[P]).
+ fmt("~!r~ts",[P]).
bad_arg(N, Args) ->
@@ -370,7 +370,7 @@ good_arg(N, Args) ->
colour_arg(N, C, Args) when is_integer(N) ->
colour_arg([N], C, Args);
colour_arg(Ns, C, Args) ->
- {Args1, Rest} =seperate_args(Args),
+ {Args1, Rest} =separate_args(Args),
Args2 = highlight(Ns, 1, C, Args1),
join_args(Args2) ++ Rest.
@@ -378,53 +378,53 @@ highlight([], _N, _C, Rest) ->
Rest;
highlight([N | Nr], N, g, [Arg | Rest]) ->
- [fmt("~!g~s", [Arg]) | highlight(Nr, N+1, g, Rest)];
+ [fmt("~!g~ts", [Arg]) | highlight(Nr, N+1, g, Rest)];
highlight([N | Nr], N, r, [Arg | Rest]) ->
- [fmt("~!r~s", [Arg]) | highlight(Nr, N+1, r, Rest)];
+ [fmt("~!r~ts", [Arg]) | highlight(Nr, N+1, r, Rest)];
highlight(Ns, N, C, [Arg | Rest]) ->
[Arg | highlight(Ns, N + 1, C, Rest)].
%% Arugments to functions and constraints are passed as
%% strings not as data, this function pulls them apart
-%% to allow interacting with them seperately and not
+%% to allow interacting with them separately and not
%% as one bug chunk of data.
-seperate_args([$( | S]) ->
- seperate_args([], S, "", []).
+separate_args([$( | S]) ->
+ separate_args([], S, "", []).
%% We strip this space since dialyzer is inconsistant in adding or not adding
%% it ....
-seperate_args([], [$,, $\s | R], Arg, Args) ->
- seperate_args([], R, [], [lists:reverse(Arg) | Args]);
+separate_args([], [$,, $\s | R], Arg, Args) ->
+ separate_args([], R, [], [lists:reverse(Arg) | Args]);
-seperate_args([], [$, | R], Arg, Args) ->
- seperate_args([], R, [], [lists:reverse(Arg) | Args]);
+separate_args([], [$, | R], Arg, Args) ->
+ separate_args([], R, [], [lists:reverse(Arg) | Args]);
-seperate_args([], [$) | Rest], Arg, Args) ->
+separate_args([], [$) | Rest], Arg, Args) ->
{lists:reverse([lists:reverse(Arg) | Args]), Rest};
-seperate_args([C | D], [C | R], Arg, Args) ->
- seperate_args(D, R, [C | Arg], Args);
+separate_args([C | D], [C | R], Arg, Args) ->
+ separate_args(D, R, [C | Arg], Args);
%% Brackets
-seperate_args(D, [${ | R], Arg, Args) ->
- seperate_args([$}|D], R, [${ | Arg], Args);
+separate_args(D, [${ | R], Arg, Args) ->
+ separate_args([$}|D], R, [${ | Arg], Args);
-seperate_args(D, [$( | R], Arg, Args) ->
- seperate_args([$)|D], R, [$( | Arg], Args);
+separate_args(D, [$( | R], Arg, Args) ->
+ separate_args([$)|D], R, [$( | Arg], Args);
-seperate_args(D, [$[ | R], Arg, Args) ->
- seperate_args([$]|D], R, [$[ | Arg], Args);
+separate_args(D, [$[ | R], Arg, Args) ->
+ separate_args([$]|D], R, [$[ | Arg], Args);
-seperate_args(D, [$< | R], Arg, Args) ->
- seperate_args([$>|D], R, [$< | Arg], Args);
+separate_args(D, [$< | R], Arg, Args) ->
+ separate_args([$>|D], R, [$< | Arg], Args);
%% 'strings'
-seperate_args(D, [$' | R], Arg, Args) ->
- seperate_args([$'|D], R, [$' | Arg], Args);
-seperate_args(D, [$" | R], Arg, Args) ->
- seperate_args([$"|D], R, [$" | Arg], Args);
+separate_args(D, [$' | R], Arg, Args) ->
+ separate_args([$'|D], R, [$' | Arg], Args);
+separate_args(D, [$" | R], Arg, Args) ->
+ separate_args([$"|D], R, [$" | Arg], Args);
-seperate_args(D, [C | R], Arg, Args) ->
- seperate_args(D, R, [C | Arg], Args).
+separate_args(D, [C | R], Arg, Args) ->
+ separate_args(D, R, [C | Arg], Args).
join_args(Args) ->
[$(, string:join(Args, ", "), $)].
diff --git a/src/rebar_digraph.erl b/src/rebar_digraph.erl
index a827735..776d7b8 100644
--- a/src/rebar_digraph.erl
+++ b/src/rebar_digraph.erl
@@ -53,9 +53,9 @@ add(Graph, {PkgName, Deps}) ->
lists:foreach(fun(DepName) ->
Name1 = case DepName of
{Name, _Vsn} ->
- ec_cnv:to_binary(Name);
+ rebar_utils:to_binary(Name);
Name ->
- ec_cnv:to_binary(Name)
+ rebar_utils:to_binary(Name)
end,
V3 = case digraph:vertex(Graph, Name1) of
false ->
diff --git a/src/rebar_dir.erl b/src/rebar_dir.erl
index b61bfcc..d0c7805 100644
--- a/src/rebar_dir.erl
+++ b/src/rebar_dir.erl
@@ -41,7 +41,7 @@ base_dir(State) ->
%% of profiles.
-spec profile_dir(rebar_dict(), [atom()]) -> file:filename_all().
profile_dir(Opts, Profiles) ->
- {BaseDir, ProfilesStrings} = case [ec_cnv:to_list(P) || P <- Profiles] of
+ {BaseDir, ProfilesStrings} = case [rebar_utils:to_list(P) || P <- Profiles] of
["global" | _] -> {?MODULE:global_cache_dir(Opts), [""]};
["bootstrap", "default"] -> {rebar_opts:get(Opts, base_dir, ?DEFAULT_BASE_DIR), ["default"]};
["default"] -> {rebar_opts:get(Opts, base_dir, ?DEFAULT_BASE_DIR), ["default"]};
@@ -363,7 +363,7 @@ warn_source_format_once(Format) ->
ok;
true ->
?WARN("Invalid argument ~p for compiler_source_format - "
- "assuming ~s~n", [Format, ?DEFAULT_COMPILER_SOURCE_FORMAT])
+ "assuming ~ts~n", [Format, ?DEFAULT_COMPILER_SOURCE_FORMAT])
end.
%% @private takes a filename and canonicalizes its path if it is a link.
diff --git a/src/rebar_dist_utils.erl b/src/rebar_dist_utils.erl
index 93edf9d..5de858e 100644
--- a/src/rebar_dist_utils.erl
+++ b/src/rebar_dist_utils.erl
@@ -51,14 +51,27 @@ find_options(State) ->
%%% PRIVATE %%%
%%%%%%%%%%%%%%%
start(Name, Type, Opts) ->
- check_epmd(net_kernel:start([Name, Type])),
+ case dist_up(net_kernel:start([Name, Type])) of
+ false ->
+ start_epmd(),
+ dist_up(net_kernel:start([Name, Type])) orelse warn_dist();
+ true ->
+ ok
+ end,
setup_cookie(Opts).
-check_epmd({error,{{shutdown, {_,net_kernel,{'EXIT',nodistribution}}},_}}) ->
- ?ERROR("Erlang Distribution failed, falling back to nonode@nohost. "
- "Verify that epmd is running and try again.",[]);
-check_epmd(_) ->
- ok.
+dist_up({error,{{shutdown,{_,net_kernel,{'EXIT',nodistribution}}},_}}) -> false;
+dist_up(_) -> true.
+
+start_epmd() ->
+ %% Indirectly boot EPMD through calling Erlang so that we don't risk
+ %% attaching it to the current proc
+ ?CONSOLE("Attempting to start epmd...", []),
+ os:cmd("erl -sname a -eval 'halt(0).'").
+
+warn_dist() ->
+ ?ERROR("Erlang Distribution failed, falling back to nonode@nohost.", []).
+
setup_cookie(Opts) ->
case {node(), proplists:get_value(setcookie, Opts, nocookie)} of
diff --git a/src/rebar_erlc_compiler.erl b/src/rebar_erlc_compiler.erl
index f7244dc..94cbe13 100644
--- a/src/rebar_erlc_compiler.erl
+++ b/src/rebar_erlc_compiler.erl
@@ -92,7 +92,7 @@ compile(AppInfo) when element(1, AppInfo) == app_info_t ->
%% @doc compile an individual application.
-spec compile(rebar_app_info:t(), compile_opts()) -> ok.
compile(AppInfo, CompileOpts) when element(1, AppInfo) == app_info_t ->
- Dir = ec_cnv:to_list(rebar_app_info:out_dir(AppInfo)),
+ Dir = rebar_utils:to_list(rebar_app_info:out_dir(AppInfo)),
RebarOpts = rebar_app_info:opts(AppInfo),
SrcOpts = [check_last_mod,
@@ -237,8 +237,8 @@ clean(AppInfo) ->
YrlFiles = rebar_utils:find_files(filename:join([AppDir, "src"]), ?RE_PREFIX".*\\.[x|y]rl\$"),
rebar_file_utils:delete_each(
- [ binary_to_list(iolist_to_binary(re:replace(F, "\\.[x|y]rl$", ".erl")))
- || F <- YrlFiles ]),
+ [rebar_utils:to_list(re:replace(F, "\\.[x|y]rl$", ".erl", [unicode]))
+ || F <- YrlFiles]),
BinDirs = ["ebin"|rebar_dir:extra_src_dirs(rebar_app_info:opts(AppInfo))],
ok = clean_dirs(AppDir, BinDirs),
@@ -279,7 +279,7 @@ gather_src(Opts, BaseDirParts, [Dir|Rest], Srcs, CompileOpts) ->
end,
DirRecursive = dir_recursive(Opts, RelDir, CompileOpts),
gather_src(Opts, BaseDirParts, Rest, Srcs ++ rebar_utils:find_files(Dir, ?RE_PREFIX".*\\.erl\$", DirRecursive), CompileOpts).
-
+
%% Get files which need to be compiled first, i.e. those specified in erl_first_files
%% and parse_transform options. Also produce specific erl_opts for these first
%% files, so that yet to be compiled parse transformations are excluded from it.
@@ -339,7 +339,7 @@ maybe_rm_beam_and_edge(G, OutDir, Source) ->
false;
false ->
Target = target_base(OutDir, Source) ++ ".beam",
- ?DEBUG("Source ~s is gone, deleting previous beam file if it exists ~s", [Source, Target]),
+ ?DEBUG("Source ~ts is gone, deleting previous beam file if it exists ~ts", [Source, Target]),
file:delete(Target),
digraph:del_vertex(G, Source),
true
@@ -351,10 +351,25 @@ opts_changed(NewOpts, Target) ->
false -> NewOpts
end,
case compile_info(Target) of
- {ok, Opts} -> lists:sort(Opts) =/= lists:sort(TotalOpts);
+ {ok, Opts} -> lists:any(fun effects_code_generation/1, lists:usort(TotalOpts) -- lists:usort(Opts));
_ -> true
end.
+effects_code_generation(Option) ->
+ case Option of
+ beam -> false;
+ report_warnings -> false;
+ report_errors -> false;
+ return_errors-> false;
+ return_warnings-> false;
+ warnings_as_errors -> false;
+ binary -> false;
+ verbose -> false;
+ {cwd,_} -> false;
+ {outdir, _} -> false;
+ _ -> true
+ end.
+
compile_info(Target) ->
case beam_lib:chunks(Target, [compile_info]) of
{ok, {_mod, Chunks}} ->
@@ -385,7 +400,7 @@ init_erlcinfo(InclDirs, Erls, Dir, OutDir) ->
try restore_erlcinfo(G, InclDirs, Dir)
catch
_:_ ->
- ?WARN("Failed to restore ~s file. Discarding it.~n", [erlcinfo_file(Dir)]),
+ ?WARN("Failed to restore ~ts file. Discarding it.~n", [erlcinfo_file(Dir)]),
file:delete(erlcinfo_file(Dir))
end,
Dirs = source_and_include_dirs(InclDirs, Erls),
diff --git a/src/rebar_fetch.erl b/src/rebar_fetch.erl
index 47bfe1d..f68a54d 100644
--- a/src/rebar_fetch.erl
+++ b/src/rebar_fetch.erl
@@ -41,12 +41,12 @@ download_source_(AppDir, Source, State) ->
Resources = rebar_state:resources(State),
Module = get_resource_type(Source, Resources),
TmpDir = ec_file:insecure_mkdtemp(),
- AppDir1 = ec_cnv:to_list(AppDir),
+ AppDir1 = rebar_utils:to_list(AppDir),
case Module:download(TmpDir, Source, State) of
{ok, _} ->
ec_file:mkdir_p(AppDir1),
code:del_path(filename:absname(filename:join(AppDir1, "ebin"))),
- ec_file:remove(filename:absname(AppDir1), [recursive]),
+ ok = rebar_file_utils:rm_rf(filename:absname(AppDir1)),
?DEBUG("Moving checkout ~p to ~p", [TmpDir, filename:absname(AppDir1)]),
ok = rebar_file_utils:mv(TmpDir, filename:absname(AppDir1)),
true;
@@ -66,25 +66,25 @@ needs_update(AppDir, Source, State) ->
end.
format_error({bad_download, CachePath}) ->
- io_lib:format("Download of package does not match md5sum from server: ~s", [CachePath]);
+ io_lib:format("Download of package does not match md5sum from server: ~ts", [CachePath]);
format_error({unexpected_hash, CachePath, Expected, Found}) ->
- io_lib:format("The checksum for package at ~s (~s) does not match the "
- "checksum previously locked (~s). Either unlock or "
+ io_lib:format("The checksum for package at ~ts (~ts) does not match the "
+ "checksum previously locked (~ts). Either unlock or "
"upgrade the package, or make sure you fetched it from "
"the same index from which it was initially fetched.",
[CachePath, Found, Expected]);
format_error({failed_extract, CachePath}) ->
- io_lib:format("Failed to extract package: ~s", [CachePath]);
+ io_lib:format("Failed to extract package: ~ts", [CachePath]);
format_error({bad_etag, Source}) ->
- io_lib:format("MD5 Checksum comparison failed for: ~s", [Source]);
+ io_lib:format("MD5 Checksum comparison failed for: ~ts", [Source]);
format_error({fetch_fail, Name, Vsn}) ->
- io_lib:format("Failed to fetch and copy dep: ~s-~s", [Name, Vsn]);
+ io_lib:format("Failed to fetch and copy dep: ~ts-~ts", [Name, Vsn]);
format_error({fetch_fail, Source}) ->
io_lib:format("Failed to fetch and copy dep: ~p", [Source]);
format_error({bad_checksum, File}) ->
- io_lib:format("Checksum mismatch against tarball in ~s", [File]);
+ io_lib:format("Checksum mismatch against tarball in ~ts", [File]);
format_error({bad_registry_checksum, File}) ->
- io_lib:format("Checksum mismatch against registry in ~s", [File]).
+ io_lib:format("Checksum mismatch against registry in ~ts", [File]).
get_resource_type({Type, Location}, Resources) ->
find_resource_module(Type, Location, Resources);
@@ -100,7 +100,7 @@ find_resource_module(Type, Location, Resources) ->
false ->
case code:which(Type) of
non_existing ->
- {error, io_lib:format("Cannot handle dependency ~s.~n"
+ {error, io_lib:format("Cannot handle dependency ~ts.~n"
" No module for resource type ~p", [Location, Type])};
_ ->
Type
diff --git a/src/rebar_file_utils.erl b/src/rebar_file_utils.erl
index 8158312..d7716e5 100644
--- a/src/rebar_file_utils.erl
+++ b/src/rebar_file_utils.erl
@@ -84,7 +84,7 @@ consult_config(State, Filename) ->
[JoinedConfig].
format_error({bad_term_file, AppFile, Reason}) ->
- io_lib:format("Error reading file ~s: ~s", [AppFile, file:format_error(Reason)]).
+ io_lib:format("Error reading file ~ts: ~ts", [AppFile, file:format_error(Reason)]).
symlink_or_copy(Source, Target) ->
Link = case os:type() of
@@ -121,7 +121,7 @@ symlink_or_copy(Source, Target) ->
win32_symlink(Source, Target) ->
Res = rebar_utils:sh(
- ?FMT("cmd /c mklink /j \"~s\" \"~s\"",
+ ?FMT("cmd /c mklink /j \"~ts\" \"~ts\"",
[rebar_utils:escape_double_quotes(filename:nativename(Target)),
rebar_utils:escape_double_quotes(filename:nativename(Source))]),
[{use_stdout, false}, return_on_error]),
@@ -129,7 +129,7 @@ win32_symlink(Source, Target) ->
true -> ok;
false ->
{error, lists:flatten(
- io_lib:format("Failed to symlink ~s to ~s~n",
+ io_lib:format("Failed to symlink ~ts to ~ts~n",
[Source, Target]))}
end.
@@ -141,7 +141,7 @@ rm_rf(Target) ->
case os:type() of
{unix, _} ->
EscTarget = rebar_utils:escape_chars(Target),
- {ok, []} = rebar_utils:sh(?FMT("rm -rf ~s", [EscTarget]),
+ {ok, []} = rebar_utils:sh(?FMT("rm -rf ~ts", [EscTarget]),
[{use_stdout, false}, abort_on_error]),
ok;
{win32, _} ->
@@ -161,7 +161,7 @@ cp_r(Sources, Dest) ->
{unix, _} ->
EscSources = [rebar_utils:escape_chars(Src) || Src <- Sources],
SourceStr = string:join(EscSources, " "),
- {ok, []} = rebar_utils:sh(?FMT("cp -Rp ~s \"~s\"",
+ {ok, []} = rebar_utils:sh(?FMT("cp -Rp ~ts \"~ts\"",
[SourceStr, rebar_utils:escape_double_quotes(Dest)]),
[{use_stdout, false}, abort_on_error]),
ok;
@@ -176,7 +176,7 @@ mv(Source, Dest) ->
{unix, _} ->
EscSource = rebar_utils:escape_chars(Source),
EscDest = rebar_utils:escape_chars(Dest),
- case rebar_utils:sh(?FMT("mv ~s ~s", [EscSource, EscDest]),
+ case rebar_utils:sh(?FMT("mv ~ts ~ts", [EscSource, EscDest]),
[{use_stdout, false}, abort_on_error]) of
{ok, []} ->
ok;
@@ -234,7 +234,7 @@ robocopy_mv_and_rename(Source, Dest, SrcDir, SrcName, DestDir, DestName) ->
case ec_file:insecure_mkdtemp() of
{error, _Reason} ->
{error, lists:flatten(
- io_lib:format("Failed to move ~s to ~s (tmpdir failed)~n",
+ io_lib:format("Failed to move ~ts to ~ts (tmpdir failed)~n",
[Source, Dest]))};
TmpPath ->
case robocopy_file(SrcDir, TmpPath, SrcName) of
@@ -246,7 +246,7 @@ robocopy_mv_and_rename(Source, Dest, SrcDir, SrcName, DestDir, DestName) ->
case file:rename(TmpSrc, TmpDst) of
{error, _} ->
{error, lists:flatten(
- io_lib:format("Failed to move ~s to ~s (via rename)~n",
+ io_lib:format("Failed to move ~ts to ~ts (via rename)~n",
[Source, Dest]))};
ok ->
case robocopy_file(TmpPath, DestDir, DestName) of
@@ -258,7 +258,7 @@ robocopy_mv_and_rename(Source, Dest, SrcDir, SrcName, DestDir, DestName) ->
end.
robocopy_file(SrcPath, DestPath, FileName) ->
- Cmd = ?FMT("robocopy /move /e \"~s\" \"~s\" \"~s\"",
+ Cmd = ?FMT("robocopy /move /e \"~ts\" \"~ts\" \"~ts\"",
[rebar_utils:escape_double_quotes(SrcPath),
rebar_utils:escape_double_quotes(DestPath),
rebar_utils:escape_double_quotes(FileName)]),
@@ -266,7 +266,7 @@ robocopy_file(SrcPath, DestPath, FileName) ->
case win32_ok(Res) of
false ->
{error, lists:flatten(
- io_lib:format("Failed to move ~s to ~s~n",
+ io_lib:format("Failed to move ~ts to ~ts~n",
[filename:join(SrcPath, FileName),
filename:join(DestPath, FileName)]))};
true ->
@@ -274,7 +274,7 @@ robocopy_file(SrcPath, DestPath, FileName) ->
end.
robocopy_dir(Source, Dest) ->
- Cmd = ?FMT("robocopy /move /e \"~s\" \"~s\"",
+ Cmd = ?FMT("robocopy /move /e \"~ts\" \"~ts\"",
[rebar_utils:escape_double_quotes(Source),
rebar_utils:escape_double_quotes(Dest)]),
Res = rebar_utils:sh(Cmd,
@@ -283,7 +283,7 @@ robocopy_dir(Source, Dest) ->
true -> ok;
false ->
{error, lists:flatten(
- io_lib:format("Failed to move ~s to ~s~n",
+ io_lib:format("Failed to move ~ts to ~ts~n",
[Source, Dest]))}
end.
@@ -301,12 +301,19 @@ delete_each([File | Rest]) ->
{error, enoent} ->
delete_each(Rest);
{error, Reason} ->
- ?ERROR("Failed to delete file ~s: ~p\n", [File, Reason]),
+ ?ERROR("Failed to delete file ~ts: ~p\n", [File, Reason]),
?FAIL
end.
write_file_if_contents_differ(Filename, Bytes) ->
- ToWrite = iolist_to_binary(Bytes),
+ %% first try to convert directly to binaries,
+ %% but if it fails, we likely contain unicode and
+ %% need special treatment
+ ToWrite = try
+ iolist_to_binary(Bytes)
+ catch
+ error:badarg -> unicode:characters_to_binary(Bytes)
+ end,
case file:read_file(Filename) of
{ok, ToWrite} ->
ok;
@@ -401,13 +408,13 @@ split_dirname(Path) ->
delete_each_dir_win32([]) -> ok;
delete_each_dir_win32([Dir | Rest]) ->
- {ok, []} = rebar_utils:sh(?FMT("rd /q /s \"~s\"",
+ {ok, []} = rebar_utils:sh(?FMT("rd /q /s \"~ts\"",
[rebar_utils:escape_double_quotes(filename:nativename(Dir))]),
[{use_stdout, false}, return_on_error]),
delete_each_dir_win32(Rest).
xcopy_win32(Source,Dest)->
- %% "xcopy \"~s\" \"~s\" /q /y /e 2> nul", Changed to robocopy to
+ %% "xcopy \"~ts\" \"~ts\" /q /y /e 2> nul", Changed to robocopy to
%% handle long names. May have issues with older windows.
Cmd = case filelib:is_dir(Source) of
true ->
@@ -417,11 +424,11 @@ xcopy_win32(Source,Dest)->
%% must manually add the last fragment of a directory to the `Dest`
%% in order to properly replicate POSIX platforms
NewDest = filename:join([Dest, filename:basename(Source)]),
- ?FMT("robocopy \"~s\" \"~s\" /e /is 1> nul",
+ ?FMT("robocopy \"~ts\" \"~ts\" /e /is 1> nul",
[rebar_utils:escape_double_quotes(filename:nativename(Source)),
rebar_utils:escape_double_quotes(filename:nativename(NewDest))]);
false ->
- ?FMT("robocopy \"~s\" \"~s\" \"~s\" /e /is 1> nul",
+ ?FMT("robocopy \"~ts\" \"~ts\" \"~ts\" /e /is 1> nul",
[rebar_utils:escape_double_quotes(filename:nativename(filename:dirname(Source))),
rebar_utils:escape_double_quotes(filename:nativename(Dest)),
rebar_utils:escape_double_quotes(filename:basename(Source))])
@@ -432,7 +439,7 @@ xcopy_win32(Source,Dest)->
true -> ok;
false ->
{error, lists:flatten(
- io_lib:format("Failed to copy ~s to ~s~n",
+ io_lib:format("Failed to copy ~ts to ~ts~n",
[Source, Dest]))}
end.
diff --git a/src/rebar_git_resource.erl b/src/rebar_git_resource.erl
index 201b8b6..a6b4d00 100644
--- a/src/rebar_git_resource.erl
+++ b/src/rebar_git_resource.erl
@@ -17,7 +17,7 @@
lock(AppDir, {git, Url, _}) ->
lock(AppDir, {git, Url});
lock(AppDir, {git, Url}) ->
- AbortMsg = lists:flatten(io_lib:format("Locking of git dependency failed in ~s", [AppDir])),
+ AbortMsg = lists:flatten(io_lib:format("Locking of git dependency failed in ~ts", [AppDir])),
Dir = rebar_utils:escape_double_quotes(AppDir),
{ok, VsnString} =
case os:type() of
@@ -38,39 +38,37 @@ needs_update(Dir, {git, Url, {tag, Tag}}) ->
[{cd, Dir}]),
Current1 = string:strip(string:strip(Current, both, $\n), both, $\r),
- ?DEBUG("Comparing git tag ~s with ~s", [Tag, Current1]),
+ ?DEBUG("Comparing git tag ~ts with ~ts", [Tag, Current1]),
not ((Current1 =:= Tag) andalso compare_url(Dir, Url));
needs_update(Dir, {git, Url, {branch, Branch}}) ->
%% Fetch remote so we can check if the branch has changed
SafeBranch = rebar_utils:escape_chars(Branch),
- {ok, _} = rebar_utils:sh(?FMT("git fetch origin ~s", [SafeBranch]),
+ {ok, _} = rebar_utils:sh(?FMT("git fetch origin ~ts", [SafeBranch]),
[{cd, Dir}]),
%% Check for new commits to origin/Branch
- {ok, Current} = rebar_utils:sh(?FMT("git log HEAD..origin/~s --oneline", [SafeBranch]),
+ {ok, Current} = rebar_utils:sh(?FMT("git log HEAD..origin/~ts --oneline", [SafeBranch]),
[{cd, Dir}]),
- ?DEBUG("Checking git branch ~s for updates", [Branch]),
+ ?DEBUG("Checking git branch ~ts for updates", [Branch]),
not ((Current =:= []) andalso compare_url(Dir, Url));
needs_update(Dir, {git, Url, "master"}) ->
needs_update(Dir, {git, Url, {branch, "master"}});
needs_update(Dir, {git, _, Ref}) ->
- {ok, Current} = rebar_utils:sh(?FMT("git rev-parse -q HEAD", []),
+ {ok, Current} = rebar_utils:sh(?FMT("git rev-parse --short=7 -q HEAD", []),
[{cd, Dir}]),
Current1 = string:strip(string:strip(Current, both, $\n), both, $\r),
Ref2 = case Ref of
{ref, Ref1} ->
Length = length(Current1),
- if
- Length >= 7 ->
- lists:sublist(Ref1, Length);
- true ->
- Ref1
+ case Length >= 7 of
+ true -> lists:sublist(Ref1, Length);
+ false -> Ref1
end;
- Ref1 ->
- Ref1
+ _ ->
+ Ref
end,
- ?DEBUG("Comparing git ref ~s with ~s", [Ref1, Current1]),
+ ?DEBUG("Comparing git ref ~ts with ~ts", [Ref2, Current1]),
(Current1 =/= Ref2).
compare_url(Dir, Url) ->
@@ -84,7 +82,7 @@ compare_url(Dir, Url) ->
parse_git_url(Url) ->
%% Checks for standard scp style git remote
- case re:run(Url, ?SCP_PATTERN, [{capture, [host, path], list}]) of
+ case re:run(Url, ?SCP_PATTERN, [{capture, [host, path], list}, unicode]) of
{match, [Host, Path]} ->
{ok, {Host, filename:rootname(Path, ".git")}};
nomatch ->
@@ -121,41 +119,41 @@ download(Dir, {git, Url, Rev}, _State) ->
%% Use different git clone commands depending on git --version
git_clone(branch,Vsn,Url,Dir,Branch) when Vsn >= {1,7,10}; Vsn =:= undefined ->
- rebar_utils:sh(?FMT("git clone ~s ~s -b ~s --single-branch",
+ rebar_utils:sh(?FMT("git clone ~ts ~ts -b ~ts --single-branch",
[rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir)),
rebar_utils:escape_chars(Branch)]),
[{cd, filename:dirname(Dir)}]);
git_clone(branch,_Vsn,Url,Dir,Branch) ->
- rebar_utils:sh(?FMT("git clone ~s ~s -b ~s",
+ rebar_utils:sh(?FMT("git clone ~ts ~ts -b ~ts",
[rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir)),
rebar_utils:escape_chars(Branch)]),
[{cd, filename:dirname(Dir)}]);
git_clone(tag,Vsn,Url,Dir,Tag) when Vsn >= {1,7,10}; Vsn =:= undefined ->
- rebar_utils:sh(?FMT("git clone ~s ~s -b ~s --single-branch",
+ rebar_utils:sh(?FMT("git clone ~ts ~ts -b ~ts --single-branch",
[rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir)),
rebar_utils:escape_chars(Tag)]),
[{cd, filename:dirname(Dir)}]);
git_clone(tag,_Vsn,Url,Dir,Tag) ->
- rebar_utils:sh(?FMT("git clone ~s ~s -b ~s",
+ rebar_utils:sh(?FMT("git clone ~ts ~ts -b ~ts",
[rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir)),
rebar_utils:escape_chars(Tag)]),
[{cd, filename:dirname(Dir)}]);
git_clone(ref,_Vsn,Url,Dir,Ref) ->
- rebar_utils:sh(?FMT("git clone -n ~s ~s",
+ rebar_utils:sh(?FMT("git clone -n ~ts ~ts",
[rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir))]),
[{cd, filename:dirname(Dir)}]),
- rebar_utils:sh(?FMT("git checkout -q ~s", [Ref]), [{cd, Dir}]);
+ rebar_utils:sh(?FMT("git checkout -q ~ts", [Ref]), [{cd, Dir}]);
git_clone(rev,_Vsn,Url,Dir,Rev) ->
- rebar_utils:sh(?FMT("git clone -n ~s ~s",
+ rebar_utils:sh(?FMT("git clone -n ~ts ~ts",
[rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir))]),
[{cd, filename:dirname(Dir)}]),
- rebar_utils:sh(?FMT("git checkout -q ~s", [rebar_utils:escape_chars(Rev)]),
+ rebar_utils:sh(?FMT("git checkout -q ~ts", [rebar_utils:escape_chars(Rev)]),
[{cd, Dir}]).
git_vsn() ->
@@ -170,7 +168,7 @@ git_vsn() ->
git_vsn_fetch() ->
case rebar_utils:sh("git --version",[]) of
{ok, VsnStr} ->
- case re:run(VsnStr, "git version\\h+(\\d)\\.(\\d)\\.(\\d).*",[{capture,[1,2,3],list}]) of
+ case re:run(VsnStr, "git version\\h+(\\d)\\.(\\d)\\.(\\d).*", [{capture,[1,2,3],list}, unicode]) of
{match,[Maj,Min,Patch]} ->
{list_to_integer(Maj),
list_to_integer(Min),
@@ -200,7 +198,7 @@ collect_default_refcount(Dir) ->
return_on_error,
{cd, Dir}]) of
{error, _} ->
- ?WARN("Getting log of git dependency failed in ~s. Falling back to version 0.0.0", [rebar_dir:get_cwd()]),
+ ?WARN("Getting log of git dependency failed in ~ts. Falling back to version 0.0.0", [rebar_dir:get_cwd()]),
{plain, "0.0.0"};
{ok, String} ->
RawRef = string:strip(String, both, $\n),
@@ -224,21 +222,20 @@ collect_default_refcount(Dir) ->
build_vsn_string(Vsn, RawRef, Count) ->
%% Cleanup the tag and the Ref information. Basically leading 'v's and
%% whitespace needs to go away.
- RefTag = [".ref", re:replace(RawRef, "\\s", "", [global])],
+ RefTag = [".ref", re:replace(RawRef, "\\s", "", [global, unicode])],
%% Create the valid [semver](http://semver.org) version from the tag
case Count of
0 ->
- erlang:binary_to_list(erlang:iolist_to_binary(Vsn));
+ rebar_utils:to_list(Vsn);
_ ->
- erlang:binary_to_list(erlang:iolist_to_binary([Vsn, "+build.",
- integer_to_list(Count), RefTag]))
+ rebar_utils:to_list([Vsn, "+build.", integer_to_list(Count), RefTag])
end.
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 = re:replace(RawRef, "\\s", "", [global, unicode]),
+ Cmd = io_lib:format("git rev-list ~ts..HEAD",
[rebar_utils:escape_chars(Ref)]),
{ok, PatchLines} = rebar_utils:sh(Cmd,
[{use_stdout, false},
@@ -254,7 +251,7 @@ parse_tags(Dir) ->
{error, _} ->
{undefined, "0.0.0"};
{ok, Line} ->
- case re:run(Line, "(\\(|\\s)(HEAD[^,]*,\\s)tag:\\s(v?([^,\\)]+))", [{capture, [3, 4], list}]) of
+ case re:run(Line, "(\\(|\\s)(HEAD[^,]*,\\s)tag:\\s(v?([^,\\)]+))", [{capture, [3, 4], list}, unicode]) of
{match,[Tag, Vsn]} ->
{Tag, Vsn};
nomatch ->
diff --git a/src/rebar_hg_resource.erl b/src/rebar_hg_resource.erl
index 7d03eda..42e634c 100644
--- a/src/rebar_hg_resource.erl
+++ b/src/rebar_hg_resource.erl
@@ -22,7 +22,7 @@ lock(AppDir, {hg, Url}) ->
needs_update(Dir, {hg, Url, {tag, Tag}}) ->
Ref = get_ref(Dir),
{ClosestTag, Distance} = get_tag_distance(Dir, Ref),
- ?DEBUG("Comparing hg tag ~s with ref ~s (closest tag is ~s at distance ~s)",
+ ?DEBUG("Comparing hg tag ~ts with ref ~ts (closest tag is ~ts at distance ~ts)",
[Tag, Ref, ClosestTag, Distance]),
not ((Distance =:= "0") andalso (Tag =:= ClosestTag)
andalso compare_url(Dir, Url));
@@ -45,7 +45,7 @@ needs_update(Dir, {hg, Url, Ref}) ->
Ref1 ->
Ref1
end,
- ?DEBUG("Comparing hg ref ~s with ~s", [Ref1, LocalRef]),
+ ?DEBUG("Comparing hg ref ~ts with ~ts", [Ref1, LocalRef]),
not ((LocalRef =:= TargetRef) andalso compare_url(Dir, Url)).
download(Dir, {hg, Url}, State) ->
@@ -56,28 +56,28 @@ download(Dir, {hg, Url, ""}, State) ->
download(Dir, {hg, Url, {branch, "default"}}, State);
download(Dir, {hg, Url, {branch, Branch}}, _State) ->
ok = filelib:ensure_dir(Dir),
- rebar_utils:sh(?FMT("hg clone -q -b ~s ~s ~s",
+ rebar_utils:sh(?FMT("hg clone -q -b ~ts ~ts ~ts",
[rebar_utils:escape_chars(Branch),
rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir))]),
[{cd, filename:dirname(Dir)}]);
download(Dir, {hg, Url, {tag, Tag}}, _State) ->
ok = filelib:ensure_dir(Dir),
- rebar_utils:sh(?FMT("hg clone -q -u ~s ~s ~s",
+ rebar_utils:sh(?FMT("hg clone -q -u ~ts ~ts ~ts",
[rebar_utils:escape_chars(Tag),
rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir))]),
[{cd, filename:dirname(Dir)}]);
download(Dir, {hg, Url, {ref, Ref}}, _State) ->
ok = filelib:ensure_dir(Dir),
- rebar_utils:sh(?FMT("hg clone -q -r ~s ~s ~s",
+ rebar_utils:sh(?FMT("hg clone -q -r ~ts ~ts ~ts",
[rebar_utils:escape_chars(Ref),
rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir))]),
[{cd, filename:dirname(Dir)}]);
download(Dir, {hg, Url, Rev}, _State) ->
ok = filelib:ensure_dir(Dir),
- rebar_utils:sh(?FMT("hg clone -q -r ~s ~s ~s",
+ rebar_utils:sh(?FMT("hg clone -q -r ~ts ~ts ~ts",
[rebar_utils:escape_chars(Rev),
rebar_utils:escape_chars(Url),
rebar_utils:escape_chars(filename:basename(Dir))]),
@@ -88,7 +88,7 @@ make_vsn(Dir) ->
Ref = get_ref(Dir),
Cmd = BaseHg ++ "log --template \"{latesttag}+build.{latesttagdistance}.rev.{node|short}\""
" --rev " ++ Ref,
- AbortMsg = io_lib:format("Version resolution of hg dependency failed in ~s", [Dir]),
+ AbortMsg = io_lib:format("Version resolution of hg dependency failed in ~ts", [Dir]),
{ok, VsnString} =
rebar_utils:sh(Cmd,
[{use_stdout, false}, {debug_abort_on_error, AbortMsg}]),
@@ -108,14 +108,14 @@ compare_url(Dir, Url) ->
parse_hg_url(CurrentUrl1) =:= parse_hg_url(Url).
get_ref(Dir) ->
- AbortMsg = io_lib:format("Get ref of hg dependency failed in ~s", [Dir]),
+ AbortMsg = io_lib:format("Get ref of hg dependency failed in ~ts", [Dir]),
{ok, RefString} =
rebar_utils:sh("hg -R \"" ++ rebar_utils:escape_double_quotes(Dir) ++ "\" --debug id -i",
[{use_stdout, false}, {debug_abort_on_error, AbortMsg}]),
string:strip(RefString, both, $\n).
get_tag_distance(Dir, Ref) ->
- AbortMsg = io_lib:format("Get tag distance of hg dependency failed in ~s", [Dir]),
+ AbortMsg = io_lib:format("Get tag distance of hg dependency failed in ~ts", [Dir]),
{ok, LogString} =
rebar_utils:sh("hg -R \"" ++ rebar_utils:escape_double_quotes(Dir) ++ "\" "
"log --template \"{latesttag}-{latesttagdistance}\n\" "
@@ -123,11 +123,12 @@ get_tag_distance(Dir, Ref) ->
[{use_stdout, false}, {debug_abort_on_error, AbortMsg}]),
Log = string:strip(LogString,
both, $\n),
- [Tag, Distance] = re:split(Log, "-([0-9]+)$", [{parts,0}, {return, list}]),
+ [Tag, Distance] = re:split(Log, "-([0-9]+)$",
+ [{parts,0}, {return,list}, unicode]),
{Tag, Distance}.
get_branch_ref(Dir, Branch) ->
- AbortMsg = io_lib:format("Get branch ref of hg dependency failed in ~s", [Dir]),
+ AbortMsg = io_lib:format("Get branch ref of hg dependency failed in ~ts", [Dir]),
{ok, BranchRefString} =
rebar_utils:sh("hg -R \"" ++ rebar_utils:escape_double_quotes(Dir) ++
"\" log --template \"{node}\n\" --rev " ++ rebar_utils:escape_chars(Branch),
diff --git a/src/rebar_hooks.erl b/src/rebar_hooks.erl
index d6a0e2b..48aa928 100644
--- a/src/rebar_hooks.erl
+++ b/src/rebar_hooks.erl
@@ -57,9 +57,9 @@ run_provider_hooks_(Dir, Type, Command, Providers, TypeHooks, State) ->
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]);
+ io_lib:format("Unable to run ~ts 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]).
+ io_lib:format("Unable to run ~ts hooks for '~p', command '~p' not found.", [Type, Command, Name]).
%% @doc The following environment variables are exported when running
%% a hook (absolute paths):
@@ -143,7 +143,7 @@ join_dirs(BaseDir, Dirs) ->
string:join([ filename:join(BaseDir, Dir) || Dir <- Dirs ], ":").
re_version(Path) ->
- case re:run(Path, "^.*-(?<VER>[^/-]*)$", [{capture, [1], list}]) of
+ case re:run(Path, "^.*-(?<VER>[^/-]*)$", [{capture,[1],list}, unicode]) of
nomatch -> "";
{match, [Ver]} -> Ver
end.
diff --git a/src/rebar_log.erl b/src/rebar_log.erl
index b1a70c2..9150346 100644
--- a/src/rebar_log.erl
+++ b/src/rebar_log.erl
@@ -57,6 +57,8 @@ intensity() ->
high;
"low" ->
low;
+ "none" ->
+ none;
_ ->
?DFLT_INTENSITY
end,
@@ -92,7 +94,7 @@ get_level() ->
log(Level = error, Str, Args) ->
{ok, LogState} = application:get_env(rebar, log),
- ec_cmd_log:Level(LogState, lists:flatten(cf:format("~!^~s~n", [Str])), Args);
+ ec_cmd_log:Level(LogState, lists:flatten(cf:format("~!^~ts~n", [Str])), Args);
log(Level, Str, Args) ->
{ok, LogState} = application:get_env(rebar, log),
ec_cmd_log:Level(LogState, Str++"~n", Args).
diff --git a/src/rebar_opts.erl b/src/rebar_opts.erl
index 444b760..589dbb8 100644
--- a/src/rebar_opts.erl
+++ b/src/rebar_opts.erl
@@ -118,6 +118,10 @@ merge_opt({plugins, _}, NewValue, _OldValue) ->
NewValue;
merge_opt(profiles, NewValue, OldValue) ->
dict:to_list(merge_opts(dict:from_list(NewValue), dict:from_list(OldValue)));
+merge_opt(erl_first_files, Value, Value) ->
+ Value;
+merge_opt(erl_first_files, NewValue, OldValue) ->
+ OldValue ++ NewValue;
merge_opt(mib_first_files, Value, Value) ->
Value;
merge_opt(mib_first_files, NewValue, OldValue) ->
diff --git a/src/rebar_otp_app.erl b/src/rebar_otp_app.erl
index ddaa44b..ed573f2 100644
--- a/src/rebar_otp_app.erl
+++ b/src/rebar_otp_app.erl
@@ -58,11 +58,11 @@ compile(State, App) ->
validate_app(State, App1).
format_error({missing_app_file, Filename}) ->
- io_lib:format("App file is missing: ~s", [Filename]);
+ io_lib:format("App file is missing: ~ts", [Filename]);
format_error({file_read, File, Reason}) ->
- io_lib:format("Failed to read required file ~s for processing: ~s", [File, file:format_error(Reason)]);
+ io_lib:format("Failed to read required file ~ts for processing: ~ts", [File, file:format_error(Reason)]);
format_error({invalid_name, File, AppName}) ->
- io_lib:format("Invalid ~s: name of application (~p) must match filename.", [File, AppName]).
+ io_lib:format("Invalid ~ts: name of application (~p) must match filename.", [File, AppName]).
%% ===================================================================
%% Internal functions
@@ -222,7 +222,7 @@ app_vsn(AppData, AppFile, State) ->
get_value(Key, AppInfo, AppFile) ->
case proplists:get_value(Key, AppInfo) of
undefined ->
- ?ABORT("Failed to get app value '~p' from '~s'~n", [Key, AppFile]);
+ ?ABORT("Failed to get app value '~p' from '~ts'~n", [Key, AppFile]);
Value ->
Value
end.
diff --git a/src/rebar_packages.erl b/src/rebar_packages.erl
index 4cce5a8..cba1d16 100644
--- a/src/rebar_packages.erl
+++ b/src/rebar_packages.erl
@@ -72,12 +72,12 @@ deps(Name, Vsn, State) ->
deps_(Name, Vsn, State) ->
?MODULE:verify_table(State),
- ets:lookup_element(?PACKAGE_TABLE, {ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)}, 2).
+ ets:lookup_element(?PACKAGE_TABLE, {rebar_utils:to_binary(Name), rebar_utils:to_binary(Vsn)}, 2).
handle_missing_package(Dep, State, Fun) ->
case Dep of
{Name, Vsn} ->
- ?INFO("Package ~s-~s not found. Fetching registry updates and trying again...", [Name, Vsn]);
+ ?INFO("Package ~ts-~ts not found. Fetching registry updates and trying again...", [Name, Vsn]);
_ ->
?INFO("Package ~p not found. Fetching registry updates and trying again...", [Dep])
end,
@@ -128,7 +128,7 @@ registry_checksum({pkg, Name, Vsn, _Hash}, State) ->
ets:lookup_element(?PACKAGE_TABLE, {Name, Vsn}, 3)
catch
_:_ ->
- throw(?PRV_ERROR({missing_package, ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)}))
+ throw(?PRV_ERROR({missing_package, rebar_utils:to_binary(Name), rebar_utils:to_binary(Vsn)}))
end.
%% Hex supports use of ~> to specify the version required for a dependency.
@@ -207,17 +207,17 @@ handle_single_vsn(Pkg, PkgVsn, Dep, Vsn, Constraint) ->
false ->
case {Pkg, PkgVsn} of
{undefined, undefined} ->
- ?WARN("Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
+ ?DEBUG("Only existing version of ~ts is ~ts which does not match constraint ~~> ~ts. "
"Using anyway, but it is not guaranteed to work.", [Dep, Vsn, Constraint]);
_ ->
- ?WARN("[~s:~s] Only existing version of ~s is ~s which does not match constraint ~~> ~s. "
+ ?DEBUG("[~ts:~ts] Only existing version of ~ts is ~ts which does not match constraint ~~> ~ts. "
"Using anyway, but it is not guaranteed to work.", [Pkg, PkgVsn, Dep, Vsn, Constraint])
end,
{ok, Vsn}
end.
format_error({missing_package, Name, Vsn}) ->
- io_lib:format("Package not found in registry: ~s-~s.", [ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)]);
+ io_lib:format("Package not found in registry: ~ts-~ts.", [rebar_utils:to_binary(Name), rebar_utils:to_binary(Vsn)]);
format_error({missing_package, Dep}) ->
io_lib:format("Package not found in registry: ~p.", [Dep]).
diff --git a/src/rebar_pkg_resource.erl b/src/rebar_pkg_resource.erl
index 88419bd..d588f24 100644
--- a/src/rebar_pkg_resource.erl
+++ b/src/rebar_pkg_resource.erl
@@ -21,7 +21,7 @@ lock(_AppDir, Source) ->
needs_update(Dir, {pkg, _Name, Vsn, _Hash}) ->
[AppInfo] = rebar_app_discover:find_apps([Dir], all),
- case rebar_app_info:original_vsn(AppInfo) =:= ec_cnv:to_list(Vsn) of
+ case rebar_app_info:original_vsn(AppInfo) =:= rebar_utils:to_list(Vsn) of
true ->
false;
false ->
@@ -43,13 +43,13 @@ download(TmpDir, Pkg={pkg, Name, Vsn, _Hash}, State) ->
cached_download(TmpDir, CachePath, Pkg={pkg, Name, Vsn, _Hash}, Url, ETag, State) ->
case request(Url, ETag) of
{ok, cached} ->
- ?INFO("Version cached at ~s is up to date, reusing it", [CachePath]),
+ ?INFO("Version cached at ~ts is up to date, reusing it", [CachePath]),
serve_from_cache(TmpDir, CachePath, Pkg, State);
{ok, Body, NewETag} ->
- ?INFO("Downloaded package, caching at ~s", [CachePath]),
+ ?INFO("Downloaded package, caching at ~ts", [CachePath]),
serve_from_download(TmpDir, CachePath, Pkg, NewETag, Body, State);
error when ETag =/= false ->
- ?INFO("Download error, using cached file at ~s", [CachePath]),
+ ?INFO("Download error, using cached file at ~ts", [CachePath]),
serve_from_cache(TmpDir, CachePath, Pkg, State);
error ->
{fetch_fail, Name, Vsn}
@@ -76,13 +76,13 @@ serve_from_cache(TmpDir, CachePath, Pkg, State) ->
end.
serve_from_download(TmpDir, CachePath, Package, ETag, Binary, State) ->
- ?DEBUG("Writing ~p to cache at ~s", [Package, CachePath]),
+ ?DEBUG("Writing ~p to cache at ~ts", [Package, CachePath]),
file:write_file(CachePath, Binary),
case etag(CachePath) of
ETag ->
serve_from_cache(TmpDir, CachePath, Package, State);
FileETag ->
- ?DEBUG("Downloaded file ~s ETag ~s doesn't match returned ETag ~s", [CachePath, ETag, FileETag]),
+ ?DEBUG("Downloaded file ~ts ETag ~ts doesn't match returned ETag ~ts", [CachePath, ETag, FileETag]),
{bad_download, CachePath}
end.
@@ -114,11 +114,11 @@ request(Url, ETag) ->
[{body_format, binary}],
rebar) of
{ok, {{_Version, 200, _Reason}, Headers, Body}} ->
- ?DEBUG("Successfully downloaded ~s", [Url]),
+ ?DEBUG("Successfully downloaded ~ts", [Url]),
{"etag", ETag1} = lists:keyfind("etag", 1, Headers),
{ok, Body, string:strip(ETag1, both, $")};
{ok, {{_Version, 304, _Reason}, _Headers, _Body}} ->
- ?DEBUG("Cached copy of ~s still valid", [Url]),
+ ?DEBUG("Cached copy of ~ts still valid", [Url]),
{ok, cached};
{ok, {{_Version, Code, _Reason}, _Headers, _Body}} ->
?DEBUG("Request to ~p failed: status code ~p", [Url, Code]),
@@ -154,7 +154,7 @@ ssl_opts(Url) ->
ssl_opts(ssl_verify_enabled, Url) ->
case check_ssl_version() of
true ->
- {ok, {_, _, Hostname, _, _, _}} = http_uri:parse(ec_cnv:to_list(Url)),
+ {ok, {_, _, Hostname, _, _, _}} = http_uri:parse(rebar_utils:to_list(Url)),
VerifyFun = {fun ssl_verify_hostname:verify_fun/3, [{check_hostname, Hostname}]},
CACerts = certifi:cacerts(),
[{verify, verify_peer}, {depth, 2}, {cacerts, CACerts}
diff --git a/src/rebar_prv_app_discovery.erl b/src/rebar_prv_app_discovery.erl
index 1954214..3f10a3f 100644
--- a/src/rebar_prv_app_discovery.erl
+++ b/src/rebar_prv_app_discovery.erl
@@ -49,19 +49,19 @@ do(State) ->
-spec format_error(any()) -> iolist().
format_error({multiple_app_files, Files}) ->
- io_lib:format("Multiple app files found in one app dir: ~s", [string:join(Files, " and ")]);
+ io_lib:format("Multiple app files found in one app dir: ~ts", [string:join(Files, " and ")]);
format_error({invalid_app_file, File, Reason}) ->
case Reason of
{Line, erl_parse, Description} ->
- io_lib:format("Invalid app file ~s at line ~b: ~p",
+ io_lib:format("Invalid app file ~ts at line ~b: ~p",
[File, Line, lists:flatten(Description)]);
_ ->
- io_lib:format("Invalid app file ~s: ~p", [File, Reason])
+ io_lib:format("Invalid app file ~ts: ~p", [File, Reason])
end;
%% Provide a slightly more informative error message for consult of app file failure
format_error({rebar_file_utils, {bad_term_file, AppFile, Reason}}) ->
- io_lib:format("Error in app file ~s: ~s", [rebar_dir:make_relative_path(AppFile,
- rebar_dir:get_cwd()),
- file:format_error(Reason)]);
+ io_lib:format("Error in app file ~ts: ~ts", [rebar_dir:make_relative_path(AppFile,
+ rebar_dir:get_cwd()),
+ file:format_error(Reason)]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
diff --git a/src/rebar_prv_as.erl b/src/rebar_prv_as.erl
index e7c6d68..562ce99 100644
--- a/src/rebar_prv_as.erl
+++ b/src/rebar_prv_as.erl
@@ -64,7 +64,7 @@ args_to_profiles_and_tasks(Args) ->
first_profile([]) -> {[], []};
first_profile([ProfileList|Rest]) ->
- case re:split(ProfileList, ",", [{return, list}, {parts, 2}]) of
+ case re:split(ProfileList, ",", [{return, list}, {parts, 2}, unicode]) of
%% `foo, bar`
[P, ""] -> profiles(Rest, [P]);
%% `foo,bar`
@@ -75,7 +75,7 @@ first_profile([ProfileList|Rest]) ->
profiles([], Acc) -> {lists:reverse(Acc), rebar_utils:args_to_tasks([])};
profiles([ProfileList|Rest], Acc) ->
- case re:split(ProfileList, ",", [{return, list}, {parts, 2}]) of
+ case re:split(ProfileList, ",", [{return, list}, {parts, 2}, unicode]) of
%% `foo, bar`
[P, ""] -> profiles(Rest, [P|Acc]);
%% `foo,bar`
@@ -101,5 +101,5 @@ warn_on_empty_profile(Profiles, State) ->
ProjectApps = rebar_state:project_apps(State),
DefinedProfiles = rebar_state:get(State, profiles, []) ++
lists:flatten([rebar_app_info:get(AppInfo, profiles, []) || AppInfo <- ProjectApps]),
- [?WARN("No entry for profile ~s in config.", [Profile]) ||
+ [?WARN("No entry for profile ~ts in config.", [Profile]) ||
Profile <- Profiles, not(lists:keymember(list_to_atom(Profile), 1, DefinedProfiles))].
diff --git a/src/rebar_prv_bare_compile.erl b/src/rebar_prv_bare_compile.erl
index 201620a..6f1ac16 100644
--- a/src/rebar_prv_bare_compile.erl
+++ b/src/rebar_prv_bare_compile.erl
@@ -29,7 +29,8 @@ init(State) ->
{example, ""},
{short_desc, ""},
{desc, ""},
- {opts, [{paths, $p, "paths", string, "Wildcard path of ebin directories to add to code path"}]}])),
+ {opts, [{paths, $p, "paths", string, "Wildcard paths of ebin directories to add to code path, separated by a colon"},
+ {separator, $s, "separator", string, "In case of multiple return paths, the separator character to use to join them."}]}])),
{ok, State1}.
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
@@ -39,8 +40,9 @@ do(State) ->
%% Add code paths from --paths to the beginning of the code path
{RawOpts, _} = rebar_state:command_parsed_args(State),
Paths = proplists:get_value(paths, RawOpts),
- CodePaths = filelib:wildcard(Paths),
- code:add_pathsa(CodePaths),
+ Sep = proplists:get_value(separator, RawOpts, " "),
+ [ code:add_pathsa(filelib:wildcard(PathWildcard))
+ || PathWildcard <- string:tokens(Paths, Sep) ],
[AppInfo] = rebar_state:project_apps(State),
AppInfo1 = rebar_app_info:out_dir(AppInfo, rebar_dir:get_cwd()),
diff --git a/src/rebar_prv_clean.erl b/src/rebar_prv_clean.erl
index 8f31fdd..aa0b5af 100644
--- a/src/rebar_prv_clean.erl
+++ b/src/rebar_prv_clean.erl
@@ -44,7 +44,8 @@ do(State) ->
case All of
true ->
DepsDir = rebar_dir:deps_dir(State1),
- AllApps = rebar_app_discover:find_apps([filename:join(DepsDir, "*")], all),
+ DepsDirs = filelib:wildcard(filename:join(DepsDir, "*")),
+ AllApps = rebar_app_discover:find_apps(DepsDirs, all),
clean_apps(State1, Providers, AllApps);
false ->
ProjectApps = rebar_state:project_apps(State1),
@@ -67,7 +68,7 @@ format_error(Reason) ->
clean_apps(State, Providers, Apps) ->
[begin
- ?INFO("Cleaning out ~s...", [rebar_app_info:name(AppInfo)]),
+ ?INFO("Cleaning out ~ts...", [rebar_app_info:name(AppInfo)]),
AppDir = rebar_app_info:dir(AppInfo),
AppInfo1 = rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, AppInfo, State),
rebar_erlc_compiler:clean(AppInfo1),
diff --git a/src/rebar_prv_common_test.erl b/src/rebar_prv_common_test.erl
index 2ac8fc7..bf788d2 100644
--- a/src/rebar_prv_common_test.erl
+++ b/src/rebar_prv_common_test.erl
@@ -41,7 +41,14 @@ do(State) ->
Tests = prepare_tests(State),
case compile(State, Tests) of
%% successfully compiled apps
- {ok, S} -> do(S, Tests);
+ {ok, S} ->
+ {RawOpts, _} = rebar_state:command_parsed_args(S),
+ case proplists:get_value(compile_only, RawOpts, false) of
+ true ->
+ {ok, S};
+ false ->
+ do(S, Tests)
+ end;
%% this should look like a compiler error, not a ct error
Error -> Error
end.
@@ -93,7 +100,7 @@ format_error({error, Reason}) ->
format_error({error_running_tests, Reason}) ->
format_error({error, Reason});
format_error({failures_running_tests, {Failed, AutoSkipped}}) ->
- io_lib:format("Failures occured running tests: ~b", [Failed+AutoSkipped]);
+ io_lib:format("Failures occurred running tests: ~b", [Failed+AutoSkipped]);
format_error({badconfig, {Msg, {Value, Key}}}) ->
io_lib:format(Msg, [Value, Key]);
format_error({badconfig, Msg}) ->
@@ -431,18 +438,21 @@ test_dirs(State, Apps, Opts) ->
set_compile_dirs(State, Apps, join(Suites, Dir));
{_Suites, _Dirs} -> {error, "Only a single directory may be specified when specifying suites"}
end;
- Specs0 ->
- case get_dirs_from_specs(Specs0) of
- {ok,{Specs,SuiteDirs}} ->
- {State1,Apps1} = set_compile_dirs1(State, Apps,
- {dir, SuiteDirs}),
- {State2,Apps2} = set_compile_dirs1(State1, Apps1,
- {spec, Specs}),
- [maybe_copy_spec(State2,Apps2,S) || S <- Specs],
- {ok, rebar_state:project_apps(State2, Apps2)};
- Error ->
- Error
- end
+ Spec when is_integer(hd(Spec)) ->
+ spec_test_dirs(State, Apps, [Spec]);
+ Specs ->
+ spec_test_dirs(State, Apps, Specs)
+ end.
+
+spec_test_dirs(State, Apps, Specs0) ->
+ case get_dirs_from_specs(Specs0) of
+ {ok,{Specs,SuiteDirs}} ->
+ {State1,Apps1} = set_compile_dirs1(State, Apps, {dir, SuiteDirs}),
+ {State2,Apps2} = set_compile_dirs1(State1, Apps1, {spec, Specs}),
+ [maybe_copy_spec(State2,Apps2,S) || S <- Specs],
+ {ok, rebar_state:project_apps(State2, Apps2)};
+ Error ->
+ Error
end.
join(Suite, Dir) when is_integer(hd(Suite)) ->
@@ -564,9 +574,6 @@ get_tests_from_specs(Specs) ->
case ct_testspec:collect_tests_from_file(Specs,true) of
Tests when is_list(Tests) ->
{ok,[{S,ct_testspec:prepare_tests(R)} || {S,R} <- Tests]};
- R when is_tuple(R), element(1,R)==testspec ->
- %% R15
- {ok,[{Specs,ct_testspec:prepare_tests(R)}]};
Error ->
Error
end
@@ -650,7 +657,11 @@ handle_results(_) ->
sum_results({Passed, Failed, {UserSkipped, AutoSkipped}},
{Passed2, Failed2, {UserSkipped2, AutoSkipped2}}) ->
{Passed+Passed2, Failed+Failed2,
- {UserSkipped+UserSkipped2, AutoSkipped+AutoSkipped2}}.
+ {UserSkipped+UserSkipped2, AutoSkipped+AutoSkipped2}};
+sum_results(_, {error, Reason}) ->
+ {error, Reason};
+sum_results(Unknown, _) ->
+ {error, Unknown}.
handle_quiet_results(_, {error, _} = Result) ->
handle_results(Result);
@@ -673,7 +684,10 @@ format_result({Passed, 0, {0, 0}}) ->
format_result({Passed, Failed, Skipped}) ->
Format = [format_failed(Failed), format_skipped(Skipped),
format_passed(Passed)],
- ?CONSOLE("~s", [Format]).
+ ?CONSOLE("~ts", [Format]);
+format_result(_Unknown) ->
+ %% Happens when CT itself encounters a bug
+ ok.
format_failed(0) ->
[];
@@ -705,17 +719,17 @@ maybe_write_coverdata(State) ->
rebar_prv_cover:maybe_write_coverdata(State1, ?PROVIDER).
ct_opts(_State) ->
- [{dir, undefined, "dir", string, help(dir)}, %% comma-seperated list
- {suite, undefined, "suite", string, help(suite)}, %% comma-seperated list
- {group, undefined, "group", string, help(group)}, %% comma-seperated list
- {testcase, undefined, "case", string, help(testcase)}, %% comma-seperated list
+ [{dir, undefined, "dir", string, help(dir)}, %% comma-separated list
+ {suite, undefined, "suite", string, help(suite)}, %% comma-separated list
+ {group, undefined, "group", string, help(group)}, %% comma-separated list
+ {testcase, undefined, "case", string, help(testcase)}, %% comma-separated list
{label, undefined, "label", string, help(label)}, %% String
- {config, undefined, "config", string, help(config)}, %% comma-seperated list
- {spec, undefined, "spec", string, help(spec)}, %% comma-seperated list
+ {config, undefined, "config", string, help(config)}, %% comma-separated list
+ {spec, undefined, "spec", string, help(spec)}, %% comma-separated list
{join_specs, undefined, "join_specs", boolean, help(join_specs)},
{allow_user_terms, undefined, "allow_user_terms", boolean, help(allow_user_terms)}, %% Bool
{logdir, undefined, "logdir", string, help(logdir)}, %% dir
- {logopts, undefined, "logopts", string, help(logopts)}, %% comma seperated list
+ {logopts, undefined, "logopts", string, help(logopts)}, %% comma-separated list
{verbosity, undefined, "verbosity", integer, help(verbosity)}, %% Integer
{cover, $c, "cover", {boolean, false}, help(cover)},
{repeat, undefined, "repeat", integer, help(repeat)}, %% integer
@@ -736,9 +750,12 @@ ct_opts(_State) ->
{name, undefined, "name", atom, help(name)},
{sname, undefined, "sname", atom, help(sname)},
{setcookie, undefined, "setcookie", atom, help(setcookie)},
- {sys_config, undefined, "sys_config", string, help(sys_config)} %% comma-seperated list
+ {sys_config, undefined, "sys_config", string, help(sys_config)}, %% comma-separated list
+ {compile_only, undefined, "compile_only", boolean, help(compile_only)}
].
+help(compile_only) ->
+ "Compile modules in the project with the test configuration but do not run the tests";
help(dir) ->
"List of additional directories containing test suites";
help(suite) ->
diff --git a/src/rebar_prv_compile.erl b/src/rebar_prv_compile.erl
index effc763..959ecb0 100644
--- a/src/rebar_prv_compile.erl
+++ b/src/rebar_prv_compile.erl
@@ -73,7 +73,7 @@ do(State) ->
-spec format_error(any()) -> iolist().
format_error({missing_artifact, File}) ->
- io_lib:format("Missing artifact ~s", [File]);
+ io_lib:format("Missing artifact ~ts", [File]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
@@ -114,7 +114,7 @@ compile(State, AppInfo) ->
compile(State, rebar_state:providers(State), AppInfo).
compile(State, Providers, AppInfo) ->
- ?INFO("Compiling ~s", [rebar_app_info:name(AppInfo)]),
+ ?INFO("Compiling ~ts", [rebar_app_info:name(AppInfo)]),
AppDir = rebar_app_info:dir(AppInfo),
AppInfo1 = rebar_hooks:run_all_hooks(AppDir, pre, ?PROVIDER, Providers, AppInfo, State),
@@ -173,8 +173,8 @@ has_all_artifacts(AppInfo1) ->
end.
copy_app_dirs(AppInfo, OldAppDir, AppDir) ->
- case ec_cnv:to_binary(filename:absname(OldAppDir)) =/=
- ec_cnv:to_binary(filename:absname(AppDir)) of
+ case rebar_utils:to_binary(filename:absname(OldAppDir)) =/=
+ rebar_utils:to_binary(filename:absname(AppDir)) of
true ->
EbinDir = filename:join([OldAppDir, "ebin"]),
%% copy all files from ebin if it exists
diff --git a/src/rebar_prv_cover.erl b/src/rebar_prv_cover.erl
index 865c557..fca7c40 100644
--- a/src/rebar_prv_cover.erl
+++ b/src/rebar_prv_cover.erl
@@ -215,18 +215,18 @@ print_analysis(Analysis, true) ->
format_table(Stats, CoverFiles) ->
MaxLength = max(lists:foldl(fun max_length/2, 0, Stats), 20),
Header = header(MaxLength),
- Seperator = seperator(MaxLength),
+ Separator = separator(MaxLength),
TotalLabel = format("total", MaxLength),
TotalCov = format(calculate_total(Stats), 8),
- [io_lib:format("~ts~n~ts~n~ts~n", [Seperator, Header, Seperator]),
+ [io_lib:format("~ts~n~ts~n~ts~n", [Separator, Header, Separator]),
lists:map(fun({Mod, Coverage}) ->
Name = format(Mod, MaxLength),
Cov = format(Coverage, 8),
io_lib:format(" | ~ts | ~ts |~n", [Name, Cov])
end, Stats),
- io_lib:format("~ts~n", [Seperator]),
+ io_lib:format("~ts~n", [Separator]),
io_lib:format(" | ~ts | ~ts |~n", [TotalLabel, TotalCov]),
- io_lib:format("~ts~n", [Seperator]),
+ io_lib:format("~ts~n", [Separator]),
io_lib:format(" coverage calculated from:~n", []),
lists:map(fun(File) ->
io_lib:format(" ~ts~n", [File])
@@ -242,7 +242,7 @@ max_length({ModName, _}, Min) ->
header(Width) ->
[" | ", format("module", Width), " | ", format("coverage", 8), " |"].
-seperator(Width) ->
+separator(Width) ->
[" |--", io_lib:format("~*c", [Width, $-]), "--|------------|"].
format(String, Width) -> io_lib:format("~*.ts", [Width, String]).
@@ -278,7 +278,7 @@ write_index(State, Coverage) ->
write_index_section(_F, []) -> ok;
write_index_section(F, [{Section, DataFile, Mods}|Rest]) ->
%% Write the report
- ok = file:write(F, ?FMT("<h1>~s summary</h1>\n", [Section])),
+ ok = file:write(F, ?FMT("<h1>~ts summary</h1>\n", [Section])),
ok = file:write(F, "coverage calculated from:\n<ul>"),
ok = lists:foreach(fun(D) -> ok = file:write(F, io_lib:format("<li>~ts</li>", [D])) end,
DataFile),
@@ -303,7 +303,7 @@ strip_coverdir(File) ->
2))).
cover_compile(State, apps) ->
- ExclApps = [list_to_binary(A) || A <- rebar_state:get(State, cover_excl_apps, [])],
+ ExclApps = [rebar_utils:to_binary(A) || A <- rebar_state:get(State, cover_excl_apps, [])],
Apps = filter_checkouts_and_excluded(rebar_state:project_apps(State), ExclApps),
AppDirs = app_dirs(Apps),
cover_compile(State, lists:filter(fun(D) -> ec_file:is_dir(D) end, AppDirs));
diff --git a/src/rebar_prv_deps.erl b/src/rebar_prv_deps.erl
index 9ff2bfa..a88b014 100644
--- a/src/rebar_prv_deps.erl
+++ b/src/rebar_prv_deps.erl
@@ -55,7 +55,7 @@ merge(Deps, SourceDeps) ->
normalize(Name) when is_binary(Name) ->
Name;
normalize(Name) when is_atom(Name) ->
- ec_cnv:to_binary(Name);
+ atom_to_binary(Name, unicode);
normalize(Dep) when is_tuple(Dep) ->
Name = element(1, Dep),
setelement(1, Dep, normalize(Name)).
@@ -87,31 +87,31 @@ display_deps(State, Deps) ->
%% packages
display_dep(_State, {Name, Vsn}) when is_list(Vsn) ->
- ?CONSOLE("~s* (package ~s)", [ec_cnv:to_binary(Name), ec_cnv:to_binary(Vsn)]);
+ ?CONSOLE("~ts* (package ~ts)", [rebar_utils:to_binary(Name), rebar_utils:to_binary(Vsn)]);
display_dep(_State, Name) when is_binary(Name) ->
- ?CONSOLE("~s* (package)", [Name]);
+ ?CONSOLE("~ts* (package)", [Name]);
display_dep(_State, {Name, Source}) when is_tuple(Source) ->
- ?CONSOLE("~s* (~s source)", [ec_cnv:to_binary(Name), type(Source)]);
+ ?CONSOLE("~ts* (~ts source)", [rebar_utils:to_binary(Name), type(Source)]);
display_dep(_State, {Name, _Vsn, Source}) when is_tuple(Source) ->
- ?CONSOLE("~s* (~s source)", [ec_cnv:to_binary(Name), type(Source)]);
+ ?CONSOLE("~ts* (~ts source)", [rebar_utils:to_binary(Name), type(Source)]);
display_dep(_State, {Name, _Vsn, Source, _Opts}) when is_tuple(Source) ->
- ?CONSOLE("~s* (~s source)", [ec_cnv:to_binary(Name), type(Source)]);
+ ?CONSOLE("~ts* (~ts source)", [rebar_utils:to_binary(Name), type(Source)]);
%% Locked
display_dep(State, {Name, Source={pkg, _, Vsn}, Level}) when is_integer(Level) ->
DepsDir = rebar_dir:deps_dir(State),
- AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]),
+ AppDir = filename:join([DepsDir, rebar_utils:to_binary(Name)]),
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source, State) of
true -> "*";
false -> ""
end,
- ?CONSOLE("~s~s (locked package ~s)", [Name, NeedsUpdate, Vsn]);
+ ?CONSOLE("~ts~ts (locked package ~ts)", [Name, NeedsUpdate, Vsn]);
display_dep(State, {Name, Source, Level}) when is_tuple(Source), is_integer(Level) ->
DepsDir = rebar_dir:deps_dir(State),
- AppDir = filename:join([DepsDir, ec_cnv:to_binary(Name)]),
+ AppDir = filename:join([DepsDir, rebar_utils:to_binary(Name)]),
NeedsUpdate = case rebar_fetch:needs_update(AppDir, Source, State) of
true -> "*";
false -> ""
end,
- ?CONSOLE("~s~s (locked ~s source)", [Name, NeedsUpdate, type(Source)]).
+ ?CONSOLE("~ts~ts (locked ~ts source)", [Name, NeedsUpdate, type(Source)]).
type(Source) when is_tuple(Source) -> element(1, Source).
diff --git a/src/rebar_prv_deps_tree.erl b/src/rebar_prv_deps_tree.erl
index c0c8bab..7c6978b 100644
--- a/src/rebar_prv_deps_tree.erl
+++ b/src/rebar_prv_deps_tree.erl
@@ -90,7 +90,7 @@ type(Source, Verbose) when is_tuple(Source) ->
{pkg, _} ->
"hex package";
{Other, false} ->
- io_lib:format("~s repo", [Other]);
+ io_lib:format("~ts repo", [Other]);
{_, true} ->
- io_lib:format("~s", [element(2, Source)])
+ io_lib:format("~ts", [element(2, Source)])
end.
diff --git a/src/rebar_prv_dialyzer.erl b/src/rebar_prv_dialyzer.erl
index 21d7f5a..a74eefb 100644
--- a/src/rebar_prv_dialyzer.erl
+++ b/src/rebar_prv_dialyzer.erl
@@ -116,18 +116,18 @@ maybe_fix_env() ->
-spec format_error(any()) -> iolist().
format_error({error_processing_apps, Error}) ->
- io_lib:format("Error in dialyzing apps: ~s", [Error]);
+ io_lib:format("Error in dialyzing apps: ~ts", [Error]);
format_error({dialyzer_warnings, Warnings}) ->
- io_lib:format("Warnings occured running dialyzer: ~b", [Warnings]);
+ io_lib:format("Warnings occurred running dialyzer: ~b", [Warnings]);
format_error({unknown_application, App}) ->
- io_lib:format("Could not find application: ~s", [App]);
+ io_lib:format("Could not find application: ~ts", [App]);
format_error({unknown_module, Mod}) ->
- io_lib:format("Could not find module: ~s", [Mod]);
+ io_lib:format("Could not find module: ~ts", [Mod]);
format_error({duplicate_module, Mod, File1, File2}) ->
- io_lib:format("Duplicates of module ~s: ~s ~s", [Mod, File1, File2]);
+ io_lib:format("Duplicates of module ~ts: ~ts ~ts", [Mod, File1, File2]);
format_error({output_file_error, File, Error}) ->
Error1 = file:format_error(Error),
- io_lib:format("Failed to write to ~s: ~s", [File, Error1]);
+ io_lib:format("Failed to write to ~ts: ~ts", [File, Error1]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
@@ -155,7 +155,7 @@ do(State, Plt) ->
0 ->
{ok, State2};
TotalWarnings ->
- ?INFO("Warnings written to ~s", [Output]),
+ ?INFO("Warnings written to ~ts", [Output]),
throw({dialyzer_warnings, TotalWarnings})
end.
@@ -229,7 +229,7 @@ apps_files([AppName | DepApps], SkipApps, Files) ->
apps_files(DepApps, SkipApps, Files);
false ->
AppFiles = app_files(AppName),
- ?DEBUG("~s modules: ~p", [AppName, dict:fetch_keys(AppFiles)]),
+ ?DEBUG("~ts modules: ~p", [AppName, dict:fetch_keys(AppFiles)]),
Files2 = merge_files(Files, AppFiles),
apps_files(DepApps, [AppName | SkipApps], Files2)
end.
@@ -505,7 +505,7 @@ format_warnings(Opts, Output, Warnings) ->
length(Warnings).
console_warnings(Warnings) ->
- _ = [?CONSOLE("~s", [Warning]) || Warning <- Warnings],
+ _ = [?CONSOLE("~ts", [Warning]) || Warning <- Warnings],
ok.
file_warnings(_, []) ->
diff --git a/src/rebar_prv_edoc.erl b/src/rebar_prv_edoc.erl
index 97f70a9..9517335 100644
--- a/src/rebar_prv_edoc.erl
+++ b/src/rebar_prv_edoc.erl
@@ -42,8 +42,8 @@ do(State) ->
Res = try
lists:foldl(fun(AppInfo, EdocOptsAcc) ->
rebar_hooks:run_all_hooks(Cwd, pre, ?PROVIDER, Providers, AppInfo, State),
- AppName = ec_cnv:to_list(rebar_app_info:name(AppInfo)),
- ?INFO("Running edoc for ~s", [AppName]),
+ AppName = rebar_utils:to_list(rebar_app_info:name(AppInfo)),
+ ?INFO("Running edoc for ~ts", [AppName]),
AppDir = rebar_app_info:dir(AppInfo),
AppRes = (catch edoc:application(list_to_atom(AppName), AppDir, EdocOptsAcc)),
rebar_hooks:run_all_hooks(Cwd, post, ?PROVIDER, Providers, AppInfo, State),
@@ -74,7 +74,7 @@ do(State) ->
-spec format_error(any()) -> iolist().
format_error({app_failed, AppName}) ->
- io_lib:format("Failed to generate documentation for app '~s'", [AppName]);
+ io_lib:format("Failed to generate documentation for app '~ts'", [AppName]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
@@ -89,4 +89,4 @@ add_to_paths([], Path) ->
add_to_paths([{doc_path, Paths}|T], Path) ->
[{doc_path, [Path | Paths]} | T];
add_to_paths([H|T], Path) ->
- [H | add_to_paths(Path, T)].
+ [H | add_to_paths(T, Path)].
diff --git a/src/rebar_prv_escriptize.erl b/src/rebar_prv_escriptize.erl
index 7ee20c2..cffbbdc 100644
--- a/src/rebar_prv_escriptize.erl
+++ b/src/rebar_prv_escriptize.erl
@@ -75,7 +75,7 @@ do(State) ->
end;
Name ->
AllApps = rebar_state:all_deps(State)++rebar_state:project_apps(State),
- case rebar_app_utils:find(ec_cnv:to_binary(Name), AllApps) of
+ case rebar_app_utils:find(rebar_utils:to_binary(Name), AllApps) of
{ok, AppInfo} ->
escriptize(State, AppInfo);
_ ->
@@ -87,12 +87,12 @@ do(State) ->
escriptize(State0, App) ->
AppName = rebar_app_info:name(App),
- AppNameStr = ec_cnv:to_list(AppName),
+ AppNameStr = rebar_utils:to_list(AppName),
%% Get the output filename for the escript -- this may include dirs
Filename = filename:join([rebar_dir:base_dir(State0), "bin",
rebar_state:get(State0, escript_name, AppName)]),
- ?DEBUG("Creating escript file ~s", [Filename]),
+ ?DEBUG("Creating escript file ~ts", [Filename]),
ok = filelib:ensure_dir(Filename),
State = rebar_state:escript_path(State0, Filename),
@@ -116,7 +116,7 @@ escriptize(State0, App) ->
ExtraFiles = usort(InclBeams ++ InclExtra),
Files = get_nonempty(EbinFiles ++ ExtraFiles),
- DefaultEmuArgs = ?FMT("%%! -escript main ~s -pz ~s/~s/ebin\n",
+ DefaultEmuArgs = ?FMT("%%! -escript main ~ts -pz ~ts/~ts/ebin\n",
[AppNameStr, AppNameStr, AppNameStr]),
EscriptSections =
[ {shebang,
@@ -130,9 +130,15 @@ escriptize(State0, App) ->
throw(?PRV_ERROR({escript_creation_failed, AppName, EscriptError}))
end,
- %% Finally, update executable perms for our script
- {ok, #file_info{mode = Mode}} = file:read_file_info(Filename),
- ok = file:change_mode(Filename, Mode bor 8#00111),
+ %% Finally, update executable perms for our script on *nix or write out
+ %% script files on win32
+ case os:type() of
+ {unix, _} ->
+ {ok, #file_info{mode = Mode}} = file:read_file_info(Filename),
+ ok = file:change_mode(Filename, Mode bor 8#00111);
+ {win32, _} ->
+ write_windows_script(Filename)
+ end,
{ok, State}.
-spec format_error(any()) -> iolist().
@@ -157,7 +163,7 @@ get_apps_beams(Apps, AllApps) ->
get_apps_beams([], _, Acc) ->
Acc;
get_apps_beams([App | Rest], AllApps, Acc) ->
- case rebar_app_utils:find(ec_cnv:to_binary(App), AllApps) of
+ case rebar_app_utils:find(rebar_utils:to_binary(App), AllApps) of
{ok, App1} ->
OutDir = filename:absname(rebar_app_info:ebin_dir(App1)),
Beams = get_app_beams(App, OutDir),
@@ -229,7 +235,7 @@ get_nonempty(Files) ->
[{FName,FBin} || {FName,FBin} <- Files, FBin =/= <<>>].
find_deps(AppNames, AllApps) ->
- BinAppNames = [ec_cnv:to_binary(Name) || Name <- AppNames],
+ BinAppNames = [rebar_utils:to_binary(Name) || Name <- AppNames],
[ec_cnv:to_atom(Name) ||
Name <- find_deps_of_deps(BinAppNames, AllApps, BinAppNames)].
@@ -239,7 +245,7 @@ find_deps_of_deps([Name|Names], Apps, Acc) ->
?DEBUG("processing ~p", [Name]),
{ok, App} = rebar_app_utils:find(Name, Apps),
DepNames = proplists:get_value(applications, rebar_app_info:app_details(App), []),
- BinDepNames = [ec_cnv:to_binary(Dep) || Dep <- DepNames,
+ BinDepNames = [rebar_utils:to_binary(Dep) || Dep <- DepNames,
%% ignore system libs; shouldn't include them.
DepDir <- [code:lib_dir(Dep)],
DepDir =:= {error, bad_name} orelse % those are all local
@@ -258,3 +264,14 @@ def(Rm, State, Key, Default) ->
rm_newline(String) ->
[C || C <- String, C =/= $\n].
+
+write_windows_script(Target) ->
+ CmdPath = if is_binary(Target) -> <<Target/binary, ".cmd">>;
+ is_list(Target) -> Target ++ ".cmd"
+ end,
+ CmdScript=
+ "@echo off\r\n"
+ "setlocal\r\n"
+ "set rebarscript=%~f0\r\n"
+ "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
+ ok = file:write_file(CmdPath, CmdScript).
diff --git a/src/rebar_prv_eunit.erl b/src/rebar_prv_eunit.erl
index 7d44137..65addc3 100644
--- a/src/rebar_prv_eunit.erl
+++ b/src/rebar_prv_eunit.erl
@@ -83,13 +83,16 @@ run_tests(State, Tests) ->
EUnitOpts = resolve_eunit_opts(State),
?DEBUG("eunit_tests ~p", [T]),
?DEBUG("eunit_opts ~p", [EUnitOpts]),
- Result = eunit:test(T, EUnitOpts),
- ok = maybe_write_coverdata(State),
- case handle_results(Result) of
- {error, Reason} ->
- ?PRV_ERROR(Reason);
- ok ->
- {ok, State}
+ try eunit:test(T, EUnitOpts) of
+ Result ->
+ ok = maybe_write_coverdata(State),
+ case handle_results(Result) of
+ {error, Reason} ->
+ ?PRV_ERROR(Reason);
+ ok ->
+ {ok, State}
+ end
+ catch error:badarg -> ?PRV_ERROR({error, badarg})
end.
-spec format_error(any()) -> iolist().
diff --git a/src/rebar_prv_install_deps.erl b/src/rebar_prv_install_deps.erl
index c9fe0ad..65aabff 100644
--- a/src/rebar_prv_install_deps.erl
+++ b/src/rebar_prv_install_deps.erl
@@ -104,22 +104,22 @@ do_(State) ->
%% @doc convert a given exception's payload into an io description.
-spec format_error(any()) -> iolist().
format_error({dep_app_not_found, AppDir, AppName}) ->
- io_lib:format("Dependency failure: Application ~s not found at the top level of directory ~s", [AppName, AppDir]);
+ io_lib:format("Dependency failure: Application ~ts not found at the top level of directory ~ts", [AppName, AppDir]);
format_error({load_registry_fail, Dep}) ->
- io_lib:format("Error loading registry to resolve version of ~s. Try fixing by running 'rebar3 update'", [Dep]);
+ io_lib:format("Error loading registry to resolve version of ~ts. Try fixing by running 'rebar3 update'", [Dep]);
format_error({bad_constraint, Name, Constraint}) ->
- io_lib:format("Unable to parse version for package ~s: ~s", [Name, Constraint]);
+ io_lib:format("Unable to parse version for package ~ts: ~ts", [Name, Constraint]);
format_error({parse_dep, Dep}) ->
io_lib:format("Failed parsing dep ~p", [Dep]);
format_error({not_rebar_package, Package, Version}) ->
- io_lib:format("Package not buildable with rebar3: ~s-~s", [Package, Version]);
+ io_lib:format("Package not buildable with rebar3: ~ts-~ts", [Package, Version]);
format_error({missing_package, Package, Version}) ->
- io_lib:format("Package not found in registry: ~s-~s", [Package, Version]);
+ io_lib:format("Package not found in registry: ~ts-~ts", [Package, Version]);
format_error({missing_package, Package}) ->
- io_lib:format("Package not found in registry: ~s", [Package]);
+ io_lib:format("Package not found in registry: ~ts", [Package]);
format_error({cycles, Cycles}) ->
Prints = [["applications: ",
- [io_lib:format("~s ", [Dep]) || Dep <- Cycle],
+ [io_lib:format("~ts ", [Dep]) || Dep <- Cycle],
"depend on each other\n"]
|| Cycle <- Cycles],
["Dependency cycle(s) detected:\n", Prints];
@@ -140,7 +140,9 @@ handle_deps_as_profile(Profile, State, Deps, Upgrade) ->
DepsDir = profile_dep_dir(State, Profile),
Deps1 = rebar_app_utils:parse_deps(DepsDir, Deps, State, Locks, Level),
ProfileLevelDeps = [{Profile, Deps1, Level}],
- handle_profile_level(ProfileLevelDeps, [], sets:new(), Upgrade, Locks, State).
+ RootSeen = sets:from_list([rebar_app_info:name(AppInfo)
+ || AppInfo <- rebar_state:project_apps(State)]),
+ handle_profile_level(ProfileLevelDeps, [], RootSeen, RootSeen, Upgrade, Locks, State).
%% ===================================================================
%% Internal functions
@@ -153,7 +155,9 @@ deps_per_profile(Profiles, Upgrade, State) ->
Deps = lists:foldl(fun(Profile, DepAcc) ->
[parsed_profile_deps(State, Profile, Level) | DepAcc]
end, [], Profiles),
- handle_profile_level(Deps, [], sets:new(), Upgrade, Locks, State).
+ RootSeen = sets:from_list([rebar_app_info:name(AppInfo)
+ || AppInfo <- rebar_state:project_apps(State)]),
+ handle_profile_level(Deps, [], RootSeen, RootSeen, Upgrade, Locks, State).
parsed_profile_deps(State, Profile, Level) ->
ParsedDeps = rebar_state:get(State, {parsed_deps, Profile}, []),
@@ -162,17 +166,27 @@ parsed_profile_deps(State, Profile, Level) ->
%% 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([], Apps, _Seen, _Upgrade, _Locks, State) ->
+%%
+%% There are two 'seen' sets: one for the top-level apps (`RootSeen') and
+%% one for all dependencies (`Seen'). The former is used to know when
+%% to skip the resolving of dependencies altogether (since they're already
+%% top-level apps), while the latter is used to prevent reprocessing
+%% deps more than one.
+handle_profile_level([], Apps, _RootSeen, _Seen, _Upgrade, _Locks, State) ->
{Apps, State};
-handle_profile_level([{Profile, Deps, Level} | Rest], Apps, Seen, Upgrade, Locks, State) ->
+handle_profile_level([{Profile, Deps, Level} | Rest], Apps, RootSeen, Seen, Upgrade, Locks, State) ->
+ Deps0 = [rebar_app_utils:expand_deps_sources(Dep, State)
+ || Dep <- Deps,
+ %% skip top-level apps being double-declared
+ not sets:is_element(rebar_app_info:name(Dep), RootSeen)],
{Deps1, Apps1, State1, Seen1} =
- update_deps(Profile, Level, Deps, Apps
+ update_deps(Profile, Level, Deps0, Apps
,State, Upgrade, Seen, Locks),
Deps2 = case Deps1 of
[] -> Rest;
_ -> Rest ++ [{Profile, Deps1, Level+1}]
end,
- handle_profile_level(Deps2, Apps1, sets:union(Seen, Seen1), Upgrade, Locks, State1).
+ handle_profile_level(Deps2, Apps1, RootSeen, sets:union(Seen, Seen1), Upgrade, Locks, State1).
find_cycles(Apps) ->
case rebar_digraph:compile_order(Apps) of
@@ -291,7 +305,7 @@ handle_dep(State, Profile, DepsDir, AppInfo, Locks, Level) ->
-spec maybe_fetch(rebar_app_info:t(), atom(), boolean(),
sets:set(binary()), rebar_state:t()) -> {boolean(), rebar_app_info:t()}.
maybe_fetch(AppInfo, Profile, Upgrade, Seen, State) ->
- AppDir = ec_cnv:to_list(rebar_app_info:dir(AppInfo)),
+ AppDir = rebar_utils:to_list(rebar_app_info:dir(AppInfo)),
%% Don't fetch dep if it exists in the _checkouts dir
case rebar_app_info:is_checkout(AppInfo) of
true ->
@@ -346,7 +360,7 @@ symlink_dep(State, From, To) ->
ok ->
RelativeFrom = make_relative_to_root(State, From),
RelativeTo = make_relative_to_root(State, To),
- ?INFO("Linking ~s to ~s", [RelativeFrom, RelativeTo]),
+ ?INFO("Linking ~ts to ~ts", [RelativeFrom, RelativeTo]),
ok;
exists ->
ok
@@ -359,7 +373,7 @@ make_relative_to_root(State, Path) when is_list(Path) ->
rebar_dir:make_relative_path(Path, Root).
fetch_app(AppInfo, AppDir, State) ->
- ?INFO("Fetching ~s (~p)", [rebar_app_info:name(AppInfo),
+ ?INFO("Fetching ~ts (~p)", [rebar_app_info:name(AppInfo),
format_source(rebar_app_info:source(AppInfo))]),
Source = rebar_app_info:source(AppInfo),
true = rebar_fetch:download_source(AppDir, Source, State).
@@ -384,12 +398,12 @@ maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
true ->
case rebar_fetch:needs_update(AppDir, Source, State) of
true ->
- ?INFO("Upgrading ~s (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]),
+ ?INFO("Upgrading ~ts (~p)", [rebar_app_info:name(AppInfo), rebar_app_info:source(AppInfo)]),
true = rebar_fetch:download_source(AppDir, Source, State);
false ->
case Upgrade of
true ->
- ?INFO("No upgrade needed for ~s", [rebar_app_info:name(AppInfo)]),
+ ?INFO("No upgrade needed for ~ts", [rebar_app_info:name(AppInfo)]),
false;
false ->
false
@@ -400,7 +414,7 @@ maybe_upgrade(AppInfo, AppDir, Upgrade, State) ->
end.
warn_skip_deps(AppInfo, State) ->
- Msg = "Skipping ~s (from ~p) as an app of the same name "
+ Msg = "Skipping ~ts (from ~p) as an app of the same name "
"has already been fetched",
Args = [rebar_app_info:name(AppInfo),
rebar_app_info:source(AppInfo)],
diff --git a/src/rebar_prv_local_install.erl b/src/rebar_prv_local_install.erl
index 1b58859..282c548 100644
--- a/src/rebar_prv_local_install.erl
+++ b/src/rebar_prv_local_install.erl
@@ -60,7 +60,7 @@ format_error(Reason) ->
bin_contents(OutputDir) ->
<<"#!/usr/bin/env sh
-erl -pz ", (ec_cnv:to_binary(OutputDir))/binary,"/*/ebin +sbtu +A0 -noshell -boot start_clean -s rebar3 main $REBAR3_ERL_ARGS -extra \"$@\"
+erl -pz ", (rebar_utils:to_binary(OutputDir))/binary,"/*/ebin +sbtu +A0 -noshell -boot start_clean -s rebar3 main $REBAR3_ERL_ARGS -extra \"$@\"
">>.
extract_escript(State, ScriptPath) ->
@@ -73,7 +73,7 @@ extract_escript(State, ScriptPath) ->
OutputDir = filename:join(rebar_dir:global_cache_dir(Opts), "lib"),
filelib:ensure_dir(filename:join(OutputDir, "empty")),
- ?INFO("Extracting rebar3 libs to ~s...", [OutputDir]),
+ ?INFO("Extracting rebar3 libs to ~ts...", [OutputDir]),
zip:extract(Archive, [{cwd, OutputDir}]),
BinDir = filename:join(rebar_dir:global_cache_dir(Opts), "bin"),
@@ -84,12 +84,12 @@ extract_escript(State, ScriptPath) ->
uid = Uid,
gid = Gid}} = file:read_file_info(ScriptPath),
- ?INFO("Writing rebar3 run script ~s...", [BinFile]),
+ ?INFO("Writing rebar3 run script ~ts...", [BinFile]),
file:write_file(BinFile, bin_contents(OutputDir)),
ok = file:write_file_info(BinFile, #file_info{mode=33277,
uid=Uid,
gid=Gid}),
- ?INFO("Add to $PATH for use: export PATH=$PATH:~s", [BinDir]),
+ ?INFO("Add to $PATH for use: export PATH=~ts:$PATH", [BinDir]),
{ok, State}.
diff --git a/src/rebar_prv_new.erl b/src/rebar_prv_new.erl
index 152a56e..f632362 100644
--- a/src/rebar_prv_new.erl
+++ b/src/rebar_prv_new.erl
@@ -60,7 +60,7 @@ do(State) ->
-spec format_error(any()) -> iolist().
format_error({consult, File, Reason}) ->
- io_lib:format("Error consulting file at ~s for reason ~p", [File, Reason]);
+ io_lib:format("Error consulting file at ~ts for reason ~p", [File, Reason]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
@@ -70,7 +70,7 @@ format_error(Reason) ->
list_templates(State) ->
lists:foldl(fun({error, {consult, File, Reason}}, Acc) ->
- ?WARN("Error consulting template file ~s for reason ~p",
+ ?WARN("Error consulting template file ~ts for reason ~p",
[File, Reason]),
Acc
; (Tpl, Acc) ->
@@ -116,16 +116,16 @@ show_short_templates(List) ->
lists:map(fun show_short_template/1, lists:sort(List)).
show_short_template({Name, Type, _Location, Description, _Vars}) ->
- io:format("~s (~s): ~s~n",
+ io:format("~ts (~ts): ~ts~n",
[Name,
format_type(Type),
format_description(Description)]).
show_template({Name, Type, Location, Description, Vars}) ->
- io:format("~s:~n"
- "\t~s~n"
- "\tDescription: ~s~n"
- "\tVariables:~n~s~n",
+ io:format("~ts:~n"
+ "\t~ts~n"
+ "\tDescription: ~ts~n"
+ "\tVariables:~n~ts~n",
[Name,
format_type(Type, Location),
format_description(Description),
@@ -141,9 +141,9 @@ format_type(escript, _) ->
format_type(builtin, _) ->
"built-in template";
format_type(plugin, Loc) ->
- io_lib:format("plugin template (~s)", [Loc]);
+ io_lib:format("plugin template (~ts)", [Loc]);
format_type(file, Loc) ->
- io_lib:format("custom template (~s)", [Loc]).
+ io_lib:format("custom template (~ts)", [Loc]).
format_description(Description) ->
case Description of
@@ -156,4 +156,4 @@ format_vars(Vars) -> [format_var(Var) || Var <- Vars].
format_var({Var, Default}) ->
io_lib:format("\t\t~p=~p~n",[Var, Default]);
format_var({Var, Default, Doc}) ->
- io_lib:format("\t\t~p=~p (~s)~n", [Var, Default, Doc]).
+ io_lib:format("\t\t~p=~p (~ts)~n", [Var, Default, Doc]).
diff --git a/src/rebar_prv_packages.erl b/src/rebar_prv_packages.erl
index 7217ab8..6e8e683 100644
--- a/src/rebar_prv_packages.erl
+++ b/src/rebar_prv_packages.erl
@@ -30,7 +30,7 @@ do(State) ->
rebar_packages:packages(State),
case rebar_state:command_args(State) of
[Name] ->
- print_packages(get_packages(iolist_to_binary(Name)));
+ print_packages(get_packages(rebar_utils:to_binary(Name)));
_ ->
print_packages(sort_packages())
end,
@@ -47,7 +47,7 @@ print_packages(Pkgs) ->
,ec_semver:parse(B))
end, Vsns),
VsnStr = join(SortedVsns, <<", ">>),
- ?CONSOLE("~s:~n Versions: ~s~n", [Name, VsnStr])
+ ?CONSOLE("~ts:~n Versions: ~ts~n", [Name, VsnStr])
end, Pkgs).
sort_packages() ->
@@ -71,4 +71,4 @@ join([Bin | T], Sep) ->
info(Description) ->
- io_lib:format("~s.~n", [Description]).
+ io_lib:format("~ts.~n", [Description]).
diff --git a/src/rebar_prv_path.erl b/src/rebar_prv_path.erl
index 4259eec..75d38eb 100644
--- a/src/rebar_prv_path.erl
+++ b/src/rebar_prv_path.erl
@@ -27,7 +27,7 @@ init(State) ->
{example, "rebar3 path"},
{short_desc, "Print paths to build dirs in current profile."},
{desc, "Print paths to build dirs in current profile."},
- {opts, eunit_opts(State)}])),
+ {opts, path_opts(State)}])),
{ok, State1}.
@@ -75,23 +75,23 @@ paths([{src, true}|Rest], Apps, State, Acc) ->
paths([{rel, true}|Rest], Apps, State, Acc) ->
paths(Rest, Apps, State, [rel_dir(State)|Acc]).
-base_dir(State) -> io_lib:format("~s", [rebar_dir:base_dir(State)]).
-bin_dir(State) -> io_lib:format("~s/bin", [rebar_dir:base_dir(State)]).
-lib_dir(State) -> io_lib:format("~s", [rebar_dir:deps_dir(State)]).
-rel_dir(State) -> io_lib:format("~s/rel", [rebar_dir:base_dir(State)]).
+base_dir(State) -> io_lib:format("~ts", [rebar_dir:base_dir(State)]).
+bin_dir(State) -> io_lib:format("~ts/bin", [rebar_dir:base_dir(State)]).
+lib_dir(State) -> io_lib:format("~ts", [rebar_dir:deps_dir(State)]).
+rel_dir(State) -> io_lib:format("~ts/rel", [rebar_dir:base_dir(State)]).
ebin_dirs(Apps, State) ->
- lists:map(fun(App) -> io_lib:format("~s/~s/ebin", [rebar_dir:deps_dir(State), App]) end, Apps).
+ lists:map(fun(App) -> io_lib:format("~ts/~ts/ebin", [rebar_dir:deps_dir(State), App]) end, Apps).
priv_dirs(Apps, State) ->
- lists:map(fun(App) -> io_lib:format("~s/~s/priv", [rebar_dir:deps_dir(State), App]) end, Apps).
+ lists:map(fun(App) -> io_lib:format("~ts/~ts/priv", [rebar_dir:deps_dir(State), App]) end, Apps).
src_dirs(Apps, State) ->
- lists:map(fun(App) -> io_lib:format("~s/~s/src", [rebar_dir:deps_dir(State), App]) end, Apps).
+ lists:map(fun(App) -> io_lib:format("~ts/~ts/src", [rebar_dir:deps_dir(State), App]) end, Apps).
print_paths_if_exist(Paths, State) ->
{RawOpts, _} = rebar_state:command_parsed_args(State),
Sep = proplists:get_value(separator, RawOpts, " "),
RealPaths = lists:filter(fun(P) -> ec_file:is_dir(P) end, Paths),
- io:format("~s", [string:join(RealPaths, Sep)]).
+ io:format("~ts", [string:join(RealPaths, Sep)]).
project_deps(State) ->
Profiles = rebar_state:current_profiles(State),
@@ -107,7 +107,7 @@ normalize(AppName) when is_list(AppName) -> AppName;
normalize(AppName) when is_atom(AppName) -> atom_to_list(AppName);
normalize(AppName) when is_binary(AppName) -> binary_to_list(AppName).
-eunit_opts(_State) ->
+path_opts(_State) ->
[{app, undefined, "app", string, help(app)},
{base, undefined, "base", boolean, help(base)},
{bin, undefined, "bin", boolean, help(bin)},
@@ -118,7 +118,7 @@ eunit_opts(_State) ->
{src, undefined, "src", boolean, help(src)},
{rel, undefined, "rel", boolean, help(rel)}].
-help(app) -> "Comma seperated list of applications to return paths for.";
+help(app) -> "Comma separated list of applications to return paths for.";
help(base) -> "Return the `base' path of the current profile.";
help(bin) -> "Return the `bin' path of the current profile.";
help(ebin) -> "Return all `ebin' paths of the current profile's applications.";
diff --git a/src/rebar_prv_plugins.erl b/src/rebar_prv_plugins.erl
index 7e6b88e..4bea3b3 100644
--- a/src/rebar_prv_plugins.erl
+++ b/src/rebar_prv_plugins.erl
@@ -34,14 +34,17 @@ do(State) ->
GlobalConfigFile = rebar_dir:global_config(),
GlobalConfig = rebar_state:new(rebar_config:consult_file(GlobalConfigFile)),
GlobalPlugins = rebar_state:get(GlobalConfig, plugins, []),
+ GlobalSrcDirs = rebar_state:get(GlobalConfig, src_dirs, ["src"]),
GlobalPluginsDir = filename:join([rebar_dir:global_cache_dir(rebar_state:opts(State)), "plugins", "*"]),
- GlobalApps = rebar_app_discover:find_apps([GlobalPluginsDir], all),
+ GlobalApps = rebar_app_discover:find_apps([GlobalPluginsDir], GlobalSrcDirs, all),
display_plugins("Global plugins", GlobalApps, GlobalPlugins),
+ RebarOpts = rebar_state:opts(State),
+ SrcDirs = rebar_dir:src_dirs(RebarOpts, ["src"]),
Plugins = rebar_state:get(State, plugins, []),
- PluginsDir = filename:join(rebar_dir:plugins_dir(State), "*"),
- CheckoutsDir = filename:join(rebar_dir:checkouts_dir(State), "*"),
- Apps = rebar_app_discover:find_apps([CheckoutsDir, PluginsDir], all),
+ PluginsDirs = filelib:wildcard(filename:join(rebar_dir:plugins_dir(State), "*")),
+ CheckoutsDirs = filelib:wildcard(filename:join(rebar_dir:checkouts_dir(State), "*")),
+ Apps = rebar_app_discover:find_apps(CheckoutsDirs++PluginsDirs, SrcDirs, all),
display_plugins("Local plugins", Apps, Plugins),
{ok, State}.
@@ -52,19 +55,19 @@ format_error(Reason) ->
display_plugins(_Header, _Apps, []) ->
ok;
display_plugins(Header, Apps, Plugins) ->
- ?CONSOLE("--- ~s ---", [Header]),
+ ?CONSOLE("--- ~ts ---", [Header]),
display_plugins(Apps, Plugins),
?CONSOLE("", []).
display_plugins(Apps, Plugins) ->
lists:foreach(fun(Plugin) ->
- Name = if is_atom(Plugin) -> ec_cnv:to_binary(Plugin);
- is_tuple(Plugin) -> ec_cnv:to_binary(element(1, Plugin))
+ Name = if is_atom(Plugin) -> atom_to_binary(Plugin, unicode);
+ is_tuple(Plugin) -> rebar_utils:to_binary(element(1, Plugin))
end,
case rebar_app_utils:find(Name, Apps) of
{ok, _App} ->
- ?CONSOLE("~s", [Name]);
+ ?CONSOLE("~ts", [Name]);
error ->
- ?DEBUG("Unable to find plugin ~s", [Name])
+ ?DEBUG("Unable to find plugin ~ts", [Name])
end
end, Plugins).
diff --git a/src/rebar_prv_plugins_upgrade.erl b/src/rebar_prv_plugins_upgrade.erl
index 03521c7..7420c83 100644
--- a/src/rebar_prv_plugins_upgrade.erl
+++ b/src/rebar_prv_plugins_upgrade.erl
@@ -44,7 +44,7 @@ do(State) ->
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]);
+ io_lib:format("Plugin to upgrade not found: ~ts", [Plugin]);
format_error(Reason) ->
io_lib:format("~p", [Reason]).
diff --git a/src/rebar_prv_report.erl b/src/rebar_prv_report.erl
index d6c8b60..73e9624 100644
--- a/src/rebar_prv_report.erl
+++ b/src/rebar_prv_report.erl
@@ -44,7 +44,7 @@ do(State) ->
{ok, Vsn} = application:get_key(rebar, vsn),
{ok, Apps} = application:get_key(rebar, applications),
[application:load(App) || App <- Apps],
- Vsns = [io_lib:format("~p: ~s~n", [App, AVsn])
+ Vsns = [io_lib:format("~p: ~ts~n", [App, AVsn])
|| App <- lists:sort(Apps),
{ok, AVsn} <- [application:get_key(App, vsn)]],
%% Show OS and versions
@@ -59,10 +59,10 @@ do(State) ->
%%
?CONSOLE(
"Rebar3 report~n"
- " version ~s~n"
- " generated at ~s~n"
+ " version ~ts~n"
+ " generated at ~ts~n"
"=================~n"
- "Please submit this along with your issue at ~s "
+ "Please submit this along with your issue at ~ts "
"(and feel free to edit out private information, if any)~n"
"-----------------~n"
"Task: ~ts~n"
@@ -75,11 +75,11 @@ do(State) ->
"Library directory: ~ts~n"
"-----------------~n"
"Loaded Applications:~n"
- "~s~n"
+ "~ts~n"
"-----------------~n"
"Escript path: ~ts~n"
"Providers:~n"
- " ~s",
+ " ~ts",
[Vsn, time_to_string(UTC),
?ISSUES_URL, Command, Task,
OS, ERTS, Root, Lib,
@@ -100,4 +100,4 @@ time_to_string({{Y,M,D},{H,Min,S}}) ->
[Y,M,D,H,Min,S])).
parse_task(Str) ->
- hd(re:split(Str, " ")).
+ hd(re:split(Str, " ", [unicode])).
diff --git a/src/rebar_prv_shell.erl b/src/rebar_prv_shell.erl
index c1bf735..c958dde 100644
--- a/src/rebar_prv_shell.erl
+++ b/src/rebar_prv_shell.erl
@@ -360,8 +360,10 @@ boot_apps(Apps) ->
ok.
normalize_load_apps([]) -> [];
+normalize_load_apps([{_App, none} | T]) -> normalize_load_apps(T);
normalize_load_apps([{App, _} | T]) -> [App | normalize_load_apps(T)];
normalize_load_apps([{App, _Vsn, load} | T]) -> [App | normalize_load_apps(T)];
+normalize_load_apps([{_App, _Vsn, none} | T]) -> normalize_load_apps(T);
normalize_load_apps([{App, _Vsn, Operator} | T]) when is_atom(Operator) ->
[App | normalize_load_apps(T)];
normalize_load_apps([App | T]) when is_atom(App) -> [App | normalize_load_apps(T)].
@@ -369,12 +371,13 @@ normalize_load_apps([App | T]) when is_atom(App) -> [App | normalize_load_apps(T
normalize_boot_apps([]) -> [];
normalize_boot_apps([{_App, load} | T]) -> normalize_boot_apps(T);
normalize_boot_apps([{_App, _Vsn, load} | T]) -> normalize_boot_apps(T);
+normalize_boot_apps([{_App, none} | T]) -> normalize_boot_apps(T);
+normalize_boot_apps([{_App, _Vsn, none} | T]) -> normalize_boot_apps(T);
normalize_boot_apps([{App, _Vsn, Operator} | T]) when is_atom(Operator) ->
[App | normalize_boot_apps(T)];
normalize_boot_apps([{App, _Vsn} | T]) -> [App | normalize_boot_apps(T)];
normalize_boot_apps([App | T]) when is_atom(App) -> [App | normalize_boot_apps(T)].
-
remove_error_handler(0) ->
?WARN("Unable to remove simple error_logger handler", []);
remove_error_handler(N) ->
diff --git a/src/rebar_prv_unlock.erl b/src/rebar_prv_unlock.erl
index 7ff0d89..51c57ab 100644
--- a/src/rebar_prv_unlock.erl
+++ b/src/rebar_prv_unlock.erl
@@ -66,7 +66,7 @@ format_error(Reason) ->
handle_unlocks(State, Locks, LockFile) ->
{Args, _} = rebar_state:command_parsed_args(State),
- Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args, <<"">>))),
+ Names = parse_names(rebar_utils:to_binary(proplists:get_value(package, Args, <<"">>))),
case [Lock || Lock = {Name, _, _} <- Locks, not lists:member(Name, Names)] of
[] ->
file:delete(LockFile);
@@ -77,7 +77,7 @@ handle_unlocks(State, Locks, LockFile) ->
end.
parse_names(Bin) ->
- case lists:usort(re:split(Bin, <<" *, *">>, [trim])) of
+ case lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode])) of
[<<"">>] -> []; % nothing submitted
Other -> Other
end.
diff --git a/src/rebar_prv_update.erl b/src/rebar_prv_update.erl
index 046c864..a019c5a 100644
--- a/src/rebar_prv_update.erl
+++ b/src/rebar_prv_update.erl
@@ -150,7 +150,7 @@ update_deps_list(Pkg, PkgVsn, Deps, HexRegistry, State) ->
%% and doubled since spaces seem not to be
%% enforced
{false, Vsn} ->
- ?WARN("[~s:~s], Bad dependency version for ~s: ~s.",
+ ?WARN("[~ts:~ts], Bad dependency version for ~ts: ~ts.",
[Pkg, PkgVsn, Dep, Vsn]),
DepsListAcc;
{_, <<"~>", Vsn/binary>>} ->
@@ -202,14 +202,14 @@ valid_vsn(Vsn) ->
SemVerRegExp = "v?(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))?"
"(-[0-9a-z-]+(\\.[0-9a-z-]+)*)?(\\+[0-9a-z-]+(\\.[0-9a-z-]+)*)?",
SupportedVersions = "^(>=?|<=?|~>|==)?\\s*" ++ SemVerRegExp ++ "$",
- re:run(Vsn, SupportedVersions) =/= nomatch.
+ re:run(Vsn, SupportedVersions, [unicode]) =/= nomatch.
highest_matching({Pkg, PkgVsn, Dep, App}, Vsn, HexRegistry, State, DepsListAcc) ->
case rebar_packages:find_highest_matching(Pkg, PkgVsn, Dep, Vsn, HexRegistry, State) of
{ok, HighestDepVsn} ->
[{App, {pkg, Dep, HighestDepVsn, undefined}} | DepsListAcc];
none ->
- ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ ?WARN("[~ts:~ts] Missing registry entry for package ~ts. Try to fix with `rebar3 update`",
[Pkg, PkgVsn, Dep]),
DepsListAcc
end.
@@ -220,7 +220,7 @@ cmp({_Pkg, _PkgVsn, Dep, _App} = Dep1, Vsn, HexRegistry, State, DepsListAcc, Cmp
cmp_(undefined, _MinVsn, [], DepsListAcc, {Pkg, PkgVsn, Dep, _App}, _CmpFun) ->
- ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ ?WARN("[~ts:~ts] Missing registry entry for package ~ts. Try to fix with `rebar3 update`",
[Pkg, PkgVsn, Dep]),
DepsListAcc;
cmp_(HighestDepVsn, _MinVsn, [], DepsListAcc, {_Pkg, _PkgVsn, Dep, App}, _CmpFun) ->
@@ -241,7 +241,7 @@ cmpl({_Pkg, _PkgVsn, Dep, _App} = Dep1, Vsn, HexRegistry, State, DepsListAcc, Cm
cmpl_(undefined, Vsn, Vsns, DepsListAcc, Dep1, CmpFun).
cmpl_(undefined, _MaxVsn, [], DepsListAcc, {Pkg, PkgVsn, Dep, _App}, _CmpFun) ->
- ?WARN("[~s:~s] Missing registry entry for package ~s. Try to fix with `rebar3 update`",
+ ?WARN("[~ts:~ts] Missing registry entry for package ~ts. Try to fix with `rebar3 update`",
[Pkg, PkgVsn, Dep]),
DepsListAcc;
diff --git a/src/rebar_prv_upgrade.erl b/src/rebar_prv_upgrade.erl
index 18c307b..5a7dff8 100644
--- a/src/rebar_prv_upgrade.erl
+++ b/src/rebar_prv_upgrade.erl
@@ -32,7 +32,7 @@ init(State) ->
{deps, ?DEPS},
{example, "rebar3 upgrade [cowboy[,ranch]]"},
{short_desc, "Upgrade dependencies."},
- {desc, "Upgrade project dependecies. Mentioning no application "
+ {desc, "Upgrade project dependencies. Mentioning no application "
"will upgrade all dependencies. To upgrade specific dependencies, "
"their names can be listed in the command."},
{opts, [
@@ -68,9 +68,11 @@ do(State) ->
ProfileDeps = rebar_state:get(State, {deps, default}, []),
Deps = [Dep || Dep <- TopDeps ++ ProfileDeps, % TopDeps > ProfileDeps
is_atom(Dep) orelse is_atom(element(1, Dep))],
- Names = parse_names(ec_cnv:to_binary(proplists:get_value(package, Args, <<"">>)), Locks),
+ Names = parse_names(rebar_utils:to_binary(proplists:get_value(package, Args, <<"">>)), Locks),
DepsDict = deps_dict(rebar_state:all_deps(State)),
- case prepare_locks(Names, Deps, Locks, [], DepsDict) of
+ AltDeps = find_non_default_deps(Deps, State),
+ FilteredNames = cull_default_names_if_profiles(Names, Deps, State),
+ case prepare_locks(FilteredNames, Deps, Locks, [], DepsDict, AltDeps) of
{error, Reason} ->
{error, Reason};
{Locks0, _Unlocks0} ->
@@ -107,7 +109,7 @@ format_error(Reason) ->
io_lib:format("~p", [Reason]).
parse_names(Bin, Locks) ->
- case lists:usort(re:split(Bin, <<" *, *">>, [trim])) of
+ case lists:usort(re:split(Bin, <<" *, *">>, [trim, unicode])) of
%% Nothing submitted, use *all* apps
[<<"">>] -> [Name || {Name, _, 0} <- Locks];
[] -> [Name || {Name, _, 0} <- Locks];
@@ -115,20 +117,45 @@ parse_names(Bin, Locks) ->
Other -> Other
end.
-prepare_locks([], _, Locks, Unlocks, _Dict) ->
+%% Find alternative deps in non-default profiles since they may
+%% need to be passed through (they are never locked)
+find_non_default_deps(Deps, State) ->
+ AltProfiles = rebar_state:current_profiles(State) -- [default],
+ AltProfileDeps = lists:append([
+ rebar_state:get(State, {deps, Profile}, []) || Profile <- AltProfiles]
+ ),
+ [Dep || Dep <- AltProfileDeps,
+ is_atom(Dep) orelse is_atom(element(1, Dep))
+ andalso not lists:member(Dep, Deps)].
+
+%% If any alt profiles are used, remove the default profiles from
+%% the upgrade list and warn about it.
+cull_default_names_if_profiles(Names, Deps, State) ->
+ case rebar_state:current_profiles(State) of
+ [default] ->
+ Names;
+ _ ->
+ ?INFO("Dependencies in the default profile will not be upgraded", []),
+ lists:filter(fun(Name) ->
+ AtomName = binary_to_atom(Name, utf8),
+ rebar_utils:tup_find(AtomName, Deps) == false
+ end, Names)
+ end.
+
+prepare_locks([], _, Locks, Unlocks, _Dict, _AltDeps) ->
{Locks, Unlocks};
-prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict) ->
+prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict, AltDeps) ->
AtomName = binary_to_atom(Name, utf8),
case lists:keyfind(Name, 1, Locks) of
{_, _, 0} = Lock ->
case rebar_utils:tup_find(AtomName, Deps) of
false ->
- ?WARN("Dependency ~s has been removed and will not be upgraded", [Name]),
- prepare_locks(Names, Deps, Locks, Unlocks, Dict);
+ ?WARN("Dependency ~ts has been removed and will not be upgraded", [Name]),
+ prepare_locks(Names, Deps, Locks, Unlocks, Dict, AltDeps);
Dep ->
{Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),
prepare_locks(Names, Deps, NewLocks,
- [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict)
+ [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict, AltDeps)
end;
{_, _, Level} = Lock when Level > 0 ->
case rebar_utils:tup_find(AtomName, Deps) of
@@ -137,10 +164,15 @@ prepare_locks([Name|Names], Deps, Locks, Unlocks, Dict) ->
Dep -> % Dep has been promoted
{Source, NewLocks, NewUnlocks} = prepare_lock(Dep, Lock, Locks, Dict),
prepare_locks(Names, Deps, NewLocks,
- [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict)
+ [{Name, Source, 0} | NewUnlocks ++ Unlocks], Dict, AltDeps)
end;
false ->
- ?PRV_ERROR({unknown_dependency, Name})
+ case rebar_utils:tup_find(AtomName, AltDeps) of
+ false ->
+ ?PRV_ERROR({unknown_dependency, Name});
+ _ -> % non-default profile dependency found, pass through
+ prepare_locks(Names, Deps, Locks, Unlocks, Dict, AltDeps)
+ end
end.
prepare_lock(Dep, Lock, Locks, Dict) ->
@@ -149,7 +181,7 @@ prepare_lock(Dep, Lock, Locks, Dict) ->
{Name, _, Src} -> {Name, Src};
_ when is_atom(Dep) ->
%% version-free package. Must unlock whatever matches in locks
- {_, Vsn, _} = lists:keyfind(ec_cnv:to_binary(Dep), 1, Locks),
+ {_, Vsn, _} = lists:keyfind(rebar_utils:to_binary(Dep), 1, Locks),
{Dep, Vsn}
end,
Children = all_children(Name1, Dict),
@@ -165,7 +197,7 @@ unlock_children(Children, Locks) ->
unlock_children(_, [], Locks, Unlocks) ->
{Locks, Unlocks};
unlock_children(Children, [App = {Name,_,_} | Apps], Locks, Unlocks) ->
- case lists:member(ec_cnv:to_binary(Name), Children) of
+ case lists:member(rebar_utils:to_binary(Name), Children) of
true ->
unlock_children(Children, Apps, Locks, [App | Unlocks]);
false ->
@@ -183,7 +215,7 @@ all_children(Name, Dict) ->
lists:flatten(all_children_(Name, Dict)).
all_children_(Name, Dict) ->
- case dict:find(ec_cnv:to_binary(Name), Dict) of
+ case dict:find(rebar_utils:to_binary(Name), Dict) of
{ok, Children} ->
[Children | [all_children_(Child, Dict) || Child <- Children]];
error ->
diff --git a/src/rebar_prv_xref.erl b/src/rebar_prv_xref.erl
index c4e72e7..2405ebb 100644
--- a/src/rebar_prv_xref.erl
+++ b/src/rebar_prv_xref.erl
@@ -36,6 +36,7 @@ init(State) ->
-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
+ OldPath = code:get_path(),
code:add_pathsa(rebar_state:code_paths(State, all_deps)),
XrefChecks = prepare(State),
XrefIgnores = rebar_state:get(State, xref_ignores, []),
@@ -47,7 +48,7 @@ do(State) ->
QueryChecks = rebar_state:get(State, xref_queries, []),
QueryResults = lists:foldl(fun check_query/2, [], QueryChecks),
stopped = xref:stop(xref),
- rebar_utils:cleanup_code_path(rebar_state:code_paths(State, default)),
+ rebar_utils:cleanup_code_path(OldPath),
case XrefResults =:= [] andalso QueryResults =:= [] of
true ->
{ok, State};
@@ -70,7 +71,7 @@ short_desc() ->
desc() ->
io_lib:format(
- "~s~n"
+ "~ts~n"
"~n"
"Valid rebar.config options:~n"
" ~p~n"
@@ -97,8 +98,11 @@ prepare(State) ->
rebar_state:get(State, xref_warnings, false)},
{verbose, rebar_log:is_verbose(State)}]),
- [{ok, _} = xref:add_directory(xref, rebar_app_info:ebin_dir(App))
- || App <- rebar_state:project_apps(State)],
+ [{ok, _} = xref:add_directory(xref, Dir)
+ || App <- rebar_state:project_apps(State),
+ %% the directory may not exist in rare cases of a compile
+ %% hook of a dep running xref prior to the full job being done
+ Dir <- [rebar_app_info:ebin_dir(App)], filelib:is_dir(Dir)],
%% Get list of xref checks we want to run
ConfXrefChecks = rebar_state:get(State, xref_checks,
@@ -165,8 +169,15 @@ keyall(Key, List) ->
lists:flatmap(fun({K, L}) when Key =:= K -> L; (_) -> [] end, List).
get_behaviour_callbacks(exports_not_used, Attributes) ->
- [B:behaviour_info(callbacks) || B <- keyall(behaviour, Attributes) ++
- keyall(behavior, Attributes)];
+ lists:map(fun(Mod) ->
+ try
+ Mod:behaviour_info(callbacks)
+ catch
+ error:undef ->
+ ?WARN("Behaviour ~p is used but cannot be found.", [Mod]),
+ []
+ end
+ end, keyall(behaviour, Attributes) ++ keyall(behavior, Attributes));
get_behaviour_callbacks(_XrefCheck, _Attributes) ->
[].
@@ -193,7 +204,7 @@ display_results(XrefResults, QueryResults) ->
lists:map(fun display_query_result/1, QueryResults)].
display_query_result({Query, Answer, Value}) ->
- io_lib:format("Query ~s~n answer ~p~n did not match ~p~n",
+ io_lib:format("Query ~ts~n answer ~p~n did not match ~p~n",
[Query, Answer, Value]).
display_xref_results_for_type({Type, XrefResults}) ->
@@ -214,37 +225,37 @@ display_xref_result_fun(Type) ->
end,
case Type of
undefined_function_calls ->
- io_lib:format("~sWarning: ~s calls undefined function ~s (Xref)\n",
+ io_lib:format("~tsWarning: ~ts calls undefined function ~ts (Xref)\n",
[Source, SMFA, TMFA]);
undefined_functions ->
- io_lib:format("~sWarning: ~s is undefined function (Xref)\n",
+ io_lib:format("~tsWarning: ~ts is undefined function (Xref)\n",
[Source, SMFA]);
locals_not_used ->
- io_lib:format("~sWarning: ~s is unused local function (Xref)\n",
+ io_lib:format("~tsWarning: ~ts is unused local function (Xref)\n",
[Source, SMFA]);
exports_not_used ->
- io_lib:format("~sWarning: ~s is unused export (Xref)\n",
+ io_lib:format("~tsWarning: ~ts is unused export (Xref)\n",
[Source, SMFA]);
deprecated_function_calls ->
- io_lib:format("~sWarning: ~s calls deprecated function ~s (Xref)\n",
+ io_lib:format("~tsWarning: ~ts calls deprecated function ~ts (Xref)\n",
[Source, SMFA, TMFA]);
deprecated_functions ->
- io_lib:format("~sWarning: ~s is deprecated function (Xref)\n",
+ io_lib:format("~tsWarning: ~ts is deprecated function (Xref)\n",
[Source, SMFA]);
Other ->
- io_lib:format("~sWarning: ~s - ~s xref check: ~s (Xref)\n",
+ io_lib:format("~tsWarning: ~ts - ~ts xref check: ~ts (Xref)\n",
[Source, SMFA, TMFA, Other])
end
end.
format_mfa({M, F, A}) ->
- ?FMT("~s:~s/~w", [M, F, A]).
+ ?FMT("~ts:~ts/~w", [M, F, A]).
format_mfa_source(MFA) ->
case find_mfa_source(MFA) of
{module_not_found, function_not_found} -> "";
- {Source, function_not_found} -> ?FMT("~s: ", [Source]);
- {Source, Line} -> ?FMT("~s:~w: ", [Source, Line])
+ {Source, function_not_found} -> ?FMT("~ts: ", [Source]);
+ {Source, Line} -> ?FMT("~ts:~w: ", [Source, Line])
end.
%%
@@ -270,12 +281,21 @@ find_mfa_source({M, F, A}) ->
end.
find_function_source(M, F, A, Bin) ->
- AbstractCode = beam_lib:chunks(Bin, [abstract_code]),
- {ok, {M, [{abstract_code, {raw_abstract_v1, Code}}]}} = AbstractCode,
+ ChunksLookup = beam_lib:chunks(Bin, [abstract_code]),
+ {ok, {M, [{abstract_code, AbstractCodeLookup}]}} = ChunksLookup,
+ case AbstractCodeLookup of
+ no_abstract_code ->
+ % There isn't much else we can do at this point
+ {module_not_found, function_not_found};
+ {raw_abstract_v1, AbstractCode} ->
+ find_function_source_in_abstract_code(F, A, AbstractCode)
+ end.
+
+find_function_source_in_abstract_code(F, A, AbstractCode) ->
%% Extract the original source filename from the abstract code
- [{attribute, _, file, {Source, _}} | _] = Code,
+ [{attribute, _, file, {Source, _}} | _] = AbstractCode,
%% Extract the line number for a given function def
- Fn = [E || E <- Code,
+ Fn = [E || E <- AbstractCode,
safe_element(1, E) == function,
safe_element(3, E) == F,
safe_element(4, E) == A],
diff --git a/src/rebar_relx.erl b/src/rebar_relx.erl
index 5c653a3..17c0bd6 100644
--- a/src/rebar_relx.erl
+++ b/src/rebar_relx.erl
@@ -6,6 +6,10 @@
-export([do/4,
format_error/1]).
+-ifdef(TEST).
+-export([merge_overlays/1]).
+-endif.
+
-include("rebar.hrl").
%% ===================================================================
@@ -26,19 +30,21 @@ do(Module, Command, Provider, State) ->
AllOptions = string:join([Command | Options], " "),
Cwd = rebar_state:dir(State),
Providers = rebar_state:providers(State),
+ RebarOpts = rebar_state:opts(State),
+ ErlOpts = rebar_opts:erl_opts(RebarOpts),
rebar_hooks:run_project_and_app_hooks(Cwd, pre, Provider, Providers, State),
try
case rebar_state:get(State, relx, []) of
[] ->
relx:main([{lib_dirs, LibDirs}
,{caller, api}
- ,{log_level, LogLevel} | output_dir(OutputDir, Options)], AllOptions);
+ ,{log_level, LogLevel} | output_dir(OutputDir, Options)] ++ ErlOpts, AllOptions);
Config ->
Config1 = merge_overlays(Config),
relx:main([{lib_dirs, LibDirs}
,{config, Config1}
,{caller, api}
- ,{log_level, LogLevel} | output_dir(OutputDir, Options)], AllOptions)
+ ,{log_level, LogLevel} | output_dir(OutputDir, Options)] ++ ErlOpts, AllOptions)
end,
rebar_hooks:run_project_and_app_hooks(Cwd, post, Provider, Providers, State),
{ok, State}
@@ -62,5 +68,5 @@ merge_overlays(Config) ->
(_) -> false
end, Config),
%% Have profile overlay entries come before others to match how profiles work elsewhere
- NewOverlay = lists:reverse(lists:flatmap(fun({overlay, Overlay}) -> Overlay end, Overlays)),
+ NewOverlay = lists:flatmap(fun({overlay, Overlay}) -> Overlay end, lists:reverse(Overlays)),
[{overlay, NewOverlay} | Others].
diff --git a/src/rebar_state.erl b/src/rebar_state.erl
index 9683709..3314a11 100644
--- a/src/rebar_state.erl
+++ b/src/rebar_state.erl
@@ -182,7 +182,7 @@ all(_, []) ->
all(Dir, [File|Artifacts]) ->
case filelib:is_regular(filename:join(Dir, File)) of
false ->
- ?DEBUG("Missing artifact ~s", [filename:join(Dir, File)]),
+ ?DEBUG("Missing artifact ~ts", [filename:join(Dir, File)]),
{false, File};
true ->
all(Dir, Artifacts)
@@ -302,9 +302,9 @@ dir(State=#state_t{}, Dir) ->
deps_names(Deps) when is_list(Deps) ->
lists:map(fun(Dep) when is_tuple(Dep) ->
- ec_cnv:to_binary(element(1, Dep));
+ rebar_utils:to_binary(element(1, Dep));
(Dep) when is_atom(Dep) ->
- ec_cnv:to_binary(Dep)
+ rebar_utils:to_binary(Dep)
end, Deps);
deps_names(State) ->
Deps = rebar_state:get(State, deps, []),
diff --git a/src/rebar_templater.erl b/src/rebar_templater.erl
index 9b33ec5..75190ec 100644
--- a/src/rebar_templater.erl
+++ b/src/rebar_templater.erl
@@ -129,7 +129,7 @@ default_author_and_email() ->
%% Ok, try mecurial
case rebar_utils:sh("hg showconfig ui.username", [return_on_error]) of
{ok, NameEmail} ->
- case re:run(NameEmail, "^(.*) <(.*)>$", [{capture, [1,2], list}]) of
+ case re:run(NameEmail, "^(.*) <(.*)>$", [{capture, [1,2], list}, unicode]) of
{match, [Name, Email]} ->
{Name, Email};
_ ->
@@ -169,7 +169,7 @@ maybe_warn_about_name(Vars) ->
invalid ->
?WARN("The 'name' variable is often associated with Erlang "
"module names and/or file names. The value submitted "
- "(~s) isn't an unquoted Erlang atom. Templates "
+ "(~ts) isn't an unquoted Erlang atom. Templates "
"generated may contain errors.",
[Name]);
valid ->
@@ -189,7 +189,7 @@ validate_atom(Str) ->
%% Run template instructions one at a time.
execute_template([], _, {Template,_,_}, _, _) ->
- ?DEBUG("Template ~s applied", [Template]),
+ ?DEBUG("Template ~ts applied", [Template]),
ok;
%% We can't execute the description
execute_template([{description, _} | Terms], Files, Template, Vars, Force) ->
@@ -242,7 +242,7 @@ execute_template([{template, From, To} | Terms], Files, {Template, Type, Cwd}, V
execute_template(Terms, Files, {Template, Type, Cwd}, Vars, Force);
%% Unknown
execute_template([Instruction|Terms], Files, Tpl={Template,_,_}, Vars, Force) ->
- ?WARN("Unknown template instruction ~p in template ~s",
+ ?WARN("Unknown template instruction ~p in template ~ts",
[Instruction, Template]),
execute_template(Terms, Files, Tpl, Vars, Force).
@@ -305,7 +305,7 @@ cache_escript_files(State) ->
find_escript_templates(Files) ->
[{escript, Name}
|| {Name, _Bin} <- Files,
- re:run(Name, ?TEMPLATE_RE, [{capture, none}]) == match].
+ re:run(Name, ?TEMPLATE_RE, [{capture, none}, unicode]) == match].
find_localinstall_templates(_State) ->
Templates = rebar_utils:find_files(code:priv_dir(rebar), ?TEMPLATE_RE),
@@ -334,8 +334,19 @@ find_plugin_templates(State) ->
|| App <- rebar_state:all_plugin_deps(State),
Priv <- [rebar_app_info:priv_dir(App)],
Priv =/= undefined,
+ File <- rebar_utils:find_files(Priv, ?TEMPLATE_RE)]
+ ++ %% and add global plugins too
+ [{plugin, File}
+ || PSource <- rebar_state:get(State, {plugins, global}, []),
+ Plugin <- [plugin_provider(PSource)],
+ is_atom(Plugin),
+ Priv <- [code:priv_dir(Plugin)],
+ Priv =/= undefined,
File <- rebar_utils:find_files(Priv, ?TEMPLATE_RE)].
+plugin_provider(P) when is_atom(P) -> P;
+plugin_provider(T) when is_tuple(T) -> element(1, T).
+
%% Take an existing list of templates and tag them by name the way
%% the user would enter it from the CLI
tag_names(List) ->
@@ -363,7 +374,7 @@ prioritize_templates([{Name, Type, File} | Rest], Valid) ->
prioritize_templates(Rest, Valid);
{_, file, _} ->
?DEBUG("Skipping template ~p, due to presence of a custom "
- "template at ~s", [Name, File]),
+ "template at ~ts", [Name, File]),
prioritize_templates(Rest, Valid)
end.
@@ -418,10 +429,10 @@ write_file(Output, Data, Force) ->
ok = filelib:ensure_dir(Output),
case {Force, FileExists} of
{true, true} ->
- ?INFO("Writing ~s (forcibly overwriting)",
+ ?INFO("Writing ~ts (forcibly overwriting)",
[Output]);
_ ->
- ?INFO("Writing ~s", [Output])
+ ?INFO("Writing ~ts", [Output])
end,
case file:write_file(Output, Data) of
ok ->
@@ -438,4 +449,4 @@ write_file(Output, Data, Force) ->
%% Render a binary to a string, using mustache and the specified context
%%
render(Bin, Context) ->
- bbmustache:render(ec_cnv:to_binary(Bin), Context, [{key_type, atom}]).
+ bbmustache:render(rebar_utils:to_binary(Bin), Context, [{key_type, atom}]).
diff --git a/src/rebar_utils.erl b/src/rebar_utils.erl
index c357e94..016847e 100644
--- a/src/rebar_utils.erl
+++ b/src/rebar_utils.erl
@@ -55,6 +55,8 @@
get_arch/0,
wordsize/0,
deps_to_binary/1,
+ to_binary/1,
+ to_list/1,
tup_dedup/1,
tup_umerge/2,
tup_sort/1,
@@ -115,7 +117,7 @@ filtermap(F, [Hd|Tail]) ->
filtermap(F, []) when is_function(F, 1) -> [].
is_arch(ArchRegex) ->
- case re:run(get_arch(), ArchRegex, [{capture, none}]) of
+ case re:run(get_arch(), ArchRegex, [{capture, none}, unicode]) of
match ->
true;
nomatch ->
@@ -142,7 +144,7 @@ wordsize() ->
end.
sh_send(Command0, String, Options0) ->
- ?INFO("sh_send info:\n\tcwd: ~p\n\tcmd: ~s < ~s\n",
+ ?INFO("sh_send info:\n\tcwd: ~p\n\tcmd: ~ts < ~ts\n",
[rebar_dir:get_cwd(), Command0, String]),
?DEBUG("\topts: ~p\n", [Options0]),
@@ -171,7 +173,7 @@ sh_send(Command0, String, Options0) ->
%% Val = string() | false
%%
sh(Command0, Options0) ->
- ?DEBUG("sh info:\n\tcwd: ~p\n\tcmd: ~s\n", [rebar_dir:get_cwd(), Command0]),
+ ?DEBUG("sh info:\n\tcwd: ~p\n\tcmd: ~ts\n", [rebar_dir:get_cwd(), Command0]),
?DEBUG("\topts: ~p\n", [Options0]),
DefaultOptions = [{use_stdout, false}, debug_and_abort_on_error],
@@ -184,7 +186,7 @@ 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, eof],
- ?DEBUG("Port Cmd: ~s\nPort Opts: ~p\n", [Command, PortSettings]),
+ ?DEBUG("Port Cmd: ~ts\nPort Opts: ~p\n", [Command, PortSettings]),
Port = open_port({spawn, Command}, PortSettings),
try
@@ -232,7 +234,7 @@ deprecated(Old, New, When) ->
<<"WARNING: deprecated ~p option used~n"
"Option '~p' has been deprecated~n"
"in favor of '~p'.~n"
- "'~p' will be removed ~s.~n">>,
+ "'~p' will be removed ~ts.~n">>,
[Old, Old, New, Old, When]).
%% for use by `do` task
@@ -244,11 +246,17 @@ args_to_tasks(Args) -> new_task(Args, []).
deps_to_binary([]) ->
[];
deps_to_binary([{Name, _, Source} | T]) ->
- [{ec_cnv:to_binary(Name), Source} | deps_to_binary(T)];
+ [{to_binary(Name), Source} | deps_to_binary(T)];
deps_to_binary([{Name, Source} | T]) ->
- [{ec_cnv:to_binary(Name), Source} | deps_to_binary(T)];
+ [{to_binary(Name), Source} | deps_to_binary(T)];
deps_to_binary([Name | T]) ->
- [ec_cnv:to_binary(Name) | deps_to_binary(T)].
+ [to_binary(Name) | deps_to_binary(T)].
+
+to_binary(A) when is_atom(A) -> atom_to_binary(A, unicode);
+to_binary(Str) -> unicode:characters_to_binary(Str).
+
+to_list(A) when is_atom(A) -> atom_to_list(A);
+to_list(Str) -> unicode:characters_to_list(Str).
tup_dedup(List) ->
tup_dedup_(tup_sort(List)).
@@ -396,10 +404,10 @@ check_min_otp_version(MinOtpVersion) ->
case ParsedVsn >= ParsedMin of
true ->
- ?DEBUG("~s satisfies the requirement for minimum OTP version ~s",
+ ?DEBUG("~ts satisfies the requirement for minimum OTP version ~ts",
[OtpRelease, MinOtpVersion]);
false ->
- ?ABORT("OTP release ~s or later is required. Version in use: ~s",
+ ?ABORT("OTP release ~ts or later is required. Version in use: ~ts",
[MinOtpVersion, OtpRelease])
end.
@@ -415,16 +423,16 @@ check_blacklisted_otp_versions(BlacklistedRegexes) ->
abort_if_blacklisted(BlacklistedRegex, OtpRelease) ->
case re:run(OtpRelease, BlacklistedRegex, [{capture, none}]) of
match ->
- ?ABORT("OTP release ~s matches blacklisted version ~s",
+ ?ABORT("OTP release ~ts matches blacklisted version ~ts",
[OtpRelease, BlacklistedRegex]);
nomatch ->
- ?DEBUG("~s does not match blacklisted OTP version ~s",
+ ?DEBUG("~ts does not match blacklisted OTP version ~ts",
[OtpRelease, BlacklistedRegex])
end.
user_agent() ->
{ok, Vsn} = application:get_key(rebar, vsn),
- ?FMT("Rebar/~s (OTP/~s)", [Vsn, otp_release()]).
+ ?FMT("Rebar/~ts (OTP/~ts)", [Vsn, otp_release()]).
reread_config(ConfigList) ->
%% NB: we attempt to mimic -config here, which survives app reload,
@@ -457,7 +465,7 @@ version_tuple(OtpRelease) ->
{match, [_Full, Maj]} ->
{list_to_integer(Maj), 0, 0};
nomatch ->
- ?ABORT("Minimum OTP release unable to be parsed: ~s", [OtpRelease])
+ ?ABORT("Minimum OTP release unable to be parsed: ~ts", [OtpRelease])
end.
otp_release() ->
@@ -510,7 +518,7 @@ patch_on_windows(Cmd, Env) ->
end, Cmd, Env),
%% Remove left-over vars
re:replace(Cmd1, "\\\$\\w+|\\\${\\w+}", "",
- [global, {return, list}]);
+ [global, {return, list}, unicode]);
_ ->
Cmd
end.
@@ -529,7 +537,7 @@ expand_env_variable(InStr, VarName, RawVarValue) ->
VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", ReOpts),
%% Use a regex to match/replace:
%% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
- RegEx = io_lib:format("\\\$(~s(\\W|$)|{~s})", [VarName, VarName]),
+ RegEx = io_lib:format("\\\$(~ts(\\W|$)|{~ts})", [VarName, VarName]),
re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
end.
@@ -554,7 +562,7 @@ expand_sh_flag(use_stdout) ->
{output_handler,
fun(Line, Acc) ->
%% Line already has a newline so don't use ?CONSOLE which adds one
- io:format("~s", [Line]),
+ io:format("~ts", [Line]),
[Line | Acc]
end};
expand_sh_flag({use_stdout, false}) ->
@@ -577,23 +585,23 @@ log_msg_and_abort(Message) ->
-spec debug_log_msg_and_abort(string()) -> err_handler().
debug_log_msg_and_abort(Message) ->
fun(Command, {Rc, Output}) ->
- ?DEBUG("sh(~s)~n"
+ ?DEBUG("sh(~ts)~n"
"failed with return code ~w and the following output:~n"
- "~s", [Command, Rc, Output]),
+ "~ts", [Command, Rc, Output]),
?ABORT(Message, [])
end.
-spec log_and_abort(string(), {integer(), string()}) -> no_return().
log_and_abort(Command, {Rc, Output}) ->
- ?ABORT("sh(~s)~n"
+ ?ABORT("sh(~ts)~n"
"failed with return code ~w and the following output:~n"
- "~s", [Command, Rc, Output]).
+ "~ts", [Command, Rc, Output]).
-spec debug_and_abort(string(), {integer(), string()}) -> no_return().
debug_and_abort(Command, {Rc, Output}) ->
- ?DEBUG("sh(~s)~n"
+ ?DEBUG("sh(~ts)~n"
"failed with return code ~w and the following output:~n"
- "~s", [Command, Rc, Output]),
+ "~ts", [Command, Rc, Output]),
throw(rebar_abort).
sh_loop(Port, Fun, Acc) ->
@@ -662,7 +670,7 @@ vcs_vsn(Vcs, Dir, Resources) ->
unknown ->
?ABORT("vcs_vsn: Unknown vsn format: ~p", [Vcs]);
{error, Reason} ->
- ?ABORT("vcs_vsn: ~s", [Reason])
+ ?ABORT("vcs_vsn: ~ts", [Reason])
end.
%% Temp work around for repos like relx that use "semver"
@@ -779,7 +787,7 @@ cleanup_code_path(OrigPath) ->
new_task([], Acc) -> lists:reverse(Acc);
new_task([TaskList|Rest], Acc) ->
- case re:split(TaskList, ",", [{return, list}, {parts, 2}]) of
+ case re:split(TaskList, ",", [{return, list}, {parts, 2}, unicode]) of
%% `do` consumes all remaining args
["do" = Task] ->
lists:reverse([{Task, Rest}|Acc]);
@@ -806,7 +814,7 @@ arg_or_flag(["-" ++ _ = Flag|Rest], [{Task, Args}|Acc]) ->
end;
%% an argument or a sequence of arguments
arg_or_flag([ArgList|Rest], [{Task, Args}|Acc]) ->
- case re:split(ArgList, ",", [{return, list}, {parts, 2}]) of
+ case re:split(ArgList, ",", [{return, list}, {parts, 2}, unicode]) of
%% single arg terminated by a comma
[Arg, ""] -> new_task(Rest, [{Task,
lists:reverse([Arg|Args])}|Acc]);
@@ -857,15 +865,18 @@ url_append_path(Url, ExtraPath) ->
escape_chars(Str) when is_atom(Str) ->
escape_chars(atom_to_list(Str));
escape_chars(Str) ->
- re:replace(Str, "([ ()?`!$&;])", "\\\\&", [global, {return, list}]).
+ re:replace(Str, "([ ()?`!$&;\"\'])", "\\\\&",
+ [global, {return, list}, unicode]).
%% "escape inside these"
escape_double_quotes(Str) ->
- re:replace(Str, "([\"\\\\`!$&*;])", "\\\\&", [global, {return, list}]).
+ re:replace(Str, "([\"\\\\`!$&*;])", "\\\\&",
+ [global, {return, list}, unicode]).
%% "escape inside these" but allow *
escape_double_quotes_weak(Str) ->
- re:replace(Str, "([\"\\\\`!$&;])", "\\\\&", [global, {return, list}]).
+ re:replace(Str, "([\"\\\\`!$&;])", "\\\\&",
+ [global, {return, list}, unicode]).
info_useless(Old, New) ->
[?INFO("App ~ts is no longer needed and can be deleted.", [Name])
diff --git a/test/rebar_as_SUITE.erl b/test/rebar_as_SUITE.erl
index ce8046b..78ea8ae 100644
--- a/test/rebar_as_SUITE.erl
+++ b/test/rebar_as_SUITE.erl
@@ -176,7 +176,7 @@ error_on_empty_tasks(Config) ->
warn_match(App, History) ->
lists:any(
- fun({_, {rebar_log,log, [warn, "No entry for profile ~s in config.",
+ fun({_, {rebar_log,log, [warn, "No entry for profile ~ts in config.",
[ArgApp]]}, _}) -> ArgApp =:= App
; (_) ->
false
diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl
index 9f01496..5a18745 100644
--- a/test/rebar_compile_SUITE.erl
+++ b/test/rebar_compile_SUITE.erl
@@ -78,21 +78,10 @@ all() ->
recompile_when_parse_transform_as_opt_changes,
recompile_when_parse_transform_inline_changes,
regex_filter_skip, regex_filter_regression,
- %% recompile behaviour when `ERL_COMPILER_OPTIONS` differs prior to 19.x
- recursive, no_recursive] ++ recompile_when_env_changes_test().
-
-recompile_when_env_changes_test() ->
- _ = code:ensure_loaded(os),
- UnSetEnv = erlang:function_exported(os, unsetenv, 1),
- _ = code:ensure_loaded(compile),
- EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
- case {UnSetEnv, EnvOpts} of
- {true, true} ->
- [dont_recompile_when_erl_compiler_options_env_does_not_change,
- recompile_when_erl_compiler_options_env_changes];
- {true, false} -> [always_recompile_when_erl_compiler_options_set];
- {false, _} -> []
- end.
+ recursive, no_recursive,
+ always_recompile_when_erl_compiler_options_set,
+ dont_recompile_when_erl_compiler_options_env_does_not_change,
+ recompile_when_erl_compiler_options_env_changes].
groups() ->
[{basic_app, [], [build_basic_app, paths_basic_app, clean_basic_app]},
@@ -266,7 +255,31 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
-init_per_testcase(_, Config) ->
+init_per_testcase(Test, Config) when
+ Test == dont_recompile_when_erl_compiler_options_env_does_not_change
+ orelse
+ Test == recompile_when_erl_compiler_options_env_changes ->
+ _ = code:ensure_loaded(os),
+ UnSetEnv = erlang:function_exported(os, unsetenv, 1),
+ _ = code:ensure_loaded(compile),
+ EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
+ case {UnSetEnv, EnvOpts} of
+ {true, true} -> maybe_init_config(Config);
+ _ -> {skip, "compile:env_compiler_options/0 unavailable"}
+ end;
+init_per_testcase(always_recompile_when_erl_compiler_options_set, Config) ->
+ _ = code:ensure_loaded(os),
+ UnSetEnv = erlang:function_exported(os, unsetenv, 1),
+ _ = code:ensure_loaded(compile),
+ EnvOpts = erlang:function_exported(compile, env_compiler_options, 0),
+ case {UnSetEnv, EnvOpts} of
+ {true, true} -> {skip, "compile:env_compiler_options/0 available"};
+ {true, false} -> maybe_init_config(Config);
+ _ -> {skip, "os:unsetenv/1 unavailable"}
+ end;
+init_per_testcase(_, Config) -> maybe_init_config(Config).
+
+maybe_init_config(Config) ->
case ?config(apps, Config) of
undefined -> rebar_test_utils:init_rebar_state(Config);
_ -> Config
@@ -276,7 +289,6 @@ end_per_testcase(_, _Config) ->
catch meck:unload().
-
%% test cases
build_basic_app(Config) ->
diff --git a/test/rebar_ct_SUITE.erl b/test/rebar_ct_SUITE.erl
index 06dc76e..70cf60c 100644
--- a/test/rebar_ct_SUITE.erl
+++ b/test/rebar_ct_SUITE.erl
@@ -55,7 +55,9 @@
testspec/1,
testspec_at_root/1,
testspec_parse_error/1,
- cmd_vs_cfg_opts/1]).
+ cmd_vs_cfg_opts/1,
+ single_testspec_in_ct_opts/1,
+ compile_only/1]).
-include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl").
@@ -75,7 +77,9 @@ all() -> [{group, basic_app},
testspec,
testspec_at_root,
testspec_parse_error,
- cmd_vs_cfg_opts].
+ cmd_vs_cfg_opts,
+ single_testspec_in_ct_opts,
+ compile_only].
groups() -> [{basic_app, [], [basic_app_default_dirs,
basic_app_default_beams,
@@ -1548,6 +1552,57 @@ cmd_vs_cfg_opts(Config) ->
ok.
+single_testspec_in_ct_opts(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "ct_testspec_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name("ct_testspec_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ Spec = filename:join([AppDir, "test", "some.spec"]),
+ ok = filelib:ensure_dir(Spec),
+ ok = file:write_file(Spec, "{suites,\".\",all}.\n"),
+
+ {ok,Wd} = file:get_cwd(),
+ ok = file:set_cwd(AppDir),
+
+ RebarConfig = [{ct_opts, [{spec,"test/some.spec"}]}],
+
+ {ok, State} = rebar_test_utils:run_and_check(C, RebarConfig, ["as", "test", "lock"], return),
+
+ Providers = rebar_state:providers(State),
+ Namespace = rebar_state:namespace(State),
+ CommandProvider = providers:get_provider(ct, Providers, Namespace),
+ GetOptSpec = providers:opts(CommandProvider),
+
+ %% Testspec in "test" directory
+ {ok, GetOptResult1} = getopt:parse(GetOptSpec, []),
+ State1 = rebar_state:command_parsed_args(State, GetOptResult1),
+ Tests1 = rebar_prv_common_test:prepare_tests(State1),
+ {ok, T1} = Tests1,
+ "test/some.spec" = proplists:get_value(spec,T1),
+ {ok, _NewState} = rebar_prv_common_test:compile(State1, Tests1),
+
+ ok = file:set_cwd(Wd),
+ ok.
+
+compile_only(Config) ->
+ C = rebar_test_utils:init_rebar_state(Config, "compile_only_"),
+
+ AppDir = ?config(apps, C),
+
+ Name = rebar_test_utils:create_random_name(atom_to_list(basic_app) ++ "_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ Suite = filename:join([AppDir, "test", Name ++ "_SUITE.erl"]),
+ ok = filelib:ensure_dir(Suite),
+ ok = file:write_file(Suite, test_suite(Name)),
+
+ {ok, _State} = rebar_test_utils:run_and_check(C, [], ["ct", "--compile_only"], {ok, [{app,Name}], "test"}).
+
+
%% helper for generating test data
test_suite(Name) ->
io_lib:format("-module(~ts_SUITE).\n"
@@ -1556,7 +1611,7 @@ test_suite(Name) ->
"some_test(_) -> ok.\n", [Name]).
cmd_sys_config_file(AppName) ->
- io_lib:format("[{~s, [{key, cmd_value}]}].", [AppName]).
+ io_lib:format("[{~ts, [{key, cmd_value}]}].", [AppName]).
cfg_sys_config_file(AppName) ->
- io_lib:format("[{~s, [{key, cfg_value}]}].", [AppName]).
+ io_lib:format("[{~ts, [{key, cfg_value}]}].", [AppName]).
diff --git a/test/rebar_deps_SUITE.erl b/test/rebar_deps_SUITE.erl
index 6b2ecea..ae50ea3 100644
--- a/test/rebar_deps_SUITE.erl
+++ b/test/rebar_deps_SUITE.erl
@@ -7,7 +7,7 @@ all() -> [sub_app_deps, newly_added_dep, newly_added_after_empty_lock,
http_proxy_settings, https_proxy_settings,
http_os_proxy_settings, https_os_proxy_settings,
semver_matching_lt, semver_matching_lte, semver_matching_gt,
- valid_version, {group, git}, {group, pkg}].
+ valid_version, top_override, {group, git}, {group, pkg}].
groups() ->
[{all, [], [flat, pick_highest_left, pick_highest_right,
@@ -47,6 +47,8 @@ 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(top_override, Config) ->
+ rebar_test_utils:init_rebar_state(Config);
init_per_testcase(http_proxy_settings, Config) ->
%% Create private rebar.config
Priv = ?config(priv_dir, Config),
@@ -255,6 +257,32 @@ circular1(Config) -> run(Config).
circular2(Config) -> run(Config).
circular_skip(Config) -> run(Config).
+%% Test that a top-level application overtakes dependencies, and
+%% works even if said deps do not exist.
+top_override(Config) ->
+ AppDir = ?config(apps, Config),
+ ct:pal("dir: ~p", [AppDir]),
+ Name1 = rebar_test_utils:create_random_name("sub_app1_"),
+ Name2 = rebar_test_utils:create_random_name("sub_app2_"),
+ SubAppsDir1 = filename:join([AppDir, "apps", Name1]),
+ SubAppsDir2 = filename:join([AppDir, "apps", Name2]),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(SubAppsDir1, Name1, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_app(SubAppsDir2, Name2, Vsn, [kernel, stdlib]),
+ rebar_test_utils:create_config(
+ SubAppsDir1,
+ [{deps, [list_to_atom(Name2)]}]
+ ),
+ rebar_test_utils:create_config(
+ SubAppsDir2,
+ [{deps, [{list_to_atom(Name1),
+ {git, "https://example.org", {branch, "master"}}}]}]
+ ),
+ rebar_test_utils:run_and_check(
+ Config, [], ["compile"],
+ {ok, [{app, Name1}, {app,Name2}]}
+ ).
+
%% Test that the deps of project apps that have their own rebar.config
%% are included, but that top level rebar.config deps take precedence
sub_app_deps(Config) ->
diff --git a/test/rebar_eunit_SUITE.erl b/test/rebar_eunit_SUITE.erl
index 6fb325b..4805b3d 100644
--- a/test/rebar_eunit_SUITE.erl
+++ b/test/rebar_eunit_SUITE.erl
@@ -1,7 +1,8 @@
-module(rebar_eunit_SUITE).
-export([all/0, groups/0]).
--export([init_per_suite/1, init_per_group/2, end_per_group/2]).
+-export([init_per_suite/1, end_per_suite/1]).
+-export([init_per_group/2, end_per_group/2]).
-export([basic_app_compiles/1, basic_app_files/1]).
-export([basic_app_exports/1, basic_app_testset/1]).
-export([basic_app_eunit_macro/1]).
@@ -60,6 +61,8 @@ init_per_suite(Config) ->
{ok, _} = zip:extract(filename:join([PrivDir, "multi_app.zip"]), [{cwd, PrivDir}]),
Config.
+end_per_suite(Config) -> Config.
+
init_per_group(basic_app, Config) ->
GroupState = rebar_test_utils:init_rebar_state(Config, "basic_app_"),
diff --git a/test/rebar_hooks_SUITE.erl b/test/rebar_hooks_SUITE.erl
index b121dd5..f7fcb82 100644
--- a/test/rebar_hooks_SUITE.erl
+++ b/test/rebar_hooks_SUITE.erl
@@ -9,6 +9,7 @@
build_and_clean_app/1,
escriptize_artifacts/1,
run_hooks_once/1,
+ run_hooks_once_profiles/1,
run_hooks_for_plugins/1,
eunit_app_hooks/1,
deps_hook_namespace/1]).
@@ -33,8 +34,9 @@ end_per_testcase(_, _Config) ->
catch meck:unload().
all() ->
- [build_and_clean_app, run_hooks_once, escriptize_artifacts,
- run_hooks_for_plugins, deps_hook_namespace, eunit_app_hooks].
+ [build_and_clean_app, run_hooks_once, run_hooks_once_profiles,
+ escriptize_artifacts, run_hooks_for_plugins, deps_hook_namespace,
+ eunit_app_hooks].
%% Test post provider hook cleans compiled project app, leaving it invalid
build_and_clean_app(Config) ->
@@ -98,6 +100,18 @@ run_hooks_once(Config) ->
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], {ok, [{app, Name, valid}]}).
+%% test that even if a hook is defined at the project level in a used profile
+%% the hook is not run for each application in the project umbrella
+run_hooks_once_profiles(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("app1_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ RebarConfig = [{profiles, [{hooks, [{pre_hooks, [{compile, "mkdir blah"}]}]}]}],
+ rebar_test_utils:create_config(AppDir, RebarConfig),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["as", "hooks", "compile"], {ok, [{app, Name, valid}]}).
+
deps_hook_namespace(Config) ->
mock_git_resource:mock([{deps, [{some_dep, "0.0.1"}]}]),
Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", []}]),
diff --git a/test/rebar_pkg_SUITE.erl b/test/rebar_pkg_SUITE.erl
index 30cc0a8..32873c8 100644
--- a/test/rebar_pkg_SUITE.erl
+++ b/test/rebar_pkg_SUITE.erl
@@ -287,7 +287,7 @@ mock_config(Name, Config) ->
unmock_config(Config) ->
meck:unload(),
- ets:delete(?config(mock_table, Config)).
+ catch ets:delete(?config(mock_table, Config)).
copy_to_cache({Pkg,Vsn}, Config) ->
Name = <<Pkg/binary, "-", Vsn/binary, ".tar">>,
diff --git a/test/rebar_profiles_SUITE.erl b/test/rebar_profiles_SUITE.erl
index ed492a9..9ffaf98 100644
--- a/test/rebar_profiles_SUITE.erl
+++ b/test/rebar_profiles_SUITE.erl
@@ -25,7 +25,8 @@
test_profile_erl_opts_order_2/1,
test_profile_erl_opts_order_3/1,
test_profile_erl_opts_order_4/1,
- test_profile_erl_opts_order_5/1]).
+ test_profile_erl_opts_order_5/1,
+ first_files_exception/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -46,7 +47,8 @@ all() ->
test_profile_erl_opts_order_2,
test_profile_erl_opts_order_3,
test_profile_erl_opts_order_4,
- test_profile_erl_opts_order_5].
+ test_profile_erl_opts_order_5,
+ first_files_exception].
init_per_suite(Config) ->
application:start(meck),
@@ -468,6 +470,25 @@ test_profile_erl_opts_order_5(Config) ->
Opt = last_erl_opt(Opts, [warn_export_all, nowarn_export_all], undefined),
warn_export_all = Opt.
+first_files_exception(_Config) ->
+ RebarConfig = [{erl_first_files, ["c","a","b"]},
+ {mib_first_files, ["c","a","b"]},
+ {other, ["c","a","b"]},
+ {profiles,
+ [{profile2, [{erl_first_files, ["a","e"]},
+ {mib_first_files, ["a","e"]},
+ {other, ["a","e"]}
+ ]}]}],
+ State = rebar_state:new(RebarConfig),
+ State1 = rebar_state:apply_profiles(State, [profile2]),
+
+ %% Combine lists
+ ?assertEqual(["a","b","c","e"], rebar_state:get(State1, other)),
+ %% there is no specific reason not to dedupe "a" here aside from "this is how it is"
+ ?assertEqual(["c","a","b","a","e"], rebar_state:get(State1, erl_first_files)),
+ ?assertEqual(["c","a","b","a","e"], rebar_state:get(State1, mib_first_files)),
+ ok.
+
get_compiled_profile_erl_opts(Profiles, Config) ->
AppDir = ?config(apps, Config),
PStrs = [atom_to_list(P) || P <- Profiles],
diff --git a/test/rebar_release_SUITE.erl b/test/rebar_release_SUITE.erl
index 1125a7e..e41339b 100644
--- a/test/rebar_release_SUITE.erl
+++ b/test/rebar_release_SUITE.erl
@@ -11,6 +11,7 @@ all() -> [release,
profile_ordering_sys_config_extend_3_tuple_merge,
extend_release,
user_output_dir, profile_overlays,
+ profile_overlay_merge,
overlay_vars].
init_per_testcase(Case, Config0) ->
@@ -217,6 +218,30 @@ profile_overlays(Config) ->
{dir, filename:join(ReleaseDir, "randomdir")}]}
).
+profile_overlay_merge (_Config) ->
+ % when profile and relx overlays both exist, the profile overlays should be
+ % first, then the relx overlays, all the rest of the config should come
+ % after, rebar_relx:merge_overlays/1 should do this.
+ RelxOverlay = [{mkdir, "1_from_relx"}, {mkdir, "2_from_relx"}],
+ ProfileOverlay = [{mkdir, "0_from_other_profile"}],
+ OtherConfig = [{other1, config}, {other2, config}],
+
+ % test with no overlays
+ ?assertEqual([{overlay,[]}] ++ OtherConfig,
+ rebar_relx:merge_overlays(OtherConfig)),
+
+ % test with relx only, just move overlays to the top
+ RelxOnly = OtherConfig ++ [{overlay, RelxOverlay}],
+ ?assertEqual([{overlay, RelxOverlay}]++OtherConfig,
+ rebar_relx:merge_overlays(RelxOnly)),
+
+ % now test with a profile (profiles end up after relx overlays
+ ProfilesToMerge = OtherConfig ++
+ [{overlay, RelxOverlay},
+ {overlay, ProfileOverlay}],
+ ?assertEqual([{overlay, ProfileOverlay ++ RelxOverlay}] ++ OtherConfig,
+ rebar_relx:merge_overlays(ProfilesToMerge)).
+
overlay_vars(Config) ->
AppDir = ?config(apps, Config),
Name = ?config(name, Config),
diff --git a/test/rebar_src_dirs_SUITE.erl b/test/rebar_src_dirs_SUITE.erl
index f854a94..bc22160 100644
--- a/test/rebar_src_dirs_SUITE.erl
+++ b/test/rebar_src_dirs_SUITE.erl
@@ -11,12 +11,16 @@
src_dirs_in_erl_opts/1,
extra_src_dirs_in_erl_opts/1,
src_dirs_at_root_and_in_erl_opts/1,
+ dupe_src_dirs_at_root_and_in_erl_opts/1,
extra_src_dirs_at_root_and_in_erl_opts/1,
build_basic_app/1,
build_multi_apps/1,
- src_dir_takes_precedence_over_extra/1]).
+ src_dir_takes_precedence_over_extra/1,
+ src_dir_checkout_dep/1,
+ app_src_info/1]).
-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
suite() ->
[].
@@ -35,8 +39,11 @@ end_per_testcase(_, _Config) -> ok.
all() ->
[src_dirs_at_root, extra_src_dirs_at_root,
src_dirs_in_erl_opts, extra_src_dirs_in_erl_opts,
- src_dirs_at_root_and_in_erl_opts, extra_src_dirs_at_root_and_in_erl_opts,
- build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra].
+ src_dirs_at_root_and_in_erl_opts,
+ dupe_src_dirs_at_root_and_in_erl_opts,
+ extra_src_dirs_at_root_and_in_erl_opts,
+ build_basic_app, build_multi_apps, src_dir_takes_precedence_over_extra,
+ src_dir_checkout_dep, app_src_info].
src_dirs_at_root(Config) ->
AppDir = ?config(apps, Config),
@@ -93,15 +100,47 @@ extra_src_dirs_in_erl_opts(Config) ->
src_dirs_at_root_and_in_erl_opts(Config) ->
AppDir = ?config(apps, Config),
- Name = rebar_test_utils:create_random_name("app1_"),
+ Name = rebar_test_utils:create_random_name("src_dirs_root_erlopts_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}],
+ %% move the .app.src file to one of the subdirs, out of src/
+ filelib:ensure_dir(filename:join([AppDir, "qux", "fake"])),
+ rebar_file_utils:mv(filename:join([AppDir, "src", Name ++ ".app.src"]),
+ filename:join([AppDir, "qux", Name ++ ".app.src"])),
+
{ok, State} = rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
- ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State), []).
+ ["bar", "baz", "foo", "qux"] = rebar_dir:src_dirs(rebar_state:opts(State), []),
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"],
+ {ok, [{app, Name}]}),
+ ok.
+
+dupe_src_dirs_at_root_and_in_erl_opts(Config) ->
+ AppDir = ?config(apps, Config),
+
+ Name = rebar_test_utils:create_random_name("dupe_src_dirs_root_erlopts_"),
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]),
+
+ RebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]}, {src_dirs, ["baz", "qux"]}],
+
+ %% move the .app.src file to one of the subdirs, out of src/
+ filelib:ensure_dir(filename:join([AppDir, "qux", "fake"])),
+ filelib:ensure_dir(filename:join([AppDir, "foo", "fake"])),
+ Src1 = filename:join([AppDir, "qux", Name ++ ".app.src"]),
+ Src2 = filename:join([AppDir, "foo", Name ++ ".app.src"]),
+ rebar_file_utils:mv(filename:join([AppDir, "src", Name ++ ".app.src"]),
+ Src1),
+ %% Then copy it over to create a conflict with dupes
+ file:copy(Src1, Src2),
+
+ {error, {rebar_prv_app_discovery, {multiple_app_files, [Src2, Src1]}}} =
+ rebar_test_utils:run_and_check(Config, RebarConfig, ["compile"], return),
+
+ ok.
extra_src_dirs_at_root_and_in_erl_opts(Config) ->
AppDir = ?config(apps, Config),
@@ -236,3 +275,52 @@ src_dir_takes_precedence_over_extra(Config) ->
[{application, _, KVs}] = App,
Mods = proplists:get_value(modules, KVs),
true = lists:member(extra, Mods).
+
+src_dir_checkout_dep(Config) ->
+ AppDir = ?config(apps, Config),
+ AppName = rebar_test_utils:create_random_name("src_dir_checkout_app"),
+ DepName = rebar_test_utils:create_random_name("src_dir_checkout_dep"),
+ AtomDep = list_to_atom(DepName),
+
+ Vsn = rebar_test_utils:create_random_vsn(),
+ rebar_test_utils:create_app(AppDir, AppName, Vsn, [kernel, stdlib]),
+ RebarConfig = [{deps, [AtomDep]}],
+
+ DepDir = filename:join([?config(checkouts, Config), DepName]),
+ ct:pal("checkouts dir: ~p", [DepDir]),
+ rebar_test_utils:create_app(DepDir, DepName, Vsn, [kernel, stdlib]),
+
+
+ %% move the .app.src file to one of the subdirs, out of src/
+ rebar_file_utils:mv(filename:join([DepDir, "src"]),
+ filename:join([DepDir, "qux"])),
+ DepRebarConfig = [{erl_opts, [{src_dirs, ["foo", "bar"]}]},
+ {src_dirs, ["baz", "qux"]}],
+ file:write_file(filename:join([DepDir, "rebar.config"]),
+ io_lib:format("~p.~n~p.~n", DepRebarConfig)),
+
+ rebar_test_utils:run_and_check(
+ Config, RebarConfig, ["compile"],
+ {ok, [{checkout, DepName}, {app, AppName}]}
+ ),
+ ok.
+
+app_src_info(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ AppName1 = rebar_test_utils:create_random_name("app_src_info"),
+ AppDir1 = filename:join(PrivDir, AppName1),
+ {ok, Info1} = rebar_app_info:new(AppName1, "1.0.0", AppDir1),
+ AppSrc1 = filename:join([AppDir1, "src", AppName1 ++ ".app.src"]),
+ ok = filelib:ensure_dir(AppSrc1),
+ ok = file:write_file(AppSrc1, "[]."),
+ ?assertEqual(AppSrc1, rebar_app_info:app_file_src(Info1)),
+
+ AppName2 = rebar_test_utils:create_random_name("app_src_info"),
+ AppDir2 = filename:join(PrivDir, AppName2),
+ {ok, Info2Tmp} = rebar_app_info:new(AppName2, "1.0.0", AppDir2),
+ Info2 = rebar_app_info:set(Info2Tmp, src_dirs, ["foo", "bar", "baz"]),
+ AppSrc2 = filename:join([AppDir2, "bar", AppName2 ++ ".app.src"]),
+ ok = filelib:ensure_dir(AppSrc2),
+ ok = file:write_file(AppSrc2, "[]."),
+ ?assertEqual(AppSrc2, rebar_app_info:app_file_src(Info2)),
+ ok.
diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl
index 8c177c9..0ccec56 100644
--- a/test/rebar_test_utils.erl
+++ b/test/rebar_test_utils.erl
@@ -218,7 +218,7 @@ 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", "*"]),
+ CheckoutsDirs = filelib:wildcard(filename:join([AppDir, "_checkouts", "*"])),
LockFile = filename:join([AppDir, "rebar.lock"]),
Locks = lists:flatten(rebar_config:consult_lock_file(LockFile)),
@@ -230,7 +230,7 @@ check_results(AppDir, Expected, ProfileRun) ->
Deps = rebar_app_discover:find_apps(BuildDirs, all),
DepsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Deps],
- Checkouts = rebar_app_discover:find_apps([CheckoutsDir], all),
+ Checkouts = rebar_app_discover:find_apps(CheckoutsDirs, all),
CheckoutsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Checkouts],
Plugins = rebar_app_discover:find_apps(PluginDirs, all),
PluginsNames = [{ec_cnv:to_list(rebar_app_info:name(App)), App} || App <- Plugins],
@@ -349,7 +349,7 @@ check_results(AppDir, Expected, ProfileRun) ->
iolist_to_binary(LockVsn))
end
; ({release, Name, Vsn, ExpectedDevMode}) ->
- ct:pal("Release: ~p-~s", [Name, Vsn]),
+ ct:pal("Release: ~p-~ts", [Name, Vsn]),
{ok, Cwd} = file:get_cwd(),
try
file:set_cwd(AppDir),
@@ -377,14 +377,14 @@ check_results(AppDir, Expected, ProfileRun) ->
file:set_cwd(Cwd)
end
; ({tar, Name, Vsn}) ->
- ct:pal("Tarball: ~s-~s", [Name, Vsn]),
+ ct:pal("Tarball: ~ts-~ts", [Name, Vsn]),
Tarball = filename:join([AppDir, "_build", "rel", Name, Name++"-"++Vsn++".tar.gz"]),
?assertNotEqual([], filelib:is_file(Tarball))
; ({file, Filename}) ->
- ct:pal("Filename: ~s", [Filename]),
+ ct:pal("Filename: ~ts", [Filename]),
?assert(filelib:is_file(Filename))
; ({dir, Dirname}) ->
- ct:pal("Directory: ~s", [Dirname]),
+ ct:pal("Directory: ~ts", [Dirname]),
?assert(filelib:is_dir(Dirname))
end, Expected).
diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl
index 66e1fdf..45a7433 100644
--- a/test/rebar_upgrade_SUITE.erl
+++ b/test/rebar_upgrade_SUITE.erl
@@ -11,7 +11,8 @@ groups() ->
triplet_a, triplet_b, triplet_c,
tree_a, tree_b, tree_c, tree_c2, tree_cj, tree_ac, tree_all,
delete_d, promote, stable_lock, fwd_lock,
- compile_upgrade_parity, umbrella_config]},
+ compile_upgrade_parity, umbrella_config,
+ profiles, profiles_exclusion]},
{git, [], [{group, all}]},
{pkg, [], [{group, all}]}].
@@ -78,6 +79,23 @@ setup_project(Case=umbrella_config, Config0, Deps, UpDeps) ->
[{rebarconfig, TopConf},
{rebarumbrella, RebarConf},
{next_top_deps, rebar_test_utils:top_level_deps(UpDeps)} | Config];
+setup_project(Case, Config0, Deps, UpDeps) when Case == profiles;
+ Case == profiles_exclusion ->
+ DepsType = ?config(deps_type, Config0),
+ NameRoot = atom_to_list(Case)++"_"++atom_to_list(DepsType),
+ Config = rebar_test_utils:init_rebar_state(Config0, NameRoot++"_"),
+ AppDir = filename:join([?config(apps, Config), "apps", NameRoot]),
+ rebar_test_utils:create_app(AppDir, "Root", "0.0.0", [kernel, stdlib]),
+ [Top|ProfileDeps] = rebar_test_utils:top_level_deps(Deps),
+ RebarConf = rebar_test_utils:create_config(AppDir, [
+ {deps, [Top]},
+ {profiles, [{fake, [{deps, ProfileDeps}]}]}
+ ]),
+ [NextTop|NextPDeps] = rebar_test_utils:top_level_deps(UpDeps),
+ NextConfig = [{deps, [NextTop]},
+ {profiles, [{fake, [{deps, NextPDeps}]}]}],
+ [{rebarconfig, RebarConf},
+ {next_config, NextConfig} | Config];
setup_project(Case, Config0, Deps, UpDeps) ->
DepsType = ?config(deps_type, Config0),
Config = rebar_test_utils:init_rebar_state(
@@ -454,7 +472,47 @@ upgrades(umbrella_config) ->
{[{"A", "1", []}],
[{"A", "2", []}],
["A"],
- {"A", [{"A","2"}]}}.
+ {"A", [{"A","2"}]}};
+upgrades(profiles) ->
+ %% Ensure that we can unlock deps under a given profile;
+ %% B and C should both be in a custom profile
+ %% and must not be locked.
+ {[{"A", "1", [{"D",[]},
+ {"E","3",[]}]},
+ {"B", "1", [{"F","1",[]},
+ {"G",[]}]},
+ {"C", "0", [{"H","3",[]},
+ {"I",[]}]}],
+ [{"A", "2", [{"D",[]},
+ {"E","2",[]}]},
+ {"B", "2", [{"F","2",[]},
+ {"G",[]}]},
+ {"C", "1", [{"H","4",[]},
+ {"I",[]}]}],
+ ["A","B","C","E","F","H"],
+ {"C", [{"A","1"}, "D", {"E","3"},
+ {"B","2"}, {"F","2"}, "G",
+ {"C","1"}, {"H","4"}, "I"]}};
+upgrades(profiles_exclusion) ->
+ %% Ensure that we can unlock deps under a given profile;
+ %% B and C should both be in a custom profile
+ %% and must not be locked.
+ {[{"A", "1", [{"D",[]},
+ {"E","3",[]}]},
+ {"B", "1", [{"F","1",[]},
+ {"G",[]}]},
+ {"C", "0", [{"H","3",[]},
+ {"I",[]}]}],
+ [{"A", "2", [{"D",[]},
+ {"E","2",[]}]},
+ {"B", "2", [{"F","2",[]},
+ {"G",[]}]},
+ {"C", "1", [{"H","4",[]},
+ {"I",[]}]}],
+ ["A","B","C","E","F","H"],
+ {"A", [{"A","1"}, "D", {"E","3"},
+ {"B","2"}, {"F","2"}, "G",
+ {"C","1"}, {"H","4"}, "I"]}}.
%% TODO: add a test that verifies that unlocking files and then
%% running the upgrade code is enough to properly upgrade things.
@@ -613,6 +671,37 @@ umbrella_config(Config) ->
),
meck:unload(rebar_prv_upgrade).
+profiles(Config) ->
+ apply(?config(mock, Config), []),
+ {ok, TopConfig} = file:consult(?config(rebarconfig, Config)),
+ %% Install dependencies before re-mocking for an upgrade
+ rebar_test_utils:run_and_check(Config, TopConfig, ["lock"], {ok, []}),
+ %% Install test deps along with them
+ rebar_test_utils:run_and_check(Config, TopConfig, ["as","fake","lock"], {ok, []}),
+ {App, Unlocks} = ?config(expected, Config),
+ ct:pal("Upgrades: ~p -> ~p", [App, Unlocks]),
+ Expectation = case Unlocks of
+ {error, Term} -> {error, Term};
+ _ -> {ok, [T || T <- Unlocks,
+ element(1,T) == dep orelse
+ lists:member(element(2,T), ["A","D","E"])]}
+ end,
+
+ meck:new(rebar_prv_app_discovery, [passthrough]),
+ meck:expect(rebar_prv_app_discovery, do, fun(S) ->
+ apply(?config(mock_update, Config), []),
+ meck:passthrough([S])
+ end),
+ NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
+ ?config(next_config, Config)),
+ {ok, NewRebarConfig} = file:consult(NewRebarConf),
+ rebar_test_utils:run_and_check(
+ Config, NewRebarConfig, ["as","fake","upgrade", App], Expectation
+ ),
+ meck:unload(rebar_prv_app_discovery).
+
+profiles_exclusion(Config) -> profiles(Config).
+
run(Config) ->
apply(?config(mock, Config), []),
ConfigPath = ?config(rebarconfig, Config),
diff --git a/test/rebar_xref_SUITE.erl b/test/rebar_xref_SUITE.erl
index 09f73a7..f052fa4 100644
--- a/test/rebar_xref_SUITE.erl
+++ b/test/rebar_xref_SUITE.erl
@@ -9,7 +9,9 @@
end_per_testcase/2,
all/0,
xref_test/1,
- xref_ignore_test/1]).
+ xref_ignore_test/1,
+ xref_dep_hook/1,
+ xref_undef_behaviour/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -28,6 +30,15 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
+init_per_testcase(xref_dep_hook, Config) ->
+ Src = filename:join([?config(data_dir, Config), "recursive"]),
+ Dst = filename:join([?config(priv_dir, Config), "recursive"]),
+ ok = rebar_file_utils:cp_r([Src], Dst),
+ GlobalDir = filename:join([?config(priv_dir, Config), "cache"]),
+ State = rebar_state:new([{base_dir, filename:join([Dst, "_build"])}
+ ,{global_rebar_dir, GlobalDir}
+ ,{root_dir, Dst}]),
+ [{apps, Dst}, {state, State} | Config];
init_per_testcase(Case, Config) ->
UpdConfig = rebar_test_utils:init_rebar_state(Config),
AppDir = ?config(apps, UpdConfig),
@@ -48,7 +59,7 @@ end_per_testcase(_, _Config) ->
ok.
all() ->
- [xref_test, xref_ignore_test].
+ [xref_test, xref_ignore_test, xref_dep_hook, xref_undef_behaviour].
%% ===================================================================
%% Test cases
@@ -70,6 +81,21 @@ xref_ignore_test(Config) ->
Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
verify_results(xref_ignore_test, Name, Result).
+xref_dep_hook(Config) ->
+ rebar_test_utils:run_and_check(Config, [], ["compile"], {ok, []}).
+
+xref_undef_behaviour(Config) ->
+ AppDir = ?config(apps, Config),
+ State = ?config(state, Config),
+ Name = ?config(app_name, Config),
+ RebarConfig = ?config(rebar_config, Config),
+ %% delete one of the behaviours, which should create new warnings
+ delete_src_file(AppDir, Name, behaviour1),
+ %% just ensure this does not crash
+ Result = rebar3:run(rebar_state:new(State, RebarConfig, AppDir), ["xref"]),
+ verify_results(xref_undef_behaviour, Name, Result).
+
+
%% ===================================================================
%% Helper functions
%% ===================================================================
@@ -110,6 +136,31 @@ verify_test_results(xref_test, AppName, XrefResults, _QueryResults) ->
?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)),
?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)),
ok;
+verify_test_results(xref_undef_behaviour, AppName, XrefResults, _QueryResults) ->
+ AppModules = ["behaviour2", "mymod", "othermod", "somemod"],
+ [Behaviour2Mod, MyMod, OtherMod, SomeMod] =
+ [list_to_atom(AppName ++ "_" ++ Mod) || Mod <- AppModules],
+ UndefFuns = proplists:get_value(undefined_functions, XrefResults),
+ UndefFunCalls = proplists:get_value(undefined_function_calls, XrefResults),
+ LocalsNotUsed = proplists:get_value(locals_not_used, XrefResults),
+ ExportsNotUsed = proplists:get_value(exports_not_used, XrefResults),
+ DeprecatedFuns = proplists:get_value(deprecated_functions, XrefResults),
+ DeprecatedFunCalls = proplists:get_value(deprecated_function_calls, XrefResults),
+ ?assert(lists:member({SomeMod, notavailable, 1}, UndefFuns)),
+ ?assert(lists:member({{OtherMod, somefunc, 0}, {SomeMod, notavailable, 1}},
+ UndefFunCalls)),
+ ?assert(lists:member({MyMod, fdeprecated, 0}, DeprecatedFuns)),
+ ?assert(lists:member({{OtherMod, somefunc, 0}, {MyMod, fdeprecated, 0}},
+ DeprecatedFunCalls)),
+ ?assert(lists:member({MyMod, localfunc2, 0}, LocalsNotUsed)),
+ ?assert(lists:member({Behaviour2Mod, behaviour_info, 1}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, other2, 1}, ExportsNotUsed)),
+ ?assert(lists:member({OtherMod, somefunc, 0}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, bh1_a, 1}, ExportsNotUsed)),
+ ?assert(lists:member({MyMod, bh1_b, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh2_a, 1}, ExportsNotUsed)),
+ ?assertNot(lists:member({MyMod, bh2_b, 1}, ExportsNotUsed)),
+ ok;
verify_test_results(xref_ignore_test, AppName, XrefResults, _QueryResults) ->
AppModules = ["behaviour1", "behaviour2", "mymod", "othermod", "somemod"],
[_Behaviour1Mod, _Behaviour2Mod, _MyMod, _OtherMod, SomeMod] =
@@ -128,6 +179,10 @@ write_src_file(Dir, AppName, Module, IgnoreXref) ->
ok = filelib:ensure_dir(Erl),
ok = ec_file:write(Erl, get_module_body(Module, AppName, IgnoreXref)).
+delete_src_file(Dir, AppName, Module) ->
+ Erl = filename:join([Dir, "src", module_name(AppName, Module)]),
+ ok = file:delete(Erl).
+
module_name(AppName, Module) ->
lists:flatten([AppName, "_", atom_to_list(Module), ".erl"]).
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config
new file mode 100644
index 0000000..cf48edf
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/rebar.config
@@ -0,0 +1,12 @@
+{erl_opts, [debug_info]}.
+{deps, []}.
+
+{xref_checks,[
+ undefined_function_calls,
+ undefined_functions,
+ locals_not_used,
+ deprecated_function_calls,
+ deprecated_functions
+]}.
+
+{provider_hooks, [{post, [{compile, xref}]}]}.
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src
new file mode 100644
index 0000000..b935082
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1.app.src
@@ -0,0 +1,16 @@
+{application, rebar_issue1,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { rebar_issue1_app, []}},
+ {applications,
+ [kernel,
+ stdlib
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl
new file mode 100644
index 0000000..78c88c1
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue1 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue1_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ rebar_issue1_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl
new file mode 100644
index 0000000..6e5a9f8
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue1/src/rebar_issue1_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue1 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue1_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src
new file mode 100644
index 0000000..59ffa35
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2.app.src
@@ -0,0 +1,17 @@
+{application, rebar_issue2,
+ [{description, "An OTP application"},
+ {vsn, "0.1.0"},
+ {registered, []},
+ {mod, { rebar_issue2_app, []}},
+ {applications,
+ [kernel,
+ stdlib,
+ rebar_issue1
+ ]},
+ {env,[]},
+ {modules, []},
+
+ {maintainers, []},
+ {licenses, []},
+ {links, []}
+ ]}.
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl
new file mode 100644
index 0000000..968966c
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_app.erl
@@ -0,0 +1,26 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue2 public API
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue2_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%%====================================================================
+%% API
+%%====================================================================
+
+start(_StartType, _StartArgs) ->
+ rebar_issue2_sup:start_link().
+
+%%--------------------------------------------------------------------
+stop(_State) ->
+ ok.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl
new file mode 100644
index 0000000..3673548
--- /dev/null
+++ b/test/rebar_xref_SUITE_data/recursive/apps/rebar_issue2/src/rebar_issue2_sup.erl
@@ -0,0 +1,35 @@
+%%%-------------------------------------------------------------------
+%% @doc rebar_issue2 top level supervisor.
+%% @end
+%%%-------------------------------------------------------------------
+
+-module(rebar_issue2_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% API functions
+%%====================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Supervisor callbacks
+%%====================================================================
+
+%% Child :: {Id,StartFunc,Restart,Shutdown,Type,Modules}
+init([]) ->
+ {ok, { {one_for_all, 0, 1}, []} }.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================