aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/relx.hrl1
-rw-r--r--rebar.config8
-rw-r--r--src/relx.app.src2
-rw-r--r--src/relx.erl57
-rw-r--r--src/rlx_app_discovery.erl2
-rw-r--r--src/rlx_cmd_args.erl20
-rw-r--r--src/rlx_config.erl (renamed from src/rlx_prv_config.erl)25
-rw-r--r--src/rlx_dscv_util.erl6
-rw-r--r--src/rlx_provider.erl117
-rw-r--r--src/rlx_prv_archive.erl17
-rw-r--r--src/rlx_prv_assembler.erl23
-rw-r--r--src/rlx_prv_discover.erl18
-rw-r--r--src/rlx_prv_overlay.erl16
-rw-r--r--src/rlx_prv_release.erl18
-rw-r--r--src/rlx_prv_relup.erl19
-rw-r--r--src/rlx_rel_discovery.erl2
-rw-r--r--src/rlx_state.erl113
-rw-r--r--src/rlx_topo.erl14
-rw-r--r--test/rlx_command_SUITE.erl16
-rw-r--r--test/rlx_discover_SUITE.erl17
-rw-r--r--test/rlx_release_SUITE.erl21
21 files changed, 255 insertions, 277 deletions
diff --git a/include/relx.hrl b/include/relx.hrl
index 43aec62..3194873 100644
--- a/include/relx.hrl
+++ b/include/relx.hrl
@@ -1,4 +1,3 @@
-
%% Copyright 2012 Erlware, LLC. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
diff --git a/rebar.config b/rebar.config
index a250ce9..396c546 100644
--- a/rebar.config
+++ b/rebar.config
@@ -8,6 +8,9 @@
{erlware_commons, ".*",
{git, "https://github.com/erlware/erlware_commons.git",
{branch, "master"}}},
+ {providers, ".*",
+ {git, "https://github.com/tsloughter/providers.git",
+ {branch, "master"}}},
{erlydtl, ".*",
{git, "https://github.com/erlydtl/erlydtl.git",
{tag, "0.9.0"}}},
@@ -22,6 +25,7 @@
%% Compiler Options ============================================================
{erl_opts,
[{platform_define, "^[0-9]+", namespaced_types},
+ {platform_define, "R14", no_callback_support},
debug_info,
warnings_as_errors,
inline]}.
@@ -36,6 +40,6 @@
{erlydtl_opts, [{doc_root, "priv/templates"},
{compiler_options, [report, return, debug_info]}]}.
{escript_incl_apps,
- [getopt, erlware_commons, erlydtl]}.
+ [getopt, erlware_commons, erlydtl, providers]}.
-{first_files, [rcl_provider]}.
+{first_files, [rlx_provider]}.
diff --git a/src/relx.app.src b/src/relx.app.src
index c52958b..3e2b493 100644
--- a/src/relx.app.src
+++ b/src/relx.app.src
@@ -23,4 +23,4 @@
{vsn, "semver"},
{modules, []},
{registered, []},
- {applications, [kernel, stdlib, getopt, erlware_commons]}]}.
+ {applications, [kernel, stdlib, getopt, erlware_commons, providers]}]}.
diff --git a/src/relx.erl b/src/relx.erl
index 1364538..e9867a9 100644
--- a/src/relx.erl
+++ b/src/relx.erl
@@ -57,6 +57,7 @@ main(Args) ->
true ->
usage();
false ->
+ application:start(relx),
do([{caller, command_line} | Options], NonOptions)
end
end;
@@ -212,7 +213,7 @@ opt_spec_list() ->
-spec format_error(Reason::term()) -> string().
format_error({invalid_return_value, Provider, Value}) ->
- io_lib:format(lists:flatten([rlx_provider:format(Provider), " returned an invalid value ",
+ io_lib:format(lists:flatten([providers:format(Provider), " returned an invalid value ",
io_lib:format("~p", [Value])]), []);
format_error({opt_parse, {invalid_option, Opt}}) ->
io_lib:format("invalid option ~s~n", [Opt]);
@@ -240,16 +241,27 @@ run_relx_process(State) ->
%% providers again and run the rest of them (because they could have been
%% updated by the config process).
run_providers(State0) ->
- [ConfigProvider | _] = rlx_state:providers(State0),
- case run_provider(ConfigProvider, {ok, State0}) of
- Err = {error, _} ->
- Err;
+ case rlx_config:do(State0) of
{ok, State1} ->
+ Actions = rlx_state:actions(State0),
+
+ AllProviders = rlx_state:providers(State1),
+ TargetProviders = lists:flatmap(fun(Target) ->
+ providers:get_target_providers(Target, AllProviders)
+ end, Actions),
+ Providers1 = lists:map(fun(P) ->
+ providers:get_provider(P, AllProviders)
+ end, TargetProviders),
+
+ %% Unique Sort Providers
+ Providers2 = providers:process_deps(Providers1, AllProviders),
+
RootDir = rlx_state:root_dir(State1),
ok = file:set_cwd(RootDir),
- Providers = rlx_state:providers(State1),
- Result = run_providers(ConfigProvider, Providers, State1),
- handle_output(State1, rlx_state:caller(State1), Result)
+ Result = lists:foldl(fun run_provider/2, {ok, State1}, Providers2),
+ handle_output(State1, rlx_state:caller(State1), Result);
+ Err ->
+ Err
end.
handle_output(State, command_line, E={error, _}) ->
@@ -260,33 +272,24 @@ handle_output(_State, command_line, _) ->
handle_output(_State, api, Result) ->
Result.
-run_providers(ConfigProvider, Providers, State0) ->
- case Providers of
- [ConfigProvider | Rest] ->
- %% IF the config provider is still the first provider do not run it
- %% again just run the rest.
- lists:foldl(fun run_provider/2, {ok, State0}, Rest);
- _ ->
- lists:foldl(fun run_provider/2, {ok, State0}, Providers)
- end.
-
--spec run_provider(rlx_provider:t(), {ok, rlx_state:t()} | error()) ->
+-spec run_provider(atom(), {ok, rlx_state:t()} | error()) ->
{ok, rlx_state:t()} | error().
-run_provider(_Provider, Error = {error, _}) ->
- Error;
-run_provider(Provider, {ok, State0}) ->
+run_provider(ProviderName, {ok, State0}) ->
+ Provider = providers:get_provider(ProviderName, rlx_state:providers(State0)),
ec_cmd_log:debug(rlx_state:log(State0), "Running provider ~p~n",
- [rlx_provider:impl(Provider)]),
- case rlx_provider:do(Provider, State0) of
+ [providers:impl(Provider)]),
+ case providers:do(Provider, State0) of
{ok, State1} ->
ec_cmd_log:debug(rlx_state:log(State0), "Provider successfully run: ~p~n",
- [rlx_provider:impl(Provider)]),
+ [providers:impl(Provider)]),
{ok, State1};
E={error, _} ->
ec_cmd_log:debug(rlx_state:log(State0), "Provider (~p) failed with: ~p~n",
- [rlx_provider:impl(Provider), E]),
+ [providers:impl(Provider), E]),
E
- end.
+ end;
+run_provider(_ProviderName, Error) ->
+ Error.
-spec usage() -> ok.
usage() ->
diff --git a/src/rlx_app_discovery.erl b/src/rlx_app_discovery.erl
index 4a5620b..6ac8d11 100644
--- a/src/rlx_app_discovery.erl
+++ b/src/rlx_app_discovery.erl
@@ -21,7 +21,7 @@
%%% @doc This provider uses the lib_dir setting of the state. It searches the
%%% Lib Dirs looking for all OTP Applications that are available. When it finds
%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the rlx_provider behaviour.
+%%% the state of available apps. This implements the provider behaviour.
-module(rlx_app_discovery).
-export([do/2,
diff --git a/src/rlx_cmd_args.erl b/src/rlx_cmd_args.erl
index 5df9392..e117d8e 100644
--- a/src/rlx_cmd_args.erl
+++ b/src/rlx_cmd_args.erl
@@ -87,15 +87,15 @@ format_error({invalid_target, Target}) ->
%%%===================================================================
%%% Internal Functions
%%%===================================================================
--spec handle_config([getopt:option()], [atom()], proplists:proplist()) ->
- {ok, {rlx_state:t(), [string()]}} |
- relx:error().
+-spec handle_config(any(), [atom()], proplists:proplist()) ->
+ {ok, {rlx_state:t(), [string()]}} | relx:error().
handle_config(Opts, Targets, CommandLineConfig) ->
- case validate_config(proplists:get_value(config, Opts, [])) of
- Error = {error, _} ->
- Error;
- {ok, Config} ->
- {ok, rlx_state:new(Config, CommandLineConfig, Targets)}
+ {ok, Config} = validate_config(proplists:get_value(config, Opts, [])),
+ case rlx_state:new(Config, CommandLineConfig, Targets) of
+ {error, Error} ->
+ {error, Error};
+ State ->
+ {ok, State}
end.
-spec convert_targets([string()]) -> {ok, release | relup} | relx:error().
@@ -117,8 +117,8 @@ convert_targets(["tar" | T], Acc) ->
convert_targets([Target | _T], _Acc) ->
?RLX_ERROR({invalid_target, Target}).
--spec validate_config(file:filename() | undefined) ->
- {ok, file:filename() | undefined} | relx:error().
+-spec validate_config(file:filename() | list() | undefined) ->
+ {ok, file:filename() | list() | undefined}.
validate_config(undefined) ->
{ok, undefined};
validate_config("") ->
diff --git a/src/rlx_prv_config.erl b/src/rlx_config.erl
index 5724661..d4acb3c 100644
--- a/src/rlx_prv_config.erl
+++ b/src/rlx_config.erl
@@ -21,13 +21,10 @@
%%% A module that provides config parsing and support to the system
%%% @end
%%%-------------------------------------------------------------------
--module(rlx_prv_config).
-
--behaviour(rlx_provider).
+-module(rlx_config).
%% API
--export([init/1,
- do/1,
+-export([do/1,
format_error/1]).
-include("relx.hrl").
@@ -36,11 +33,6 @@
%%% API
%%%===================================================================
-%% @doc Required by the system, but not used in this provider
--spec init(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
-init(State) ->
- {ok, State}.
-
%% @doc parse all the configs currently specified in the state,
%% populating the state as a result.
-spec do(rlx_state:t()) ->{ok, rlx_state:t()} | relx:error().
@@ -143,6 +135,8 @@ load_terms({lib_dirs, Dirs}, {ok, State}) ->
rlx_state:add_lib_dirs(State,
[list_to_binary(Dir) || Dir <- rlx_util:wildcard_paths(Dirs)]),
{ok, State2};
+load_terms({hooks, Hooks}, {ok, State0}) ->
+ add_hooks(Hooks, State0);
load_terms({providers, Providers0}, {ok, State0}) ->
Providers1 = gen_providers(Providers0, State0),
case Providers1 of
@@ -231,15 +225,22 @@ load_terms(InvalidTerm, _) ->
?RLX_ERROR({invalid_term, InvalidTerm}).
-spec gen_providers([module()], rlx_state:t()) ->
- {[rlx_provider:t()], {ok, rlx_state:t()} | relx:error()}.
+ {[providers:t()], {ok, rlx_state:t()} | relx:error()}.
gen_providers(Providers, State) ->
lists:foldl(fun(ProviderName, {Providers1, {ok, State1}}) ->
- {Provider, State2} = rlx_provider:new(ProviderName, State1),
+ {Provider, State2} = providers:new(ProviderName, State1),
{[Provider | Providers1], State2};
(_, E={_, {error, _}}) ->
E
end, {[], {ok, State}}, Providers).
+add_hooks(Hooks, State) ->
+ {ok, lists:foldl(fun({pre, Target, Hook}, StateAcc) ->
+ rlx_state:prepend_hook(StateAcc, Target, Hook);
+ ({post, Target, Hook}, StateAcc) ->
+ rlx_state:append_hook(StateAcc, Target, Hook)
+ end, State, Hooks)}.
+
list_of_overlay_vars_files(undefined) ->
[];
list_of_overlay_vars_files([]) ->
diff --git a/src/rlx_dscv_util.erl b/src/rlx_dscv_util.erl
index aa642b8..fefdbce 100644
--- a/src/rlx_dscv_util.erl
+++ b/src/rlx_dscv_util.erl
@@ -21,7 +21,7 @@
%%% @doc This provider uses the lib_dir setting of the state. It searches the
%%% Lib Dirs looking for all OTP Applications that are available. When it finds
%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the rlx_provider behaviour.
+%%% the state of available apps. This implements provider behaviour.
-module(rlx_dscv_util).
-export([do/2,
@@ -110,8 +110,8 @@ discover_dir(ProcessDir, File, symlink) ->
discover_real_symlink_dir(ProcessDir, File)
end.
-discover_real_symlink_dir(ProcessDir, File) ->
- {ok, ActualRealDir} = file:read_link(File),
+discover_real_symlink_dir(ProcessDir, File) ->
+ {ok, ActualRealDir} = file:read_link(File),
case lists:prefix(iolist_to_list(filename:absname(ActualRealDir)),
iolist_to_list(filename:absname(File))) of
true ->
diff --git a/src/rlx_provider.erl b/src/rlx_provider.erl
deleted file mode 100644
index b3e6310..0000000
--- a/src/rlx_provider.erl
+++ /dev/null
@@ -1,117 +0,0 @@
-%% -*- erlang-indent-level: 4; indent-tabs-mode: nil; fill-column: 80 -*-
-%%% Copyright 2012 Erlware, LLC. All Rights Reserved.
-%%%
-%%% This file is provided to you under the Apache License,
-%%% Version 2.0 (the "License"); you may not use this file
-%%% except in compliance with the License. You may obtain
-%%% a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing,
-%%% software distributed under the License is distributed on an
-%%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-%%% KIND, either express or implied. See the License for the
-%%% specific language governing permissions and limitations
-%%% under the License.
-%%%-------------------------------------------------------------------
-%%% @author Eric Merritt <[email protected]>
-%%% @copyright 2011 Erlware, LLC.
-%%% @doc
-%%% A module that supports providing state manipulation services to the system.
-%%% @end
-%%%-------------------------------------------------------------------
--module(rlx_provider).
-
-%% API
--export([new/2,
- do/2,
- impl/1,
- format_error/1,
- format_error/2,
- format/1]).
-
--export_type([t/0]).
-
--include("relx.hrl").
-
-%%%===================================================================
-%%% Types
-%%%===================================================================
-
--opaque t() :: {?MODULE, module()}.
-
-
--ifdef(have_callback_support).
-
--callback init(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
--callback do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
--callback format_error(Reason::term()) -> iolist().
-
--else.
-
-%% In the case where R14 or lower is being used to compile the system
-%% we need to export a behaviour info
--export([behaviour_info/1]).
--spec behaviour_info(atom()) -> [{atom(), arity()}] | undefined.
-behaviour_info(callbacks) ->
- [{init, 1},
- {do, 1},
- {format_error, 1}];
-behaviour_info(_) ->
- undefined.
-
--endif.
-
-%%%===================================================================
-%%% API
-%%%===================================================================
-
-%% @doc create a new provider object from the specified module. The
-%% module should implement the provider behaviour.
-%%
-%% @param ModuleName The module name.
-%% @param State0 The current state of the system
--spec new(module(), rlx_state:t()) ->
- {t(), {ok, rlx_state:t()}} | relx:error().
-new(ModuleName, State0) when is_atom(ModuleName) ->
- State1 = ModuleName:init(State0),
- case code:which(ModuleName) of
- non_existing ->
- ?RLX_ERROR({non_existing, ModuleName});
- _ ->
- {{?MODULE, ModuleName}, State1}
- end.
-
-%% @doc Manipulate the state of the system, that new state
-%%
-%% @param Provider the provider object
-%% @param State the current state of the system
--spec do(Provider::t(), rlx_state:t()) ->
- {ok, rlx_state:t()} | relx:error().
-do({?MODULE, Mod}, State) ->
- Mod:do(State).
-
-%%% @doc get the name of the module that implements the provider
-%%% @param Provider the provider object
--spec impl(Provider::t()) -> module().
-impl({?MODULE, Mod}) ->
- Mod.
-
-%% @doc format an error produced from a provider.
--spec format_error(Reason::term()) -> iolist().
-format_error({non_existing, ModuleName}) ->
- io_lib:format("~p does not exist in the system", [ModuleName]).
-
-%% @doc format an error produced from a provider.
--spec format_error(t(), Reason::term()) -> iolist().
-format_error({?MODULE, Mod}, Error) ->
- Mod:format_error(Error).
-
-%% @doc print the provider module name
-%%
-%% @param T - The provider
-%% @return An iolist describing the provider
--spec format(t()) -> iolist().
-format({?MODULE, Mod}) ->
- erlang:atom_to_list(Mod).
diff --git a/src/rlx_prv_archive.erl b/src/rlx_prv_archive.erl
index ab640ed..8370659 100644
--- a/src/rlx_prv_archive.erl
+++ b/src/rlx_prv_archive.erl
@@ -22,7 +22,7 @@
%%% into a release directory.
-module(rlx_prv_archive).
--behaviour(rlx_provider).
+-behaviour(provider).
-export([init/1,
do/1,
@@ -30,12 +30,25 @@
-include("relx.hrl").
+-define(PROVIDER, tar).
+-define(DEPS, [release]).
+
%%============================================================================
%% API
%%============================================================================
+
-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
init(State) ->
- {ok, State}.
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "tar"},
+ {short_desc, ""},
+ {desc, ""},
+ {opts, []}])),
+
+ {ok, State1}.
-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
do(State) ->
diff --git a/src/rlx_prv_assembler.erl b/src/rlx_prv_assembler.erl
index f34dfa6..8a25cdd 100644
--- a/src/rlx_prv_assembler.erl
+++ b/src/rlx_prv_assembler.erl
@@ -22,7 +22,7 @@
%%% into a release directory.
-module(rlx_prv_assembler).
--behaviour(rlx_provider).
+-behaviour(provider).
-export([init/1,
do/1,
@@ -30,31 +30,42 @@
-include("relx.hrl").
+-define(PROVIDER, release).
+-define(DEPS, [overlay]).
+
%%============================================================================
%% API
%%============================================================================
-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
init(State) ->
- {ok, State}.
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "release"},
+ {short_desc, ""},
+ {desc, ""},
+ {opts, []}])),
+ {ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
%% looking for OTP Applications
-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
-do(State) ->
+do(State) ->
print_dev_mode(State),
{RelName, RelVsn} = rlx_state:default_configured_release(State),
Release = rlx_state:get_realized_release(State, RelName, RelVsn),
- OutputDir = rlx_state:output_dir(State),
+ OutputDir = rlx_state:output_dir(State),
case create_output_dir(OutputDir) of
ok ->
case rlx_release:realized(Release) of
- true ->
+ true ->
copy_app_directories_to_output(State, Release, OutputDir);
false ->
?RLX_ERROR({unresolved_release, RelName, RelVsn})
end;
Error ->
- Error
+ Error
end.
-spec format_error(ErrorDetail::term()) -> iolist().
diff --git a/src/rlx_prv_discover.erl b/src/rlx_prv_discover.erl
index 21e5687..c05cdb1 100644
--- a/src/rlx_prv_discover.erl
+++ b/src/rlx_prv_discover.erl
@@ -21,9 +21,9 @@
%%% @doc This provider uses the lib_dir setting of the state. It searches the
%%% Lib Dirs looking for all OTP Applications that are available. When it finds
%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the rlx_provider behaviour.
+%%% the state of available apps. This implements the provider behaviour.
-module(rlx_prv_discover).
--behaviour(rlx_provider).
+-behaviour(provider).
-export([init/1,
do/1,
@@ -31,12 +31,24 @@
-include("relx.hrl").
+-define(PROVIDER, discover).
+-define(DEPS, []).
+
%%============================================================================
%% API
%%============================================================================
+
-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
init(State) ->
- {ok, State}.
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "build"},
+ {short_desc, ""},
+ {desc, ""},
+ {opts, []}])),
+ {ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
%% looking for OTP Applications
diff --git a/src/rlx_prv_overlay.erl b/src/rlx_prv_overlay.erl
index 23df218..4cbbf31 100644
--- a/src/rlx_prv_overlay.erl
+++ b/src/rlx_prv_overlay.erl
@@ -22,7 +22,7 @@
%%% into a release directory.
-module(rlx_prv_overlay).
--behaviour(rlx_provider).
+-behaviour(provider).
-export([init/1,
do/1,
@@ -34,12 +34,24 @@
-include("relx.hrl").
+-define(PROVIDER, overlay).
+-define(DEPS, [resolve_release]).
+
%%============================================================================
%% API
%%============================================================================
+
-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
init(State) ->
- {ok, State}.
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "overlay"},
+ {short_desc, ""},
+ {desc, ""},
+ {opts, []}])),
+ {ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
%% looking for OTP Applications
diff --git a/src/rlx_prv_release.erl b/src/rlx_prv_release.erl
index 7e8304b..d579291 100644
--- a/src/rlx_prv_release.erl
+++ b/src/rlx_prv_release.erl
@@ -21,10 +21,10 @@
%%% @doc This provider uses the lib_dir setting of the state. It searches the
%%% Lib Dirs looking for all OTP Applications that are available. When it finds
%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the rlx_provider behaviour.
+%%% the state of available apps. This implements the provider behaviour.
-module(rlx_prv_release).
--behaviour(rlx_provider).
+-behaviour(provider).
-export([init/1,
do/1,
@@ -32,12 +32,24 @@
-include("relx.hrl").
+-define(PROVIDER, resolve_release).
+-define(DEPS, [discover]).
+
%%============================================================================
%% API
%%============================================================================
+
-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
init(State) ->
- {ok, State}.
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, ""},
+ {short_desc, ""},
+ {desc, ""},
+ {opts, []}])),
+ {ok, State1}.
%% @doc recursively dig down into the library directories specified in the state
%% looking for OTP Applications
diff --git a/src/rlx_prv_relup.erl b/src/rlx_prv_relup.erl
index 241d45b..bc86304 100644
--- a/src/rlx_prv_relup.erl
+++ b/src/rlx_prv_relup.erl
@@ -22,7 +22,7 @@
%%% into a release directory.
-module(rlx_prv_relup).
--behaviour(rlx_provider).
+-behaviour(provider).
-export([init/1,
do/1,
@@ -30,16 +30,28 @@
-include("relx.hrl").
+-define(PROVIDER, relup).
+-define(DEPS, [release]).
+
%%============================================================================
%% API
%%============================================================================
+
-spec init(rlx_state:t()) -> {ok, rlx_state:t()}.
init(State) ->
- {ok, State}.
+ State1 = rlx_state:add_provider(State, providers:create([{name, ?PROVIDER},
+ {module, ?MODULE},
+ {bare, false},
+ {deps, ?DEPS},
+ {example, "relup"},
+ {short_desc, "Builds release upgrade for latest and last release."},
+ {desc, ""},
+ {opts, []}])),
+ {ok, State1}.
-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error().
do(State) ->
- {RelName, RelVsn} = rlx_state:default_configured_release(State),
+ {RelName, RelVsn} = rlx_state:default_configured_release(State),
Release0 = rlx_state:get_realized_release(State, RelName, RelVsn),
make_relup(State, Release0).
@@ -151,4 +163,3 @@ write_relup_file(State, Release, Relup) ->
strip_rel(Name) ->
rlx_util:to_string(filename:join(filename:dirname(Name),
filename:basename(Name, ".rel"))).
-
diff --git a/src/rlx_rel_discovery.erl b/src/rlx_rel_discovery.erl
index 23c0ab9..b7c15bc 100644
--- a/src/rlx_rel_discovery.erl
+++ b/src/rlx_rel_discovery.erl
@@ -21,7 +21,7 @@
%%% @doc This provider uses the lib_dir setting of the state. It searches the
%%% Lib Dirs looking for all OTP Applications that are available. When it finds
%%% those OTP Applications it loads the information about them and adds them to
-%%% the state of available apps. This implements the rlx_provider behaviour.
+%%% the state of available apps. This implements the provider behaviour.
-module(rlx_rel_discovery).
-export([do/3,
diff --git a/src/rlx_state.erl b/src/rlx_state.erl
index 267d9fe..71b96f3 100644
--- a/src/rlx_state.erl
+++ b/src/rlx_state.erl
@@ -44,6 +44,10 @@
cli_args/2,
providers/1,
providers/2,
+ add_provider/2,
+ prepend_hook/3,
+ append_hook/3,
+ hooks/2,
vm_args/1,
vm_args/2,
sys_config/1,
@@ -91,7 +95,7 @@
config_file=[] :: file:filename() | undefined,
cli_args=[] :: proplists:proplist(),
goals=[] :: [rlx_depsolver:constraint()],
- providers=[] :: [rlx_provider:t()],
+ providers=[] :: [providers:t()],
available_apps=[] :: [rlx_app_info:t()],
default_configured_release :: {rlx_release:name() | undefined, rlx_release:vsn() |undefined} | undefined,
vm_args :: file:filename() | undefined,
@@ -122,11 +126,11 @@
%%============================================================================
%% API
%%============================================================================
--spec new(string(), undefined | [atom()]) -> t().
+-spec new(string(), undefined | [atom()]) -> t() | relx:error().
new(Config, Targets) ->
new(Config, [], Targets).
--spec new(string(), proplists:proplist(), undefined | [atom()]) -> t().
+-spec new(string(), proplists:proplist(), undefined | [atom()]) -> t() | relx:error().
new(Config, CommandLineConfig, undefined) ->
new(Config, CommandLineConfig, [release]);
new(Config, CommandLineConfig, Targets)
@@ -151,6 +155,7 @@ new(Config, CommandLineConfig, Targets)
State1 = rlx_state:put(State0, default_libs, true),
State2 = rlx_state:put(State1, system_libs, undefined),
State3 = rlx_state:put(State2, overlay_vars, []),
+
create_logic_providers(State3).
%% @doc the actions targeted for this system
@@ -227,7 +232,7 @@ cli_args(#state_t{cli_args=CliArgs}) ->
cli_args(State, CliArgs) ->
State#state_t{cli_args=CliArgs}.
--spec providers(t()) -> [rlx_provider:t()].
+-spec providers(t()) -> [providers:t()].
providers(#state_t{providers=Providers}) ->
Providers.
@@ -255,10 +260,14 @@ root_dir(#state_t{root_dir=RootDir}) ->
root_dir(State, RootDir) ->
State#state_t{root_dir=filename:absname(RootDir)}.
--spec providers(t(), [rlx_provider:t()]) -> t().
+-spec providers(t(), [providers:t()]) -> t().
providers(M, NewProviders) ->
M#state_t{providers=NewProviders}.
+-spec add_provider(t(), providers:t()) -> t().
+add_provider(M=#state_t{providers=Providers}, Provider) ->
+ M#state_t{providers=[Provider | Providers]}.
+
-spec add_configured_release(t(), rlx_release:t()) -> t().
add_configured_release(M=#state_t{configured_releases=Releases}, Release) ->
M#state_t{configured_releases=ec_dictionary:add({rlx_release:name(Release),
@@ -390,55 +399,61 @@ format(#state_t{log=LogState, output_dir=OutDir, lib_dirs=LibDirs,
rlx_util:indent(Indent + 2), "lib_dirs: \n",
[[rlx_util:indent(Indent + 3), LibDir, ",\n"] || LibDir <- LibDirs],
rlx_util:indent(Indent + 2), "providers: \n",
- [[rlx_util:indent(Indent + 3), rlx_provider:format(Provider), ",\n"] || Provider <- Providers],
+ [[rlx_util:indent(Indent + 3), providers:format(Provider), ",\n"] || Provider <- Providers],
rlx_util:indent(Indent + 2), "provider config values: \n",
[[rlx_util:indent(Indent + 3), io_lib:format("~p", [Value]), ",\n"] || Value <- Values1]].
-%%%===================================================================
-%%% Internal Functions
-%%%===================================================================
-
--spec create_logic_providers(t()) -> t().
-create_logic_providers(State0) ->
- {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State0),
- {DiscoveryProvider, {ok, State2}} = rlx_provider:new(rlx_prv_discover, State1),
- {ReleaseProvider, {ok, State3}} = rlx_provider:new(rlx_prv_release, State2),
- {OverlayProvider, {ok, State4}} = rlx_provider:new(rlx_prv_overlay, State3),
- {ActionProviders, State5} = add_providers([release, relup, tar], State4),
- State5#state_t{providers=[ConfigProvider, DiscoveryProvider,
- ReleaseProvider, OverlayProvider | ActionProviders]}.
-
-add_providers(Actions, State) ->
- add_providers(Actions, [], State).
-
-add_providers([], Providers, State) ->
- {lists:reverse(Providers), State};
-add_providers([Action | T], Providers, State) ->
- case lists:member(Action, actions(State)) of
- true ->
- {Provider, {ok, State1}} = new_provider(Action, State),
- add_providers(T, [Provider | Providers], State1);
- false ->
- add_providers(T, Providers, State)
+prepend_hook(State=#state_t{providers=_Providers}, Target, Hook) ->
+ {Providers1, State1} = add_hook(pre, Target, Hook, State),
+ State1#state_t{providers=Providers1}.
+
+append_hook(State=#state_t{providers=_Providers}, Target, Hook) ->
+ {Providers1, State1} = add_hook(post, Target, Hook, State),
+ State1#state_t{providers=Providers1}.
+
+-spec hooks(t(), atom()) -> {[providers:t()], [providers:t()]}.
+hooks(_State=#state_t{providers=Providers}, Target) ->
+ Provider = providers:get_provider(Target, Providers),
+ providers:hooks(Provider).
+
+%% ===================================================================
+%% Internal functions
+%% ===================================================================
+
+add_hook(Which, Target, Hook, State) ->
+ {ok, State1} = providers:new(Hook, State),
+ Providers1 = providers(State1),
+ HookProvider = providers:get_provider_by_module(Hook, Providers1),
+ Provider = providers:get_provider(Target, Providers1),
+ Hooks = providers:hooks(Provider),
+ NewHooks = add_hook(Which, Hooks, HookProvider),
+ NewProvider = providers:hooks(Provider, NewHooks),
+ {[NewProvider | lists:delete(Provider, Providers1)], State1}.
+
+add_hook(pre, {PreHooks, PostHooks}, Hook) ->
+ {[Hook | PreHooks], PostHooks};
+add_hook(post, {PreHooks, PostHooks}, Hook) ->
+ {PreHooks, [Hook | PostHooks]}.
+
+-spec create_logic_providers(t()) -> t() | relx:error().
+create_logic_providers(State) ->
+ create_all(State, [rlx_prv_discover,
+ rlx_prv_overlay,
+ rlx_prv_release,
+ rlx_prv_assembler,
+ rlx_prv_relup,
+ rlx_prv_archive]).
+
+create_all(State, []) ->
+ State;
+create_all(State, [Module | Rest]) ->
+ case providers:new(Module, State) of
+ {ok, State1} ->
+ create_all(State1, Rest);
+ Error ->
+ Error
end.
-new_provider(release, State) ->
- rlx_provider:new(rlx_prv_assembler, State);
-new_provider(relup, State) ->
- rlx_provider:new(rlx_prv_relup, State);
-new_provider(tar, State) ->
- rlx_provider:new(rlx_prv_archive, State).
-
%%%===================================================================
%%% Test Functions
%%%===================================================================
-
--ifndef(NOTEST).
--include_lib("eunit/include/eunit.hrl").
-
-new_test() ->
- LogState = ec_cmd_log:new(error),
- RCLState = new("", [{log, LogState}], [release]),
- ?assertMatch(LogState, log(RCLState)).
-
--endif.
diff --git a/src/rlx_topo.erl b/src/rlx_topo.erl
index b5585df..d24f227 100644
--- a/src/rlx_topo.erl
+++ b/src/rlx_topo.erl
@@ -32,7 +32,8 @@
%%%-------------------------------------------------------------------
-module(rlx_topo).
--export([sort_apps/1,
+-export([sort/1,
+ sort_apps/1,
format_error/1]).
-include("relx.hrl").
@@ -64,6 +65,12 @@ sort_apps(Apps) ->
E ->
E
end.
+
+%% @doc Do a topological sort on the list of pairs.
+-spec sort([pair()]) -> {ok, [atom()]} | relx:error().
+sort(Pairs) ->
+ iterate(Pairs, [], all(Pairs)).
+
%% @doc nicely format the error from the sort.
-spec format_error(Reason::term()) -> iolist().
format_error({cycle, Pairs}) ->
@@ -82,11 +89,6 @@ format_error({cycle, Pairs}) ->
%%====================================================================
%% Internal Functions
%%====================================================================
-%% @doc Do a topological sort on the list of pairs.
--spec sort([pair()]) -> {ok, [atom()]} | relx:error().
-sort(Pairs) ->
- iterate(Pairs, [], all(Pairs)).
-
-spec names_to_apps([atom()], [rlx_app_info:t()]) -> [rlx_app_info:t()].
names_to_apps(Names, Apps) ->
[find_app_by_name(Name, Apps) || Name <- Names].
diff --git a/test/rlx_command_SUITE.erl b/test/rlx_command_SUITE.erl
index 26783ff..db2794d 100644
--- a/test/rlx_command_SUITE.erl
+++ b/test/rlx_command_SUITE.erl
@@ -61,19 +61,18 @@ normal_passing_case(Config) ->
"-n", RelName, "-v", RelVsn, "-o", Outdir, "-a", "lib1:"++binary_to_list(Lib1)],
{ok, {Opts, Targets}} = getopt:parse(relx:opt_spec_list(), CmdLine),
{ok, State} = rlx_cmd_args:args2state(Opts, Targets),
- {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
- {ok, State2} = rlx_provider:do(ConfigProvider, State1),
- Overrides = rlx_state:overrides(State2),
+ {ok, State1} = rlx_config:do(State),
+ Overrides = rlx_state:overrides(State1),
?assertMatch([{lib1, Lib1}], Overrides),
?assertMatch([Lib1, Lib2],
- rlx_state:lib_dirs(State2)),
- ?assertMatch(Outdir, rlx_state:base_output_dir(State2)),
+ rlx_state:lib_dirs(State1)),
+ ?assertMatch(Outdir, rlx_state:base_output_dir(State1)),
?assertMatch([{app1,{{33,33},{[],[<<"build4">>]}},lte},
{app2,
{{33,22},{[],[]}},
{{45,22},{[],[<<"build">>,21]}}, between}],
- rlx_state:goals(State2)).
+ rlx_state:goals(State1)).
lib_expansion_case(Config) ->
DataDir = proplists:get_value(data_dir, Config),
@@ -85,10 +84,9 @@ lib_expansion_case(Config) ->
CmdLine = ["-l", filename:join(DataDir, "*")],
{ok, {Opts, Targets}} = getopt:parse(relx:opt_spec_list(), CmdLine),
{ok, State} = rlx_cmd_args:args2state(Opts, Targets),
- {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
- {ok, State2} = rlx_provider:do(ConfigProvider, State1),
+ {ok, State1} = rlx_config:do(State),
?assertMatch([Lib1, Lib2],
- rlx_state:lib_dirs(State2)).
+ rlx_state:lib_dirs(State1)).
lib_fail_case(Config) ->
DataDir = proplists:get_value(data_dir, Config),
diff --git a/test/rlx_discover_SUITE.erl b/test/rlx_discover_SUITE.erl
index 7e7015c..ffa64d4 100644
--- a/test/rlx_discover_SUITE.erl
+++ b/test/rlx_discover_SUITE.erl
@@ -49,11 +49,10 @@ init_per_testcase(_, Config) ->
ok = rlx_util:mkdir_p(LibDir1),
ok = rlx_util:mkdir_p(LibDir2),
State = rlx_state:new([], [{lib_dirs, [LibDir1, LibDir2]}], [release]),
- {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
- {ok, State2} = rlx_provider:do(ConfigProvider, State1),
+ {ok, State1} = rlx_config:do(State),
[{lib1, LibDir1},
{lib2, LibDir2},
- {state, State2} | Config].
+ {state, State1} | Config].
all() ->
@@ -78,7 +77,8 @@ normal_case(Config) ->
|| _ <- lists:seq(1, 100)]],
State0 = rlx_state:put(proplists:get_value(state, Config),
default_libs, false),
- {DiscoverProvider, {ok, State1}} = rlx_provider:new(rlx_prv_discover, State0),
+ {ok, State1} = rlx_provider:new(rlx_prv_discover, State0),
+ DiscoverProvider = rlx_provider:get_provider(discover, rlx_state:providers(State1)),
{ok, State2} = rlx_provider:do(DiscoverProvider, State1),
lists:foreach(fun(App) ->
@@ -116,7 +116,8 @@ no_beam_case(Config) ->
State0 = proplists:get_value(state, Config),
%% Deliberately disable release discovery when running `rlx_prv_discover`
State1 = rlx_state:put(State0, disable_rel_discovery, true),
- {DiscoverProvider, {ok, State2}} = rlx_provider:new(rlx_prv_discover, State1),
+ {ok, State2} = rlx_provider:new(rlx_prv_discover, State1),
+ DiscoverProvider = rlx_provider:get_provider(discover, rlx_state:providers(State2)),
?assertMatch({ok, _},
rlx_provider:do(DiscoverProvider, State2)).
@@ -145,7 +146,8 @@ bad_ebin_case(Config) ->
ok = filelib:ensure_dir(Filename),
ok = ec_file:write_term(Filename, get_bad_app_metadata(BadName, BadVsn)),
State0 = proplists:get_value(state, Config),
- {DiscoverProvider, {ok, State1}} = rlx_provider:new(rlx_prv_discover, State0),
+ {ok, State1} = rlx_provider:new(rlx_prv_discover, State0),
+ DiscoverProvider = rlx_provider:get_provider(discover, rlx_state:providers(State1)),
{ok, State2} = rlx_provider:do(DiscoverProvider, State1),
?assertMatch([], [App || App <- rlx_state:available_apps(State2),
BadName =:= rlx_app_info:name(App)]).
@@ -170,7 +172,8 @@ shallow_app_discovery(Config) ->
State0 = rlx_state:put(proplists:get_value(state, Config),
default_libs, false),
State1 = rlx_state:put(State0, enable_shallow_app_discovery, true),
- {DiscoverProvider, {ok, State2}} = rlx_provider:new(rlx_prv_discover, State1),
+ {ok, State2} = rlx_provider:new(rlx_prv_discover, State1),
+ DiscoverProvider = rlx_provider:get_provider(discover, rlx_state:providers(State2)),
{ok, State3} = rlx_provider:do(DiscoverProvider, State2),
lists:foreach(fun(App) ->
?assertMatch(true, lists:member(App, rlx_state:available_apps(State3)))
diff --git a/test/rlx_release_SUITE.erl b/test/rlx_release_SUITE.erl
index 6f067dc..112afc8 100644
--- a/test/rlx_release_SUITE.erl
+++ b/test/rlx_release_SUITE.erl
@@ -61,10 +61,9 @@ init_per_testcase(_, Config) ->
LibDir1 = filename:join([DataDir, create_random_name("lib_dir1_")]),
ok = rlx_util:mkdir_p(LibDir1),
State = rlx_state:new([], [{lib_dirs, [LibDir1]}], [release]),
- {ConfigProvider, {ok, State1}} = rlx_provider:new(rlx_prv_config, State),
- {ok, State2} = rlx_provider:do(ConfigProvider, State1),
+ {ok, State1} = rlx_config:do(State),
[{lib1, LibDir1},
- {state, State2} | Config].
+ {state, State1} | Config].
all() ->
[make_release, make_extend_release, make_scriptless_release,
@@ -178,7 +177,7 @@ make_invalid_config_release(Config) ->
goal_app_2,]}"),
OutputDir = filename:join([proplists:get_value(data_dir, Config),
create_random_name("relx-output")]),
- {error, {rlx_prv_config,
+ {error, {rlx_config,
{consult, _, _}}} = relx:do(undefined, undefined, [], [LibDir1], 3,
OutputDir, ConfigFile).
@@ -575,7 +574,7 @@ overlay_release(Config) ->
Error ->
erlang:throw({failed_to_consult, Error})
end,
-
+
{ok, ReadFileInfo} = file:read_file_info(filename:join([OutputDir, "foo", "test_template_resolved"])),
?assertEqual(8#100777, ReadFileInfo#file_info.mode),
@@ -742,12 +741,12 @@ make_relup_release(Config) ->
{ok, _} = relx:do(foo, "0.0.2", [], [LibDir1], 3,
OutputDir, ConfigFile),
{ok, State} = relx:do([{relname, foo},
- {relvsn, "0.0.3"},
- {goals, []},
- {lib_dirs, [LibDir1]},
- {log_level, 3},
- {output_dir, OutputDir},
- {config, ConfigFile}], ["release", "relup"]),
+ {relvsn, "0.0.3"},
+ {goals, []},
+ {lib_dirs, [LibDir1]},
+ {log_level, 3},
+ {output_dir, OutputDir},
+ {config, ConfigFile}], ["release", "relup"]),
%% we should have one 'resolved' release and three discovered realized_releases.
?assertMatch([{foo, "0.0.1"},