aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/relx.app.src2
-rw-r--r--src/relx.erl63
-rw-r--r--src/rlx_app_discovery.erl2
-rw-r--r--src/rlx_cmd_args.erl27
-rw-r--r--src/rlx_config.erl (renamed from src/rlx_prv_config.erl)53
-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.erl21
-rw-r--r--src/rlx_prv_overlay.erl23
-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.erl117
-rw-r--r--src/rlx_topo.erl14
16 files changed, 263 insertions, 261 deletions
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..37918be 100644
--- a/src/relx.erl
+++ b/src/relx.erl
@@ -21,6 +21,7 @@
-module(relx).
-export([main/1,
+ main/2,
do/2,
do/7,
do/8,
@@ -44,6 +45,9 @@
%%============================================================================
-spec main([string()]) -> ok | error() | {ok, rlx_state:t()}.
main(Args) ->
+ main([], Args).
+
+main(ApiOptions, Args) ->
OptSpecList = opt_spec_list(),
Result = case getopt:parse(OptSpecList, Args) of
{ok, {Options, NonOptions}} ->
@@ -57,7 +61,8 @@ main(Args) ->
true ->
usage();
false ->
- do([{caller, command_line} | Options], NonOptions)
+ application:start(relx),
+ do(ApiOptions++[{caller, command_line} | Options], NonOptions)
end
end;
{error, Detail} ->
@@ -212,7 +217,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 +245,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 +276,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..ac3e718 100644
--- a/src/rlx_cmd_args.erl
+++ b/src/rlx_cmd_args.erl
@@ -69,7 +69,7 @@ format_error({invalid_option_arg, Arg}) ->
io_lib:format("Invalid code path argument -n ~p~n", [Path])
end;
format_error({invalid_config_file, Config}) ->
- io_lib:format("Invalid configuration file specified: ~s", [Config]);
+ io_lib:format("Invalid configuration file specified: ~p", [Config]);
format_error({invalid_caller, Caller}) ->
io_lib:format("Invalid caller specified: ~s", [Caller]);
format_error({failed_to_parse, Spec}) ->
@@ -87,15 +87,19 @@ 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)}
+ case rlx_state:new(Config, CommandLineConfig, Targets) of
+ {error, Error} ->
+ {error, Error};
+ State ->
+ {ok, State}
+ end
end.
-spec convert_targets([string()]) -> {ok, release | relup} | relx:error().
@@ -117,8 +121,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} | relx:error().
validate_config(undefined) ->
{ok, undefined};
validate_config("") ->
@@ -128,7 +132,14 @@ validate_config(Config) ->
true ->
{ok, filename:absname(Config)};
false ->
- ?RLX_ERROR({invalid_config_file, Config})
+ case io_lib:printable_list(Config) of
+ true ->
+ ?RLX_ERROR({invalid_config_file, Config});
+ false when is_list(Config) ->
+ {ok, Config};
+ false ->
+ ?RLX_ERROR({invalid_config_file, Config})
+ end
end.
run_creates(Opts) ->
diff --git a/src/rlx_prv_config.erl b/src/rlx_config.erl
index 5724661..dbfe1c6 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().
@@ -105,20 +97,26 @@ parent_dir([_H], Acc) ->
parent_dir([H | T], Acc) ->
parent_dir(T, [H | Acc]).
--spec load_config(file:filename(), rlx_state:t()) ->
+-spec load_config(file:filename() | proplists:proplist(), rlx_state:t()) ->
{ok, rlx_state:t()} | relx:error().
load_config(ConfigFile, State) ->
{ok, CurrentCwd} = file:get_cwd(),
- ok = file:set_cwd(filename:dirname(ConfigFile)),
- Result = case file:consult(ConfigFile) of
- {error, Reason} ->
- ?RLX_ERROR({consult, ConfigFile, Reason});
- {ok, Terms} ->
- CliTerms = rlx_state:cli_args(State),
- lists:foldl(fun load_terms/2, {ok, State}, merge_configs(CliTerms, Terms))
- end,
- ok = file:set_cwd(CurrentCwd),
- Result.
+ case filelib:is_regular(ConfigFile) of
+ true ->
+ ok = file:set_cwd(filename:dirname(ConfigFile)),
+ Result = case file:consult(ConfigFile) of
+ {error, Reason} ->
+ ?RLX_ERROR({consult, ConfigFile, Reason});
+ {ok, Terms} ->
+ CliTerms = rlx_state:cli_args(State),
+ lists:foldl(fun load_terms/2, {ok, State}, merge_configs(CliTerms, Terms))
+ end,
+ ok = file:set_cwd(CurrentCwd),
+ Result;
+ false ->
+ CliTerms = rlx_state:cli_args(State),
+ lists:foldl(fun load_terms/2, {ok, State}, merge_configs(CliTerms, ConfigFile))
+ end.
-spec load_terms(term(), {ok, rlx_state:t()} | relx:error()) ->
{ok, rlx_state:t()} | relx:error().
@@ -143,6 +141,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 +231,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..520cf15 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
@@ -97,6 +109,7 @@ add_common_project_dirs(State) ->
Apps = filename:join(Root, "apps"),
Lib = filename:join(Root, "lib"),
Deps = filename:join(Root, "deps"),
+ Rebar3Deps = filename:join(Root, "_deps"),
Ebin = filename:join(Root, "ebin"),
lists:foldl(fun(Dir, LibDirs) ->
case ec_file:exists(Dir) of
@@ -105,7 +118,7 @@ add_common_project_dirs(State) ->
false ->
LibDirs
end
- end, [], [Deps, Lib, Apps, Ebin])
+ end, [], [Rebar3Deps, Deps, Lib, Apps, Ebin])
end.
-spec add_system_lib_dir(rlx_state:t()) -> [file:name()].
diff --git a/src/rlx_prv_overlay.erl b/src/rlx_prv_overlay.erl
index 23df218..f7e2be8 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
@@ -365,7 +377,12 @@ get_relative_root(State) ->
[] ->
rlx_state:root_dir(State);
Config ->
- filename:dirname(Config)
+ case filelib:is_regular(Config) of
+ true ->
+ filename:dirname(Config);
+ false ->
+ rlx_state:root_dir(State)
+ end
end.
-spec is_directory(file:name(), file:name()) -> boolean().
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..a25c60f 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
@@ -211,11 +216,11 @@ goals(#state_t{goals=TS}) ->
goals(State, Goals) ->
State#state_t{goals=Goals}.
--spec config_file(t()) -> file:filename() | undefined.
+-spec config_file(t()) -> file:filename() | proplists:proplist() | undefined.
config_file(#state_t{config_file=ConfigFiles}) ->
ConfigFiles.
--spec config_file(t(), file:filename() | undefined) -> t().
+-spec config_file(t(), file:filename() | proplists:proplist() | undefined) -> t().
config_file(State, ConfigFiles) ->
State#state_t{config_file=ConfigFiles}.
@@ -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].