diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/relx.app.src (renamed from src/relcool.app.src) | 2 | ||||
-rw-r--r-- | src/relx.erl (renamed from src/relcool.erl) | 165 | ||||
-rw-r--r-- | src/rlx_app_discovery.erl (renamed from src/rcl_app_discovery.erl) | 44 | ||||
-rw-r--r-- | src/rlx_app_info.erl (renamed from src/rcl_app_info.erl) | 26 | ||||
-rw-r--r-- | src/rlx_cmd_args.erl (renamed from src/rcl_cmd_args.erl) | 172 | ||||
-rw-r--r-- | src/rlx_depsolver.erl (renamed from src/rcl_depsolver.erl) | 36 | ||||
-rw-r--r-- | src/rlx_depsolver_culprit.erl (renamed from src/rcl_depsolver_culprit.erl) | 96 | ||||
-rw-r--r-- | src/rlx_dscv_util.erl (renamed from src/rcl_dscv_util.erl) | 6 | ||||
-rw-r--r-- | src/rlx_goal.erl | 263 | ||||
-rw-r--r-- | src/rlx_goal.peg (renamed from src/rcl_goal.peg) | 10 | ||||
-rw-r--r-- | src/rlx_goal_utils.erl (renamed from src/rcl_goal_utils.erl) | 6 | ||||
-rw-r--r-- | src/rlx_log.erl (renamed from src/rcl_log.erl) | 48 | ||||
-rw-r--r-- | src/rlx_provider.erl (renamed from src/rcl_provider.erl) | 18 | ||||
-rw-r--r-- | src/rlx_prv_assembler.erl (renamed from src/rcl_prv_assembler.erl) | 261 | ||||
-rw-r--r-- | src/rlx_prv_config.erl (renamed from src/rcl_prv_config.erl) | 64 | ||||
-rw-r--r-- | src/rlx_prv_discover.erl (renamed from src/rcl_prv_discover.erl) | 46 | ||||
-rw-r--r-- | src/rlx_prv_overlay.erl (renamed from src/rcl_prv_overlay.erl) | 182 | ||||
-rw-r--r-- | src/rlx_prv_release.erl (renamed from src/rcl_prv_release.erl) | 84 | ||||
-rw-r--r-- | src/rlx_rel_discovery.erl (renamed from src/rcl_rel_discovery.erl) | 48 | ||||
-rw-r--r-- | src/rlx_release.erl (renamed from src/rcl_release.erl) | 124 | ||||
-rw-r--r-- | src/rlx_state.erl (renamed from src/rcl_state.erl) | 177 | ||||
-rw-r--r-- | src/rlx_topo.erl (renamed from src/rcl_topo.erl) | 58 | ||||
-rw-r--r-- | src/rlx_util.erl (renamed from src/rcl_util.erl) | 13 |
23 files changed, 1253 insertions, 696 deletions
diff --git a/src/relcool.app.src b/src/relx.app.src index 0c1c45a..3f655cf 100644 --- a/src/relcool.app.src +++ b/src/relx.app.src @@ -18,7 +18,7 @@ %% under the License. %% -{application, relcool, +{application, relx, [{description, "Release assembler for Erlang/OTP Releases"}, {vsn, "0.0.5"}, {modules, []}, diff --git a/src/relcool.erl b/src/relx.erl index 7750efa..30ee77f 100644 --- a/src/relcool.erl +++ b/src/relx.erl @@ -18,9 +18,10 @@ %%% @author Eric Merritt <[email protected]> %%% @copyright (C) 2012 Erlware, LLC. %%% @doc --module(relcool). +-module(relx). -export([main/1, + do/2, do/7, do/8, do/9, @@ -29,104 +30,148 @@ -export_type([error/0]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% types %%============================================================================ -type error() :: {error, {Module::module(), Reason::term()}}. --type goal() :: string() | binary() | rcl_depsolver:constraint(). +-type goal() :: string() | binary() | rlx_depsolver:constraint(). %%============================================================================ %% API %%============================================================================ --spec main([string()]) -> ok | error() | {ok, rcl_state:t()}. +-spec main([string()]) -> ok | error() | {ok, rlx_state:t()}. main(Args) -> OptSpecList = opt_spec_list(), - Result = - case rcl_cmd_args:args2state(getopt:parse(OptSpecList, Args)) of - {ok, State} -> - run_relcool_process(rcl_state:caller(State, command_line)); - Error={error, _} -> - Error - end, + Result = case getopt:parse(OptSpecList, Args) of + {ok, {Options, NonOptions}} -> + do([{caller, command_line} | Options], NonOptions); + {error, Detail} -> + ?RLX_ERROR({opt_parse, Detail}) + end, case Result of {error, _} -> - report_error(rcl_state:caller(rcl_state:new([], undefined), + report_error(rlx_state:caller(rlx_state:new([], undefined), command_line), Result); _ -> Result end. -%% @doc provides an API to run the Relcool process from erlang applications +%% @doc provides an API to run the Relx process from erlang applications %% %% @param RelName - The release name to build (maybe `undefined`) %% @param RelVsn - The release version to build (maybe `undefined`) -%% @param Goals - The release goals for the system in depsolver or Relcool goal +%% @param Goals - The release goals for the system in depsolver or Relx goal %% format %% @param LibDirs - The library dirs that should be used for the system %% @param OutputDir - The directory where the release should be built to %% @param Configs - The list of config files for the system --spec do(atom(), string(), [goal()], [file:name()], rcl_log:log_level(), +-spec do(atom(), string(), [goal()], [file:name()], rlx_log:log_level(), [file:name()], file:name() | undefined) -> - ok | error() | {ok, rcl_state:t()}. + ok | error() | {ok, rlx_state:t()}. do(RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, Config) -> {ok, Cwd} = file:get_cwd(), do(Cwd, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, [], Config). -%% @doc provides an API to run the Relcool process from erlang applications +%% @doc provides an API to run the Relx process from erlang applications %% %% @param RootDir - The root directory for the project %% @param RelName - The release name to build (maybe `undefined`) %% @param RelVsn - The release version to build (maybe `undefined`) -%% @param Goals - The release goals for the system in depsolver or Relcool goal +%% @param Goals - The release goals for the system in depsolver or Relx goal %% format %% @param LibDirs - The library dirs that should be used for the system %% @param OutputDir - The directory where the release should be built to %% @param Configs - The list of config files for the system -spec do(file:name(), atom(), string(), [goal()], [file:name()], - rcl_log:log_level(), [file:name()], file:name() | undefined) -> - ok | error() | {ok, rcl_state:t()}. + rlx_log:log_level(), [file:name()], file:name() | undefined) -> + ok | error() | {ok, rlx_state:t()}. do(RootDir, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, Configs) -> do(RootDir, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, [], Configs). -%% @doc provides an API to run the Relcool process from erlang applications +%% @doc provides an API to run the Relx process from erlang applications %% %% @param RootDir - The root directory for the system %% @param RelName - The release name to build (maybe `undefined`) %% @param RelVsn - The release version to build (maybe `undefined`) -%% @param Goals - The release goals for the system in depsolver or Relcool goal +%% @param Goals - The release goals for the system in depsolver or Relx goal %% format %% @param LibDirs - The library dirs that should be used for the system %% @param OutputDir - The directory where the release should be built to %% @param Overrides - A list of overrides for the system %% @param Configs - The list of config files for the system -spec do(file:name(), atom(), string(), [goal()], [file:name()], - rcl_log:log_level(), [file:name()], [{atom(), file:name()}], file:name() | undefined) -> - ok | error() | {ok, rcl_state:t()}. + rlx_log:log_level(), [file:name()], [{atom(), file:name()}], file:name() | undefined) -> + ok | error() | {ok, rlx_state:t()}. do(RootDir, RelName, RelVsn, Goals, LibDirs, LogLevel, OutputDir, Overrides, Config) -> - State = rcl_state:new([{relname, RelName}, - {relvsn, RelVsn}, - {goals, Goals}, - {overrides, Overrides}, - {output_dir, OutputDir}, - {lib_dirs, LibDirs}, - {root_dir, RootDir}, - {log, rcl_log:new(LogLevel)}, - {config, Config}], - release), - run_relcool_process(rcl_state:caller(State, api)). + do([{relname, RelName}, + {relvsn, RelVsn}, + {goals, Goals}, + {overrides, Overrides}, + {output_dir, OutputDir}, + {lib_dirs, LibDirs}, + {root_dir, RootDir}, + {log_level, LogLevel}, + {config, Config}], + ["release"]). +%% @doc provides an API to run the Relx process from erlang applications +%% +%% @param Opts - A proplist of options. There are good defaults for each of +%% these entries, so any or all may be omitted. Individual options may be: +%% +%% <dl> +%% <dt><pre>{relname, RelName}</pre></dt> +%% <dd>The release name to build </dd> +%% <dt><pre>{relvsn, RelVsn}</pre></dt> +%% <dd>The release version to build</dd> +%% <dt><pre>{goals, Goals}</pre></dt> +%% <dd>The release goals for the system in depsolver or Relx goal +%% format (@see goals())</dd> +%% <dt><pre>{lib_dirs, LibDirs}</pre></dt> +%% <dd>A list of library dirs that should be used for the system</dd> +%% <dt><pre>{lib_dir, LibDir}</pre></dt> +%% <dd>A single lib dir that should be used for the system, may appear any +%% number of times and may be used in conjunction with lib_dirs</dd> +%% <dt><pre>{output_dir, OutputDir}</pre></dt> +%% <dd>The directory where the release should be built to</dd> +%% <dt><pre>{root_dir, RootDir}</pre></dt> +%% <dd>The base directory for this run of relx. </dd> +%% <dt><pre>{config, Config}</pre></dt> +%% <dd>The path to a relx config file</dd> +%% <dt><pre>{log_level, LogLevel}</pre></dt> +%% <dd>Defines the verbosity of output. Maybe a number between 0 and 2, with +%% with higher values being more verbose</dd> +%% <dt><pre>{overrides, Overrides}</pre></dt> +%% <dd>A list of app overrides for the system in the form of [{AppName:atom(), +%% Dir:string() | binary()} | string() | binary()] where the string or binary +%% is in the form "AppName:AppDir"</dd> +%% <dt><pre>{override, Override}</pre></dt> +%% <dd>A single of app override for the system in the same form as entries for +%% Overrides</dd> +%% </dl> +-spec do(proplists:proplist(), [string()]) -> + ok | error() | {ok, rlx_state:t()}. +do(Opts, NonOpts) -> + case rlx_cmd_args:args2state(Opts, NonOpts) of + {ok, State} -> + run_relx_process(State); + Error={error, _} -> + Error + end. -spec opt_spec_list() -> [getopt:option_spec()]. opt_spec_list() -> [{relname, $n, "relname", string, "Specify the name for the release that will be generated"}, {relvsn, $v, "relvsn", string, "Specify the version for the release"}, - {goals, $g, "goal", string, + {goal, $g, "goal", string, "Specify a target constraint on the system. These are usually the OTP"}, + {upfrom, $u, "upfrom", string, + "Only valid with relup target, specify the release to upgrade from"}, {output_dir, $o, "output-dir", string, "The output directory for the release. This is `./` by default."}, {lib_dir, $l, "lib-dir", string, @@ -136,24 +181,30 @@ opt_spec_list() -> "Disable the default system added lib dirs (means you must add them all manually"}, {log_level, $V, "verbose", {integer, 1}, "Verbosity level, maybe between 0 and 2"}, + {override_app, $a, "override_app", string, + "Provide an app name and a directory to override in the form <appname>:<app directory>"}, {config, $c, "config", {string, ""}, "The path to a config file"}, {root_dir, $r, "root", string, "The project root directory"}]. -spec format_error(Reason::term()) -> iolist(). format_error({invalid_return_value, Provider, Value}) -> - [rcl_provider:format(Provider), " returned an invalid value ", + [rlx_provider: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]); +format_error({opt_parse, Arg}) -> + io_lib:format("~p~n", [Arg]); format_error({error, {Module, Reason}}) -> io_lib:format("~s~n", [Module:format_error(Reason)]). %%============================================================================ %% internal api %%============================================================================ -run_relcool_process(State) -> - rcl_log:info(rcl_state:log(State), "Starting relcool build process ..."), - rcl_log:debug(rcl_state:log(State), +run_relx_process(State) -> + rlx_log:info(rlx_state:log(State), "Starting relx build process ..."), + rlx_log:debug(rlx_state:log(State), fun() -> - rcl_state:format(State) + rlx_state:format(State) end), run_providers(State). @@ -163,16 +214,16 @@ run_relcool_process(State) -> %% providers again and run the rest of them (because they could have been %% updated by the config process). run_providers(State0) -> - [ConfigProvider | _] = rcl_state:providers(State0), + [ConfigProvider | _] = rlx_state:providers(State0), case run_provider(ConfigProvider, {ok, State0}) of Err = {error, _} -> Err; {ok, State1} -> - RootDir = rcl_state:root_dir(State1), + RootDir = rlx_state:root_dir(State1), ok = file:set_cwd(RootDir), - Providers = rcl_state:providers(State1), + Providers = rlx_state:providers(State1), Result = run_providers(ConfigProvider, Providers, State1), - handle_output(State1, rcl_state:caller(State1), Result) + handle_output(State1, rlx_state:caller(State1), Result) end. handle_output(State, command_line, E={error, _}) -> @@ -193,33 +244,33 @@ run_providers(ConfigProvider, Providers, State0) -> lists:foldl(fun run_provider/2, {ok, State0}, Providers) end. --spec run_provider(rcl_provider:t(), {ok, rcl_state:t()} | error()) -> - {ok, rcl_state:t()} | error(). +-spec run_provider(rlx_provider:t(), {ok, rlx_state:t()} | error()) -> + {ok, rlx_state:t()} | error(). run_provider(_Provider, Error = {error, _}) -> Error; run_provider(Provider, {ok, State0}) -> - rcl_log:debug(rcl_state:log(State0), "Running provider ~p~n", - [rcl_provider:impl(Provider)]), - case rcl_provider:do(Provider, State0) of + rlx_log:debug(rlx_state:log(State0), "Running provider ~p~n", + [rlx_provider:impl(Provider)]), + case rlx_provider:do(Provider, State0) of {ok, State1} -> - rcl_log:debug(rcl_state:log(State0), "Provider successfully run: ~p~n", - [rcl_provider:impl(Provider)]), + rlx_log:debug(rlx_state:log(State0), "Provider successfully run: ~p~n", + [rlx_provider:impl(Provider)]), {ok, State1}; E={error, _} -> - rcl_log:debug(rcl_state:log(State0), "Provider (~p) failed with: ~p~n", - [rcl_provider:impl(Provider), E]), + rlx_log:debug(rlx_state:log(State0), "Provider (~p) failed with: ~p~n", + [rlx_provider:impl(Provider), E]), E end. -spec usage() -> ok. usage() -> - getopt:usage(opt_spec_list(), "relcool", "[*release-specification-file*]"). + getopt:usage(opt_spec_list(), "relx", "[*release-specification-file*]"). --spec report_error(rcl_state:t(), error()) -> none() | error(). +-spec report_error(rlx_state:t(), error()) -> none() | error(). report_error(State, Error) -> io:format(format_error(Error)), usage(), - case rcl_state:caller(State) of + case rlx_state:caller(State) of command_line -> erlang:halt(127); api -> diff --git a/src/rcl_app_discovery.erl b/src/rlx_app_discovery.erl index 7b04b19..e6b6e2c 100644 --- a/src/rcl_app_discovery.erl +++ b/src/rlx_app_discovery.erl @@ -21,13 +21,13 @@ %%% @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 rcl_provider behaviour. --module(rcl_app_discovery). +%%% the state of available apps. This implements the rlx_provider behaviour. +-module(rlx_app_discovery). -export([do/2, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API @@ -35,12 +35,12 @@ %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications --spec do(rcl_state:t(), [filename:name()]) -> {ok, [rcl_app_info:t()]} | relcool:error(). +-spec do(rlx_state:t(), [filename:name()]) -> {ok, [rlx_app_info:t()]} | relx:error(). do(State, LibDirs) -> - rcl_log:info(rcl_state:log(State), + rlx_log:info(rlx_state:log(State), fun() -> ["Resolving OTP Applications from directories:\n", - [[rcl_util:indent(1), LibDir, "\n"] || LibDir <- LibDirs]] + [[rlx_util:indent(1), LibDir, "\n"] || LibDir <- LibDirs]] end), resolve_app_metadata(State, LibDirs). @@ -53,7 +53,7 @@ format_error(ErrorDetails) %%% Internal Functions %%%=================================================================== resolve_app_metadata(State, LibDirs) -> - AppMeta0 = lists:flatten(rcl_dscv_util:do(fun discover_dir/2, LibDirs)), + AppMeta0 = lists:flatten(rlx_dscv_util:do(fun discover_dir/2, LibDirs)), case [case Err of {error, Ret} -> Ret @@ -66,26 +66,26 @@ resolve_app_metadata(State, LibDirs) -> false end] of [] -> - SkipApps = rcl_state:skip_apps(State), + SkipApps = rlx_state:skip_apps(State), AppMeta1 = [App || {ok, App} <- setup_overrides(State, AppMeta0), - not lists:keymember(rcl_app_info:name(App), 1, SkipApps)], - rcl_log:debug(rcl_state:log(State), + not lists:keymember(rlx_app_info:name(App), 1, SkipApps)], + rlx_log:debug(rlx_state:log(State), fun() -> ["Resolved the following OTP Applications from the system: \n", - [[rcl_app_info:format(1, App), "\n"] || App <- AppMeta1]] + [[rlx_app_info:format(1, App), "\n"] || App <- AppMeta1]] end), {ok, AppMeta1}; Errors -> - ?RCL_ERROR(Errors) + ?RLX_ERROR(Errors) end. app_name({error, _}) -> undefined; app_name({ok, AppMeta}) -> - rcl_app_info:name(AppMeta). + rlx_app_info:name(AppMeta). setup_overrides(State, AppMetas0) -> - Overrides = rcl_state:overrides(State), + Overrides = rlx_state:overrides(State), AppMetas1 = [AppMeta || AppMeta <- AppMetas0, not lists:keymember(app_name(AppMeta), 1, Overrides)], [case is_valid_otp_app(filename:join([FileName, <<"ebin">>, @@ -95,7 +95,7 @@ setup_overrides(State, AppMetas0) -> Error = {error, _} -> Error; {ok, App} -> - {ok, rcl_app_info:link(App, true)} + {ok, rlx_app_info:link(App, true)} end || {AppName, FileName} <- Overrides] ++ AppMetas1. @@ -123,13 +123,13 @@ format_detail({app_info_error, {Module, Detail}}) -> Module:format_error(Detail). -spec discover_dir([file:name()], directory | file) -> - {ok, rcl_app_info:t()} | {error, Reason::term()}. + {ok, rlx_app_info:t()} | {error, Reason::term()}. discover_dir(_File, directory) -> {noresult, true}; discover_dir(File, file) -> is_valid_otp_app(File). --spec is_valid_otp_app(file:name()) -> {ok, rcl_app_info:t()} | {error, Reason::term()} | +-spec is_valid_otp_app(file:name()) -> {ok, rlx_app_info:t()} | {error, Reason::term()} | {noresult, false}. is_valid_otp_app(File) -> @@ -148,7 +148,7 @@ is_valid_otp_app(File) -> end. -spec has_at_least_one_beam(file:name(), file:filename()) -> - {ok, rcl_app_info:t()} | {error, Reason::term()}. + {ok, rlx_app_info:t()} | {error, Reason::term()}. has_at_least_one_beam(EbinDir, File) -> case file:list_dir(EbinDir) of {ok, List} -> @@ -163,7 +163,7 @@ has_at_least_one_beam(EbinDir, File) -> end. -spec gather_application_info(file:name(), file:filename()) -> - {ok, rcl_app_info:t()} | {error, Reason::term()}. + {ok, rlx_app_info:t()} | {error, Reason::term()}. gather_application_info(EbinDir, File) -> AppDir = filename:dirname(EbinDir), case file:consult(File) of @@ -176,7 +176,7 @@ gather_application_info(EbinDir, File) -> end. -spec get_vsn(file:name(), atom(), proplists:proplist()) -> - {ok, rcl_app_info:t()} | {error, Reason::term()}. + {ok, rlx_app_info:t()} | {error, Reason::term()}. get_vsn(AppDir, AppName, AppDetail) -> case proplists:get_value(vsn, AppDetail) of undefined -> @@ -191,11 +191,11 @@ get_vsn(AppDir, AppName, AppDetail) -> end. -spec get_deps(file:name(), atom(), string(), proplists:proplist()) -> - {ok, rcl_app_info:t()} | {error, Reason::term()}. + {ok, rlx_app_info:t()} | {error, Reason::term()}. get_deps(AppDir, AppName, AppVsn, AppDetail) -> ActiveApps = proplists:get_value(applications, AppDetail, []), LibraryApps = proplists:get_value(included_applications, AppDetail, []), - rcl_app_info:new(AppName, AppVsn, AppDir, ActiveApps, LibraryApps). + rlx_app_info:new(AppName, AppVsn, AppDir, ActiveApps, LibraryApps). %%%=================================================================== %%% Test Functions diff --git a/src/rcl_app_info.erl b/src/rlx_app_info.erl index dadc579..de6ed7d 100644 --- a/src/rcl_app_info.erl +++ b/src/rlx_app_info.erl @@ -34,7 +34,7 @@ %%% application metadata. %%% </ul> %%% --module(rcl_app_info). +-module(rlx_app_info). -export([new/0, new/5, @@ -57,7 +57,7 @@ -export_type([t/0]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). -record(app_info_t, {name :: atom(), vsn :: ec_semver:semver(), @@ -82,20 +82,20 @@ new() -> %% @doc build a complete version of the app info with all fields set. -spec new(atom(), string(), file:name(), [atom()], [atom()]) -> - {ok, t()} | relcool:error(). + {ok, t()} | relx:error(). new(AppName, Vsn, Dir, ActiveDeps, LibraryDeps) -> new(AppName, Vsn, Dir, ActiveDeps, LibraryDeps, false). %% @doc build a complete version of the app info with all fields set. -spec new(atom(), string(), file:name(), [atom()], [atom()], boolean()) -> - {ok, t()} | relcool:error(). + {ok, t()} | relx:error(). new(AppName, Vsn, Dir, ActiveDeps, LibraryDeps, Link) when erlang:is_atom(AppName), erlang:is_list(ActiveDeps), erlang:is_list(LibraryDeps) -> case parse_version(Vsn) of {fail, _} -> - ?RCL_ERROR({vsn_parse, AppName}); + ?RLX_ERROR({vsn_parse, AppName}); ParsedVsn -> {ok, #app_info_t{name=AppName, vsn=ParsedVsn, dir=Dir, active_deps=ActiveDeps, @@ -120,12 +120,12 @@ vsn(#app_info_t{vsn=Vsn}) -> vsn_as_string(#app_info_t{vsn=Vsn}) -> erlang:binary_to_list(erlang:iolist_to_binary(ec_semver:format(Vsn))). --spec vsn(t(), string()) -> {ok, t()} | relcool:error(). +-spec vsn(t(), string()) -> {ok, t()} | relx:error(). vsn(AppInfo=#app_info_t{name=AppName}, AppVsn) when erlang:is_list(AppVsn) -> case parse_version(AppVsn) of {fail, _} -> - ?RCL_ERROR({vsn_parse, AppName}); + ?RLX_ERROR({vsn_parse, AppName}); ParsedVsn -> {ok, AppInfo#app_info_t{vsn=ParsedVsn}} end. @@ -175,13 +175,13 @@ format(AppInfo) -> format(Indent, #app_info_t{name=Name, vsn=Vsn, dir=Dir, active_deps=Deps, library_deps=LibDeps, link=Link}) -> - [rcl_util:indent(Indent), erlang:atom_to_list(Name), "-", ec_semver:format(Vsn), + [rlx_util:indent(Indent), erlang:atom_to_list(Name), "-", ec_semver:format(Vsn), ": ", Dir, "\n", - rcl_util:indent(Indent + 1), "Symlink: ", erlang:atom_to_list(Link), "\n", - rcl_util:indent(Indent + 1), "Active Dependencies:\n", - [[rcl_util:indent(Indent + 2), erlang:atom_to_list(Dep), ",\n"] || Dep <- Deps], - rcl_util:indent(Indent + 1), "Library Dependencies:\n", - [[rcl_util:indent(Indent + 2), erlang:atom_to_list(LibDep), ",\n"] || LibDep <- LibDeps]]. + rlx_util:indent(Indent + 1), "Symlink: ", erlang:atom_to_list(Link), "\n", + rlx_util:indent(Indent + 1), "Active Dependencies:\n", + [[rlx_util:indent(Indent + 2), erlang:atom_to_list(Dep), ",\n"] || Dep <- Deps], + rlx_util:indent(Indent + 1), "Library Dependencies:\n", + [[rlx_util:indent(Indent + 2), erlang:atom_to_list(LibDep), ",\n"] || LibDep <- LibDeps]]. %%%=================================================================== %%% Internal Functions diff --git a/src/rcl_cmd_args.erl b/src/rlx_cmd_args.erl index bfb63b7..b5fe8a7 100644 --- a/src/rcl_cmd_args.erl +++ b/src/rlx_cmd_args.erl @@ -19,22 +19,20 @@ %%% @copyright (C) 2012 Erlware, LLC. %%% %%% @doc Trivial utility file to help handle common tasks --module(rcl_cmd_args). +-module(rlx_cmd_args). --export([args2state/1, +-export([args2state/2, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API %%============================================================================ --spec args2state({error, Reason::term()} | {[getopt:option()], [string()]}) -> - {ok, {rcl_state:t(), [string()]}} | - relcool:error(). -args2state({error, Detail}) -> - ?RCL_ERROR({opt_parse, Detail}); -args2state({ok, {Opts, Target}}) +-spec args2state([getopt:option()], [string()]) -> + {ok, {rlx_state:t(), [string()]}} | + relx:error(). +args2state(Opts, Target) when erlang:length(Target) == 0; erlang:length(Target) == 1 -> RelName = proplists:get_value(relname, Opts, undefined), RelVsn = proplists:get_value(relvsn, Opts, undefined), @@ -50,16 +48,12 @@ args2state({ok, {Opts, Target}}) Error -> Error end; -args2state({ok, {_Opts, Targets}}) -> - ?RCL_ERROR({invalid_targets, Targets}). +args2state(_Opts, Targets) -> + ?RLX_ERROR({invalid_targets, Targets}). -spec format_error(Reason::term()) -> iolist(). format_error({invalid_targets, Targets}) -> io_lib:format("One config must be specified! not ~p~n", [Targets]); -format_error({opt_parse, {invalid_option, Opt}}) -> - io_lib:format("invalid option ~s~n", [Opt]); -format_error({opt_parse, Arg}) -> - io_lib:format("~p~n", [Arg]); format_error({invalid_option_arg, Arg}) -> case Arg of {goals, Goal} -> @@ -77,8 +71,12 @@ format_error({invalid_option_arg, Arg}) -> end; format_error({invalid_config_file, Config}) -> io_lib:format("Invalid configuration file specified: ~s", [Config]); +format_error({invalid_caller, Caller}) -> + io_lib:format("Invalid caller specified: ~s", [Caller]); format_error({failed_to_parse, Spec}) -> io_lib:format("Unable to parse spec ~s", [Spec]); +format_error({failed_to_parse_override, QA}) -> + io_lib:format("Failed to parse app override ~s", [QA]); format_error({not_directory, Dir}) -> io_lib:format("Library directory does not exist: ~s", [Dir]); format_error({invalid_log_level, LogLevel}) -> @@ -87,22 +85,21 @@ format_error({invalid_log_level, LogLevel}) -> format_error({invalid_target, Target}) -> io_lib:format("Invalid action specified: ~s", [Target]). - %%%=================================================================== %%% Internal Functions %%%=================================================================== -spec handle_config([getopt:option()], atom(), proplists:proplist()) -> - {ok, {rcl_state:t(), [string()]}} | - relcool:error(). + {ok, {rlx_state:t(), [string()]}} | + relx:error(). handle_config(Opts, Target, CommandLineConfig) -> case validate_config(proplists:get_value(config, Opts, [])) of Error = {error, _} -> Error; {ok, Config} -> - {ok, rcl_state:new([{config, Config} | CommandLineConfig], Target)} + {ok, rlx_state:new([{config, Config} | CommandLineConfig], Target)} end. --spec convert_target([string()]) -> {ok, release | relup} | relcool:error(). +-spec convert_target([string()]) -> {ok, release | relup} | relx:error(). convert_target([]) -> {ok, release}; convert_target(["release"]) -> @@ -110,10 +107,10 @@ convert_target(["release"]) -> convert_target(["relup"]) -> {ok, relup}; convert_target(Target) -> - ?RCL_ERROR({invalid_target, Target}). + ?RLX_ERROR({invalid_target, Target}). -spec validate_config(file:filename() | undefined) -> - {ok, file:filename() | undefined} | relcool:error(). + {ok, file:filename() | undefined} | relx:error(). validate_config(undefined) -> {ok, undefined}; validate_config("") -> @@ -123,53 +120,101 @@ validate_config(Config) -> true -> {ok, filename:absname(Config)}; false -> - ?RCL_ERROR({invalid_config_file, Config}) + ?RLX_ERROR({invalid_config_file, Config}) end. --spec create_log([getopt:option()], rcl_state:cmd_args()) -> - {ok, rcl_state:cmd_args()} | relcool:error(). +-spec create_log([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). create_log(Opts, Acc) -> LogLevel = proplists:get_value(log_level, Opts, 0), if LogLevel >= 0, LogLevel =< 2 -> - create_goals(Opts, [{log, rcl_log:new(LogLevel)} | Acc]); + create_goals(Opts, [{log, rlx_log:new(LogLevel)} | Acc]); true -> - ?RCL_ERROR({invalid_log_level, LogLevel}) + ?RLX_ERROR({invalid_log_level, LogLevel}) end. --spec create_goals([getopt:option()], rcl_state:cmd_args()) -> - {ok, rcl_state:cmd_args()} | relcool:error(). +-spec create_goals([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). create_goals(Opts, Acc) -> - case convert_goals(proplists:get_all_values(goals, Opts), []) of + Goals = proplists:get_value(goals, Opts, []) ++ + proplists:get_all_values(goal, Opts), + case convert_goals(Goals, []) of Error={error, _} -> Error; {ok, Specs} -> - create_output_dir(Opts, [{goals, Specs} | Acc]) + create_overrides(Opts, [{goals, Specs} | Acc]) end. --spec convert_goals([string()], [rcl_depsolver:constraint()]) -> - {ok,[rcl_depsolver:constraint()]} | - relcool:error(). +-spec create_overrides([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). +create_overrides(Opts, Acc) -> + Overrides = proplists:get_all_values(override, Opts) ++ + proplists:get_value(overrides, Opts, []), + case convert_overrides(Overrides, []) of + {ok, Overrides} -> + create_output_dir(Opts, [{overrides, Overrides} | Acc]); + Error -> + Error + end. + +-spec convert_overrides([{atom(), string() | binary()} | + string() | binary()], [{atom(), string() | binary()}]) -> + {ok, [string() | binary()]} | relx:error(). +convert_overrides([], Acc) -> + {ok, Acc}; +convert_overrides([QA = {OverrideApp, _} | Rest], Acc) + when erlang:is_atom(OverrideApp) -> + convert_overrides(Rest, [QA | Acc]); +convert_overrides([Override | Rest], Acc) + when erlang:is_list(Override); erlang:is_binary(Override) -> + case re:split(Override, ":") of + [AppName, AppDir] -> + convert_overrides(Rest, [{erlang:iolist_to_binary(AppName), AppDir} | Acc]); + _ -> + ?RLX_ERROR({failed_to_parse_override, Override}) + end; +convert_overrides([QA | _], _) -> + ?RLX_ERROR({failed_to_parse_override, QA}). + +-spec convert_goals([string()], [rlx_depsolver:constraint()]) -> + {ok,[rlx_depsolver:constraint()]} | + relx:error(). convert_goals([], Specs) -> - %% Reverse the specs because order matters to rcl_depsolver + %% Reverse the specs because order matters to rlx_depsolver {ok, lists:reverse(Specs)}; convert_goals([RawSpec | Rest], Acc) -> - case rcl_goal:parse(RawSpec) of + parse_goal(RawSpec, Rest, Acc). + +-spec parse_goal(string() | binary() | rlx_depsolver:constraint(), + [string() | binary() | rlx_depsolver:constraint()], + rlx_depsolver:constraints()) -> + {ok, rlx_depsolver:constraints()} | relx:error(). +parse_goal(Spec, Rest, Acc) + when erlang:is_atom(Spec) -> + convert_goals(Rest, [Spec | Acc]); +parse_goal(Spec, Rest, Acc) + when erlang:is_tuple(Spec) -> + convert_goals(Rest, [Spec | Acc]); +parse_goal(RawSpec, Rest, Acc) -> + case rlx_goal:parse(RawSpec) of {ok, Spec} -> convert_goals(Rest, [Spec | Acc]); {fail, _} -> - ?RCL_ERROR({failed_to_parse, RawSpec}) + ?RLX_ERROR({failed_to_parse, RawSpec}) end. --spec create_output_dir([getopt:option()], rcl_state:cmd_args()) -> - {ok, rcl_state:cmd_args()} | relcool:error(). + +-spec create_output_dir([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). create_output_dir(Opts, Acc) -> OutputDir = proplists:get_value(output_dir, Opts, "./_rel"), create_lib_dirs(Opts, [{output_dir, filename:absname(OutputDir)} | Acc]). --spec create_lib_dirs([getopt:option()], rcl_state:cmd_args()) -> - {ok, rcl_state:cmd_args()} | relcool:error(). +-spec create_lib_dirs([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). create_lib_dirs(Opts, Acc) -> - Dirs = proplists:get_all_values(lib_dir, Opts), + Dirs = proplists:get_all_values(lib_dir, Opts) ++ + proplists:get_value(lib_dirs, Opts, []), case check_lib_dirs(Dirs) of Error = {error, _} -> Error; @@ -177,8 +222,8 @@ create_lib_dirs(Opts, Acc) -> create_root_dir(Opts, [{lib_dirs, [filename:absname(Dir) || Dir <- Dirs]} | Acc]) end. --spec create_root_dir([getopt:option()], rcl_state:cmd_args()) -> - {ok, rcl_state:cmd_args()} | relcool:error(). +-spec create_root_dir([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). create_root_dir(Opts, Acc) -> Dir = proplists:get_value(root_dir, Opts, undefined), case Dir of @@ -189,19 +234,48 @@ create_root_dir(Opts, Acc) -> create_disable_default_libs(Opts, [{root_dir, Dir} | Acc]) end. --spec create_disable_default_libs([getopt:option()], rcl_state:cmd_args()) -> - {ok, rcl_state:cmd_args()} | relcool:error(). +-spec create_disable_default_libs([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). create_disable_default_libs(Opts, Acc) -> Def = proplists:get_value(disable_default_libs, Opts, false), - {ok, [{disable_default_libs, Def} | Acc]}. + create_upfrom(Opts, [{disable_default_libs, Def} | Acc]). --spec check_lib_dirs([string()]) -> ok | relcool:error(). +-spec create_upfrom([getopt:option()], rcl:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). +create_upfrom(Opts, Acc) -> + case proplists:get_value(upfrom, Opts, undefined) of + undefined -> + create_caller(Opts, Acc); + UpFrom -> + create_caller(Opts, [{upfrom, UpFrom} | Acc]) + end. + +-spec create_caller([getopt:option()], rlx_state:cmd_args()) -> + {ok, rlx_state:cmd_args()} | relx:error(). +create_caller(Opts, Acc) -> + case proplists:get_value(caller, Opts, api) of + "command_line" -> + {ok, [{caller, command_line} | Acc]}; + "commandline" -> + {ok, [{caller, command_line} | Acc]}; + "api" -> + {ok, [{caller, api} | Acc]}; + api -> + {ok, [{caller, api} | Acc]}; + commandline -> + {ok, [{caller, command_line} | Acc]}; + command_line -> + {ok, [{caller, command_line} | Acc]}; + Caller -> + ?RLX_ERROR({invalid_caller, Caller}) + end. +-spec check_lib_dirs([string()]) -> ok | relx:error(). check_lib_dirs([]) -> ok; check_lib_dirs([Dir | Rest]) -> case filelib:is_dir(Dir) of false -> - ?RCL_ERROR({not_directory, Dir}); + ?RLX_ERROR({not_directory, Dir}); true -> check_lib_dirs(Rest) end. diff --git a/src/rcl_depsolver.erl b/src/rlx_depsolver.erl index 0cf8c88..2b6e420 100644 --- a/src/rcl_depsolver.erl +++ b/src/rlx_depsolver.erl @@ -41,8 +41,8 @@ %%% %%% we can add this world to the system all at once as follows %%% -%%% Graph0 = rcl_depsolver:new_graph(), -%%% Graph1 = rcl_depsolver:add_packages( +%%% Graph0 = rlx_depsolver:new_graph(), +%%% Graph1 = rlx_depsolver:add_packages( %%% [{app1, [{"0.1", [{app2, "0.2"}, %%% {app3, "0.2", '>='}]}, %%% {"0.2", []}, @@ -57,23 +57,23 @@ %%% We can also build it up incrementally using the other add_package and %%% add_package_version functions. %%% -%%% Finally, once we have built up the graph we can ask rcl_depsolver to solve the +%%% Finally, once we have built up the graph we can ask rlx_depsolver to solve the %%% dependency constraints. That is to give us a list of valid dependencies by %%% using the solve function. Lets say we want the app3 version "0.3" and all of %%% its resolved dependencies. We could call solve as follows. %%% -%%% rcl_depsolver:solve(Graph1, [{app3, "0.3"}]). +%%% rlx_depsolver:solve(Graph1, [{app3, "0.3"}]). %%% %%% That will give us the completely resolved dependencies including app3 %%% itself. Lets be a little more flexible. Lets ask for a graph that is rooted %%% in anything greater then or equal to app3 "0.3". We could do that by %%% -%%% rcl_depsolver:solve(Graph1, [{app3, "0.3", '>='}]). +%%% rlx_depsolver:solve(Graph1, [{app3, "0.3", '>='}]). %%% %%% Of course, you can specify any number of goals at the top level. %%% @end %%%------------------------------------------------------------------- --module(rcl_depsolver). +-module(rlx_depsolver). %% Public Api -export([format_error/1, @@ -91,7 +91,7 @@ is_valid_constraint/1, filter_packages/2]). -%% Internally Exported API. This should *not* be used outside of the rcl_depsolver +%% Internally Exported API. This should *not* be used outside of the rlx_depsolver %% application. You have been warned. -export([dep_pkg/1, filter_package/2, @@ -156,7 +156,7 @@ new_graph() -> %% @doc add a complete set of list of packages to the graph. Where the package %% consists of the name and a list of versions and dependencies. %% -%% ``` rcl_depsolver:add_packages(Graph, +%% ``` rlx_depsolver:add_packages(Graph, %% [{app1, [{"0.1", [{app2, "0.2"}, %% {app3, "0.2", '>='}]}, %% {"0.2", []}, @@ -177,7 +177,7 @@ add_packages(Dom0, Info) %% @doc add a single package to the graph, where it consists of a package name %% and its versions and thier dependencies. -%% ```rcl_depsolver:add_package(Graph, app1, [{"0.1", [{app2, "0.2"}, +%% ```rlx_depsolver:add_package(Graph, app1, [{"0.1", [{app2, "0.2"}, %% {app3, "0.2", '>='}]}, %% {"0.2", []}, %% {"0.3", []}]}]). @@ -193,7 +193,7 @@ add_package(State, Pkg, Versions) %% @doc add a set of dependencies to a specific package and version. %% and its versions and thier dependencies. -%% ```rcl_depsolver:add_package(Graph, app1, "0.1", [{app2, "0.2"}, +%% ```rlx_depsolver:add_package(Graph, app1, "0.1", [{app2, "0.2"}, %% {app3, "0.2", '>='}]}, %% {"0.2", []}, %% {"0.3", []}]). @@ -225,7 +225,7 @@ add_package_version({?MODULE, Dom0}, RawPkg, RawVsn, RawPkgConstraints) -> %% @doc add a package and version to the dependency graph with no dependency %% constraints, dependency constraints can always be added after the fact. %% -%% ```rcl_depsolver:add_package_version(Graph, app1, "0.1").''' +%% ```rlx_depsolver:add_package_version(Graph, app1, "0.1").''' -spec add_package_version(t(),pkg_name(),raw_vsn()) -> t(). add_package_version(State, Pkg, Vsn) -> add_package_version(State, Pkg, Vsn, []). @@ -233,7 +233,7 @@ add_package_version(State, Pkg, Vsn) -> %% @doc Given a set of goals (in the form of constrains) find a set of packages %% and versions that satisfy all constraints. If no solution can be found then %% an exception is thrown. -%% ``` rcl_depsolver:solve(State, [{app1, "0.1", '>='}]).''' +%% ``` rlx_depsolver:solve(State, [{app1, "0.1", '>='}]).''' -spec solve(t(),[constraint()]) -> {ok, [pkg()]} | {error, term()}. solve({?MODULE, DepGraph0}, RawGoals) when erlang:length(RawGoals) > 0 -> @@ -245,7 +245,7 @@ solve({?MODULE, DepGraph0}, RawGoals) case primitive_solve(DepGraph1, Goals, no_path) of {fail, _} -> [FirstCons | Rest] = Goals, - {error, rcl_depsolver_culprit:search(DepGraph1, [FirstCons], Rest)}; + {error, rlx_depsolver_culprit:search(DepGraph1, [FirstCons], Rest)}; Solution -> {ok, Solution} end @@ -317,7 +317,7 @@ filter_packages(PVPairs, RawConstraints) -> {invalid_constraints, [constraint()]} | list()}) -> iolist(). format_error(Error) -> - rcl_depsolver_culprit:format_error(Error). + rlx_depsolver_culprit:format_error(Error). %% @doc Return a formatted list of roots of the dependency trees which %% could not be satisified. These may also have versions attached. @@ -327,7 +327,7 @@ format_error(Error) -> %% -spec format_roots([constraints()]) -> iolist(). format_roots(Roots) -> - rcl_depsolver_culprit:format_roots(Roots). + rlx_depsolver_culprit:format_roots(Roots). %% @doc Return a formatted list of the culprit depenedencies which led to @@ -336,17 +336,17 @@ format_roots(Roots) -> %% ```(foo = 1.2.0) -> (bar > 2.0.0)``` -spec format_culprits([{[constraint()], [constraint()]}]) -> iolist(). format_culprits(Culprits) -> - rcl_depsolver_culprit:format_culprits(Culprits). + rlx_depsolver_culprit:format_culprits(Culprits). %% @doc A formatted version tuple -spec format_version(vsn()) -> iolist(). format_version(Version) -> - rcl_depsolver_culprit:format_version(Version). + rlx_depsolver_culprit:format_version(Version). %% @doc A formatted constraint tuple -spec format_constraint(constraint()) -> iolist(). format_constraint(Constraint) -> - rcl_depsolver_culprit:format_constraint(Constraint). + rlx_depsolver_culprit:format_constraint(Constraint). %%==================================================================== %% Internal Functions diff --git a/src/rcl_depsolver_culprit.erl b/src/rlx_depsolver_culprit.erl index f2115c7..cf6dcb2 100644 --- a/src/rcl_depsolver_culprit.erl +++ b/src/rlx_depsolver_culprit.erl @@ -28,7 +28,7 @@ %%% goal, and the good apps (those not immediately constrained from %%% the goals). %%% @end --module(rcl_depsolver_culprit). +-module(rlx_depsolver_culprit). -export([search/3, format_error/1, @@ -46,10 +46,10 @@ %%============================================================================ %% @doc start running the solver, with each run reduce the number of constraints %% set as goals. At some point the solver should succeed. --spec search(rcl_depsolver:dep_graph(), [rcl_depsolver:constraint()], [rcl_depsolver:constraint()]) +-spec search(rlx_depsolver:dep_graph(), [rlx_depsolver:constraint()], [rlx_depsolver:constraint()]) -> term(). search(State, ActiveCons, []) -> - case rcl_depsolver:primitive_solve(State, ActiveCons, keep_paths) of + case rlx_depsolver:primitive_solve(State, ActiveCons, keep_paths) of {fail, FailPaths} -> extract_culprit_information0(ActiveCons, lists:flatten(FailPaths)); _Success -> @@ -59,7 +59,7 @@ search(State, ActiveCons, []) -> inconsistant_graph_state end; search(State, ActiveCons, [NewCon | Constraints]) -> - case rcl_depsolver:primitive_solve(State, ActiveCons, keep_paths) of + case rlx_depsolver:primitive_solve(State, ActiveCons, keep_paths) of {fail, FailPaths} -> extract_culprit_information0(ActiveCons, lists:flatten(FailPaths)); _Success -> @@ -84,7 +84,7 @@ format_error(Details) when erlang:is_list(Details) -> ["Unable to solve constraints, the following solutions were attempted \n\n", [[format_error_path(" ", Detail)] || Detail <- Details]]. --spec format_roots([rcl_depsolver:constraints()]) -> iolist(). +-spec format_roots([rlx_depsolver:constraints()]) -> iolist(). format_roots(Roots) -> lists:foldl(fun(Root, Acc0) -> lists:foldl( @@ -95,9 +95,9 @@ format_roots(Roots) -> end, Acc0, Root) end, [], Roots). --spec format_culprits([{[rcl_depsolver:constraint()], [rcl_depsolver:constraint()]}]) -> iolist(). +-spec format_culprits([{[rlx_depsolver:constraint()], [rlx_depsolver:constraint()]}]) -> iolist(). format_culprits(FailingDeps) -> - Deps = sets:to_list(sets:from_list(lists:flatten([[rcl_depsolver:dep_pkg(Con) || Con <- Cons] + Deps = sets:to_list(sets:from_list(lists:flatten([[rlx_depsolver:dep_pkg(Con) || Con <- Cons] || {_, Cons} <- FailingDeps]))), lists:foldl(fun(Con, "") -> [format_constraint(Con)]; @@ -106,11 +106,11 @@ format_culprits(FailingDeps) -> ", " | Acc1] end, [], Deps). --spec format_version(rcl_depsolver:vsn()) -> iolist(). +-spec format_version(rlx_depsolver:vsn()) -> iolist(). format_version(Vsn) -> ec_semver:format(Vsn). --spec format_constraint(rcl_depsolver:constraint()) -> list(). +-spec format_constraint(rlx_depsolver:constraint()) -> list(). format_constraint(Pkg) when is_atom(Pkg) -> erlang:atom_to_list(Pkg); format_constraint(Pkg) when is_binary(Pkg) -> @@ -170,8 +170,8 @@ append_value(Key, Value, PropList) -> proplists:delete(Key, PropList)] end. --spec strip_goal([[rcl_depsolver:pkg()] | rcl_depsolver:pkg()]) -> - [[rcl_depsolver:pkg()] | rcl_depsolver:pkg()]. +-spec strip_goal([[rlx_depsolver:pkg()] | rlx_depsolver:pkg()]) -> + [[rlx_depsolver:pkg()] | rlx_depsolver:pkg()]. strip_goal([{'_GOAL_', 'NO_VSN'}, Children]) -> Children; strip_goal(All = [Val | _]) @@ -180,25 +180,25 @@ strip_goal(All = [Val | _]) strip_goal(Else) -> Else. --spec extract_culprit_information0(rcl_depsolver:constraints(), - [rcl_depsolver:fail_info()]) -> +-spec extract_culprit_information0(rlx_depsolver:constraints(), + [rlx_depsolver:fail_info()]) -> [term()]. extract_culprit_information0(ActiveCons, FailInfo) when is_list(FailInfo) -> [extract_culprit_information1(ActiveCons, FI) || FI <- FailInfo]. --spec extract_root(rcl_depsolver:constraints(), [rcl_depsolver:pkg()]) -> - {[rcl_depsolver:constraint()], [rcl_depsolver:pkg()]}. +-spec extract_root(rlx_depsolver:constraints(), [rlx_depsolver:pkg()]) -> + {[rlx_depsolver:constraint()], [rlx_depsolver:pkg()]}. extract_root(ActiveCons, TPath = [PRoot | _]) -> - RootName = rcl_depsolver:dep_pkg(PRoot), + RootName = rlx_depsolver:dep_pkg(PRoot), Roots = lists:filter(fun(El) -> - RootName =:= rcl_depsolver:dep_pkg(El) + RootName =:= rlx_depsolver:dep_pkg(El) end, ActiveCons), {Roots, TPath}. --spec extract_culprit_information1(rcl_depsolver:constraints(), - rcl_depsolver:fail_info()) -> +-spec extract_culprit_information1(rlx_depsolver:constraints(), + rlx_depsolver:fail_info()) -> term(). extract_culprit_information1(_ActiveCons, {[], RawConstraints}) -> %% In this case where there was no realized versions, the GOAL @@ -226,9 +226,9 @@ extract_culprit_information1(ActiveCons, {Path, RawConstraints}) -> RunListItems = [extract_root(ActiveCons, TPath) || TPath <- TreedPath], {RunListItems, FailCons}. --spec follow_chain(rcl_depsolver:pkg_name(), rcl_depsolver:vsn(), - {rcl_depsolver:constraint(), rcl_depsolver:pkg()}) -> - false | {ok, rcl_depsolver:constraint()}. +-spec follow_chain(rlx_depsolver:pkg_name(), rlx_depsolver:vsn(), + {rlx_depsolver:constraint(), rlx_depsolver:pkg()}) -> + false | {ok, rlx_depsolver:constraint()}. follow_chain(Pkg, Vsn, {{Pkg, Vsn}, {Pkg, Vsn}}) -> %% When the package version is the same as the source we dont want to try to follow it at all false; @@ -237,9 +237,9 @@ follow_chain(Pkg, Vsn, {Con, {Pkg, Vsn}}) -> follow_chain(_Pkg, _Vsn, _) -> false. --spec find_chain(rcl_depsolver:pkg_name(), rcl_depsolver:vsn(), - [{rcl_depsolver:constraint(), rcl_depsolver:pkg()}]) -> - rcl_depsolver:constraints(). +-spec find_chain(rlx_depsolver:pkg_name(), rlx_depsolver:vsn(), + [{rlx_depsolver:constraint(), rlx_depsolver:pkg()}]) -> + rlx_depsolver:constraints(). find_chain(Pkg, Vsn, Constraints) -> lists:foldl(fun(NCon, Acc) -> case follow_chain(Pkg, Vsn, NCon) of @@ -250,46 +250,46 @@ find_chain(Pkg, Vsn, Constraints) -> end end, [], Constraints). --spec get_constraints(rcl_depsolver:pkg_name(), rcl_depsolver:vsn(), [rcl_depsolver:pkg()], - [{rcl_depsolver:constraint(), rcl_depsolver:pkg()}]) -> - rcl_depsolver:constraints(). +-spec get_constraints(rlx_depsolver:pkg_name(), rlx_depsolver:vsn(), [rlx_depsolver:pkg()], + [{rlx_depsolver:constraint(), rlx_depsolver:pkg()}]) -> + rlx_depsolver:constraints(). get_constraints(FailedPkg, FailedVsn, Path, Constraints) -> Chain = find_chain(FailedPkg, FailedVsn, Constraints), lists:filter(fun(Con) -> - PkgName = rcl_depsolver:dep_pkg(Con), + PkgName = rlx_depsolver:dep_pkg(Con), (lists:any(fun(PathEl) -> - not rcl_depsolver:filter_package(PathEl, Con) + not rlx_depsolver:filter_package(PathEl, Con) end, Path) orelse not lists:keymember(PkgName, 1, Path)) end, Chain). --spec pkg_vsn(rcl_depsolver:constraint(), [{rcl_depsolver:constraint(), - rcl_depsolver:pkg()}]) -> - [rcl_depsolver:pkg()]. +-spec pkg_vsn(rlx_depsolver:constraint(), [{rlx_depsolver:constraint(), + rlx_depsolver:pkg()}]) -> + [rlx_depsolver:pkg()]. pkg_vsn(PkgCon, Constraints) -> - PkgName = rcl_depsolver:dep_pkg(PkgCon), + PkgName = rlx_depsolver:dep_pkg(PkgCon), [DepPkg || Con = {DepPkg, _} <- Constraints, case Con of {Pkg = {PkgName, PkgVsn}, {PkgName, PkgVsn}} -> - rcl_depsolver:filter_package(Pkg, PkgCon); + rlx_depsolver:filter_package(Pkg, PkgCon); _ -> false end]. --spec depends(rcl_depsolver:pkg(), [{rcl_depsolver:constraint(), - rcl_depsolver:pkg()}], - [rcl_depsolver:pkg()]) -> - [rcl_depsolver:pkg()]. +-spec depends(rlx_depsolver:pkg(), [{rlx_depsolver:constraint(), + rlx_depsolver:pkg()}], + [rlx_depsolver:pkg()]) -> + [rlx_depsolver:pkg()]. depends(SrcPkg, Constraints, Seen) -> lists:flatten([pkg_vsn(Pkg, Constraints) || {Pkg, Source} <- Constraints, Source =:= SrcPkg andalso Pkg =/= SrcPkg andalso not lists:member(Pkg, Seen)]). --spec treeize_path(rcl_depsolver:pkg(), [{rcl_depsolver:constraint(), - rcl_depsolver:pkg()}], - [rcl_depsolver:pkg()]) -> - [rcl_depsolver:pkg() | [rcl_depsolver:pkg()]]. +-spec treeize_path(rlx_depsolver:pkg(), [{rlx_depsolver:constraint(), + rlx_depsolver:pkg()}], + [rlx_depsolver:pkg()]) -> + [rlx_depsolver:pkg() | [rlx_depsolver:pkg()]]. treeize_path(Pkg, Constraints, Seen0) -> Seen1 = [Pkg | Seen0], case depends(Pkg, Constraints, Seen1) of @@ -310,7 +310,7 @@ add_s(Roots) -> "" end. --spec format_path(string(), [rcl_depsolver:pkg()]) -> iolist(). +-spec format_path(string(), [rlx_depsolver:pkg()]) -> iolist(). format_path(CurrentIdent, Path) -> [CurrentIdent, " ", lists:foldl(fun(Con, "") -> @@ -320,8 +320,8 @@ format_path(CurrentIdent, Path) -> end, "", Path), "\n"]. --spec format_dependency_paths(string(), [[rcl_depsolver:pkg()] | rcl_depsolver:pkg()], - [{rcl_depsolver:pkg(), [rcl_depsolver:constraint()]}], [rcl_depsolver:pkg()]) -> iolist(). +-spec format_dependency_paths(string(), [[rlx_depsolver:pkg()] | rlx_depsolver:pkg()], + [{rlx_depsolver:pkg(), [rlx_depsolver:constraint()]}], [rlx_depsolver:pkg()]) -> iolist(). format_dependency_paths(CurrentIndent, [SubPath | Rest], FailingDeps, Acc) when erlang:is_list(SubPath) -> [format_dependency_paths(CurrentIndent, lists:sort(SubPath), FailingDeps, Acc), @@ -348,8 +348,8 @@ format_dependency_paths(CurrentIndent, [Con | Rest], FailingDeps, Acc) -> format_dependency_paths(_CurrentIndent, [], _FailingDeps, _Acc) -> []. --spec format_error_path(string(), {[{[rcl_depsolver:constraint()], [rcl_depsolver:pkg()]}], - [rcl_depsolver:constraint()]}) -> iolist(). +-spec format_error_path(string(), {[{[rlx_depsolver:constraint()], [rlx_depsolver:pkg()]}], + [rlx_depsolver:constraint()]}) -> iolist(). format_error_path(CurrentIndent, {RawPaths, FailingDeps}) -> Roots = [RootSet || {RootSet, _} <- RawPaths], Paths = [Path || {_, Path} <- RawPaths], diff --git a/src/rcl_dscv_util.erl b/src/rlx_dscv_util.erl index 68dcb68..3d90b08 100644 --- a/src/rcl_dscv_util.erl +++ b/src/rlx_dscv_util.erl @@ -21,13 +21,13 @@ %%% @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 rcl_provider behaviour. --module(rcl_dscv_util). +%%% the state of available apps. This implements the rlx_provider behaviour. +-module(rlx_dscv_util). -export([do/2, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% Types diff --git a/src/rlx_goal.erl b/src/rlx_goal.erl new file mode 100644 index 0000000..7226525 --- /dev/null +++ b/src/rlx_goal.erl @@ -0,0 +1,263 @@ +-module(rlx_goal). +-export([parse/1,file/1]). +-compile({nowarn_unused_function,[p/4, p/5, p_eof/0, p_optional/1, p_not/1, p_assert/1, p_seq/1, p_and/1, p_choose/1, p_zero_or_more/1, p_one_or_more/1, p_label/2, p_string/1, p_anything/0, p_charclass/1, p_regexp/1, p_attempt/4, line/1, column/1]}). + + +-compile(export_all). +-spec file(file:name()) -> any(). +file(Filename) -> {ok, Bin} = file:read_file(Filename), parse(Bin). + +-spec parse(binary() | list()) -> any(). +parse(List) when is_list(List) -> parse(list_to_binary(List)); +parse(Input) when is_binary(Input) -> + setup_memo(), + Result = case 'constraint'(Input,{{line,1},{column,1}}) of + {AST, <<>>, _Index} -> AST; + Any -> Any + end, + release_memo(), Result. + +'constraint'(Input, Index) -> + p(Input, Index, 'constraint', fun(I,D) -> (p_choose([p_seq([p_optional(fun 'ws'/2), fun 'app_name'/2, p_optional(fun 'ws'/2), fun 'between_op'/2, p_optional(fun 'ws'/2), fun 'version'/2, p_optional(fun 'ws'/2), p_string(<<",">>), p_optional(fun 'ws'/2), fun 'version'/2, p_optional(fun 'ws'/2), p_not(p_anything())]), p_seq([p_optional(fun 'ws'/2), fun 'app_name'/2, p_optional(fun 'ws'/2), fun 'constraint_op'/2, p_optional(fun 'ws'/2), fun 'version'/2, p_optional(fun 'ws'/2), p_not(p_anything())]), p_seq([p_optional(fun 'ws'/2), fun 'app_name'/2, p_optional(fun 'ws'/2), p_not(p_anything())])]))(I,D) end, fun(Node, _Idx) -> + case Node of + [_,AppName,_, _] -> + {ok, AppName}; + [_,AppName,_,Op,_,Vsn,_, _] -> + {ok, + {AppName, + rlx_goal_utils:to_vsn(Vsn), + rlx_goal_utils:to_op(Op)}}; + [_,AppName,_,Op,_,Vsn1,_,_,_,Vsn2,_,_] -> + {ok, + {AppName, + rlx_goal_utils:to_vsn(Vsn1), + rlx_goal_utils:to_vsn(Vsn2), + rlx_goal_utils:to_op(Op)}}; + _ -> + io:format("~p~n", [Node]) + end + end). + +'ws'(Input, Index) -> + p(Input, Index, 'ws', fun(I,D) -> (p_charclass(<<"[\s\t\n\s\r]">>))(I,D) end, fun(Node, Idx) -> transform('ws', Node, Idx) end). + +'app_name'(Input, Index) -> + p(Input, Index, 'app_name', fun(I,D) -> (p_one_or_more(p_charclass(<<"[a-zA-Z0-9_]">>)))(I,D) end, fun(Node, _Idx) -> erlang:list_to_atom(erlang:binary_to_list(erlang:iolist_to_binary(Node))) end). + +'between_op'(Input, Index) -> + p(Input, Index, 'between_op', fun(I,D) -> (p_seq([p_string(<<":">>), p_optional(fun 'ws'/2), p_choose([p_string(<<"btwn">>), p_string(<<"between">>)]), p_optional(fun 'ws'/2), p_string(<<":">>)]))(I,D) end, fun(Node, _Idx) -> case Node of + [C,_,Op,_,C] -> erlang:iolist_to_binary([C,Op,C]); + _ -> Node + end + end). + +'constraint_op'(Input, Index) -> + p(Input, Index, 'constraint_op', fun(I,D) -> (p_choose([p_string(<<"=">>), p_string(<<"-">>), p_string(<<"<=">>), p_string(<<"<">>), p_string(<<"~>">>), p_string(<<">=">>), p_string(<<">">>), fun 'word_constraint_op'/2, p_string(<<":">>)]))(I,D) end, fun(Node, Idx) -> transform('constraint_op', Node, Idx) end). + +'word_constraint_op'(Input, Index) -> + p(Input, Index, 'word_constraint_op', fun(I,D) -> (p_seq([p_string(<<":">>), p_optional(fun 'ws'/2), p_choose([p_string(<<"gte">>), p_string(<<"lte">>), p_string(<<"gt">>), p_string(<<"lt">>), p_string(<<"pes">>)]), p_optional(fun 'ws'/2), p_string(<<":">>)]))(I,D) end, fun(Node, _Idx) -> case Node of + [C,_,Op,_,C] -> erlang:iolist_to_binary([C,Op,C]); + _ -> Node + end + end). + +'version'(Input, Index) -> + p(Input, Index, 'version', fun(I,D) -> (p_one_or_more(p_charclass(<<"[0-9a-zA-Z-+.]">>)))(I,D) end, fun(Node, Idx) -> transform('version', Node, Idx) end). + + +transform(_,Node,_Index) -> Node. + +p(Inp, Index, Name, ParseFun) -> + p(Inp, Index, Name, ParseFun, fun(N, _Idx) -> N end). + +p(Inp, StartIndex, Name, ParseFun, TransformFun) -> + case get_memo(StartIndex, Name) of % See if the current reduction is memoized + {ok, Memo} -> %Memo; % If it is, return the stored result + Memo; + _ -> % If not, attempt to parse + Result = case ParseFun(Inp, StartIndex) of + {fail,_} = Failure -> % If it fails, memoize the failure + Failure; + {Match, InpRem, NewIndex} -> % If it passes, transform and memoize the result. + Transformed = TransformFun(Match, StartIndex), + {Transformed, InpRem, NewIndex} + end, + memoize(StartIndex, Name, Result), + Result + end. + +setup_memo() -> + put({parse_memo_table, ?MODULE}, ets:new(?MODULE, [set])). + +release_memo() -> + ets:delete(memo_table_name()). + +memoize(Index, Name, Result) -> + Memo = case ets:lookup(memo_table_name(), Index) of + [] -> []; + [{Index, Plist}] -> Plist + end, + ets:insert(memo_table_name(), {Index, [{Name, Result}|Memo]}). + +get_memo(Index, Name) -> + case ets:lookup(memo_table_name(), Index) of + [] -> {error, not_found}; + [{Index, Plist}] -> + case proplists:lookup(Name, Plist) of + {Name, Result} -> {ok, Result}; + _ -> {error, not_found} + end + end. + +memo_table_name() -> + get({parse_memo_table, ?MODULE}). + +p_eof() -> + fun(<<>>, Index) -> {eof, [], Index}; + (_, Index) -> {fail, {expected, eof, Index}} end. + +p_optional(P) -> + fun(Input, Index) -> + case P(Input, Index) of + {fail,_} -> {[], Input, Index}; + {_, _, _} = Success -> Success + end + end. + +p_not(P) -> + fun(Input, Index)-> + case P(Input,Index) of + {fail,_} -> + {[], Input, Index}; + {Result, _, _} -> {fail, {expected, {no_match, Result},Index}} + end + end. + +p_assert(P) -> + fun(Input,Index) -> + case P(Input,Index) of + {fail,_} = Failure-> Failure; + _ -> {[], Input, Index} + end + end. + +p_and(P) -> + p_seq(P). + +p_seq(P) -> + fun(Input, Index) -> + p_all(P, Input, Index, []) + end. + +p_all([], Inp, Index, Accum ) -> {lists:reverse( Accum ), Inp, Index}; +p_all([P|Parsers], Inp, Index, Accum) -> + case P(Inp, Index) of + {fail, _} = Failure -> Failure; + {Result, InpRem, NewIndex} -> p_all(Parsers, InpRem, NewIndex, [Result|Accum]) + end. + +p_choose(Parsers) -> + fun(Input, Index) -> + p_attempt(Parsers, Input, Index, none) + end. + +p_attempt([], _Input, _Index, Failure) -> Failure; +p_attempt([P|Parsers], Input, Index, FirstFailure)-> + case P(Input, Index) of + {fail, _} = Failure -> + case FirstFailure of + none -> p_attempt(Parsers, Input, Index, Failure); + _ -> p_attempt(Parsers, Input, Index, FirstFailure) + end; + Result -> Result + end. + +p_zero_or_more(P) -> + fun(Input, Index) -> + p_scan(P, Input, Index, []) + end. + +p_one_or_more(P) -> + fun(Input, Index)-> + Result = p_scan(P, Input, Index, []), + case Result of + {[_|_], _, _} -> + Result; + _ -> + {fail, {expected, Failure, _}} = P(Input,Index), + {fail, {expected, {at_least_one, Failure}, Index}} + end + end. + +p_label(Tag, P) -> + fun(Input, Index) -> + case P(Input, Index) of + {fail,_} = Failure -> + Failure; + {Result, InpRem, NewIndex} -> + {{Tag, Result}, InpRem, NewIndex} + end + end. + +p_scan(_, [], Index, Accum) -> {lists:reverse( Accum ), [], Index}; +p_scan(P, Inp, Index, Accum) -> + case P(Inp, Index) of + {fail,_} -> {lists:reverse(Accum), Inp, Index}; + {Result, InpRem, NewIndex} -> p_scan(P, InpRem, NewIndex, [Result | Accum]) + end. + +p_string(S) when is_list(S) -> p_string(list_to_binary(S)); +p_string(S) -> + Length = erlang:byte_size(S), + fun(Input, Index) -> + try + <<S:Length/binary, Rest/binary>> = Input, + {S, Rest, p_advance_index(S, Index)} + catch + error:{badmatch,_} -> {fail, {expected, {string, S}, Index}} + end + end. + +p_anything() -> + fun(<<>>, Index) -> {fail, {expected, any_character, Index}}; + (Input, Index) when is_binary(Input) -> + <<C/utf8, Rest/binary>> = Input, + {<<C/utf8>>, Rest, p_advance_index(<<C/utf8>>, Index)} + end. + +p_charclass(Class) -> + {ok, RE} = re:compile(Class, [unicode, dotall]), + fun(Inp, Index) -> + case re:run(Inp, RE, [anchored]) of + {match, [{0, Length}|_]} -> + {Head, Tail} = erlang:split_binary(Inp, Length), + {Head, Tail, p_advance_index(Head, Index)}; + _ -> {fail, {expected, {character_class, binary_to_list(Class)}, Index}} + end + end. + +p_regexp(Regexp) -> + {ok, RE} = re:compile(Regexp, [unicode, dotall, anchored]), + fun(Inp, Index) -> + case re:run(Inp, RE) of + {match, [{0, Length}|_]} -> + {Head, Tail} = erlang:split_binary(Inp, Length), + {Head, Tail, p_advance_index(Head, Index)}; + _ -> {fail, {expected, {regexp, binary_to_list(Regexp)}, Index}} + end + end. + +line({{line,L},_}) -> L; +line(_) -> undefined. + +column({_,{column,C}}) -> C; +column(_) -> undefined. + +p_advance_index(MatchedInput, Index) when is_list(MatchedInput) orelse is_binary(MatchedInput)-> % strings + lists:foldl(fun p_advance_index/2, Index, unicode:characters_to_list(MatchedInput)); +p_advance_index(MatchedInput, Index) when is_integer(MatchedInput) -> % single characters + {{line, Line}, {column, Col}} = Index, + case MatchedInput of + $\n -> {{line, Line+1}, {column, 1}}; + _ -> {{line, Line}, {column, Col+1}} + end. diff --git a/src/rcl_goal.peg b/src/rlx_goal.peg index bfac607..08a3726 100644 --- a/src/rcl_goal.peg +++ b/src/rlx_goal.peg @@ -10,14 +10,14 @@ constraint <- ws? app_name ws? between_op ws? version ws? "," ws? version ws? [_,AppName,_,Op,_,Vsn,_, _] -> {ok, {AppName, - rcl_goal_utils:to_vsn(Vsn), - rcl_goal_utils:to_op(Op)}}; + rlx_goal_utils:to_vsn(Vsn), + rlx_goal_utils:to_op(Op)}}; [_,AppName,_,Op,_,Vsn1,_,_,_,Vsn2,_,_] -> {ok, {AppName, - rcl_goal_utils:to_vsn(Vsn1), - rcl_goal_utils:to_vsn(Vsn2), - rcl_goal_utils:to_op(Op)}}; + rlx_goal_utils:to_vsn(Vsn1), + rlx_goal_utils:to_vsn(Vsn2), + rlx_goal_utils:to_op(Op)}}; _ -> io:format("~p~n", [Node]) end diff --git a/src/rcl_goal_utils.erl b/src/rlx_goal_utils.erl index 6065e5c..764fab6 100644 --- a/src/rcl_goal_utils.erl +++ b/src/rlx_goal_utils.erl @@ -20,7 +20,7 @@ %%% %%% @doc %%% Utilities to help with parsing of target specs --module(rcl_goal_utils). +-module(rlx_goal_utils). -export([to_op/1, to_vsn/1]). @@ -32,7 +32,7 @@ %%============================================================================ %% API %%============================================================================ --spec to_op(iolist()) -> rcl_depsolver:constraint_op(). +-spec to_op(iolist()) -> rlx_depsolver:constraint_op(). to_op(List) when erlang:is_list(List) -> to_op(erlang:iolist_to_binary(List)); @@ -70,7 +70,7 @@ to_op(<<":between:">>) -> to_vsn(Version) when erlang:is_list(Version) -> to_vsn(erlang:iolist_to_binary(Version)); to_vsn(Vsn) -> - rcl_depsolver:parse_version(Vsn). + rlx_depsolver:parse_version(Vsn). %%%=================================================================== %%% Test Functions diff --git a/src/rcl_log.erl b/src/rlx_log.erl index 71c0b5d..901ae7c 100644 --- a/src/rcl_log.erl +++ b/src/rlx_log.erl @@ -18,9 +18,9 @@ %%% @author Eric Merritt <[email protected]> %%% @copyright (C) 2012 Erlware, LLC. %%% -%%% @doc This provides simple output functions for relcool. You should use this +%%% @doc This provides simple output functions for relx. You should use this %%% to talk to the users if you are wrting code for the system --module(rcl_log). +-module(rlx_log). -export([new/1, log/4, @@ -41,7 +41,7 @@ log_fun/0, t/0]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% types @@ -83,7 +83,7 @@ new(AtomLogLevel) -spec debug(t(), string() | log_fun()) -> ok. debug(LogState, Fun) when erlang:is_function(Fun) -> - log(LogState, ?RCL_DEBUG, Fun); + log(LogState, ?RLX_DEBUG, Fun); debug(LogState, String) -> debug(LogState, "~s~n", [String]). @@ -91,14 +91,14 @@ debug(LogState, String) -> %% and argements @see io:format/2 -spec debug(t(), string(), [any()]) -> ok. debug(LogState, FormatString, Args) -> - log(LogState, ?RCL_DEBUG, FormatString, Args). + log(LogState, ?RLX_DEBUG, FormatString, Args). %% @doc log at the info level given the current log state with a string or %% function that returns a string -spec info(t(), string() | log_fun()) -> ok. info(LogState, Fun) when erlang:is_function(Fun) -> - log(LogState, ?RCL_INFO, Fun); + log(LogState, ?RLX_INFO, Fun); info(LogState, String) -> info(LogState, "~s~n", [String]). @@ -106,14 +106,14 @@ info(LogState, String) -> %% and argements @see io:format/2 -spec info(t(), string(), [any()]) -> ok. info(LogState, FormatString, Args) -> - log(LogState, ?RCL_INFO, FormatString, Args). + log(LogState, ?RLX_INFO, FormatString, Args). %% @doc log at the error level given the current log state with a string or %% format string that returns a function -spec error(t(), string() | log_fun()) -> ok. error(LogState, Fun) when erlang:is_function(Fun) -> - log(LogState, ?RCL_ERROR, Fun); + log(LogState, ?RLX_ERROR, Fun); error(LogState, String) -> error(LogState, "~s~n", [String]). @@ -121,7 +121,7 @@ error(LogState, String) -> %% and argements @see io:format/2 -spec error(t(), string(), [any()]) -> ok. error(LogState, FormatString, Args) -> - log(LogState, ?RCL_ERROR, FormatString, Args). + log(LogState, ?RLX_ERROR, FormatString, Args). %% @doc Execute the fun passed in if log level is as expected. -spec log(t(), int_log_level(), log_fun()) -> ok. @@ -158,11 +158,11 @@ log_level({?MODULE, DetailLogLevel}) -> %% @doc get the current log level as an atom -spec atom_log_level(t()) -> atom_log_level(). -atom_log_level({?MODULE, ?RCL_ERROR}) -> +atom_log_level({?MODULE, ?RLX_ERROR}) -> error; -atom_log_level({?MODULE, ?RCL_INFO}) -> +atom_log_level({?MODULE, ?RLX_INFO}) -> info; -atom_log_level({?MODULE, ?RCL_DEBUG}) -> +atom_log_level({?MODULE, ?RLX_DEBUG}) -> debug. -spec format(t()) -> iolist(). @@ -181,24 +181,24 @@ format(Log) -> should_test() -> ErrorLogState = new(error), - ?assertMatch(true, should(ErrorLogState, ?RCL_ERROR)), - ?assertMatch(true, not should(ErrorLogState, ?RCL_INFO)), - ?assertMatch(true, not should(ErrorLogState, ?RCL_DEBUG)), - ?assertEqual(?RCL_ERROR, log_level(ErrorLogState)), + ?assertMatch(true, should(ErrorLogState, ?RLX_ERROR)), + ?assertMatch(true, not should(ErrorLogState, ?RLX_INFO)), + ?assertMatch(true, not should(ErrorLogState, ?RLX_DEBUG)), + ?assertEqual(?RLX_ERROR, log_level(ErrorLogState)), ?assertEqual(error, atom_log_level(ErrorLogState)), InfoLogState = new(info), - ?assertMatch(true, should(InfoLogState, ?RCL_ERROR)), - ?assertMatch(true, should(InfoLogState, ?RCL_INFO)), - ?assertMatch(true, not should(InfoLogState, ?RCL_DEBUG)), - ?assertEqual(?RCL_INFO, log_level(InfoLogState)), + ?assertMatch(true, should(InfoLogState, ?RLX_ERROR)), + ?assertMatch(true, should(InfoLogState, ?RLX_INFO)), + ?assertMatch(true, not should(InfoLogState, ?RLX_DEBUG)), + ?assertEqual(?RLX_INFO, log_level(InfoLogState)), ?assertEqual(info, atom_log_level(InfoLogState)), DebugLogState = new(debug), - ?assertMatch(true, should(DebugLogState, ?RCL_ERROR)), - ?assertMatch(true, should(DebugLogState, ?RCL_INFO)), - ?assertMatch(true, should(DebugLogState, ?RCL_DEBUG)), - ?assertEqual(?RCL_DEBUG, log_level(DebugLogState)), + ?assertMatch(true, should(DebugLogState, ?RLX_ERROR)), + ?assertMatch(true, should(DebugLogState, ?RLX_INFO)), + ?assertMatch(true, should(DebugLogState, ?RLX_DEBUG)), + ?assertEqual(?RLX_DEBUG, log_level(DebugLogState)), ?assertEqual(debug, atom_log_level(DebugLogState)). -endif. diff --git a/src/rcl_provider.erl b/src/rlx_provider.erl index 4d8f044..b0de178 100644 --- a/src/rcl_provider.erl +++ b/src/rlx_provider.erl @@ -21,7 +21,7 @@ %%% A module that supports providing state manipulation services to the system. %%% @end %%%------------------------------------------------------------------- --module(rcl_provider). +-module(rlx_provider). %% API -export([new/2, @@ -33,7 +33,7 @@ -export_type([t/0]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%%=================================================================== %%% Types @@ -44,8 +44,8 @@ -ifdef(have_callback_support). --callback init(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). --callback do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). +-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. @@ -72,13 +72,13 @@ behaviour_info(_) -> %% %% @param ModuleName The module name. %% @param State0 The current state of the system --spec new(module(), rcl_state:t()) -> - {t(), {ok, rcl_state:t()}} | relcool:error(). +-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 -> - ?RCL_ERROR({non_existing, ModuleName}); + ?RLX_ERROR({non_existing, ModuleName}); _ -> {{?MODULE, ModuleName}, State1} end. @@ -87,8 +87,8 @@ new(ModuleName, State0) when is_atom(ModuleName) -> %% %% @param Provider the provider object %% @param State the current state of the system --spec do(Provider::t(), rcl_state:t()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec do(Provider::t(), rlx_state:t()) -> + {ok, rlx_state:t()} | relx:error(). do({?MODULE, Mod}, State) -> Mod:do(State). diff --git a/src/rcl_prv_assembler.erl b/src/rlx_prv_assembler.erl index f40bdc5..18a372c 100644 --- a/src/rcl_prv_assembler.erl +++ b/src/rlx_prv_assembler.erl @@ -20,37 +20,37 @@ %%% %%% @doc Given a complete built release this provider assembles that release %%% into a release directory. --module(rcl_prv_assembler). +-module(rlx_prv_assembler). --behaviour(rcl_provider). +-behaviour(rlx_provider). -export([init/1, do/1, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API %%============================================================================ --spec init(rcl_state:t()) -> {ok, rcl_state:t()}. +-spec init(rlx_state:t()) -> {ok, rlx_state:t()}. init(State) -> {ok, State}. %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications --spec do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). +-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). do(State) -> - {RelName, RelVsn} = rcl_state:default_release(State), - Release = rcl_state:get_release(State, RelName, RelVsn), - OutputDir = rcl_state:output_dir(State), + {RelName, RelVsn} = rlx_state:default_configured_release(State), + Release = rlx_state:get_realized_release(State, RelName, RelVsn), + OutputDir = rlx_state:output_dir(State), case create_output_dir(OutputDir) of ok -> - case rcl_release:realized(Release) of + case rlx_release:realized(Release) of true -> copy_app_directories_to_output(State, Release, OutputDir); false -> - ?RCL_ERROR({unresolved_release, RelName, RelVsn}) + ?RLX_ERROR({unresolved_release, RelName, RelVsn}) end; Error -> Error @@ -73,16 +73,30 @@ format_error({release_script_generation_error, RelFile}) -> [RelFile]); format_error({release_script_generation_warning, Module, Warnings}) -> ["Warnings generating release \s", - rcl_util:indent(1), Module:format_warning(Warnings)]; + rlx_util:indent(1), Module:format_warning(Warnings)]; format_error({unable_to_create_output_dir, OutputDir}) -> io_lib:format("Unable to create output directory (possible permissions issue): ~s", [OutputDir]); format_error({release_script_generation_error, Module, Errors}) -> ["Errors generating release \n", - rcl_util:indent(1), Module:format_error(Errors)]; + rlx_util:indent(1), Module:format_error(Errors)]; +format_error({relup_generation_error, CurrentName, UpFromName}) -> + io_lib:format("Unknown internal release error generating the relup from ~s to ~s", + [UpFromName, CurrentName]); +format_error({relup_generation_warning, Module, Warnings}) -> + ["Warnings generating relup \s", + rlx_util:indent(1), Module:format_warning(Warnings)]; +format_error({relup_script_generation_error, + {relupcript_generation_error, systools_relup, + {missing_sasl, _}}}) -> + "Unfortunately, due to requirements in systools, you need to have the sasl application " + "in both the current release and the release to upgrade from."; +format_error({relup_script_generation_error, Module, Errors}) -> + ["Errors generating relup \n", + rlx_util:indent(1), Module:format_error(Errors)]; format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}) -> io_lib:format("Unable to symlink directory ~s to ~s because \n~s~s", - [AppDir, TargetDir, rcl_util:indent(1), + [AppDir, TargetDir, rlx_util:indent(1), file:format_error(Reason)]). %%%=================================================================== @@ -93,11 +107,11 @@ format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}) -> create_output_dir(OutputDir) -> case filelib:is_dir(OutputDir) of false -> - case rcl_util:mkdir_p(OutputDir) of + case rlx_util:mkdir_p(OutputDir) of ok -> ok; {error, _} -> - ?RCL_ERROR({unable_to_create_output_dir, OutputDir}) + ?RLX_ERROR({unable_to_create_output_dir, OutputDir}) end; true -> ok @@ -106,7 +120,7 @@ create_output_dir(OutputDir) -> copy_app_directories_to_output(State, Release, OutputDir) -> LibDir = filename:join([OutputDir, "lib"]), ok = ec_file:mkdir_p(LibDir), - Apps = rcl_release:application_details(Release), + Apps = rlx_release:application_details(Release), Result = lists:filter(fun({error, _}) -> true; (_) -> @@ -123,9 +137,9 @@ copy_app_directories_to_output(State, Release, OutputDir) -> end. copy_app(LibDir, App) -> - AppName = erlang:atom_to_list(rcl_app_info:name(App)), - AppVsn = rcl_app_info:vsn_as_string(App), - AppDir = rcl_app_info:dir(App), + AppName = erlang:atom_to_list(rlx_app_info:name(App)), + AppVsn = rlx_app_info:vsn_as_string(App), + AppDir = rlx_app_info:dir(App), TargetDir = filename:join([LibDir, AppName ++ "-" ++ AppVsn]), if AppDir == TargetDir -> @@ -138,7 +152,7 @@ copy_app(LibDir, App) -> copy_app(App, AppDir, TargetDir) -> remove_symlink_or_directory(TargetDir), - case rcl_app_info:link(App) of + case rlx_app_info:link(App) of true -> link_directory(AppDir, TargetDir); false -> @@ -161,7 +175,7 @@ remove_symlink_or_directory(TargetDir) -> link_directory(AppDir, TargetDir) -> case file:make_symlink(AppDir, TargetDir) of {error, Reason} -> - ?RCL_ERROR({unable_to_make_symlink, AppDir, TargetDir, Reason}); + ?RLX_ERROR({unable_to_make_symlink, AppDir, TargetDir, Reason}); ok -> ok end. @@ -182,10 +196,10 @@ copy_dir(AppDir, TargetDir, SubDir) -> SubTarget = filename:join(TargetDir, SubDir), case filelib:is_dir(SubSource) of true -> - ok = rcl_util:mkdir_p(SubTarget), + ok = rlx_util:mkdir_p(SubTarget), case ec_file:copy(SubSource, SubTarget, [recursive]) of {error, E} -> - ?RCL_ERROR({ec_file_error, AppDir, SubTarget, E}); + ?RLX_ERROR({ec_file_error, AppDir, SubTarget, E}); ok -> ok end; @@ -193,42 +207,41 @@ copy_dir(AppDir, TargetDir, SubDir) -> ok end. -create_release_info(State, Release, OutputDir) -> - RelName = erlang:atom_to_list(rcl_release:name(Release)), - ReleaseDir = filename:join([OutputDir, - "releases", - RelName ++ "-" ++ - rcl_release:vsn(Release)]), +create_release_info(State0, Release0, OutputDir) -> + RelName = erlang:atom_to_list(rlx_release:name(Release0)), + ReleaseDir = release_output_dir(State0, Release0), ReleaseFile = filename:join([ReleaseDir, RelName ++ ".rel"]), ok = ec_file:mkdir_p(ReleaseDir), - case rcl_release:metadata(Release) of + Release1 = rlx_release:relfile(Release0, ReleaseFile), + State1 = rlx_state:update_realized_release(State0, Release1), + case rlx_release:metadata(Release1) of {ok, Meta} -> ok = ec_file:write_term(ReleaseFile, Meta), - write_bin_file(State, Release, OutputDir, ReleaseDir); + write_bin_file(State1, Release1, OutputDir, ReleaseDir); E -> E end. write_bin_file(State, Release, OutputDir, RelDir) -> - RelName = erlang:atom_to_list(rcl_release:name(Release)), - RelVsn = rcl_release:vsn(Release), + RelName = erlang:atom_to_list(rlx_release:name(Release)), + RelVsn = rlx_release:vsn(Release), BinDir = filename:join([OutputDir, "bin"]), ok = ec_file:mkdir_p(BinDir), - VsnRel = filename:join(BinDir, RelName ++ "-" ++ RelVsn), + VsnRel = filename:join(BinDir, rlx_release:canonical_name(Release)), BareRel = filename:join(BinDir, RelName), - ErlOpts = rcl_state:get(State, erl_opts, ""), - StartFile = case rcl_state:get(State, extended_start_script, false) of + ErlOpts = rlx_state:get(State, erl_opts, ""), + StartFile = case rlx_state:get(State, extended_start_script, false) of false -> bin_file_contents(RelName, RelVsn, - rcl_release:erts(Release), + rlx_release:erts(Release), ErlOpts); true -> - extended_bin_file_contents(RelName, RelVsn, rcl_release:erts(Release), ErlOpts) + extended_bin_file_contents(RelName, RelVsn, rlx_release:erts(Release), ErlOpts) end, %% We generate the start script by default, unless the user %% tells us not too - case rcl_state:get(State, generate_start_script, true) of + case rlx_state:get(State, generate_start_script, true) of false -> ok; _ -> @@ -241,19 +254,19 @@ write_bin_file(State, Release, OutputDir, RelDir) -> copy_or_generate_sys_config_file(State, Release, OutputDir, RelDir). %% @doc copy config/sys.config or generate one to releases/VSN/sys.config --spec copy_or_generate_sys_config_file(rcl_state:t(), rcl_release:t(), +-spec copy_or_generate_sys_config_file(rlx_state:t(), rlx_release:t(), file:name(), file:name()) -> - {ok, rcl_state:t()} | relcool:error(). + {ok, rlx_state:t()} | relx:error(). copy_or_generate_sys_config_file(State, Release, OutputDir, RelDir) -> RelSysConfPath = filename:join([RelDir, "sys.config"]), - case rcl_state:sys_config(State) of + case rlx_state:sys_config(State) of undefined -> ok = generate_sys_config_file(RelSysConfPath), include_erts(State, Release, OutputDir, RelDir); ConfigPath -> case filelib:is_regular(ConfigPath) of false -> - ?RCL_ERROR({config_does_not_exist, ConfigPath}); + ?RLX_ERROR({config_does_not_exist, ConfigPath}); true -> ok = ec_file:copy(ConfigPath, RelSysConfPath), include_erts(State, Release, OutputDir, RelDir) @@ -277,23 +290,23 @@ generate_sys_config_file(RelSysConfPath) -> file:close(Fd). %% @doc Optionally add erts directory to release, if defined. --spec include_erts(rcl_state:t(), rcl_release:t(), file:name(), file:name()) -> {ok, rcl_state:t()} | relcool:error(). +-spec include_erts(rlx_state:t(), rlx_release:t(), file:name(), file:name()) -> {ok, rlx_state:t()} | relx:error(). include_erts(State, Release, OutputDir, RelDir) -> - case rcl_state:get(State, include_erts, true) of + case rlx_state:get(State, include_erts, true) of true -> Prefix = code:root_dir(), - ErtsVersion = rcl_release:erts(Release), + ErtsVersion = rlx_release:erts(Release), ErtsDir = filename:join([Prefix, "erts-" ++ ErtsVersion]), LocalErts = filename:join([OutputDir, "erts-" ++ ErtsVersion]), case filelib:is_dir(ErtsDir) of false -> - ?RCL_ERROR({specified_erts_does_not_exist, ErtsVersion}); + ?RLX_ERROR({specified_erts_does_not_exist, ErtsVersion}); true -> ok = ec_file:mkdir_p(LocalErts), ok = ec_file:copy(ErtsDir, LocalErts, [recursive]), ok = ec_file:remove(filename:join([LocalErts, "bin", "erl"])), ok = file:write_file(filename:join([LocalErts, "bin", "erl"]), erl_script(ErtsVersion)), - case rcl_state:get(State, extended_start_script, false) of + case rlx_state:get(State, extended_start_script, false) of true -> ok = ec_file:copy(filename:join([Prefix, "bin", "start_clean.boot"]), filename:join([OutputDir, "bin", "start_clean.boot"])), @@ -311,58 +324,158 @@ include_erts(State, Release, OutputDir, RelDir) -> end. --spec make_boot_script(rcl_state:t(), rcl_release:t(), file:name(), file:name()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec make_boot_script(rlx_state:t(), rlx_release:t(), file:name(), file:name()) -> + {ok, rlx_state:t()} | relx:error(). make_boot_script(State, Release, OutputDir, RelDir) -> Options = [{path, [RelDir | get_code_paths(Release, OutputDir)]}, {outdir, RelDir}, no_module_tests, silent], - Name = erlang:atom_to_list(rcl_release:name(Release)), + Name = erlang:atom_to_list(rlx_release:name(Release)), ReleaseFile = filename:join([RelDir, Name ++ ".rel"]), - rcl_log:debug(rcl_state:log(State), - "Creating script from release file ~s ~n with options ~p ~n", - [ReleaseFile, Options]), - case make_script(Name, Options) of + case make_script(Options, + fun(CorrectedOptions) -> + systools:make_script(Name, CorrectedOptions) + end) of ok -> - rcl_log:error(rcl_state:log(State), + rlx_log:error(rlx_state:log(State), "release successfully created!"), - {ok, State}; + make_relup(State, Release); error -> - ?RCL_ERROR({release_script_generation_error, ReleaseFile}); + ?RLX_ERROR({release_script_generation_error, ReleaseFile}); {ok, _, []} -> - rcl_log:error(rcl_state:log(State), + rlx_log:error(rlx_state:log(State), "release successfully created!"), - {ok, State}; + make_relup(State, Release); {ok,Module,Warnings} -> - ?RCL_ERROR({release_script_generation_warn, Module, Warnings}); + ?RLX_ERROR({release_script_generation_warn, Module, Warnings}); {error,Module,Error} -> - ?RCL_ERROR({release_script_generation_error, Module, Error}) + ?RLX_ERROR({release_script_generation_error, Module, Error}) end. --spec make_script(string(), [term()]) -> - ok | - error | - {ok, module(), [term()]} | - {error,module,[term()]}. -make_script(Name, Options) -> +-spec make_script([term()], + fun(([term()]) -> Res)) -> Res. +make_script(Options, RunFun) -> %% Erts 5.9 introduced a non backwards compatible option to %% erlang this takes that into account Erts = erlang:system_info(version), case ec_semver:gte(Erts, "5.9") of true -> - systools:make_script(Name, [no_warn_sasl | Options]); + RunFun([no_warn_sasl | Options]); _ -> - systools:make_script(Name, Options) + RunFun(Options) + end. + +make_relup(State, Release) -> + case rlx_state:action(State) of + relup -> + UpFrom = + case rlx_state:upfrom(State) of + undefined -> + get_last_release(State, Release); + Vsn -> + get_up_release(State, Release, Vsn) + end, + case UpFrom of + undefined -> + ?RLX_ERROR(no_upfrom_release_found); + _ -> + make_upfrom_script(State, Release, UpFrom) + end; + _ -> + {ok, State} + end. + +make_upfrom_script(State, Release, UpFrom) -> + OutputDir = rlx_state:output_dir(State), + Options = [{outdir, OutputDir}, + {path, get_code_paths(Release, OutputDir) ++ + get_code_paths(UpFrom, OutputDir)}, + silent], + CurrentRel = strip_rel(rlx_release:relfile(Release)), + UpFromRel = strip_rel(rlx_release:relfile(UpFrom)), + rlx_log:debug(rlx_state:log(State), + "systools:make_relup(~p, ~p, ~p, ~p)", + [CurrentRel, UpFromRel, UpFromRel, Options]), + case make_script(Options, + fun(CorrectOptions) -> + systools:make_relup(CurrentRel, [UpFromRel], [UpFromRel], CorrectOptions) + end) of + ok -> + rlx_log:error(rlx_state:log(State), + "relup from ~s to ~s successfully created!", + [UpFromRel, CurrentRel]), + {ok, State}; + error -> + ?RLX_ERROR({relup_script_generation_error, CurrentRel, UpFromRel}); + {ok, RelUp, _, []} -> + rlx_log:error(rlx_state:log(State), + "relup successfully created!"), + write_relup_file(State, Release, RelUp), + {ok, State}; + {ok,_, Module,Warnings} -> + ?RLX_ERROR({relup_script_generation_warn, Module, Warnings}); + {error,Module,Errors} -> + ?RLX_ERROR({relupcript_generation_error, Module, Errors}) end. +write_relup_file(State, Release, Relup) -> + OutDir = release_output_dir(State, Release), + RelName = rlx_util:to_string(rlx_release:name(Release)), + RelupFile = filename:join(OutDir, RelName ++ ".relup"), + ok = ec_file:write_term(RelupFile, Relup). + +strip_rel(Name) -> + rlx_util:to_string(filename:join(filename:dirname(Name), + filename:basename(Name, ".rel"))). + + +get_up_release(State, Release, Vsn) -> + Name = rlx_release:name(Release), + try + ec_dictionary:get({Name, Vsn}, rlx_state:realized_releases(State)) + catch + throw:notfound -> + undefined + end. + +get_last_release(State, Release) -> + Releases0 = [Rel || {{_, _}, Rel} <- ec_dictionary:to_list(rlx_state:realized_releases(State))], + Releases1 = lists:sort(fun(R1, R2) -> + ec_semver:lte(rlx_release:vsn(R1), + rlx_release:vsn(R2)) + end, Releases0), + Res = lists:foldl(fun(_Rel, R = {found, _}) -> + R; + (Rel, Prev) -> + case rlx_release:vsn(Rel) == rlx_release:vsn(Release) of + true -> + {found, Prev}; + false -> + Rel + end + end, undefined, Releases1), + case Res of + {found, R} -> + R; + Else -> + Else + end. + +-spec release_output_dir(rlx_state:t(), rlx_release:t()) -> string(). +release_output_dir(State, Release) -> + OutputDir = rlx_state:output_dir(State), + filename:join([OutputDir, + "releases", + rlx_release:canonical_name(Release)]). + %% @doc Generates the correct set of code paths for the system. --spec get_code_paths(rcl_release:t(), file:name()) -> [file:name()]. +-spec get_code_paths(rlx_release:t(), file:name()) -> [file:name()]. get_code_paths(Release, OutDir) -> LibDir = filename:join(OutDir, "lib"), [filename:join([LibDir, - erlang:atom_to_list(rcl_app_info:name(App)) ++ "-" ++ - rcl_app_info:vsn_as_string(App), "ebin"]) || - App <- rcl_release:application_details(Release)]. + erlang:atom_to_list(rlx_app_info:name(App)) ++ "-" ++ + rlx_app_info:vsn_as_string(App), "ebin"]) || + App <- rlx_release:application_details(Release)]. erl_script(ErtsVsn) -> [<<"#!/bin/sh diff --git a/src/rcl_prv_config.erl b/src/rlx_prv_config.erl index dfbc321..36a0527 100644 --- a/src/rcl_prv_config.erl +++ b/src/rlx_prv_config.erl @@ -21,31 +21,31 @@ %%% A module that provides config parsing and support to the system %%% @end %%%------------------------------------------------------------------- --module(rcl_prv_config). +-module(rlx_prv_config). --behaviour(rcl_provider). +-behaviour(rlx_provider). %% API -export([init/1, do/1, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%%=================================================================== %%% API %%%=================================================================== %% @doc Required by the system, but not used in this provider --spec init(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). +-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(rcl_state:t()) ->{ok, rcl_state:t()} | relcool:error(). +-spec do(rlx_state:t()) ->{ok, rlx_state:t()} | relx:error(). do(State) -> - case rcl_state:config_file(State) of + case rlx_state:config_file(State) of [] -> search_for_dominating_config(State); undefined -> @@ -65,7 +65,7 @@ format_error({invalid_term, Term}) -> %%% Internal Functions %%%=================================================================== search_for_dominating_config({ok, Cwd}) -> - ConfigFile = filename:join(Cwd, "relcool.config"), + ConfigFile = filename:join(Cwd, "relx.config"), case ec_file:exists(ConfigFile) of true -> {ok, ConfigFile}; @@ -80,8 +80,8 @@ search_for_dominating_config(State0) -> {ok, Config} -> %% we need to set the root dir on state as well {ok, RootDir} = parent_dir(Config), - State1 = rcl_state:root_dir(State0, RootDir), - load_config(Config, rcl_state:config_file(State1, Config)); + State1 = rlx_state:root_dir(State0, RootDir), + load_config(Config, rlx_state:config_file(State1, Config)); no_config -> {ok, State0} end. @@ -106,24 +106,24 @@ parent_dir([H | T], Acc) -> parent_dir(T, [H | Acc]). --spec load_config(file:filename(), rcl_state:t()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec load_config(file:filename(), 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} -> - ?RCL_ERROR({consult, ConfigFile, Reason}); + ?RLX_ERROR({consult, ConfigFile, Reason}); {ok, Terms} -> lists:foldl(fun load_terms/2, {ok, State}, Terms) end, ok = file:set_cwd(CurrentCwd), Result. --spec load_terms(term(), {ok, rcl_state:t()} | relcool:error()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec load_terms(term(), {ok, rlx_state:t()} | relx:error()) -> + {ok, rlx_state:t()} | relx:error(). load_terms({default_release, RelName, RelVsn}, {ok, State}) -> - {ok, rcl_state:default_release(State, RelName, RelVsn)}; + {ok, rlx_state:default_configured_release(State, RelName, RelVsn)}; load_terms({paths, Paths}, {ok, State}) -> code:add_pathsa([filename:absname(Path) || Path <- Paths]), {ok, State}; @@ -133,7 +133,7 @@ load_terms({providers, Providers0}, {ok, State0}) -> {_, E={error, _}} -> E; {Providers3, {ok, State3}} -> - {ok, rcl_state:providers(State3, Providers3)} + {ok, rlx_state:providers(State3, Providers3)} end; load_terms({add_providers, Providers0}, {ok, State0}) -> Providers1 = gen_providers(Providers0, State0), @@ -141,45 +141,45 @@ load_terms({add_providers, Providers0}, {ok, State0}) -> {_, E={error, _}} -> E; {Providers3, {ok, State1}} -> - ExistingProviders = rcl_state:providers(State1), - {ok, rcl_state:providers(State1, ExistingProviders ++ Providers3)} + ExistingProviders = rlx_state:providers(State1), + {ok, rlx_state:providers(State1, ExistingProviders ++ Providers3)} end; load_terms({skip_apps, SkipApps0}, {ok, State0}) -> - {ok, rcl_state:skip_apps(State0, SkipApps0)}; + {ok, rlx_state:skip_apps(State0, SkipApps0)}; load_terms({overrides, Overrides0}, {ok, State0}) -> - {ok, rcl_state:overrides(State0, Overrides0)}; + {ok, rlx_state:overrides(State0, Overrides0)}; load_terms({release, {RelName, Vsn}, Applications}, {ok, State0}) -> - Release0 = rcl_release:new(RelName, Vsn), - case rcl_release:goals(Release0, Applications) of + Release0 = rlx_release:new(RelName, Vsn), + case rlx_release:goals(Release0, Applications) of E={error, _} -> E; {ok, Release1} -> - {ok, rcl_state:add_release(State0, Release1)} + {ok, rlx_state:add_configured_release(State0, Release1)} end; load_terms({release, {RelName, Vsn}, {erts, ErtsVsn}, Applications}, {ok, State}) -> - Release0 = rcl_release:erts(rcl_release:new(RelName, Vsn), ErtsVsn), - case rcl_release:goals(Release0, Applications) of + Release0 = rlx_release:erts(rlx_release:new(RelName, Vsn), ErtsVsn), + case rlx_release:goals(Release0, Applications) of E={error, _} -> E; {ok, Release1} -> - {ok, rcl_state:add_release(State, Release1)} + {ok, rlx_state:add_configured_release(State, Release1)} end; load_terms({sys_config, SysConfig}, {ok, State}) -> - {ok, rcl_state:sys_config(State, filename:absname(SysConfig))}; + {ok, rlx_state:sys_config(State, filename:absname(SysConfig))}; load_terms({Name, Value}, {ok, State}) when erlang:is_atom(Name) -> - {ok, rcl_state:put(State, Name, Value)}; + {ok, rlx_state:put(State, Name, Value)}; load_terms(_, Error={error, _}) -> Error; load_terms(InvalidTerm, _) -> - ?RCL_ERROR({invalid_term, InvalidTerm}). + ?RLX_ERROR({invalid_term, InvalidTerm}). --spec gen_providers([module()], rcl_state:t()) -> - {[rcl_provider:t()], {ok, rcl_state:t()} | relcool:error()}. +-spec gen_providers([module()], rlx_state:t()) -> + {[rlx_provider:t()], {ok, rlx_state:t()} | relx:error()}. gen_providers(Providers, State) -> lists:foldl(fun(ProviderName, {Providers1, {ok, State1}}) -> - {Provider, State2} = rcl_provider:new(ProviderName, State1), + {Provider, State2} = rlx_provider:new(ProviderName, State1), {[Provider | Providers1], State2}; (_, E={_, {error, _}}) -> E diff --git a/src/rcl_prv_discover.erl b/src/rlx_prv_discover.erl index 3627787..5e54828 100644 --- a/src/rcl_prv_discover.erl +++ b/src/rlx_prv_discover.erl @@ -21,36 +21,36 @@ %%% @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 rcl_provider behaviour. --module(rcl_prv_discover). --behaviour(rcl_provider). +%%% the state of available apps. This implements the rlx_provider behaviour. +-module(rlx_prv_discover). +-behaviour(rlx_provider). -export([init/1, do/1, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API %%============================================================================ --spec init(rcl_state:t()) -> {ok, rcl_state:t()}. +-spec init(rlx_state:t()) -> {ok, rlx_state:t()}. init(State) -> {ok, State}. %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications --spec do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). +-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). do(State0) -> LibDirs = get_lib_dirs(State0), - case rcl_app_discovery:do(State0, LibDirs) of + case rlx_app_discovery:do(State0, LibDirs) of {ok, AppMeta} -> - case rcl_rel_discovery:do(State0, LibDirs, AppMeta) of + case rlx_rel_discovery:do(State0, LibDirs, AppMeta) of {ok, Releases} -> - State1 = rcl_state:available_apps(State0, AppMeta), - {ok, rcl_state:discovered_releases(State1, lists:foldl(fun add/2, - ec_dictionary:new(ec_dict), - Releases))}; + State1 = rlx_state:available_apps(State0, AppMeta), + {ok, rlx_state:realized_releases(State1, lists:foldl(fun add/2, + ec_dictionary:new(ec_dict), + Releases))}; Error -> Error end; @@ -69,13 +69,13 @@ format_error(_) -> %%%=================================================================== %% @doc only add the release if its not documented in the system add(Rel, Dict) -> - RelName = rcl_release:name(Rel), - RelVsn = rcl_release:vsn(Rel), + RelName = rlx_release:name(Rel), + RelVsn = rlx_release:vsn(Rel), ec_dictionary:add({RelName, RelVsn}, Rel, Dict). get_lib_dirs(State) -> - LibDirs0 = rcl_state:lib_dirs(State), - case rcl_state:get(State, disable_default_libs, false) of + LibDirs0 = rlx_state:lib_dirs(State), + case rlx_state:get(State, disable_default_libs, false) of true -> LibDirs0; false -> @@ -85,15 +85,15 @@ get_lib_dirs(State) -> add_release_output_dir(State)]) end. --spec add_common_project_dirs(rcl_state:t()) -> [file:name()]. +-spec add_common_project_dirs(rlx_state:t()) -> [file:name()]. add_common_project_dirs(State) -> %% Check to see if there is a rebar.config. If so then look for a deps %% dir. If both are there then we add that to the lib dirs. - case rcl_state:get(State, disable_project_subdirs, false) of + case rlx_state:get(State, disable_project_subdirs, false) of true -> []; false -> - Root = rcl_state:root_dir(State), + Root = rlx_state:root_dir(State), Apps = filename:join(Root, "apps"), Lib = filename:join(Root, "lib"), Deps = filename:join(Root, "deps"), @@ -108,9 +108,9 @@ add_common_project_dirs(State) -> end, [], [Deps, Lib, Apps, Ebin]) end. --spec add_system_lib_dir(rcl_state:t()) -> [file:name()]. +-spec add_system_lib_dir(rlx_state:t()) -> [file:name()]. add_system_lib_dir(State) -> - ExcludeSystem = rcl_state:get(State, discover_exclude_system, false), + ExcludeSystem = rlx_state:get(State, discover_exclude_system, false), case ExcludeSystem of true -> []; @@ -119,11 +119,11 @@ add_system_lib_dir(State) -> end. add_release_output_dir(State) -> - case rcl_state:get(State, disable_discover_release_output, false) of + case rlx_state:get(State, disable_discover_release_output, false) of true -> []; false -> - Output = erlang:iolist_to_binary(rcl_state:output_dir(State)), + Output = erlang:iolist_to_binary(rlx_state:output_dir(State)), case ec_file:exists(erlang:binary_to_list(Output)) of true -> Output; diff --git a/src/rcl_prv_overlay.erl b/src/rlx_prv_overlay.erl index 40471ea..5fffd78 100644 --- a/src/rcl_prv_overlay.erl +++ b/src/rlx_prv_overlay.erl @@ -20,9 +20,9 @@ %%% %%% @doc Given a complete built release this provider assembles that release %%% into a release directory. --module(rcl_prv_overlay). +-module(rlx_prv_overlay). --behaviour(rcl_provider). +-behaviour(rlx_provider). -export([init/1, do/1, @@ -30,26 +30,26 @@ -define(DIRECTORY_RE, ".*(\/|\\\\)$"). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API %%============================================================================ --spec init(rcl_state:t()) -> {ok, rcl_state:t()}. +-spec init(rlx_state:t()) -> {ok, rlx_state:t()}. init(State) -> {ok, State}. %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications --spec do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). +-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). do(State) -> - {RelName, RelVsn} = rcl_state:default_release(State), - Release = rcl_state:get_release(State, RelName, RelVsn), - case rcl_release:realized(Release) of + {RelName, RelVsn} = rlx_state:default_configured_release(State), + Release = rlx_state:get_realized_release(State, RelName, RelVsn), + case rlx_release:realized(Release) of true -> generate_overlay_vars(State, Release); false -> - ?RCL_ERROR({unresolved_release, RelName, RelVsn}) + ?RLX_ERROR({unresolved_release, RelName, RelVsn}) end. -spec format_error(ErrorDetail::term()) -> iolist(). @@ -62,13 +62,13 @@ format_error({unable_to_read_varsfile, FileName, Reason}) -> io_lib:format("Unable to read vars file (~s) for overlay due to: ~p", [FileName, Reason]); format_error({overlay_failed, Errors}) -> - [[format_error(rcl_util:error_reason(Error)), "\n"] || Error <- Errors]; + [[format_error(rlx_util:error_reason(Error)), "\n"] || Error <- Errors]; format_error({dir_render_failed, Dir, Error}) -> io_lib:format("rendering mkdir path failed ~s with ~p", [Dir, Error]); format_error({unable_to_make_symlink, AppDir, TargetDir, Reason}) -> io_lib:format("Unable to symlink directory ~s to ~s because \n~s~s", - [AppDir, TargetDir, rcl_util:indent(1), + [AppDir, TargetDir, rlx_util:indent(1), file:format_error(Reason)]); format_error({copy_failed, FromFile, ToFile, Err}) -> io_lib:format("Unable to copy from ~s to ~s because of ~p", @@ -92,25 +92,25 @@ format_error({unable_to_make_dir, Absolute, Error}) -> %%%=================================================================== %%% Internal Functions %%%=================================================================== --spec generate_overlay_vars(rcl_state:t(), rcl_release:t()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec generate_overlay_vars(rlx_state:t(), rlx_release:t()) -> + {ok, rlx_state:t()} | relx:error(). generate_overlay_vars(State, Release) -> StateVars = generate_state_vars(State), ReleaseVars = generate_release_vars(Release), get_overlay_vars_from_file(State, StateVars ++ ReleaseVars). --spec get_overlay_vars_from_file(rcl_state:t(), proplists:proplist()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec get_overlay_vars_from_file(rlx_state:t(), proplists:proplist()) -> + {ok, rlx_state:t()} | relx:error(). get_overlay_vars_from_file(State, OverlayVars) -> - case rcl_state:get(State, overlay_vars, undefined) of + case rlx_state:get(State, overlay_vars, undefined) of undefined -> do_overlay(State, OverlayVars); FileName -> read_overlay_vars(State, OverlayVars, FileName) end. --spec read_overlay_vars(rcl_state:t(), proplists:proplist(), file:name()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec read_overlay_vars(rlx_state:t(), proplists:proplist(), file:name()) -> + {ok, rlx_state:t()} | relx:error(). read_overlay_vars(State, OverlayVars, FileName) -> RelativeRoot = get_relative_root(State), RelativePath = filename:join(RelativeRoot, erlang:iolist_to_binary(FileName)), @@ -123,12 +123,12 @@ read_overlay_vars(State, OverlayVars, FileName) -> Error end; {error, Reason} -> - ?RCL_ERROR({unable_to_read_varsfile, FileName, Reason}) + ?RLX_ERROR({unable_to_read_varsfile, FileName, Reason}) end. -spec render_overlay_vars(proplists:proplist(), proplists:proplist(), proplists:proplist()) -> - {ok, proplists:proplist()} | relcool:error(). + {ok, proplists:proplist()} | relx:error(). render_overlay_vars(OverlayVars, [{Key, Value} | Rest], Acc) when erlang:is_list(Value) -> case io_lib:printable_list(Value) of @@ -161,66 +161,66 @@ render_overlay_vars(OverlayVars, [KeyValue | Rest], Acc) -> render_overlay_vars(_OverlayVars, [], Acc) -> {ok, Acc}. --spec generate_release_vars(rcl_release:t()) -> proplists:proplist(). +-spec generate_release_vars(rlx_release:t()) -> proplists:proplist(). generate_release_vars(Release) -> - [{erts_vsn, rcl_release:erts(Release)}, - {release_erts_version, rcl_release:erts(Release)}, - {release_name, rcl_release:name(Release)}, - {rel_vsn, rcl_release:vsn(Release)}, - {release_version, rcl_release:vsn(Release)}, + [{erts_vsn, rlx_release:erts(Release)}, + {release_erts_version, rlx_release:erts(Release)}, + {release_name, rlx_release:name(Release)}, + {rel_vsn, rlx_release:vsn(Release)}, + {release_version, rlx_release:vsn(Release)}, {release_applications, lists:map(fun(App) -> - rcl_app_info:name(App) - end, rcl_release:application_details(Release))}, - {release, [generate_app_vars(App)|| App <- rcl_release:application_details(Release)]}, + rlx_app_info:name(App) + end, rlx_release:application_details(Release))}, + {release, [generate_app_vars(App)|| App <- rlx_release:application_details(Release)]}, {release_goals, [if erlang:is_list(Constraint) -> Constraint; true -> - rcl_depsolver:format_constraint(Constraint) - end || Constraint <- rcl_release:goals(Release)]}]. + rlx_depsolver:format_constraint(Constraint) + end || Constraint <- rlx_release:goals(Release)]}]. --spec generate_app_vars(rcl_app_info:t()) -> AppInfo::tuple(). +-spec generate_app_vars(rlx_app_info:t()) -> AppInfo::tuple(). generate_app_vars(App) -> - {rcl_app_info:name(App), - [{version, rcl_app_info:vsn_as_string(App)}, - {dir, rcl_app_info:dir(App)}, - {active_dependencies, rcl_app_info:active_deps(App)}, - {library_dependencies, rcl_app_info:library_deps(App)}, - {link, rcl_app_info:link(App)}]}. + {rlx_app_info:name(App), + [{version, rlx_app_info:vsn_as_string(App)}, + {dir, rlx_app_info:dir(App)}, + {active_dependencies, rlx_app_info:active_deps(App)}, + {library_dependencies, rlx_app_info:library_deps(App)}, + {link, rlx_app_info:link(App)}]}. --spec generate_state_vars(rcl_state:t()) -> proplists:proplist(). +-spec generate_state_vars(rlx_state:t()) -> proplists:proplist(). generate_state_vars(State) -> - [{log, rcl_log:format(rcl_state:log(State))}, - {output_dir, rcl_state:output_dir(State)}, - {target_dir, rcl_state:output_dir(State)}, - {overridden, [AppName || {AppName, _} <- rcl_state:overrides(State)]}, - {overrides, rcl_state:overrides(State)}, - {goals, [rcl_depsolver:format_constraint(Constraint) || - Constraint <- rcl_state:goals(State)]}, - {lib_dirs, rcl_state:lib_dirs(State)}, - {config_file, rcl_state:config_file(State)}, - {providers, rcl_state:providers(State)}, - {sys_config, rcl_state:sys_config(State)}, - {root_dir, rcl_state:root_dir(State)}, - {default_release_name, case rcl_state:default_release(State) of + [{log, rlx_log:format(rlx_state:log(State))}, + {output_dir, rlx_state:output_dir(State)}, + {target_dir, rlx_state:output_dir(State)}, + {overridden, [AppName || {AppName, _} <- rlx_state:overrides(State)]}, + {overrides, rlx_state:overrides(State)}, + {goals, [rlx_depsolver:format_constraint(Constraint) || + Constraint <- rlx_state:goals(State)]}, + {lib_dirs, rlx_state:lib_dirs(State)}, + {config_file, rlx_state:config_file(State)}, + {providers, rlx_state:providers(State)}, + {sys_config, rlx_state:sys_config(State)}, + {root_dir, rlx_state:root_dir(State)}, + {default_release_name, case rlx_state:default_configured_release(State) of {Name0, _} -> Name0 end}, - {default_release_version, case rcl_state:default_release(State) of + {default_release_version, case rlx_state:default_configured_release(State) of {_, Vsn0} -> Vsn0 end}, - {default_release, case rcl_state:default_release(State) of + {default_release, case rlx_state:default_configured_release(State) of {Name1, undefined} -> erlang:atom_to_list(Name1); {Name1, Vsn1} -> erlang:atom_to_list(Name1) ++ "-" ++ Vsn1 end}]. --spec do_overlay(rcl_state:t(), proplists:proplist()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec do_overlay(rlx_state:t(), proplists:proplist()) -> + {ok, rlx_state:t()} | relx:error(). do_overlay(State, OverlayVars) -> - case rcl_state:get(State, overlay, undefined) of + case rlx_state:get(State, overlay, undefined) of undefined -> {ok, State}; Overlays -> @@ -231,44 +231,44 @@ do_overlay(State, OverlayVars) -> end, Overlays)) end. --spec handle_errors(rcl_state:t(), [ok | relcool:error()]) -> - {ok, rcl_state:t()} | relcool:error(). +-spec handle_errors(rlx_state:t(), [ok | relx:error()]) -> + {ok, rlx_state:t()} | relx:error(). handle_errors(State, Result) -> case [Error || Error <- Result, - rcl_util:is_error(Error)] of + rlx_util:is_error(Error)] of Errors = [_|_] -> - ?RCL_ERROR({overlay_failed, Errors}); + ?RLX_ERROR({overlay_failed, Errors}); [] -> {ok, State} end. --spec do_individual_overlay(rcl_state:t(), proplists:proplist(), +-spec do_individual_overlay(rlx_state:t(), proplists:proplist(), OverlayDirective::term()) -> - {ok, rcl_state:t()} | relcool:error(). + {ok, rlx_state:t()} | relx:error(). do_individual_overlay(State, OverlayVars, {mkdir, Dir}) -> - ModuleName = make_template_name("rcl_mkdir_template", Dir), + ModuleName = make_template_name("rlx_mkdir_template", Dir), case erlydtl:compile(erlang:iolist_to_binary(Dir), ModuleName) of {ok, ModuleName} -> case render(ModuleName, OverlayVars) of {ok, IoList} -> Absolute = absolutize(State, - filename:join(rcl_state:output_dir(State), + filename:join(rlx_state:output_dir(State), erlang:iolist_to_binary(IoList))), - case rcl_util:mkdir_p(Absolute) of + case rlx_util:mkdir_p(Absolute) of {error, Error} -> - ?RCL_ERROR({unable_to_make_dir, Absolute, Error}); + ?RLX_ERROR({unable_to_make_dir, Absolute, Error}); ok -> ok end; {error, Error} -> - ?RCL_ERROR({dir_render_failed, Dir, Error}) + ?RLX_ERROR({dir_render_failed, Dir, Error}) end; {error, Reason} -> - ?RCL_ERROR({unable_to_compile_template, Dir, Reason}) + ?RLX_ERROR({unable_to_compile_template, Dir, Reason}) end; do_individual_overlay(State, OverlayVars, {copy, From, To}) -> - FromTemplateName = make_template_name("rcl_copy_from_template", From), - ToTemplateName = make_template_name("rcl_copy_to_template", To), + FromTemplateName = make_template_name("rlx_copy_from_template", From), + ToTemplateName = make_template_name("rlx_copy_to_template", To), file_render_do(OverlayVars, From, FromTemplateName, fun(FromFile) -> file_render_do(OverlayVars, To, ToTemplateName, @@ -277,8 +277,8 @@ do_individual_overlay(State, OverlayVars, {copy, From, To}) -> end) end); do_individual_overlay(State, OverlayVars, {template, From, To}) -> - FromTemplateName = make_template_name("rcl_template_from_template", From), - ToTemplateName = make_template_name("rcl_template_to_template", To), + FromTemplateName = make_template_name("rlx_template_from_template", From), + ToTemplateName = make_template_name("rlx_template_to_template", To), file_render_do(OverlayVars, From, FromTemplateName, fun(FromFile) -> file_render_do(OverlayVars, To, ToTemplateName, @@ -291,15 +291,15 @@ do_individual_overlay(State, OverlayVars, {template, From, To}) -> write_template(OverlayVars, FromFile1, absolutize(State, - filename:join(rcl_state:output_dir(State), + filename:join(rlx_state:output_dir(State), erlang:iolist_to_binary(ToFile)))) end) end). --spec copy_to(rcl_state:t(), file:name(), file:name()) -> ok | relcool:error(). +-spec copy_to(rlx_state:t(), file:name(), file:name()) -> ok | relx:error(). copy_to(State, FromFile0, ToFile0) -> RelativeRoot = get_relative_root(State), - ToFile1 = absolutize(State, filename:join(rcl_state:output_dir(State), + ToFile1 = absolutize(State, filename:join(rlx_state:output_dir(State), erlang:iolist_to_binary(ToFile0))), FromFile1 = absolutize(State, filename:join(RelativeRoot, @@ -309,7 +309,7 @@ copy_to(State, FromFile0, ToFile0) -> filelib:ensure_dir(ToFile1), ToFile1; true -> - rcl_util:mkdir_p(ToFile1), + rlx_util:mkdir_p(ToFile1), erlang:iolist_to_binary(filename:join(ToFile1, filename:basename(FromFile1))) end, @@ -319,15 +319,15 @@ copy_to(State, FromFile0, ToFile0) -> ok = file:write_file_info(ToFile2, FileInfo), ok; {error, Err} -> - ?RCL_ERROR({copy_failed, + ?RLX_ERROR({copy_failed, FromFile1, ToFile1, Err}) end. get_relative_root(State) -> - case rcl_state:config_file(State) of + case rlx_state:config_file(State) of [] -> - rcl_state:root_dir(State); + rlx_state:root_dir(State); Config -> filename:dirname(Config) end. @@ -343,19 +343,19 @@ is_directory(ToFile0, ToFile1) -> -spec render_template(proplists:proplist(), iolist()) -> - ok | relcool:error(). + ok | relx:error(). render_template(OverlayVars, Data) -> - TemplateName = make_template_name("rcl_template_renderer", Data), + TemplateName = make_template_name("rlx_template_renderer", Data), case erlydtl:compile(Data, TemplateName) of Good when Good =:= ok; Good =:= {ok, TemplateName} -> case render(TemplateName, OverlayVars) of {ok, IoData} -> {ok, IoData}; {error, Reason} -> - ?RCL_ERROR({unable_to_render_template, Data, Reason}) + ?RLX_ERROR({unable_to_render_template, Data, Reason}) end; {error, Reason} -> - ?RCL_ERROR({unable_to_compile_template, Data, Reason}) + ?RLX_ERROR({unable_to_compile_template, Data, Reason}) end. write_template(OverlayVars, FromFile, ToFile) -> @@ -369,18 +369,18 @@ write_template(OverlayVars, FromFile, ToFile) -> ok = file:write_file_info(ToFile, FileInfo), ok; {error, Reason} -> - ?RCL_ERROR({unable_to_write, ToFile, Reason}) + ?RLX_ERROR({unable_to_write, ToFile, Reason}) end; {error, Reason} -> - ?RCL_ERROR({unable_to_enclosing_dir, ToFile, Reason}) + ?RLX_ERROR({unable_to_enclosing_dir, ToFile, Reason}) end; Error -> Error end. -spec file_render_do(proplists:proplist(), iolist(), module(), - fun((term()) -> {ok, rcl_state:t()} | relcool:error())) -> - {ok, rcl_state:t()} | relcool:error(). + fun((term()) -> {ok, rlx_state:t()} | relx:error())) -> + {ok, rlx_state:t()} | relx:error(). file_render_do(OverlayVars, Data, TemplateName, NextAction) -> case erlydtl:compile(erlang:iolist_to_binary(Data), TemplateName) of {ok, TemplateName} -> @@ -388,10 +388,10 @@ file_render_do(OverlayVars, Data, TemplateName, NextAction) -> {ok, IoList} -> NextAction(IoList); {error, Error} -> - ?RCL_ERROR({render_failed, Data, Error}) + ?RLX_ERROR({render_failed, Data, Error}) end; {error, Reason} -> - ?RCL_ERROR({unable_to_compile_template, Data, Reason}) + ?RLX_ERROR({unable_to_compile_template, Data, Reason}) end. -spec make_template_name(string(), term()) -> module(). @@ -414,5 +414,5 @@ render(ModuleName, OverlayVars) -> end. absolutize(State, FileName) -> - filename:absname(filename:join(rcl_state:root_dir(State), + filename:absname(filename:join(rlx_state:root_dir(State), erlang:iolist_to_binary(FileName))). diff --git a/src/rcl_prv_release.erl b/src/rlx_prv_release.erl index eac1f20..10e1eb0 100644 --- a/src/rcl_prv_release.erl +++ b/src/rlx_prv_release.erl @@ -21,27 +21,27 @@ %%% @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 rcl_provider behaviour. --module(rcl_prv_release). +%%% the state of available apps. This implements the rlx_provider behaviour. +-module(rlx_prv_release). --behaviour(rcl_provider). +-behaviour(rlx_provider). -export([init/1, do/1, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API %%============================================================================ --spec init(rcl_state:t()) -> {ok, rcl_state:t()}. +-spec init(rlx_state:t()) -> {ok, rlx_state:t()}. init(State) -> {ok, State}. %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications --spec do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error(). +-spec do(rlx_state:t()) -> {ok, rlx_state:t()} | relx:error(). do(State) -> DepGraph = create_dep_graph(State), find_default_release(State, DepGraph). @@ -65,37 +65,37 @@ format_error({release_not_found, {RelName, RelVsn}}) -> io_lib:format("No releases exist in the system for ~p:~s!", [RelName, RelVsn]); format_error({failed_solve, Error}) -> io_lib:format("Failed to solve release:\n ~s", - [rcl_depsolver:format_error({error, Error})]). + [rlx_depsolver:format_error({error, Error})]). %%%=================================================================== %%% Internal Functions %%%=================================================================== --spec create_dep_graph(rcl_state:t()) -> rcl_depsolver:t(). +-spec create_dep_graph(rlx_state:t()) -> rlx_depsolver:t(). create_dep_graph(State) -> - Apps = rcl_state:available_apps(State), - Graph0 = rcl_depsolver:new_graph(), + Apps = rlx_state:available_apps(State), + Graph0 = rlx_depsolver:new_graph(), lists:foldl(fun(App, Graph1) -> - AppName = rcl_app_info:name(App), - AppVsn = rcl_app_info:vsn(App), - Deps = rcl_app_info:active_deps(App) ++ - rcl_app_info:library_deps(App), - rcl_depsolver:add_package_version(Graph1, + AppName = rlx_app_info:name(App), + AppVsn = rlx_app_info:vsn(App), + Deps = rlx_app_info:active_deps(App) ++ + rlx_app_info:library_deps(App), + rlx_depsolver:add_package_version(Graph1, AppName, AppVsn, Deps) end, Graph0, Apps). --spec find_default_release(rcl_state:t(), rcl_depsolver:t()) -> - {ok, rcl_state:t()} | relcool:error(). +-spec find_default_release(rlx_state:t(), rlx_depsolver:t()) -> + {ok, rlx_state:t()} | relx:error(). find_default_release(State, DepGraph) -> - case rcl_state:default_release(State) of + case rlx_state:default_configured_release(State) of {undefined, undefined} -> resolve_default_release(State, DepGraph); {RelName, undefined} -> resolve_default_version(State, DepGraph, RelName); {undefined, Vsn} -> - ?RCL_ERROR({no_release_name, Vsn}); + ?RLX_ERROR({no_release_name, Vsn}); {RelName, RelVsn} -> solve_release(State, DepGraph, RelName, RelVsn) end. @@ -103,29 +103,29 @@ find_default_release(State, DepGraph) -> resolve_default_release(State0, DepGraph) -> %% Here we will just get the highest versioned release and run that. case lists:sort(fun release_sort/2, - ec_dictionary:to_list(rcl_state:releases(State0))) of + ec_dictionary:to_list(rlx_state:configured_releases(State0))) of [{{RelName, RelVsn}, _} | _] -> - State1 = rcl_state:default_release(State0, RelName, RelVsn), + State1 = rlx_state:default_configured_release(State0, RelName, RelVsn), solve_release(State1, DepGraph, RelName, RelVsn); [] -> - ?RCL_ERROR(no_releases_in_system) + ?RLX_ERROR(no_releases_in_system) end. resolve_default_version(State0, DepGraph, RelName) -> %% Here we will just get the lastest version and run that. - AllReleases = ec_dictionary:to_list(rcl_state:releases(State0)), + AllReleases = ec_dictionary:to_list(rlx_state:configured_releases(State0)), SpecificReleases = [Rel || Rel={{PossibleRelName, _}, _} <- AllReleases, PossibleRelName =:= RelName], case lists:sort(fun release_sort/2, SpecificReleases) of [{{RelName, RelVsn}, _} | _] -> - State1 = rcl_state:default_release(State0, RelName, RelVsn), + State1 = rlx_state:default_configured_release(State0, RelName, RelVsn), solve_release(State1, DepGraph, RelName, RelVsn); [] -> - ?RCL_ERROR({no_releases_for, RelName}) + ?RLX_ERROR({no_releases_for, RelName}) end. --spec release_sort({{rcl_release:name(),rcl_release:vsn()}, term()}, - {{rcl_release:name(),rcl_release:vsn()}, term()}) -> +-spec release_sort({{rlx_release:name(),rlx_release:vsn()}, term()}, + {{rlx_release:name(),rlx_release:vsn()}, term()}) -> boolean(). release_sort({{RelName, RelVsnA}, _}, {{RelName, RelVsnB}, _}) -> @@ -139,42 +139,42 @@ release_sort({{RelNameA, RelVsnA}, _}, {{RelNameB, RelVsnB}, _}) -> ec_semver:lte(RelVsnA, RelVsnB). solve_release(State0, DepGraph, RelName, RelVsn) -> - rcl_log:debug(rcl_state:log(State0), + rlx_log:debug(rlx_state:log(State0), "Solving Release ~p-~s~n", [RelName, RelVsn]), try - Release = rcl_state:get_release(State0, RelName, RelVsn), - Goals = rcl_release:goals(Release), + Release = rlx_state:get_configured_release(State0, RelName, RelVsn), + Goals = rlx_release:goals(Release), case Goals of [] -> - ?RCL_ERROR(no_goals_specified); + ?RLX_ERROR(no_goals_specified); _ -> - case rcl_depsolver:solve(DepGraph, Goals) of + case rlx_depsolver:solve(DepGraph, Goals) of {ok, Pkgs} -> set_resolved(State0, Release, Pkgs); {error, Error} -> - ?RCL_ERROR({failed_solve, Error}) + ?RLX_ERROR({failed_solve, Error}) end end catch throw:not_found -> - ?RCL_ERROR({release_not_found, RelName, RelVsn}) + ?RLX_ERROR({release_not_found, RelName, RelVsn}) end. set_resolved(State, Release0, Pkgs) -> - case rcl_release:realize(Release0, Pkgs, rcl_state:available_apps(State)) of + case rlx_release:realize(Release0, Pkgs, rlx_state:available_apps(State)) of {ok, Release1} -> - rcl_log:info(rcl_state:log(State), + rlx_log:info(rlx_state:log(State), "Resolved ~p-~s~n", - [rcl_release:name(Release1), - rcl_release:vsn(Release1)]), - rcl_log:debug(rcl_state:log(State), + [rlx_release:name(Release1), + rlx_release:vsn(Release1)]), + rlx_log:debug(rlx_state:log(State), fun() -> - rcl_release:format(1, Release1) + rlx_release:format(1, Release1) end), - {ok, rcl_state:update_release(State, Release1)}; + {ok, rlx_state:add_realized_release(State, Release1)}; {error, E} -> - ?RCL_ERROR({release_error, E}) + ?RLX_ERROR({release_error, E}) end. %%%=================================================================== diff --git a/src/rcl_rel_discovery.erl b/src/rlx_rel_discovery.erl index d9012ea..53b329f 100644 --- a/src/rcl_rel_discovery.erl +++ b/src/rlx_rel_discovery.erl @@ -21,13 +21,13 @@ %%% @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 rcl_provider behaviour. --module(rcl_rel_discovery). +%%% the state of available apps. This implements the rlx_provider behaviour. +-module(rlx_rel_discovery). -export([do/3, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%============================================================================ %% API @@ -35,13 +35,13 @@ %% @doc recursively dig down into the library directories specified in the state %% looking for OTP Applications --spec do(rcl_state:t(), [filename:name()], [rcl_app_info:t()]) -> - {ok, [rcl_release:t()]} | relcool:error(). +-spec do(rlx_state:t(), [filename:name()], [rlx_app_info:t()]) -> + {ok, [rlx_release:t()]} | relx:error(). do(State, LibDirs, AppMeta) -> - rcl_log:info(rcl_state:log(State), + rlx_log:info(rlx_state:log(State), fun() -> ["Resolving available releases from directories:\n", - [[rcl_util:indent(1), LibDir, "\n"] || LibDir <- LibDirs]] + [[rlx_util:indent(1), LibDir, "\n"] || LibDir <- LibDirs]] end), resolve_rel_metadata(State, LibDirs, AppMeta). @@ -54,7 +54,7 @@ format_error(ErrorDetails) %%% Internal Functions %%%=================================================================== resolve_rel_metadata(State, LibDirs, AppMeta) -> - ReleaseMeta0 = lists:flatten(rcl_dscv_util:do(fun(LibDir, FileType) -> + ReleaseMeta0 = lists:flatten(rlx_dscv_util:do(fun(LibDir, FileType) -> discover_dir(LibDir, AppMeta, FileType) @@ -75,14 +75,14 @@ resolve_rel_metadata(State, LibDirs, AppMeta) -> case Errors of [] -> ReleaseMeta1 = [RelMeta || {ok, RelMeta} <- ReleaseMeta0], - rcl_log:debug(rcl_state:log(State), + rlx_log:debug(rlx_state:log(State), fun() -> ["Resolved the following OTP Releases from the system: \n", - [[rcl_release:format(1, Rel), "\n"] || Rel <- ReleaseMeta1]] + [[rlx_release:format(1, Rel), "\n"] || Rel <- ReleaseMeta1]] end), {ok, ReleaseMeta1}; _ -> - ?RCL_ERROR(Errors) + ?RLX_ERROR(Errors) end. -spec format_detail(ErrorDetail::term()) -> iolist(). @@ -91,8 +91,8 @@ format_detail({accessing, File, eaccess}) -> format_detail({accessing, File, Type}) -> io_lib:format("error (~p) accessing file ~s", [Type, File]). --spec discover_dir(file:name(), [rcl_app_info:t()], directory | file) -> - {ok, rcl_release:t()} +-spec discover_dir(file:name(), [rlx_app_info:t()], directory | file) -> + {ok, rlx_release:t()} | {error, Reason::term()} | {noresult, false}. discover_dir(_File, _AppMeta, directory) -> @@ -101,8 +101,8 @@ discover_dir(File, AppMeta, file) -> is_valid_release(File, AppMeta). -spec is_valid_release(file:name(), - [rcl_app_info:t()]) -> - {ok, rcl_release:t()} + [rlx_app_info:t()]) -> + {ok, rlx_release:t()} | {error, Reason::term()} | {noresult, false}. is_valid_release(File, AppMeta) -> @@ -118,20 +118,20 @@ resolve_release(RelFile, AppMeta) -> {ok, [{release, {RelName, RelVsn}, {erts, ErtsVsn}, Apps}]} -> - build_release(RelName, RelVsn, ErtsVsn, Apps, AppMeta); + build_release(RelFile, RelName, RelVsn, ErtsVsn, Apps, AppMeta); {ok, InvalidRelease} -> - ?RCL_ERROR({invalid_release_information, InvalidRelease}); + ?RLX_ERROR({invalid_release_information, InvalidRelease}); {error, Reason} -> - ?RCL_ERROR({unable_to_read, RelFile, Reason}) + ?RLX_ERROR({unable_to_read, RelFile, Reason}) end. -build_release(RelName, RelVsn, ErtsVsn, Apps, AppMeta) -> - Release = rcl_release:erts(rcl_release:new(RelName, RelVsn), +build_release(RelFile, RelName, RelVsn, ErtsVsn, Apps, AppMeta) -> + Release = rlx_release:erts(rlx_release:new(RelName, RelVsn, RelFile), ErtsVsn), resolve_apps(Apps, AppMeta, Release, []). resolve_apps([], _AppMeta, Release, Acc) -> - {ok, rcl_release:application_details(Release, Acc)}; + {ok, rlx_release:application_details(Release, Acc)}; resolve_apps([AppInfo | Apps], AppMeta, Release, Acc) -> AppName = erlang:element(1, AppInfo), AppVsn = ec_semver:parse(erlang:element(2, AppInfo)), @@ -144,13 +144,13 @@ resolve_apps([AppInfo | Apps], AppMeta, Release, Acc) -> find_app(AppName, AppVsn, AppMeta) -> case ec_lists:find(fun(App) -> - NAppName = rcl_app_info:name(App), - NAppVsn = rcl_app_info:vsn(App), + NAppName = rlx_app_info:name(App), + NAppVsn = rlx_app_info:vsn(App), AppName == NAppName andalso AppVsn == NAppVsn end, AppMeta) of {ok, Head} -> Head; error -> - ?RCL_ERROR({could_not_find, {AppName, AppVsn}}) + ?RLX_ERROR({could_not_find, {AppName, AppVsn}}) end. diff --git a/src/rcl_release.erl b/src/rlx_release.erl index 97465d0..68193fa 100644 --- a/src/rcl_release.erl +++ b/src/rlx_release.erl @@ -20,9 +20,12 @@ %%% %%% @doc This module represents a release and its metadata and is used to %%% manipulate the release metadata. --module(rcl_release). +-module(rlx_release). -export([new/2, + new/3, + relfile/1, + relfile/2, erts/2, erts/1, goals/2, @@ -35,6 +38,7 @@ application_details/2, realized/1, metadata/1, + canonical_name/1, format/1, format/2, format_error/1]). @@ -48,16 +52,17 @@ application_spec/0, application_goal/0]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). -record(release_t, {name :: atom(), vsn :: ec_semver:any_version(), erts :: ec_semver:any_version(), - goals = [] :: [rcl_depsolver:constraint()], + goals = [] :: [rlx_depsolver:constraint()], realized = false :: boolean(), annotations = undefined :: annotations(), applications = [] :: [application_spec()], - app_detail = [] :: [rcl_app_info:t()]}). + relfile :: undefined | string(), + app_detail = [] :: [rlx_app_info:t()]}). %%============================================================================ %% types @@ -73,7 +78,7 @@ {app_name(), app_vsn(), app_type() | incl_apps()} | {app_name(), app_vsn(), app_type(), incl_apps()}. --type application_constraint() :: rcl_depsolver:raw_constraint() | string() | binary(). +-type application_constraint() :: rlx_depsolver:raw_constraint() | string() | binary(). -type application_goal() :: application_constraint() | {application_constraint(), app_type() | incl_apps()} | {application_constraint(), app_type(), incl_apps() | none}. @@ -87,11 +92,25 @@ %%============================================================================ %% API %%============================================================================ --spec new(atom(), string()) -> t(). -new(ReleaseName, ReleaseVsn) -> +-spec new(atom(), string(), undefined | file:name()) -> t(). +new(ReleaseName, ReleaseVsn, Relfile) -> #release_t{name=to_atom(ReleaseName), vsn=ReleaseVsn, + relfile = Relfile, annotations=ec_dictionary:new(ec_dict)}. +-spec new(atom(), string()) -> t(). +new(ReleaseName, ReleaseVsn) -> + new(ReleaseName, ReleaseVsn, undefined). + + +-spec relfile(t()) -> file:name() | undefined. +relfile(#release_t{relfile=Relfile}) -> + Relfile. + +-spec relfile(t(), file:name()) -> t(). +relfile(Release, Relfile) -> + Release#release_t{relfile=Relfile}. + -spec name(t()) -> atom(). name(#release_t{name=Name}) -> Name. @@ -108,7 +127,7 @@ erts(Release, Vsn) -> erts(#release_t{erts=Vsn}) -> Vsn. --spec goals(t(), [application_goal()]) -> {ok, t()} | relcool:error(). +-spec goals(t(), [application_goal()]) -> {ok, t()} | relx:error(). goals(Release, Goals0) -> lists:foldl(fun parse_goal0/2, {ok, Release}, Goals0). @@ -117,11 +136,11 @@ goals(Release, Goals0) -> goals(#release_t{goals=Goals}) -> Goals. --spec realize(t(), [{app_name(), app_vsn()}], [rcl_app_info:t()]) -> - {ok, t()} | relcool:error(). +-spec realize(t(), [{app_name(), app_vsn()}], [rlx_app_info:t()]) -> + {ok, t()} | relx:error(). realize(Rel, Pkgs0, World0) -> World1 = subset_world(Pkgs0, World0), - case rcl_topo:sort_apps(World1) of + case rlx_topo:sort_apps(World1) of {ok, Pkgs1} -> process_specs(realize_erts(Rel), Pkgs1); Error={error, _} -> @@ -134,16 +153,16 @@ realize(Rel, Pkgs0, World0) -> applications(#release_t{applications=Apps}) -> Apps. -%% @doc this gives the rcl_app_info objects representing the applications in +%% @doc this gives the rlx_app_info objects representing the applications in %% this release. These should only be populated by the 'realize' call in this %% module or by reading an existing rel file. --spec application_details(t()) -> [rcl_app_info:t()]. +-spec application_details(t()) -> [rlx_app_info:t()]. application_details(#release_t{app_detail=App}) -> App. %% @doc this is only expected to be called by a process building a new release %% from an existing rel file. --spec application_details(t(), [rcl_app_info:t()]) -> t(). +-spec application_details(t(), [rlx_app_info:t()]) -> t(). application_details(Release, AppDetail) -> Release#release_t{app_detail=AppDetail}. @@ -159,9 +178,15 @@ metadata(#release_t{name=Name, vsn=Vsn, erts=ErtsVsn, applications=Apps, {ok, {release, {erlang:atom_to_list(Name), Vsn}, {erts, ErtsVsn}, Apps}}; false -> - ?RCL_ERROR({not_realized, Name, Vsn}) + ?RLX_ERROR({not_realized, Name, Vsn}) end. +%% @doc produce the canonical name (<name>-<vsn>) for this release +-spec canonical_name(t()) -> string(). +canonical_name(#release_t{name=Name, vsn=Vsn}) -> + erlang:binary_to_list(erlang:iolist_to_binary([erlang:atom_to_list(Name), "-", + Vsn])). + -spec format(t()) -> iolist(). format(Release) -> format(0, Release). @@ -169,31 +194,32 @@ format(Release) -> -spec format(non_neg_integer(), t()) -> iolist(). format(Indent, #release_t{name=Name, vsn=Vsn, erts=ErtsVsn, realized=Realized, goals = Goals, applications=Apps}) -> - BaseIndent = rcl_util:indent(Indent), - [BaseIndent, "release: ", rcl_util:to_string(Name), "-", Vsn, "\n", - rcl_util:indent(Indent + 1), " erts-", ErtsVsn, + BaseIndent = rlx_util:indent(Indent), + [BaseIndent, "release: ", rlx_util:to_string(Name), "-", Vsn, "\n", + rlx_util:indent(Indent + 1), " erts-", ErtsVsn, ", realized = ", erlang:atom_to_list(Realized), "\n", BaseIndent, "goals: \n", - [[rcl_util:indent(Indent + 1), format_goal(Goal), ",\n"] || Goal <- Goals], + [[rlx_util:indent(Indent + 1), format_goal(Goal), ",\n"] || Goal <- Goals], case Realized of true -> [BaseIndent, "applications: \n", - [[rcl_util:indent(Indent + 1), io_lib:format("~p", [App]), ",\n"] || + [[rlx_util:indent(Indent + 1), io_lib:format("~p", [App]), ",\n"] || App <- Apps]]; false -> [] end]. + -spec format_goal(application_goal()) -> iolist(). format_goal({Constraint, AppType}) -> - io_lib:format("~p", [{rcl_depsolver:format_constraint(Constraint), AppType}]); + io_lib:format("~p", [{rlx_depsolver:format_constraint(Constraint), AppType}]); format_goal({Constraint, AppType, AppInc}) -> - io_lib:format("~p", [{rcl_depsolver:format_constraint(Constraint), AppType, AppInc}]); + io_lib:format("~p", [{rlx_depsolver:format_constraint(Constraint), AppType, AppInc}]); format_goal(Constraint) -> - rcl_depsolver:format_constraint(Constraint). + rlx_depsolver:format_constraint(Constraint). -spec format_error(Reason::term()) -> iolist(). format_error({topo_error, E}) -> - rcl_topo:format_error(E); + rlx_topo:format_error(E); format_error({failed_to_parse, Con}) -> io_lib:format("Failed to parse constraint ~p", [Con]); format_error({invalid_constraint, _, Con}) -> @@ -211,30 +237,30 @@ realize_erts(Rel=#release_t{erts=undefined}) -> realize_erts(Rel) -> Rel. --spec process_specs(t(), [rcl_app_info:t()]) -> +-spec process_specs(t(), [rlx_app_info:t()]) -> {ok, t()}. process_specs(Rel=#release_t{annotations=Annots, goals=Goals}, World) -> - ActiveApps = lists:flatten([rcl_app_info:active_deps(El) || El <- World] ++ + ActiveApps = lists:flatten([rlx_app_info:active_deps(El) || El <- World] ++ [case get_app_name(Goal) of {error, _} -> []; G -> G end || Goal <- Goals]), - LibraryApps = lists:flatten([rcl_app_info:library_deps(El) || El <- World]), + LibraryApps = lists:flatten([rlx_app_info:library_deps(El) || El <- World]), Specs = [create_app_spec(Annots, App, ActiveApps, LibraryApps) || App <- World], {ok, Rel#release_t{annotations=Annots, applications=Specs, app_detail=World, realized=true}}. --spec create_app_spec(annotations(), rcl_app_info:t(), [app_name()], +-spec create_app_spec(annotations(), rlx_app_info:t(), [app_name()], [app_name()]) -> application_spec(). create_app_spec(Annots, App, ActiveApps, LibraryApps) -> %% If the app only exists as a dependency in a library app then it should %% get the 'load' annotation unless the release spec has provided something %% else - AppName = rcl_app_info:name(App), + AppName = rlx_app_info:name(App), TypeAnnot = case (lists:member(AppName, LibraryApps) and (not lists:member(AppName, ActiveApps))) of @@ -255,7 +281,7 @@ create_app_spec(Annots, App, ActiveApps, LibraryApps) -> throw:not_found -> {TypeAnnot, none} end, - Vsn = rcl_app_info:vsn_as_string(App), + Vsn = rlx_app_info:vsn_as_string(App), case BaseAnnots of {none, none} -> {AppName, Vsn}; @@ -267,16 +293,16 @@ create_app_spec(Annots, App, ActiveApps, LibraryApps) -> {AppName, Vsn, Type, Incld1} end. --spec subset_world([{app_name(), app_vsn()}], [rcl_app_info:t()]) -> [rcl_app_info:t()]. +-spec subset_world([{app_name(), app_vsn()}], [rlx_app_info:t()]) -> [rlx_app_info:t()]. subset_world(Pkgs, World) -> [get_app_info(Pkg, World) || Pkg <- Pkgs]. --spec get_app_info({app_name(), app_vsn()}, [rcl_app_info:t()]) -> rcl_app_info:t(). +-spec get_app_info({app_name(), app_vsn()}, [rlx_app_info:t()]) -> rlx_app_info:t(). get_app_info({PkgName, PkgVsn}, World) -> {ok, WorldEl} = ec_lists:find(fun(El) -> - rcl_app_info:name(El) =:= PkgName andalso - rcl_app_info:vsn(El) =:= PkgVsn + rlx_app_info:name(El) =:= PkgName andalso + rlx_app_info:vsn(El) =:= PkgVsn end, World), WorldEl. @@ -315,7 +341,7 @@ parse_goal0(Constraint0, {ok, Release}) -> parse_goal0(_, E = {error, _}) -> E; parse_goal0(Constraint, _) -> - ?RCL_ERROR({invalid_constraint, 1, Constraint}). + ?RLX_ERROR({invalid_constraint, 1, Constraint}). parse_goal1(Release = #release_t{annotations=Annots, goals=Goals}, Constraint, NewAnnots) -> @@ -329,12 +355,12 @@ parse_goal1(Release = #release_t{annotations=Annots, goals=Goals}, end. -spec parse_constraint(application_constraint()) -> - rcl_depsolver:constraint() | relcool:error(). + rlx_depsolver:constraint() | relx:error(). parse_constraint(Constraint0) when erlang:is_list(Constraint0); erlang:is_binary(Constraint0) -> - case rcl_goal:parse(Constraint0) of + case rlx_goal:parse(Constraint0) of {fail, _} -> - ?RCL_ERROR({failed_to_parse, Constraint0}); + ?RLX_ERROR({failed_to_parse, Constraint0}); {ok, Constraint1} -> {ok, Constraint1} end; @@ -342,17 +368,17 @@ parse_constraint(Constraint0) when erlang:is_tuple(Constraint0); erlang:is_atom(Constraint0) -> Constraint1 = parse_version(Constraint0), - case rcl_depsolver:is_valid_constraint(Constraint1) of + case rlx_depsolver:is_valid_constraint(Constraint1) of false -> - ?RCL_ERROR({invalid_constraint, 2, Constraint0}); + ?RLX_ERROR({invalid_constraint, 2, Constraint0}); true -> {ok, Constraint1} end; parse_constraint(Constraint) -> - ?RCL_ERROR({invalid_constraint, 3, Constraint}). + ?RLX_ERROR({invalid_constraint, 3, Constraint}). --spec get_app_name(rcl_depsolver:raw_constraint()) -> - AppName::atom() | relcool:error(). +-spec get_app_name(rlx_depsolver:raw_constraint()) -> + AppName::atom() | relx:error(). get_app_name(AppName) when erlang:is_atom(AppName) -> AppName; get_app_name({AppName, _}) when erlang:is_atom(AppName) -> @@ -362,22 +388,22 @@ get_app_name({AppName, _, _}) when erlang:is_atom(AppName) -> get_app_name({AppName, _, _, _}) when erlang:is_atom(AppName) -> AppName; get_app_name(V) -> - ?RCL_ERROR({invalid_constraint, 4, V}). + ?RLX_ERROR({invalid_constraint, 4, V}). --spec parse_version(rcl_depsolver:raw_constraint()) -> - rcl_depsolver:constraint(). +-spec parse_version(rlx_depsolver:raw_constraint()) -> + rlx_depsolver:constraint(). parse_version({AppName, Version}) when erlang:is_binary(Version); erlang:is_list(Version) -> - {AppName, rcl_depsolver:parse_version(Version)}; + {AppName, rlx_depsolver:parse_version(Version)}; parse_version({AppName, Version, Constraint}) when erlang:is_binary(Version); erlang:is_list(Version) -> - {AppName, rcl_depsolver:parse_version(Version), Constraint}; + {AppName, rlx_depsolver:parse_version(Version), Constraint}; parse_version({AppName, Version, Constraint0, Constraint1}) when erlang:is_binary(Version); erlang:is_list(Version) -> - {AppName, rcl_depsolver:parse_version(Version), Constraint1, Constraint0}; + {AppName, rlx_depsolver:parse_version(Version), Constraint1, Constraint0}; parse_version(Constraint) -> Constraint. diff --git a/src/rcl_state.erl b/src/rlx_state.erl index 4b21bbe..9b0811f 100644 --- a/src/rcl_state.erl +++ b/src/rlx_state.erl @@ -18,13 +18,14 @@ %%% @author Eric Merritt <[email protected]> %%% @copyright (C) 2012 Erlware, LLC. %%% -%%% @doc Provides state management services for the relcool tool. Generally, +%%% @doc Provides state management services for the relx tool. Generally, %%% those things that are fixed have a direct api. Those things that are mutable %%% have a more mutable api. --module(rcl_state). +-module(rlx_state). -export([new/2, log/1, + action/1, output_dir/1, lib_dirs/1, overrides/1, @@ -40,14 +41,16 @@ sys_config/2, root_dir/1, root_dir/2, - add_release/2, - get_release/3, - update_release/2, - releases/1, - discovered_releases/1, - discovered_releases/2, - default_release/1, - default_release/3, + add_configured_release/2, + get_configured_release/3, + configured_releases/1, + realized_releases/1, + realized_releases/2, + add_realized_release/2, + get_realized_release/3, + update_realized_release/2, + default_configured_release/1, + default_configured_release/3, available_apps/1, available_apps/2, get/2, @@ -55,6 +58,7 @@ put/3, caller/1, caller/2, + upfrom/1, format/1, format/2]). @@ -63,22 +67,23 @@ releases/0, cmd_args/0]). --record(state_t, {log :: rcl_log:t(), +-record(state_t, {log :: rlx_log:t(), root_dir :: file:name(), caller :: caller(), action :: atom(), output_dir :: file:name(), lib_dirs=[] :: [file:name()], config_file=[] :: file:filename() | undefined, - goals=[] :: [rcl_depsolver:constraint()], - providers = [] :: [rcl_provider:t()], - available_apps = [] :: [rcl_app_info:t()], - default_release :: {rcl_release:name(), rcl_release:vsn()}, + goals=[] :: [rlx_depsolver:constraint()], + providers = [] :: [rlx_provider:t()], + available_apps = [] :: [rlx_app_info:t()], + default_configured_release :: {rlx_release:name(), rlx_release:vsn()}, sys_config :: file:filename() | undefined, overrides :: [{AppName::atom(), Directory::file:filename()}], skip_apps = [] :: [AppName::atom()], - releases :: releases(), - discovered_releases :: releases(), + configured_releases :: releases(), + realized_releases :: releases(), + upfrom :: string() | binary() | undefined, config_values :: ec_dictionary:dictionary(Key::atom(), Value::term())}). @@ -86,9 +91,9 @@ %% types %%============================================================================ --type releases() :: ec_dictionary:dictionary({rcl_release:name(), - rcl_release:vsn()}, - rcl_release:t()). +-type releases() :: ec_dictionary:dictionary({rlx_release:name(), + rlx_release:vsn()}, + rlx_release:t()). -type cmd_args() :: proplists:proplist(). -type caller() :: command_line | api. @@ -104,24 +109,31 @@ new(PropList, Target) erlang:is_atom(Target) -> {ok, Root} = file:get_cwd(), State0 = - #state_t{log = proplists:get_value(log, PropList, rcl_log:new(error)), + #state_t{log = proplists:get_value(log, PropList, rlx_log:new(error)), output_dir=proplists:get_value(output_dir, PropList, ""), lib_dirs=[to_binary(Dir) || Dir <- proplists:get_value(lib_dirs, PropList, [])], config_file=proplists:get_value(config, PropList, undefined), action = Target, + caller = proplists:get_value(caller, PropList, api), goals=proplists:get_value(goals, PropList, []), providers = [], - releases=ec_dictionary:new(ec_dict), - discovered_releases=ec_dictionary:new(ec_dict), + configured_releases=ec_dictionary:new(ec_dict), + realized_releases=ec_dictionary:new(ec_dict), config_values=ec_dictionary:new(ec_dict), overrides = proplists:get_value(overrides, PropList, []), root_dir = proplists:get_value(root_dir, PropList, Root), - default_release={proplists:get_value(relname, PropList, undefined), + upfrom = proplists:get_value(upfrom, PropList, undefined), + default_configured_release={proplists:get_value(relname, PropList, undefined), proplists:get_value(relvsn, PropList, undefined)}}, - rcl_state:put(create_logic_providers(State0), + rlx_state:put(create_logic_providers(State0), disable_default_libs, proplists:get_value(disable_default_libs, PropList, false)). +%% @doc the action targeted for this system +-spec action(t()) -> atom(). +action(#state_t{action=Action}) -> + Action. + %% @doc the application overrides for the system -spec overrides(t()) -> [{AppName::atom(), Directory::file:filename()}]. overrides(#state_t{overrides=Overrides}) -> @@ -143,7 +155,7 @@ skip_apps(State, SkipApps) -> State#state_t{skip_apps=SkipApps}. %% @doc get the current log state for the system --spec log(t()) -> rcl_log:t(). +-spec log(t()) -> rlx_log:t(). log(#state_t{log=LogState}) -> LogState. @@ -155,7 +167,7 @@ output_dir(#state_t{output_dir=OutDir}) -> lib_dirs(#state_t{lib_dirs=LibDir}) -> LibDir. --spec goals(t()) -> [rcl_depsolver:constraint()]. +-spec goals(t()) -> [rlx_depsolver:constraint()]. goals(#state_t{goals=TS}) -> TS. @@ -167,7 +179,7 @@ config_file(#state_t{config_file=ConfigFiles}) -> config_file(State, ConfigFiles) -> State#state_t{config_file=ConfigFiles}. --spec providers(t()) -> [rcl_provider:t()]. +-spec providers(t()) -> [rlx_provider:t()]. providers(#state_t{providers=Providers}) -> Providers. @@ -187,54 +199,65 @@ root_dir(#state_t{root_dir=RootDir}) -> root_dir(State, RootDir) -> State#state_t{root_dir=RootDir}. --spec providers(t(), [rcl_provider:t()]) -> t(). +-spec providers(t(), [rlx_provider:t()]) -> t(). providers(M, NewProviders) -> M#state_t{providers=NewProviders}. --spec add_release(t(), rcl_release:t()) -> t(). -add_release(M=#state_t{releases=Releases}, Release) -> - M#state_t{releases=ec_dictionary:add({rcl_release:name(Release), - rcl_release:vsn(Release)}, - Release, - Releases)}. - --spec update_release(t(), rcl_release:t()) -> t(). -update_release(M=#state_t{releases=Releases}, Release) -> - M#state_t{releases=ec_dictionary:add({rcl_release:name(Release), - rcl_release:vsn(Release)}, +-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), + rlx_release:vsn(Release)}, Release, Releases)}. --spec get_release(t(), rcl_release:name(), rcl_release:vsn()) -> rcl_release:t(). -get_release(#state_t{releases=Releases}, Name, Vsn) -> +-spec get_configured_release(t(), rlx_release:name(), rlx_release:vsn()) -> rlx_release:t(). +get_configured_release(#state_t{configured_releases=Releases}, Name, Vsn) -> ec_dictionary:get({Name, Vsn}, Releases). --spec releases(t()) -> releases(). -releases(#state_t{releases=Releases}) -> +-spec configured_releases(t()) -> releases(). +configured_releases(#state_t{configured_releases=Releases}) -> Releases. --spec discovered_releases(t()) -> releases(). -discovered_releases(#state_t{discovered_releases=Releases}) -> +-spec realized_releases(t()) -> releases(). +realized_releases(#state_t{realized_releases=Releases}) -> Releases. --spec discovered_releases(t(), releases()) -> t(). -discovered_releases(State, Releases) -> - State#state_t{discovered_releases=Releases}. +-spec realized_releases(t(), releases()) -> t(). +realized_releases(State, Releases) -> + State#state_t{realized_releases=Releases}. --spec default_release(t()) -> - {rcl_release:name() | undefined, rcl_release:vsn() | undefined}. -default_release(#state_t{default_release=Def}) -> +-spec add_realized_release(t(), rlx_release:t()) -> t(). +add_realized_release(State = #state_t{realized_releases=Releases}, Release) -> + NewReleases = ec_dictionary:add({rlx_release:name(Release), rlx_release:vsn(Release)}, + Release, Releases), + State#state_t{realized_releases=NewReleases}. + +-spec get_realized_release(t(), rlx_release:name(), rlx_release:vsn()) -> rlx_release:t(). +get_realized_release(#state_t{realized_releases=Releases}, Name, Vsn) -> + ec_dictionary:get({Name, Vsn}, Releases). + +-spec update_realized_release(t(), rlx_release:t()) -> + t(). +update_realized_release(M=#state_t{realized_releases=Releases}, Release) -> + M#state_t{realized_releases=ec_dictionary:add({rlx_release:name(Release), + rlx_release:vsn(Release)}, + Release, + Releases)}. + +-spec default_configured_release(t()) -> + {rlx_release:name() | undefined, rlx_release:vsn() | undefined}. +default_configured_release(#state_t{default_configured_release=Def}) -> Def. --spec default_release(t(), rcl_release:name(), rcl_release:vsn()) -> t(). -default_release(M, Name, Vsn) -> - M#state_t{default_release={Name, Vsn}}. +-spec default_configured_release(t(), rlx_release:name(), rlx_release:vsn()) -> t(). +default_configured_release(M, Name, Vsn) -> + M#state_t{default_configured_release={Name, Vsn}}. --spec available_apps(t()) -> [rcl_app_info:t()]. +-spec available_apps(t()) -> [rlx_app_info:t()]. available_apps(#state_t{available_apps=Apps}) -> Apps. --spec available_apps(t(), [rcl_app_info:t()]) -> t(). +-spec available_apps(t(), [rlx_app_info:t()]) -> t(). available_apps(M, NewApps) -> M#state_t{available_apps=NewApps}. @@ -266,6 +289,10 @@ caller(#state_t{caller=Caller}) -> caller(S, Caller) -> S#state_t{caller=Caller}. +-spec upfrom(t()) -> string() | binary() | undefined. +upfrom(#state_t{upfrom=UpFrom}) -> + UpFrom. + -spec format(t()) -> iolist(). format(Mod) -> format(Mod, 0). @@ -277,19 +304,19 @@ format(#state_t{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, providers=Providers}, Indent) -> Values1 = ec_dictionary:to_list(Values0), - [rcl_util:indent(Indent), + [rlx_util:indent(Indent), <<"state(">>, erlang:atom_to_list(Caller), <<"):\n">>, - rcl_util:indent(Indent + 1), <<"log: ">>, rcl_log:format(LogState), <<",\n">>, - rcl_util:indent(Indent + 1), "config file: ", rcl_util:optional_to_string(ConfigFile), "\n", - rcl_util:indent(Indent + 1), "goals: \n", - [[rcl_util:indent(Indent + 2), rcl_depsolver:format_constraint(Goal), ",\n"] || Goal <- Goals], - rcl_util:indent(Indent + 1), "output_dir: ", OutDir, "\n", - rcl_util:indent(Indent + 1), "lib_dirs: \n", - [[rcl_util:indent(Indent + 2), LibDir, ",\n"] || LibDir <- LibDirs], - rcl_util:indent(Indent + 1), "providers: \n", - [[rcl_util:indent(Indent + 2), rcl_provider:format(Provider), ",\n"] || Provider <- Providers], - rcl_util:indent(Indent + 1), "provider config values: \n", - [[rcl_util:indent(Indent + 2), io_lib:format("~p", [Value]), ",\n"] || Value <- Values1]]. + rlx_util:indent(Indent + 1), <<"log: ">>, rlx_log:format(LogState), <<",\n">>, + rlx_util:indent(Indent + 1), "config file: ", rlx_util:optional_to_string(ConfigFile), "\n", + rlx_util:indent(Indent + 1), "goals: \n", + [[rlx_util:indent(Indent + 2), rlx_depsolver:format_constraint(Goal), ",\n"] || Goal <- Goals], + rlx_util:indent(Indent + 1), "output_dir: ", OutDir, "\n", + rlx_util:indent(Indent + 1), "lib_dirs: \n", + [[rlx_util:indent(Indent + 2), LibDir, ",\n"] || LibDir <- LibDirs], + rlx_util:indent(Indent + 1), "providers: \n", + [[rlx_util:indent(Indent + 2), rlx_provider:format(Provider), ",\n"] || Provider <- Providers], + rlx_util:indent(Indent + 1), "provider config values: \n", + [[rlx_util:indent(Indent + 2), io_lib:format("~p", [Value]), ",\n"] || Value <- Values1]]. %%%=================================================================== %%% Internal Functions @@ -297,11 +324,11 @@ format(#state_t{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, -spec create_logic_providers(t()) -> t(). create_logic_providers(State0) -> - {ConfigProvider, {ok, State1}} = rcl_provider:new(rcl_prv_config, State0), - {DiscoveryProvider, {ok, State2}} = rcl_provider:new(rcl_prv_discover, State1), - {ReleaseProvider, {ok, State3}} = rcl_provider:new(rcl_prv_release, State2), - {OverlayProvider, {ok, State4}} = rcl_provider:new(rcl_prv_overlay, State3), - {AssemblerProvider, {ok, State5}} = rcl_provider:new(rcl_prv_assembler, State4), + {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), + {AssemblerProvider, {ok, State5}} = rlx_provider:new(rlx_prv_assembler, State4), State5#state_t{providers=[ConfigProvider, DiscoveryProvider, ReleaseProvider, OverlayProvider, AssemblerProvider]}. @@ -320,7 +347,7 @@ to_binary(Dir) -include_lib("eunit/include/eunit.hrl"). new_test() -> - LogState = rcl_log:new(error), + LogState = rlx_log:new(error), RCLState = new([{log, LogState}], release), ?assertMatch(LogState, log(RCLState)). diff --git a/src/rcl_topo.erl b/src/rlx_topo.erl index 462b7c5..11928c1 100644 --- a/src/rcl_topo.erl +++ b/src/rlx_topo.erl @@ -20,7 +20,7 @@ %%% @doc %%% This is a pretty simple topological sort for erlang. It was %%% originally written for ermake by Joe Armstrong back in '98. It -%%% has been pretty heavily modified by Eric Merritt since '06 and modified again for Relcool. +%%% has been pretty heavily modified by Eric Merritt since '06 and modified again for Relx. %%% %%% A partial order on the set S is a set of pairs {Xi,Xj} such that %%% some relation between Xi and Xj is obeyed. @@ -30,12 +30,12 @@ %%% order i < j %%% @end %%%------------------------------------------------------------------- --module(rcl_topo). +-module(rlx_topo). -export([sort_apps/1, format_error/1]). --include_lib("relcool/include/relcool.hrl"). +-include_lib("relx/include/relx.hrl"). %%==================================================================== %% Types @@ -53,9 +53,9 @@ %% applications. This implies that you have already done the %% constraint solve before you pass the list of apps here to be %% sorted. --spec sort_apps([rcl_app_info:t()]) -> - {ok, [rcl_app_info:t()]} | - relcool:error(). +-spec sort_apps([rlx_app_info:t()]) -> + {ok, [rlx_app_info:t()]} | + relx:error(). sort_apps(Apps) -> Pairs = apps_to_pairs(Apps), case sort(Pairs) of @@ -71,9 +71,9 @@ format_error({cycle, Pairs}) -> "before we can continue:\n", case Pairs of [{P1, P2}] -> - [rcl_util:indent(1), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1)]; + [rlx_util:indent(1), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1)]; [{P1, P2} | Rest] -> - [rcl_util:indent(1), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1), + [rlx_util:indent(1), erlang:atom_to_list(P2), "->", erlang:atom_to_list(P1), [["-> ", erlang:atom_to_list(PP2), " -> ", erlang:atom_to_list(PP1)] || {PP1, PP2} <- Rest]]; [] -> [] @@ -83,43 +83,43 @@ format_error({cycle, Pairs}) -> %% Internal Functions %%==================================================================== %% @doc Do a topological sort on the list of pairs. --spec sort([pair()]) -> {ok, [atom()]} | relcool:error(). +-spec sort([pair()]) -> {ok, [atom()]} | relx:error(). sort(Pairs) -> iterate(Pairs, [], all(Pairs)). --spec names_to_apps([atom()], [rcl_app_info:t()]) -> [rcl_app_info:t()]. +-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]. --spec find_app_by_name(atom(), [rcl_app_info:t()]) -> rcl_app_info:t(). +-spec find_app_by_name(atom(), [rlx_app_info:t()]) -> rlx_app_info:t(). find_app_by_name(Name, Apps) -> {ok, App1} = ec_lists:find(fun(App) -> - rcl_app_info:name(App) =:= Name + rlx_app_info:name(App) =:= Name end, Apps), App1. --spec apps_to_pairs([rcl_app_info:t()]) -> [pair()]. +-spec apps_to_pairs([rlx_app_info:t()]) -> [pair()]. apps_to_pairs(Apps) -> lists:flatten([app_to_pairs(App) || App <- Apps]). --spec app_to_pairs(rcl_app_info:t()) -> [pair()]. +-spec app_to_pairs(rlx_app_info:t()) -> [pair()]. app_to_pairs(App) -> - [{DepApp, rcl_app_info:name(App)} || + [{DepApp, rlx_app_info:name(App)} || DepApp <- - rcl_app_info:active_deps(App) ++ - rcl_app_info:library_deps(App)]. + rlx_app_info:active_deps(App) ++ + rlx_app_info:library_deps(App)]. %% @doc Iterate over the system. @private -spec iterate([pair()], [name()], [name()]) -> - {ok, [name()]} | relcool:error(). + {ok, [name()]} | relx:error(). iterate([], L, All) -> {ok, remove_duplicates(L ++ subtract(All, L))}; iterate(Pairs, L, All) -> case subtract(lhs(Pairs), rhs(Pairs)) of [] -> - ?RCL_ERROR({cycle, Pairs}); + ?RLX_ERROR({cycle, Pairs}); Lhs -> iterate(remove_pairs(Lhs, Pairs), L ++ Lhs, All) end. @@ -193,8 +193,8 @@ topo_pairs_cycle_test() -> sort(Pairs)). topo_apps_cycle_test() -> - {ok, App1} = rcl_app_info:new(app1, "0.1", "/no-dir", [app2], [stdlib]), - {ok, App2} = rcl_app_info:new(app2, "0.1", "/no-dir", [app1], []), + {ok, App1} = rlx_app_info:new(app1, "0.1", "/no-dir", [app2], [stdlib]), + {ok, App2} = rlx_app_info:new(app2, "0.1", "/no-dir", [app1], []), Apps = [App1, App2], ?assertMatch({error, {_, {cycle, [{app2,app1},{app1,app2}]}}}, sort_apps(Apps)). @@ -202,16 +202,16 @@ topo_apps_cycle_test() -> topo_apps_good_test() -> Apps = [App || {ok, App} <- - [rcl_app_info:new(app1, "0.1", "/no-dir", [app2, zapp1], [stdlib, kernel]), - rcl_app_info:new(app2, "0.1", "/no-dir", [app3], []), - rcl_app_info:new(app3, "0.1", "/no-dir", [kernel], []), - rcl_app_info:new(zapp1, "0.1", "/no-dir", [app2,app3,zapp2], []), - rcl_app_info:new(stdlib, "0.1", "/no-dir", [], []), - rcl_app_info:new(kernel, "0.1", "/no-dir", [], []), - rcl_app_info:new(zapp2, "0.1", "/no-dir", [], [])]], + [rlx_app_info:new(app1, "0.1", "/no-dir", [app2, zapp1], [stdlib, kernel]), + rlx_app_info:new(app2, "0.1", "/no-dir", [app3], []), + rlx_app_info:new(app3, "0.1", "/no-dir", [kernel], []), + rlx_app_info:new(zapp1, "0.1", "/no-dir", [app2,app3,zapp2], []), + rlx_app_info:new(stdlib, "0.1", "/no-dir", [], []), + rlx_app_info:new(kernel, "0.1", "/no-dir", [], []), + rlx_app_info:new(zapp2, "0.1", "/no-dir", [], [])]], {ok, Sorted} = sort_apps(Apps), ?assertMatch([stdlib, kernel, zapp2, app3, app2, zapp1, app1], - [rcl_app_info:name(App) || App <- Sorted]). + [rlx_app_info:name(App) || App <- Sorted]). -endif. diff --git a/src/rcl_util.erl b/src/rlx_util.erl index 61e1392..c2b2081 100644 --- a/src/rcl_util.erl +++ b/src/rlx_util.erl @@ -19,7 +19,7 @@ %%% @copyright (C) 2012 Erlware, LLC. %%% %%% @doc Trivial utility file to help handle common tasks --module(rcl_util). +-module(rlx_util). -export([mkdir_p/1, to_binary/1, @@ -58,17 +58,20 @@ to_binary(String) when erlang:is_list(String) -> erlang:iolist_to_binary(String); to_binary(Bin) when erlang:is_binary(Bin) -> Bin. + +to_string(Binary) when erlang:is_binary(Binary) -> + erlang:binary_to_list(Binary); to_string(Atom) when erlang:is_atom(Atom) -> erlang:atom_to_list(Atom); to_string(Else) when erlang:is_list(Else) -> Else. -%% @doc get the reason for a particular relcool error --spec error_reason(relcool:error()) -> any(). +%% @doc get the reason for a particular relx error +-spec error_reason(relx:error()) -> any(). error_reason({error, {_, Reason}}) -> Reason. -%% @doc check to see if the value is a relcool error --spec is_error(relcool:error() | any()) -> boolean(). +%% @doc check to see if the value is a relx error +-spec is_error(relx:error() | any()) -> boolean(). is_error({error, _}) -> true; is_error(_) -> |