Skip to content

Instantly share code, notes, and snippets.

@tsloughter
Last active May 22, 2023 22:08
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsloughter/1e16d70268182db1415a to your computer and use it in GitHub Desktop.
Save tsloughter/1e16d70268182db1415a to your computer and use it in GitHub Desktop.
Rebar3 Profiles

Rebar3 Profiles

Motivation

Often you want to build the same project in different ways depending on context, whether it be development or preparing for production deployment. Or you want some dependencies only for use in certain contexts such as running tests and don't want them conflicting with regular dependencies or bother to be fetched and built when not needed.

Those are some of the reasons we've introduced profiles.

Directory Structure

Each profile has a separate output directory, by default under _build:

_build
└── <profile>
    ├── lib
    └── rel

Defaults

  • default
  • test

Configuration

Example rebar.config:

{deps, [...]}.

{relx, [{release, {relname, "0.0.1"},
         [appname]},

        {dev_mode, true},
        {include_erts, false}]}.

{profiles, [{prod, [{relx, [{dev_mode, false}, {include_erts, true}]}]},

            {test, [{deps, [
                           {meck, ".*",
                             {git, "git://github.com/eproxus/meck.git", {tag, "0.8.2"}}}
                           ]
                    }]
             }]
}.

Result after running rebar3 ct and REBAR3_PROFILE=prod rebar3 release:

_build
├── default
│   ├── lib
│   │   ├── ...
│   └── rel
│       └── relname
├── prod
│   └── rel
│       └── relname
└── test
    └── lib
        └── meck

How They are Applied

  • All config values outside of profiles is part of the default profile
  • When using a profile besides default the config keys between the profile and default are merged, the profile in use takes precedence.
  • If the value of a config is a list of values (not a printable list) merge the keys of the lists, again with the profile in use taking precedence.

Tasks

A task can declare it depends on a provider that has run within a certain profile's context. For example the Common Test provider depends on install_deps having run run under the default profile so that all dependencies of the project are installed and available during the test runs:

-define(DEPS, [{install_deps, default}, compile]).

Additionally the Common Test provider specifies that the profile it must run under is the test profile:

providers:create([{name, ?PROVIDER},
                  {module, ?MODULE},
                  {deps, ?DEPS},
                  {bare, false},
                  {example, "rebar ct"},
                  {short_desc, "Run Common Tests"},
                  {desc, ""},
                  {opts, ct_opts(State)},
                  {profile, test}])

Providers and their dependencies are resolved and sorted. In this example all deps of install_deps provider in the default profile context will be run as well as compile and all its dependencies in the test context, meaning install_deps and app_discovery run twice. This ultimately expands to the following list of providers to run:

[{app_discovery,default},
 {app_discovery,test},
 {install_deps,default},
 {install_deps,test},
 {lock,test},
 {compile,test},
 {ct,test}]
@Laymer
Copy link

Laymer commented May 30, 2018

Thank you 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment