rebar

v0.0.0+build.5492.ref67808dff

Rebar3

What is Rebar3?

Why Rebar3?

Should I Use Rebar3?

Getting Started

Documentation

Features

Migrating from rebar2

Additional Resources

What is Rebar3

Rebar3 is an Erlang tool that makes it easy to create, develop, and release Erlang libraries, applications, and systems in a repeatable manner.

Rebar3 will:

respect and enforce standard Erlang/OTP conventions for project structure so they are easily reusable by the community;

manage source dependencies and Erlang packages while ensuring repeatable builds;

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 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 flexible enough that even other languages on the Erlang VM will use it as a build tool.

Why Rebar3

Rebar3 is the spiritual successor to rebar 2.x, which was the first usable build tool for Erlang that ended up seeing widespread community adoption. It however had several shortcomings that made it difficult to use with larger projects or with teams with users new to Erlang.

Rebar3 was our attempt at improving over the legacy of Rebar 2.x, providing the features we felt it was missing, and to provide a better environment in which newcomers joining our teams could develop.

Should I use Rebar3?

If your main language for your system is Erlang, that you value repeatable builds and want your various tools to integrate together, we do believe Rebar3 is the best experience you can get.

Getting Started

Compatibility between Rebar3 and Erlang/OTP

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, but installing rebar3 can be done by any of the ways described below

Latest stable compiled version:

$ wget https://s3.amazonaws.com/rebar3/rebar3 && chmod +x rebar3

From Source (assuming you have a full Erlang install):

$ git clone https://github.com/erlang/rebar3.git
$ cd rebar3
$ ./bootstrap

Stable versions can also be obtained from the releases page.

The rebar3 escript can also extract itself with a run script under the user's home directory:

$ ./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=~/.cache/rebar3/bin:$PATH

To keep it up to date after you've installed rebar3 this way you can use rebar3 local upgrade which fetches the latest stable release and extracts to the same place as above. A nightly version can also be obtained if desired.

Rebar3 may also be available on various OS-specific package managers such as FreeBSD Ports. Those are maintained by the community and Rebar3 maintainers themselves are generally not involved in that process.

If you do not have a full Erlang install, we recommend using erln8 or kerl. For binary packages, use those provided by Erlang Solutions, but be sure to choose the "Standard" download option or you'll have issues building projects.

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 3 newest major Erlang releases are supported at any given time: if the newest version is OTP-27, building with versions as old as OTP-25 will be supported, and produce an executable that will work with those that follow.

Documentation

Rebar3 documentation is maintained on https://rebar3.org/docs

Features

Rebar3 supports the following features or tools by default, and may provide many others via the plugin ecosystem:

features | Description
Command composition | Rebar3 allows multiple commands to be run in sequence by calling rebar3 do <task1>,<task2>,...,<taskN>.
Command dependencies | Rebar3 commands know their own dependencies. If a test run needs to fetch dependencies and build them, it will do so.
Command namespaces | Allows multiple tools or commands to share the same name.
Compiling | Build the project, including fetching all of its dependencies by calling rebar3 compile
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. 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.
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 providing an easy way to run all your applications on a system where Erlang is installed
Eunit | The test framework can be run by calling rebar3 eunit
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 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. 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 in the docs.
Releases | Rebar3 supports building 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 are also supported, and plugins can also add their own.
Xref | Run cross-reference analysis on the project with xref by calling rebar3 xref.

Migrating From rebar2

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 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 rather than maintaining them in core rebar, and moving release builds from reltool to relx.

Additional Resources

In the case of problems that cannot be solved through documentation or examples, you may want to try to contact members of the community for help. The community is also where you want to go for questions about how to extend rebar, fill in bug reports, and so on.

If you need quick feedback, you can try the #rebar channel on irc.freenode.net or the #rebar3 channel on erlanger.slack.com. Be sure to check the documentation 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.

General rebar community resources and links can be found at Community | About Us

To contribute to rebar3, please refer to CONTRIBUTING.

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 section 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 as an executable escript. 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:

$ ./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:

$ 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:

@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:

$ 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:

$ ./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:

$ 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 to learn more on how to use rebar3, and follow it with Workflow for broader usage.

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, 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:

$ 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 and to learn how to create and use custom templates go to the templates tutorial.

Adding Dependencies

Dependencies are listed in rebar.config file under the deps key:

{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:

{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

Building

Only one command, compile, is required to fetch dependencies and compile all applications.

$ 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.

_build/
└── default
  └── lib
    └── elli

More about profiles and the _build directory can be found in the profiles documentation page.

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:

{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.

_build/
   └── test
     └── lib
       └── meck

Releases and Target Systems

Releases are built using relx.

Creating a new project with a release structure and default relx config in the rebar.config file run:

$ 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.

{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).

$ 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:

$ 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.

Workflow

Recommended steps and possible default configurations for various tasks.

If you know the basic commands, have gone through Getting Started, Basic Usage, and have a brief understanding of Releases, 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 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 declaregit_subdir dependencies

Setting up Dependencies

The basic configuration of a project should do at least two things:

Always track the rebar.lock file

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

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 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:

Update the index cache

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:

$ 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:

$ 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:

{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)

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

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.

{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]}
    ]}
]}.

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:

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

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

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 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.
--case | Comma separated list of strings | List of test cases to run. See the Common Test Documentation.
--spec | Comma separated list of strings | List of 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.
--allow_user_terms | Boolean | Allow user defined config values in config files. See the Common Test Documentation.
--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. Default: _build/test/logs
--logopts | Comma separated list of strings | Set common test logging options. See the Common Test Documentation. 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 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 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:

{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.

Runs in the test profile.

get-deps

Not Required

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 for production.

Option | Type | Description
--config | string | Allows to load a config file, 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.

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 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:

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:

{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.

{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/:

{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:

{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:

{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.

{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.

{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:

{erl_first_files, ["src/mymodule.erl", "src/mymodule.erl"]}.

And some other general options exist:

{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 with {xrl_opts, [...]}

SNMP MIB Compiler with {mib_opts, [...]}

Yecc compiler 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:

{erlc_compiler,[{recursive,boolean()}]}.

Disable or enable recursive compiling on src_dirs:

{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:

{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:

{erlc_compiler,[{recursive,false}]},
{erl_opts,[{src_dirs,["src",{"other_src",[{recursive,true}]}]}]}.

Disable recursive compiling on test and other dirs:

{erl_opts, [
            {extra_src_dirs,[
                    {"test", [{recursive,boolean()}]},
                    {"other_dir", [{recursive,boolean()}]}]}
            ]
}.

Completion

{completion,
    [{aliases,["rebar", "r3"]},
     {file, "/home/user/completion/_rebar3"},
     {shell, bash}]}.

Options mirror those specified in Commands arguments.

Common Test

{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

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 arguments.

Cover

Enable code coverage in tests 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

-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.

For information on suppressing warnings in modules see the Requesting or Suppressing Warnings in Source Files 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:

{dist_node, [
    {setcookie, 'atom-cookie'},
    {name | sname, 'nodename'}
]}.

Directories

The following options exist for directories; the value chosen below is the default value

%% 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 can be put in {edoc_opts, [...]}.

Escript

Full details at the escriptize command. Example configuration values below.

{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

{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

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 plugin to authenticate, rebar3 hex auth. This creates a separate config file ~/.config/rebar3/hex.config storing the keys.

{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.

{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.

{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.

{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:

{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

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.

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.

-type hook() :: {atom(), string()}
              | {string(), atom(), string()}.

{pre_hooks, [hook()]}.
{post_hooks, [hook()]}.
{shell_hooks_env, [{string(), string()}].

An example for building merl with Rebar3 by using pre_hooks:

{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

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 | $REBAR_ROOT_DIR/_checkouts
REBAR_CHECKOUTS_OUT_DIR | Directory where 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 | $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) - recursive option is ignored, paths are returned as is | src
ERLANG_ARCH | Wordsize of the system | Return value of rebar_api:wordsize()
ERLANG_TARGET | Description of the system | Return value of rebar_api:get_arch()
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.

{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

Plugins

See Plugins. 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

{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:

-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

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 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, which builds standalone systems.

Dependencies fit any of the following formats:

{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 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:

{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, and sent to the maintainers with a pull request.

Dependencies and Profiles

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 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. 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

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 mandates semver) hex dependencies can be specified using semver-like syntax:

{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:

$ rebar3 update
===> Updating package index...

To use a CDN other than the default, such as one of the official mirrors add to your project's rebar.config or to ~/.config/rebar3/rebar.config:

{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:

_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:

  A
 / \
B   C

the dependencies A, B, and C will be fetched.

However, for more complex trees, such as:

   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?

   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:

  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:

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:

    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:

    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:

$ 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 for details.

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:

calling rebar as rebar3 as <profile> <command> or rebar3 as <profile1>,<profile2> <command>

by a given Rebar3 command. For example, the eunit and ct commands always add a test profile to the run.

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:

{profiles, [{ProfileName1, [Options, ...]},
            {ProfileName2, [Options, ...]}]}.

For example, a test profile that adds the meck dependency only for test runs could be defined as:

{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:

{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:

default, the de-facto profile for all runs, corresponding to the overall rebar.config file

prod, in this case probably used to generate full releases without symlinks, and with stricter compiler options

native, to force compiling with HiPE, for faster mathematical code

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:

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.

rebar3 as test ct: will run the same as before. Profiles are applied only once.

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).

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.

rebar3 release will build the release only as the default profile.

rebar3 as prod release will build the release without development mode, with a stricter set of compiler options.

rebar3 as prod, native release will build the release as with the last command, but while also compiling modules to native mode.

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:

default

The REBAR_PROFILE value, if any

the profiles specified in the as part of the command line

the profiles specified by each individual command

Profiles are therefore a composable way to specify configuration subsets in a contextual manner.

Locking Dependencies

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, 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:

{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

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.

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:

{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:

{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:

{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-Test

Hex Package Management

Port Compiler

Run Release

Alias

QuickCheck

PropEr

Diameter

ErlyDTL

Neotoma

Protocol buffers

Appup

Vendoring 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.

{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.

{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.

{plugins, [rebar3_hex]}.

For usage go to the Hex Package Management section. To view the package go to hex.pm and to open issues GitHub.

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 and issues at GitHub.

In your project's rebar.config, add the pc plugin and calls to it in provider_hooks for compile and clean:

{plugins, [pc]}.

{provider_hooks,
 [
  {pre,
   [
    {compile, {pc, compile}},
    {clean, {pc, clean}}
   ]
  }
 ]
}.

Configuration variables available:

%% 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 and hex.pm.

{plugins, [rebar3_run]}.

Alias

The alias plugin has been added to Rebar3 starting with version 3.5.0. See 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 and Hex.pm.

{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 properties. Found on GitHub and Hex.pm.

{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 is a free alternative to Quviq QuickCheck. The plugin is available on Hex as a package or GitHub

%% 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 plugin compiles diameter .dia files in Rebar3 projects.

{plugins, [rebar3_diameter_compiler]}.

Add hooks to automatically compile and clean the diameter dictionaries:

{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 compiler has been moved to a separate plugin.

{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.
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. This plugin is published to Hex so can be added to your project with:

{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:

{provider_hooks, [
    {pre, [{compile, {neotoma, compile}}]}
]}.

Protocol Buffers

Using gpb

Plugin for building .proto files using Tomas Abrahamsson's gpb. This plugin is published to Hex so can be added to your project with:

{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:

{provider_hooks, [
    {pre, [{compile, {protobuf, compile}}]}
]}.

Full documentation available in the plugin's README.

Appup

Plugin for generating, compiling and validating .appup.src files. This plugin is published to Hex so can be added to your project with:

{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:

{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:

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

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 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:

# 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:

{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:

{plugins, [
   rebar3_path_deps
]}.

Then just compile your application:

$ 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.

{plugins, [rebar3_vendor]}.

To store the fetched dependencies under ./deps/ for committing:

rebar3 vendor store

To take the vendored dependencies from ./deps/ and place them under the build directory in the appropriate place:

rebar3 vendor apply

SVN Dependencies

The 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 to use it.

Elixir Dependencies

Starting with Rebar3 3.7.0, Mix dependencies are supported with the 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:

{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:

{overlay, [{copy, "{{base_dir}}/consolidated", "releases/{{release_version}}/consolidated"}]}

And update your vm.args.src to include:

-pa releases/${REL_VSN}/consolidated

Elixir with Older Rebar3 releases

For Rebar3 versions prior to 3.7.0, the 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.

Config Scripts

With rebar.config and *.app.src you can make use of dynamic configuration based on file: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 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.

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:

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.

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

EUnit

Coverage

Common Test

To run common_test suites:

$ 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. This behaviour can however be turned on manually with the right compilation options.

To run only specific test suites:

$ 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:

$ ct_run -pa `rebar3 path` ...

The ct command runs as the test profile, by default. See Profiles for details.

For available options and their usage see Commands or:

$ rebar3 help ct

EUnit

To run all EUnit test suites:

$ 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 for details.

For available options and their usage see Commands or:

$ rebar3 help eunit

Test Selection

The following flags can be provided standalone or combined.

Apps

To run tests for specific apps only:

$ 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:

$ 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:

$ rebar3 eunit --test=mod1:test1+test2,mod2:test1

The format is a comma separated list of test functions.

Generators

To run specific test case generators only:

$ rebar3 eunit --generator=mod1:gen1+gen2,mod2:gen1

The format is a comma separated list of test functions.

Files

To run tests for specific files only:

$ 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:

$ 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. Rebar3 will do its best to ensure any modules specified in tests are compiled and made available on the code path.

Examples:

{eunit_tests, [{module, smoke_tests}]}.

{eunit_tests, [{inparallel, mod1}]}.

eunit_opts

The default EUnit options can be configured, as documented here.

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:

 -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:

{eunit_opts, [no_tty, {report, {my_reporter, Opts}}]}.

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:

$ 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

Publishing Packages

For package management rebar3 uses hex.pm, a package manager for Erlang and Elixir packages.

Basic usage

You should read the docs 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.

$ 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 run:

$ 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 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 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 for more information.

$ rebar3 hex publish

cut is available to provide some additional functionality around versioning and git tags. See the docs for more information.

$ 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.

$ rebar3 hex owner [add | remove | list | transfer] <package> <email>

See the docs 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 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.

{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 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:

$ 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.

$ 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 on hexpm for more setup and usage instructions. See the docs for detailed documentation for all available providers.

Releases

What are releases and target systems anyway?

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 from Adopting Erlang.

Getting Started

Add a relx section to your project's rebar.config:

{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.

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:

{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:

{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

{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:

% 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):

 {<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.

{include_src, false}

Application exclusions

The following allows you to remove specific applications from the output release.

{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.

{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:

{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

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:

[
  {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:

{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:

{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.

## 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:

{vm_args, "config/vm_prod.args"}

or:

{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:

[
  {<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:

{sys_config, "config/sys_prod.config"}

{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 and in the systools docs.

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.

%% sys.config.src
[
  {appname,
   [
    {port, ${PORT:-8080}},
    {log_level, ${LOG_LEVEL:-info}},
    {log_root, "${LOG_ROOT:-/var/log/appname}"}
   ]}
].

# vm.args.src
-name ${NODE_NAME}

%% 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:

# vm.args
-name ${NODE_NAME}

%% sys.config
[
 {appname, [{port, "${PORT}"}]}
].

And then be used to start multiple nodes of the same release with different name.

#!/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.

{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). 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:

%% 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.

%% base.config
{data_dir, "/data/yolo_app"}.
{version, "1.0.0"}.
{run_user, "root"}.

%% dev.config
%% Include the base config
"./base.config".
%% The build we have
{build, "dev"}.

%% 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:

$ 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:

$ 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:

{profiles, [{prod, [{relx, [{mode, minimal},
                            {system_libs, false}]}]}]}.

Or manually set include_erts to false:

{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:

{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:

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.

For a detailed workflow including version increments and appup generation checkout Richard Jones 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.

{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:

%% 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:

{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:

#!/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

relflow

Releases chapter from Adopting Erlang

Releases chapter from Learn You Some Erlang

OTP release documentation

OTP target system documentation

Building Plugins

Rebar3's system is based on the concept of 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

Reference

Provider Interface

List of Possible Dependencies

Rebar API

Rebar State Manipulation

Namespaces

Tutorial

First Version

Optionally Search Deps

Using a Plugin

To use the a plugin, add it to the rebar.config:

{plugins, [
  {plugin_name, {git, "git@host:user/name-of-plugin.git", {tag, "1.0.0"}}}
]}.

Then you can just call it directly:

$ 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:

-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 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.
all_deps(State) -> DepsList | Returns a list of dependencies. These can be handled using rebar_app_info.
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 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

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.

The first step is to create a new OTP Application that will contain the plugin:

→ 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:

-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:

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.

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:

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:

{plugins, [
  {todo, {git, "git@bitbucket.org:ferd/rebar3-todo-plugin.git", {branch, "master"}}}
]}.

Then you can just call it directly:

→ 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:

-define(DEPS, [install_deps]).

We can add the option to the list we use to configure the provider in init/1:

{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:

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:

===> 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:

→ 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:

-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.

Templates

Default Variables

Global Variables

Batteries-Included Templates

Custom Templates

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:

{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:

$ ./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>:

$ ./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.

A template can be run by calling:

$ ./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).

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:

{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:

{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 template. All the paths are relative to the current working directory.

Let's create the template file:

-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:

$ ./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:

$ ./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:

$ ./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.

Building C/C++

No port compiler

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.

$ 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 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.

{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.

#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.

-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 will not, and is preferred here.

Run rebar3 shell and give the NIF a try.

$ 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

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

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

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:

$ 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:

$ 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:

{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:

-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:

$ 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:

-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.

$ 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:

%% 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:

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:

-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:

$ 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:

%% 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 or randomized runs in order to detect weird conditions and automatically trigger a break point when required.

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:

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:

apps/app1/src/*.{erl,app.src}
apps/app2/src/*.{erl,app.src}
apps/app3/src/*.{erl,app.src}

or

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, and Publishing Packages

moving your dependencies like meck and PropEr to the test profile 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 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.

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 Makefiles or use the port compiler plugin (backwards compatible with rebar 2.x)

if you used QuickCheck or PropEr, you have to use the plugin for that

diameter has its own plugin

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

Others

if you are still using Makefiles to create shortcut commands, consider using aliases

for code coverage, you will want to use the 'cover' command, as in 'rebar3 do eunit, cover'. See the 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, 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:

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.

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

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.

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.

Current Interface

The following callbacks are defined:

%% 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:

%% 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}.

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

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:

%% 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, find application state, and generally work with the rebar_state, rebar_app_info, rebar_dir, and the new rebar_paths modules.

An example of a plugin making use of this functionality is rebar3_path_deps. Rebar3's own hex package resource uses this API.

A resource plugin is initialized the same way as any other plugin would:

-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:

-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.

-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, rebar_hg_resource and rebar_pkg_resource.

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:

-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:

{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:

-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 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.

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:

{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.

The definitions are similar to what was done in the Building Plugins 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.

-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:

-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:

-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:

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:

{provider_hooks, [
    {pre, [{compile, {exc, compile}}]}
]}.

About Us

Community

Issue Tracker

Github Discussions

Slack: #rebar3 on Erlang Slack

IRC: #rebar on freenode

Contribution guidelines

Credits

Source Contributors (including rebar 2.x contributors prior to forking)

Rebar3 logo by Francis Tseng.

Maintainers with admin rights:

@tsloughter

@ferd

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 (@ferd)

Tristan Sloughter (@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

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:

The issue is received and discussed privately by the maintainers

A fix is prepared and reviewed between maintainers

When ready, the fix will be committed to the repository and a release will be cut

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.

rebar_api

Packages rebar.hrl features and macros into a more generic API that can be used by plugin builders.

Summary

Types

rebar_dict/0

rebar_digraph/0

Functions

abort()

Interrupts program flow

abort(Str, Args)

like error/2, except it also raises an exception to interrupt program flow.

add_deps_to_path(State)

Add deps to the code path

console(Str, Args)

Prints to the console, including a newline

debug(Str, Args)

logs with severity debug

error(Str, Args)

logs with severity error

expand_env_variable(InStr, VarName, RawVarValue)

Given env. variable FOO we want to expand all references to it in InStr. References can have two forms: $FOO and ${FOO} The end of form $FOO is delimited with whitespace or EOL

get_arch()

returns the system architecture, in strings like "19.0.4-x86_64-unknown-linux-gnu-64".

info(Str, Args)

logs with severity info

processing_base_dir(State)

checks if the current working directory is the base directory for the project.

restore_code_path(State)

Revert to only having the beams necessary for running rebar3 and plugins in the path

set_paths(List, State)

Set code paths. Takes arguments of the form [plugins, deps] or [deps, plugins] and ensures the project's app and dependencies are set in the right order for the next bit of execution

ssl_opts(Url)

returns the SSL options adequate for the project based on its configuration, including for validation of certs.

unset_paths(List, State)

Unsets code paths. Takes arguments of the form [plugins, deps] or [deps, plugins] and ensures the paths are no longer active.

warn(Str, Args)

logs with severity warn

wordsize()

returns the size of a word on the system, as a string

Types

rebar_dict/0

-type rebar_dict() :: dict:dict().

rebar_digraph/0

-type rebar_digraph() :: digraph:graph().

Functions

abort()

-spec abort() -> no_return().

Interrupts program flow

abort(Str, Args)

-spec abort(string(), list()) -> no_return().

like error/2, except it also raises an exception to interrupt program flow.

add_deps_to_path(State)

-spec add_deps_to_path(rebar_state:t()) -> ok.

Add deps to the code path

console(Str, Args)

-spec console(string(), list()) -> ok.

Prints to the console, including a newline

debug(Str, Args)

-spec debug(string(), list()) -> ok.

logs with severity debug

error(Str, Args)

-spec error(string(), list()) -> ok.

logs with severity error

expand_env_variable(InStr, VarName, RawVarValue)

-spec expand_env_variable(string(), string(), term()) -> string().

Given env. variable FOO we want to expand all references to it in InStr. References can have two forms: $FOO and ${FOO} The end of form $FOO is delimited with whitespace or EOL

get_arch()

-spec get_arch() -> string().

returns the system architecture, in strings like "19.0.4-x86_64-unknown-linux-gnu-64".

info(Str, Args)

-spec info(string(), list()) -> ok.

logs with severity info

processing_base_dir(State)

-spec processing_base_dir(rebar_state:t()) -> boolean().

checks if the current working directory is the base directory for the project.

restore_code_path(State)

-spec restore_code_path(rebar_state:t()) -> true | {error, term()}.

Revert to only having the beams necessary for running rebar3 and plugins in the path

set_paths(List, State)

-spec set_paths(rebar_paths:targets(), rebar_state:t()) -> ok.

Set code paths. Takes arguments of the form [plugins, deps] or [deps, plugins] and ensures the project's app and dependencies are set in the right order for the next bit of execution

ssl_opts(Url)

-spec ssl_opts(string() | binary()) -> [term()].

returns the SSL options adequate for the project based on its configuration, including for validation of certs.

unset_paths(List, State)

-spec unset_paths(rebar_paths:targets(), rebar_state:t()) -> ok.

Unsets code paths. Takes arguments of the form [plugins, deps] or [deps, plugins] and ensures the paths are no longer active.

warn(Str, Args)

-spec warn(string(), list()) -> ok.

logs with severity warn

wordsize()

-spec wordsize() -> string().

returns the size of a word on the system, as a string

rebar_app_info

Summary

Types

app_vsn/0

project_type/0

rebar_dict/0

t/0

Functions

add_to_profile(AppInfo, Profile, KVs)

adds a new profile with its own config to the app data

app_details(AppInfo)

returns the information stored in the app's app file, or if none, from the .app.src file.

app_details(AppInfo, AppDetails)

stores the information that would be returned from the app file, when reading from app_details/1.

app_file(App_info_t)

finds the .app file for an app, if any.

app_file(AppInfo, AppFile)

sets the .app file for an app.

app_file_src(App_info_t)

finds the .app.src file for an app, if any.

app_file_src(AppInfo, AppFileSrc)

sets the .app.src file for an app. An app without such a file can explicitly be set with undefined.

app_file_src_script(App_info_t)

finds the .app.src.script file for an app, if any.

app_file_src_script(AppInfo, AppFileSrcScript)

sets the .app.src.script file for an app. An app without such a file can explicitly be set with undefined.

app_to_map(App_info_t)

applications(App_info_t)

returns the list of applications the app depends on.

applications(AppInfo, Applications)

sets the list of applications the app depends on. Should be obtained from the app file.

apply_overrides(Overrides, AppInfo)

given a set of override rules, modify the app info accordingly

apply_profiles(AppInfo, Profile)

applies and merges the profile configuration in the specified order of profiles (or for a single profile) and returns an app info record with the resulting configuration

default(App_info_t)

get the dictionary of options under the default profile. Represents a root set prior to applying other profiles.

default(AppInfo, Default)

set the dictionary of options under the default profile. Useful when re-applying profile.

dep_level(App_info_t)

returns the level the app has in the lock files or in the dep tree.

dep_level(AppInfo, Level)

sets the level the app has in the lock files or in the dep tree.

deps(App_info_t)

returns the list of dependencies

deps(AppInfo, Deps)

sets the list of dependencies.

dir(App_info_t)

returns the directory that contains the app.

dir(AppInfo, Dir)

sets the directory that contains the app.

discover(Dir, State)

discover a complete version of the app info with all fields set.

ebin_dir(App_info_t)

gets the directory where ebin files for the app should go

ebin_dir(AppInfo, EbinDir)

sets the directory where beam files should go

fetch_dir(App_info_t)

returns the directory to fetch the dep source to

fetch_dir(AppInfo, FetchDir)

returns the directory to fetch the dep source to

get(AppInfo, Key)

look up a value in the dictionary of options; fails if the key for it does not exist.

get(AppInfo, Key, Default)

look up a value in the dictionary of options; returns a Default value otherwise.

has_all_artifacts(App_info_t)

checks whether all the build artifacts for an app to be considered valid are present.

included_applications(App_info_t)

returns the list of included_applications the app depends on.

included_applications(AppInfo, Applications)

sets the list of applications the app depends on. Should be obtained from the app file.

is_available(App_info_t)

returns whether the app source exists in the deps dir

is_available(AppInfo, IsAvailable)

sets whether the app's source is available only set if the app's source is found in the expected dep directory

is_checkout(App_info_t)

returns whether the app is a checkout app or not

is_checkout(AppInfo, IsCheckout)

sets whether the app is a checkout app or not

is_lock(App_info_t)

returns the lock status for the app

is_lock(AppInfo, IsLock)

sets the lock status for the app

name(App_info_t)

get the name of the app.

name(AppInfo, AppName)

set the name of the app.

new()

Build a new, empty, app info value. This is not of a lot of use and you probably won't be doing this much.

new(AppName)

Build a new app info value with only the app name set.

new(AppName, Vsn)

Build a new app info value with only the name and version set.

new(AppName, Vsn, Dir)

build a complete version of the app info with all fields set.

new(AppName, Vsn, Dir, Deps)

build a complete version of the app info with all fields set.

new(Parent, AppName, Vsn, Dir, Deps)

build a complete version of the app info with all fields set.

optional_applications(App_info_t)

returns the list of optional_applications the app depends on.

optional_applications(AppInfo, Applications)

sets the list of optional applications the app depends on. Should be obtained from the app file.

opts(App_info_t)

get the dictionary of options for the app.

opts(AppInfo, Opts)

set the dictionary of options for the app.

original_vsn(App_info_t)

returns the original version of the app (unevaluated if asking for a semver)

original_vsn(AppInfo, Vsn)

stores the original version of the app (unevaluated if asking for a semver)

out_dir(App_info_t)

returns the directory where build artifacts for the app should go

out_dir(AppInfo, OutDir)

sets the directory where build artifacts for the app should go

parent(App_info_t)

returns the app's parent in the dep tree.

parent(AppInfo, Parent)

sets the app's parent.

priv_dir(App_info_t)

gets the directory where private files for the app should go

profiles(App_info_t)

returns the list of active profiles

profiles(AppInfo, Profiles)

sets the list of active profiles

project_type(App_info_t)

project_type(AppInfo, ProjectType)

set(AppInfo, Key, Value)

sets a given value in the dictionary of options for the app.

source(App_info_t)

finds the source specification for the app

source(AppInfo, Source)

sets the source specification for the app

update_opts(AppInfo, Opts)

update current app info opts by merging in a new dict of opts

update_opts(AppInfo, Opts, Config)

update the opts based on the contents of a config file for the app

update_opts_deps(AppInfo, Deps)

update the opts based on new deps, usually from an app's hex registry metadata

valid(AppInfo)

returns whether the app is valid (built) or not

valid(AppInfo, Valid)

sets whether the app is valid (built) or not. If left unset, rebar3 will do the detection of the status itself. Explicitly setting the value to undefined can force a re-evaluation.

verify_otp_vsn(AppInfo)

checks whether the app can be built with the current Erlang/OTP version. If the check fails, the function raises an exception and displays an error.

vsn(App_info_t)

returns the version of the app after evaluation

vsn(AppInfo, Vsn)

sets the evaluated vsn of the app

Types

app_vsn/0

-type app_vsn() :: binary() | string() | {git, short} | {git, long}.

project_type/0

-type project_type() :: rebar3 | mix | undefined.

rebar_dict/0

-type rebar_dict() :: dict:dict().

t/0

-type t() ::
          #app_info_t{name :: binary() | undefined,
                      app_file_src :: file:filename_all() | undefined,
                      app_file_src_script :: file:filename_all() | undefined,
                      app_file :: file:filename_all() | undefined,
                      original_vsn :: app_vsn() | undefined,
                      vsn :: app_vsn() | undefined,
                      parent :: binary() | root,
                      app_details :: list(),
                      applications :: list(),
                      included_applications :: [atom()],
                      optional_applications :: [atom()],
                      deps :: list(),
                      profiles :: [atom()],
                      default :: rebar_dict(),
                      opts :: rebar_dict(),
                      dep_level :: integer(),
                      fetch_dir :: file:name(),
                      dir :: file:name(),
                      out_dir :: file:name(),
                      ebin_dir :: file:name(),
                      source :: string() | tuple() | checkout | undefined,
                      is_lock :: boolean(),
                      is_checkout :: boolean(),
                      valid :: boolean() | undefined,
                      project_type :: project_type(),
                      is_available :: boolean()}.

Functions

add_to_profile(AppInfo, Profile, KVs)

-spec add_to_profile(t(), atom(), [{_, _}]) -> t().

adds a new profile with its own config to the app data

app_details(AppInfo)

-spec app_details(t()) -> list().

returns the information stored in the app's app file, or if none, from the .app.src file.

app_details(AppInfo, AppDetails)

-spec app_details(t(), list()) -> t().

stores the information that would be returned from the app file, when reading from app_details/1.

app_file(App_info_t)

-spec app_file(t()) -> file:filename_all() | undefined.

finds the .app file for an app, if any.

app_file(AppInfo, AppFile)

-spec app_file(t(), file:filename_all() | undefined) -> t().

sets the .app file for an app.

app_file_src(App_info_t)

-spec app_file_src(t()) -> file:filename_all() | undefined.

finds the .app.src file for an app, if any.

app_file_src(AppInfo, AppFileSrc)

-spec app_file_src(t(), file:filename_all() | undefined) -> t().

sets the .app.src file for an app. An app without such a file can explicitly be set with undefined.

app_file_src_script(App_info_t)

-spec app_file_src_script(t()) -> file:filename_all() | undefined.

finds the .app.src.script file for an app, if any.

app_file_src_script(AppInfo, AppFileSrcScript)

-spec app_file_src_script(t(), file:filename_all()) -> t().

sets the .app.src.script file for an app. An app without such a file can explicitly be set with undefined.

app_to_map(App_info_t)

-spec app_to_map(t()) ->
                    #{name := atom(),
                      vsn := app_vsn(),
                      applications := [atom()],
                      included_applications := [atom()],
                      optional_applications := [atom()],
                      dir := file:name(),
                      out_dir := file:name(),
                      ebin_dir := file:name(),
                      link := false}.

applications(App_info_t)

-spec applications(t()) -> list().

returns the list of applications the app depends on.

applications(AppInfo, Applications)

-spec applications(t(), list()) -> t().

sets the list of applications the app depends on. Should be obtained from the app file.

apply_overrides(Overrides, AppInfo)

-spec apply_overrides(list(), t()) -> t().

given a set of override rules, modify the app info accordingly

apply_profiles(AppInfo, Profile)

-spec apply_profiles(t(), atom() | [atom(), ...]) -> t().

applies and merges the profile configuration in the specified order of profiles (or for a single profile) and returns an app info record with the resulting configuration

default(App_info_t)

-spec default(t()) -> rebar_dict().

get the dictionary of options under the default profile. Represents a root set prior to applying other profiles.

default(AppInfo, Default)

-spec default(t(), rebar_dict()) -> t().

set the dictionary of options under the default profile. Useful when re-applying profile.

dep_level(App_info_t)

-spec dep_level(t()) -> non_neg_integer().

returns the level the app has in the lock files or in the dep tree.

dep_level(AppInfo, Level)

-spec dep_level(t(), non_neg_integer()) -> t().

sets the level the app has in the lock files or in the dep tree.

deps(App_info_t)

-spec deps(t()) -> list().

returns the list of dependencies

deps(AppInfo, Deps)

-spec deps(t(), list()) -> t().

sets the list of dependencies.

dir(App_info_t)

-spec dir(t()) -> file:name().

returns the directory that contains the app.

dir(AppInfo, Dir)

-spec dir(t(), file:name()) -> t().

sets the directory that contains the app.

discover(Dir, State)

-spec discover(file:filename_all(), rebar_state:t()) -> {ok, t()} | not_found.

discover a complete version of the app info with all fields set.

ebin_dir(App_info_t)

-spec ebin_dir(t()) -> file:name().

gets the directory where ebin files for the app should go

ebin_dir(AppInfo, EbinDir)

-spec ebin_dir(t(), file:name()) -> t().

sets the directory where beam files should go

fetch_dir(App_info_t)

-spec fetch_dir(t()) -> file:name().

returns the directory to fetch the dep source to

fetch_dir(AppInfo, FetchDir)

-spec fetch_dir(t(), file:name()) -> t().

returns the directory to fetch the dep source to

get(AppInfo, Key)

-spec get(t(), term()) -> term().

look up a value in the dictionary of options; fails if the key for it does not exist.

get(AppInfo, Key, Default)

-spec get(t(), term(), term()) -> term().

look up a value in the dictionary of options; returns a Default value otherwise.

has_all_artifacts(App_info_t)

-spec has_all_artifacts(#app_info_t{name :: binary() | undefined,
                                    app_file_src :: file:filename_all() | undefined,
                                    app_file_src_script :: file:filename_all() | undefined,
                                    app_file :: file:filename_all() | undefined,
                                    original_vsn :: app_vsn() | undefined,
                                    vsn :: app_vsn() | undefined,
                                    parent :: binary() | root,
                                    app_details :: list(),
                                    applications :: list(),
                                    included_applications :: [atom()],
                                    optional_applications :: [atom()],
                                    deps :: list(),
                                    profiles :: [atom()],
                                    default :: rebar_dict(),
                                    opts :: rebar_dict(),
                                    dep_level :: integer(),
                                    fetch_dir :: file:name(),
                                    dir :: file:name(),
                                    out_dir :: file:name(),
                                    ebin_dir :: file:name(),
                                    source :: string() | tuple() | checkout | undefined,
                                    is_lock :: boolean(),
                                    is_checkout :: boolean(),
                                    valid :: boolean() | undefined,
                                    project_type :: project_type(),
                                    is_available :: boolean()}) ->
                           true | {false, file:filename()}.

checks whether all the build artifacts for an app to be considered valid are present.

included_applications(App_info_t)

-spec included_applications(t()) -> list().

returns the list of included_applications the app depends on.

included_applications(AppInfo, Applications)

-spec included_applications(t(), list()) -> t().

sets the list of applications the app depends on. Should be obtained from the app file.

is_available(App_info_t)

-spec is_available(t()) -> boolean().

returns whether the app source exists in the deps dir

is_available(AppInfo, IsAvailable)

-spec is_available(t(), boolean()) -> t().

sets whether the app's source is available only set if the app's source is found in the expected dep directory

is_checkout(App_info_t)

-spec is_checkout(t()) -> boolean().

returns whether the app is a checkout app or not

is_checkout(AppInfo, IsCheckout)

-spec is_checkout(t(), boolean()) -> t().

sets whether the app is a checkout app or not

is_lock(App_info_t)

-spec is_lock(t()) -> boolean().

returns the lock status for the app

is_lock(AppInfo, IsLock)

-spec is_lock(t(), boolean()) -> t().

sets the lock status for the app

name(App_info_t)

-spec name(t()) -> binary().

get the name of the app.

name(AppInfo, AppName)

-spec name(t(), atom() | binary() | string()) -> t().

set the name of the app.

new()

-spec new() -> t().

Build a new, empty, app info value. This is not of a lot of use and you probably won't be doing this much.

new(AppName)

-spec new(atom() | binary() | string()) -> {ok, t()}.

Build a new app info value with only the app name set.

new(AppName, Vsn)

-spec new(atom() | binary() | string(), app_vsn()) -> {ok, t()}.

Build a new app info value with only the name and version set.

new(AppName, Vsn, Dir)

-spec new(atom() | binary() | string(), app_vsn(), file:name()) -> {ok, t()}.

build a complete version of the app info with all fields set.

new(AppName, Vsn, Dir, Deps)

-spec new(atom() | binary() | string(), app_vsn(), file:name(), list()) -> {ok, t()}.

build a complete version of the app info with all fields set.

new(Parent, AppName, Vsn, Dir, Deps)

-spec new(atom() | binary(), atom() | binary() | string(), app_vsn(), file:name(), list()) -> {ok, t()}.

build a complete version of the app info with all fields set.

optional_applications(App_info_t)

-spec optional_applications(t()) -> list().

returns the list of optional_applications the app depends on.

optional_applications(AppInfo, Applications)

-spec optional_applications(t(), list()) -> t().

sets the list of optional applications the app depends on. Should be obtained from the app file.

opts(App_info_t)

-spec opts(t()) -> rebar_dict().

get the dictionary of options for the app.

opts(AppInfo, Opts)

-spec opts(t(), rebar_dict()) -> t().

set the dictionary of options for the app.

original_vsn(App_info_t)

-spec original_vsn(t()) -> app_vsn().

returns the original version of the app (unevaluated if asking for a semver)

original_vsn(AppInfo, Vsn)

-spec original_vsn(t(), app_vsn()) -> t().

stores the original version of the app (unevaluated if asking for a semver)

out_dir(App_info_t)

-spec out_dir(t()) -> file:name().

returns the directory where build artifacts for the app should go

out_dir(AppInfo, OutDir)

-spec out_dir(t(), file:name()) -> t().

sets the directory where build artifacts for the app should go

parent(App_info_t)

-spec parent(t()) -> root | binary().

returns the app's parent in the dep tree.

parent(AppInfo, Parent)

-spec parent(t(), binary() | root) -> t().

sets the app's parent.

priv_dir(App_info_t)

-spec priv_dir(t()) -> file:name().

gets the directory where private files for the app should go

profiles(App_info_t)

-spec profiles(t()) -> list().

returns the list of active profiles

profiles(AppInfo, Profiles)

-spec profiles(t(), list()) -> t().

sets the list of active profiles

project_type(App_info_t)

-spec project_type(t()) -> atom().

project_type(AppInfo, ProjectType)

-spec project_type(t(), atom()) -> t().

set(AppInfo, Key, Value)

-spec set(t(), any(), any()) -> t().

sets a given value in the dictionary of options for the app.

source(App_info_t)

-spec source(t()) -> string() | tuple().

finds the source specification for the app

source(AppInfo, Source)

-spec source(t(), string() | tuple() | checkout | undefined) -> t().

sets the source specification for the app

update_opts(AppInfo, Opts)

-spec update_opts(t(), rebar_dict()) -> t().

update current app info opts by merging in a new dict of opts

update_opts(AppInfo, Opts, Config)

-spec update_opts(t(), rebar_dict(), [any()]) -> t().

update the opts based on the contents of a config file for the app

update_opts_deps(AppInfo, Deps)

-spec update_opts_deps(t(), [any()]) -> t().

update the opts based on new deps, usually from an app's hex registry metadata

valid(AppInfo)

-spec valid(t()) -> boolean().

returns whether the app is valid (built) or not

valid(AppInfo, Valid)

-spec valid(t(), boolean() | undefined) -> t().

sets whether the app is valid (built) or not. If left unset, rebar3 will do the detection of the status itself. Explicitly setting the value to undefined can force a re-evaluation.

verify_otp_vsn(AppInfo)

-spec verify_otp_vsn(t()) -> ok | no_return().

checks whether the app can be built with the current Erlang/OTP version. If the check fails, the function raises an exception and displays an error.

vsn(App_info_t)

-spec vsn(t()) -> app_vsn().

returns the version of the app after evaluation

vsn(AppInfo, Vsn)

-spec vsn(t(), app_vsn()) -> t().

sets the evaluated vsn of the app

rebar_base_compiler

Summary

Types

col/0

compile_fn3/0

compile_fn/0

compile_fn_ret/0

desc/0

err_or_warn/0

error_tuple/0

line/0

loc/0

rebar_dict/0

Functions

error_tuple(Source, Es, Ws, Opts)

format error and warning strings for a given source file according to user preferences.

error_tuple(Source, Es, Ws, Config, Opts)

format error and warning strings for a given source file according to user preferences.

format_error_source(Path, Opts)

from a given path, and based on the user-provided options, format the file path according to the preferences.

ok_tuple(Source, Ws)

Format good compiler results with warnings to work with module internals. Assumes that warnings are not treated as errors.

ok_tuple(Source, Ws, Config, Opts)

Format good compiler results with warnings to work with module internals. Assumes that warnings are not treated as errors.

run(Config, FirstFiles, RestFiles, CompileFn)

Runs a compile job, applying compile_fn() to all files, starting with First files, and then RestFiles.

run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt, Compile3Fn)

Runs a compile job, applying compile_fn3() to all files, starting with First files, and then the other content of SourceDir. Files looked for are those ending in SourceExt. Results of the compilation are put in TargetDir with the base file names postfixed with SourceExt.

run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt, Compile3Fn, Opts)

Runs a compile job, applying compile_fn3() to all files, starting with First files, and then the other content of SourceDir. Files looked for are those ending in SourceExt. Results of the compilation are put in TargetDir with the base file names postfixed with SourceExt. Additional compile options can be passed in the last argument as a proplist.

Types

col/0

-type col() :: integer().

compile_fn3/0

-type compile_fn3() ::
          fun((file:filename(), file:filename(), [{_, _}] | rebar_dict()) -> compile_fn_ret()).

compile_fn/0

-type compile_fn() :: fun((file:filename(), [{_, _}] | rebar_dict()) -> compile_fn_ret()).

compile_fn_ret/0

-type compile_fn_ret() :: ok | {ok, [string()]} | skipped | term().

desc/0

-type desc() :: term().

err_or_warn/0

-type err_or_warn() :: {module(), desc()} | {loc(), module(), desc()}.

error_tuple/0

-type error_tuple() :: {error, [string()], [string()]}.

line/0

-type line() :: integer().

loc/0

-type loc() :: {line(), col()} | line().

rebar_dict/0

-type rebar_dict() :: dict:dict().

Functions

error_tuple(Source, Es, Ws, Opts)

-spec error_tuple(file:filename(), [Err], [Warn], rebar_dict() | [{_, _}]) -> error_tuple()
                     when Err :: string(), Warn :: string().

format error and warning strings for a given source file according to user preferences.

error_tuple(Source, Es, Ws, Config, Opts)

-spec error_tuple(file:filename(), [Err], [Warn], rebar_dict(), [{_, _}]) -> error_tuple()
                     when Err :: string(), Warn :: string().

format error and warning strings for a given source file according to user preferences.

format_error_source(Path, Opts)

-spec format_error_source(file:filename(), rebar_dict() | [{_, _}]) -> file:filename().

from a given path, and based on the user-provided options, format the file path according to the preferences.

ok_tuple(Source, Ws)

-spec ok_tuple(file:filename(), [string()]) -> {ok, [string()]}.

Format good compiler results with warnings to work with module internals. Assumes that warnings are not treated as errors.

ok_tuple(Source, Ws, Config, Opts)

-spec ok_tuple(file:filename(), [string()], rebar_dict(), [{_, _}]) -> {ok, [string()]}.

Format good compiler results with warnings to work with module internals. Assumes that warnings are not treated as errors.

run(Config, FirstFiles, RestFiles, CompileFn)

-spec run(rebar_dict() | [{_, _}], [First], [Next], compile_fn()) -> compile_fn_ret()
             when First :: file:filename(), Next :: file:filename().

Runs a compile job, applying compile_fn() to all files, starting with First files, and then RestFiles.

run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt, Compile3Fn)

-spec run(rebar_dict() | [{_, _}], [First], SourceDir, SourceExt, TargetDir, TargetExt, compile_fn3()) ->
             compile_fn_ret()
             when
                 First :: file:filename(),
                 SourceDir :: file:filename(),
                 TargetDir :: file:filename(),
                 SourceExt :: string(),
                 TargetExt :: string().

Runs a compile job, applying compile_fn3() to all files, starting with First files, and then the other content of SourceDir. Files looked for are those ending in SourceExt. Results of the compilation are put in TargetDir with the base file names postfixed with SourceExt.

run(Config, FirstFiles, SourceDir, SourceExt, TargetDir, TargetExt, Compile3Fn, Opts)

-spec run(rebar_dict() | [{_, _}],
          [First],
          SourceDir, SourceExt, TargetDir, TargetExt,
          compile_fn3(),
          [term()]) ->
             compile_fn_ret()
             when
                 First :: file:filename(),
                 SourceDir :: file:filename(),
                 TargetDir :: file:filename(),
                 SourceExt :: string(),
                 TargetExt :: string().

Runs a compile job, applying compile_fn3() to all files, starting with First files, and then the other content of SourceDir. Files looked for are those ending in SourceExt. Results of the compilation are put in TargetDir with the base file names postfixed with SourceExt. Additional compile options can be passed in the last argument as a proplist.

rebar_dir

utility functions for directory and path handling of all kind.

Summary

Types

rebar_dict/0

Functions

all_src_dirs(Opts)

returns all the source directories (src_dirs and extra_src_dirs).

all_src_dirs(Opts, SrcDefault, ExtraDefault)

returns all the source directories (src_dirs and extra_src_dirs) while being able to configure defaults for both.

base_dir(State)

returns the directory root for build artifacts for the current profile, such as _build/default/.

checkouts_dir(State)

returns the expected location of the _checkouts directory.

checkouts_dir(State, App)

returns the expected location of a given app in the checkouts directory for the project.

checkouts_out_dir(State)

returns the location of the directory checkouts are built to

checkouts_out_dir(State, App)

returns the expected location of a given app in the checkouts directory for the project.

deps_dir(State)

returns the directory where dependencies should be placed given the current profile.

deps_dir(DepsDir, App)

returns the directory where a dependency should be placed given the current profile, based on its app name. Expects to be passed the result of deps_dir/1 as a first argument.

extra_src_dirs(Opts)

same as src_dirs/1, but for the extra_src_dirs options

extra_src_dirs(Opts, Default)

same as src_dirs/2, but for the extra_src_dirs options

format_source_file_name(Path)

format_source_file_name(Path, Opts)

get_cwd()

returns the current working directory, with some specific conversions and handling done to be cross-platform compatible.

global_cache_dir(Opts)

returns the location for the global cache directory

global_config()

returns the default path of the global rebar.config file

global_config(State)

returns the path of the global rebar.config file

global_config_dir(State)

returns the directory where the global configuration files for rebar3 may be stored.

home_dir()

returns the user's home directory.

lib_dirs(State)

returns the list of relative path where the project applications can be located.

local_cache_dir(Dir)

appends the cache directory to the path passed to this function.

make_relative_path(Source, Target)

take a source and a target path, and relativize the target path onto the source.

plugins_dir(State)

Returns the directory where plugins are located.

processing_base_dir(State)

checks if the current working directory is the base directory for the project.

processing_base_dir(State, Dir)

checks if the passed in directory is the base directory for the project.

profile_dir(Opts, Profiles)

returns the directory root for build artifacts for a given set of profiles.

profile_dir_name(State)

returns the directory name for build artifacts for a given set of profiles.

project_plugin_dirs(State)

returns the list of relative path where the project plugins can be located.

recursive(Opts, Dir)

Return the value of the 'recursive' option for the given directory. If not given, the value of 'recursive' in the 'erlc_compiler' options is used, and finally the default is 'true'.

retarget_path(State, Path)

given a path if that path is an ancestor of an app dir, return the path relative to that apps outdir. If the path is not an ancestor to any app dirs but is an ancestor of the project root, return the path relative to the project base_dir. If it is not an ancestor of either return it unmodified

root_dir(State)

returns the absolute path for the project root (by default, the current working directory for the currently running escript).

src_dir_opts(Opts, Dir)

Return the list of options for the given src directory If the same option is given multiple times for a directory in the config, the priority order is: first occurrence of src_dirs followed by first occurrence of extra_src_dirs.

src_dirs(Opts)

src_dirs and extra_src_dirs can be configured with options like this

src_dirs(Opts, Default)

same as src_dirs/1, but allows to pass in a list of default options.

template_dir(State)

returns the location for the global template directory

template_globals(State)

returns the file location for the global template configuration variables file.

Types

rebar_dict/0

-type rebar_dict() :: dict:dict().

Functions

all_src_dirs(Opts)

-spec all_src_dirs(rebar_dict()) -> [file:filename_all()].

returns all the source directories (src_dirs and extra_src_dirs).

all_src_dirs(Opts, SrcDefault, ExtraDefault)

-spec all_src_dirs(rebar_dict(), [file:filename_all()], [file:filename_all()]) -> [file:filename_all()].

returns all the source directories (src_dirs and extra_src_dirs) while being able to configure defaults for both.

base_dir(State)

-spec base_dir(rebar_state:t()) -> file:filename_all().

returns the directory root for build artifacts for the current profile, such as _build/default/.

checkouts_dir(State)

-spec checkouts_dir(rebar_state:t()) -> file:filename_all().

returns the expected location of the _checkouts directory.

checkouts_dir(State, App)

-spec checkouts_dir(rebar_state:t(), file:filename_all()) -> file:filename_all().

returns the expected location of a given app in the checkouts directory for the project.

checkouts_out_dir(State)

-spec checkouts_out_dir(rebar_state:t()) -> file:filename_all().

returns the location of the directory checkouts are built to

checkouts_out_dir(State, App)

-spec checkouts_out_dir(rebar_state:t(), file:filename_all()) -> file:filename_all().

returns the expected location of a given app in the checkouts directory for the project.

deps_dir(State)

-spec deps_dir(rebar_state:t()) -> file:filename_all().

returns the directory where dependencies should be placed given the current profile.

deps_dir(DepsDir, App)

-spec deps_dir(file:filename_all(), file:filename_all()) -> file:filename_all().

returns the directory where a dependency should be placed given the current profile, based on its app name. Expects to be passed the result of deps_dir/1 as a first argument.

extra_src_dirs(Opts)

-spec extra_src_dirs(rebar_dict()) -> [file:filename_all()].

same as src_dirs/1, but for the extra_src_dirs options

extra_src_dirs(Opts, Default)

-spec extra_src_dirs(rebar_dict(), [file:filename_all()]) -> [file:filename_all()].

same as src_dirs/2, but for the extra_src_dirs options

format_source_file_name(Path)

format_source_file_name(Path, Opts)

get_cwd()

-spec get_cwd() -> file:filename_all().

returns the current working directory, with some specific conversions and handling done to be cross-platform compatible.

global_cache_dir(Opts)

-spec global_cache_dir(rebar_dict()) -> file:filename_all().

returns the location for the global cache directory

global_config()

-spec global_config() -> file:filename_all().

returns the default path of the global rebar.config file

global_config(State)

-spec global_config(rebar_state:t()) -> file:filename_all().

returns the path of the global rebar.config file

global_config_dir(State)

-spec global_config_dir(rebar_state:t()) -> file:filename_all().

returns the directory where the global configuration files for rebar3 may be stored.

home_dir()

-spec home_dir() -> file:filename_all().

returns the user's home directory.

lib_dirs(State)

-spec lib_dirs(rebar_state:t()) -> file:filename_all().

returns the list of relative path where the project applications can be located.

local_cache_dir(Dir)

-spec local_cache_dir(file:filename_all()) -> file:filename_all().

appends the cache directory to the path passed to this function.

make_relative_path(Source, Target)

-spec make_relative_path(file:filename(), file:filename()) -> file:filename().

take a source and a target path, and relativize the target path onto the source.

Example:

  1> rebar_dir:make_relative_path("a/b/c/d/file", "a/b/file").
  "c/d/file"
  2> rebar_dir:make_relative_path("a/b/file", "a/b/c/d/file").
  "../../file"

plugins_dir(State)

-spec plugins_dir(rebar_state:t()) -> file:filename_all().

Returns the directory where plugins are located.

processing_base_dir(State)

-spec processing_base_dir(rebar_state:t()) -> boolean().

checks if the current working directory is the base directory for the project.

processing_base_dir(State, Dir)

-spec processing_base_dir(rebar_state:t(), file:filename()) -> boolean().

checks if the passed in directory is the base directory for the project.

profile_dir(Opts, Profiles)

-spec profile_dir(rebar_dict(), [atom(), ...]) -> file:filename_all().

returns the directory root for build artifacts for a given set of profiles.

profile_dir_name(State)

-spec profile_dir_name(rebar_state:t()) -> file:filename_all().

returns the directory name for build artifacts for a given set of profiles.

project_plugin_dirs(State)

-spec project_plugin_dirs(rebar_state:t()) -> [file:filename_all()].

returns the list of relative path where the project plugins can be located.

recursive(Opts, Dir)

-spec recursive(rebar_dict(), file:filename_all()) -> boolean().

Return the value of the 'recursive' option for the given directory. If not given, the value of 'recursive' in the 'erlc_compiler' options is used, and finally the default is 'true'.

retarget_path(State, Path)

-spec retarget_path(rebar_state:t(), string()) -> string().

given a path if that path is an ancestor of an app dir, return the path relative to that apps outdir. If the path is not an ancestor to any app dirs but is an ancestor of the project root, return the path relative to the project base_dir. If it is not an ancestor of either return it unmodified

root_dir(State)

returns the absolute path for the project root (by default, the current working directory for the currently running escript).

src_dir_opts(Opts, Dir)

-spec src_dir_opts(rebar_dict(), file:filename_all()) -> [{atom(), term()}].

Return the list of options for the given src directory If the same option is given multiple times for a directory in the config, the priority order is: first occurrence of src_dirs followed by first occurrence of extra_src_dirs.

src_dirs(Opts)

-spec src_dirs(rebar_dict()) -> [file:filename_all()].

src_dirs and extra_src_dirs can be configured with options like this:

   {src_dirs,[{"foo",[{recursive,false}]}]}
   {extra_src_dirs,[{"bar",[recursive]}]} (equivalent to {recursive,true})

src_dirs/1,2 and extra_src_dirs/1,2 return only the list of directories for the src_dirs and extra_src_dirs options respectively, while src_dirs_opts/2 returns the options list for the given directory, no matter if it is configured as src_dirs or extra_src_dirs.

src_dirs(Opts, Default)

-spec src_dirs(rebar_dict(), [file:filename_all()]) -> [file:filename_all()].

same as src_dirs/1, but allows to pass in a list of default options.

template_dir(State)

-spec template_dir(rebar_state:t()) -> file:filename_all().

returns the location for the global template directory

template_globals(State)

-spec template_globals(rebar_state:t()) -> file:filename_all().

returns the file location for the global template configuration variables file.

rebar_paths

Summary

Types

target/0

targets/0

Functions

clashing_apps(Targets, State)

set_paths(UserTargets, State)

unset_paths(UserTargets, State)

Types

target/0

-type target() :: deps | plugins | runtime.

targets/0

-type targets() :: [target(), ...].

Functions

clashing_apps(Targets, State)

-spec clashing_apps(targets(), rebar_state:t()) -> [{target(), [binary()]}].

set_paths(UserTargets, State)

-spec set_paths(targets(), rebar_state:t()) -> ok.

unset_paths(UserTargets, State)

-spec unset_paths(targets(), rebar_state:t()) -> ok.

rebar_resource behaviour

Summary

Types

location/0

ref/0

source/0

type/0

Callbacks

download/3

lock/2

make_vsn/1

needs_update/2

Functions

download(Module, TmpDir, AppInfo, State)

lock(Module, AppInfo)

make_vsn(Module, AppInfo)

needs_update(Module, AppInfo)

new(Type, Module, State)

Types

location/0

-type location() :: string().

ref/0

-type ref() :: any().

source/0

-type source() :: {type(), location(), ref()} | {type(), location(), ref(), binary()}.

type/0

-type type() :: atom().

Callbacks

download/3

-callback download(file:filename_all(), tuple(), rebar_state:t()) ->
                      {tarball, file:filename_all()} | {ok, any()} | {error, any()}.

lock/2

-callback lock(file:filename_all(), tuple()) -> source().

make_vsn/1

-callback make_vsn(file:filename_all()) -> {plain, string()} | {error, string()}.

needs_update/2

-callback needs_update(file:filename_all(), tuple()) -> boolean().

Functions

download(Module, TmpDir, AppInfo, State)

lock(Module, AppInfo)

make_vsn(Module, AppInfo)

needs_update(Module, AppInfo)

new(Type, Module, State)

-spec new(type(), module(), term()) -> rebar_resource_v2:resource().

rebar_resource_v2 behaviour

Summary

Types

location/0

ref/0

resource/0

resource_state/0

source/0

type/0

Callbacks

download/4

init/2

lock/2

make_vsn/2

needs_update/2

Functions

download(TmpDir, AppInfo, State)

find_resource_state(Type, Resources)

format_error(_)

format_source(AppInfo)

lock(AppInfo, State)

make_vsn(AppInfo, Vsn, State)

needs_update(AppInfo, State)

new(Type, Module, State)

Types

location/0

-type location() :: string().

ref/0

-type ref() :: any().

resource/0

-type resource() ::
          #resource{type :: atom(),
                    module :: module(),
                    state :: term(),
                    implementation :: rebar_resource | rebar_resource_v2}.

resource_state/0

-type resource_state() :: term().

source/0

-type source() ::
          {type(), location(), ref()} |
          {type(), location(), ref(), binary()} |
          {type(), location(), ref(), binary(), binary()}.

type/0

-type type() :: atom().

Callbacks

download/4

-callback download(file:filename_all(), rebar_app_info:t(), rebar_state:t(), resource_state()) ->
                      ok | {error, any()}.

init/2

-callback init(type(), rebar_state:t()) -> {ok, resource()}.

lock/2

-callback lock(rebar_app_info:t(), resource_state()) -> source().

make_vsn/2

-callback make_vsn(rebar_app_info:t(), resource_state()) -> {plain, string()} | {error, string()}.

needs_update/2

-callback needs_update(rebar_app_info:t(), resource_state()) -> boolean().

Functions

download(TmpDir, AppInfo, State)

find_resource_state(Type, Resources)

format_error(_)

format_source(AppInfo)

lock(AppInfo, State)

make_vsn(AppInfo, Vsn, State)

needs_update(AppInfo, State)

new(Type, Module, State)

-spec new(type(), module(), term()) -> resource().

rebar_state

Summary

Types

rebar_dict/0

t/0

Functions

add_project_builder(State, Type, Module)

add_provider(State, Provider)

add_resource(State, _)

add_to_profile(State, Profile, KVs)

all_checkout_deps(State_t)

all_deps(State_t)

all_deps(State, NewApps)

all_plugin_deps(State_t)

all_plugin_deps(State, NewApps)

allow_provider_overrides(State_t)

allow_provider_overrides(State, Allow)

append_compilers(State, NewCompilers)

register compiler modules. Each compiler module should implement the rebar_compiler behaviour. Use this when your custom compiler generates binary artifacts and does not have a particular need to run before any other compiler.

apply_profiles(State, Profile)

code_paths(State_t, Key)

code_paths(State_t, Key, CodePath)

command_args(State_t)

command_args(State, CmdArgs)

command_parsed_args(State_t)

command_parsed_args(State, CmdArgs)

compilers(State_t)

get a list of all registered compiler modules, which should implement the rebar_compiler behaviour

create_logic_providers(ProviderModules, State0)

create_resources(Resources, State)

current_app(State_t)

current_app(State, CurrentApp)

current_profiles(State_t)

current_profiles(State, Profiles)

default(State_t)

default(State, Opts)

default_hex_repo_url_override(State)

deps_names(Deps)

deps_to_build(State_t)

deps_to_build(State, NewApps)

dir(State_t)

dir(State, Dir)

escript_path(State_t)

escript_path(State, EscriptPath)

format_error(_)

get(State, Key)

get(State, Key, Default)

has_all_artifacts(State_t)

lock(State_t)

lock(State, Apps)

merge_all_deps(State, UpdatedApps)

namespace(State_t)

namespace(State, Namespace)

new()

new(Config)

new(Profile, Config)

new(ParentState, Config, Dir)

opts(State_t)

opts(State, Opts)

prepend_compilers(State, NewCompilers)

register compiler modules prior to the existing ones. Each compiler module should implement the rebar_compiler behaviour. Use this when your custom compiler generates .erl files (or files of another type) and that should run before other compiler modules.

project_apps(State_t)

project_apps(State, NewApps)

project_builders(State_t)

providers(State_t)

providers(State, NewProviders)

resources(State_t)

resources(State, NewResources)

set(State, Key, Value)

set_resources(State, Resources)

to_list(State_t)

update_all_deps(State, NewApps)

update_all_plugin_deps(State, NewApps)

update_code_paths(State_t, Key, CodePath)

Types

rebar_dict/0

-type rebar_dict() :: dict:dict().

t/0

-type t() ::
          #state_t{dir :: file:name(),
                   opts :: rebar_dict(),
                   code_paths :: rebar_dict(),
                   default :: rebar_dict(),
                   escript_path :: undefined | file:filename_all(),
                   lock :: term(),
                   current_profiles :: [atom()],
                   namespace :: atom(),
                   command_args :: term(),
                   command_parsed_args :: term(),
                   current_app :: undefined | rebar_app_info:t(),
                   project_apps :: [rebar_app_info:t()],
                   deps_to_build :: [rebar_app_info:t()],
                   all_plugin_deps :: [rebar_app_info:t()],
                   all_deps :: [rebar_app_info:t()],
                   compilers :: [module()],
                   project_builders :: [{rebar_app_info:project_type(), module()}],
                   resources :: term(),
                   providers :: term(),
                   allow_provider_overrides :: boolean()}.

Functions

add_project_builder(State, Type, Module)

add_provider(State, Provider)

-spec add_provider(t(), providers:t()) -> t().

add_resource(State, _)

-spec add_resource(t(), {rebar_resource_v2:type(), module()}) -> t().

add_to_profile(State, Profile, KVs)

all_checkout_deps(State_t)

all_deps(State_t)

all_deps(State, NewApps)

all_plugin_deps(State_t)

all_plugin_deps(State, NewApps)

allow_provider_overrides(State_t)

allow_provider_overrides(State, Allow)

append_compilers(State, NewCompilers)

-spec append_compilers(t(), [module()]) -> t().

register compiler modules. Each compiler module should implement the rebar_compiler behaviour. Use this when your custom compiler generates binary artifacts and does not have a particular need to run before any other compiler.

apply_profiles(State, Profile)

code_paths(State_t, Key)

-spec code_paths(#state_t{dir :: file:name(),
                          opts :: rebar_dict(),
                          code_paths :: rebar_dict(),
                          default :: rebar_dict(),
                          escript_path :: undefined | file:filename_all(),
                          lock :: term(),
                          current_profiles :: [atom()],
                          namespace :: atom(),
                          command_args :: term(),
                          command_parsed_args :: term(),
                          current_app :: undefined | rebar_app_info:t(),
                          project_apps :: [rebar_app_info:t()],
                          deps_to_build :: [rebar_app_info:t()],
                          all_plugin_deps :: [rebar_app_info:t()],
                          all_deps :: [rebar_app_info:t()],
                          compilers :: [module()],
                          project_builders :: [{rebar_app_info:project_type(), module()}],
                          resources :: term(),
                          providers :: term(),
                          allow_provider_overrides :: boolean()},
                 atom()) ->
                    [file:filename()].

code_paths(State_t, Key, CodePath)

-spec code_paths(#state_t{dir :: file:name(),
                          opts :: rebar_dict(),
                          code_paths :: rebar_dict(),
                          default :: rebar_dict(),
                          escript_path :: undefined | file:filename_all(),
                          lock :: term(),
                          current_profiles :: [atom()],
                          namespace :: atom(),
                          command_args :: term(),
                          command_parsed_args :: term(),
                          current_app :: undefined | rebar_app_info:t(),
                          project_apps :: [rebar_app_info:t()],
                          deps_to_build :: [rebar_app_info:t()],
                          all_plugin_deps :: [rebar_app_info:t()],
                          all_deps :: [rebar_app_info:t()],
                          compilers :: [module()],
                          project_builders :: [{rebar_app_info:project_type(), module()}],
                          resources :: term(),
                          providers :: term(),
                          allow_provider_overrides :: boolean()},
                 atom(),
                 [file:filename()]) ->
                    #state_t{dir :: file:name(),
                             opts :: rebar_dict(),
                             code_paths :: rebar_dict(),
                             default :: rebar_dict(),
                             escript_path :: undefined | file:filename_all(),
                             lock :: term(),
                             current_profiles :: [atom()],
                             namespace :: atom(),
                             command_args :: term(),
                             command_parsed_args :: term(),
                             current_app :: undefined | rebar_app_info:t(),
                             project_apps :: [rebar_app_info:t()],
                             deps_to_build :: [rebar_app_info:t()],
                             all_plugin_deps :: [rebar_app_info:t()],
                             all_deps :: [rebar_app_info:t()],
                             compilers :: [module()],
                             project_builders :: [{rebar_app_info:project_type(), module()}],
                             resources :: term(),
                             providers :: term(),
                             allow_provider_overrides :: boolean()}.

command_args(State_t)

command_args(State, CmdArgs)

command_parsed_args(State_t)

command_parsed_args(State, CmdArgs)

compilers(State_t)

-spec compilers(t()) -> [module()].

get a list of all registered compiler modules, which should implement the rebar_compiler behaviour

create_logic_providers(ProviderModules, State0)

create_resources(Resources, State)

current_app(State_t)

current_app(State, CurrentApp)

current_profiles(State_t)

current_profiles(State, Profiles)

default(State_t)

default(State, Opts)

default_hex_repo_url_override(State)

-spec default_hex_repo_url_override(t()) -> binary().

deps_names(Deps)

deps_to_build(State_t)

deps_to_build(State, NewApps)

dir(State_t)

dir(State, Dir)

escript_path(State_t)

escript_path(State, EscriptPath)

format_error(_)

get(State, Key)

get(State, Key, Default)

has_all_artifacts(State_t)

-spec has_all_artifacts(#state_t{dir :: file:name(),
                                 opts :: rebar_dict(),
                                 code_paths :: rebar_dict(),
                                 default :: rebar_dict(),
                                 escript_path :: undefined | file:filename_all(),
                                 lock :: term(),
                                 current_profiles :: [atom()],
                                 namespace :: atom(),
                                 command_args :: term(),
                                 command_parsed_args :: term(),
                                 current_app :: undefined | rebar_app_info:t(),
                                 project_apps :: [rebar_app_info:t()],
                                 deps_to_build :: [rebar_app_info:t()],
                                 all_plugin_deps :: [rebar_app_info:t()],
                                 all_deps :: [rebar_app_info:t()],
                                 compilers :: [module()],
                                 project_builders :: [{rebar_app_info:project_type(), module()}],
                                 resources :: term(),
                                 providers :: term(),
                                 allow_provider_overrides :: boolean()}) ->
                           true | {false, file:filename()}.

lock(State_t)

lock(State, Apps)

merge_all_deps(State, UpdatedApps)

namespace(State_t)

namespace(State, Namespace)

new()

-spec new() -> t().

new(Config)

-spec new(list()) -> t().

new(Profile, Config)

-spec new(t() | atom(), list()) -> t().

new(ParentState, Config, Dir)

-spec new(t(), list(), file:filename_all()) -> t().

opts(State_t)

opts(State, Opts)

prepend_compilers(State, NewCompilers)

-spec prepend_compilers(t(), [module()]) -> t().

register compiler modules prior to the existing ones. Each compiler module should implement the rebar_compiler behaviour. Use this when your custom compiler generates .erl files (or files of another type) and that should run before other compiler modules.

project_apps(State_t)

project_apps(State, NewApps)

project_builders(State_t)

providers(State_t)

providers(State, NewProviders)

resources(State_t)

-spec resources(t()) -> [{rebar_resource_v2:type(), module()}].

resources(State, NewResources)

-spec resources(t(), [{rebar_resource_v2:type(), module()}]) -> t().

set(State, Key, Value)

-spec set(t(), any(), any()) -> t().

set_resources(State, Resources)

-spec set_resources(t(), [{rebar_resource_v2:type(), module()}]) -> t().

to_list(State_t)

update_all_deps(State, NewApps)

update_all_plugin_deps(State, NewApps)

update_code_paths(State_t, Key, CodePath)

-spec update_code_paths(#state_t{dir :: file:name(),
                                 opts :: rebar_dict(),
                                 code_paths :: rebar_dict(),
                                 default :: rebar_dict(),
                                 escript_path :: undefined | file:filename_all(),
                                 lock :: term(),
                                 current_profiles :: [atom()],
                                 namespace :: atom(),
                                 command_args :: term(),
                                 command_parsed_args :: term(),
                                 current_app :: undefined | rebar_app_info:t(),
                                 project_apps :: [rebar_app_info:t()],
                                 deps_to_build :: [rebar_app_info:t()],
                                 all_plugin_deps :: [rebar_app_info:t()],
                                 all_deps :: [rebar_app_info:t()],
                                 compilers :: [module()],
                                 project_builders :: [{rebar_app_info:project_type(), module()}],
                                 resources :: term(),
                                 providers :: term(),
                                 allow_provider_overrides :: boolean()},
                        atom(),
                        [file:filename()]) ->
                           #state_t{dir :: file:name(),
                                    opts :: rebar_dict(),
                                    code_paths :: rebar_dict(),
                                    default :: rebar_dict(),
                                    escript_path :: undefined | file:filename_all(),
                                    lock :: term(),
                                    current_profiles :: [atom()],
                                    namespace :: atom(),
                                    command_args :: term(),
                                    command_parsed_args :: term(),
                                    current_app :: undefined | rebar_app_info:t(),
                                    project_apps :: [rebar_app_info:t()],
                                    deps_to_build :: [rebar_app_info:t()],
                                    all_plugin_deps :: [rebar_app_info:t()],
                                    all_deps :: [rebar_app_info:t()],
                                    compilers :: [module()],
                                    project_builders :: [{rebar_app_info:project_type(), module()}],
                                    resources :: term(),
                                    providers :: term(),
                                    allow_provider_overrides :: boolean()}.

rebar_utils

Summary

Types

err_handler/0

Functions

abort()

abort(String, Args)

args_to_tasks(Args)

beam_to_mod(Filename)

beams(Dir)

check_blacklisted_otp_versions(BlacklistedRegexes)

check_min_otp_version(MinOtpVersion)

check_min_otp_version(MinOtpVersion, App)

cleanup_code_path(OrigPath)

Revert to only having the beams necessary for running rebar3 and plugins in the path

deprecated(Old, New, When)

deprecated(Old, New, Opts, When)

deps_to_binary(T)

droplast(L)

erl_to_mod(Filename)

escape_chars(Str)

escape_double_quotes(Str)

escape_double_quotes_weak(Str)

escript_foldl(Fun, Acc, File)

expand_env_variable(InStr, VarName, RawVarValue)

Given env. variable FOO we want to expand all references to it in InStr. References can have two forms: $FOO and ${FOO} The end of form $FOO is delimited with whitespace or EOL

filtermap(F, In)

wrapper around lists:filtermap/2

find_executable(Name)

find_files(Dir, Regex)

find_files(Dir, Regex, Recursive)

find_files_in_dirs(T, Regex, Recursive)

find_source(Filename, Dir, Rules)

get_arch()

returns the system architecture, in strings like "19.0.4-x86_64-unknown-linux-gnu-64".

get_proxy_auth()

indent(Amount)

ident to the level specified

info_useless(Old, New)

is_arch(ArchRegex)

is_list_of_strings(List)

line_count(PatchLines)

list_dir(Dir)

otp_release()

remove_from_code_path(Paths)

reread_config(ConfigList)

reread_config(ConfigList, Opts)

set_httpc_options()

sh(Command0, Options0)

sh_send(Command0, String, Options0)

sort_deps(Deps)

ssl_opts(Url)

Return the SSL options adequate for the project based on its configuration, including for validation of certs.

to_atom(B)

to_binary(A)

to_list(A)

tup_dedup(List)

tup_find(Elem, Elems)

tup_sort(List)

tup_umerge(NewList, OldList)

update_code(Paths)

update_code(Paths, Opts)

url_append_path(Url, ExtraPath)

user_agent()

vcs_vsn(OriginalVsn, Dir, Resources)

wordsize()

returns the size of a word on the system, as a string

Types

err_handler/0

-type err_handler() :: fun((string(), {integer(), string()}) -> no_return()).

Functions

abort()

-spec abort() -> no_return().

abort(String, Args)

-spec abort(string(), [term()]) -> no_return().

args_to_tasks(Args)

beam_to_mod(Filename)

beams(Dir)

check_blacklisted_otp_versions(BlacklistedRegexes)

check_min_otp_version(MinOtpVersion)

check_min_otp_version(MinOtpVersion, App)

cleanup_code_path(OrigPath)

-spec cleanup_code_path([string()]) -> true | {error, term()}.

Revert to only having the beams necessary for running rebar3 and plugins in the path

deprecated(Old, New, When)

deprecated(Old, New, Opts, When)

deps_to_binary(T)

droplast(L)

erl_to_mod(Filename)

escape_chars(Str)

escape_double_quotes(Str)

escape_double_quotes_weak(Str)

escript_foldl(Fun, Acc, File)

expand_env_variable(InStr, VarName, RawVarValue)

-spec expand_env_variable(string(), string(), term()) -> string().

Given env. variable FOO we want to expand all references to it in InStr. References can have two forms: $FOO and ${FOO} The end of form $FOO is delimited with whitespace or EOL

filtermap(F, In)

-spec filtermap(F, [In]) -> [Out]
                   when F :: fun((In) -> boolean() | {true, Out}), In :: term(), Out :: term().

wrapper around lists:filtermap/2

find_executable(Name)

find_files(Dir, Regex)

find_files(Dir, Regex, Recursive)

find_files_in_dirs(T, Regex, Recursive)

find_source(Filename, Dir, Rules)

get_arch()

-spec get_arch() -> string().

returns the system architecture, in strings like "19.0.4-x86_64-unknown-linux-gnu-64".

get_proxy_auth()

indent(Amount)

-spec indent(non_neg_integer()) -> iolist().

ident to the level specified

info_useless(Old, New)

is_arch(ArchRegex)

is_list_of_strings(List)

-spec is_list_of_strings(term()) -> boolean().

line_count(PatchLines)

list_dir(Dir)

otp_release()

remove_from_code_path(Paths)

reread_config(ConfigList)

reread_config(ConfigList, Opts)

set_httpc_options()

sh(Command0, Options0)

sh_send(Command0, String, Options0)

sort_deps(Deps)

ssl_opts(Url)

-spec ssl_opts(Url) -> Res when Url :: string() | binary(), Res :: proplists:proplist().

Return the SSL options adequate for the project based on its configuration, including for validation of certs.

to_atom(B)

to_binary(A)

to_list(A)

tup_dedup(List)

tup_find(Elem, Elems)

tup_sort(List)

tup_umerge(NewList, OldList)

update_code(Paths)

update_code(Paths, Opts)

url_append_path(Url, ExtraPath)

user_agent()

vcs_vsn(OriginalVsn, Dir, Resources)

wordsize()

-spec wordsize() -> string().

returns the size of a word on the system, as a string