From d80a5a307c27ff463c36110c055c1aaffd4df16d Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Sat, 27 Sep 2025 11:58:47 -0400 Subject: [PATCH 1/6] let's try out exdoc --- .gitignore | 1 + apps/rebar/src/cth_fail_fast.erl | 1 + apps/rebar/src/cth_retry.erl | 1 + apps/rebar/src/rebar_agent.erl | 2 +- apps/rebar/src/rebar_file_utils.erl | 2 +- doc.config | 18 ++++++++++++++++++ 6 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 doc.config diff --git a/.gitignore b/.gitignore index d7740bcb3..38087be00 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ env # hex_core artifact apps/rebar/src/vendored/r3_safe_erl_term.erl +apps/rebar/doc diff --git a/apps/rebar/src/cth_fail_fast.erl b/apps/rebar/src/cth_fail_fast.erl index 13b35570d..970d8b25e 100644 --- a/apps/rebar/src/cth_fail_fast.erl +++ b/apps/rebar/src/cth_fail_fast.erl @@ -1,4 +1,5 @@ -module(cth_fail_fast). +-moduledoc false. %% Callbacks -export([id/1]). diff --git a/apps/rebar/src/cth_retry.erl b/apps/rebar/src/cth_retry.erl index b745c35e9..dac482f15 100644 --- a/apps/rebar/src/cth_retry.erl +++ b/apps/rebar/src/cth_retry.erl @@ -1,4 +1,5 @@ -module(cth_retry). +-moduledoc false. %% Callbacks -export([id/1]). diff --git a/apps/rebar/src/rebar_agent.erl b/apps/rebar/src/rebar_agent.erl index d89a643e9..d71ef7238 100644 --- a/apps/rebar/src/rebar_agent.erl +++ b/apps/rebar/src/rebar_agent.erl @@ -290,9 +290,9 @@ reload_modules(Modules0) -> Modules = [M || M <- Modules0, is_changed(M)], reload_modules(Modules, erlang:function_exported(code, prepare_loading, 1)). -%% @spec is_changed(atom()) -> boolean() %% @doc true if the loaded module is a beam with a vsn attribute %% and does not match the on-disk beam file, returns false otherwise. +-spec is_changed(atom()) -> boolean(). is_changed(M) -> try module_vsn(M:module_info(attributes)) =/= module_vsn(code:get_object_code(M)) diff --git a/apps/rebar/src/rebar_file_utils.erl b/apps/rebar/src/rebar_file_utils.erl index f9ebd07e0..f8ed7deba 100644 --- a/apps/rebar/src/rebar_file_utils.erl +++ b/apps/rebar/src/rebar_file_utils.erl @@ -86,7 +86,7 @@ consult_config(State, Filename) -> consult_config_terms(State, Config). %% @doc Reads a config file via consult_env_config/2 if the file name has -%% the suffix `.src`, and with consult_config/2 otherwise +%% the suffix `.src', and with consult_config/2 otherwise -spec consult_any_config(rebar_state:t(), file:filename()) -> [[tuple()]]. consult_any_config(State, Filename) -> case is_src_config(Filename) of diff --git a/doc.config b/doc.config new file mode 100644 index 000000000..552e6f3b8 --- /dev/null +++ b/doc.config @@ -0,0 +1,18 @@ +%% ./bootstrap +%% REBAR_CONFIG=doc.config ./rebar3 ex_doc + +{project_plugins, [ + {rebar3_ex_doc, "0.2.30"}, + {rebar3_hex, "7.0.11"} +]}. + +{hex, [{doc, #{provider => ex_doc}}]}. +{ex_doc, [ + {source_url, ~"https://example.com"}, + {extras, [ + ~"README.md", + ~"LICENSE", + ~"CONTRIBUTING.md" + ]}, + {main, ~"readme"} +]}. From 6d7133702747a8e6d21b2b0ad04b62ec6ebae4dc Mon Sep 17 00:00:00 2001 From: Jesse Stimpson Date: Sun, 28 Sep 2025 10:51:49 -0400 Subject: [PATCH 2/6] Include rebar3.org docs --- doc.config.script | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 doc.config.script diff --git a/doc.config.script b/doc.config.script new file mode 100644 index 000000000..c4a89595c --- /dev/null +++ b/doc.config.script @@ -0,0 +1,34 @@ +case filelib:is_dir("rebar3.org") of + true -> + ok; + false -> + erlang:error(""" + This demo requires that you clone the rebar3.org repository from GitHub + so that we can bundle the documentation together. + + git clone https://github.com/tsloughter/rebar3.org.git + """) +end, + +GetRebar3OrgFiles = fun() -> + Files = filelib:wildcard("rebar3.org/content/en/docs/**/*.md"), + lists:filter(fun(X) -> nomatch =:= re:run(X, "_index", [{capture, none}]) end, Files) +end, + +FixHeader = fun(File) -> + io:format("Processing ~p~n", [File]), + {ok, Content} = file:read_file(File), + NewContent = re:replace(Content, "^---$\n+title: \"(?[^\"]*)\"$.*^---$", "# \\1", [unicode, dotall, anchored, multiline]), + file:write_file(File, NewContent), + File +end, + +MdFiles = GetRebar3OrgFiles(), +MdFiles = lists:map(FixHeader, MdFiles), + +ExDoc = proplists:get_value(ex_doc, CONFIG), +Extras = proplists:get_value(extras, ExDoc), +Extras2 = Extras ++ MdFiles, +ExDoc2 = lists:keystore(extras, 1, ExDoc, {extras, Extras2}), +CONFIG2 = lists:keystore(ex_doc, 1, CONFIG, {ex_doc, ExDoc2}), +CONFIG2. From f68fcf6abf5c619297f4a25573d6b3a0f8ec80d6 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson <jesse.stimpson@gmail.com> Date: Sun, 5 Oct 2025 10:47:43 -0400 Subject: [PATCH 3/6] Add docs from rebar3.org, reworked for ExDoc - Copy rebar3.org content/en/docs to docs - Remove Hugo headers in all md files - Where possible, move Hugo descriptions to quote blocks under the h1 - Remove search.md - Create package_management/publishing-packages.md from _index.md - Remove content/en/_index.html (the rebar3.org home page) - Create testing/introduction.md from testing/_index.md - Remove _index.md from about, configuration, deployment, extending, and tutorials (only contained generic descriptions) - Tweak markdown tables to render correctly in ExDoc (README, configuration.md, commands.md, building_plugins.md) - Remove <br> from table cells - Rework blocks/callout to Admonitions `{: .warning}` and `{: .info}` - Fix various broken links (e.g. plugins.md publishing, aliases sections, in configuration.md cover section) - Convert internal doc linking to ExDoc paths --- README.md | 62 +- doc.config | 18 - doc.config.script | 34 - docs/about/about-us.md | 16 + docs/about/security-policy.md | 45 ++ docs/basic_usage.md | 195 +++++ docs/commands.md | 336 +++++++++ docs/configuration/config_script.md | 36 + docs/configuration/configuration.md | 558 +++++++++++++++ docs/configuration/dependencies.md | 268 +++++++ docs/configuration/plugins.md | 478 +++++++++++++ docs/configuration/profiles.md | 143 ++++ docs/deployment/releases.md | 671 ++++++++++++++++++ docs/extending/custom_compiler_modules.md | 106 +++ docs/extending/custom_compiler_plugins.md | 96 +++ docs/extending/custom_dep_resources.md | 233 ++++++ docs/getting-started.md | 87 +++ .../package_management/publishing-packages.md | 162 +++++ docs/testing/coverage.md | 27 + docs/testing/ct.md | 29 + docs/testing/eunit.md | 134 ++++ docs/testing/introduction.md | 9 + docs/tutorials/building_c_cpp.md | 157 ++++ docs/tutorials/building_plugins.md | 454 ++++++++++++ docs/tutorials/from_rebar2_to_rebar3.md | 103 +++ docs/tutorials/templates.md | 208 ++++++ .../using_breakpoints_to_debug_tests.md | 277 ++++++++ docs/workflow.md | 124 ++++ rebar.config | 40 ++ 29 files changed, 5023 insertions(+), 83 deletions(-) delete mode 100644 doc.config delete mode 100644 doc.config.script create mode 100644 docs/about/about-us.md create mode 100644 docs/about/security-policy.md create mode 100644 docs/basic_usage.md create mode 100644 docs/commands.md create mode 100644 docs/configuration/config_script.md create mode 100644 docs/configuration/configuration.md create mode 100644 docs/configuration/dependencies.md create mode 100644 docs/configuration/plugins.md create mode 100644 docs/configuration/profiles.md create mode 100644 docs/deployment/releases.md create mode 100644 docs/extending/custom_compiler_modules.md create mode 100644 docs/extending/custom_compiler_plugins.md create mode 100644 docs/extending/custom_dep_resources.md create mode 100644 docs/getting-started.md create mode 100644 docs/package_management/publishing-packages.md create mode 100644 docs/testing/coverage.md create mode 100644 docs/testing/ct.md create mode 100644 docs/testing/eunit.md create mode 100644 docs/testing/introduction.md create mode 100644 docs/tutorials/building_c_cpp.md create mode 100644 docs/tutorials/building_plugins.md create mode 100644 docs/tutorials/from_rebar2_to_rebar3.md create mode 100644 docs/tutorials/templates.md create mode 100644 docs/tutorials/using_breakpoints_to_debug_tests.md create mode 100644 docs/workflow.md diff --git a/README.md b/README.md index 3a223edd7..82ccbf4b5 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,12 @@ Rebar3 will: - handle build artifacts, paths, and libraries such that standard development tools can be used without a headache; - adapt to projects of all sizes on almost any platform; -- treat [documentation](https://rebar3.org/docs/) as a feature, +- treat [documentation](https://hexdocs.pm/rebar3) as a feature, and errors or lack of documentation as a bug. Rebar3 is also a self-contained Erlang script. It is easy to distribute or embed directly in a project. Tasks or behaviours can be modified or expanded -with a [plugin system](https://rebar3.org/docs/configuration/plugins) +with a [plugin system](https://hexdocs.pm/rebar3/configuration/plugins.html) [flexible enough](https://github.com/lfe-rebar3/rebar3_lfe) that even other languages on the Erlang VM will use it as a build tool. @@ -61,23 +61,23 @@ This list presents the known working version combos between Rebar3 and Erlang/OTP. Always use the latest version your project can tolerate for latest security fixes. -| Rebar3 | Erlang/OTP Support Range | Notes -|- |- | - -| 3.25.1 | 26-28 | issues with newer Windows versions were reported on 3.25.0 and OTP-28 -| 3.24.0 | 25-27 | -| 3.23.0 | 25-27 | -| 3.22.1 | 25-27 | -| 3.21.0 | 24-26 | -| 3.20.0 | 23-25 | -| 3.19.0 | 23-25 | -| 3.18.0 | 22-24 | -| 3.17.0 | 22-24 | -| 3.16.1 | 22-24 | Don't use 3.16.0, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html -| 3.15.2 | 19-23 | Don't use 3.15.0 or 3.15.1, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html -| 3.14.1 | 19-23 | -| 3.13.3 | 19-22 | Don't use 3.13.1 or 3.13.2, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html - -A [getting started guide is maintained on the official documentation website](https://rebar3.org/docs/getting-started), +| Rebar3 | Erlang/OTP Support Range | Notes | +|- |- | - | +| 3.25.1 | 26-28 | issues with newer Windows versions were reported on 3.25.0 and OTP-28 | +| 3.24.0 | 25-27 | | +| 3.23.0 | 25-27 | | +| 3.22.1 | 25-27 | | +| 3.21.0 | 24-26 | | +| 3.20.0 | 23-25 | | +| 3.19.0 | 23-25 | | +| 3.18.0 | 22-24 | | +| 3.17.0 | 22-24 | | +| 3.16.1 | 22-24 | Don't use 3.16.0, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html | +| 3.15.2 | 19-23 | Don't use 3.15.0 or 3.15.1, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html | +| 3.14.1 | 19-23 | | +| 3.13.3 | 19-22 | Don't use 3.13.1 or 3.13.2, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html | + +A [getting started guide is maintained on the official documentation website](https://hexdocs.pm/rebar3/getting-started.html), but installing rebar3 can be done by any of the ways described below Latest stable compiled version: @@ -122,7 +122,7 @@ Do note that if you are planning to work with multiple Erlang versions on the sa ## Documentation -Rebar3 documentation is maintained on [https://rebar3.org/docs](https://rebar3.org/docs) +Rebar3 documentation is maintained on [https://hexdocs.pm/rebar3](https://hexdocs.pm/rebar3) ## Features @@ -138,8 +138,8 @@ others via the plugin ecosystem: | Clean up artifacts | Remove the compiled beam files from a project with `rebar3 clean` or just remove the `_build` directory to remove *all* compilation artifacts | | Code Coverage | Various commands can be instrumented to accumulate code coverage data (such as `eunit` or `ct`). Reports can be generated with `rebar3 cover` | | Common Test | The test framework can be run by calling `rebar3 ct` | -| Dependencies | Rebar3 maintains local copies of dependencies on a per-project basis. They are fetched deterministically, can be locked, upgraded, fetched from source, packages, or from local directories. See [Dependencies on the documentation website](https://rebar3.org/docs/configuration/dependencies/). Call `rebar3 tree` to show the whole dependency tree. | -| Documentation | Print help for rebar3 itself (`rebar3 help`) or for a specific task (`rebar3 help <task>`). Full reference at [rebar3.org](https://rebar3.org/docs). | +| Dependencies | Rebar3 maintains local copies of dependencies on a per-project basis. They are fetched deterministically, can be locked, upgraded, fetched from source, packages, or from local directories. See [Dependencies on the documentation website](https://hexdocs.pm/rebar3/configuration/dependencies.html). Call `rebar3 tree` to show the whole dependency tree. | +| Documentation | Print help for rebar3 itself (`rebar3 help`) or for a specific task (`rebar3 help <task>`). Full reference at [rebar3 documentation](https://hexdocs.pm/rebar3). | | Dialyzer | Run the Dialyzer analyzer on the project with `rebar3 dialyzer`. Base PLTs for each version of the language will be cached and reused for faster analysis | | Edoc | Generate documentation using edoc with `rebar3 edoc` | | Escript generation | Rebar3 can be used to generate [escripts](http://www.erlang.org/doc/man/escript.html) providing an easy way to run all your applications on a system where Erlang is installed | @@ -147,12 +147,12 @@ others via the plugin ecosystem: | Locked dependencies | Dependencies are going to be automatically locked to ensure repeatable builds. Versions can be changed with `rebar3 upgrade` or `rebar3 upgrade <app>`, or locks can be released altogether with `rebar3 unlock`. | | Packages | A given [Hex package](https://hex.pm) can be inspected `rebar3 pkgs <name>`. This will output its description and available versions | | Path | While paths are managed automatically, you can print paths to the current build directories with `rebar3 path`. | -| Plugins | Rebar3 can be fully extended with [plugins](https://rebar3.org/docs/configuration/plugins/). List or upgrade plugins by using the plugin namespace (`rebar3 plugins`). | -| Profiles | Rebar3 can have subconfiguration options for different profiles, such as `test` or `prod`. These allow specific dependencies or compile options to be used in specific contexts. See [Profiles](https://rebar3.org/docs/configuration/profiles) in the docs. | -| Releases | Rebar3 supports [building releases](https://rebar3.org/docs/deployment/releases) with the `relx` tool, providing a way to ship fully self-contained Erlang systems. Release update scripts for live code updates can also be generated. | +| Plugins | Rebar3 can be fully extended with [plugins](https://hexdocs.pm/rebar3/plugins.html). List or upgrade plugins by using the plugin namespace (`rebar3 plugins`). | +| Profiles | Rebar3 can have subconfiguration options for different profiles, such as `test` or `prod`. These allow specific dependencies or compile options to be used in specific contexts. See [Profiles](https://hexdocs.pm/rebar3/configuration/profiles.html) in the docs. | +| Releases | Rebar3 supports [building releases](https://hexdocs.pm/rebar3/deployment/releases.html) with the `relx` tool, providing a way to ship fully self-contained Erlang systems. Release update scripts for live code updates can also be generated. | | Shell | A full shell with your applications available can be started with `rebar3 shell`. From there, call tasks as `r3:do(compile)` to automatically recompile and reload the code without interruption | | Tarballs | Releases can be packaged into tarballs ready to be deployed. | -| Templates | Configurable templates ship out of the box (try `rebar3 new` for a list or `rebar3 new help <template>` for a specific one). [Custom templates](https://rebar3.org/docs/tutorials/templates) are also supported, and plugins can also add their own. | +| Templates | Configurable templates ship out of the box (try `rebar3 new` for a list or `rebar3 new help <template>` for a specific one). [Custom templates](https://hexdocs.pm/rebar3/tutorials/templates.html) are also supported, and plugins can also add their own. | | Xref | Run cross-reference analysis on the project with [xref](http://www.erlang.org/doc/apps/tools/xref_chapter.html) by calling `rebar3 xref`. | ## Migrating From rebar2 @@ -160,13 +160,13 @@ others via the plugin ecosystem: The grievances we had with Rebar 2.x were not fixable without breaking compatibility in some very important ways. -A full guide titled [From Rebar 2.x to Rebar3](https://rebar3.org/docs/tutorials/from_rebar2_to_rebar3/) +A full guide titled [From Rebar 2.x to Rebar3](https://hexdocs.pm/rebar3/tutorials/from_rebar2_to_rebar3.html) is provided on the documentation website. Notable modifications include mandating a more standard set of directory structures, changing the handling of dependencies, moving some compilers (such as C, Diameter, ErlyDTL, or ProtoBuffs) to -[plugins](https://rebar3.org/docs/configuration/plugins) rather than +[plugins](https://hexdocs.pm/rebar3/configuration/plugins.html) rather than maintaining them in core rebar, and moving release builds from reltool to relx. @@ -181,13 +181,13 @@ If you need quick feedback, you can try the #rebar channel on [irc.freenode.net](https://freenode.net) or the #rebar3 channel on [erlanger.slack.com](https://erlanger.slack.com/). Be sure to check the -[documentation](https://rebar3.org/docs) first, just to be sure you're not +[documentation](https://hexdocs.pm/rebar3) first, just to be sure you're not asking about things with well-known answers. For bug reports, roadmaps, and issues, visit the [github issues page](https://github.com/erlang/rebar3/issues). General rebar community resources and links can be found at -[rebar3.org/docs/about/about-us/#community](https://rebar3.org/docs/about/about-us/#community) +[Community | About Us](https://hexdocs.pm/rebar3/about/about-us.html#community) -To contribute to rebar3, please refer to [CONTRIBUTING](CONTRIBUTING.md). +To contribute to rebar3, please refer to [CONTRIBUTING](https://github.com/erlang/rebar3/blob/master/CONTRIBUTING.md). diff --git a/doc.config b/doc.config deleted file mode 100644 index 552e6f3b8..000000000 --- a/doc.config +++ /dev/null @@ -1,18 +0,0 @@ -%% ./bootstrap -%% REBAR_CONFIG=doc.config ./rebar3 ex_doc - -{project_plugins, [ - {rebar3_ex_doc, "0.2.30"}, - {rebar3_hex, "7.0.11"} -]}. - -{hex, [{doc, #{provider => ex_doc}}]}. -{ex_doc, [ - {source_url, ~"https://example.com"}, - {extras, [ - ~"README.md", - ~"LICENSE", - ~"CONTRIBUTING.md" - ]}, - {main, ~"readme"} -]}. diff --git a/doc.config.script b/doc.config.script deleted file mode 100644 index c4a89595c..000000000 --- a/doc.config.script +++ /dev/null @@ -1,34 +0,0 @@ -case filelib:is_dir("rebar3.org") of - true -> - ok; - false -> - erlang:error(""" - This demo requires that you clone the rebar3.org repository from GitHub - so that we can bundle the documentation together. - - git clone https://github.com/tsloughter/rebar3.org.git - """) -end, - -GetRebar3OrgFiles = fun() -> - Files = filelib:wildcard("rebar3.org/content/en/docs/**/*.md"), - lists:filter(fun(X) -> nomatch =:= re:run(X, "_index", [{capture, none}]) end, Files) -end, - -FixHeader = fun(File) -> - io:format("Processing ~p~n", [File]), - {ok, Content} = file:read_file(File), - NewContent = re:replace(Content, "^---$\n+title: \"(?<title>[^\"]*)\"$.*^---$", "# \\1", [unicode, dotall, anchored, multiline]), - file:write_file(File, NewContent), - File -end, - -MdFiles = GetRebar3OrgFiles(), -MdFiles = lists:map(FixHeader, MdFiles), - -ExDoc = proplists:get_value(ex_doc, CONFIG), -Extras = proplists:get_value(extras, ExDoc), -Extras2 = Extras ++ MdFiles, -ExDoc2 = lists:keystore(extras, 1, ExDoc, {extras, Extras2}), -CONFIG2 = lists:keystore(ex_doc, 1, CONFIG, {ex_doc, ExDoc2}), -CONFIG2. diff --git a/docs/about/about-us.md b/docs/about/about-us.md new file mode 100644 index 000000000..c85d0132a --- /dev/null +++ b/docs/about/about-us.md @@ -0,0 +1,16 @@ +# About Us +## Community + +- [Issue Tracker](https://github.com/erlang/rebar3/issues) +- [Github Discussions](https://github.com/erlang/rebar3/discussions) +- Slack: #rebar3 on [Erlang Slack](https://erlef.org/slack-invite/erlanger) +- IRC: #rebar on freenode +- [Contribution guidelines](https://github.com/erlang/rebar3/blob/master/CONTRIBUTING.md) + +## Credits + +- [Source Contributors](https://github.com/rebar/rebar3/blob/master/THANKS) *(including rebar 2.x contributors prior to forking)* +- Rebar3 logo by [Francis Tseng](https://twitter.com/frnsys). +- Maintainers with admin rights: + - [@tsloughter](https://github.com/tsloughter/) + - [@ferd](https://github.com/ferd/) diff --git a/docs/about/security-policy.md b/docs/about/security-policy.md new file mode 100644 index 000000000..2a7e0a813 --- /dev/null +++ b/docs/about/security-policy.md @@ -0,0 +1,45 @@ +# Security Policy +## Security Caveats + +Rebar3 is a build tool that by design allows arbitrary code execution from downloaded components. Scripts can be executed in all kinds of areas of a regular project workflow including (but not limited to): scripts to modify configuration files, "parse transforms" (macros), plugins, provider and shell hooks, and so on. + +Users of Rebar3 should be aware of the nature of its model, and issues related to these parts of its design will not be considered to be security issues nor vulnerabilities. + +## Reporting a Security Issue + +All security issues should be reported to one or more of the current maintainers: + +- [Fred Hebert](https://keybase.io/mononcqc) ([@ferd](https://github.com/ferd/)) +- [Tristan Sloughter](https://keybase.io/tsloughter) ([@tsloughter](https://github.com/tsloughter/)) + +E-Mail addresses are available in GitHub profiles, and PGP public keys in Keybase profiles. + +If you have not received a reply to your query within 48 hours, or have not heard from one of the maintainers for the past five days, there are a few steps you can take: + +- One of the authenticated channels in the maintainers Keybase profiles +- Open a GitHub issue directly +- Ask on #rebar3 on the [official Erlang Slack team](https://erlef.org/slack-invite/erlanger) +- Ask on #rebar on IRC on libera.chat + +Please note that the GitHub issues, mailing list, and chat channels are public areas. When escalating in these venues, please do not discuss details of your issue. Simply say that you’re trying to get a hold of someone from the maintainer team. + +## Disclosure Policy + +We're a small project of volunteers working in whatever free time they have, with limited mechanisms to reach developers from other communication channels. + +Disclosure will be fairly ad-hoc and made to reach as many people as possible. + +Nevertheless, the expected steps are: + +1. The issue is received and discussed privately by the maintainers +2. A fix is prepared and reviewed between maintainers +3. When ready, the fix will be committed to the repository and a release will be cut +4. An announcement will be made about the new release on the public channels associated to the project + +## Receiving Security Updates + +The best way to know about security updates is to subscribe to any of the communication channels of the project. + +## Comments on This Policy + +If you have any suggestions to improve this policy, please contact the maintainers or open a GitHub issue. diff --git a/docs/basic_usage.md b/docs/basic_usage.md new file mode 100644 index 000000000..201a7eae0 --- /dev/null +++ b/docs/basic_usage.md @@ -0,0 +1,195 @@ +# Basic Usage + +## New App or Release + +There are two main ways to organize code with rebar3 projects: either as a single application, or as an umbrella project. + +Single application projects contain a lone top-level application at the root of the directory, with its Erlang source modules directly inside a `src/` directory. This format is applicable to libraries to be published on GitHub or in hex with the objective of making them shareable to the world, but can also be used with [Releases](deployment/releases.md), which allow to ship an Erlang runtime system that boots the application directly. + +Umbrella projects' defining characteristic is that they can contain multiple top-level Erlang/OTP applications, usually within a top-level `apps/` or `lib/` directory. Each of these applications may contain its own rebar.config file. This format is applicable to only for releases with one or more top-level applications. + +Rebar3 comes with templates for creating either types of project, callable through the `rebar3 new <template> <project-name>` command. The `<template>` value can be any of: + +- `app`: a stateful OTP application with a supervision tree, as a single application project +- `lib`: a library OTP application (without supervision trees), useful for grouping together various modules, as a single application project +- `release`: an umbrella project ready to be released +- `umbrella`: an alias for `release` +- `escript`: a special form of single application project that can be built as a runnable script +- `plugin`: structure for a rebar3 plugin +- `cmake`: generates a `c_src` directory and `Makefile` for building C/C++ code + +For example: + +```shell +$ rebar3 new app myapp +===> Writing myapp/src/myapp_app.erl +===> Writing myapp/src/myapp_sup.erl +===> Writing myapp/src/myapp.app.src +===> Writing myapp/rebar.config +===> Writing myapp/.gitignore +===> Writing myapp/LICENSE +===> Writing myapp/README.md +``` + +For more information on `new` and available options check the docs on [commands](commands.md) and to learn how to create and use custom templates go to the [templates tutorial](tutorials/templates.md). + +## Adding Dependencies + +Dependencies are listed in `rebar.config` file under the `deps` key: + +```erlang +{deps, [ + {elli, "~> 3.3.0"}, % package + {elli, {git, "git://github.com/elli-lib/elli.git", {tag, "3.3.0"}}} % alternatively, source + ] +}. +``` + +Now you can add the dep to one of your project's application's .app.src file under applications so that Erlang knows the dependency is required for yours to work: + +```erlang +{application, <APPNAME>, + [{description, ""}, + {vsn, <APPVSN>}, + {registered, []}, + {modules, []}, + {applications, [kernel, + stdlib, + elli]}, + {mod, {<APPNAME>_app, []}}, + {env, []} + ]}. +``` + +The `<APPVSN>` value can be any of: + +| Version type | Result | +| --------------------- | ------------------------------------------------------------- | +| `string()` | A string is used, as is, for the version. Example: `"0.1.0"`| +| `git | semver` | Uses the latest git tag on the repo to construct the version. | +| `{cmd, string()}` | Uses the result of executing the contents of `string()` in a shell. Example to use a file `VERSION`: `{cmd, "cat VERSION | tr -d '[:space:]'"}` | +| `{git, short | long}` | Uses either the short (8 characters) or the full Git ref. of the current commit. | +| `{file, File}` | Uses the content of a file. For example, a better way to use a `VERSION` file than using `cmd` would be: `{file, "VERSION"}` | + +For more information on dependency handling view the [dependency documentation](configuration/dependencies.md) + +## Building + +Only one command, `compile`, is required to fetch dependencies and compile all applications. + +```shell +$ rebar3 compile +===> Verifying dependencies... +===> Fetching elli v3.3.0 +===> Analyzing applications... +===> Compiling elli +===> Analyzing applications... +===> Compiling custom_hex_repos +``` + +## Output Format + +Output for installing dependencies, building releases and any other output written to disk is found in the `_build` directory at the root of the project. + +```shell +_build/ +└── default + └── lib + └── elli +``` + +More about profiles and the `_build` directory can be found in the [profiles documentation page](configuration/profiles.md). + +## Testing + +Tests by default are expected to be found under the `test/` directory, aside from `eunit` found within individual modules. + +Dependencies that are only needed for running tests can be placed in the `test` profile: + +```erlang +{profiles, [ + {test, [ + {deps, [ + {meck, "0.9.0"} + ]} + ]} +]}. +``` + +Now the first time `rebar3 ct` is run `meck` will be installed to `_build/test/lib/`. But it will not be added to `rebar.lock`. + +```shell +_build/ + └── test + └── lib + └── meck +``` + +## Releases and Target Systems + +Releases are built using [relx](https://github.com/erlware/relx). + +Creating a new project with a release structure and default `relx` config in the `rebar.config` file run: + +```shell +$ rebar3 new release myrel +===> Writing myrel/apps/myrel/src/myrel_app.erl +===> Writing myrel/apps/myrel/src/myrel_sup.erl +===> Writing myrel/apps/myrel/src/myrel.app.src +===> Writing myrel/rebar.config +===> Writing myrel/config/sys.config +===> Writing myrel/config/vm.args +===> Writing myrel/.gitignore +===> Writing myrel/LICENSE +===> Writing myrel/README.md +``` + +Looking in `rebar.config` we find a couple elements that were not there in our application example. + +```erlang +{relx, [{release, {myrel, "0.0.1"}, + [myrel]}, + + {dev_mode, true}, + {include_erts, false}, + + {extended_start_script, true} + ] +}. + +{profiles, [ + {prod, [{relx, [{dev_mode, false}, + {include_erts, true}]} + ]} +]}. +``` + +This configuration provides some nice defaults for building a release with Relx for development (default profile) and for production (prod profile). When building a release for production we'll most likely want to create a target system (include erts) and definitely will not want the release to contain symlinks to apps (`dev_mode` `false`). + +```shell +$ rebar3 release +===> Verifying default dependencies... +===> Compiling myrel +===> Starting relx build process ... +===> Resolving OTP Applications from directories: + _build/default/lib + /usr/lib/erlang/lib +===> Resolved myrel-0.1.0 +===> Dev mode enabled, release will be symlinked +===> release successfully created! +``` + +With the default `rebar.config`, creating a compressed archive of the release as a target system is as simple as setting the profile to `prod` and running `tar`: + +```shell +$ rebar3 as prod tar +===> Verifying dependencies... +===> Analyzing applications... +===> Compiling relx_overlays +===> Assembling release myrel-0.1.0... +===> Release successfully assembled: _build/prod/rel/myrel +===> Building release tarball myrel-0.1.0.tar.gz... +===> Tarball successfully created: _build/prod/rel/myrel/myrel-0.1.0.tar.gz +``` + +For more details go to the [release section](deployment/releases.md). diff --git a/docs/commands.md b/docs/commands.md new file mode 100644 index 000000000..f983fae8a --- /dev/null +++ b/docs/commands.md @@ -0,0 +1,336 @@ +# Commands + +> Usage of each Rebar3 command. + +Each command represents a task which runs one or more providers to fulfill the task. + +## alias + +List aliases' definitions (from `rebar.config`). + +Example output: + +```console +test=eunit,ct --suite=rebar_alias_SUITE,cover +check=xref,dialyzer +``` + +## as + +Higher order task which takes a profile name and list of tasks to run under that profile. + +## compile + +After ensuring all dependencies are available, and fetching them if they are not, compile will compile the needed dependencies and the project's apps' `.app.src` and `.erl` files. + +| Option | Type | Description | +| ---------------- | ---- | ---------------------------------------------------------| +| `-d/--deps_only` | none | Only compile dependencies, no project apps will be built | + +## completion + +> #### Since version 3.23.0 {: .info} + +Generates a completion file for one of the supported shells: `bash`, `zsh`. + +Completion files can be generated based on the project setup, so autocompletion also works for all plugins used in the project, not just for default providers. + +To use generated completion files run `source path/to/generated/file`. + +| Option | Type | Description | +| ------- | ------- | --------- | +| `-a/--aliases` | Comma separated list of strings | OS level aliases on which rebar3 completion will be triggered (e.g. `"rebar, r3"`) | +| `-f/--file` | string | Completion file name. If not absolute, it's relative to the `_build/<profile>/` directory | +| `-s/--shell` | atom | Specify type of the completion file. By default it is autodected using `$SHELL` variable. Valid values are `bash` and `zsh`. | + +> #### zsh specific requirement {: .warning} +> Make sure that `autoload -Uz compinit; compinit` is called in `.zshrc` file. + +For better user experience, set default autocompletion and override it when needed. +Default autocompletion can be set by generating a global completion file and loading it in `.bashrc` or `.zshrc`. + +To generate a global (project-independent) completion file run `rebar3 completion --file path/to/global/completion/file` outside a `rebar3` project. + + + +## clean + +Removes compiled BEAM files from apps. + +The `clean` command by default removes the BEAM files for top-level applications. It does so while respecting profiles, which means that 'rebar3 clean' will only clean the default profile, and 'rebar3 as test clean' will only clean the test profile. + +| Option | Type | Description | +| -------------- | ------------------------------- | ------------------------------------------------------| +| `--all/-a` | none | Clean all apps, including the dependencies | +| `--apps` | Comma separated list of strings | Clean a specific list of apps or dependencies | +| `--profile/-p` | string | Specify a profile (alternative to `rebar3 as clean`) | + +## ct + +Runs common tests for the project located under the `test/` directory. + +Most Common Test [options](https://www.erlang.org/doc/man/ct_run.html) as described in the Erlang documentation for `ct_run` are available. Some common ones are described below: + +| Option | Type | Description | +| ----------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `--dir` | Comma separated list of strings | Compile and run all test suites in the specified directories. | +| `--suite` | Comma separated list of strings | Compile and run all test suites specified. Must be specified by full path, either absolute or relative to the current directory. | +| `--group` | Comma separated list of strings | Test groups to run. See the [Common Test Documentation.](https://erlang.org/doc/apps/common_test/index.html) | +| `--case` | Comma separated list of strings | List of test cases to run. See the [Common Test Documentation.](https://erlang.org/doc/apps/common_test/index.html) | +| `--spec` | Comma separated list of strings | List of [Test Specifications](https://erlang.org/doc/apps/common_test/run_test_chapter.html#test_specifications) | +| `--join_specs` | Comma separated list of strings | Like `--spec` but merges all the specifications into one and does a single run. | +| `--repeat` | Integer | How often to repeat the tests | +| `--duration` | String (format: HHMMSS) | Max allowed duration of the test run | +| `--until` | String (format: HHMMSS) | Time until which to run the tests | +| `--force_stop` | `true \| false \| skip_rest` | Force termination on test timeout | +| `--multiply_timetraps` | Integer | Extends the timeout values for tests by a given multiplier value | +| `--scale_timetraps` | Boolean | Enables automatic timeout value scaling, when using code coverage or tracing | +| `--abort_if_missing_suites` | Boolean | Abort the test run if a test suite is missing (Default: true) | +| `--sys_config` | String | List of OTP application config files (like `sys.config`) that should be applied by Rebar3 before the test run. | +| `--config` | Comma separated list of strings | Config files to use when running tests. See the [Common Test Documentation.](https://erlang.org/doc/apps/common_test/index.html) | +| `--allow_user_terms` | Boolean | Allow user defined config values in config files. See the [Common Test Documentation.](https://erlang.org/doc/apps/common_test/index.html) | +| `--decrypt_key` | String | If the configuration file is encrypted, set the key to decrypt it | +| `--decrypt_file` | String | If the configuration file is encrypted, point to the file containing the key to decrypt it | +| `--logdir` | String | The directory in which test logs will be written. See the [Common Test Documentation.](https://erlang.org/doc/apps/common_test/index.html) Default: `_build/test/logs` | +| `--logopts` | Comma separated list of strings | Set common test logging options. See the [Common Test Documentation.](https://erlang.org/doc/apps/common_test/index.html) Default: `_build/test/logs` | +| `--readable` | Boolean | Adds test names with results on a per-test basis, and only displays common-test logs in the terminal on failing tests. Default: `true` | +| `--verbose`, `-v` | Boolean | Enable verbose output. Default: false | +| `--verbosity` | Integer | Set the level of Common Test verbosity | +| `--cover`, `-c` | Boolean | Generate cover data | +| `--cover_export_name` | String | Change the name of the code coverage file | +| `--label` | String | Set a test label | +| `--basic_html` | Boolean | show basic HTML | +| `--stylesheet` | String | CSS stylesheet to apply to HTML output | +| `--create_priv_dir` | `auto_per_run \| auto_per_tc \| manual_per_tc` | change the behaviour of the private (scratch) directories creation done by Common Test | +| `--include` | String | Additional directories containing include files. Option added for parity with ct_run, usually rebar3 should take care of include file paths | +| `--name`, `--sname` | String | Start a distributed node with a given name | +| `--setcookie` | String | Set a value for the distributed cookie | +| `--compile_only` | Boolean | Compile the project with the test configuration specified, but without running the tests | + +Runs in the `test` profile. + +## cover + +Performs coverage analysis on modules called by Common Test or Eunit test suites. Call as `rebar3 do ct, cover`, `rebar3 do eunit, cover` or the combination of both with `rebar3 do eunit, ct, cover` while the `{cover_enabled, true}` option is in your rebar config file, or if the cover flags were used with these commands individually. + +An HTML report is generated. + +| Option | Type | Description | +| ---------------------- | ------- | ---------------------------------------------------------- | +| `-m`, `--min_coverage` | Integer | Mandate a coverage percentage required to succeed (0..100) | +| `--reset`, `-r` | none | Resets all cover data | +| `--verbose`, `-v` | none | Prints coverage analysis in the terminal. | + +Specific modules can be blacklisted from code coverage by adding `{cover_excl_mods, [Modules]}` to the config file. Specific applications can be blacklisted by adding `{cover_excl_apps, [AppNames]}` to the config file. + +## deps + +Lists dependencies, whether they're source or package dependencies, and whether they're locked or not. Those that are locked but not matching the lock file are followed by an asterisk (`*`). + +## do + +Higher order provider for running multiple tasks in a sequence, separated by commas. Example: `rebar3 do a, b, c`. + +## dialyzer + +Builds and keeps up-to-date a suitable PLT (Persistent Lookup Table), and uses it to carry out success typing analysis on the current project. + +| Option | Type | Description | Default | +| ---------------------- | ------- | --------------------------------- | ------- | +| `--incremental`, `-i` | boolean | Enable incremental analysis mode. | false | +| `--update-plt`, `-u` | boolean | Enable updating the PLT. | true | +| `--succ-typings`, `-s` | boolean | Enable success typing analysis. | true | + +For instructions on suppressing warnings read the [Requesting or Suppressing Warnings in Source Files](https://erlang.org/doc/man/dialyzer.html) section of the Dialyzer documentation. + +PLT files are named `<prefix>_<otp_release>_plt`; The base PLT is a PLT containing the core applications often required for a project's PLT. One base PLT is created per OTP version and stored in `base_plt_location`. A base PLT is then used to build project PLTs. + +The following (optional) configurations can be added to a `proplist` of options `dialyzer` in rebar.config: + +| Option | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `warnings` | a list of dialyzer warnings | +| `get_warnings` | display warnings when altering a PLT file (boolean) | +| `plt_apps` | the strategy for determining the applications which are included in the PLT file, `top_level_deps` to include just the direct dependencies or `all_deps` to include all nested dependencies (the direct dependent applications are listed in `applications` and `included_applications` of their .app files.) | +| `plt_extra_apps` | a list of applications to include in the PLT file (the applications in `base_plt_apps` will already be in the list) | +| `plt_location` | the location of the PLT file, `local` to store in the profile's base directory (default) or a custom directory. | +| `plt_prefix` | the prefix to the PLT file, defaults to "rebar3" | +| `base_plt_apps` | a list of applications to include in the base PLT file | +| `base_plt_location` | the location of base PLT file, `global` to store in $HOME/.cache/rebar3 (default) or a custom directory | +| `base_plt_prefix` | the prefix to the base PLT file, defaults to "rebar3" | +| `incremental` | incremental analysis mode | + +## edoc + +Generates documentation using doc. + +Runs in the `docs` profile. + +## escriptize + +Generates an [escript](https://www.erlang.org/doc/man/escript.html) executable containing the project's and its dependencies' BEAM files. + +| Config Option | Type | Description | +| ------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `escript_main_app` | atom | Name of the application to turn to an escript. Defaults to the top-level app if there is only one. When using an umbrella repository (with multiple top-level apps), this value *must* be specified. | +| `escript_name` | string | Name of the generated escript, and default module name to boot (`Module:main(_)`). Defaults to the value for `escript_main_app` | +| `escript_incl_apps` | list of atoms | List of applications to include in the escript archive aside from the main app and its dependencies (from the app file). Defaults to `[]` | +| `escript_emu_args` | string | Escript emulator arguments (after `%%!` in escript declarations). The string must begin with `%%!` and end with a line break. An example string would be `"%%! +sbtu +A0\n"`. The Default value is `"%%! -escript main MainApp\n"` | +| `escript_shebang` | string | Location of escript file to run. Defaults to `"#!/usr/bin/env escript\n"`. The end of line marker must be included in the string. | +| `escript_comment` | string | Arbitrary comment to put into the generated escript. Must include a newline marker at the end. Defaults to `%%\n`. | + +To override the default module name for the escript (which is expected to be the same as the `escript_name`), add `-escript main Module` to `escript_emu_args`. + +Example escript configuration from `relx`: + +```erlang +{escript_emu_args, "%%! +sbtu +A0 -noinput\n"}. +{escript_incl_apps, [getopt, erlware_commons, bbmustache, providers, relx]}. +``` + +## eunit + +Runs EUnit tests on project apps. + +| Config Option | Type | Description | +| --------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `--application` | Comma separated list of strings | Application test suites to run. Equivalent to `[{application, App}]` | +| `-c, --cover` | Boolean | Generate cover data. Defaults to false | +| `--cover_export_name` | String | Base name of the coverdata file to write | +| `-p, --profile` | Boolean | Show the slowest tests. Defaults to false | +| `-d, --dir` | Comma separated list of strings | Dirs to load tests from. Equivalent to `[{dir, Dir}]` | +| `-f, --file` | Comma separated list of strings | Files to load tests from. Equivalent to `[{file, File}]` | +| `-m, --module` | Comma separated list of strings | Modules to load tests from. Equivalent to `[{module, Module}]` | +| `-t, --test` | Comma separated list of strings | Tests to run. The format is `Module:Func1+Func2`. Equivalent to `[{test, Module, Function}]` | +| `-g, --generator` | Comma separated list of strings | Generators to load tests from. The format is `Module:Func1+Func2`. Equivalent to `[{generator, Module, Function}]`. | +| `-v, --verbose` | Boolean | Verbose output. Defaults to false. | +| `--name` | String | Gives a long name to the node | +| `--sname` | String | Gives a short name to the node | +| `--sys_config` | Comma separated list of strings | List of application config files | +| `--setcookie` | String | Sets the cookie if the node is distributed | + +For more details, see [EUnit](testing/eunit.md). + +Runs in the `test` profile. + +## get-deps + +> #### Not Required {: .warning} +> Unlike Rebar 2 this command is not required for fetching dependencies. The compile command will result in dependencies being fetched and then built if they aren't already. This command is useful if you have a specific use case that requires fetching dependencies separate from compilation. + +Fetch project dependencies. + +## help + +Displays a list of tasks or help for a given task or subtask. + +|Option|Description| +|----|----| +|`<task>`|Task to print help for.| +|`<namespace> <task>` |Task within \<namespace\> to print help for| + +## new + +Creates a new project from templates. See a list of available templates by providing no arguments. + +| Option | Description | +|------------------|-------------------------------------------------------| +|`--force`, `-f` | Overwrite existing files. | +|`help <template>` | Display all variables and arguments for each template | + +## path + +Print paths to build dirs in current profile. + +| Option | Type | Description | +| ------------------- | ------------------------------- | ------------------------------------------------------------------------------ | +| `--app` | Comma separated list of strings | Comma separated list of applications to return paths for. | +| `--base` | none | Return the base path of the current profile. | +| `--bin` | none | Return the bin path of the current profile. | +| `--ebin` | none | Return all ebin paths of the current profile's applications. | +| `--lib` | none | Return the lib path of the current profile. | +| `--priv` | none | Return the priv path of the current profile. | +| `--separator`, `-s` | string | In case of multiple return paths, the separator character to use to join them. | +| `--src` | none | Return the src path of the current profile's applications. | +| `--rel` | none | Return the rel path of the current profile. | + +## release + +Builds release of project. Call `rebar3 help release` for arguments. + +## relup + +Creates a relup from two releases that were already built by calling `rebar3 release` without clearing the `_build` directory. Call `rebar3 help relup` for arguments. + +## report + +Generates contextual data to include in bug reports. + +## shell + +Runs a shell with project apps and deps in path. Intended for development use only; use [Releases](deployment/releases.md) for production. + +| Option | Type | Description | +| ------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------- | +| `--config` | string | Allows to load a [config file](https://www.erlang.org/doc/man/config.html), if any. Defaults to the sys_config entry defined for relx if present. | +| `--name`, `--sname` | atom | Starts the node in network mode. Equivalent to erl's `-name` and `-sname` options. | +| `--setcookie` | string | Sets the cookie for a distributed node. Equivalent to erl's `-setcookie` option. | +| `--script` | string | path to an escript to be evaluated before applications are started. | +| `--apps` | string | Comma-separated list of application names to be booted. Defaults to the apps in the relx release if present. | +| `--start-clean` | | When specified, no apps are booted by the shell; useful to override release or shell tuple configurations in rebar.config. | +| `--relname`, `-r` | atom | If multiple releases are present, specify which one to pick. | +| `--relvsn`, `-v` | string | If multiple releases are present, specify which version to use. | +| `--env-file` | string | Path to file of os environment variables to setup before expanding vars in config files. | +| `--user_drv_args` | string | For versions of Erlang prior to 26, this option can be used to pass arguments to the user_drv start function for creating custom shells. Starting with Erlang 26, the arguments defined with this option are applied to the shell start_interactive function.| +| `--eval` | string | Erlang expressions to execute during startup. These will run last, just before presenting the user with the Erlang shell prompt. There can be more than one `--eval` switch. Roughly equivalent to erl's `-eval` option.| + +The shell booted with this command has a running agent that allows running Rebar3 commands dynamically, such as `r3:compile()` or `r3:upgrade()`, and have new modules automatically reloaded. Specific namespaces can be reached by calling `r3:do(Namespace, Command)`. No arguments can be passed to these commands. + +## tar + +Builds a compressed tar archive of release built of project. Call `rebar3 help tar` for arguments. + +## tree + +Prints a tree of dependencies and transitive dependencies of the project. + +| Option | Type | Description | +| ----------------- | ---- | ------------------------------------------------- | +| `-v`, `--verbose` | none | Print repo and branch/tag/ref for git and hg deps | + +## lock + +Get unbuilt dependencies to be added to the `rebar.lock` file. They will just have been downloaded, but none of their build script should have run. Though this is not necessarily true with pre/post hooks and dep plugins. + +## unlock + +Unlocks dependencies. Specify a comma separated list of dependencies to unlock and regenerate the `rebar.lock` file, or `-a,--all` to unlock them all and remove the `rebar.lock` file. + +This command should be used when one or more dependencies have been taken out of `rebar.config`, but remain in the lock file. + +| Option | Type | Description | +| -------------- | ------ | ----------------------------------------- | +| `<dependency>` | string | Dependencies to unlock (comma-separated). | +| `-a`, `--all` | none | Unlock all dependencies. | + +## update + +Updates the package index. + +## upgrade + +Takes the current dependency specifications in `rebar.config` and fetches the most up-to-date versions satisfying them, while updating the lock file accordingly. + +| Option | Type | Description | +| -------------- | ------ | ------------------------------------------ | +| `<dependency>` | string | Dependencies to upgrade (comma-separated). | +| `-a`, `--all` | none | Upgrade all dependencies. | + + +## version + +Prints version for rebar3 and current Erlang. + +## xref + +Runs cross reference analysis. diff --git a/docs/configuration/config_script.md b/docs/configuration/config_script.md new file mode 100644 index 000000000..c078d6304 --- /dev/null +++ b/docs/configuration/config_script.md @@ -0,0 +1,36 @@ +# Config Scripts + +With `rebar.config` and `*.app.src` you can make use of dynamic configuration based on [file:script/2](https://www.erlang.org/doc/man/file.html#script-2). + +If a `<name>.script` exists in the same directory as the original file (in the case of `rebar.config` that would be `rebar.config.script`), the script file will be evaluated and the result used as configuration. + +For convenience two bindings (variables) are available in a script during evaluation: + +- `CONFIG` - the result of [file:consult/1](https://www.erlang.org/doc/man/file.html#consult-1) if the script file being evaluated also exists + +without the ``.script`` extension. Otherwise, `[]`. + +- `SCRIPT` - the filename of the script being evaluated + +In all cases, the data returned by the script, that is the last thing evaluated in the file, must be data in the same format as the original non-script file. For example, if I have `rebar.config.script` that script must return Rebar3 configuration data, if it is an `<app-name>.app.src.script` it must return data in the Application Metadata Format. + +Each script may be executed more than once within each Rebar3 execution. It is a good idea to avoid scripts that have side-effects that are not [idempotent](https://en.wikipedia.org/wiki/Idempotence). + +## Simple Example + +If you are building fairly complex systems, going to GitHub to fetch deps each time will slow down your development cycle. Serving dependencies locally may be a much faster route, but you don't want to modify the `rebar.config` and suffer merge conflicts as a result. + +The following `rebar.config.script` file can be kept centrally, and linked into your application directory: + +```erlang +case os:getenv("REBAR_DEPS") of + false -> CONFIG; % env var not defined + [] -> CONFIG; % env var set to empty string + Dir -> + lists:keystore(deps_dir, 1, CONFIG, {deps_dir, Dir}) +end. +``` + +Whenever you want to build 'properly' (which you should, regularly), simply call `unset REBAR_DEPS` (or equivalent), and perform a clean build. + +Note that `file:script/2` differs from `file:consult/1` in that only the result of the last expression is returned. You must therefore take care to return a list of config items. Before that, you may do any form of I/O (including network), checking OS environment variables, reading files (perhaps calling `file:script/2` on other files) or writing files. You can basically use all OTP libs. As in `file:eval/2`, each expression is terminated with a full stop. diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md new file mode 100644 index 000000000..431122ab3 --- /dev/null +++ b/docs/configuration/configuration.md @@ -0,0 +1,558 @@ +# Base Config + +Nearly all of Rebar3's configuration is done by modifying a `rebar.config` file at the root of your project or OTP application's main directory. The values defined at the root of a project will apply to all applications declared there, and specific configuration files within an OTP application's main directory will apply only to that application. The few exceptions to that rule are global configuration used [for plugins](configuration/plugins.md) and environment variables for changes to overall Rebar3 behaviour. + +This page documents all of the standard options that can go in a `rebar.config` file, and the environment variables that can impact Rebar3's behaviour. + +## Environment configuration + +Rebar3 supports some options that will impact the behaviour of the tool wholesale. Those are defined as OS environment variables, as follows: + +```shell +REBAR_PROFILE="term" # force a base profile +HEX_CDN="https://..." # change the Hex endpoint for a private one +QUIET=1 # only display errors +DEBUG=1 # show debug output + # "QUIET=1 DEBUG=1" displays both errors and warnings +DIAGNOSTIC=1 # show maintainers output +REBAR_COLOR="low" # reduces amount of color in output if supported +REBAR_CACHE_DIR # override where Rebar3 stores cache data +REBAR_GLOBAL_CONFIG_DIR # override where Rebar3 stores config data +REBAR_BASE_DIR # override where Rebar3 stores build output +REBAR_CONFIG="rebar3.config" # changes the name of rebar.config files +REBAR_GIT_CLONE_OPTIONS="" # pass additional options to all git clone operations + # for example, a cache across project can be set up + # with "--reference ~/.cache/repos.reference" +http_proxy # standard proxy ENV variable is respected +https_proxy # standard proxy ENV variable is respected +TERM # standard terminal definition value. TERM=dumb disables color +``` + +## Alias + +Aliases allow for creating new commands out of existing ones, as if they were run one after the other: + +```erlang +{alias, [{check, [eunit, {ct, "--sys_config=config/app.config"}]}]}. +``` + +Arguments (as with a command line) can be passed by replacing `Provider` with `{Provider, Args}`. + +## Artifacts + +Artifacts are a list of files that are required to exist after a successful compilation (including any compile hooks) other than Erlang modules. This is useful to let `rebar3` figure out if a dependency with some non-Erlang artifacts was successfully built or not. Examples where this can be useful include identifying C code built for shared libraries, rendered templates, or that an escript was properly generated. + +If a dependency is found to already be built (meaning its `.app` file's list of modules matches its `.beam` files and all its artifacts exist) it will not have the compilation provider or its hooks called on it during a subsequent run of `rebar3`. + +```erlang +{artifacts, [file:filename_all()]}. +``` + +What the paths are relative to depends on if it is defined at the top level of an umbrella project or not. For example, let's say we have a project `my_project` that contains an application `my_app` under `apps/my_app/` that we build an `escript` from. Then we want to tell `rebar3` to not consider the configuration in `my_project/rebar.config`, since it is the top level `rebar.config` of an umbrella. The `artifact` will be relative to the `profile_dir`, which by default is `_build/default/`: + +```erlang +{escript_name, rebar3}. + +{provider_hooks, [{post, [{compile, escriptize}]}]}. + +{artifacts, ["bin/rebar3"]}. +``` + +If instead it isn't an umbrella but with `my_app` being the top level directory the artifact defined in `rebar.config` is relative to the application's output directory, in this case `_build/default/lib/my_app/` but we can use a template to define it from `profile_dir` as well: + +```erlang +{escript_name, rebar3}. + +{provider_hooks, [{post, [{compile, escriptize}]}]}. + +{artifacts, ["{{profile_dir}}/bin/rebar3"]}. +``` + +All available template key are listed in the table below. + +| Template Key | Description | +| ------------ | --------------------------------------------------------------------------------------- | +| profile_dir | The base output directory with the profile string appended, default: `_build/default/`. | +| base_dir | The base output directory, default: `_build` or value of `REBAR_BASE_DIR` env var. | +| out_dir | The application's output directory, default: `_build/default/lib//`. | + +One more example would be using artifacts within an override, in this case for `eleveldb`: + +```erlang +{overrides, + [{override, eleveldb, [{artifacts, ["priv/eleveldb.so"]}, + ... + ] + }]}. +``` + +The artifact is define on the application `eleveldb` so it is relative to the output directory, meaning the path used above is the same as if we used `"{{out_dir}}/priv/eleveldb.so"`. + +## Compilation + +Compiler options can be set with `erl_opts`, available options are listed in the Erlang compile module's [documentation](https://www.erlang.org/doc/man/compile.html). + +```erlang +{erl_opts, []}. +``` + +Additionally it is possible to set platform specific options. The options run a regular expression against the OTP version joined with the OS details. + +```erlang +{erl_opts, [{platform_define, + "(linux|solaris|freebsd|darwin)", + 'HAVE_SENDFILE'}, + {platform_define, "(linux|freebsd)", + 'BACKLOG', 128}, + {platform_define, "^18", + 'OTP_GREATER_THAN_18'}, + {platform_define, "^R13", + 'old_inets'}] +}. +``` + +The version string might look like `"22.0-x86_64-apple-darwin18.5.0-64"` so if you want to check for a specific OTP version (and avoid matching against an OS version), remember to prefix your regular expression with `^`. + +A separate compile option is one to declare modules to compile before all others: + +```erlang +{erl_first_files, ["src/mymodule.erl", "src/mymodule.erl"]}. +``` + +And some other general options exist: + +```erlang +{validate_app_modules, true}. % Make sure modules in .app match those found in code +{app_vars_file, undefined | Path}. % file containing elements to put in all generated app files +%% Paths the compiler outputs when reporting warnings or errors +%% relative (default), build (all paths are in _build, default prior +%% to 3.2.0, and absolute are valid options +{compiler_source_format, relative}. +``` + +Other Erlang-related compilers are supported with their own configuration options: + +- [Leex compiler](https://erlang.org/doc/man/leex.html) with `{xrl_opts, [...]}` +- [SNMP MIB Compiler](https://www.erlang.org/doc/apps/snmp/snmp_mib_compiler.html) with `{mib_opts, [...]}` +- [Yecc compiler](https://erlang.org/doc/man/yecc.html) with `{yrl_opts, [...]}` + +### Rebar3 compiler options + +Rebar3 ships with some compiler options specific to it. + +#### Enable/Disable recursive compiling + +Disable or enable recursive compiling globally: + +```erlang +{erlc_compiler,[{recursive,boolean()}]}. +``` + +Disable or enable recursive compiling on `src_dirs`: + +```erlang +{src_dirs, [{"src", [{recursive, true|false}]}]} +%% Or alternatively: +{erl_opts, [{src_dirs,[{string(),[{recursive,boolean()}]}]}]}. +``` + +Disable or enable recursive compiling on for `extra_src_dirs`: + +```erlang +{extra_src_dirs, [{"test", [{recursive, true | false}]}]} +%% or +{erl_opts, [{extra_src_dirs,[{string(),[{recursive,boolean()}]}]}]}. +``` + +##### Examples + +All three options can be combined for granularity which should provide enough +flexibility for any project. Below are some examples. + +Disable recursive compiling globally, but enable it for a few dirs: + +```erlang +{erlc_compiler,[{recursive,false}]}, +{erl_opts,[{src_dirs,["src",{"other_src",[{recursive,true}]}]}]}. +``` + +Disable recursive compiling on test and other dirs: + +```erlang +{erl_opts, [ + {extra_src_dirs,[ + {"test", [{recursive,boolean()}]}, + {"other_dir", [{recursive,boolean()}]}]} + ] +}. +``` + +## Completion + +```erlang +{completion, + [{aliases,["rebar", "r3"]}, + {file, "/home/user/completion/_rebar3"}, + {shell, bash}]}. +``` + +Options mirror those specified in [Commands](commands.md#completion) arguments. + +## Common Test + +```erlang +{ct_first_files, [...]}. % {erl_first_files, ...} but for CT +{ct_opts, [...]}. % same as options for ct:run_test(...) +{ct_readable, true | false}. % disable Rebar3 modifying CT output in the shell +``` + +Reference of common test options for `ct_opts`: [https://www.erlang.org/doc/man/ct.html#run_test-1](https://www.erlang.org/doc/man/ct.html#run_test-1) + +A special option allows to load a default `sys.config` set of entries using `{ct_opts, [{sys_config, ["name.of.config"]}]}`. From the command line, it is however specified as `--sys_config name.of.config`. + +Options often exist mirroring those that can be specified in [Commands](commands.md#ct) arguments. + +## Cover + +Enable code coverage in [tests](testing/introduction.md) with `{cover_enabled, true}`. Then the `cover` provider can be run after tests to show reports. The option `{cover_opts, [verbose]}` can be used to force coverage reports be printed to the terminal rather than just in files. Specific modules can be blacklisted from code coverage by adding `{cover_excl_mods, [Modules]}` to the config file. Applications can be blacklisted as a whole with the `{cover_excl_apps, [AppNames]}` option. + +## Dialyzer + +```erlang +-type warning() :: dialyzer:warn_option(). + +{dialyzer, [{warnings, [warning()]}, + {get_warnings, boolean()}, + {plt_apps, top_level_deps | all_deps} % default: top_level_deps + {plt_extra_apps, [atom()]}, + {plt_location, local | file:filename()}, + {plt_prefix, string()}, + {base_plt_apps, [atom(), ...]}, + {base_plt_location, global | file:filename()}, + {base_plt_prefix, string()}]}. +``` + +To find all possible `dialyzer:warn_option()` use [dialyzer documentation](https://www.erlang.org/doc/man/dialyzer.html#type-warn_option). + +For information on suppressing warnings in modules see the [Requesting or Suppressing Warnings in Source Files](https://erlang.org/doc/man/dialyzer.html) section of the Dialyzer documentation. + +## Distribution + +Multiple providers and plugins may demand to support distributed Erlang. Generally, the configuration for all such commands (such as `ct` and `shell`) respect the following configuration values: + +```erlang +{dist_node, [ + {setcookie, 'atom-cookie'}, + {name | sname, 'nodename'} +]}. +``` + +## Directories + +The following options exist for directories; the value chosen below is the default value + +```erlang +%% directory for artifacts produced by Rebar3 +{base_dir, "_build"}. +%% directory in '<base_dir>/<profile>/' where deps go +{deps_dir, "lib"}. +%% where Rebar3 operates from; defaults to the current working directory +{root_dir, "."}. +%% where checkout dependencies are to be located +{checkouts_dir, "_checkouts"}. +%% directory in '<base_dir>/<profile>/' where plugins go +{plugins_dir, "plugins"}. +%% directories where OTP applications for the project can be located +{project_app_dirs, ["apps/*", "lib/*", "."]}. +%% Directories where source files for an OTP application can be found +{src_dirs, ["src"]}. +%% Paths to miscellaneous Erlang files to compile for an app +%% without including them in its modules list +{extra_src_dirs, []}. +%% Paths the compiler outputs when reporting warnings or errors +%% relative (default), build (all paths are in _build, default prior +%% to 3.2.0, and absolute are valid options +{compiler_source_format, relative}. +``` + +Furthermore, Rebar3 stores some of its configuration data in `~/.config/rebar3` and cache some data in `~/.cache/rebar3`. Both can be overridden by specifying `{global_rebar_dir, "./some/path"}.` + +## EDoc + +All options supported by [EDoc](https://www.erlang.org/doc/man/edoc.html#run-3) can be put in `{edoc_opts, [...]}`. + +## Escript + +Full details at the [escriptize command](commands.md#escriptize). Example configuration values below. + +```erlang +{escript_main_app, AppName}. % specify which app is the escript app +{escript_name, "FinalName"}. % name of final generated escript +{escript_incl_apps, [App]}. % apps (other than the main one and its deps) to be included +{escript_emu_args, "%%! -escript main Module\n"}. % emulator args +{escript_shebang, "#!/usr/bin/env escript\n"}. % executable line +{escript_comment, "%%\n"}. % comment at top of escript file +``` + +Because of the structure of escript building, options at the top-level `rebar.config` file only are used to build an escript. + +## EUnit + +```erlang +{eunit_first_files, [...]}. % {erl_first_files, ...} but for CT +{eunit_opts, [...]}. % same as options for eunit:test(Tests, ...) +{eunit_tests, [...]}. % same as Tests argument in eunit:test(Tests, ...) +``` + +A special option allows to load a default `sys.config` set of entries using `{eunit_opts, [{sys_config, ["name.of.config"]}]}`. From the command line, it is however specified as `--sys_config name.of.config`. + +Eunit Options reference: [https://www.erlang.org/doc/man/eunit.html#test-2](https://www.erlang.org/doc/man/eunit.html#test-2) + +## Hex Repos and Indexes + +Starting with Rebar3 version 3.7.0, multiple Hex repositories (or indexes) can be used at the same time. Repositories are declared in an ordered list, from highest priority to lowest priority. + +When looking for a package, repositories are going to be traversed in order. As soon as one of the packages fits the description, it is downloaded. The hashes for each found packages are kept in the project's lockfile, so that if the order of repositories changes and some of them end up containing conflicting packages definitions for the same name and version pairs, only the expected one will be downloaded. + +This allows the same mechanism to be used for both mirrors, private repositories (as provided by hex.pm), and self-hosted indexes. + +For publishing or using a private repository you must use the [rebar3_hex](https://github.com/tsloughter/rebar3_hex) plugin to authenticate, `rebar3 hex auth`. This creates a separate config file `~/.config/rebar3/hex.config` storing the keys. + +```erlang +{hex, [ + {repos, [ + %% A self-hosted repository that allows publishing may look like this + #{name => <<"my_hexpm">>, + api_url => <<"https://localhost:8080/api">>, + repo_url => <<"https://localhost:8080/repo">>, + repo_public_key => <<"-----BEGIN PUBLIC KEY----- + ... + -----END PUBLIC KEY-----">> + }, + %% A mirror looks like a standard repo definition, but uses the same + %% public key as hex itself. Note that the API URL is not required + %% if all you do is fetch information + #{name => <<"jsDelivr">>, + repo_url => <<"https://cdn.jsdelivr.net/hex">>, + ... + }, + %% If you are a paying hex.pm user with a private organisation, your + %% private repository can be declared as: + #{name => <<"hexpm:private_repo">>} + %% and authenticate with the hex plugin, rebar3 hex user auth + ]} +]}. + +%% The default Hex config is always implicitly present. +%% You could however replace it wholesale by using a 'replace' value, +%% which in this case would redirect to a local index with no signature +%% validation being done. Any repository can be replaced. +{hex, [ + {repos, replace, [ + #{name => <<"hexpm">>, + api_url => <<"https://localhost:8080/api">>, + repo_url => <<"https://localhost:8080/repo">>, + ... + } + ]} +]}. +``` + +## Minimum OTP Version + +A minimum version of Erlang/OTP can be specified which causes a build to fail if an earlier version is being used to build the application. + +```erlang +{minimum_otp_vsn, "17.4"}. +``` + +## Overrides + +Overrides allow for modifying the configuration of a dependency from a higher level application. They are meant to allow quick fixes and workarounds, although we do recommend working on permanent fixes that make it to the target app's configuration when possible. + +Overrides come in 3 flavours: add, override on app, and override on all. + +```erlang +{overrides, [{add, app_name(), [{atom(), any()}]}, + {del, app_name(), [{atom(), any()}]}, + {override, app_name(), [{atom(), any()}]}, + {add, [{atom(), any()}]}, + {del, [{atom(), any()}]}, + {override, [{atom(), any()}]}]}. +``` + +These are applied to dependencies, and dependencies can have their own overrides as well that are applied in the following order: overrides on all, per app overrides, per app additions. + +As an example, this can be used to force all the dependencies to be compiled with `debug_info` by default, and to force `no_debug_info` in case the production profile is used. + +```erlang +{overrides, [{override, [{erl_opts, [debug_info]}]}]}. + +{profiles, [{prod, [{overrides, [{override, [{erl_opts,[no_debug_info]}]}]}, + {relx, [{dev_mode, false}, + {include_erts, true}]}]} + ]}. +``` + +Another example could be to remove `warnings_as_errors` as a compiler option for all applications: + +```erlang +{overrides, [ + %% For all apps: + {del, [{erl_opts, [warnings_as_errors]}]}, + %% Or for just one app: + {del, one_app, [{erl_opts, [warnings_as_errors]}]} +]}. +``` + +Do note that overrides don't work on the finalized flattened option, but on the configuration as you see it in the project's `rebar.config` file. This means that if you want to replace the value of some configuration that is changed in a profile, you must override that profile's entry. + +> #### Overrides For All Apps in Umbrella Projects {: .warning} +> In an umbrella project, overrides that are specified in the top-level rebar.config file will also apply to applications within the `apps/` or `lib/` directory. By comparison, overrides specified in the `rebar.config` file at the application level will only apply to their dependencies. + +## Hooks + +There are two types of hooks: shell hooks and provider hooks. They both apply [to the same type of providers](#hookable-providers). + +### Shell Hooks + +Hooks provide a way to run arbitrary shell commands before or after hookable providers, optionally first matching on the type of system to choose which hook to run. Shell hooks are run after provider hooks. + +```erlang +-type hook() :: {atom(), string()} + | {string(), atom(), string()}. + +{pre_hooks, [hook()]}. +{post_hooks, [hook()]}. +{shell_hooks_env, [{string(), string()}]. +``` + +An example for building [merl](https://github.com/richcarl/merl) with Rebar3 by using `pre_hooks`: + +```erlang +{pre_hooks, [{"(linux|darwin|solaris)", compile, "make -C \"$REBAR_DEPS_DIR/merl\" all -W test"}, + {"(freebsd|netbsd|openbsd)", compile, "gmake -C \"$REBAR_DEPS_DIR/merl\" all"}, + {"win32", compile, "make -C \"%REBAR_DEPS_DIR%/merl\" all -W test"}, + {eunit, "erlc -I include/erlydtl_preparser.hrl -o test test/erlydtl_extension_testparser.yrl"}, + {"(linux|darwin|solaris)", eunit, "make -C \"$REBAR_DEPS_DIR/merl\" test"}, + {"(freebsd|netbsd|openbsd)", eunit, "gmake -C \"$REBAR_DEPS_DIR/merl\" test"}, + {"win32", eunit, "make -C \"%REBAR_DEPS_DIR%/merl\" test"} + ]}. +``` + +> #### Behaviour of post_hooks {: .warning} +> A `post_hooks` entry will only be called if its hookable provider was successful. This means that if you add a `post_hooks` entry for `eunit`, it will only be called if your EUnit tests are able to finish successfully. + +In shell hooks, environment variables from the host OS and those defined by the `shell_hooks_env` entry are available. +Starting with `v3.23.0`, additional environment variables exported by `rebar3` are documented and can be used in shell hooks. The variables are described in the table below (all paths except `REBAR_APP_DIRS` and `REBAR_SRC_DIRS` are absolute): + +| Name | Description | Default | +| ---- | ---- | ---- | +| `REBAR_ROOT_DIR` | Root of the project | | +| `REBAR_BUILD_DIR` | Build directory of a profile | `$REBAR_ROOT_DIR/_build/$REBAR_PROFILE` | +| `REBAR_DEPS_DIR` | Directory where dependencies are stored | `$REBAR_BUILD_DIR/lib` | +| `REBAR_CHECKOUTS_DIR` | Directory which is searched for [checkout dependencies](configuration/dependencies.md#checkout-dependencies) | `$REBAR_ROOT_DIR/_checkouts` | +| `REBAR_CHECKOUTS_OUT_DIR` | Directory where [checkout dependencies](configuration/dependencies.md#checkout-dependencies) are stored | `$REBAR_BUILD_DIR/checkouts` | +| `REBAR_PLUGINS_DIR` | Directory where plugins are stored | `$REBAR_BUILD_DIR/plugins` | +| `REBAR_GLOBAL_CONFIG_DIR` | Directory which is searched for global `rebar.config` | `$HOME/.config/rebar3` | +| `REBAR_GLOBAL_CACHE_DIR` | Cache directory | `$HOME/.cache/rebar3` | +| `REBAR_TEMPLATE_DIR` | Directory which is searched for [templates](tutorials/templates.md) | `$REBAR_GLOBAL_CONFIG_DIR/templates` | +| `REBAR_APP_DIRS` | Colon-separated list of relative paths which can contain applications | `apps/*:lib/*:.` | +| `REBAR_SRC_DIRS` | Colon-separated list of relative paths which can contain source code (including [extra_src_dirs](configuration/configuration.md#compilation)) - `recursive` option is ignored, paths are returned as is | `src` | +| `ERLANG_ARCH` | Wordsize of the system | Return value of [`rebar_api:wordsize()`](tutorials/building_plugins.md#rebar-api) | +| `ERLANG_TARGET` | Description of the system | Return value of [`rebar_api:get_arch()`](tutorials/building_plugins.md#rebar-api)| +| `ERLANG_ROOT_DIR` | Root directory of Erlang installation | Return value of `code:root_dir()` | +| `ERLANG_ERTS_VER` | Version of the `erts` | Return value of `erlang:system_info(version)` | +| `ERL` | Path to `erl` executable | `$ERLANG_ROOT_DIR/bin/erl` | +| `ERLC` | Path to `erlc` executable | `$ERLANG_ROOT_DIR/bin/erlc` | +| `ERLANG_LIB_DIR_erl_interface` | Path to the `erl_interface` application (if it's missing, variable is not defined!) | `$ERLANG_ROOT_DIR/lib/erl_interface` | +| `ERLANG_LIB_VER_erl_interface` | Version of the `erl_interface` application (if it's missing, variable is not defined!) | | + +### Provider Hooks + +Providers are also able to be used as hooks. The following hook runs `clean` before `compile` runs. To execute commands in a namespace a tuple is used as second argument. Provider hooks are run before shell hooks. + +```erlang +{provider_hooks, [{pre, [{compile, clean}]} + {post, [{compile, {erlydtl, compile}}]}]} +``` + +### Hookable Points in Providers + +Only specific built-in providers support hooks attached to them. Control depends on whether the provider operates on the project's applications (each application and dependency) or if it's expected to only run on the project at large. + +Provider hooks are run before shell hooks. + +| Hook | before and after | +| ------------ | --------------------------------------------------------------------------------------------------- | +| clean | each application and dependency, and/or before and after all top-level applications are compiled\* | +| ct | the entire run | +| compile | each application and dependency, and/or before and after all top-level applications are compiled\* | +| edoc | the entire run | +| escriptize | the entire run | +| eunit | the entire run | +| release | the entire run | +| tar | the entire run | +| erlc_compile | compilation of the beam files for an app | +| app_compile | building of the .app file from .app.src for an app | + +\* These hooks are, by default, running for every application, because dependencies may specify their own hook in their own context. The distinction is that in some cases (umbrella apps), hooks can be defined on many levels (omitting overrides): + +- the rebar.config file at the application root +- each top-level app's (in `apps/` or `libs/`) rebar.config +- each dependency's rebar.config + +By default, when there is no umbrella app, the hook defined in the top-level rebar.config is attributed to be part of the top-level app. This allows the hook to keep working for a dependency when the library is later published. + +If however the hook is defined in rebar.config at the root of a project with umbrella applications, the hooks will be run before/after the task runs for *all* of the top-level applications. + +To preserve the per-app behaviour in an umbrella project, hooks must instead be defined within each application's rebar.config. + +## Relx + +See [Releases](deployment/releases.md) + +## Plugins + +See [Plugins](configuration/plugins.md). Use `{plugins, [Dep]}` for plugins required to make the project build when used as a dependency, and `{project_plugins, [...]}` for plugins that provide utilities that aren't required for the project to build when used as a dependency. + +## Shell + +The `rebar3 shell` REPL will automatically boot applications if a `relx` entry is found, but apps to be started by the shell can be specified explicitly with `{shell, [{apps, [App]}]}`. + +Other options include: + +| Option | Value | Description | +| -------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| apps | [app1, app2, ...] | Applications to be booted by the shell. Overtakes the `relx` entry values | +| config | "path/to/a/file.config" | Loads a `.config` file (such as `sys.config`) for the applications to be booted by the shell. | +| script_file | "path/to/a/file.escript" | Evaluates a given escript before booting the applications for a node. | +| app_reload_blacklist | [app1, app2, ...] | Applications that should not be reloaded when calling commands such as `r3:compile()`. Useful when working with applications such as `ranch`, which crash after two reloads. | + +## XRef + +```erlang +{xref_warnings,false}. +{xref_extra_paths,[]}. +{xref_checks,[undefined_function_calls,undefined_functions,locals_not_used, + exports_not_used,deprecated_function_calls, + deprecated_functions]}. +{xref_queries,[{"(xc - uc) || (xu - x - b - (\"mod\":\".*foo\"/\"4\"))", []}]}. +{xref_ignores, [Module, {Module, Fun}, {Module, Fun, Arity}]}. +``` + +You can also ignore `xref` warnings for certain modules or functions by using the `-ignore_xref(_).` attribute in your modules. +This is useful for ignoring functions that give you undesired warnings such as `undefined_function_calls` and `exports_not_used`, like so: + +```erlang +-ignore_xref({other, call, 0}). % ignore warnings for calls to "external" module function +-ignore_xref([{other, call, 0}]). % equivalent to the previous declaration + +-ignore_xref({function,0}). % ignore warnings for locally exported function not used in the analysis scope +-ignore_xref([{function,0}]). % equivalent to the previous declaration +-ignore_xref(function/0). % equivalent to the previous declaration +-ignore_xref([function/0]). % equivalent to the previous declaration + +-ignore_xref(module). % ignore warnings related to a given module +-ignore_xref([module]). % equivalent to previous declaration +``` diff --git a/docs/configuration/dependencies.md b/docs/configuration/dependencies.md new file mode 100644 index 000000000..de4a98d9b --- /dev/null +++ b/docs/configuration/dependencies.md @@ -0,0 +1,268 @@ +# Dependencies + +> How to add dependencies to a project. + +## Declaring Dependencies + +Dependencies can be declared in a top-level `rebar.config` file, and inspected with the `rebar3 tree` command. + +In general, Rebar3 supports two types of dependencies: + +- Source dependencies (Git, Mercurial) +- Package dependencies + +Both types of dependencies work roughly the same way. Rebar3 uses [hex.pm](https://hex.pm) to provide a managed set of packages and their dependencies. They will generally be faster (behind a CDN), can be mirrored, and will be cached locally in `~/.cache/rebar3/`. + +All dependencies are to be project-local. This is usually a good choice in order avoid the common problems of global libraries having version conflicts. It also helps with the general Erlang mechanism of [Releases](deployment/releases.md), which builds standalone systems. + +Dependencies fit any of the following formats: + +```erlang +{deps,[ + %% Packages + rebar, + {rebar,"1.0.0"}, + {rebar, {pkg, rebar_fork}}, % rebar app under a different pkg name + {rebar, "1.0.0", {pkg, rebar_fork}}, + %% Source Dependencies + {rebar, {git, "git://github.com/erlang/rebar3.git"}}, + {rebar, {git, "https://github.com/erlang/rebar3.git"}}, + {rebar, {git, "git@github.com:erlang/rebar3.git"}}, + {rebar, {hg, "https://othersite.com/erlang/rebar3"}}, + {rebar, {git, "git://github.com/erlang/rebar3.git", {ref, "aef728"}}}, + {rebar, {git, "git://github.com/erlang/rebar3.git", {branch, "master"}}}, + {rebar, {git, "git://github.com/erlang/rebar3.git", {tag, "3.0.0"}}}, + %% Source dependencies (git only) in subdirectories, from version 3.14 onwards + {rebar, {git_subdir, "git://github.com/erlang/rebar3.git", {branch, "main"}, "subdir"}}, + {rebar, {git_subdir, "git://github.com/erlang/rebar3.git", {tag, "3.14"}, "sub/dir"}}, + {rebar, {git_subdir, "git://github.com/erlang/rebar3.git", {ref, "aeaefd"}, "dir"}} +]}. +``` + +As the example above shows, for the current versions, only packages, git sources, and mercurial sources are supported. Custom dependency sources can be added by [implementing the resource behaviour](extending/custom_dep_resources.md) and including it like a plugin. + +### Runtime Dependencies + +However, the dependency handling done by Erlang/OTP to boot and shut down applications, and tools (even part of Rebar3) to build releases and scripts, depend on a more granular dependency declaration, specifying which of each application in a project depend on others. + +You should add each dependency to your `app` or `app.src` files: + +```erlang +{application, <APPNAME>, + [{description, ""}, + {vsn, "<APPVSN>"}, + {registered, []}, + {modules, []}, + {applications, [kernel + ,stdlib + ,cowboy + ]}, + {mod, {<APPNAME>_app, []}}, + {env, []} + ]}. +``` + +This will allow the flexibility to write and generate software where various disjoint applications can coexist in a virtual machine without their dependencies being entirely tangled together. For example, you may want your web server to be able to run independently of administrative and debugging tools, even if they should be available in production. + +If more formats require support, Rebar3 can be extended via the [`rebar_resource` behaviour](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_resource.erl), and sent to the maintainers with a [pull request](https://github.com/erlang/rebar3/blob/master/CONTRIBUTING.md). + +> #### Dependencies and Profiles {: .warning} +> Dependencies will always be compiled with the `prod` profile applied to their configuration. No other profile (besides `default`, of course) is used on any dependency. Even though they are configured for `prod` the dependency will still be fetched to the profile directory for the profile it is declared under. For example, a dependency in the top level `deps` will be under `_build/default/lib` and dependency under the profile `test` will be fetched to `_build/test/lib`, and both will be compiled with their `prod` profile configuration applied. + +## Dependency Version Handling + +Rebar3 considers dependency versions to be informational only. Given the existing open source landscape in the Erlang community when Rebar3 was added, trying to impose [semantic versioning](https://semver.org/) or any other similar scheme was considered unpractical: + +- People update *some* versions but not all of them (Git tags vs. branch names vs. OTP application versions) and they may contradict each other; +- Some people never update their versions and publish many times under them; +- Not everyone subscribes to the same version schemes; +- People make errors in subscribing to semantic versioning; +- Many applications are stuck in versions smaller than `1.0.0`, and therefore considered unstable forever; +- Source dependencies are frequently used: figuring out version conflicts therefore requires downloading all transitive dependencies from all dependencies to figure out whether they conflict or not, every time, and is costly; +- Strict adherence to semantic versioning ends up causing false conflicts where using a subset of an API which hasn't changed across major versions still requires manual conflict resolution and dependency audits. + +Instead, Rebar3 will fetch and download dependencies in a [level-order traversal](#fetching-order). This means that the dependencies closest to the root of the dependency tree are those that will be chosen, regardless of their versions. Any dependency declared in your project's `rebar.config` will never be overwritten by a transitive dependency, and a transitive dependency will never be overridden by a later encountered conflicting transitive dependency. + +This also means that if you prefer a version to be used above all else, you can just add it to your `rebar.config` file and pick what will be kept; the same conflict resolution mechanism sometimes required by semantic versioning. + +In practice, this has proven to be absolutely adequate as a mechanism. + +After each run of dependency fetching and resolving the list of final dependencies are written to `rebar.lock`. + +> #### Treating Conflicts as Errors {: .info} +> If you ever want Rebar3 to abort as soon as it detects a dependency conflict, instead of skipping the file and proceeding as usual, add the line `{deps_error_on_conflict, true}.` to your rebar configuration file. + +For convenience reasons (and because [hex.pm](https://hex.pm) mandates semver) hex dependencies can be specified using semver-like syntax: + +```erlang +{deps,[ + rebar, % fetches latest known version, ignoring pre-releases + {rebar, "~> 2.0.0"}, % >= 2.0.0 and < 2.1.0` + {rebar, "~> 2.1.2"}, % >= 2.1.2 and < 2.2.0` + {rebar, "~> 2.1.3-dev"}` % >= 2.1.3-dev and < 2.2.0` + {rebar, "~> 2.0"}` % >= 2.0.0 and < 3.0.0` + {rebar, "~> 2.1"}` % >= 2.1.0 and < 3.0.0` +]}. +``` + +To get the latest version of packages available, call: + +```shell +$ rebar3 update +===> Updating package index... +``` + +To use a CDN other than the default, such as one of the [official mirrors](https://hex.pm/docs/mirrors) add to your project's `rebar.config` or to `~/.config/rebar3/rebar.config`: + +```erlang +{rebar_packages_cdn, "https://s3-eu-west-1.amazonaws.com/s3-eu.hex.pm"}. +``` + +## Checkout Dependencies + +To handle the case of dependencies you wish to work on locally without having to constantly publish new versions, there is the `_checkouts` directory. Simply make a symlink or copy your dependency to `_checkouts` at the top level of your project: + +```shell +_checkouts +└── depA + └── src +``` + +Any application or plugin in `_checkouts` will take precedence over the same application if it is additionally listed in the `rebar.config`'s `deps`, `plugins`, or `project_plugins`. This also overrides anything already fetched to `_build`. + +Note that `_checkouts` is an override, this means that for it to work a `dep` or `plugin` entry in `rebar.config` _must_ exist. + +## Fetching Order + +For a regular dependency tree, such as: + +```plain + A + / \ +B C +``` + +the dependencies `A`, `B`, and `C` will be fetched. + +However, for more complex trees, such as: + +```plain + A + / \ +B C1 +| +C2 +``` + +The dependencies `A`, `B`, and `C1` will be fetched. When Rebar3 will encounter the requirement for `C2`, it will instead display the warning: `Skipping C2 (from $SOURCE) as an app of the same name has already been fetched`. + +Such a message should let the user know which dependency has been skipped. + +What about cases where two transitive dependencies have the same name and are on the same level? + +```plain + A + / \ +B C +| | +D1 D2 +``` + +In such a case, `D1` will take over `D2`, because `B` lexicographically sorts before `C`. It's an entirely arbitrary rule, but it is at least a rule that ensures repeatable fetches. + +In the event users disagree with the outcome, they can bring `D2` to the top level and ensure it will be chosen early: + +```plain + A D2 + / \ +B C +| | +D1 D2 +``` + +Which will yield `A`, `B`, `C`, and `D2`. + +Rebar3 will perform that same algorithm with packages, and will also detect circular dependencies and error out on these. + +Dependencies in the `_checkouts` directory will be left untouched, and are treated as top-level OTP applications. + +## Lock Files + +Lock files (`rebar.lock`) are one of the only artifacts that will be generated by Rebar3 that will live outside of `_build/`. They should always be checked into source control. The lock file contains information regarding code dependencies, including immutable references for source dependencies like those in git, and their versions along with expected hashes for packages (which can be used to protect against mirrors being hijacked). + +The objective is to use more accurate information regarding found dependencies than what would be obtained through the config file on its own, allowing, for example, to configure a dependency to be updated from `main` on-demand, but to be locked to a stable tested version in the meanwhile. Only unlocking or upgrading the dependency will allow it to move it to a newer or different version. The idea is to allow repeatable builds, even if, for example, Git tags or branches are destructively modified by someone. + +Rebar3 will also use the lock file as the true source of authority for dependencies when switching branches or fetching transitive deps (it will pick data from the lock file if any is available) rather than the `rebar.config` file. This way, we can carry a safe tested state into other applications when loose references or versions are used in the `rebar.config` file. + +The format is expected to be forwards and backwards compatible. Rebar3 will annotate lock file versions according to the format of metadata stored, and warn when an old version of Rebar3 is used to read a newer version of lock files. This can tell the user that some metadata that is judged important at a later date will be lost by using an older copy of the tool. + +## Upgrading Dependencies + +Whenever a dependency is fetched and locked, Rebar3 will extract a reference from the source file to pin it to a specific version in time. The dependency should be forced to follow that version on following builds. + +Rebar3 can upgrade previously installed dependencies to newer versions in two ways: forwarding a branch's reference to its latest version (e.g. an old `main` branch up to the new `main`'s `HEAD` for source files, or the newest versions for packages that didn't specify one), or crushing an existing locked dependency with a new version from the `rebar.config` file. + +In the following dependency tree: + +```plain +A B +| | +C D +``` + +The user can upgrade either dependency (`rebar3 upgrade A` and `rebar3 upgrade B`) or both at once (`rebar3 upgrade A,B` or `rebar3 upgrade`, which upgrades *all* dependencies). + +Upgrading only `A` means that `A` and `C` may be upgraded. Upgrades to `B` and `D` will be ignored. + +Upgrading dependencies can have surprising effects and interesting corner cases. Consider the following dependency tree: + +```plain + A B C1 + / \ / \ / \ + D E F G H I2 + | | + J K + | + I1 +``` + +After fetching the dependency tree above, `I2` would be chosen before `I1` since it is closer to the project root. However, following an upgrade from `C1` to `C2` where `C2` no longer needs to depend on `I2`, Rebar3 will automatically go fetch `I1` under the `A` tree (even if no upgrade in `A` was required) to provide a correct new tree. The upgraded tree would look like: + +```plain + A B C2 + / \ / \ | + D E F G H + | | + J K + | + I1 +``` + +Where `I2` no longer exists in the project, and `I1` now does. + +Calling `rebar3 unlock` will flush the lock file entirely. + +You can inspect things manually with `rebar3 tree`, which will display the current dependencies tree: + +```shell +$ rebar3 tree +... +├─ bootstrap-0.0.2 (git repo) +├─ dirmon-0.1.0 (project app) +├─ file_monitor-0.1 (git repo) +├─ peeranha-0.1.0 (git repo) +│ ├─ gproc-git (git repo) +│ ├─ interclock-0.1.2 (git repo) +│ │ ├─ bitcask-1.7.0 (git repo) +│ │ │ └─ lager-2.1.1 (hex package) +│ │ │ └─ goldrush-0.1.6 (hex package) +│ │ └─ itc-1.0.0 (git repo) +│ └─ merklet-1.0.0 (git repo) +├─ recon-2.2.2 (git repo) +└─ uuid-1.5.0 (git repo) + └─ quickrand-1.5.0 (git repo) +``` + +## Elixir Dependencies + +Elixir Dependencies are supported starting with Rebar3 version 3.7.0, and Elixir version 1.7.4 through the use of a plugin. See [the relevant plugin section](configuration/plugins.md#elixir-dependencies) for details. diff --git a/docs/configuration/plugins.md b/docs/configuration/plugins.md new file mode 100644 index 000000000..13165afe6 --- /dev/null +++ b/docs/configuration/plugins.md @@ -0,0 +1,478 @@ +# Plugins + +Plugins can be installed locally, to a project, and/or globally. To install a plugin locally, specify it under `plugins` in your project's `rebar.config`. Globally installed plugins are configured in `~/.config/rebar3/rebar.config` and automatically installed when you use a Rebar3 command in your project. + +## Including Plugins + +Plugins required for building an application should be included under `plugins` in the same format as dependencies are listed in `deps`. They are built under the directory `_build/<profile>/plugins/` and are listed in the output of `rebar3 help`, available to use as tasks and in `provider_hooks`: + +```erlang +{plugins, [{rebar_erl_vsn, "~> 0.1"}]}. +{provider_hooks, [{pre, [{compile, {default, erl_vsn}}]}]}. +``` + +The above configuration will result in `erl_vsn` task being run before the `compile` task. This plugin adds defines to the compile configuration, such as if running on an Erlang version above 17 it will include `{d, 'maps'}` in `erl_opts` during compilation. + +## Project Plugins and Overriding Commands + +Some plugins work best if they are able to override the available commands. However, this isn't something that plugins should be able to do when the project they are included in is used as a dependency. `project_plugins` defines plugins that will only be available when the project is being built directly by `rebar3` commands, as in running `rebar3` from the top level directory of the application/project. + +For example the cuttlefish plugin is only necessary when building a release, so not fetching it and having it available per application dependency makes sense. It also works best if it works the same as building a release or tarball. So when included in `project_plugins`: + +```erlang +{project_plugins, [rebar3_cuttlefish]}. +``` + +Running `rebar3 release` or `rebar3 tar` will be running the `rebar3_cuttlefish` providers instead of the built in providers. + +Additionally there are cases you only need a plugin for development. Say you have protobufs and commit the generated modules to the repo and include in the Hex package, then there is no need for the protobuf plugin to be available when the application is a dependency and is only needed for development purposes. Before `project_plugins` it was common to see a `dev` profile with plugins added under it, but this then required running `rebar3 as dev protobuf` and dealing with another profile under `_build`. With project plugins the config can instead be: + +```erlang +{project_plugins, [rebar3_gpb_plugin]}. +``` + +Now we need only run `rebar3 protobuf`. We do not include any hooks because we will be committing the generated code to the repository and the plugin will not be fetched if this project is used as a dependency. + +## Upgrading Plugins + +Plugins work a bit like dependencies (although they are currently not being version-locked); they will not be automatically updated unless you ask for them to be. + +- You can upgrade project-local plugins by calling `rebar3 plugins upgrade <plugin_name>`. +- You can upgrade global plugins by calling `rebar3 as global plugins upgrade <plugin_name>`, which invokes a hidden global profile used specifically to switch the upgrade context for plugins. + +If you are using Hex packages as plugins and you do not see the version you expected, remember to use call `rebar3 update` to get a fresh Hex index. Once again, since plugins are not locked as part of the lock file, it might be a good idea to always specify a version for them. + +## Recommended Plugins + +- [Auto-Compile and Load](#auto-compile-and-load) +- [Auto-Test](#auto-test) +- [Hex Package Management](#hex-package-management) +- [Port Compiler](#port-compiler) +- [Run Release](#run-release) +- [Alias](#alias) +- [QuickCheck](#quickcheck) +- [PropEr](#proper) +- [Diameter](#diameter) +- [ErlyDTL](#erlydtl) +- [Neotoma](#neotoma) +- [Protocol buffers](#protocol-buffers) +- [Appup](#appup) +- [Vendoring Dependencies](#vendoring-dependencies) +- [Elixir Dependencies](#elixir-dependencies) + +### Auto Compile and Load + +For the `auto` plugin it is suggested to place the entry in the global `rebar3` config which should be made as `~/.config/rebar3/rebar.config`. + +```erlang +{plugins, [rebar3_auto]}. +``` + +Running `rebar3 auto` will start the shell the same as running `rebar3 shell` but will be listening for file changes in your project's application source directories. When a file is changed it will message the Rebar3 agent to run compile and reload modules. + +### Auto-Test + +For the `autotest` plugin it is suggested to place the entry in the global `rebar3` config which should be made as `~/.config/rebar3/rebar.config`. + +```erlang +{plugins, [{rebar3_autotest, "0.1.1"}]}. +``` + +Running `rebar3 as test autotest` will start `eunit` once and set watches for your source, header and test-files, so that it reruns `eunit` on changes on one of the files. + +### Hex Package Management + +For the `hex` plugin it is suggested to place the entry in the global `rebar3` config which should be made as `~/.config/rebar3/rebar.config`. + +```erlang +{plugins, [rebar3_hex]}. +``` + +For usage go to the [Hex Package Management](package_management/publishing-packages.md) section. To view the package go to [hex.pm](https://hex.pm/packages/rebar3_hex) and to open issues [GitHub](https://github.com/tsloughter/rebar3_hex). + +### Port Compiler + +This plugin provides the old `rebar` interface, to building C and C++ code, to `rebar3`. The package can be found at [hex.pm](https://hex.pm/packages/pc) and issues at [GitHub](https://github.com/blt/port_compiler). + +In your project's `rebar.config`, add the `pc` plugin and calls to it in `provider_hooks` for `compile` and `clean`: + +```erlang +{plugins, [pc]}. + +{provider_hooks, + [ + {pre, + [ + {compile, {pc, compile}}, + {clean, {pc, clean}} + ] + } + ] +}. +``` + +Configuration variables available: + +```erlang +%% Supported configuration variables: +%% +%% * port_specs - Erlang list of tuples of the forms +%% {ArchRegex, TargetFile, Sources, Options} +%% {ArchRegex, TargetFile, Sources} +%% {TargetFile, Sources} +%% +%% * port_env - Erlang list of key/value pairs which will control +%% the environment when running the compiler and linker. +%% Variables set in the surrounding system shell are taken +%% into consideration when expanding port_env. +%% +%% By default, the following variables are defined: +%% CC - C compiler +%% CXX - C++ compiler +%% CFLAGS - C compiler +%% CXXFLAGS - C++ compiler +%% LDFLAGS - Link flags +%% ERL_CFLAGS - default -I paths for erts and ei +%% ERL_LDFLAGS - default -L and -lerl_interface -lei +%% DRV_CFLAGS - flags that will be used for compiling +%% DRV_LDFLAGS - flags that will be used for linking +%% EXE_CFLAGS - flags that will be used for compiling +%% EXE_LDFLAGS - flags that will be used for linking +%% ERL_EI_LIBDIR - ei library directory +%% DRV_CXX_TEMPLATE - C++ command template +%% DRV_CC_TEMPLATE - C command template +%% DRV_LINK_TEMPLATE - C Linker command template +%% DRV_LINK_CXX_TEMPLATE - C++ Linker command template +%% EXE_CXX_TEMPLATE - C++ command template +%% EXE_CC_TEMPLATE - C command template +%% EXE_LINK_TEMPLATE - C Linker command template +%% EXE_LINK_CXX_TEMPLATE - C++ Linker command template +%% +%% Note that if you wish to extend (vs. replace) these variables, +%% you MUST include a shell-style reference in your definition. +%% e.g. to extend CFLAGS, do something like: +%% +%% {port_env, [{"CFLAGS", "$CFLAGS -MyOtherOptions"}]} +%% +%% It is also possible to specify platform specific options +%% by specifying a triplet where the first string is a regex +%% that is checked against Erlang's system architecture string. +%% e.g. to specify a CFLAG that only applies to x86_64 on linux +%% do: +%% +%% {port_env, [{"x86_64.*-linux", "CFLAGS", +%% "$CFLAGS -X86Options"}]} +%% +%% Cross-arch environment variables to configure toolchain: +%% GET_ARCH to set the tool chain name to use +%% GET_ARCH_WORDSIZE (optional - to determine word size)" +%% word size is 32 +%% GET_ARCH_VSN (optional - " +%% l version of CC/CXX is requested), +``` + +### Run Release + +`rebar3 run` will start the release console, instead of having to run `_build/default/rel/<release>/bin/<release> console`. Found at [GitHub](https://github.com/tsloughter/rebar3_run) and [hex.pm](https://hex.pm/packages/rebar3_run). + +```erlang +{plugins, [rebar3_run]}. +``` + +### Alias + +The alias plugin has been added to Rebar3 starting with version 3.5.0. See [Create Aliases for Common Tasks](workflow.md#create-aliases-for-common-tasks) for instructions. + +For prior versions, the plugin for aliasing a single command to run multiple tasks can be found at [GitHub](https://github.com/tsloughter/rebar_alias) and [Hex.pm](https://hex.pm/packages/rebar_alias). + +```erlang +{plugins, [rebar_alias]}. + +{alias, [{check, [eunit, {ct, "--sys_config=config/app.config"}]}]}. +``` + +Arguments (as with a command line) can be passed by replacing `Provider` with `{Provider, Args}`. + +### QuickCheck + +A Rebar3 plugin to enable the execution of [Erlang QuickCheck](https://www.quviq.com/products/erlang-quickcheck/) properties. Found on [GitHub](https://github.com/kellymclaughlin/rebar3-eqc-plugin) and [Hex.pm](https://hex.pm/packages/rebar3_eqc). + +```erlang +{plugins, [rebar3_eqc]}. +``` + +Config options for the QuickCheck go under `eqc_opts`, for example `{eqc_opts, [{numtests, 500}]}.`: + +| Config Option | Type | Description | +| ------------- | ------- | ------------------------------------------------------------------------------------------------ | +| numtests | integer | Number of test executions, default 100. | +| testing_time | integer | Time in seconds to execute property. If both are specified, the testing_time setting is ignored. | + +Similarly configuration can be passed on the command line: + +| Option | Type | Description | +| ------ | ------- | ----------------------------------------------------------------------------------------------------------------- | +| -n | integer | Number of test executions, default 100. | +| -t | integer | Time in seconds to execute property. If both are specified, the testing_time setting is ignored. | +| -p | string | Property to execute. This can be either `module:property` or `property` and the plugin will determine the module. | + +### PropEr + +[PropEr](https://proper.softlab.ntua.gr/) is a free alternative to Quviq QuickCheck. The plugin is available [on Hex as a package](https://hex.pm/packages/rebar3_proper) or [GitHub](https://github.com/ferd/rebar3_proper/) + +```erlang +%% the plugin itself +{plugins, [rebar3_proper]}. + +%% The PropEr dependency is still required to compile the test cases +{profiles, + [{test, [ + {deps, [{proper, "1.1.1-beta"}]} + ]} +]}. +``` + +All of PropEr's configuration options can be passed in rebar.config under `{proper_opts, Options}` or as command line arguments: + +| rebar.config key | Command Line | Description | +| ------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| {dir, String} | -d, --dir | directory where the property tests are located (defaults to "test") | +| {module, [Modules]} | -m, --module | name of one or more modules to test | +| {properties, [PropNames]} | -p, --prop | name of properties to test within a specified module | +| {numtests, N} | -n, --numtests | number of tests to run when testing a given property | +| verbose \| quiet | -v, --verbose | Whether each property tested shows its output or not (defaults to true/verbose) | +| {cover, true \| false} | -c, --cover | generate cover data (default: false) | +| long_result | --long_result | enables long-result mode, displaying counter-examples on failure rather than just false | +| {start_size, N} | --start_size | specifies the initial value of the size parameter | +| {max_size, N} | --max_size | specifies the maximum value of the size parameter | +| {max_shrinks, N} | --max_shrinks | specifies the maximum number of times a failing test case should be shrunk before returning | +| noshrink | --noshrink | instructs PropEr to not attempt to shrink any failing test cases | +| {constraint_tries, N} | --constraint_tries | specifies the maximum number of tries before the generator subsystem gives up on producing an instance that satisfies a ?SUCHTHAT constraint | +| {spec_timeout, Millisecs} | --spec_timeout | duration, in milliseconds, after which PropEr considers an input to be failing | +| any_to_integer | --any_to_integer | converts instances of the any() type to integers in order to speed up execution | + +### Diameter + +The [rebar3_diameter_compiler](https://github.com/carlosedp/rebar3_diameter_compiler) plugin compiles diameter `.dia` files in Rebar3 projects. + +```erlang +{plugins, [rebar3_diameter_compiler]}. +``` + +Add hooks to automatically compile and clean the diameter dictionaries: + +```erlang +{provider_hooks, [ + {pre, [ + {compile, {diameter, compile}}, + {clean, {diameter, clean}} + ]} +]}. +``` + +Configuration options: + +| Config Option | Type | Description | +| --------------- | ---- | ------------------------------------------------------------------------ | +| dia_opts | list | Options from diameter_make:codec/2 supported with exception of inherits. | +| dia_first_files | list | Files in sequence to compile first. | +| | | | + +### ErlyDTL + +The [erlydtl](https://github.com/erlydtl/erlydtl) compiler has been moved to a separate plugin. + +```erlang +{plugins, [ + {rebar3_erlydtl_plugin, ".*", + {git, "https://github.com/tsloughter/rebar3_erlydtl_plugin.git", {branch, "master"}}} +]}. +``` + +Config options go in a list under `erlydtl_opts` in `rebar.config`: + +| Config Option | Type | Description | +| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ | +| doc_root | string | Where to find templates to compile. "priv/templates" by default. | +| compiler_options | proplist | Template compilation options to pass to erlydtl. Descriptions [here](https://github.com/erlydtl/erlydtl#template-compilation). | +| out_dir | string | Where to put compiled template beam files "ebin" by default. | +| source_ext | string | The file extension the template sources have ".dtl" by default. | +| module_ext | string | Characters to append to the template's module name "\_dtl" by default. | +| recursive | boolean | Boolean that determines if doc_root(s) need to be scanned recursively for matching template file names. 'true' by default. | + +### Neotoma + +Plugin for building PEG files using [Sean Cribbs neotoma app](https://github.com/seancribbs/neotoma). This plugin is published to Hex so can be added to your project with: + +```erlang +{plugins, [rebar3_neotoma_plugin]}. +``` + +The `compile` function is under the `neotoma` namespace. To automatically before the Erlang compiler add the `pre_hook` to `rebar.config`: + +```erlang +{provider_hooks, [ + {pre, [{compile, {neotoma, compile}}]} +]}. +``` + +### Protocol Buffers + +### Using gpb + +[Plugin](https://github.com/lrascao/rebar3_gpb_plugin) for building `.proto` files using Tomas Abrahamsson's [gpb](https://github.com/tomas-abrahamsson/gpb). This plugin is published to Hex so can be added to your project with: + +```erlang +{erl_opts, [{i, "./_build/default/plugins/gpb/include/"}]}. +{plugins, [{rebar3_gpb_plugin, "2.10.0"}]}. + +{gpb_opts, [{i, "proto"}, + {o_erl, "src"}, + {o_hrl, "include"}]}. +``` + +The `compile` function is under the `protobuf` namespace. To automatically build before the Erlang compiler add the `provider` `pre` hook to `rebar.config`: + +```erlang +{provider_hooks, [ + {pre, [{compile, {protobuf, compile}}]} +]}. +``` + +Full documentation available in the plugin's [README](https://github.com/lrascao/rebar3_gpb_plugin/blob/develop/README.md#use). + +### Appup + +Plugin for generating, compiling and validating `.appup.src` files. This plugin is published to Hex so can be added to your project with: + +```erlang +{plugins, [rebar3_appup_plugin]}. +``` + +The `compile` and `clean` functions are under the `appup` namespace. To automatically build before the Erlang compiler add the `provider` `pre` hook to `rebar.config`: + +```erlang +{provider_hooks, [ + {post, [{compile, {appup, compile}}, + {clean, {appup, clean}}]} +]}. +``` + +To compare two releases and generate the `.appup` with the necessary instructions to execute the release upgrade run: + +```shell +git checkout <from version> +rebar3 release +git checkout <to version> +rebar3 release +rebar3 appup generate +rebar3 relup tar +``` + +| Argument | Type | Description | +| ---------------- | -------- | --------------------------------------------------------------------------------------------------- | +| previous | optional | Path location of the previous release to compare with | +| current | optional | Path location of the current release to compare with, defaults to _build/\<profile\>/rel/\<app_name\> | +| target_dir | optional | Location of where to generate the .appup file. | +| previous_version | optional | Version to update from | + +Full documentation available in the plugin's [README](https://github.com/lrascao/rebar3_appup_plugin/blob/master/README.md) + +### Vendoring dependencies + +This section contains plugins for storing vendored dependencies within a project. + +Starting with Rebar3 3.7.0, you can make use of [`rebar3_path_deps`](https://github.com/benoitc/rebar3_path_deps) as a plugin, to specify relative vendored paths for dependency retrieval. The local paths should work even when the plugin is used for a dependency. + +Let’s start off by making a new OTP application `hello_utils` inside of your project `hello_world`: + +```shell +# inside of hello-world/ +$ rebar3 new app hello_utils +``` + +This will create a new folder `hello_utils` inside of which a `rebar.config` and `src` folder are ready to be used. + +In order to tell Rebar3 about this, open up `hello_world/rebar.config` and add `hello_utils` to your dependencies: + +```erlang +{deps, [ + {hello_utils, {path, "hello_utils"}}, + ... +] +``` + +This tells Rebar3 that we depend on an application called `hello_utils` which is found in the `hello_utils` directory (relative to the `rebar.config` file it’s written in). + +Then add the plugin to your `rebar.config`: + +```erlang +{plugins, [ + rebar3_path_deps +]}. +``` + +Then just compile your application: + +```shell +$ rebar3 compile +===> Compiling rebar3_path_deps +===> Verifying dependencies... +===> Fetching hello_utils ({path,"hello_utils", + {mtime,<<"2018-10-17T11:21:18Z">>}}) +===> Compiling hello_utils +===> Compiling hello_world +``` + +This should cover it all. + +For versions prior to 3.7.0, the following plugin was preferable, but only worked at the top-level of a project. + +```erlang +{plugins, [rebar3_vendor]}. +``` + +To store the fetched dependencies under `./deps/` for committing: + +```shell +rebar3 vendor store +``` + +To take the vendored dependencies from `./deps/` and place them under the build directory in the appropriate place: + +```shell +rebar3 vendor apply +``` + +### SVN Dependencies + +The [rebar3_svn_deps](https://github.com/seanhinde/rebar3_svn_deps) plugin can allow to use SVN repositories for dependencies: + +Since SVN follows somewhat different approaches to branching and hierarchies than Git or Hg dependencies, please [follow the plugin instructions](https://github.com/seanhinde/rebar3_svn_deps#use) to use it. + +### Elixir Dependencies + +Starting with Rebar3 3.7.0, Mix dependencies are supported with the [rebar_mix](https://github.com/tsloughter/rebar_mix) plugin. Requirements and instructions are detailed in its README page, and include features such as protocol consolidation. + +Add the plugin to your rebar config: + +```erlang +{plugins, [rebar_mix]}. + +{provider_hooks, [{post, [{compile, {mix, consolidate_protocols}}]}]}. +``` + +The `consolidate_protocols` hook places beams in `_build/<profile>/consolidated` that will need to be included in a release when built. Using: + +```erlang +{overlay, [{copy, "{{base_dir}}/consolidated", "releases/{{release_version}}/consolidated"}]} +``` + +And update your `vm.args.src` to include: + +```erlang +-pa releases/${REL_VSN}/consolidated +``` + +> #### Elixir with Older Rebar3 releases {: .warning} +> For Rebar3 versions prior to 3.7.0, the [rebar3_elixir_compile](https://github.com/barrel-db/rebar3_elixir_compile) plugin was preferred, although it required manually hoisting all transitive dependencies to the project root. Full example and configuration instructions are provided on the plugin's [README page](https://github.com/barrel-db/rebar3_elixir_compile). diff --git a/docs/configuration/profiles.md b/docs/configuration/profiles.md new file mode 100644 index 000000000..fd1ee9b78 --- /dev/null +++ b/docs/configuration/profiles.md @@ -0,0 +1,143 @@ +# Profiles + +In any project, there's invariably a set of options that are desired depending on the task run or the role of the person running the task. + +In Erlang projects for example, the most common example is dependencies required only for test runs, such as mocking libraries or specific testing tools or frameworks. + +Rebar3 addresses such requirements with the concept of *profiles*. A profile is a set of configuration settings to be used only in one of these specific contexts, overriding or complementing the regular configuration. Their objective is to be able to support multiple development use cases, while keeping things repeatable and without requiring external tools or environment values to do that work. + +A profile for a run can be specified in three different ways: + +1. calling rebar as `rebar3 as <profile> <command>` or `rebar3 as <profile1>,<profile2> <command>` +2. by a given Rebar3 command. For example, the `eunit` and `ct` commands *always* add a `test` profile to the run. +3. The `REBAR_PROFILE` environment variable + +Any of these forms (or even all at once) will let Rebar3 know that it should run as one of the special profiles and modify its configuration accordingly. + +The profile configuration can be specified in the main `rebar.config` file as such: + +```erlang +{profiles, [{ProfileName1, [Options, ...]}, + {ProfileName2, [Options, ...]}]}. +``` + +For example, a test profile that adds the `meck` dependency only for test runs could be defined as: + +```erlang +{profiles, [{test, [{deps, [meck]}]}]}. +``` + +Any configuration value can go in profiles, including plugins, compiler options, release options, and so on. + +## Example + +A more complete example might look like this: + +```erlang +{deps, [...]}. +{relx, [ + ... +]}. + +{profiles, [ + {prod, [ + {erl_opts, [no_debug_info, warnings_as_errors]}, + {relx, [{dev_mode, false}]} + ]}, + {native, [ + {erl_opts, [{native, {hipe, o3}}]} + ]}, + {test, [ + {deps, [meck]}, + {erl_opts, [debug_info]} + ]} +]}. +``` + +Such a project therefore has *four* distinct profiles: + +1. `default`, the de-facto profile for all runs, corresponding to the overall `rebar.config` file + +2. `prod`, in this case probably used to generate full releases without symlinks, and with stricter compiler options + +3. `native`, to force compiling with [HiPE](http://www.erlang.org/doc/man/HiPE_app.html), for faster mathematical code + +4. `test`, which loads mocking libraries and enables debug information to be kept in files during test runs. + +Those might be combined in many ways. Here are example runs: + +1. `rebar3 ct`: will run the Common Test suites of the project. In order, the profiles applied will be `default`, and then `test`, because `ct` mandates the usage of a `test` profile. + +2. `rebar3 as test ct`: will run the same as before. Profiles are applied only once. + +3. `rebar3 as native ct`: will run the tests in native mode. The order of profiles will be `default`, then `native`, and finally `test` (which is specified last, by the command run). + +4. `rebar3 as test,native ct`: will be similar as the above, with one slight variation. When applying profiles, Rebar3 first expands them all, and applies them in the right order. So the order here would be `default`, then `test`, then `native`. The last `test` profile (because of the `ct` command) is elided since it was already applied. This is not entirely equivalent to calling `rebar3 as native ct`, because if both the `test` and `native` profile were to set conflicting options, the profile order becomes important. + +5. `rebar3 release` will build the release only as the `default` profile. + +6. `rebar3 as prod release` will build the release without development mode, with a stricter set of compiler options. + +7. `rebar3 as prod, native release` will build the release as with the last command, but while also compiling modules to native mode. + +8. `rebar3 as prod release` with `REBAR_PROFILE=native`, in the environment, will build the release as in the last command, but `native` will be applied *before* `prod`. + +The order of application of profiles is therefore: + +1. `default` +2. The `REBAR_PROFILE` value, if any +3. the profiles specified in the `as` part of the command line +4. the profiles specified by each individual command + +Profiles are therefore a composable way to specify configuration subsets in a contextual manner. + +> #### Locking Dependencies {: .info} +> Only dependencies listed at the top level of `rebar.config`, the `default` profile, are saved to `rebar.lock`. Other dependencies will not get locked. +> +> If someone wants to "lock for production" (meaning with production-related profiles), the answer is to keep the default profile and to use [releases](deployment/releases.md), which produce compiled artifacts that can be reused at any time. + +## Option-Merging Algorithm + +It's generally tricky to try and merge all configuration options automatically. Different tools or commands will expect them differently, either as lists of tuples, proplists, or key/value pairs to be transformed into a dictionary of some sort. + +To support the most generic form as possible, Rebar3 handles them as a loose combination of proplists and tuple lists. This means the following options are all seen as having the key `native`: + +- `native` +- `{native, {hipe, o3}}` +- `{native, still, supported}` + +Even though some of them may not be supported by tools. For example, the Erlang compiler supports defining macros as either `{d, 'MACRONAME'}` or `{d, 'MACRONAME', MacroValue}`, but not `d` alone, whereas it does support `native` and `{native, {hipe, o3}}`. + +Rebar3 properly supports all these forms and merges them in a functional manner. Let's take the following profiles as an example: + +```erlang +{profiles, [ + {prod, [ + {erl_opts, [no_debug_info, warnings_as_errors]}, + ]}, + {native, [ + {erl_opts, [{native, {hipe, o3}}, {d, 'NATIVE'}]} + ]}, + {test, [ + {erl_opts, [debug_info]} + ]} +]}. +``` + +Applying the profiles in various orders will yield different lists of options for `erl_opts`: + +- `rebar3 as prod,native,test <command>`: `[debug_info, {d, 'NATIVE'}, {native, {hipe, o3}}, no_debug_info, warnings_as_errors]` +- `rebar3 as test,prod,native <command>`: `[{d, 'NATIVE'}, {native, {hipe, o3}}, no_debug_info, warnings_as_errors, debug_info]` +- `rebar3 as native,test,prod <command>`: `[no_debug_info, warnings_as_errors, debug_info, {d, 'NATIVE'}, {native, {hipe, o3}}]` +- `rebar3 as native,prod,test <command>`: `[debug_info, no_debug_info, warnings_as_errors, {d, 'NATIVE'}, {native, {hipe, o3}}]` + +Notice that the last profiles applied yield the first elements in the list, and that the elements within each profile's list will be sorted according to their key. + +This will allow Rebar3 commands to pick up elements in the right order, while still supporting multi-value lists that require many elements to share the same key (such as `[{d, 'ABC'}, {d, 'DEF'}]`, which are two independent macros!). Commands that do not support duplicated elements can stop processing them after the first ones, while those that build dictionaries (or maps) out of them may choose to insert them as is, or can safely reverse the list first (if the last elements processed become the final ones in maps). + +All profile merging rules are processed safely that way. Plugin writers should be aware of these rules and plan accordingly. + +Note that in practice, the Erlang compiler does not play nice with `debug_info` and `no_debug_info` (which isn't even a real option and was added by Rebar3). Rebar3 does some magic to deduplicate these specific values to please the compiler, but does not extend this courtesy to all tools. Designing your plugins to use `{OptionName, true|false}` is generally a good idea. + +> #### Dependencies and Profiles {: .warning} +> Dependencies will always be compiled with the `prod` profile applied to their configuration. No other (besides `default`, of course) is used on any dependency. Even though they are configured for `prod` the dependency will still be fetched to the profile directory for the profile it is declared under. For example, a dependency in the top level `deps` will be under `_build/default/lib` and a dependency under the profile `test` will be fetched to `_build/test/lib`. Both will be compiled with their `prod` profile configuration applied. diff --git a/docs/deployment/releases.md b/docs/deployment/releases.md new file mode 100644 index 000000000..503c47320 --- /dev/null +++ b/docs/deployment/releases.md @@ -0,0 +1,671 @@ +# Releases + +> #### What are releases and target systems anyway? {: .info} +> A release is a set of applications needed for booting an Erlang VM and starting your project. This is described through a release resource file (`.rel`) which is used to generate a > `.script` and `.boot`. The boot file is the binary form of the script file and is what is used by the Erlang Run-Time System (ERTS) to start an Erlang node, sort of like booting an > operating system. Even running `erl` on the command line is using a boot script. +> +> A target system is an Erlang system capable of being booted on another machine (virtual or otherwise). Often ERTS is bundled along with the target system. +> +> For more information, check out the [chapter on releases](https://adoptingerlang.org/docs/production/releases/) from _Adopting Erlang_. + +## Getting Started + +Add a `relx` section to your project's `rebar.config`: + +```erlang +{relx, [{release, {<release_name>, <release_vsn>}, + [<app>]}, + {release, {<release_name>, <release_vsn>}, + [<app>]}, + + {dev_mode, true}, + {include_erts, false}, + + {extended_start_script, true}]}. +``` + +Running `rebar3 release` will build the release and provide a script for starting a node under `_build/<profile>/rel/<release name>/bin/<release name>`. + +`<release_name>` must be an atom. `<release_vsn>` can be one of: + +| Version type | Result | +| --------------------- | ------------------------------------------------------------- | +| `string()` | A string is used, as is, for the version. Example: `"0.1.0"`| +| `git | semver` | Uses the latest git tag on the repo to construct the version. | +| `{cmd, string()}` | Uses the result of executing the contents of `string()` in a shell. Example to use a file `VERSION`: `{cmd, "cat VERSION | tr -d '[:space:]'"}` | +| `{git, short | long}` | Uses either the short (8 characters) or the full Git ref. of the current commit. | +| `{file, File}` | Uses the content of a file. For example, a better way to use a `VERSION` file than using `cmd` would be: `{file, "VERSION"}` | + +Each `<app>` is an atom of the app name (e.g., `myapp`), or a tuple. For the tuple syntax of `<app>`, see [App Syntax](#app-syntax). + +You can add multiple `release` sections to your project's `rebar.config` under `relx`. + +You can either just specify different releases sharing the same configuration: + +```erlang +{relx, [{release, {<release name>, "0.0.1"}, + [<app>]}, + + {release, {<other release name>, "0.1.0"}, + [<app>]}, + + {dev_mode, false}, + {include_erts, true}, + ]}. +``` + +Or you can also specify releases with independent configurations by using a +4-tuple `release` definition: + +```erlang +{relx, [{release, {<release name>, "0.0.1"}, + [<app>], + [{dev_mode, false}, + {include_erts, true}]}, + {release, {<release name>, "0.1.0"}, + [<app>], + [{dev_mode, true}]} + ]}. +``` + +You can build specific releases using `rebar3 release -n <release_name>` + +## Build Configuration + +### App Syntax + +```erlang +{release, {myrelease, "0.1.0"}, + [<app1>, <app2>]} +``` + +In a release, each `<app>` is an atom of the app name, or a tuple with the app name and additional options: + +```erlang +% No options specified +myapp + +% All options specified +{myapp, "1.1.0", transient, [otherapp]} + +% Some options specified +{myapp, "1.1.0"} +{myapp, "1.1.0", transient} +{myapp, "1.1.0", [otherapp]} +{myapp, transient} +{myapp, [otherapp]} +{myapp, transient, [otherapp]} +``` + +In this case, `myapp` is included in the release, its app version is `"1.1.0"`, its start type is `transient`, and its list of included apps is `[otherapp]`. These options directly correspond to the [release resource file (`.rel`)](//erlang.org/doc/man/rel.html): + +```erlang + {<app_name>, % atom() + <app_vsn>, % string() + <start_type>, % permanent | transient | temporary | load | none + <included_apps>} % [atom()] +``` + +- Elements after `<app_name>` may be omitted, as long as the order is preserved. +- If `<app_vsn>` is included (uncommon), it must match `.app.src`. Otherwise, `relx` determines it from `.app.src`. +- The release resource file syntax, repeated below for completeness, makes it so that: + - `<start_type>` defaults to `permanent`. + - `<included_apps>` defaults to `included_apps` from `.app.src`. If specified, must be a subset `included_apps` from `.app.src`. + +### Source Code Inclusion in Release + +By default, the release will include source files of your applications, if present. + +If you don't want to include the source files, set `include_src` to false. + +```erlang +{include_src, false} +``` + +### Application exclusions + +The following allows you to remove specific applications from the output release. + +```erlang +{exclude_apps, [app1, app2]} +``` + +The Applications will be removed from the `.app` file of any Application in the +release that had them listed under `applications`. + +### Module exclusions + +The following directive allows you to remove application modules from the output release. + +```erlang +{exclude_modules, [ + {app1, [app1_mod1, app1_mod2]}, + {app2, [app2_mod1, app2_mod2]} +]}. +``` + +The modules will be removed from the Application's `.app` file's `module` list. + +### Modes + +Other modes include `prod` and `minimal`: + +```erlang +{relx, [... + {mode, <mode>}, + ... + ] +}. +``` + +| Mode | Expanded Options | +| --------------------- | ------------------------------------------------------------- | +| `dev` | `[{dev_mode, true}, {include_src, true}, {debug_info, keep}, {include_erts, false}]` | +| `prod` | `[{include_src, false}, {debug_info, strip}, {include_erts, true}, {dev_mode, false}]` | +| `minimal` | `[{include_src, false}, {debug_info, strip}, {include_erts, false}, {dev_mode, false}]` | + +While developing you'll likely want all your changes to applications be +immediately available in the release. `relx` provides multiple modes, including +a mode `dev` for this particular use case. Instead of copying the applications +that make up the release to the release structure it creates symlinks, so +compiling and restarting or loading the changed modules is all that is necessary. + +The `prod` mode expands to options that are commonly used for production +releases: `include_src` is `false`, so that source code is not included in the release; +`debug_info` is set to `strip`, which makes BEAM files smaller and only removes +data that is used by tools you more than likely aren't including in your +release; and `include_erts` is set to `true`, to bundle in the current Erlang +runtime, making a release you can copy to a compatible target and run without +first installing Erlang. + +> #### Rebar3 Prod Profile {: .info} +> When building in the `rebar3` `prod` profile, like with `rebar3 as prod release` +> then the `relx` `prod` mode is enabled automatically. + +The `minimal` mode is the same as `prod` except it does not include the Erlang +runtime. + +You can override options that the modes expand to by including explicit setting +them. For example, if you wanted to keep the debug info in the BEAM modules +you can use a configuration like: + +```erlang +[ + {mode, prod}, + {debug_info, keep} +] +``` + +## Verification Checks + +### Missing Functions + +By default `relx` will check that the external functions used in the modules of +the project applications included in a release exist. This means a warning will +be given if a function is called that isn't included in the release, even if it +is a dependency in `rebar.config` or an application included in OTP. + +This helps to protect against a common mistake that has bitten us all at some +point, forgetting to add an application to the `.app.src` of the application +that depends on it. + +If for some reason you wish to disable this check you can set it to false in the +`relx` config: + +```erlang +{check_for_undefined_functions, false} +``` + +### Stale Modules + +Option `src_tests` will issue a warning if the source code for a module is +missing or is newer than the object code: + +```erlang +{src_tests, true} +``` + +This is useful to catch any modifications to dependency source files. Since +`rebar3 release` will automatically compile all changes to the Applications in +your project, the dependencies should be the only modules that could possibly be +stale. + +## Runtime Configuration + +### VM Configuration + +By default `relx` will give a basic `vm.args` file that sets a node name and cookie. For a complete list of options and their use check the [Erlang documentation](https://erlang.org/doc/man/erl.html). + +```plain +## Name of the node +-name {{release_name}}@127.0.0.1 + +## Cookie for distributed Erlang +-setcookie {{release_name}} +``` + +To provide a custom `vm.args` or `vm.args.src`, simply create the file in the +top level `config/` directory at the root of your project. If you name it +something other than `vm.args` or `vm.args.src` you must add to the `relx` +configuration: + +```erlang +{vm_args, "config/vm_prod.args"} +``` + +or: + +```erlang +{vm_args_src, "config/vm_prod.args.src"} +``` + +### Application Configuration + +For passing Application configuration at release runtime there is `sys.config` and `sys.config.src`: + +```erlang +[ + {<app_name>, [{<key>, <val>}, ...]} +]. +``` + +If either file `config/sys.config.src` or `config/sys.config` exists in the +project then `relx` will automatically include one of them (`.src` takes +precedence if both exist) in the release. + +To set a specific file to use as the Application configuration file it can be +set with either `sys_config` or `sys_config_src`: + +```erlang +{sys_config, "config/sys_prod.config"} +``` + +```erlang +{sys_config_src, "config/sys_prod.config.src"} +``` + +The files will be renamed to `sys.config` or `sys.config.src` when included into +the release. + +If none exists then a file with an empty list is used. + +Read more about Erlang configuration in the [config +docs](https://erlang.org/doc/man/config.html) and in the [systools +docs](https://erlang.org/doc/man/systools.html). + +### Environment Variable Replacement + +#### With OTP-21+ and Rebar3 3.6+ + +Starting with Erlang/OTP 21 and Rebar3 3.6.0 the configuration options +`sys_config_src` and `vm_args_src` are available for explicitly including +templates that will be rendered at runtime, substituting variables defined +as `${VARIABLE}` with their equivalent value in the shell environment. +Since Rebar3 3.14.0, a default value can be optionally set when using variables +by defining them as `${VARIABLE:-DEFAULT}`. + +As of Rebar3 3.14.0 the configs will be included if they exist, so only if the +files are not named `config/sys.config.src` and `config/vm.args.src` do you +need to include `{sys_config_src, <filename>}` or `{vm_args_src, <filename>}` +in the relx config. + +```erlang +%% sys.config.src +[ + {appname, + [ + {port, ${PORT:-8080}}, + {log_level, ${LOG_LEVEL:-info}}, + {log_root, "${LOG_ROOT:-/var/log/appname}"} + ]} +]. +``` + +```plain +# vm.args.src +-name ${NODE_NAME} +``` + +```erlang +%% rebar.config +{relx, [{release, {<release name>, "0.0.1"}, + [<app>]}, + + {mode, dev}]}. +``` + +There is no need to set `RELX_REPLACE_OS_VARS=true` when using `.src` files for +configuration. In the following section we'll see older forms of runtime +configuration. + +#### Before OTP-21 and Rebar3 3.6 + +By setting `RELX_REPLACE_OS_VARS=true` both `vm.args` and `sys.config` files may contain OS environment variables that will be replaced with the current value from the environment the node is started in. This means a `vm.args` and `sys.config` for a release that starts a web server listening on a port could look like: + +```plain +# vm.args +-name ${NODE_NAME} +``` + +```erlang +%% sys.config +[ + {appname, [{port, "${PORT}"}]} +]. +``` + +And then be used to start multiple nodes of the same release with different name. + +```bash +#!/bin/bash + +export RELX_REPLACE_OS_VARS=true + +for i in `seq 1 10`; +do + NODE_NAME=node_$i PORT=808$i _build/default/rel/<release>/bin/<release> foreground & + sleep 1 +done +``` + +### Overlays: Build-Time Configuration + +Overlays provide the ability to define files and templates to include in the target system. For example, custom scripts for managing your node or the Procfile needed for running on Heroku. + +```erlang +{relx, [ + ... + {overlay_vars, "vars.config"}, + {overlay, [{mkdir, "log/sasl"}, + {template, "priv/app.config", "etc/app.config"}, + {copy, "Procfile", "Procfile"}]} +]}. +``` + +The supported actions are: + +- `mkdir` to create a directory within the release +- `copy` to copy a file from a local directory to a location within the release +- `template` to behave the way `copy` does, but with variable expansion in it. + +Relx's templating exposes variables along with the full power of a Mustache templating system (see [mustache](https://github.com/soranoba/mustache)). You can look at the documentation there for the full syntax supported. + +There is a set of variables made available by default which are described in the next session, and custom variables can otherwise be declared in the file specified in `{overlay_vars, "vars.config"}`, which should have the following format: + +```erlang +%% some variables +{key, value}. +{other_key, other_val}. +%% includes variables from another file +"./some_file.config". +``` + +The default variables are defined below. + +#### Predefined Overlay variables + +| Name | Description | +|------|-------------| +| `log` | The current log level in the format of `(<logname>:<loglevel>)` | +| `output_dir` | The current output directory for the built release | +| `target_dir` | The same as `output_dir`; exists for backwards compatibility | +| `overridden` | The current list of overridden apps (a list of app names) | +| `goals` | The list of user-specified goals in the system | +| `lib_dirs` | The list of library directories, both user-specified and derived | +| `config_file` | The list of config file used in the system | +| `providers` | The list of provider names used for this run of `relx` | +| `sys_config` | The location of the `sys.config` file | +| `root_dir` | The root dir of the current project | +| `default_release_name` | The current default release name for the `relx` run | +| `default_release_version` | The current default release version for the `relx` run | +| `default_release` | The current default release for the `relx` run | +| `release_erts_version` | The version of the Erlang Run-Time System in use | +| `erts_vsn` | The same as `release_erts_version` (for backwards compatibility) | +| `release_name` | The currently executing release | +| `release_version` | The currently executing version | +| `rel_vsn` | Same as `release_version`. Exists for backwards compatibility | +| `release_applications` | A list of applications included in the release | + +##### Splitting configurations + +It is possible to split overlay files to deal with more complex situations. To explain this lets look at a simplified example. + +We build our application and want to distinguish between production and developing builds by having the overlay variable `build` spell out either `"prod"` or `"dev"` so the `app.config` file could include it in its configuration and we can either enable or disable features. + +For this we build three overlay files: + +- `dev.config` +- `prod.config` +- `base.config` + +For dev builds we will use `dev.config` as `overlay_vars` and for prod we will be using `prod.config`. + +```erlang +%% base.config +{data_dir, "/data/yolo_app"}. +{version, "1.0.0"}. +{run_user, "root"}. +``` + +```erlang +%% dev.config +%% Include the base config +"./base.config". +%% The build we have +{build, "dev"}. +``` + +```erlang +%% prod.config +%% Include the base config +"./base.config". +%% The build we have +{build, "prod"}. +``` + +## Deployable Tarball + +### With ERTS Included + +A target system can not have symlinks like those created when using `dev_mode` and often we want to include ERTS along with the system so it does not need to be previously installed on the target. + +Rebar3 will automatically add `{mode, prod}` to the Relx configuration if the +`prod` profile is used to build the release. For example: + +```shell +$ rebar3 as prod tar +===> Verifying dependencies... +===> Analyzing applications... +===> Compiling relx_overlays +===> Assembling release myrel-0.1.0... +===> Release successfully assembled: _build/prod/rel/myrel +===> Building release tarball myrel-0.1.0.tar.gz... +===> Tarball successfully created: _build/prod/rel/myrel/myrel-0.1.0.tar.gz +``` + +Now a tarball `myrel-0.1.0.tar.gz` can be copied to another compatible system and booted: + +```shell +$ mkdir myrel +$ mv myrel-0.1.0.tar.gz myrel/ +$ cd myrel +$ tar -zxvf myrel-0.1.0.tar.gz +$ bin/myrel console +``` + +### Without ERTS + +When it is required to leave ERTS out of a release the `prod` profile +configuration can be set in `rebar.config` under `profiles`. For example, to use +the ERTS and base applications like `kernel` and `stdlib` on the target, set +`mode` to `minimal` and `system_libs` to `false` in the `relx` configuration tuple: + +```erlang +{profiles, [{prod, [{relx, [{mode, minimal}, + {system_libs, false}]}]}]}. +``` + +Or manually set `include_erts` to `false`: + +```erlang +{profiles, [{prod, [{relx, [{include_erts, false}, + {system_libs, false}]}]}]} +``` + +Now when running `rebar3 as prod tar` the generated tarball will not include +ERTS or Applications like `kernel` and `stdlib`. + +### With ERTS Built for Another System + +If you wish to include an Erlang Run Time System that is not the version you are using to run `rebar3`, for example you are building on MacOS but wish to include an ERTS that was built for a version of GNU/Linux, you can supply a path instead of a boolean for `include_erts` and provide a path for `system_libs`, still within the `relx` configuration tuple: + +```erlang +{include_erts, "/path/to/erlang"}, +{system_libs, "/path/to/erlang"}, +``` + +Using these paths with profiles can yield easier ways to set up cross-compiling. + +## Extended Start Script + +### Commands + +The extended start script that comes with `relx` provides a few ways of starting +and connecting to your release. + +For local development you'll likely use `console`. In production you'll want +`foreground`, no matter if you are starting manually in something like `tmux`, +using an init system like `systemd` or running the release in a Docker container. + +To open a console on a node started with `foreground` use `remote_console`. + +A full list of commands is below. + +| Command | Description | +| --------------------- | ------------------------------------------------------------- | +| `foreground` | Start release with output to stdout | +| `remote` | Connect remote shell to running node | +| `console` | Start the release with an interactive shell | +| `console_clean` | Start an interactive shell without the release's applications | +| `rpc [Mod [Fun [Args]]]]` | Run `apply(Mod, Fun, Args)` on running node | +| `eval [Exprs]` | Run expressions on running node | +| `status` | Verify node is running and then run status hook scripts | +| `restart` | Restart the applications but not the VM | +| `reboot` | Reboot the entire VM | +| `stop` | Stop the running node | +| `pid` | Print the PID of the OS process | +| `ping` | Print pong if the node is alive | +| `daemon` | Start release in the background with `run_erl` (named pipes) | +| `daemon_attach` | Connect to node started as daemon with `to_erl` (named pipes) | + +### Release Handling: Install and Upgrade + +Additionally, the extended start script contains commands for using +[release_handler](https://erlang.org/doc/man/release_handler.html): + +| Command | Description | +| --------------------- | ------------------------------------------------------------- | +| `unpack [Version]` | Unpack a release tarball | +| `install [Version]` | Install a release | +| `uninstall [Version]` | Uninstall a release | +| `upgrade [Version]` | Upgrade the running release to a new version | +| `downgrade [Version]` | Downgrade the running release to a new version | +| `versions` | Print versions of the release available | + +To understand how these work see the OTP Design Principles chapter [Release +Handling](https://erlang.org/doc/design_principles/release_handling.html). + +For a detailed workflow including version increments and appup generation +checkout Richard Jones [relflow](https://github.com/RJ/relflow) tool built +around `rebar3`. + +For the basic release upgrade after installation of a release assume we have a release named `myrel` with a version `0.0.1` and `0.0.2`: + +- Installing: Installing a release on a running system will unpack and upgrade the version: `bin/myrel install 0.0.1` +- Listing: you can inspect what versions are currently available: `bin/myrel versions` +- Upgrading: If the version is already unpacked you can simply call `upgrade` to upgrade to the version: `bin/myrel upgrade 0.0.2` +- Downgrading: To downgrade to the previous version use the `downgrade` command: `bin/myrel downgrade 0.0.1` + +### Hooks + +It is possible to define hooks on specific operations of the extended start script, the operations are `start`, `stop`, and `install_upgrade`; `pre` and `post` hooks for each of these operations are available. + +The hooks can either be built-in (ie. they are already included in the release) or custom (scripts written by the user for custom functionality). The built-in scripts, offering pre-packaged functionality, are: + +- *pid* : Writes the BEAM pid to a configurable file location (`/var/run/<rel_name>.pid` by default). +- *wait_for_vm_start* : Waits for the VM to start (ie. when it can be pinged). +- *wait_for_process* : Waits for a configurable name to appear in the Erlang process registry. + +```erlang +{extended_start_script_hooks, [ + {pre_start, [{custom, "hooks/pre_start"}]}, + {post_start, [ + {pid, "/tmp/foo.pid"}, + {wait_for_process, some_process}, + {custom, "hooks/post_start"} + ]}, + {pre_stop, [ + {custom, "hooks/pre_stop"}]}, + {post_stop, [{custom, "hooks/post_stop"}]}, + ]}, + {post_stop, [{custom, "hooks/post_stop"}]} +]}. +``` + +### Extensions + +The extended start script that is generated comes with a built-in set of commands that allows you to manage your release: `foreground`, `stop`, `restart`, etc. + +Sometimes it's useful to expose some custom commands that are specific to your application. For example, if you're running a game server it would be convenient to just call `bin/gameserver games` that outputs useful information. + +Extended start script extensions allow you to create a custom shell script that gets appended to the list of commands available to your start script. The extension shell script can take arguments and has access to all shell variables defined in the start script itself. You begin by defining the extension in your `rebar.config`, for example: + +```erlang +%% start script extensions +{extended_start_script_extensions, [ + {status, "extensions/status"} +]}. +``` + +Here you are adding the `status` script extension that will invoke an `extensions/status` shell script. + +This path is relative to the location of the start script on the generated release so you probably will want to use a `overlay` to place it at the correct location: + +```erlang +{copy, "scripts/extensions/status", "bin/extensions/status"}, +``` + +The extension script itself is standard shell script, the game server example described could be implemented in the following way: + +```bash +#!/bin/bash + +case $1 in + help) + echo "bin/gameserver status" + ;; + *) + ;; +esac + +# get the status tuple from gameserver +Status=$(relx_nodetool eval "pool_debug:status(json).") + +# now print it out +code="Json = binary_to_list($Status), + io:format(\"~p~n\", [Json]), + halt()." +echo $(erl -boot no_dot_erlang -sasl errlog_type error -noshell -eval "$code") +``` + +## Other Configurations + +The `RELX_RPC_TIMEOUT` environment value can be set on the target system running a release to choose how long the scripts can wait before giving up on contacting the running Erlang system. It defaults to the `NODETOOL_TIMEOUT` value (converted from milliseconds to seconds) if no value is specified. If `NODETOOL_TIMEOUT` itself is not set, the default is 60 seconds. + +## References + +- [relx](https://github.com/erlware/relx) +- [relflow](https://github.com/RJ/relflow) +- [Releases](https://adoptingerlang.org/docs/production/releases/) chapter from Adopting Erlang +- [Releases](https://learnyousomeerlang.com/release-is-the-word) chapter from Learn You Some Erlang +- OTP [release](https://www.erlang.org/doc/design_principles/release_structure.html) documentation +- OTP [target system](https://www.erlang.org/doc/system_principles/create_target.html) documentation diff --git a/docs/extending/custom_compiler_modules.md b/docs/extending/custom_compiler_modules.md new file mode 100644 index 000000000..99e53dcf1 --- /dev/null +++ b/docs/extending/custom_compiler_modules.md @@ -0,0 +1,106 @@ +# Custom Compiler Modules + +This is a new feature in Rebar3 3.7.0, to write custom compilers to be used with it. It is useful whenever you have files of a different language that you want to build alongside Erlang resources. Starting with Rebar3 3.14.0, the interface was enhanced to allow better tracking of files in a directed acyclic graph (DAG), which lets you annotate build artifacts and allows Rebar3 to track dependencies across applications. + +This interface is currently used internally for `.xrl`, `.yrl`, and `.mib` files. Few plugins have tried it. + +> #### This is an unstable interface {: .warning} +> Since we have not had many plugin authors try this interface yet, it is marked as unstable and is subject to change. +> +> We are looking for help from contributors to further stabilize it before marking it as stable. You should use this if you are willing to contact us, and help iterate on the > features available in [Custom Compiler Plugins](extending/custom_compiler_plugins.md). +> +> It is possible that your custom compiler requires something more complex. For example, the facilities provided by this interface are insufficient to build projects that run with `mix` as a build tool, and the plugin for that uses [a custom compiler plugin](extending/custom_compiler_plugins.md). + +## Current Interface + +The following callbacks are defined: + +```erlang +%% specify what kind of files to find and where to find them. Rebar3 handles +%% doing all the searching from these concepts. +context(AppInfo) -> + %% Mandatory Fields + %% directories containing source files + #{src_dirs => ["/path/to/src/"], + include_dirs => ["/path/to/includes/"], + src_ext => ".erl", + out_mappings => [{".beam", "/path/to/ebin"}], + %% Optional Fieldsstate passed to dependencies callback + dependencies_opts => term()}. % optional, v3.14+ + +%% Define which files each of the files depends on, including includes and whatnot. +%% This is then used to create a digraph of all existing files to know how to propagate +%% file changes. The Digraph is passed to other callbacks as `G' and annotates all files +%% with their last changed timestamp +%% Prior to 3.14, the `State' argument was not available. +dependencies("/path/to/file.erl", "/path/to/", + ["/path/to/all/other_sources/", ...], State) -> + ["path/to/deps.erl", ...]. + +%% do your own analysis aided by the graph to specify what needs re-compiling. +%% You can use this to add more or fewer files (i.e. compiler options changed), +%% and specify how to schedule their compilation. One thing we do here for +%% Erlang files is look at the digraph to only rebuild files with newer +%% timestamps than their build artifacts (which are also in the DAG after the +%% first build) or those with compiler options that changed (the +%% compile_and_track callback lets you annotate artifacts) +needed_files(G, ["/path/to/all/files.erl", ...], [{".beam", "/path/to/ebin"}], AppInfo) -> + %% the returned files to build essentially specify a schedule and priority with special + %% option sets + %% Files that _must_ be built first like those in parse transforms, with + %% different build options + {{["/top/priority/files.erl"], CompilerOpts}, + %% {Sequential, Parallel} build order for regular files, with shared + %% compiler options + {{["/path/to/file.erl", ...], ["other/files/mod.erl", ...]}, CompilerOpts}}. + +%% Compilation callback with the ability to track build artifacts in the DAG itself. +%% Introduced in 3.14. Prior to this version, refer to `compile/4'. +compile_and_track("/path/to/file.erl", [{".beam, "/path/to/ebin"}], + AppOptDict, CompilerOpts) -> + %% Successfully built a file, tying it to artifacts with optional metadata + {ok, [{"/path/to/file.erl", "path/to/ebin/file.beam", Metadata}]} | + %% Successfully built a file, but it has compiler warnings + {ok, [{"/path/to/file.erl", "path/to/ebin/file.beam", Metadata}], + ["Some compiler warning"]} | + %% Failed build + {error, ["error strings"], ["warning strings"]} | error. + +%% A simpler compilation mechanism which does not track build artifacts into the +%% DAG for the compiler. Change for built files must be figured out from files on +%% disk or other storage. +compile("/path/to/file.erl", [{".beam", "/path/to/ebin"}], + AppConfig, CompilerOpts) -> + ok + | {ok, ["Some compiler warning"]} + | {ok, ["error strings"], ["warning strings"]}. + +%% Just delete files however you need to +clean(["/path/to/file"], AppInfo) -> _. +``` + +## Initializing a Compiler Module as a Plugin + +Register the compiler module in the same place where you would register [a custom compiler plugin](extending/custom_compiler_plugins.md): + +```erlang +%% Note: the name of the module matches the name of the plugin application +-module(my_compiler_plugin). +-export([init/1]). + +%% Called when Rebar3 first boots, before even parsing the arguments +%% or commands to be run. Purely initiates the provider, and nothing +%% else should be done here. +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + %% Optional: + %% Provider = providers:create([Options]), + %% State1 = rebar_state:add_provider(State, Provider), + + %% This adds the new compiler module: + State1 = rebar_state:append_compilers(State, [my_compiler_mod]), + %% If needing the new compiler module to take precedence over + %% other ones (i.e. generating .erl files from another format): + State2 = rebar_state:prepend_compilers(State1, [translator_mod]), + {ok, State2}. +``` diff --git a/docs/extending/custom_compiler_plugins.md b/docs/extending/custom_compiler_plugins.md new file mode 100644 index 000000000..c173ca47c --- /dev/null +++ b/docs/extending/custom_compiler_plugins.md @@ -0,0 +1,96 @@ +# Custom Compiler Plugins + +This tutorial shows you how to write plugins that provide wholesale new compilers. This is something you should use if you want to be compatible with Rebar3 prior to version 3.7.0, or when your compiler requires features outside of the scope of what is provided by the compiler plugin behaviour. + +Often applications have non-Erlang code that needs compiling, such as DTL templates, C code for generating parsers from PEG files, etc. The plugin providers that implement these compilers should be in their own namespace and must be hooked to the main `compile` provider if they are to automatically run when a user invokes `compile`: + +```erlang +{provider_hooks, [ + {post, [{compile, {pc, compile}}]} +]}. +``` + +In the above example the namespace `pc` (port compiler) has a provider named `compile` that we have set to run after the main `compile` provider. + +## Example Provider + +We'll implement an example provider that "compiles" files in the directory `exc_files/` with the extension `.exc` to the priv directory of the application. The full source code can be found on [github](https://github.com/tsloughter/rebar3_ex_compiler). + +The definitions are similar to what was done in the [Building Plugins](tutorials/building_plugins.md) tutorial, but in this case we also have a `NAMESPACE` macro. This is important because the provider name is `compile` which, without defining a new namespace, would conflict with the existing `default` namespace `compile` provider. + +```erlang +-module(rebar3_prv_ex_compiler). + +-export([init/1, do/1, format_error/1]). + +-define(PROVIDER, compile). +-define(NAMESPACE, exc). +-define(DEPS, [{default, app_discovery}]). +``` + +The same is done for `init/1`, similar to the previous tutorial, but with `namespace` added to the properties: + +```erlang +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + Provider = providers:create([ + {name, ?PROVIDER}, + {namespace, ?NAMESPACE}, + {module, ?MODULE}, + {bare, true}, + {deps, ?DEPS}, + {example, "rebar3 exc compile"}, + {opts, []}, + {short_desc, "An example rebar compile plugin"}, + {desc, ""} + ]), + {ok, rebar_state:add_provider(State, Provider)}. +``` + +Now for the meat of the provider. Since the provider is for compiling part of an Erlang application we must find what application it is we are currently building. If the provider is being run as a hook `current_app` will contain the application record to use. Otherwise it will be undefined, like in the case the user ran `rebar3 exc compile`. For that case the list of applications to compile files for are the `project_apps`, found in `State`. + +For each application the `rebar_base_compiler:run/4` function is run, it will run `CompileFun` (in this case `exc_compile/3` on each source file: + +```erlang +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + Apps = case rebar_state:current_app(State) of + undefined -> + rebar_state:project_apps(State); + AppInfo -> + [AppInfo] + end, + [begin + Opts = rebar_app_info:opts(AppInfo), + OutDir = rebar_app_info:out_dir(AppInfo), + SourceDir = filename:join(rebar_app_info:dir(AppInfo), "exc_files"), + FoundFiles = rebar_utils:find_files(SourceDir, ".*\\.exc\$"), + + CompileFun = fun(Source, Opts1) -> + exc_compile(Opts1, Source, OutDir) + end, + + rebar_base_compiler:run(Opts, [], FoundFiles, CompileFun) + end || AppInfo <- Apps], + + {ok, State}. +``` + +Finally, `exc_compile/3` reads in the source file and writes it to the output `priv` directory for the application. Yes, we aren't actually "compiling" anything, but if you wanted to, this is where you would: + +```erlang +exc_compile(_Opts, Source, OutDir) -> + {ok, Binary} = file:read_file(Source), + OutFile = filename:join([OutDir, "priv", filename:basename(Source)]), + filelib:ensure_dir(OutFile), + rebar_api:info("Writing out ~s", [OutFile]), + file:write_file(OutFile, Binary). +``` + +Finally, in the `rebar.config` of a project our provider can be hooked to the default `compile` provider with a `provider_hook` and run every time `rebar3 compile` is executed. In this case `rebar_state:current_app/1` would return a single `AppInfo` record for the application we are currently building: + +```erlang +{provider_hooks, [ + {pre, [{compile, {exc, compile}}]} +]}. +``` diff --git a/docs/extending/custom_dep_resources.md b/docs/extending/custom_dep_resources.md new file mode 100644 index 000000000..0bfdd0966 --- /dev/null +++ b/docs/extending/custom_dep_resources.md @@ -0,0 +1,233 @@ +# Custom Dep Resources + +## Resources Compatible with versions 3.7.0 and Above + +Starting with version 3.7.0, Rebar3 published a new API for custom resources, which gives access to the project's local configuration to enable more powerful custom dependency formats. They can use contextual information from the current build to customize how dependencies might be fetched. + +> #### The new Interface is not backwards compatible {: .warning} +> This new interface is unknown and unsupported in versions prior to 3.7.0. If you are writing libraries that should work with all Rebar3 copies, skip to the next section, where > resources compatible with all Rebar3 versions are documented. +> +> Old interfaces however are still compatible with all versions and no support for existing project has been broken in adding the new API. + +The new callback API is defined as follows: + +```erlang +%% Type declarations +-type resource() :: #resource{}. % an opaque record generated by an API call described below +-type source() :: {type(), location(), ref()} | {type(), location(), ref(), binary()}. +-type type() :: atom(). +-type location() :: string(). +-type ref() :: any(). +-type resource_state() :: term(). + +%% and the following callbacks +-callback init(type(), rebar_state:t()) -> {ok, resource()}. +-callback lock(rebar_app_info:t(), resource_state()) -> source(). +-callback download(file:filename_all(), rebar_app_info:t(), rebar_state:t(), resource_state()) -> + ok | {error, any()}. +-callback needs_update(rebar_app_info:t(), resource_state()) -> boolean(). +-callback make_vsn(rebar_app_info:t(), resource_state()) -> + {plain, string()} | {error, string()}. +``` + +The callbacks allow the resource plugin to have access to the `rebar_state:t()` data structure, which lets you access and manipulate the [Rebar3 state](tutorials/building_plugins.md#rebar-state-manipulation), find application state, and generally work with the [`rebar_state`](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_state.erl), [`rebar_app_info`](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_app_info.erl), [`rebar_dir`](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_dir.erl), and the new [`rebar_paths`](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_paths.erl) modules. + +An example of a plugin making use of this functionality is [rebar3_path_deps](https://github.com/benoitc/rebar3_path_deps). Rebar3's own [hex package resource](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_pkg_resource.erl) uses this API. + +A resource plugin is initialized the same way as any other plugin would: + +```erlang +-module(my_rebar_plugin). + +-export([init/1]). + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + {ok, rebar_state:add_resource(State, {Tag, Module})}. +``` + +Where `Tag` stands for the type in the `deps` configuration value (`git`, `hg`, etc.), and `Module` is the callback module. + +The callback module may look as follows: + +```erlang +-module(my_rebar_plugin_resource). + +-export([init/2, + lock/2, + download/4, + needs_update/2, + make_vsn/1]). + +%% Initialize the custom dep resource plugin +init(Type, _RebarState) -> + CustomState = #{}, + Resource = rebar_resource_v2:new( + Type, % type tag such as 'git' or 'hg' + ?MODULE, % this callback module + CustomState % anything you want to carry around for next calls + ), + {ok, Resource}. + +lock(AppInfo, CustomState) -> + %% Extract info such as {Type, ResourcePath, ...} as declared + %% in rebar.config + SourceTuple = rebar_app_info:source(AppInfo), + %% Annotate and modify the source tuple to make it absolutely + %% and indeniably unambiguous (for example, with git this means + %% transforming a branch name into an immutable ref) + ... + %% Return the unambiguous source tuple + ModifiedSource. + +download(TmpDir, AppInfo, RebarState, CustomState) -> + %% Extract info such as {Type, ResourcePath, ...} as declared + %% in rebar.config + SourceTuple = rebar_app_info:source(AppInfo)), + %% Download the resource defined by SourceTuple, which should be + %% an OTP application or library, into TmpDir + ... + ok. + +make_vsn(Dir, CustomState) -> + %% Extract a version number from the application. This is useful + %% when defining the version in the .app.src file as `{version, Type}', + %% which means it should be derived from the build information. For + %% the `git' resource, this means looking for the last tag and adding + %% commit-specific information + ... + {plain, "0.1.2"}. + + +needs_update(AppInfo, CustomState) -> + %% Extract the Source tuple if needed + SourceTuple = rebar_app_info:source(AppInfo), + %% Base version in the current file + OriginalVsn = rebar_app_info:original_vsn(AppInfo) + %% Check if the copy in the current install matches + %% the defined value in the source tuple. On a conflict, + %% return `true', otherwise `false' + ..., + Bool. +``` + +## Resources Compatible with all versions + +Prior to version 3.7.0, the dependency resource framework was a bit more restricted. It had to essentially work context-free, with only the `deps` information from the `rebar.config` and `rebar.lock` to work from. It was not possible to have any information relative to the project configuration, which essentially restricted what could be done by each resource. + +These custom resources are still supported in Rebar3 versions higher than 3.7.0, and so if you have users running older build, we recommend that you develop this kind of resources only. + +Each dependency resource must implement the `rebar_resource` behaviour. + +```erlang +-module(rebar_resource). + +-export_type([resource/0 + ,type/0 + ,location/0 + ,ref/0]). + +-type resource() :: {type(), location(), ref()}. +-type type() :: atom(). +-type location() :: string(). +-type ref() :: any(). + +-callback lock(file:filename_all(), tuple()) -> + rebar_resource:resource(). +-callback download(file:filename_all(), tuple(), rebar_state:t()) -> + {tarball, file:filename_all()} | {ok, any()} | {error, any()}. +-callback needs_update(file:filename_all(), tuple()) -> + boolean(). +-callback make_vsn(file:filename_all()) -> + {plain, string()} | {error, string()}. +``` + +Included with `rebar3` are [rebar_git_resource](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_git_resource.erl), [rebar_hg_resource](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_hg_resource.erl) and [rebar_pkg_resource](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_pkg_resource.erl). + +A custom resource can be included the same way as a plugin. An example of this can be seen in Kelly McLaughlin's [rebar3_tidy_deps resource](https://github.com/kellymclaughlin/rebar3-tidy-deps-plugin): + +```erlang +-module(rebar_tidy_deps). + +-export([init/1]). + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + {ok, rebar_state:add_resource(State, {github, rebar_github_resource})}. +``` + +This resource `rebar_github_resource` which implements the `rebar3` resource behaviour is added to the list of resources available in `rebar_state`. Adding the repo as a plugin to `rebar.config` allows this resource to be used: + +```erlang +{mydep, {github, "kellymclauglin/mydep.git", {tag, "1.0.1"}}}. + +{plugins, [ + {rebar_tidy_deps, ".*", {git, "https://github.com/kellymclaughlin/rebar3-tidy-deps-plugin.git", {tag, "0.0.2"}}} +]}. +``` + +## Writing a Plugin working with both versions + +If you want to write a custom resource plugin that works with both versions, you can dynamically detect arguments to provide backwards-compatible functionality. In the example below, the new API disregards all new information and just plugs itself back in the old API: + +```erlang +-module(my_rebar_plugin_resource). + +-export([init/2, + lock/2, + download/4, download/3, + needs_update/2, + make_vsn/1]). + +init(Type, _RebarState) -> + CustomState = #{}, + Resource = rebar_resource_v2:new(Type, ?MODULE, CustomState), + {ok, Resource}. + +%% Old API +lock(Dir, Source) when is_tuple(Source) -> + lock_(Dir, Source); +%% New API +lock(AppInfo, _ResourceState) -> + %% extract info for dir extract info for source + lock_(rebar_app_info:dir(AppInfo), rebar_app_info:source(AppInfo)). + +%% Function handling normalized case +lock_(Dir, Path) -> + ... + +%% Old Version +download(TmpDir, SourceTuple, RebarState) -> + download_(TmpDir, SourceTuple, State). + +%% New Version +download(TmpDir, AppInfo, RebarState, _ResourceState) -> + %% extract source tuple + download_(TmpDir, rebar_app_info:source(AppInfo), RebarState). + +%% Function handling normalized case +download_(TmpDir, {MyTag, ...}, _State) -> + ... + +%% Old version +make_vsn(Dir) -> + ... +%% New version +make_vsn(Dir, _ResourceState) -> + make_vsn(Dir). + +%% Old Version +needs_update(Dir, {MyTag, Path, _}) -> + needs_update_(Dir, {MyTag, Path}); +%% New Version +needs_update(AppInfo, _) -> + needs_update_(rebar_app_info:dir(AppInfo), rebar_app_info:source(AppInfo)). + +%% Function handling normalized case +needs_update_(Dir, {Tag, Path}) -> + ... +``` + +Note that if you resource really needs the new API to work, backwards compatibility will be difficult to achieve since whenever it will be called, it won't have all the information of the new API. + +This approach is mostly useful when you can provide an acceptable (even if degraded) user experience with the old API. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 000000000..addbcfa8f --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,87 @@ +# Getting Started + +Rebar3 is the standard build tool within the Erlang community. It essentially integrates many of the other tools shipping with Erlang along with a few open-source ones, and makes them all work under a unified project structure. + +## Installing Erlang + +Rebar3 relies on Erlang already being present in your system in order to run. If Erlang runs there, Rebar3 should run there as well. + +See the [Adopting Erlang](https://adoptingerlang.org/) section [Installing Erlang/OTP](https://adoptingerlang.org/docs/development/setup/#installing-erlang-otp) for detailed steps on how to install Erlang for Windows, MacOS, Linux and FreeBSD. + +## Installing from the Rebar3 escript + +[Download the latest stable release](https://s3.amazonaws.com/rebar3/rebar3) as an executable [escript](https://erlang.org/doc/man/escript.html). While the script version of Rebar3 is portable and usable from anywhere, it is advised not to keep it in your project's repository and to install it globally, for your entire system. Regardless of which recent Erlang version you have installed, Rebar3 should be fully compatible with it. + +One downside of the escript however is that it is a bit slower than a regular Erlang program. We recommend installing a fully compiled form of Rebar3, which Rebar3 itself can do for you: + +```shell +$ ./rebar3 local install +===> Extracting rebar3 libs to ~/.cache/rebar3/lib... +===> Writing rebar3 run script ~/.cache/rebar3/bin/rebar3... +===> Add to $PATH for use: export PATH=$PATH:~/.cache/rebar3/bin +``` + +Be sure to follow the instructions the command outputs and add the executable to your system's `$PATH`, such as by calling `export PATH=$PATH:~/.cache/rebar3/bin`. You can then delete the `rebar3` escript you used to run `local install`. + +When a new stable release of `rebar3` is available, you can simply run `rebar3 local upgrade` and the new version will be fetched and installed the same way: + +```shell +$ rebar3 local upgrade +===> Extracting rebar3 libs to ~/.cache/rebar3/lib... +===> Writing rebar3 run script ~/.cache/rebar3/bin/rebar3... +===> Add to $PATH for use: export PATH=$PATH:~/.cache/rebar3/bin +``` + +### Windows + +Windows users who want to use the code from PowerShell or `cmd.exe` (rather than a terminal emulator) must ensure that a `rebar3.cmd` file is added: + +```powershell +@echo off +setlocal +set rebarscript=%~f0 +escript.exe "%rebarscript:.cmd=%" %* +``` + +Then add the directory where the file has been saved to the system `PATH`. + +If you want to change the default path (`C:\Users\<user>`) you can set an environment variable for `REBAR_CACHE_DIR` pointing to a directory of your liking. + +## Installing from Source + +The `rebar3` project's repo is hosted on GitHub and comes with a `bootstrap` script for building from source. This form is likely to cause fewer issues for Windows users, since building from source will generate the wrapper scripts required to work well in both `cmd.exe` and PowerShell environments: + +```shell +$ git clone https://github.com/erlang/rebar3.git +$ cd rebar3 +$ ./bootstrap +``` + +This will compile a `rebar3` escript to the top level of the `rebar3` directory, which you can then install globally: + +```shell +$ ./rebar3 local install +``` + +Do note that if you are planning to work with multiple Erlang versions on the same machine, you will want to build Rebar3 with the oldest one of them. The three newest major Erlang releases are supported at any given time: if the newest version is OTP-24, building with versions as old as OTP-22 will be supported, and produce an executable that will work with those that follow. + +## Creating a New Project + +Rebar3 offers templates that will ensure your Erlang project fits into a regular OTP structure: + +```shell +$ rebar3 new umbrella myproj +===> Writing apps/myproj/src/myproj_app.erl +===> Writing apps/myproj/src/myproj_sup.erl +===> Writing apps/myproj/src/myproj.app.src +===> Writing rebar.config +===> Writing config/sys.config +===> Writing config/vm.args +===> Writing .gitignore +===> Writing LICENSE +===> Writing README.md +``` + +The OTP structure is part of the basic contract Rebar3 expects; following it will guarantee a much better time than doing otherwise. + +You can see [Basic Usage](basic_usage.md) to learn more on how to use `rebar3`, and follow it with [Workflow](workflow.md) for broader usage. diff --git a/docs/package_management/publishing-packages.md b/docs/package_management/publishing-packages.md new file mode 100644 index 000000000..d970a29e9 --- /dev/null +++ b/docs/package_management/publishing-packages.md @@ -0,0 +1,162 @@ +# Hex Package Management + +For package management `rebar3` uses [hex.pm](https://hex.pm), a package manager for Erlang and Elixir packages. + +## Basic usage + +You should read the [docs](https://hexdocs.pm/rebar3_hex/) for a complete guide for each provider, but below is a +brief overview of basic usage. + +### Registering a Hex user + +When registering a user, you will be prompted for a username, your email and a password. The email is used to confirm your identity during signup, as well as to contact you in case there is an issue with one of your packages. The email will never be shared with a third party. + +```nohighlight +$ rebar3 hex user register +Username: johndoe +Email: john.doe@example.com +Password: +Password (confirm): +Registering... +Generating API key... +You are required to confirm your email to access your account, a confirmation email has been sent to john.doe@example.com + +``` + +### Authenticating User + +If you already have a user for [hex.pm](https://hex.pm) run: + + +```shell +$ rebar3 hex user auth +``` + +Note that this will ask for your hex.pm username and password, as well as a password for encrypting your api token that +has write permissions to the repository. When publishing a package you will have to give this password to decrypt the +token in order to publish. + +See the [docs](https://hexdocs.pm/rebar3_hex/rebar3_hex_user.html) for more information. + +### Building + +The `build` provider is very useful for seeing exactly what would be published using either the `publish` or `cut` task +without any chance of actually publishing the package or docs. Tarballs for the package and docs are written to +`_build/<profile>/lib/your_app/hex/` by default. + + +``` +$ rebar3 hex build +``` + +See the [docs](https://hexdocs.pm/rebar3_hex/rebar3_hex_build.html) for more information. + +### Publishing + +Two providers are available for publishing packages, `publish` and `cut` + +By default `publish` builds and pushes your package and docs to a repository. See the +[docs](https://hexdocs.pm/rebar3_hex/rebar3_hex_publish.html) for more information. + +``` shell +$ rebar3 hex publish +``` + +`cut` is available to provide some additional functionality around versioning and git tags. See the +[docs](https://hexdocs.pm/hex/rebar3_hex_cut.html) for more information. + +``` shell +$ rebar3 hex cut +``` + +In either case, both providers will display the details of what is being published +(what files, the version, dependencies) and ask if it should continue, so be sure to read the +output carefully and make sure it is publishing what you expected. + +### Managing package owners + +Owners can be added, removed, and listed for packages you are an owner of with the `hex owner` command. Packages +can also be transfered to other registered users on hexpm as well. + +``` shell +$ rebar3 hex owner [add | remove | list | transfer] <package> <email> +``` + +See the [docs](https://hexdocs.pm/rebar3_hex/rebar3_hex_owner.html) for more information. + +### Retiring packages + +Packages can be flagged as retired on hexpm via the `retire` provider : + +``` +$ rebar3 hex retire PACKAGE VERSION REASON --message +``` + +They can also be unretired in case a mistake was made : + +``` +$ rebar3 hex retire PACKAGE VERSION --unretire +``` + +See the [docs](https://hexdocs.pm/rebar3_hex/rebar3_hex_retire.html) for more information. + +### Organizations + +rebar3_hex supports working with organizations via the `organization` provider. + +Simply add your organization to either your global rebar.config (i.e., `~/.config/rebar3/rebar.config` ) or a local +project rebar.config. + +```erlang +{hex, [{repos, [#{name => <<"hexpm:your_org">>}]}]}. +``` + +You can then authenticate with with the organization repository. Be sure you have already authenticated with the main +repository first: + +``` +$ rebar3 hex auth # make sure you're authenticated to the main repo first +$ rebar3 hex organization auth hexpm:your_org # authenticate to the org +``` + +Now you can generate, revoke, and list keys for your organizations. See below for an example of generating a key for use +in CI. + +See the [docs](https://hexdocs.pm/rebar3_hex/rebar3_hex_organization.html) for more information. + +#### Read-Only Repo Key for CI + +If you have a private organization or other private repository it is recommended that you use a repo specific +auth token for reading from the repository in CI. To generate a token: + +```shell +$ rebar3 hex organization auth hexpm:myrepo +Successfully authenticated to hexpm:myrepo +``` + +Now you can generate a key to use in CI for your organization + +``` +$ rebar3 hex organization key hexpm:myrepo generate +abc123 +``` + +Then in CI use whatever method is available for setting an environment variable to the token and add this call at the +beginning of your CI runs to add the token to your rebar3 hex config. Below we'll use the environment `REPO_KEY` as an +example. + +```shell +$ rebar3 hex organization auth hexpm:myrepo --key $REPO_KEY +``` + +### Searching hexpm + +A `search` provider is available to search packages across hex.pm as a convenience. + +``` +$ rebar3 hex search +``` + +## Further reading +See [Publishing packages](https://hex.pm/docs/rebar3-publish) on hexpm for more setup and usage instructions. See the +[docs](https://hexdocs.pm/rebar3_hex) for detailed documentation for all available providers. diff --git a/docs/testing/coverage.md b/docs/testing/coverage.md new file mode 100644 index 000000000..0328e9533 --- /dev/null +++ b/docs/testing/coverage.md @@ -0,0 +1,27 @@ +# Coverage + +Test runs from all of the built-in test tools generate cover data. Calling `rebar3 cover` at any later point generates a general code coverage report by merging all the individual reports: + +```shell +$ rebar3 ct --dir test/suites1 --cover --cover_export_name=suites1 +===> Running Common Test suites... +... +$ rebar3 ct --dir test/suites2 --cover --cover_export_name=suites2 +===> Running Common Test suites... +... +$ ls _build/test/cover +cover.log suite1.coverdata suite2.coverdata +$ rebar3 cover --verbose +===> Performing cover analysis... + |----------------------------|------------| + | module | coverage | + |----------------------------|------------| + | .... | Y% | + |----------------------------|------------| + | total | X% | + |----------------------------|------------| + coverage calculated from: + _build/test/cover/suites1.coverdata + _build/test/cover/suites2.coverdata + cover summary written to: _build/test/cover/index.html +``` diff --git a/docs/testing/ct.md b/docs/testing/ct.md new file mode 100644 index 000000000..28516ffa8 --- /dev/null +++ b/docs/testing/ct.md @@ -0,0 +1,29 @@ +# Common Test + +To run `common_test` suites: + +```shell +$ rebar3 ct +``` + +Rebar3 will look in all your applications' `test` directories and compile and run any source files named `*_SUITE.erl`. Unlike regular source directories, the compilation of test modules will **not** be recursive by default in order to avoid issues with files in [data directories](https://erlang.org/doc/apps/common_test/write_test_chapter.html#data-and-private-directories). This behaviour [can however be turned on manually with the right compilation options](configuration/configuration.md#rebar3-compiler-options). + +To run only specific test suites: + +```shell +$ rebar3 ct --suite=test/first_SUITE,test/second_SUITE +``` + +Rebar3 has a built in `common_test` runner that supports most test suites and `common_test` options. If your test suites require use of test specs or cover specs be aware Rebar3 keeps separate build artifacts for each profile so you may need to adjust paths to point to the modules and directories in the relevant profile directory under `_build` for them to work as expected. If you need to use an unsupported `common_test` option, the following command can be used to run `common_test` with the path to the compiled beam files Rebar3 generates: + +```shell +$ ct_run -pa `rebar3 path` ... +``` + +The `ct` command runs as the `test` profile, by default. See [Profiles](configuration/profiles.md) for details. + +For available options and their usage see [Commands](commands.md) or: + +```shell +$ rebar3 help ct +``` diff --git a/docs/testing/eunit.md b/docs/testing/eunit.md new file mode 100644 index 000000000..cfb5a4e7e --- /dev/null +++ b/docs/testing/eunit.md @@ -0,0 +1,134 @@ +# EUnit + +To run all EUnit test suites: + +```console +$ rebar3 eunit +``` + +Rebar3 will compile all project modules with the macros `{d, TEST, true}` and `{d, EUNIT, true}` defined so you can safely hide your test code within `-ifdef(TEST).` or `-ifdef(EUNIT).` sections. It will also automatically compile any source files in your application's `test` directory, if present. By default, Rebar3 runs tests by calling `eunit:test([{application, App}])` for each application in your project. + +The `eunit` command runs as the `test` profile, by default. See [Profiles](configuration/profiles.md) for details. + +For available options and their usage see [Commands](commands.md) or: + +```console +$ rebar3 help eunit +``` + +## Test Selection + +The following flags can be provided standalone or combined. + +### Apps + +To run tests for specific apps only: + +```console +$ rebar3 eunit --application=app1,app2 +``` + +The format is a comma separated list of application names. + +Alias: `--app`. + +### Modules + +To run tests for specific modules only: + +```console +$ rebar3 eunit --module=mod1,mod2,mod3 +``` + +The format is a comma separated list of module names. + +Alias: `--suite`. + +### Test Cases + +To run specific test cases only: + +```console +$ rebar3 eunit --test=mod1:test1+test2,mod2:test1 +``` + +The format is a [comma separated list of test functions](#test-function-format). + +### Generators + +To run specific test case generators only: + +```console +$ rebar3 eunit --generator=mod1:gen1+gen2,mod2:gen1 +``` + +The format is a [comma separated list of test functions](#test-function-format). + +### Files + +To run tests for specific files only: + +```console +$ rebar3 eunit --file="test/mod1.erl,test/mod2.erl" +``` + +The format is a comma separated list of file paths. + +### Directories + +To run tests for specific directories only: + +```console +$ rebar3 eunit --dir="test,extra_tests" +``` + +The format is a comma separated list of directory paths. + +## Test Function Format + +The format to select specific test functions is a comma separated list of `Module:Func` specifications. Multiple functions in the same module can be selected by separating them with a plus `+` sign, e.g. `Module:Func1+Func2` (alternatively they can be separated with a semicolon `;`). + +## Configuration Options + +The following configuration options can be set in `rebar.config`. + +### `eunit_tests` + +You can change the default tests `eunit:test/1` is called with when running `rebar3 eunit` (instead of the default which are all tests in all applications). + +The configuration must be a list with EUnit test representations, as documented [here](https://www.erlang.org/doc/apps/eunit/chapter.html#EUnit_test_representation). Rebar3 will do its best to ensure any modules specified in tests are compiled and made available on the code path. + +Examples: + +```erlang +{eunit_tests, [{module, smoke_tests}]}. +``` + +```erlang +{eunit_tests, [{inparallel, mod1}]}. +``` + +### `eunit_opts` + +The default EUnit options can be configured, as documented [here](https://www.erlang.org/doc/man/eunit.html#test-2). + +Interesting undocumented options are: + +* `no_tty` completely disables the default EUnit reporter output +* `{report, {Module, Args}}` runs a custom EUnit reporter (the functionality that prints results to the shell). The reporter module needs the following callbacks implemented: + + ```erlang + -export([start/0]). + -export([start/1]). + -export([init/1]). + -export([handle_begin/3]). + -export([handle_end/3]). + -export([handle_cancel/3]). + -export([terminate/2]). + ``` + +`no_tty` and `report` can be combined to replace the EUnit reporter with a custom one: + +```erlang +{eunit_opts, [no_tty, {report, {my_reporter, Opts}}]}. +``` diff --git a/docs/testing/introduction.md b/docs/testing/introduction.md new file mode 100644 index 000000000..66949c486 --- /dev/null +++ b/docs/testing/introduction.md @@ -0,0 +1,9 @@ +# Introduction + +> Running tests with Rebar3. + +Rebar3 has built-in `eunit` and `ct` (`common_test`) test runners. By following a few conventions you can run test suites with a single Rebar3 command. + +- [Common Test](docs/testing/ct.md) +- [EUnit](docs/testing/eunit.md) +- [Coverage](docs/testing/coverage.md) diff --git a/docs/tutorials/building_c_cpp.md b/docs/tutorials/building_c_cpp.md new file mode 100644 index 000000000..ed0299ade --- /dev/null +++ b/docs/tutorials/building_c_cpp.md @@ -0,0 +1,157 @@ +# Building C/C++ + +> #### No port compiler {: .warning} +> In Rebar3 it is required to have either a Makefile or other instructions for building your C/C++ code outside of Rebar3 itself. + +## Using the Makefile Template + +We'll start by making a new lib named `test_nif` and then using the `cmake` template from the root of the `test_nif` project. + +```shell +$ rebar3 new lib test_nif +===> Writing test_nif/src/test_nif.erl +===> Writing test_nif/src/test_nif.app.src +===> Writing test_nif/rebar.config +===> Writing test_nif/.gitignore +===> Writing test_nif/LICENSE +===> Writing test_nif/README.md +$ cd test_nif +$ rebar3 new cmake +===> Writing c_src/Makefile +``` + +In `test_nif`'s `rebar.config`, add the [pre_hooks](configuration/configuration.md#hooks) line so that `make` is called when `compile` is run. Furthermore, add the `post_hooks` entry for cleaning up the built C object files. + +The `Makefile` written by `rebar3 new cmake` is a GNU Makefile, which means you will need to have GNU Make installed on the system. In the example, we provide a handler for the FreeBSD operating system, which assumes GNU Make is called `gmake`. + +```erlang +{pre_hooks, + [{"(linux|darwin|solaris)", compile, "make -C c_src"}, + {"(freebsd)", compile, "gmake -C c_src"}]}. +{post_hooks, + [{"(linux|darwin|solaris)", clean, "make -C c_src clean"}, + {"(freebsd)", clean, "gmake -C c_src clean"}]}. +``` + +Below is a NIF which has a function `repeat` that will take a `pid` and an Erlang term to send to that `pid`. + +```c +#include "erl_nif.h" + +static ERL_NIF_TERM +mk_atom(ErlNifEnv* env, const char* atom) +{ + ERL_NIF_TERM ret; + + if(!enif_make_existing_atom(env, atom, &ret, ERL_NIF_LATIN1)) + { + return enif_make_atom(env, atom); + } + + return ret; +} + +static ERL_NIF_TERM +mk_error(ErlNifEnv* env, const char* mesg) +{ + return enif_make_tuple2(env, mk_atom(env, "error"), mk_atom(env, mesg)); +} + +static ERL_NIF_TERM +repeat(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifEnv* msg_env; + ErlNifPid pid; + ERL_NIF_TERM copy; + + if(argc != 2) + { + return enif_make_badarg(env); + } + + if(!enif_is_pid(env, argv[0])) + { + return mk_error(env, "not_a_pid"); + } + + if(!enif_get_local_pid(env, argv[0], &pid)) + { + return mk_error(env, "not_a_local_pid"); + } + + msg_env = enif_alloc_env(); + if(msg_env == NULL) + { + return mk_error(env, "environ_alloc_error"); + } + + copy = enif_make_copy(msg_env, argv[1]); + + if(!enif_send(env, &pid, msg_env, copy)) + { + enif_free(msg_env); + return mk_error(env, "error_sending_term"); + } + + enif_free_env(msg_env); + return mk_atom(env, "ok"); +} + +static ErlNifFunc nif_funcs[] = { + {"repeat", 2, repeat} +}; + +ERL_NIF_INIT(test_nif, nif_funcs, NULL, NULL, NULL, NULL); +``` + +Modify `test_nif.erl` to load the `test_nif` shared library from `priv` and export `repeat/2`. + +```erlang +-module(test_nif). +-export([repeat/2]). +-on_load(init/0). + +-define(APPNAME, test_nif). +-define(LIBNAME, test_nif). + +repeat(_, _) -> + not_loaded(?LINE). + +init() -> + SoName = case code:priv_dir(?APPNAME) of + {error, bad_name} -> + case filelib:is_dir(filename:join(["..", priv])) of + true -> + filename:join(["..", priv, ?LIBNAME]); + _ -> + filename:join([priv, ?LIBNAME]) + end; + Dir -> + filename:join(Dir, ?LIBNAME) + end, + erlang:load_nif(SoName, 0). + +not_loaded(Line) -> + erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}). +``` + +Note that the `error()` function will cause Dializer errors. Using [`erlang:nif_error/1`](https://erlang.org/doc/man/erlang.html#nif_error-1) will not, and is preferred here. + +Run `rebar3 shell` and give the NIF a try. + +```shell +$ rebar3 shell +===> Verifying dependencies... +===> Compiling test_nif +Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:0] [kernel-poll:false] + +Eshell V6.3 (abort with ^G) +1> test_nif:repeat(self(), hello). +ok +2> receive X -> X end. +hello +``` + +## References + +- [Erlang/OTP Interoperability Tutorial](https://www.erlang.org/doc/tutorial/introduction.html) diff --git a/docs/tutorials/building_plugins.md b/docs/tutorials/building_plugins.md new file mode 100644 index 000000000..8260c838c --- /dev/null +++ b/docs/tutorials/building_plugins.md @@ -0,0 +1,454 @@ +# Building Plugins + +Rebar3's system is based on the concept of *[providers](https://github.com/tsloughter/providers)*. A provider has three callbacks: + +- `init(State) -> {ok, NewState}`, which helps set up the state required, state dependencies, etc. +- `do(State) -> {ok, NewState} | {error, Error}`, which does the actual work. +- `format_error(Error) -> String`, which prints errors when they happen, and to filter out sensitive elements from the state. + +A provider should also be an OTP Library application, which can be fetched as any other Erlang dependency, except for Rebar3 rather than your own system or application. + +This document contains the following elements: + +- [Using a Plugin](#section-using-a-plugin) +- [Reference](#section-reference) + - [Provider Interface](#section-provider-interface) + - [List of Possible Dependencies](#section-list-of-possible-dependencies) + - [Rebar API](#section-rebar-api) + - [Rebar State Manipulation](#section-rebar-state-manipulation) + - [Namespaces](#section-namespaces) +- [Tutorial](#section-tutorial) + - [First Version](#section-first-version) + - [Optionally Search Deps](#section-optionally-search-deps) + +## Using a Plugin + +To use the a plugin, add it to the rebar.config: + +```erlang +{plugins, [ + {plugin_name, {git, "git@host:user/name-of-plugin.git", {tag, "1.0.0"}}} +]}. +``` + +Then you can just call it directly: + +```shell +$ rebar3 plugin_name +===> Fetching plugin_name +===> Compiling plugin_name +<PLUGIN OUTPUT> +``` + +## Reference + +### Provider Interface + +Each provider has the following options available: + +- *name*: The 'user friendly' name of the task. +- *module*: The module implementation of the task. +- *hooks*: A two-tuple of provider names for pre and post-hooks (`{Pre, Post}`). +- *bare*: Indicates whether task can be run by users or not. Should be `true`. +- *deps*: The list of dependencies, providers that need to run before this one. You do not need to include the dependencies of your dependencies. +- *desc*: The description for the task, used by `rebar3 help` +- *short_desc*: A one line short description of the task, used in lists of providers +- *example*: An example of the task usage, such as `"rebar3 my-provider args"` +- *opts*: The list of options that the task requires/understands. The form of each option is `{Key, $Character, "StringName", Spec, HelpText}`, where: + - `Key` is an atom, to be used to fetch the value later; + - `$Character` is the short form of the option. So if the command is to be entered as a `-c Arg`, `$c` is the value of this field + - `Spec` is either a type (`atom`, `binary`, `boolean`, `float`, `integer`, or `string`), a type with a default value (`{Type, Val}`), or the atom `undefined`. +- *profiles*: Profiles to use for provider. Default to `[default]`. +- *namespace*: namespace the provider is registered in. Defaults to `default`, which is the main namespace. + +These options are to be added to the provider when creating it. + +A provider has the following implementation: + +```erlang +-module(provider_template). +-behaviour(provider). + +-export([init/1, do/1, format_error/1]). + +%% =================================================================== +%% Public API +%% =================================================================== + +%% Called when rebar3 first boots, before even parsing the arguments +%% or commands to be run. Purely initiates the provider, and nothing +%% else should be done here. +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + Provider = providers:create([Options]), + {ok, rebar_state:add_provider(State, Provider)}. + +%% Run the code for the plugin. The command line argument are parsed +%% and dependencies have been run. +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + {ok, State}. + +%% When an exception is raised or a value returned as +%% `{error, {?MODULE, Reason}}` will see the `format_error(Reason)` +%% function called for them, so a string can be formatted explaining +%% the issue. +-spec format_error(any()) -> iolist(). +format_error(Reason) -> + io_lib:format("~p", [Reason]). +``` + +### List of Possible Dependencies + +All dependencies are in the default namespace until indicated otherwise + +|Name|Function|Profile|Also depends on| +|--- |--- |--- |--- | +|app_discovery|Explore user applications and loads their configuration.|default| | +|clean|Remove compiled beam files from apps.|default|app_discovery| +|compile|Compile apps .app.src and .erl files.|default|lock| +|cover|Analyze cover-compiled files|default|lock| +|ct|Run common test suites.|test|compile| +|deps|List dependencies.|default|app_discovery| +|dialyzer|Run the Dialyzer analyzer on the project.|default|compile| +|edoc|Generate documentation using edoc.|default|app_discovery| +|eunit|Run EUnit Tests.|test|compile| +|help|Display a list of tasks or help for a given task or subtask.|default| | +|install_deps|Download dependencies|default|app_discovery| +|lock|Lock dependencies and add rebar.lock|default|install_deps| +|new|Create new project from templates.|default| | +|pkgs|List available packages.|default| | +|release|Build release of project.|default|compile| +|report|Provide a crash report to be sent to the rebar3 issues page|default| | +|shell|Run shell with project apps and deps in path.|default|compile| +|tar|Tar archive of release built of project.|default|compile| +|update|Update package index.|default| | +|upgrade|Upgrade dependencies.|default| | +|version|Print version for rebar and current Erlang.|default| | +|xref|Run cross reference analysis|default|compile| + +Note that you can depend on more than one provider, but they *must be in the same namespace* + +### Rebar API + +Rebar comes with a module called `rebar_api` exporting commonly needed functions when writing providers. Functions include: + +|Function|Usage| +|--- |--- | +|abort()|Interrupts program flow| +|abort(FormatString, Args)|Interrupts program flow; displays an ERROR message along with it. Equivalent to calling rebar_api:error(FormatString, Args) followed by rebar_api:abort()| +|console(FormatString, Args)|Prints to the console.| +|info(FormatString, Args)|Logs with the severity INFO| +|warn(FormatString, Args)|Logs with the severity WARNING| +|error(FormatString, Args)|Logs with the severity ERROR| +|debug(FormatString, Args)|Logs with the severity DEBUG| +|expand_env_variable(InStr, VarName, RawVarValue)|Given the env variable FOO, we want to expand all references to it in InStr. References can have two forms: $FOO and ${FOO}. The form $FOO is delimited by whitespace characters or the end of a line (eol).| +|get_arch()|Returns the 'architecture' as a string of the form "$OTP_VSN-$SYSTEM_$ARCH-WORDSIZE. Final strings will look like "17-x86_64-apple-darwin13.4.0-8" or "17-x86_64-unknown-linux-gnu-8"| +|wordsize()|Returns the true wordsize of the emulator, i.e. the size of a pointer, in bytes as an string.| +|add_deps_to_path(RebarState)|The project's dependencies are added to the code path. Useful when a tool is invoked and needs to have global stateful access to libraries.| +|restore_code_path(RebarState)|Revert the code path to only include the libraries required to run Rebar3 and its plugins. This is the desired state for Rebar3 to avoid conflicts with user-provided tools.| +|ssl_opts(Url)|Returns the [ssl](https://hosting.review/web-hosting-glossary/#12) options to use with httpc to make a secure and verified HTTP request.| + +Do note that all logging functions automatically add a new line (`~n`) to every expression logged. + +### Rebar State Manipulation + +The `State` argument passed to the plugin provider can be operated on with the `rebar_state` module through the following interface: + +|Function|Usage| +|--- |--- | +|get(State, Key, [DefaultValue]) -> Value|When a rebar.config element is of the form {Key, Value}., fetches the value for it| +|set(State, Key, Value) -> *NewState*|Adds a configuration value to the rebar state.| +|lock(State) -> ListOfLocks|Returns a list of locked dependencies| +|escript_path(State) -> Path|Returns the Rebar3 escript location| +|command_args(State) -> RawArgs|Returns the arguments passed to rebar3| +|command_parsed_args(State) -> Args|Returns the arguments passed to rebar3, parsed.| +|deps_names(State) -> DepsNameList|Returns a list of dependencies' names| +|project_apps(State) -> AppList|Returns a list of applications. These can be handled using [rebar_app_info](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_app_info.erl).| +|all_deps(State) -> DepsList|Returns a list of dependencies. These can be handled using [rebar_app_info](https://github.com/erlang/rebar3/blob/main/apps/rebar/src/rebar_app_info.erl).| +|add_provider(State, Provider) -> NewState|Registers a new provider, where Provider is the result of calling providers:create(Options). To be effective, this function must be called as part of a provider's init/1 function. It can be called multiple times, allowing a plugin to register multiple commands.| +|add_resource(State, {Key, Module}) -> NewState|Registers a new resource type (such as git, hg, and so on) with the module used to handle it. The resource must implement the rebar_resource behaviour. To be effective, this function must be called as part of a provider's init/1 function.| + +## Manipulate Application State + +Each application being built (project applications and dependencies). All AppInfo records can be found in the State and accessed through `project_apps/1` and `all_deps/1` + +|Function|Usage| +|--- |--- | +|get(AppInfo, Key, [DefaultValue]) -> Value|Fetch value of Key as defined for the application AppInfo| +|set(AppInfo, Key, Value) -> *NewState*|Adds a configuration value to the application's record| + +### Namespaces + +For plugins that might require multiple commands all adapted to a single type of task (such as implementing a suite of tools for a BEAM language other than Erlang), rather than having multiple commands polluting the command space or requiring prefixes such as `rebar3 mylang_compile`, rebar3 introduces support for namespaces. + +A plugin can be declared to belong to a given namespace. For example, the [ErlyDTL compiler plugin](https://github.com/tsloughter/rebar3_erlydtl_plugin) introduces the `compile` command under the `erlydtl` namespace. It can therefore be invoked as `rebar3 erlydtl compile`. If the `erlydtl` namespace had other commands such as `clean`, they could be chained as `rebar3 erlydtl clean, compile`. + +In other ways, a namespace acts like `do` (`rebar3 do compile, edoc`), but operating on a non-default set of commands. + +To declare a namespace, an provider needs only to use the `{namespace, Namespace}` option in its configuration list. The provider will automatically register the new namespace and be available under this term. + +> #### Namespaces also apply to provider dependencies and hooks {: .warning} +> If a provider is part of a given namespace, its dependencies will be searched within that same namespace. Therefore if `rebar3 mytool rebuild` depends on `compile`, the `compile` command will be looked for in the `mytool` namespace. +> +> To use the default `compile` command, the dependency must be declared as `{default, compile}`, or more generally `{NameSpace, Command}`. +> +> The same mechanism is applied for hooks. + +## Tutorial + +### First version + +In this tutorial, we'll show how to start from scratch, and get a basic plugin written. The plugin will be quite simple: it will look for instances of `TODO:` lines in comments and report them as warnings. The final code for the plugin can be found on [bitbucket](https://bitbucket.org/ferd/rebar3-todo-plugin). + +The first step is to create a new OTP Application that will contain the plugin: + +```shell +→ rebar3 new plugin todo desc="example rebar3 plugin" +... +→ cd todo +→ git init +Initialized empty Git repository in /Users/ferd/code/self/todo/.git/ +``` + +The `src/todo.erl` file will be used to call the initialization of all commands. For now we'll only have one `todo` command. Open up the `src/todo_prv.erl` file that will contain the command implementation, and make sure you have the following skeleton in place: + +```erlang +-module(todo_prv). +-behaviour(provider). + +-export([init/1, do/1, format_error/1]). + +-define(PROVIDER, todo). +-define(DEPS, [app_discovery]). + +%% =================================================================== +%% Public API +%% =================================================================== +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + Provider = providers:create([ + {name, ?PROVIDER}, % The 'user friendly' name of the task + {module, ?MODULE}, % The module implementation of the task + {bare, true}, % The task can be run by the user, always true + {deps, ?DEPS}, % The list of dependencies + {example, "rebar provider_todo"}, % How to use the plugin + {opts, []} % list of options understood by the plugin + {short_desc, "example rebar3 plugin"}, + {desc, ""} + ]), + {ok, rebar_state:add_provider(State, Provider)}. + + +-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}. +do(State) -> + {ok, State}. + +-spec format_error(any()) -> iolist(). +format_error(Reason) -> + io_lib:format("~p", [Reason]). +``` + +This shows all the basic content needed. Note that we leave the `DEPS` macro to the value `app_discovery`, used to mean that the plugin should at least find the project's source code (excluding dependencies). + +In this case, we need to change very little in `init/1`. Here's the new provider description: + +```erlang +Provider = providers:create([ + {name, ?PROVIDER}, % The 'user friendly' name of the task + {module, ?MODULE}, % The module implementation of the task + {bare, true}, % The task can be run by the user, always true + {deps, ?DEPS}, % The list of dependencies + {example, "rebar todo"}, % How to use the plugin + {opts, []}, % list of options understood by the plugin + {short_desc, "Reports TODOs in source code"}, + {desc, "Scans top-level application source and find " + "instances of TODO: in commented out content " + "to report it to the user."} + ]), +``` + +Instead, most of the work will need to be done directly in `do/1`. We'll use the `rebar_state` module to fetch all the applications we need. This can be done by calling the `project_apps/1` function, which returns the list of the project's top-level applications. + +```erlang +do(State) -> + lists:foreach(fun check_todo_app/1, rebar_state:project_apps(State)), + {ok, State}. +``` + +This, on a high level, means that we'll check each top-level app one at a time (there may often be more than one top-level application when working with releases) + +The rest is filler code specific to the plugin, in charge of reading each app path, go read code in there, and find instances of 'TODO:' in comments in the code: + +```erlang +check_todo_app(App) -> + Paths = rebar_dir:src_dirs(rebar_app_info:opts(App)), + Mods = find_source_files(Paths), + case lists:foldl(fun check_todo_mod/2, [], Mods) of + [] -> ok; + Instances -> display_todos(rebar_app_info:name(App), Instances) + end. +find_source_files(Paths) -> + find_source_files(Paths, []). + +find_source_files([], Files) -> + Files; +find_source_files([Path | Rest], Files) -> + find_source_files(Rest, [filename:join(Path, Mod) || Mod <- filelib:wildcard("*.erl", Path)] ++ Files). + +check_todo_mod(ModPath, Matches) -> + {ok, Bin} = file:read_file(ModPath), + case find_todo_lines(Bin) of + [] -> Matches; + Lines -> [{ModPath, Lines} | Matches] + end. + +find_todo_lines(File) -> + case re:run(File, "%+.*(TODO:.*)", [{capture, all_but_first, binary}, global, caseless]) of + {match, DeepBins} -> lists:flatten(DeepBins); + nomatch -> [] + end. + +display_todos(_, []) -> ok; +display_todos(App, FileMatches) -> + io:format("Application ~s~n",[App]), + [begin + io:format("\t~s~n",[Mod]), + [io:format("\t ~s~n",[TODO]) || TODO <- TODOs] + end || {Mod, TODOs} <- FileMatches], + ok. +``` + +Just using `io:format/2` to output is going to be fine. + +To test the plugin, push it to a source repository somewhere. Pick one of your projects, and add something to the `rebar.config`: + +```erlang +{plugins, [ + {todo, {git, "git@bitbucket.org:ferd/rebar3-todo-plugin.git", {branch, "master"}}} +]}. +``` + +Then you can just call it directly: + +```shell + +→ rebar3 todo + +===> Fetching todo + +===> Compiling todo + +Application merklet + + /Users/ferd/code/self/merklet/src/merklet.erl + + todo: consider endianness for absolute portability +``` + +Rebar3 will download and install the plugin, and figure out when to run it. Once compiled, it can be run at any time again. + +### Optionally Search Deps + +Let's extend things a bit. Maybe from time to time (when cutting a release), we'd like to make sure none of our dependencies contain 'TODO:'s either. + +To do this, we'll need to go parse command line arguments a bit, and change our execution model. The `?DEPS` macro will now need to specify that the `todo` provider can only run *after* dependencies have been installed: + +```erlang +-define(DEPS, [install_deps]). +``` + +We can add the option to the list we use to configure the provider in `init/1`: + +```erlang +{opts, [ % list of options understood by the plugin + {deps, $d, "deps", undefined, "also run against dependencies"} +]}, +``` + +And then we can implement the switch to figure out what to search: + +```erlang +do(State) -> + Apps = case discovery_type(State) of + project -> rebar_state:project_apps(State); + deps -> rebar_state:project_apps(State) ++ lists:usort(rebar_state:all_deps(State)) + end, + lists:foreach(fun check_todo_app/1, Apps), + {ok, State}. + +[...] + +discovery_type(State) -> + {Args, _} = rebar_state:command_parsed_args(State), + case proplists:get_value(deps, Args) of + undefined -> project; + _ -> deps + end. +``` + +The `deps` option is found using `rebar_state:command_parsed_args(State)`, which will return a proplist of terms on the command-line after 'todo', and will take care of validating whether the flags are accepted or not. The rest can remain the same. + +Push the new code for the plugin, and try it again on a project with dependencies: + +```shell + +===> Fetching todo + +===> Compiling todo + +===> Fetching bootstrap + +===> Fetching file_monitor + +===> Fetching recon + +[...] + +Application dirmon + + /Users/ferd/code/self/figsync/apps/dirmon/src/dirmon_tracker.erl + + TODO: Peeranha should expose the UUID from a node. + +Application meck + + /Users/ferd/code/self/figsync/_deps/meck/src/meck_proc.erl + + TODO: What to do here? + + TODO: What to do here? +``` + +Rebar3 will now go pick dependencies before running the plugin on there. + +you can also see that the help will be completed for you: + +```shell +→ rebar3 help todo + +Scans top-level application source and find instances of TODO: in commented out content to report it to the user. + +Usage: rebar todo [-d] +``` + +That's it, the todo plugin is now complete! It's ready to ship and be included in other repositories. + +### Adding More Commands + +To add more commands to the same plugin, simply add entries to the `init` function in the main module: + +```erlang +-module(todo). + +-export([init/1]). + +-spec init(rebar_state:t()) -> {ok, rebar_state:t()}. +init(State) -> + %% initialize all commands here + {ok, State1} = todo_prv:init(State), + {ok, State2} = todo_other_prv:init(State1), + {ok, State2}. +``` + +And Rebar3 will pick it up from there. diff --git a/docs/tutorials/from_rebar2_to_rebar3.md b/docs/tutorials/from_rebar2_to_rebar3.md new file mode 100644 index 000000000..f59ec97d1 --- /dev/null +++ b/docs/tutorials/from_rebar2_to_rebar3.md @@ -0,0 +1,103 @@ +# From Rebar 2.x to Rebar3 + +Rebar3 changes quite a few things from rebar 2.x. By and far, Rebar3 attempts to keep full compatibility when handling OTP applications written in pure Erlang. People who built or wrote standard OTP apps will therefore see very few incompatibilities, although the ground still needs to be prepared. + +Major changes include (but are not limited to) moving all build artifacts to `_build`, and changing the way dependencies are fetched. + +## Pure Erlang, Standard OTP Applications + +The first step to converting your application is to remove old directories of artifacts: + +- Remove the `ebin/` directory. Rebar3 will read and copy `ebin/` directories that exist to its own `_build/` subdirectory, so that `.app` and `.beam` files generated by other tools remain usable. If you used rebar 2.x, `ebin/` is where it'd put its artifacts, and those will conflict with Rebar3. +- Remove the `_rel/` directory, if you used `relx`. Relx is now integrated in Rebar3 and will store its artifacts in `_build`. +- Remove the `.rebar` directory. It is no longer used. +- Remove the `deps/` directory; dependencies now go in `_build` and this can prevent conflicts. +- Remove these entries from `.gitignore`, `.hgignore`, or whatever. + +Once these directories are cleaned, the `rebar.config` configuration file can be stripped a bit: + +- remove `sub_dirs` and `lib_dirs` entries, they likely aren't necessary anymore; rebar3 automatically recognizes `src/`, `apps/*` and `lib/*` directories holding Erlang source files and OTP applications. + +You should then review your `.app.src` files to make sure that the following is respected: + +- applications you depend on are listed in the `applications` tuple +- no circular dependencies +- the following fields are mentioned (to work with releases!): `description`, `vsn`, `registered`, `applications`, `env` + +## Required Directory Structure + +Rebar3 explicitly handles releases and OTP applications only. Dependencies should only be OTP applications, one per entry. + +Make sure you have one of the following directory structures: + +```plain +src/*.{erl,app.src} +``` + +Which is a single-directory, single app structure. It is suitable for OTP applications, OTP releases, and escripts with a single top-level application. The `src` directory is searched recursively and the files are handles as if they were all at the top level. + +The other form is by using an 'umbrella' structure: + +```plain +apps/app1/src/*.{erl,app.src} +apps/app2/src/*.{erl,app.src} +apps/app3/src/*.{erl,app.src} +``` + +or + +```plain +lib/app1/src/*.{erl,app.src} +lib/app2/src/*.{erl,app.src} +lib/app3/src/*.{erl,app.src} +``` + +That format will hold many OTP applications at once and be amenable only to releases and escripts, not OTP libraries that can be used as dependencies. + +## Dependency Handling + +Rebar3 now supports Hex packages and profiles. As such, consider: + +- moving your dependencies to packages, see [Dependencies](configuration/dependencies.md), and [Publishing Packages](package_management/publishing-packages.md) +- moving your dependencies like `meck` and `PropEr` to the `test` [profile](configuration/profiles.md) to get them out of your general build. It's likely your deps still include it so it may remain in the default builds too, sadly. +- you no longer need to tell Rebar3 to fetch deps, it just knows whenever you tell it to compile or run tests. + +Also note that Rebar3 no longer re-compiles dependencies once it has done so before; use [`_checkout` dependencies](configuration/dependencies.md#checkout-dependencies) if you want that behaviour back. + +Rebar3 also no longer checks or enforces dependency versions, and instead uses a 'nearest to the root' dependency selection algorithm in case of conflicts. The details are in [Dependencies](configuration/dependencies.md). + +With this said and with your project ready, any Rebar3 guides in the documentation should be understandable and applicable. + +## Other Gotchas and Compilers + +By default, Rebar3 sticks to the compilers available to `erlc`: Erlang, yecc, MIBs, and so on. If you have: + +- **C code** you're going to need to [move things to `Makefile`s](tutorials/building_c_cpp.md) or use the [port compiler plugin](configuration/plugins.md#port-compiler) (backwards compatible with rebar 2.x) +- if you used QuickCheck or PropEr, you have to [use the plugin for that](configuration/plugins.md#recommended-plugins) +- [**diameter**](configuration/plugins.md#diameter) has its own plugin +- [**erlydtl**](configuration/plugins.md#erlydtl) has its own plugin +- you will have problems building some libraries with weird build tool interactions, specifically `edown` and similar libraries. In case of problems with these, heading to the #rebar channel on IRC will have community members point you to the easiest workaround. +- **reltool** releases are no longer supported, and instead, Relx is used and documented in [Releases](deployment/releases.md) + +## Others + +- if you are still using `Makefile`s to create shortcut commands, consider using [aliases](configuration/plugins.md#alias) +- for code coverage, you will want to use the 'cover' command, as in 'rebar3 do eunit, cover'. See the [cover](commands.md#cover) documentation for more details. + +## Maintaining backwards compatibility while using Hex packages + +If you want to use Rebar3 config and options most of the time and provide backwards compatibility to Rebar 2 users, add something similar to following contents in [`rebar.config.script`](configuration/config_script.md), which will let older Rebar versions dynamically ditch Hex packages and give them the opportunity to include material that is now part of `profiles` in Rebar3: + +```erlang +case erlang:function_exported(rebar3, main, 1) of + true -> % rebar3 + CONFIG; + false -> % rebar 2.x or older + %% Rebuild deps, possibly including those that have been moved to + %% profiles + [{deps, [ + {my_dep, "VSN", {git, "https://...", {tag, "VSN"}}}, + ... + ]} | lists:keydelete(deps, 1, CONFIG)] +end. +``` diff --git a/docs/tutorials/templates.md b/docs/tutorials/templates.md new file mode 100644 index 000000000..4e44c90b0 --- /dev/null +++ b/docs/tutorials/templates.md @@ -0,0 +1,208 @@ +# Templates + +- [Default Variables](#section-default-variables) +- [Global Variables](#section-global-variables) +- [Batteries-Included Templates](#section-batteries-included-templates) +- [Custom Templates](#section-custom-templates) +- [Plugin Templates](#section-plugin-templates) + +## Default Variables + +- `date`: defaults to today's date, under universal time, printed according to ISO 8601 (for example, `"2014-03-11"`) +- `datetime`: defaults to today's date and time, under universal time, printed according to ISO 8601 (for example, `"2014-03-11T16:06:02+00:00"`). +- `author_name`: Defaults to `"Anonymous"` +- `author_email`: Defaults to `"anonymous@example.org"` +- `apps_dir`: Directory where OTP applications should be created in release projects. Defaults to `"apps/"`. +- `copyright_year`: Defaults to the current year, under universal time. + +## Global Variables + +Global variables can be set by editing the file at `$HOME/.config/rebar3/templates/globals`: + +```erlang +{variables, [ + {author_name, "My Name Is A String"}, + {copyright_year, "2014-2022", "The year or range of years for copyright"}, + {my_custom_var, "hello there"} +]}. +``` + +This will let you define variables for all templates. Variables left undefined will be ignored and revert to the default value. + +The override order for these variables will be: `Defaults < $HOME/.config/rebar3/templates/globals < command line invocation`. + +## Batteries-Included Templates + +Rebar3 ships with a few templates installed, which can be listed by calling `rebar3 new`: + +```shell +$ ./rebar3 new +app (built-in): Complete OTP Application structure. +cmake (built-in): Standalone Makefile for building C/C++ in c_src +escript (built-in): Complete escriptized application structure +lib (built-in): Complete OTP Library application (no processes) structure +plugin (built-in): Rebar3 plugin project structure +release (built-in): OTP Release structure for executable programs +``` + +Any custom plugins would be followed as `<plugin_name> (custom): <description>`. + +Details for each individual plugin can be obtained by calling `rebar3 new help <plugin>`: + +```shell +$ ./rebar3 new help plugin +plugin: + built-in template + Description: Rebar3 plugin + Variables: + name="myplugin" (Name of the plugin) + desc="A rebar plugin" (Short description of the plugin's purpose) + date="2014-11-10" + datetime="2014-11-10T18:29:41+00:00" + author_name="Anonymous" + author_email="anonymous@example.org" + copyright_year="2014" + apps_dir="apps/" (Directory where applications will be created if needed) +``` + +All the variables there have their default values shown, and an optional explanation in parentheses. The variables can also be [overriden globally](#global-variables). + +A template can be run by calling: + +```shell +$ ./rebar3 new plugin name=demo author_name="Fred H." +... +$ ./rebar3 new plugin demo author_name="Fred H." +... +``` + +Then go to the directory created for the project by rebar3. + +## Custom Templates + +Custom templates can be added in `$HOME/.config/rebar3/templates/`. Each template is at least two files: + +- `my_template.erl`: There can be many of these files. They are regular Erlang files using the mustache template syntax for variable replacements (provided by [soranoba's implementation](https://github.com/soranoba/mustache)). +- `my_template.template`; Called the *template index*, there is one per template callable from `rebar3`. This one will be visible when calling `rebar3 new my_template`. This file regroups the different mustache template files into a more cohesive template. + +### File Syntax + +#### Template Index + +The following options are available: + +```erlang +{description, "This template does a thing"}. +{variables, [ + {var1, "default value"}, + {var2, "default", "explain what this does in help files"}, + {app_dir, ".", "The directory where the application goes"} + ]}. +{dir, "{{appdir}}/src"}. +{file, "mytemplate_README", "README"}. +{chmod, "README", 8#644}. +{template, "myapp/myapp.app.src", "{{appdir}}/src/{{name}}.app.src"}. +``` + +Specifically: + +- `description`: takes a string explaining what the template is for. +- `variables`: takes a list of variables in two forms: + - `{Name, DefaultString, HelpString}`; + - `{Name, DefaultString}`. +- `{dir, TemplatablePathString}`: creates a given directory. Variable names can be used in the path name. +- `{file, FilePath, DestFilePath}`: copies a file literally to its destination. +- `{template, FilePath, TemplatablePathString}`: evaluates a given template. The `FilePath` is relative to the template index. +- `{chmod, FilePath, Int}`: changes the permission of a file, using the integer value specified. Octal values can be entered by doing `8#640`. + +### Example + +As an example, we'll create a template for Common Test test suites. Create the directory structure `~/.config/rebar3/templates/` and then go in there. + +We'll start with an index for our template, called `ct_suite.template`: + +```erlang +{description, "A basic Common Test suite for an OTP application"}. +{variables, [ + {name, "suite", "Name of the suite, prepended to the standard _SUITE suffix"} +]}. + +{dir, "test"}. +{template, "ct_suite.erl", "test/{{name}}_SUITE.erl"}. +``` + +This tells Rebar3 to create the test directory and to evaluate a [mustache](https://github.com/soranoba/mustache) template. All the paths are relative to the current working directory. + +Let's create the template file: + +```erlang +-module({{name}}_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). % Eunit macros for convenience + +-export([all/0 + ,groups/0 + %,init_per_suite/1, end_per_suite/1 + %,init_per_group/2, end_per_group/2 + ,init_per_testcase/2, end_per_testcase/2 + ]). + +-export([fail/1]). + +all() -> [fail]. + +groups() -> []. + +init_per_testcase(_Name, Config) -> Config. + +end_per_testcase(_Name, _Config) -> ok. + +fail(_Config) -> + ?assert(false). +``` + +This one does very simple variable substitution for the name (using `{{name}}`) and that's all it needs. + +Let's get to any existing project you have and try it: + +```shell +$ ./rebar3 new +app (built-in): OTP Application +ct_suite (custom): A basic Common Test suite for an OTP application +lib (built-in): OTP Library application (no processes) +release (built-in): OTP Release structure for executable programs +plugin (built-in): Rebar3 plugin +``` + +The first line shows that our `ct_suite` template has been detected and is usable. + +Let's look at the details: + +```shell +$ ./rebar3 new help ct_suite +ct_suite: + custom template (/home/ferd/.config/rebar3/templates/ct_suite.template) + Description: A basic Common Test suite for an OTP application + Variables: + name="suite" (Name of the suite, prepended to the standard _SUITE suffix) + date="2014-11-10" + datetime="2014-11-10T18:46:33+00:00" + author_name="Anonymous" + author_email="anonymous@example.org" + copyright_year="2014" + apps_dir="apps/" (Directory where applications will be created if needed) +``` + +The documentation from variables and the description are well in place. To apply the template, go to any of your OTP application's top-level directory: + +```shell +$ ./rebar3 new ct_suite demo +===> Writing test/demo_SUITE.erl +``` + +And you will see the code in place. + +## Plugin Templates + +Plugins can be shipped with their own templates that then get listed along with the rest of templates. The structure is exactly similar to those found in `~/.config/rebar3/templates/`, except they must be placed in the plugin's `priv/` directory. diff --git a/docs/tutorials/using_breakpoints_to_debug_tests.md b/docs/tutorials/using_breakpoints_to_debug_tests.md new file mode 100644 index 000000000..b4074c2ac --- /dev/null +++ b/docs/tutorials/using_breakpoints_to_debug_tests.md @@ -0,0 +1,277 @@ +# Using Breakpoints to Debug Tests + +## The Problem + +When debugging Erlang applications, it is frequent that additional output is required to understand what is going on. + +Standard ways to do this include: + +- adding print statement debugging with `io:format/2-3` (or with `ct:pal/2` in common test) +- turning on `sys` module tracing with OTP processes to show more outputs +- trying to attach a [debugger](https://erlang.org/doc/apps/debugger/debugger_chapter.html) + +The problem with a debugger is that it can be really difficult to properly observe what goes on in a running system with timers involved; similarly, it is difficult to use any fancier tools such as tracing at more granular level than OTP interactions when you do not have any access to interactive sessions, nor do you have any way to synchronize yourself with test framework execution to attach in the right areas. + +In this document, we'll see two possible patterns that can be enabled with the new breakpoints feature introduced in version 3.7.0: breakpoints to enable trace probes, and breakpoints to go poke at a critical section in some code. + +> #### Breakpoints are useful for many types of testing {: .tip} +> This page shows breakpoints used with Common Test, but they work with any provider, including plugins for QuickCheck or PropEr, out of the box. +> +> If you are a plugin developer, you should also be able to use these breakpoints. They will only trigger once safely executing asynchronous tasks from a shell and will be ignored > otherwise. +> +> This should prevent any problems where the plugin needs to run before the shell itself starts, or where a user might accidentally hang a build. + +## The Base Mechanism + +The breakpoint feature requires the following steps: + +- the tests are run from an interactive shell with `rebar3 shell`, and using an asynchronous mode. This means that rather than calling `r3:ct()` for Common Test or `r3:eunit()` for EUnit tests (or their longer form `r3:do(Command)`), you need to call `r3:async_do(ct)` or `r3:async_do(eunit)`. +- You must call `r3:break()` from the test you want to execute. This will set a break point that will dynamically pause the code by awaiting for a secret message. The rest of the system will _not_ be paused, and test timeouts enabled by various frameworks will remain active. +- You will have the shell available to you to do anything; a confirmation message is displayed to let you know you are in a paused state +- Once you're done investigating, you can resume execution by calling `r3:resume()`. + +Your session might look like: + +```shell +$ rebar3 shell +... +1> r3:async_do(ct). +ok +... +Running Common Test suites... +%%% rebar_alias_SUITE: . +=== BREAK === + +2> % <do some checks> +2> r3:resume(). +ok +3> ..... +%%% rebar_as_SUITE: ........... +%%% rebar_compile_SUITE: ...... +... +``` + +Do note that other debuggers already exist. You can use them with the asynchronous tasks if you want more features. See <https://github.com/hachreak/cedb> for a good debugger example. + +## Break to Trace + +In a pattern where you break-to-trace, you may want to make use of a tracing tool like `dbg`, `redbug`, or `recon`. We'll use the latter for this section. + +First, let's start with a dummy project: + +```shell +$ rebar3 new app break_check +===> Writing break_check/src/break_check_app.erl +===> Writing break_check/src/break_check_sup.erl +===> Writing break_check/src/break_check.app.src +===> Writing break_check/rebar.config +===> Writing break_check/.gitignore +===> Writing break_check/LICENSE +===> Writing break_check/README.md +$ cd break_check +``` + +Open the `rebar.config` file and make sure it looks like this: + +```erlang +{deps, [recon]}. + +{profiles, [ + {test, [{erl_opts, [nowarn_export_all]}]} +]}. + +{shell, [ + % {config, "config/sys.config"}, + {apps, [break_check]} +]}. +``` + +You can then add the following test suite and save it under the name `test/start_SUITE.erl`: + +```erlang +-module(start_SUITE). +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). +-compile(export_all). + +all() -> [start]. + +start(_Config) -> + ?assertEqual(ok, application:start(break_check)), + Props = supervisor:count_children(break_check_sup), + ?assertEqual(1, proplists:get_value(workers, Props)), + ok. +``` + +If you run the tests, you'll see a failure such as: + +```shell +$ rebar3 ct +===> Verifying dependencies... +===> Compiling break_check +===> Running Common Test suites... +%%% start_SUITE: +%%% start_SUITE ==> start: FAILED +%%% start_SUITE ==> +Failure/Error: ?assertEqual(1, proplists : get_value ( workers , Props )) + expected: 1 + got: 0 + line: 11 +``` + +So clearly something broke since fewer workers are seen than expected. + +To figure out what happens at this point, looking at the code is sufficient, but let's pretend we have no idea why no children exist. + +We'll use the breakpoints to let us set up tracing. Change the test to look like this: + +```erlang +-module(start_SUITE). +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). +-compile(export_all). + +all() -> [start]. + +start(_Config) -> + r3:break(), % <===== this is the new line + ?assertEqual(ok, application:start(break_check)), + Props = supervisor:count_children(break_check_sup), + ?assertEqual(1, proplists:get_value(workers, Props)), + ok. +``` + +```shell +$ rebar3 shell --start-clean +... +1> r3:async_do(ct). +===> This feature is experimental and may be modified or removed at any time. +ok +2> Verifying dependencies... +Compiling break_check +Running Common Test suites... +%%% start_SUITE: +=== BREAK === +``` + +At this point, we have a shell, and the test is paused. We can set up our own trace probes: + +```plain +%% Set up a trace for all functions in the supervisor, returning their result +2> recon_trace:calls({break_check_sup, '_', fun(_) -> return_trace() end}, 10). +0 +%% 0 functions matching on a wildcard means the module is likely not loaded, +%% so let's do that +3> l(break_check_sup). +{module,break_check_sup} +%% Try setting the trace call again +4> recon_trace:calls({break_check_sup, '_', fun(_) -> return_trace() end}, 10). +4 % <-- and now we have a match +``` + +From this point on, all we have to do is resume the breakpoint and see the traces take place: + +```plain +5> r3:resume(). +ok + +13:34:51.207925 <0.249.0> break_check_sup:start_link() + +13:34:51.208075 <0.250.0> break_check_sup:init([]) + +13:34:51.208197 <0.250.0> break_check_sup:init/1 --> {ok, + {{one_for_all,0,1},[]}} + +13:34:51.208350 <0.249.0> break_check_sup:start_link/0 --> {ok,<0.250.0>} +7> +%%% start_SUITE ==> start: FAILED +%%% start_SUITE ==> +Failure/Error: ?assertEqual(1, proplists : get_value ( workers , Props )) + expected: 1 + got: 0 + line: 12 +``` + +We still get the same failure, but now we can clearly see that the problem is that the `init/1` function does not return any single child. It is therefore not surprising that no workers can be found in the supervisor. + +The essence of breaking to trace is that you will want to stall the test early on; you know what information you need, you just want a way to get it. You do your little observation set up (you could not only trace, but also change logging levels), and then get your data before leaving. + +## Break to Poke + +This pattern is similar to the previous one, but we'll instead want to interact with the system, poke at it, and possibly change some values to see how things work. + +For this section, we'll reuse the same set up as for the previous one, but we'll change the breakpoint's location and the test a bit: + +```erlang +-include_lib("common_test/include/ct.hrl"). +-include_lib("stdlib/include/assert.hrl"). +-compile(export_all). + +all() -> [start]. + +start(_Config) -> + ?assertEqual(ok, application:start(break_check)), + Props = supervisor:count_children(break_check_sup), + case proplists:get_value(workers, Props) of + 0 -> r3:break(); + _ -> ignore + end, + ?assertEqual(1, proplists:get_value(workers, Props)), + ok. +``` + +In this version, we not only set the breakpoint after checking for the children, we also only trigger it when a result is unexpected. This can be useful when you have some tests that do not always fail, only sometimes. Since breakpoints are normal function calls, you can even leave them in place with instructions to start debugging at this point. + +Let's run the test to see it stall on our breakpoint: + +```shell +$ rebar3 shell --start-clean +... +1> r3:async_do(ct). +===> This feature is experimental and may be modified or removed at any time. +ok +2> Verifying dependencies... +Compiling break_check +Running Common Test suites... +%%% start_SUITE: +=== BREAK === +``` + +Now we can look through the system. The application is started, the supervisor is running, and we can manipulate things, such as starting a fake child to see if that would fix the test: + +```plain +%% Poke at the supervisor's state and see it has no children +2> sys:get_state(break_check_sup). +{state,{local,break_check_sup}, + one_for_all, + {[],#{}}, + undefined,0,1,[],0,break_check_sup,[]} + +%% Add a child by hand +3> supervisor:start_child( +3> break_check_sup, +3> #{id => some_child, +3> start => {gen_event, start_link, []}, +3> type => worker} +3> ). +{ok,<0.232.0>} + +%% Check that it is actually tracked +4> sys:get_state(break_check_sup). +{state,{local,break_check_sup}, + one_for_all, + {[some_child], + #{some_child => + {child,<0.232.0>,some_child, + {gen_event,start_link,[]}, + permanent,5000,worker, + [gen_event]}}}, + undefined,0,1,[],0,break_check_sup,[]} + +%% and keep going to see the test pass +5> r3:resume(). +ok +All 1 tests passed. +``` + +It would be a good idea to remove all of your breakpoints after you're done with them, but it's interesting to know you can use features such as Common Test's [repeated executions with groups](https://erlang.org/doc/apps/common_test/write_test_chapter.html#test-case-groups) or randomized runs in order to detect weird conditions and automatically trigger a break point when required. diff --git a/docs/workflow.md b/docs/workflow.md new file mode 100644 index 000000000..2fb8479f2 --- /dev/null +++ b/docs/workflow.md @@ -0,0 +1,124 @@ +# Workflow + +> Recommended steps and possible default configurations for various tasks. + +If you know the basic commands, have gone through [Getting Started](getting-started.md), [Basic Usage](basic_usage.md), and have a brief understanding of [Releases](deployment/releases.md), the next step is possibly to figure out a workflow for your project and your team. + +This section is a work in progress of various recommended steps and possible default configurations for various tasks in order to have a good experience with the Erlang toolchain. + +## Pick the Right Type of Project + +|Type of Project|Recommended Template|Comments| +|----|----|----| +|A short script or util|escript|The user you distribute this to will need to have Erlang installed. Dependencies in C are neither trivially included nor redistributed| +|A full, self-contained, executable system|release or umbrella|This is the recommended production deploy for Erlang systems. See the [Releases](deployment/releases.md) section for more details on releases| +|A library to be used in other systems|lib or app|use `lib` for stateless libraries that contain modules, and `app` for stateful libraries with a supervision tree| +|A collection of multiple libraries|umbrella|This is the one form of project supported where multiple top-level apps are used. These projects generally cannot be used as dependencies. For projects usable as dependencies, see [how to declare`git_subdir` dependencies](configuration/dependencies.md#declaring-dependencies)| + +## Setting up Dependencies + +The basic configuration of a project should do at least two things: + +1. Always track the `rebar.lock` file + +2. Ignore the `_build` directory + +Tracking the lock file will let you have repeatable builds, and will allow Rebar3 to do things like automatically re-update dependencies when switching branches. + +> #### The _build directory should be safe to delete but you shouldn't need to {: .warning} +> Rebar3 tracks all the applications declared in your `rebar.config` files and should be able to track all required changes. +> +> There are a few edge cases where this is not possible and may lead to weird bugs, specifically when you are changing your project structure. If you are moving from a single-app project to an umbrella project (i.e. all source files move from `src/` to `apps/myapp/src`) or the opposite, chances are that various artifacts in the `_build` directory will conflict with each other. Delete it and ask for a fresh build, in this case. + +The next thing you'll want to do is add dependencies to your project. See the [Dependencies](configuration/dependencies.md) section for this. Adding dependencies does not automatically integrate them into your project, however. + +The `{deps, [...]}` configuration value tells Rebar3 which dependencies to fetch and download and track, but that's as far as it goes. You must then configure your application to make use of the dependency: + +- If the dependency is needed at runtime by your application in order for it to work (e.g. you need a web server or call the library directly), add it to your application's `.app.src` file under the `{applications, [stdlib, kernel, ...]}` tuple. This will let the Erlang VM know not to boot your app without the dependency being present +- If the dependency is only needed for releases (for example, `observer` or `recon`, which are debugging tools that your application likely does not depend on but you'd like to bundle it with), then you need to add that application explicitly to the `{releases, ...}` configuration tuple. Any dependency on that tuple will have its transitive dependencies included as well. + +Other build tools tend to make no distinction between these types of project inclusions, but Rebar3 tries to be strict with regards to what should be included or not. It can let you make specific builds, such as escripts or test releases that won't require specific toolchains like the Wx graphical toolkit in order to run. + +## Upgrading Dependencies + +There are two steps required when upgrading dependencies: + +1. Update the index cache + +2. Update the dependency itself + +The first step is required because Rebar3 keeps a cache of the Hex.pm repository packages and versions that you have fetched before. This lets the build tool run faster without useless calls to the network when all known and required versions are present on your computer. However, when a new version exists, Rebar3 won't automatically know about it. To tell it to go fetch new version definitions of known packages, call: + +```shell +$ rebar3 update +``` + +This will bring Hex packages up to date, but will not modify the existing project. + +The only way to change the existing project definition is by modifying the lock file. This is easily done by calling: + +```shell +$ rebar3 upgrade <depname> +``` + +This will update the lock file definition, and on the next build, the new copy will be fetched and compiled. If transitive dependencies have been upgraded as well, this will be detected and handled. + +You should avoid deleting the lock file when possible, and if you need to upgrade multiple dependencies, you can call `rebar3 upgrade dep1,dep2,dep3`. If you want to update all dependencies, call `rebar3 upgrade --all`, which can be fine on small projects, but you may want to do things progressively on larger projects. + +## Create Aliases for common tasks + +More complex projects may run multiple tools. For example, you may want to run `xref` to find dead code, `dialyzer` for type analysis, `ct` for Common Test suites, `cover` for coverage analysis, and so on. + +Rather than calling all the tasks by hand, an alias can create a simple command to run multiple tasks: + +```erlang +{alias, [ + {check, [xref, dialyzer, edoc, + {proper, "--regressions"}, + {proper, "-c"}, {ct, "-c"}, {cover, "-v --min_coverage=80"}]} +]}. +``` + +This configuration will allow to call `rebar3 check`, which will run the following in order: + +- `xref` analysis for dead code and calls to functions that don't exist +- `dialyzer` checks for inconsistencies and type errors +- build the project documentation, to make sure it can do so without errors +- run regression tests in `proper` (using [the PropEr plugin](configuration/plugins.md#proper)) +- run regular properties in PropEr while compiling with coverage analysis +- run Common Test test suites while compiling with coverage analysis +- run `cover` analysis, outputting the results to the shell. This alias also ensures that if code coverage dips below 80%, the command fails + +As soon as a task fails, the whole command is interrupted. You can adapt the aliases to your needs. + +> #### Optimize for task delays {: .info} +> A tip to save you time is to run tasks that are short first. For example, `xref` will find some issues that `dialyzer` also finds, but is a ton faster. Running `xref` before Dialyzer in your aliases will give you a faster feedback loop. + +## Recommended Configurations for Various tools + +Some of the Rebar3 configurations and defaults can be either too permissive or too restrictive. However, due to commitments to backwards compatibility, we can't always change and adapt them since it would risk breaking projects that relied on these specific configurations. + +The following is a collection of a few configurations that can be useful as new defaults when starting a new project. + +```erlang +{dialyzer, [ + {warnings, [ + %% Warn about undefined types and unknown functions + unknown + ]} +]}. + +{xref_checks,[ + %% enable most checks, but avoid 'unused calls' which is often + %% very verbose + undefined_function_calls, undefined_functions, locals_not_used, + deprecated_function_calls, deprecated_functions +]}. + +{profiles, [ + {test, [ + %% Avoid warnings when test suites use `-compile(export_all)` + {erl_opts, [nowarn_export_all]} + ]} +]}. +``` diff --git a/rebar.config b/rebar.config index 8db24f49a..a1e1c2d53 100644 --- a/rebar.config +++ b/rebar.config @@ -5,6 +5,11 @@ {project_app_dirs, ["apps/*","lib/*",".","vendor/*"]}. {project_plugin_dirs, ["plugins/*","vendor_plugins/*"]}. +{project_plugins, [ + {rebar3_ex_doc, "0.2.30"}, + {rebar3_hex, "7.0.11"} +]}. + %% Duplicated from apps/rebar3: %% - we want people who rely on rebar3 as a dependency to still be able %% to fetch it with git_subdir and have it work @@ -34,6 +39,41 @@ {plt_extra_apps, [parsetools, public_key]}, {exclude_apps, [cth_readable, erlware_commons, relx]}]} ]}, + {docs, [ + % ./rebar3 as docs ex_doc --app rebar + {ex_doc, [ + {source_url, <<"https://github.com/erlang/rebar3">>}, + {extras, [ + <<"README.md">>, + <<"docs/getting-started.md">>, + <<"docs/basic_usage.md">>, + <<"docs/workflow.md">>, + <<"docs/configuration/configuration.md">>, + <<"docs/configuration/dependencies.md">>, + <<"docs/configuration/profiles.md">>, + <<"docs/configuration/plugins.md">>, + <<"docs/configuration/config_script.md">>, + <<"docs/commands.md">>, + <<"docs/testing/introduction.md">>, + <<"docs/testing/ct.md">>, + <<"docs/testing/eunit.md">>, + <<"docs/testing/coverage.md">>, + <<"docs/package_management/publishing-packages.md">>, + <<"docs/deployment/releases.md">>, + <<"docs/tutorials/building_plugins.md">>, + <<"docs/tutorials/templates.md">>, + <<"docs/tutorials/building_c_cpp.md">>, + <<"docs/tutorials/using_breakpoints_to_debug_tests.md">>, + <<"docs/tutorials/from_rebar2_to_rebar3.md">>, + <<"docs/extending/custom_compiler_modules.md">>, + <<"docs/extending/custom_dep_resources.md">>, + <<"docs/extending/custom_compiler_plugins.md">>, + <<"docs/about/about-us.md">>, + <<"docs/about/security-policy.md">> + ]}, + {main, <<"readme">>} + ]} + ]}, %% Duplicated from apps/rebar3: %% - we don't want the test profile applied to our vendored deps. %% - we want people who rely on rebar3 as a dependency to still be able From 987d920ff297fb546131d00412c28c8c772d8263 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson <jesse.stimpson@gmail.com> Date: Sun, 5 Oct 2025 11:21:20 -0400 Subject: [PATCH 4/6] Hack in support for groups_for_extras --- docs/package_management/publishing-packages.md | 2 +- rebar.config | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/package_management/publishing-packages.md b/docs/package_management/publishing-packages.md index d970a29e9..ae9c1af9a 100644 --- a/docs/package_management/publishing-packages.md +++ b/docs/package_management/publishing-packages.md @@ -1,4 +1,4 @@ -# Hex Package Management +# Publishing Packages For package management `rebar3` uses [hex.pm](https://hex.pm), a package manager for Erlang and Elixir packages. diff --git a/rebar.config b/rebar.config index a1e1c2d53..b56debaec 100644 --- a/rebar.config +++ b/rebar.config @@ -71,6 +71,24 @@ <<"docs/about/about-us.md">>, <<"docs/about/security-policy.md">> ]}, + {groups_for_extras,[ + % Temporary hack, awaiting official groups_for_extras support in rebar3_ex_doc + % + % 1. mkdir _checkouts && cd _checkouts && ln -s ../_build/default/plugins/rebar3_ex_doc rebar3_ex_doc + % 2. In `to_ex_doc_format/1`, add the following clause: + % + % ({groups_for_extras = K, Groups}, Opts) when is_list(Groups) -> + % [{K, [{to_binary(GroupName), L} || {GroupName, L} <- Groups]} | Opts]; + % + % 3. The current config abuses knowledge of the Regex internals + {'Configuration', #{source => <<"docs/configuration">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, + {'Testing', #{source => <<"docs/testing">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, + {'Hex Package Management', #{source => <<"docs/package_management">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, + {'Deployment', #{source => <<"docs/deployment">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, + {'Tutorials', #{source => <<"docs/tutorials">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, + {'Extending Rebar3', #{source => <<"docs/extending">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, + {'About', #{source => <<"docs/about">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}} + ]}, {main, <<"readme">>} ]} ]}, From fff30145580a04f491e35131769dbbe384463891 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson <jesse.stimpson@gmail.com> Date: Sun, 16 Nov 2025 19:25:35 -0500 Subject: [PATCH 5/6] rebar3_ex_doc 0.2.31 supports groups_for_extras --- README.md | 28 ++++++++++++++-------------- rebar.config | 51 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 82ccbf4b5..ffbc9b728 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,12 @@ Rebar3 will: - handle build artifacts, paths, and libraries such that standard development tools can be used without a headache; - adapt to projects of all sizes on almost any platform; -- treat [documentation](https://hexdocs.pm/rebar3) as a feature, +- treat [documentation](https://rebar3.org/docs/) as a feature, and errors or lack of documentation as a bug. Rebar3 is also a self-contained Erlang script. It is easy to distribute or embed directly in a project. Tasks or behaviours can be modified or expanded -with a [plugin system](https://hexdocs.pm/rebar3/configuration/plugins.html) +with a [plugin system](https://rebar3.org/docs/configuration/plugins) [flexible enough](https://github.com/lfe-rebar3/rebar3_lfe) that even other languages on the Erlang VM will use it as a build tool. @@ -77,7 +77,7 @@ security fixes. | 3.14.1 | 19-23 | | | 3.13.3 | 19-22 | Don't use 3.13.1 or 3.13.2, see https://ferd.ca/you-ve-got-to-upgrade-rebar3.html | -A [getting started guide is maintained on the official documentation website](https://hexdocs.pm/rebar3/getting-started.html), +A [getting started guide is maintained on the official documentation website](https://rebar3.org/docs/getting-started), but installing rebar3 can be done by any of the ways described below Latest stable compiled version: @@ -122,7 +122,7 @@ Do note that if you are planning to work with multiple Erlang versions on the sa ## Documentation -Rebar3 documentation is maintained on [https://hexdocs.pm/rebar3](https://hexdocs.pm/rebar3) +Rebar3 documentation is maintained on [https://rebar3.org/docs](https://rebar3.org/docs) ## Features @@ -138,8 +138,8 @@ others via the plugin ecosystem: | Clean up artifacts | Remove the compiled beam files from a project with `rebar3 clean` or just remove the `_build` directory to remove *all* compilation artifacts | | Code Coverage | Various commands can be instrumented to accumulate code coverage data (such as `eunit` or `ct`). Reports can be generated with `rebar3 cover` | | Common Test | The test framework can be run by calling `rebar3 ct` | -| Dependencies | Rebar3 maintains local copies of dependencies on a per-project basis. They are fetched deterministically, can be locked, upgraded, fetched from source, packages, or from local directories. See [Dependencies on the documentation website](https://hexdocs.pm/rebar3/configuration/dependencies.html). Call `rebar3 tree` to show the whole dependency tree. | -| Documentation | Print help for rebar3 itself (`rebar3 help`) or for a specific task (`rebar3 help <task>`). Full reference at [rebar3 documentation](https://hexdocs.pm/rebar3). | +| Dependencies | Rebar3 maintains local copies of dependencies on a per-project basis. They are fetched deterministically, can be locked, upgraded, fetched from source, packages, or from local directories. See [Dependencies on the documentation website](https://rebar3.org/docs/configuration/dependencies/). Call `rebar3 tree` to show the whole dependency tree. | +| Documentation | Print help for rebar3 itself (`rebar3 help`) or for a specific task (`rebar3 help <task>`). Full reference at [rebar3 documentation](https://rebar3.org/docs). | | Dialyzer | Run the Dialyzer analyzer on the project with `rebar3 dialyzer`. Base PLTs for each version of the language will be cached and reused for faster analysis | | Edoc | Generate documentation using edoc with `rebar3 edoc` | | Escript generation | Rebar3 can be used to generate [escripts](http://www.erlang.org/doc/man/escript.html) providing an easy way to run all your applications on a system where Erlang is installed | @@ -147,12 +147,12 @@ others via the plugin ecosystem: | Locked dependencies | Dependencies are going to be automatically locked to ensure repeatable builds. Versions can be changed with `rebar3 upgrade` or `rebar3 upgrade <app>`, or locks can be released altogether with `rebar3 unlock`. | | Packages | A given [Hex package](https://hex.pm) can be inspected `rebar3 pkgs <name>`. This will output its description and available versions | | Path | While paths are managed automatically, you can print paths to the current build directories with `rebar3 path`. | -| Plugins | Rebar3 can be fully extended with [plugins](https://hexdocs.pm/rebar3/plugins.html). List or upgrade plugins by using the plugin namespace (`rebar3 plugins`). | -| Profiles | Rebar3 can have subconfiguration options for different profiles, such as `test` or `prod`. These allow specific dependencies or compile options to be used in specific contexts. See [Profiles](https://hexdocs.pm/rebar3/configuration/profiles.html) in the docs. | -| Releases | Rebar3 supports [building releases](https://hexdocs.pm/rebar3/deployment/releases.html) with the `relx` tool, providing a way to ship fully self-contained Erlang systems. Release update scripts for live code updates can also be generated. | +| Plugins | Rebar3 can be fully extended with [plugins](https://rebar3.org/docs/configuration/plugins/). List or upgrade plugins by using the plugin namespace (`rebar3 plugins`). | +| Profiles | Rebar3 can have subconfiguration options for different profiles, such as `test` or `prod`. These allow specific dependencies or compile options to be used in specific contexts. See [Profiles](https://rebar3.org/docs/configuration/profiles) in the docs. | +| Releases | Rebar3 supports [building releases](https://rebar3.org/docs/deployment/releases) with the `relx` tool, providing a way to ship fully self-contained Erlang systems. Release update scripts for live code updates can also be generated. | | Shell | A full shell with your applications available can be started with `rebar3 shell`. From there, call tasks as `r3:do(compile)` to automatically recompile and reload the code without interruption | | Tarballs | Releases can be packaged into tarballs ready to be deployed. | -| Templates | Configurable templates ship out of the box (try `rebar3 new` for a list or `rebar3 new help <template>` for a specific one). [Custom templates](https://hexdocs.pm/rebar3/tutorials/templates.html) are also supported, and plugins can also add their own. | +| Templates | Configurable templates ship out of the box (try `rebar3 new` for a list or `rebar3 new help <template>` for a specific one). [Custom templates](https://rebar3.org/docs/tutorials/templates) are also supported, and plugins can also add their own. | | Xref | Run cross-reference analysis on the project with [xref](http://www.erlang.org/doc/apps/tools/xref_chapter.html) by calling `rebar3 xref`. | ## Migrating From rebar2 @@ -160,13 +160,13 @@ others via the plugin ecosystem: The grievances we had with Rebar 2.x were not fixable without breaking compatibility in some very important ways. -A full guide titled [From Rebar 2.x to Rebar3](https://hexdocs.pm/rebar3/tutorials/from_rebar2_to_rebar3.html) +A full guide titled [From Rebar 2.x to Rebar3](https://rebar3.org/docs/tutorials/from_rebar2_to_rebar3/) is provided on the documentation website. Notable modifications include mandating a more standard set of directory structures, changing the handling of dependencies, moving some compilers (such as C, Diameter, ErlyDTL, or ProtoBuffs) to -[plugins](https://hexdocs.pm/rebar3/configuration/plugins.html) rather than +[plugins](https://rebar3.org/docs/configuration/plugins) rather than maintaining them in core rebar, and moving release builds from reltool to relx. @@ -181,13 +181,13 @@ If you need quick feedback, you can try the #rebar channel on [irc.freenode.net](https://freenode.net) or the #rebar3 channel on [erlanger.slack.com](https://erlanger.slack.com/). Be sure to check the -[documentation](https://hexdocs.pm/rebar3) first, just to be sure you're not +[documentation](https://rebar3.org/docs) first, just to be sure you're not asking about things with well-known answers. For bug reports, roadmaps, and issues, visit the [github issues page](https://github.com/erlang/rebar3/issues). General rebar community resources and links can be found at -[Community | About Us](https://hexdocs.pm/rebar3/about/about-us.html#community) +[Community | About Us](https://rebar3.org/docs/about/about-us/#community) To contribute to rebar3, please refer to [CONTRIBUTING](https://github.com/erlang/rebar3/blob/master/CONTRIBUTING.md). diff --git a/rebar.config b/rebar.config index b56debaec..2e5157e23 100644 --- a/rebar.config +++ b/rebar.config @@ -6,7 +6,7 @@ {project_plugin_dirs, ["plugins/*","vendor_plugins/*"]}. {project_plugins, [ - {rebar3_ex_doc, "0.2.30"}, + {rebar3_ex_doc, "0.2.31"}, {rebar3_hex, "7.0.11"} ]}. @@ -40,7 +40,7 @@ {exclude_apps, [cth_readable, erlware_commons, relx]}]} ]}, {docs, [ - % ./rebar3 as docs ex_doc --app rebar + % ./rebar3 as docs ex_doc --app rebar {ex_doc, [ {source_url, <<"https://github.com/erlang/rebar3">>}, {extras, [ @@ -72,22 +72,37 @@ <<"docs/about/security-policy.md">> ]}, {groups_for_extras,[ - % Temporary hack, awaiting official groups_for_extras support in rebar3_ex_doc - % - % 1. mkdir _checkouts && cd _checkouts && ln -s ../_build/default/plugins/rebar3_ex_doc rebar3_ex_doc - % 2. In `to_ex_doc_format/1`, add the following clause: - % - % ({groups_for_extras = K, Groups}, Opts) when is_list(Groups) -> - % [{K, [{to_binary(GroupName), L} || {GroupName, L} <- Groups]} | Opts]; - % - % 3. The current config abuses knowledge of the Regex internals - {'Configuration', #{source => <<"docs/configuration">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, - {'Testing', #{source => <<"docs/testing">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, - {'Hex Package Management', #{source => <<"docs/package_management">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, - {'Deployment', #{source => <<"docs/deployment">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, - {'Tutorials', #{source => <<"docs/tutorials">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, - {'Extending Rebar3', #{source => <<"docs/extending">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}}, - {'About', #{source => <<"docs/about">>, '__struct__' => 'Elixir.Regex', re_pattern => nil, opts => [], re_version => nil}} + {'Configuration', [ + <<"docs/configuration/configuration.md">>, + <<"docs/configuration/dependencies.md">>, + <<"docs/configuration/profiles.md">>, + <<"docs/configuration/plugins.md">>, + <<"docs/configuration/config_script.md">> + ]}, + {'Testing', [ + <<"docs/testing/introduction.md">>, + <<"docs/testing/ct.md">>, + <<"docs/testing/eunit.md">>, + <<"docs/testing/coverage.md">> + ]}, + {'Hex Package Management', [<<"docs/package_management/publishing-packages.md">>]}, + {'Deployment', [<<"docs/deployment/releases.md">>]}, + {'Tutorials', [ + <<"docs/tutorials/building_plugins.md">>, + <<"docs/tutorials/templates.md">>, + <<"docs/tutorials/building_c_cpp.md">>, + <<"docs/tutorials/using_breakpoints_to_debug_tests.md">>, + <<"docs/tutorials/from_rebar2_to_rebar3.md">> + ]}, + {'Extending Rebar3', [ + <<"docs/extending/custom_compiler_modules.md">>, + <<"docs/extending/custom_dep_resources.md">>, + <<"docs/extending/custom_compiler_plugins.md">> + ]}, + {'About', [ + <<"docs/about/about-us.md">>, + <<"docs/about/security-policy.md">> + ]} ]}, {main, <<"readme">>} ]} From 67808dffee1439e433ed1b68345cc1bb2f2ed1a5 Mon Sep 17 00:00:00 2001 From: Jesse Stimpson <jesse.stimpson@gmail.com> Date: Sun, 16 Nov 2025 20:05:36 -0500 Subject: [PATCH 6/6] Define public API for docs by excluding private modules --- apps/rebar/src/r3.erl | 1 + apps/rebar/src/rebar3.erl | 1 + apps/rebar/src/rebar_agent.erl | 1 + apps/rebar/src/rebar_app_discover.erl | 1 + apps/rebar/src/rebar_app_utils.erl | 1 + apps/rebar/src/rebar_compiler.erl | 1 + apps/rebar/src/rebar_compiler_dag.erl | 1 + apps/rebar/src/rebar_compiler_epp.erl | 1 + apps/rebar/src/rebar_compiler_erl.erl | 1 + apps/rebar/src/rebar_compiler_format.erl | 1 + apps/rebar/src/rebar_compiler_mib.erl | 1 + apps/rebar/src/rebar_compiler_xrl.erl | 1 + apps/rebar/src/rebar_compiler_yrl.erl | 1 + apps/rebar/src/rebar_completion.erl | 1 + apps/rebar/src/rebar_completion_bash.erl | 1 + apps/rebar/src/rebar_completion_zsh.erl | 1 + apps/rebar/src/rebar_config.erl | 1 + apps/rebar/src/rebar_core.erl | 1 + apps/rebar/src/rebar_dialyzer_format.erl | 1 + apps/rebar/src/rebar_digraph.erl | 1 + apps/rebar/src/rebar_dist_utils.erl | 1 + apps/rebar/src/rebar_env.erl | 1 + apps/rebar/src/rebar_erlc_compiler.erl | 1 + apps/rebar/src/rebar_fetch.erl | 1 + apps/rebar/src/rebar_file_utils.erl | 1 + apps/rebar/src/rebar_git_resource.erl | 1 + apps/rebar/src/rebar_git_subdir_resource.erl | 1 + apps/rebar/src/rebar_hex_repos.erl | 1 + apps/rebar/src/rebar_hg_resource.erl | 1 + apps/rebar/src/rebar_hooks.erl | 1 + apps/rebar/src/rebar_httpc_adapter.erl | 1 + apps/rebar/src/rebar_log.erl | 1 + apps/rebar/src/rebar_opts.erl | 1 + apps/rebar/src/rebar_otp_app.erl | 1 + apps/rebar/src/rebar_packages.erl | 1 + apps/rebar/src/rebar_parallel.erl | 1 + apps/rebar/src/rebar_pkg_resource.erl | 1 + apps/rebar/src/rebar_plugins.erl | 1 + apps/rebar/src/rebar_prv_alias.erl | 1 + apps/rebar/src/rebar_prv_app_discovery.erl | 1 + apps/rebar/src/rebar_prv_as.erl | 1 + apps/rebar/src/rebar_prv_bare_compile.erl | 1 + apps/rebar/src/rebar_prv_clean.erl | 1 + apps/rebar/src/rebar_prv_common_test.erl | 1 + apps/rebar/src/rebar_prv_compile.erl | 1 + apps/rebar/src/rebar_prv_completion.erl | 1 + apps/rebar/src/rebar_prv_cover.erl | 1 + apps/rebar/src/rebar_prv_deps.erl | 1 + apps/rebar/src/rebar_prv_deps_tree.erl | 1 + apps/rebar/src/rebar_prv_dialyzer.erl | 1 + apps/rebar/src/rebar_prv_do.erl | 1 + apps/rebar/src/rebar_prv_edoc.erl | 1 + apps/rebar/src/rebar_prv_escriptize.erl | 1 + apps/rebar/src/rebar_prv_eunit.erl | 1 + apps/rebar/src/rebar_prv_get_deps.erl | 1 + apps/rebar/src/rebar_prv_help.erl | 1 + apps/rebar/src/rebar_prv_install_deps.erl | 1 + apps/rebar/src/rebar_prv_local_install.erl | 1 + apps/rebar/src/rebar_prv_local_upgrade.erl | 1 + apps/rebar/src/rebar_prv_lock.erl | 1 + apps/rebar/src/rebar_prv_manifest.erl | 1 + apps/rebar/src/rebar_prv_new.erl | 1 + apps/rebar/src/rebar_prv_packages.erl | 1 + apps/rebar/src/rebar_prv_path.erl | 1 + apps/rebar/src/rebar_prv_plugins.erl | 1 + apps/rebar/src/rebar_prv_plugins_upgrade.erl | 1 + apps/rebar/src/rebar_prv_release.erl | 1 + apps/rebar/src/rebar_prv_relup.erl | 1 + apps/rebar/src/rebar_prv_report.erl | 1 + apps/rebar/src/rebar_prv_repos.erl | 1 + apps/rebar/src/rebar_prv_shell.erl | 1 + apps/rebar/src/rebar_prv_state.erl | 1 + apps/rebar/src/rebar_prv_tar.erl | 1 + apps/rebar/src/rebar_prv_unlock.erl | 1 + apps/rebar/src/rebar_prv_update.erl | 1 + apps/rebar/src/rebar_prv_upgrade.erl | 1 + apps/rebar/src/rebar_prv_vendor.erl | 1 + apps/rebar/src/rebar_prv_version.erl | 1 + apps/rebar/src/rebar_prv_xref.erl | 1 + apps/rebar/src/rebar_relx.erl | 1 + apps/rebar/src/rebar_string.erl | 1 + apps/rebar/src/rebar_templater.erl | 1 + apps/rebar/src/rebar_uri.erl | 1 + apps/rebar/src/rebar_user.erl | 1 + apps/rebar/src/vendored/r3_hex_api.erl | 1 + apps/rebar/src/vendored/r3_hex_api_key.erl | 1 + apps/rebar/src/vendored/r3_hex_api_package.erl | 1 + apps/rebar/src/vendored/r3_hex_api_package_owner.erl | 1 + apps/rebar/src/vendored/r3_hex_api_release.erl | 1 + apps/rebar/src/vendored/r3_hex_api_user.erl | 1 + apps/rebar/src/vendored/r3_hex_core.erl | 1 + apps/rebar/src/vendored/r3_hex_erl_tar.erl | 1 + apps/rebar/src/vendored/r3_hex_filename.erl | 1 + apps/rebar/src/vendored/r3_hex_http.erl | 1 + apps/rebar/src/vendored/r3_hex_http_httpc.erl | 1 + apps/rebar/src/vendored/r3_hex_licenses.erl | 1 + apps/rebar/src/vendored/r3_hex_pb_names.erl | 1 + apps/rebar/src/vendored/r3_hex_pb_package.erl | 1 + apps/rebar/src/vendored/r3_hex_pb_signed.erl | 1 + apps/rebar/src/vendored/r3_hex_pb_versions.erl | 1 + apps/rebar/src/vendored/r3_hex_registry.erl | 1 + apps/rebar/src/vendored/r3_hex_repo.erl | 1 + apps/rebar/src/vendored/r3_hex_tarball.erl | 1 + apps/rebar/src/vendored/r3_safe_erl_term.xrl | 2 +- docs/extending/custom_compiler_modules.md | 2 +- docs/extending/custom_dep_resources.md | 2 +- 106 files changed, 106 insertions(+), 3 deletions(-) diff --git a/apps/rebar/src/r3.erl b/apps/rebar/src/r3.erl index 5e3b22225..5143c24e9 100644 --- a/apps/rebar/src/r3.erl +++ b/apps/rebar/src/r3.erl @@ -1,6 +1,7 @@ %%% @doc external alias for `rebar_agent' for more convenient %%% calls from a shell. -module(r3). +-moduledoc false. -export([do/1, do/2, do/3, async_do/1, async_do/2, async_do/3, break/0, resume/0]). -export(['$handle_undefined_function'/2]). -include("rebar.hrl"). diff --git a/apps/rebar/src/rebar3.erl b/apps/rebar/src/rebar3.erl index b83f1797c..c90b8f10e 100644 --- a/apps/rebar/src/rebar3.erl +++ b/apps/rebar/src/rebar3.erl @@ -35,6 +35,7 @@ %% accessible to the rest of the run. %% @end -module(rebar3). +-moduledoc false. -export([main/0, main/1, diff --git a/apps/rebar/src/rebar_agent.erl b/apps/rebar/src/rebar_agent.erl index d71ef7238..aeefb1528 100644 --- a/apps/rebar/src/rebar_agent.erl +++ b/apps/rebar/src/rebar_agent.erl @@ -1,6 +1,7 @@ %%% @doc Runs a process that holds a rebar3 state and can be used %%% to statefully maintain loaded project state into a running VM. -module(rebar_agent). +-moduledoc false. -export([start_link/1, do/1, do/2, do/3, async_do/1, async_do/2, async_do/3]). -export(['$handle_undefined_function'/2]). -export([init/1, diff --git a/apps/rebar/src/rebar_app_discover.erl b/apps/rebar/src/rebar_app_discover.erl index 94fb20488..6cc304857 100644 --- a/apps/rebar/src/rebar_app_discover.erl +++ b/apps/rebar/src/rebar_app_discover.erl @@ -1,6 +1,7 @@ %%% @doc utility functions to do the basic discovery of apps %%% and layout for the project. -module(rebar_app_discover). +-moduledoc false. -export([do/2, format_error/1, diff --git a/apps/rebar/src/rebar_app_utils.erl b/apps/rebar/src/rebar_app_utils.erl index f4526e4c5..36859760b 100644 --- a/apps/rebar/src/rebar_app_utils.erl +++ b/apps/rebar/src/rebar_app_utils.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_app_utils). +-moduledoc false. -export([find/2, find/3, diff --git a/apps/rebar/src/rebar_compiler.erl b/apps/rebar/src/rebar_compiler.erl index 8e8b2e6bc..66dab2289 100644 --- a/apps/rebar/src/rebar_compiler.erl +++ b/apps/rebar/src/rebar_compiler.erl @@ -1,4 +1,5 @@ -module(rebar_compiler). +-moduledoc false. -export([analyze_all/2, analyze_all_extras/2, diff --git a/apps/rebar/src/rebar_compiler_dag.erl b/apps/rebar/src/rebar_compiler_dag.erl index e147be9aa..968d923cb 100644 --- a/apps/rebar/src/rebar_compiler_dag.erl +++ b/apps/rebar/src/rebar_compiler_dag.erl @@ -1,6 +1,7 @@ %%% Module handling the directed graph required for the analysis %%% of all top-level applications by the various compiler plugins. -module(rebar_compiler_dag). +-moduledoc false. -export([init/4, status/4, maybe_store/5, terminate/1]). -export([prune/5, populate_sources/5, populate_deps/3, propagate_stamps/1, compile_order/4, store_artifact/4]). diff --git a/apps/rebar/src/rebar_compiler_epp.erl b/apps/rebar/src/rebar_compiler_epp.erl index a98554856..67c9e868c 100644 --- a/apps/rebar/src/rebar_compiler_epp.erl +++ b/apps/rebar/src/rebar_compiler_epp.erl @@ -3,6 +3,7 @@ %%% build complete and accurate DAGs %%% @end -module(rebar_compiler_epp). +-moduledoc false. -export([deps/2, resolve_module/2]). %% cache (a la code path storage, but for dependencies not in code path) -export([ensure_started/0, flush/0, resolve_source/2]). diff --git a/apps/rebar/src/rebar_compiler_erl.erl b/apps/rebar/src/rebar_compiler_erl.erl index 98e365c94..9dc16d807 100644 --- a/apps/rebar/src/rebar_compiler_erl.erl +++ b/apps/rebar/src/rebar_compiler_erl.erl @@ -1,4 +1,5 @@ -module(rebar_compiler_erl). +-moduledoc false. -behaviour(rebar_compiler). diff --git a/apps/rebar/src/rebar_compiler_format.erl b/apps/rebar/src/rebar_compiler_format.erl index 32bf1bd21..f29da3c83 100644 --- a/apps/rebar/src/rebar_compiler_format.erl +++ b/apps/rebar/src/rebar_compiler_format.erl @@ -1,5 +1,6 @@ %%% @doc Module handling rich formatting of errors. -module(rebar_compiler_format). +-moduledoc false. -export([format/5]). -include("rebar.hrl"). diff --git a/apps/rebar/src/rebar_compiler_mib.erl b/apps/rebar/src/rebar_compiler_mib.erl index 92be10140..fe9c1c099 100644 --- a/apps/rebar/src/rebar_compiler_mib.erl +++ b/apps/rebar/src/rebar_compiler_mib.erl @@ -1,4 +1,5 @@ -module(rebar_compiler_mib). +-moduledoc false. -behaviour(rebar_compiler). diff --git a/apps/rebar/src/rebar_compiler_xrl.erl b/apps/rebar/src/rebar_compiler_xrl.erl index 15b42ff67..5d6e98796 100644 --- a/apps/rebar/src/rebar_compiler_xrl.erl +++ b/apps/rebar/src/rebar_compiler_xrl.erl @@ -1,4 +1,5 @@ -module(rebar_compiler_xrl). +-moduledoc false. -behaviour(rebar_compiler). diff --git a/apps/rebar/src/rebar_compiler_yrl.erl b/apps/rebar/src/rebar_compiler_yrl.erl index a9740afdc..b1c8fa9b4 100644 --- a/apps/rebar/src/rebar_compiler_yrl.erl +++ b/apps/rebar/src/rebar_compiler_yrl.erl @@ -1,4 +1,5 @@ -module(rebar_compiler_yrl). +-moduledoc false. -behaviour(rebar_compiler). diff --git a/apps/rebar/src/rebar_completion.erl b/apps/rebar/src/rebar_completion.erl index d6f84252c..14e5daff6 100644 --- a/apps/rebar/src/rebar_completion.erl +++ b/apps/rebar/src/rebar_completion.erl @@ -1,4 +1,5 @@ -module(rebar_completion). +-moduledoc false. -export([generate/2]). diff --git a/apps/rebar/src/rebar_completion_bash.erl b/apps/rebar/src/rebar_completion_bash.erl index aa2d019c3..1e79461c8 100644 --- a/apps/rebar/src/rebar_completion_bash.erl +++ b/apps/rebar/src/rebar_completion_bash.erl @@ -1,6 +1,7 @@ %% @doc Completion file generator for bash %% @end -module(rebar_completion_bash). +-moduledoc false. -behavior(rebar_completion). diff --git a/apps/rebar/src/rebar_completion_zsh.erl b/apps/rebar/src/rebar_completion_zsh.erl index 9300b3f72..d61834922 100644 --- a/apps/rebar/src/rebar_completion_zsh.erl +++ b/apps/rebar/src/rebar_completion_zsh.erl @@ -1,6 +1,7 @@ %% @doc Completion file generator for zsh %% @end -module(rebar_completion_zsh). +-moduledoc false. -behavior(rebar_completion). diff --git a/apps/rebar/src/rebar_config.erl b/apps/rebar/src/rebar_config.erl index 02e5c8f22..59b202539 100644 --- a/apps/rebar/src/rebar_config.erl +++ b/apps/rebar/src/rebar_config.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_config). +-moduledoc false. -export([consult_root/0 ,consult/1 diff --git a/apps/rebar/src/rebar_core.erl b/apps/rebar/src/rebar_core.erl index 588c2016d..65f05ec83 100644 --- a/apps/rebar/src/rebar_core.erl +++ b/apps/rebar/src/rebar_core.erl @@ -27,6 +27,7 @@ %% @doc Module providing core functionality about command dispatch, namespacing, %% and chaining for rebar3. -module(rebar_core). +-moduledoc false. -export([init_command/2, process_namespace/2, process_command/2, do/2, format_error/1]). diff --git a/apps/rebar/src/rebar_dialyzer_format.erl b/apps/rebar/src/rebar_dialyzer_format.erl index a5e733db9..b7e18fd77 100644 --- a/apps/rebar/src/rebar_dialyzer_format.erl +++ b/apps/rebar/src/rebar_dialyzer_format.erl @@ -13,6 +13,7 @@ %%% the 'red vs green' resambles the diff view 'remove vs add' %%% * blue: argument positions. -module(rebar_dialyzer_format). +-moduledoc false. -include("rebar.hrl"). diff --git a/apps/rebar/src/rebar_digraph.erl b/apps/rebar/src/rebar_digraph.erl index 776d7b8ba..11d594d0b 100644 --- a/apps/rebar/src/rebar_digraph.erl +++ b/apps/rebar/src/rebar_digraph.erl @@ -1,6 +1,7 @@ %%% @doc build a digraph of applications in order to figure out dependency %%% and compile order. -module(rebar_digraph). +-moduledoc false. -export([compile_order/1 ,restore_graph/1 diff --git a/apps/rebar/src/rebar_dist_utils.erl b/apps/rebar/src/rebar_dist_utils.erl index 06063a9c3..6cbda0c3e 100644 --- a/apps/rebar/src/rebar_dist_utils.erl +++ b/apps/rebar/src/rebar_dist_utils.erl @@ -1,6 +1,7 @@ %%% Common functions to boot/stop distributed setups for %%% the rebar3 script. -module(rebar_dist_utils). +-moduledoc false. -export([either/3, short/2, long/2, find_options/1]). -include("rebar.hrl"). diff --git a/apps/rebar/src/rebar_env.erl b/apps/rebar/src/rebar_env.erl index a0b6f4a2f..5cbd9fcf2 100644 --- a/apps/rebar/src/rebar_env.erl +++ b/apps/rebar/src/rebar_env.erl @@ -1,4 +1,5 @@ -module(rebar_env). +-moduledoc false. -export([create_env/1, create_env/2]). diff --git a/apps/rebar/src/rebar_erlc_compiler.erl b/apps/rebar/src/rebar_erlc_compiler.erl index 0667ebb0b..d22cb8e9d 100644 --- a/apps/rebar/src/rebar_erlc_compiler.erl +++ b/apps/rebar/src/rebar_erlc_compiler.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_erlc_compiler). +-moduledoc false. -export([compile/1, compile/2, compile/3, compile_dir/3, compile_dir/4, diff --git a/apps/rebar/src/rebar_fetch.erl b/apps/rebar/src/rebar_fetch.erl index 28753a308..ebadeba88 100644 --- a/apps/rebar/src/rebar_fetch.erl +++ b/apps/rebar/src/rebar_fetch.erl @@ -6,6 +6,7 @@ %% %% ------------------------------------------------------------------- -module(rebar_fetch). +-moduledoc false. -export([lock_source/2, download_source/2, diff --git a/apps/rebar/src/rebar_file_utils.erl b/apps/rebar/src/rebar_file_utils.erl index f8ed7deba..9c3336389 100644 --- a/apps/rebar/src/rebar_file_utils.erl +++ b/apps/rebar/src/rebar_file_utils.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_file_utils). +-moduledoc false. -export([try_consult/1, consult_config/2, diff --git a/apps/rebar/src/rebar_git_resource.erl b/apps/rebar/src/rebar_git_resource.erl index 032223b62..5378d3cb2 100644 --- a/apps/rebar/src/rebar_git_resource.erl +++ b/apps/rebar/src/rebar_git_resource.erl @@ -1,6 +1,7 @@ %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 et -module(rebar_git_resource). +-moduledoc false. -behaviour(rebar_resource_v2). diff --git a/apps/rebar/src/rebar_git_subdir_resource.erl b/apps/rebar/src/rebar_git_subdir_resource.erl index 9e4236937..b1c0e2c73 100644 --- a/apps/rebar/src/rebar_git_subdir_resource.erl +++ b/apps/rebar/src/rebar_git_subdir_resource.erl @@ -1,6 +1,7 @@ %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 et -module(rebar_git_subdir_resource). +-moduledoc false. -behaviour(rebar_resource_v2). diff --git a/apps/rebar/src/rebar_hex_repos.erl b/apps/rebar/src/rebar_hex_repos.erl index 04cdf6870..d64fc4161 100644 --- a/apps/rebar/src/rebar_hex_repos.erl +++ b/apps/rebar/src/rebar_hex_repos.erl @@ -1,4 +1,5 @@ -module(rebar_hex_repos). +-moduledoc false. -export([from_state/2, get_repo_config/2, diff --git a/apps/rebar/src/rebar_hg_resource.erl b/apps/rebar/src/rebar_hg_resource.erl index d92a4aa8e..b5b368ef0 100644 --- a/apps/rebar/src/rebar_hg_resource.erl +++ b/apps/rebar/src/rebar_hg_resource.erl @@ -1,6 +1,7 @@ %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 et -module(rebar_hg_resource). +-moduledoc false. -behaviour(rebar_resource_v2). diff --git a/apps/rebar/src/rebar_hooks.erl b/apps/rebar/src/rebar_hooks.erl index 6cbee307c..15a7227d8 100644 --- a/apps/rebar/src/rebar_hooks.erl +++ b/apps/rebar/src/rebar_hooks.erl @@ -1,4 +1,5 @@ -module(rebar_hooks). +-moduledoc false. -export([run_all_hooks/5 ,run_all_hooks/6 diff --git a/apps/rebar/src/rebar_httpc_adapter.erl b/apps/rebar/src/rebar_httpc_adapter.erl index 26318d1ba..d778a2c5b 100644 --- a/apps/rebar/src/rebar_httpc_adapter.erl +++ b/apps/rebar/src/rebar_httpc_adapter.erl @@ -1,6 +1,7 @@ %% Derived from hex_core v0.7.1 for extra flexibility. -module(rebar_httpc_adapter). +-moduledoc false. -behaviour(r3_hex_http). -export([request/5]). diff --git a/apps/rebar/src/rebar_log.erl b/apps/rebar/src/rebar_log.erl index 4942bf7fb..eb8457fe5 100644 --- a/apps/rebar/src/rebar_log.erl +++ b/apps/rebar/src/rebar_log.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_log). +-moduledoc false. -export([init/2, crashdump/2, diff --git a/apps/rebar/src/rebar_opts.erl b/apps/rebar/src/rebar_opts.erl index e7d38975d..594b80089 100644 --- a/apps/rebar/src/rebar_opts.erl +++ b/apps/rebar/src/rebar_opts.erl @@ -1,4 +1,5 @@ -module(rebar_opts). +-moduledoc false. -export([get/2, get/3, diff --git a/apps/rebar/src/rebar_otp_app.erl b/apps/rebar/src/rebar_otp_app.erl index e9dcb7886..1734d16c2 100644 --- a/apps/rebar/src/rebar_otp_app.erl +++ b/apps/rebar/src/rebar_otp_app.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_otp_app). +-moduledoc false. -export([compile/2, format_error/1]). diff --git a/apps/rebar/src/rebar_packages.erl b/apps/rebar/src/rebar_packages.erl index f7444f296..3a46c4a60 100644 --- a/apps/rebar/src/rebar_packages.erl +++ b/apps/rebar/src/rebar_packages.erl @@ -1,4 +1,5 @@ -module(rebar_packages). +-moduledoc false. -export([get/2 ,get_all_names/1 diff --git a/apps/rebar/src/rebar_parallel.erl b/apps/rebar/src/rebar_parallel.erl index eb4992d0a..95ffb1974 100644 --- a/apps/rebar/src/rebar_parallel.erl +++ b/apps/rebar/src/rebar_parallel.erl @@ -11,6 +11,7 @@ %%% without demanding to know all the tasks to run ahead of time. %%% @end -module(rebar_parallel). +-moduledoc false. -export([queue/5, pool/4, pool/5, pool_task_async/2, pool_terminate/1]). -include("rebar.hrl"). diff --git a/apps/rebar/src/rebar_pkg_resource.erl b/apps/rebar/src/rebar_pkg_resource.erl index d7d4f25a1..b174dd588 100644 --- a/apps/rebar/src/rebar_pkg_resource.erl +++ b/apps/rebar/src/rebar_pkg_resource.erl @@ -1,6 +1,7 @@ %% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- %% ex: ts=4 sw=4 et -module(rebar_pkg_resource). +-moduledoc false. -behaviour(rebar_resource_v2). diff --git a/apps/rebar/src/rebar_plugins.erl b/apps/rebar/src/rebar_plugins.erl index ad8211a94..1c364a331 100644 --- a/apps/rebar/src/rebar_plugins.erl +++ b/apps/rebar/src/rebar_plugins.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_plugins). +-moduledoc false. -export([project_plugins_install/1 ,top_level_install/1 diff --git a/apps/rebar/src/rebar_prv_alias.erl b/apps/rebar/src/rebar_prv_alias.erl index 41f71ac30..56f258a56 100644 --- a/apps/rebar/src/rebar_prv_alias.erl +++ b/apps/rebar/src/rebar_prv_alias.erl @@ -5,6 +5,7 @@ %%% from a plugin at https://github.com/tsloughter/rebar_alias after %%% years of stability. Only some error checks were added -module(rebar_prv_alias). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_app_discovery.erl b/apps/rebar/src/rebar_prv_app_discovery.erl index 20b7f904d..915255e2d 100644 --- a/apps/rebar/src/rebar_prv_app_discovery.erl +++ b/apps/rebar/src/rebar_prv_app_discovery.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_app_discovery). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_as.erl b/apps/rebar/src/rebar_prv_as.erl index f560113be..e036dc38c 100644 --- a/apps/rebar/src/rebar_prv_as.erl +++ b/apps/rebar/src/rebar_prv_as.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_as). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_bare_compile.erl b/apps/rebar/src/rebar_prv_bare_compile.erl index f1f91ba2f..775d75733 100644 --- a/apps/rebar/src/rebar_prv_bare_compile.erl +++ b/apps/rebar/src/rebar_prv_bare_compile.erl @@ -1,4 +1,5 @@ -module(rebar_prv_bare_compile). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_clean.erl b/apps/rebar/src/rebar_prv_clean.erl index 010d67cad..f0fd66008 100644 --- a/apps/rebar/src/rebar_prv_clean.erl +++ b/apps/rebar/src/rebar_prv_clean.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_clean). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_common_test.erl b/apps/rebar/src/rebar_prv_common_test.erl index a2542cf20..f4df86bdc 100644 --- a/apps/rebar/src/rebar_prv_common_test.erl +++ b/apps/rebar/src/rebar_prv_common_test.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_common_test). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_compile.erl b/apps/rebar/src/rebar_prv_compile.erl index bd774edfc..9c8344032 100644 --- a/apps/rebar/src/rebar_prv_compile.erl +++ b/apps/rebar/src/rebar_prv_compile.erl @@ -1,4 +1,5 @@ -module(rebar_prv_compile). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_completion.erl b/apps/rebar/src/rebar_prv_completion.erl index a1971fd88..719857a6c 100644 --- a/apps/rebar/src/rebar_prv_completion.erl +++ b/apps/rebar/src/rebar_prv_completion.erl @@ -1,6 +1,7 @@ %% @doc Generates shell completion files based on available providers and their opts. %% @end -module(rebar_prv_completion). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_cover.erl b/apps/rebar/src/rebar_prv_cover.erl index 611795d98..4fbae1c9e 100644 --- a/apps/rebar/src/rebar_prv_cover.erl +++ b/apps/rebar/src/rebar_prv_cover.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_cover). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_deps.erl b/apps/rebar/src/rebar_prv_deps.erl index d00a1c8ee..34d725a9c 100644 --- a/apps/rebar/src/rebar_prv_deps.erl +++ b/apps/rebar/src/rebar_prv_deps.erl @@ -1,4 +1,5 @@ -module(rebar_prv_deps). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_deps_tree.erl b/apps/rebar/src/rebar_prv_deps_tree.erl index 3a697be37..59d86c9bd 100644 --- a/apps/rebar/src/rebar_prv_deps_tree.erl +++ b/apps/rebar/src/rebar_prv_deps_tree.erl @@ -1,4 +1,5 @@ -module(rebar_prv_deps_tree). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_dialyzer.erl b/apps/rebar/src/rebar_prv_dialyzer.erl index ca71e3d11..a5923310f 100644 --- a/apps/rebar/src/rebar_prv_dialyzer.erl +++ b/apps/rebar/src/rebar_prv_dialyzer.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_dialyzer). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_do.erl b/apps/rebar/src/rebar_prv_do.erl index 5f7aa124d..c2a883960 100644 --- a/apps/rebar/src/rebar_prv_do.erl +++ b/apps/rebar/src/rebar_prv_do.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_do). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_edoc.erl b/apps/rebar/src/rebar_prv_edoc.erl index c7782d22d..06c29e606 100644 --- a/apps/rebar/src/rebar_prv_edoc.erl +++ b/apps/rebar/src/rebar_prv_edoc.erl @@ -1,4 +1,5 @@ -module(rebar_prv_edoc). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_escriptize.erl b/apps/rebar/src/rebar_prv_escriptize.erl index 43250ed64..e7289055b 100644 --- a/apps/rebar/src/rebar_prv_escriptize.erl +++ b/apps/rebar/src/rebar_prv_escriptize.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_prv_escriptize). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_eunit.erl b/apps/rebar/src/rebar_prv_eunit.erl index 16b39f40d..6cc01cb38 100644 --- a/apps/rebar/src/rebar_prv_eunit.erl +++ b/apps/rebar/src/rebar_prv_eunit.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_eunit). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_get_deps.erl b/apps/rebar/src/rebar_prv_get_deps.erl index 020e50bf4..14ead6844 100644 --- a/apps/rebar/src/rebar_prv_get_deps.erl +++ b/apps/rebar/src/rebar_prv_get_deps.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_get_deps). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_help.erl b/apps/rebar/src/rebar_prv_help.erl index 961b21d16..6db05edff 100644 --- a/apps/rebar/src/rebar_prv_help.erl +++ b/apps/rebar/src/rebar_prv_help.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_help). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_install_deps.erl b/apps/rebar/src/rebar_prv_install_deps.erl index 5331c4cbc..73145c61d 100644 --- a/apps/rebar/src/rebar_prv_install_deps.erl +++ b/apps/rebar/src/rebar_prv_install_deps.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_prv_install_deps). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_local_install.erl b/apps/rebar/src/rebar_prv_local_install.erl index a01ab7b3e..8a669b66e 100644 --- a/apps/rebar/src/rebar_prv_local_install.erl +++ b/apps/rebar/src/rebar_prv_local_install.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_local_install). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_local_upgrade.erl b/apps/rebar/src/rebar_prv_local_upgrade.erl index 74d198da6..9e65aee55 100644 --- a/apps/rebar/src/rebar_prv_local_upgrade.erl +++ b/apps/rebar/src/rebar_prv_local_upgrade.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_local_upgrade). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_lock.erl b/apps/rebar/src/rebar_prv_lock.erl index eb8b96ade..79bbd0df0 100644 --- a/apps/rebar/src/rebar_prv_lock.erl +++ b/apps/rebar/src/rebar_prv_lock.erl @@ -1,4 +1,5 @@ -module(rebar_prv_lock). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_manifest.erl b/apps/rebar/src/rebar_prv_manifest.erl index 272a14c8a..3d8a0e3bd 100644 --- a/apps/rebar/src/rebar_prv_manifest.erl +++ b/apps/rebar/src/rebar_prv_manifest.erl @@ -3,6 +3,7 @@ %% =================================================================== -module(rebar_prv_manifest). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_new.erl b/apps/rebar/src/rebar_prv_new.erl index 6368303a6..7c852b4ab 100644 --- a/apps/rebar/src/rebar_prv_new.erl +++ b/apps/rebar/src/rebar_prv_new.erl @@ -1,4 +1,5 @@ -module(rebar_prv_new). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_packages.erl b/apps/rebar/src/rebar_prv_packages.erl index a6a2c81b0..a905e2d63 100644 --- a/apps/rebar/src/rebar_prv_packages.erl +++ b/apps/rebar/src/rebar_prv_packages.erl @@ -1,4 +1,5 @@ -module(rebar_prv_packages). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_path.erl b/apps/rebar/src/rebar_prv_path.erl index dd0608c1a..9ba23d812 100644 --- a/apps/rebar/src/rebar_prv_path.erl +++ b/apps/rebar/src/rebar_prv_path.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_path). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_plugins.erl b/apps/rebar/src/rebar_prv_plugins.erl index 6fd10b262..d76db77ce 100644 --- a/apps/rebar/src/rebar_prv_plugins.erl +++ b/apps/rebar/src/rebar_prv_plugins.erl @@ -1,4 +1,5 @@ -module(rebar_prv_plugins). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_plugins_upgrade.erl b/apps/rebar/src/rebar_prv_plugins_upgrade.erl index e525e3822..fdd7ade46 100644 --- a/apps/rebar/src/rebar_prv_plugins_upgrade.erl +++ b/apps/rebar/src/rebar_prv_plugins_upgrade.erl @@ -1,4 +1,5 @@ -module(rebar_prv_plugins_upgrade). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_release.erl b/apps/rebar/src/rebar_prv_release.erl index f44a488c2..12dfec58c 100644 --- a/apps/rebar/src/rebar_prv_release.erl +++ b/apps/rebar/src/rebar_prv_release.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_release). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_relup.erl b/apps/rebar/src/rebar_prv_relup.erl index 814604194..c5f7bdebd 100644 --- a/apps/rebar/src/rebar_prv_relup.erl +++ b/apps/rebar/src/rebar_prv_relup.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_relup). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_report.erl b/apps/rebar/src/rebar_prv_report.erl index 73e962470..e263b5f43 100644 --- a/apps/rebar/src/rebar_prv_report.erl +++ b/apps/rebar/src/rebar_prv_report.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_report). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_repos.erl b/apps/rebar/src/rebar_prv_repos.erl index 051591069..d807de418 100644 --- a/apps/rebar/src/rebar_prv_repos.erl +++ b/apps/rebar/src/rebar_prv_repos.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_repos). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_shell.erl b/apps/rebar/src/rebar_prv_shell.erl index 587162aa2..4f6f6bb99 100644 --- a/apps/rebar/src/rebar_prv_shell.erl +++ b/apps/rebar/src/rebar_prv_shell.erl @@ -26,6 +26,7 @@ %% ------------------------------------------------------------------- -module(rebar_prv_shell). +-moduledoc false. -author("Kresten Krab Thorup <krab@trifork.com>"). -author("Fred Hebert <mononcqc@ferd.ca>"). diff --git a/apps/rebar/src/rebar_prv_state.erl b/apps/rebar/src/rebar_prv_state.erl index 4fbcb6759..056efd1ab 100644 --- a/apps/rebar/src/rebar_prv_state.erl +++ b/apps/rebar/src/rebar_prv_state.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_state). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_tar.erl b/apps/rebar/src/rebar_prv_tar.erl index e54ab6de5..6d00d53b4 100644 --- a/apps/rebar/src/rebar_prv_tar.erl +++ b/apps/rebar/src/rebar_prv_tar.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_tar). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_unlock.erl b/apps/rebar/src/rebar_prv_unlock.erl index f0b2298d7..7e94415ee 100644 --- a/apps/rebar/src/rebar_prv_unlock.erl +++ b/apps/rebar/src/rebar_prv_unlock.erl @@ -1,4 +1,5 @@ -module(rebar_prv_unlock). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_update.erl b/apps/rebar/src/rebar_prv_update.erl index 4c820c5b3..1b1c44a12 100644 --- a/apps/rebar/src/rebar_prv_update.erl +++ b/apps/rebar/src/rebar_prv_update.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_update). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_upgrade.erl b/apps/rebar/src/rebar_prv_upgrade.erl index 63ad951e3..450917448 100644 --- a/apps/rebar/src/rebar_prv_upgrade.erl +++ b/apps/rebar/src/rebar_prv_upgrade.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_upgrade). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_vendor.erl b/apps/rebar/src/rebar_prv_vendor.erl index 7e1cafb27..456076480 100644 --- a/apps/rebar/src/rebar_prv_vendor.erl +++ b/apps/rebar/src/rebar_prv_vendor.erl @@ -1,4 +1,5 @@ -module(rebar_prv_vendor). +-moduledoc false. -behaviour(provider). -export([init/1, diff --git a/apps/rebar/src/rebar_prv_version.erl b/apps/rebar/src/rebar_prv_version.erl index bcc5f6c66..fc635dc73 100644 --- a/apps/rebar/src/rebar_prv_version.erl +++ b/apps/rebar/src/rebar_prv_version.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_version). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_prv_xref.erl b/apps/rebar/src/rebar_prv_xref.erl index e2d504e2b..a7223ad8c 100644 --- a/apps/rebar/src/rebar_prv_xref.erl +++ b/apps/rebar/src/rebar_prv_xref.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_prv_xref). +-moduledoc false. -behaviour(provider). diff --git a/apps/rebar/src/rebar_relx.erl b/apps/rebar/src/rebar_relx.erl index bfb4674d0..6c152eeba 100644 --- a/apps/rebar/src/rebar_relx.erl +++ b/apps/rebar/src/rebar_relx.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et -module(rebar_relx). +-moduledoc false. -export([do/2, opt_spec_list/0, diff --git a/apps/rebar/src/rebar_string.erl b/apps/rebar/src/rebar_string.erl index 24989e7fb..a45c62cbf 100644 --- a/apps/rebar/src/rebar_string.erl +++ b/apps/rebar/src/rebar_string.erl @@ -3,6 +3,7 @@ %%% %%% Also contains other useful string functionality. -module(rebar_string). +-moduledoc false. %% Compatibility exports -export([join/2, split/2, lexemes/2, trim/1, trim/3, uppercase/1, lowercase/1, chr/2]). %% Util exports diff --git a/apps/rebar/src/rebar_templater.erl b/apps/rebar/src/rebar_templater.erl index ce1959397..0507b1188 100644 --- a/apps/rebar/src/rebar_templater.erl +++ b/apps/rebar/src/rebar_templater.erl @@ -25,6 +25,7 @@ %% THE SOFTWARE. %% ------------------------------------------------------------------- -module(rebar_templater). +-moduledoc false. -export([new/4, list_templates/1, diff --git a/apps/rebar/src/rebar_uri.erl b/apps/rebar/src/rebar_uri.erl index ac32f95ce..24f1a740a 100644 --- a/apps/rebar/src/rebar_uri.erl +++ b/apps/rebar/src/rebar_uri.erl @@ -1,5 +1,6 @@ %%% @doc multi-OTP version compatibility shim for working with URIs -module(rebar_uri). +-moduledoc false. -export([ parse/1, parse/2, scheme_defaults/0, diff --git a/apps/rebar/src/rebar_user.erl b/apps/rebar/src/rebar_user.erl index f20142dc1..89a2820a6 100644 --- a/apps/rebar/src/rebar_user.erl +++ b/apps/rebar/src/rebar_user.erl @@ -27,6 +27,7 @@ %% %CopyrightEnd% %% -module(rebar_user). +-moduledoc false. -compile(inline). %% Basic standard i/o server for user interface port. diff --git a/apps/rebar/src/vendored/r3_hex_api.erl b/apps/rebar/src/vendored/r3_hex_api.erl index 33d4f8b28..149d8856a 100644 --- a/apps/rebar/src/vendored/r3_hex_api.erl +++ b/apps/rebar/src/vendored/r3_hex_api.erl @@ -3,6 +3,7 @@ %% @doc %% Hex HTTP API -module(r3_hex_api). +-moduledoc false. -export([ delete/2, diff --git a/apps/rebar/src/vendored/r3_hex_api_key.erl b/apps/rebar/src/vendored/r3_hex_api_key.erl index bd549eda1..25f315e7d 100644 --- a/apps/rebar/src/vendored/r3_hex_api_key.erl +++ b/apps/rebar/src/vendored/r3_hex_api_key.erl @@ -3,6 +3,7 @@ %% @doc %% Hex HTTP API - Keys. -module(r3_hex_api_key). +-moduledoc false. -export([ list/1, get/2, diff --git a/apps/rebar/src/vendored/r3_hex_api_package.erl b/apps/rebar/src/vendored/r3_hex_api_package.erl index 7cbbdf472..2bc8a5918 100644 --- a/apps/rebar/src/vendored/r3_hex_api_package.erl +++ b/apps/rebar/src/vendored/r3_hex_api_package.erl @@ -3,6 +3,7 @@ %% @doc %% Hex HTTP API - Packages. -module(r3_hex_api_package). +-moduledoc false. -export([get/2, search/3]). %% @doc diff --git a/apps/rebar/src/vendored/r3_hex_api_package_owner.erl b/apps/rebar/src/vendored/r3_hex_api_package_owner.erl index 7bcd0f276..bf5520728 100644 --- a/apps/rebar/src/vendored/r3_hex_api_package_owner.erl +++ b/apps/rebar/src/vendored/r3_hex_api_package_owner.erl @@ -3,6 +3,7 @@ %% @doc %% Hex HTTP API - Package Owners. -module(r3_hex_api_package_owner). +-moduledoc false. -export([ add/5, delete/3, diff --git a/apps/rebar/src/vendored/r3_hex_api_release.erl b/apps/rebar/src/vendored/r3_hex_api_release.erl index f10585dc5..13490a908 100644 --- a/apps/rebar/src/vendored/r3_hex_api_release.erl +++ b/apps/rebar/src/vendored/r3_hex_api_release.erl @@ -3,6 +3,7 @@ %% @doc %% Hex HTTP API - Releases. -module(r3_hex_api_release). +-moduledoc false. -export([ delete/3, get/3, diff --git a/apps/rebar/src/vendored/r3_hex_api_user.erl b/apps/rebar/src/vendored/r3_hex_api_user.erl index 70545c349..8a487db5f 100644 --- a/apps/rebar/src/vendored/r3_hex_api_user.erl +++ b/apps/rebar/src/vendored/r3_hex_api_user.erl @@ -3,6 +3,7 @@ %% @doc %% Hex HTTP API - Users. -module(r3_hex_api_user). +-moduledoc false. -export([ create/4, get/2, diff --git a/apps/rebar/src/vendored/r3_hex_core.erl b/apps/rebar/src/vendored/r3_hex_core.erl index 441d2b50d..0ff097795 100644 --- a/apps/rebar/src/vendored/r3_hex_core.erl +++ b/apps/rebar/src/vendored/r3_hex_core.erl @@ -62,6 +62,7 @@ %% `134_217_728' (128 MiB). Set to `infinity' to not enforce the limit. -module(r3_hex_core). +-moduledoc false. -export([default_config/0]). -export_type([config/0]). diff --git a/apps/rebar/src/vendored/r3_hex_erl_tar.erl b/apps/rebar/src/vendored/r3_hex_erl_tar.erl index cfd62bc8b..a1fb28655 100644 --- a/apps/rebar/src/vendored/r3_hex_erl_tar.erl +++ b/apps/rebar/src/vendored/r3_hex_erl_tar.erl @@ -43,6 +43,7 @@ %% http://www.gnu.org/software/tar/manual/html_node/Standard.html %% http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html -module(r3_hex_erl_tar). +-moduledoc false. -export([init/3, create/2, create/3, diff --git a/apps/rebar/src/vendored/r3_hex_filename.erl b/apps/rebar/src/vendored/r3_hex_filename.erl index d3ff344c1..b6febe254 100644 --- a/apps/rebar/src/vendored/r3_hex_filename.erl +++ b/apps/rebar/src/vendored/r3_hex_filename.erl @@ -28,6 +28,7 @@ %% -module(r3_hex_filename). +-moduledoc false. -export([safe_relative_path/1]). safe_relative_path(Path) -> diff --git a/apps/rebar/src/vendored/r3_hex_http.erl b/apps/rebar/src/vendored/r3_hex_http.erl index 5e79a8ae1..26438c152 100644 --- a/apps/rebar/src/vendored/r3_hex_http.erl +++ b/apps/rebar/src/vendored/r3_hex_http.erl @@ -3,6 +3,7 @@ %% @doc %% HTTP contract. -module(r3_hex_http). +-moduledoc false. -export([request/5]). -ifdef(TEST). -export([user_agent/1]). diff --git a/apps/rebar/src/vendored/r3_hex_http_httpc.erl b/apps/rebar/src/vendored/r3_hex_http_httpc.erl index 3af77e2c1..a9f2cde0e 100644 --- a/apps/rebar/src/vendored/r3_hex_http_httpc.erl +++ b/apps/rebar/src/vendored/r3_hex_http_httpc.erl @@ -13,6 +13,7 @@ %% {@link httpc:request/5} for a list of available HTTP options. -module(r3_hex_http_httpc). +-moduledoc false. -behaviour(r3_hex_http). -export([request/5]). diff --git a/apps/rebar/src/vendored/r3_hex_licenses.erl b/apps/rebar/src/vendored/r3_hex_licenses.erl index ba42b071b..7270f98e3 100644 --- a/apps/rebar/src/vendored/r3_hex_licenses.erl +++ b/apps/rebar/src/vendored/r3_hex_licenses.erl @@ -5,6 +5,7 @@ %% File generated by https://github.com/supersimple/spdx. Do not edit manually. -module(r3_hex_licenses). +-moduledoc false. -export([valid/1]). diff --git a/apps/rebar/src/vendored/r3_hex_pb_names.erl b/apps/rebar/src/vendored/r3_hex_pb_names.erl index e05ed1ce2..c1d916406 100644 --- a/apps/rebar/src/vendored/r3_hex_pb_names.erl +++ b/apps/rebar/src/vendored/r3_hex_pb_names.erl @@ -7,6 +7,7 @@ %% Generated by gpb_compile version 4.21.1 %% Version source: file -module(r3_hex_pb_names). +-moduledoc false. -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). diff --git a/apps/rebar/src/vendored/r3_hex_pb_package.erl b/apps/rebar/src/vendored/r3_hex_pb_package.erl index 03eeae97a..3533be7eb 100644 --- a/apps/rebar/src/vendored/r3_hex_pb_package.erl +++ b/apps/rebar/src/vendored/r3_hex_pb_package.erl @@ -7,6 +7,7 @@ %% Generated by gpb_compile version 4.21.1 %% Version source: file -module(r3_hex_pb_package). +-moduledoc false. -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). diff --git a/apps/rebar/src/vendored/r3_hex_pb_signed.erl b/apps/rebar/src/vendored/r3_hex_pb_signed.erl index d3891a41f..1ef6c2124 100644 --- a/apps/rebar/src/vendored/r3_hex_pb_signed.erl +++ b/apps/rebar/src/vendored/r3_hex_pb_signed.erl @@ -7,6 +7,7 @@ %% Generated by gpb_compile version 4.21.1 %% Version source: file -module(r3_hex_pb_signed). +-moduledoc false. -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). diff --git a/apps/rebar/src/vendored/r3_hex_pb_versions.erl b/apps/rebar/src/vendored/r3_hex_pb_versions.erl index b9c5d8f60..aac8df1c9 100644 --- a/apps/rebar/src/vendored/r3_hex_pb_versions.erl +++ b/apps/rebar/src/vendored/r3_hex_pb_versions.erl @@ -7,6 +7,7 @@ %% Generated by gpb_compile version 4.21.1 %% Version source: file -module(r3_hex_pb_versions). +-moduledoc false. -export([encode_msg/2, encode_msg/3]). -export([decode_msg/2, decode_msg/3]). diff --git a/apps/rebar/src/vendored/r3_hex_registry.erl b/apps/rebar/src/vendored/r3_hex_registry.erl index 3d17fa37c..3d33a8fbf 100644 --- a/apps/rebar/src/vendored/r3_hex_registry.erl +++ b/apps/rebar/src/vendored/r3_hex_registry.erl @@ -3,6 +3,7 @@ %% @doc %% Functions for encoding and decoding Hex registries. -module(r3_hex_registry). +-moduledoc false. -export([ encode_names/1, decode_names/2, diff --git a/apps/rebar/src/vendored/r3_hex_repo.erl b/apps/rebar/src/vendored/r3_hex_repo.erl index cd26291ce..04d8bfecf 100644 --- a/apps/rebar/src/vendored/r3_hex_repo.erl +++ b/apps/rebar/src/vendored/r3_hex_repo.erl @@ -3,6 +3,7 @@ %% @doc %% Repo API. -module(r3_hex_repo). +-moduledoc false. -export([ get_names/1, get_versions/1, diff --git a/apps/rebar/src/vendored/r3_hex_tarball.erl b/apps/rebar/src/vendored/r3_hex_tarball.erl index 233b922a3..1bce3b0ae 100644 --- a/apps/rebar/src/vendored/r3_hex_tarball.erl +++ b/apps/rebar/src/vendored/r3_hex_tarball.erl @@ -3,6 +3,7 @@ %% @doc %% Functions for creating and unpacking Hex tarballs. -module(r3_hex_tarball). +-moduledoc false. -export([ create/2, create/3, create_docs/1, create_docs/2, diff --git a/apps/rebar/src/vendored/r3_safe_erl_term.xrl b/apps/rebar/src/vendored/r3_safe_erl_term.xrl index 2f3cd22f8..2b3f15c6a 100644 --- a/apps/rebar/src/vendored/r3_safe_erl_term.xrl +++ b/apps/rebar/src/vendored/r3_safe_erl_term.xrl @@ -24,7 +24,7 @@ Rules. {WS}+ : skip_token. Erlang code. - +-moduledoc false. -export([terms/1]). terms(Tokens) -> diff --git a/docs/extending/custom_compiler_modules.md b/docs/extending/custom_compiler_modules.md index 99e53dcf1..2eeca8737 100644 --- a/docs/extending/custom_compiler_modules.md +++ b/docs/extending/custom_compiler_modules.md @@ -56,7 +56,7 @@ needed_files(G, ["/path/to/all/files.erl", ...], [{".beam", "/path/to/ebin"}], A %% Compilation callback with the ability to track build artifacts in the DAG itself. %% Introduced in 3.14. Prior to this version, refer to `compile/4'. -compile_and_track("/path/to/file.erl", [{".beam, "/path/to/ebin"}], +compile_and_track("/path/to/file.erl", [{".beam", "/path/to/ebin"}], AppOptDict, CompilerOpts) -> %% Successfully built a file, tying it to artifacts with optional metadata {ok, [{"/path/to/file.erl", "path/to/ebin/file.beam", Metadata}]} | diff --git a/docs/extending/custom_dep_resources.md b/docs/extending/custom_dep_resources.md index 0bfdd0966..591ab4898 100644 --- a/docs/extending/custom_dep_resources.md +++ b/docs/extending/custom_dep_resources.md @@ -228,6 +228,6 @@ needs_update_(Dir, {Tag, Path}) -> ... ``` -Note that if you resource really needs the new API to work, backwards compatibility will be difficult to achieve since whenever it will be called, it won't have all the information of the new API. +Note that if your resource really needs the new API to work, backwards compatibility will be difficult to achieve since whenever it will be called, it won't have all the information of the new API. This approach is mostly useful when you can provide an acceptable (even if degraded) user experience with the old API.