Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebar3 support and code sharing #227

Merged
merged 5 commits into from Oct 11, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 1 addition & 3 deletions .travis.yml
@@ -1,5 +1,6 @@
language: erlang
otp_release:
- 17.1
- 17.0
- R16B03-1
- R16B03
Expand All @@ -10,9 +11,6 @@ otp_release:
- R15B02
- R15B01
- R15B
- R14B04
- R14B03
- R14B02
script: "make get-rebar && make rebuild"
branches:
only:
Expand Down
1 change: 0 additions & 1 deletion include/relx.hrl
@@ -1,4 +1,3 @@

%% Copyright 2012 Erlware, LLC. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
Expand Down
7 changes: 4 additions & 3 deletions rebar.config
Expand Up @@ -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"}}},
Expand Down Expand Up @@ -36,6 +39,4 @@
{erlydtl_opts, [{doc_root, "priv/templates"},
{compiler_options, [report, return, debug_info]}]}.
{escript_incl_apps,
[getopt, erlware_commons, erlydtl]}.

{first_files, [rcl_provider]}.
[getopt, erlware_commons, erlydtl, providers]}.
2 changes: 1 addition & 1 deletion src/relx.app.src
Expand Up @@ -23,4 +23,4 @@
{vsn, "semver"},
{modules, []},
{registered, []},
{applications, [kernel, stdlib, getopt, erlware_commons]}]}.
{applications, [kernel, stdlib, getopt, erlware_commons, providers]}]}.
63 changes: 35 additions & 28 deletions src/relx.erl
Expand Up @@ -21,6 +21,7 @@
-module(relx).

-export([main/1,
main/2,
do/2,
do/7,
do/8,
Expand All @@ -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}} ->
Expand All @@ -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} ->
Expand Down Expand Up @@ -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]);
Expand Down Expand Up @@ -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, _}) ->
Expand All @@ -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() ->
Expand Down
2 changes: 1 addition & 1 deletion src/rlx_app_discovery.erl
Expand Up @@ -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,
Expand Down
27 changes: 19 additions & 8 deletions src/rlx_cmd_args.erl
Expand Up @@ -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}) ->
Expand All @@ -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().
Expand All @@ -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("") ->
Expand All @@ -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) ->
Expand Down
53 changes: 30 additions & 23 deletions src/rlx_prv_config.erl → src/rlx_config.erl
Expand Up @@ -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").
Expand All @@ -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().
Expand Down Expand Up @@ -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().
Expand All @@ -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
Expand Down Expand Up @@ -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([]) ->
Expand Down
6 changes: 3 additions & 3 deletions src/rlx_dscv_util.erl
Expand Up @@ -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,
Expand Down Expand Up @@ -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 ->
Expand Down