From 4505d4f1ed6a7ba0d390f262bdeee9c35bc5d7a4 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 10 Sep 2012 08:23:12 -0500 Subject: add config validation support to the system --- rebar.config | 2 ++ src/rcl_cmd_args.erl | 31 +++++++++++++++++++++++++++++-- src/rcl_state.erl | 20 +++++++++++++++----- src/relcool.erl | 3 ++- test/rclt_command_SUITE.erl | 11 +++++++++-- 5 files changed, 57 insertions(+), 10 deletions(-) diff --git a/rebar.config b/rebar.config index 289db92..190f30a 100644 --- a/rebar.config +++ b/rebar.config @@ -12,4 +12,6 @@ {escript_incl_apps, [getopt, depsolver, erlware_commons]}. +{first_files, [rcl_provider]}. + {erl_opts, [debug_info, warnings_as_errors, inline]}. diff --git a/src/rcl_cmd_args.erl b/src/rcl_cmd_args.erl index 454e762..f8918c2 100644 --- a/src/rcl_cmd_args.erl +++ b/src/rcl_cmd_args.erl @@ -45,12 +45,39 @@ args2state({ok, {Opts, Targets}}) -> Error = {error, _} -> Error; {ok, CommandLineConfig} -> - {ok, {rcl_state:new(CommandLineConfig), Targets}} + case validate_configs(Targets) of + Error = {error, _} -> + Error; + {ok, Configs} -> + {ok, {rcl_state:new(CommandLineConfig, Configs), Configs}} + end end. %%%=================================================================== %%% Internal Functions %%%=================================================================== +-spec validate_configs([file:filename()]) -> + {ok, [file:filename()]} | {error, Reason::term()}. +validate_configs(Configs) -> + Result = + lists:foldl(fun(_Config, Err = {error, _}) -> + Err; + (Config, Acc) -> + case filelib:is_regular(Config) of + true -> + [filename:absname(Config) | Acc]; + false -> + {error, {invalid_config_file, Config}} + end + end, [], Configs), + case Result of + {error, _} -> + Result; + _ -> + %% Order may be important so lets make sure they remain in the same + %% order they came in as + {ok, lists:reverse(Result)} + end. -spec create_log([getopt:option()], rcl_state:cmd_args()) -> {ok, rcl_state:cmd_args()} | {error, Reason::term()}. @@ -110,7 +137,7 @@ create_lib_dirs(Opts, Acc) -> Error = {error, _} -> Error; ok -> - {ok, [{lib_dirs, Dirs} | Acc]} + {ok, [{lib_dirs, [filename:absname(Dir) || Dir <- Dirs]} | Acc]} end. -spec check_lib_dirs([string()]) -> ok | {error, {Reason::atom(), Dir::string()}}. diff --git a/src/rcl_state.erl b/src/rcl_state.erl index 3a61e58..1b25ce3 100644 --- a/src/rcl_state.erl +++ b/src/rcl_state.erl @@ -23,11 +23,12 @@ %%% have a more mutable api. -module(rcl_state). --export([new/1, +-export([new/2, log/1, output_dir/1, lib_dirs/1, goals/1, + config_files/1, format/1, format/2]). @@ -37,6 +38,7 @@ -record(?MODULE, {log :: rcl_log:t(), output_dir :: file:name(), lib_dirs=[] :: [file:name()], + config_files=[] :: [file:filename()], goals=[] :: [depsolver:constraint()]}). %%============================================================================ @@ -50,11 +52,12 @@ %% API %%============================================================================ %% @doc Create a new 'log level' for the system --spec new(proplists:proplist()) -> t(). -new(PropList) when erlang:is_list(PropList) -> +-spec new(proplists:proplist(), [file:filename()]) -> t(). +new(PropList, Targets) when erlang:is_list(PropList) -> #?MODULE{log = proplists:get_value(log, PropList, rcl_log:new(error)), output_dir=proplists:get_value(output_dir, PropList, ""), lib_dirs=proplists:get_value(lib_dirs, PropList, []), + config_files=Targets, goals=proplists:get_value(goals, PropList, [])}. %% @doc get the current log state for the system @@ -74,16 +77,23 @@ lib_dirs(#?MODULE{lib_dirs=LibDir}) -> goals(#?MODULE{goals=TS}) -> TS. +-spec config_files(t()) -> [file:filename()]. +config_files(#?MODULE{config_files=ConfigFiles}) -> + ConfigFiles. + -spec format(t()) -> iolist(). format(Mod) -> format(Mod, 0). -spec format(t(), non_neg_integer()) -> iolist(). -format(#?MODULE{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, goals=Goals}, +format(#?MODULE{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, + goals=Goals, config_files=ConfigFiles}, Indent) -> [rcl_util:indent(Indent), <<"state:\n">>, rcl_util:indent(Indent + 1), <<"log: ">>, rcl_log:format(LogState), <<",\n">>, + rcl_util:indent(Indent + 1), "config files: \n", + [[rcl_util:indent(Indent + 2), ConfigFile, ",\n"] || ConfigFile <- ConfigFiles], rcl_util:indent(Indent + 1), "goals: \n", [[rcl_util:indent(Indent + 2), depsolver:format_constraint(Goal), ",\n"] || Goal <- Goals], rcl_util:indent(Indent + 1), "output_dir: ", OutDir, "\n", @@ -99,7 +109,7 @@ format(#?MODULE{log=LogState, output_dir=OutDir, lib_dirs=LibDirs, goals=Goals}, new_test() -> LogState = rcl_log:new(error), - RCLState = new([{log, LogState}]), + RCLState = new([{log, LogState}], []), ?assertMatch(LogState, log(RCLState)). -endif. diff --git a/src/relcool.erl b/src/relcool.erl index f8a9bbd..2284d29 100644 --- a/src/relcool.erl +++ b/src/relcool.erl @@ -31,7 +31,6 @@ %%============================================================================ -spec main([string()]) -> ok. main(Args) -> - io:format("~p~n", [Args]), OptSpecList = opt_spec_list(), case rcl_cmd_args:args2state(getopt:parse(OptSpecList, Args)) of {ok, {State, _Target}} -> @@ -90,6 +89,8 @@ to_error({error,{invalid_option_arg, Arg}}) -> {log_level, LogLevel} -> io_lib:format("Invalid Library Directory argument -n ~p~n", [LogLevel]) end; +to_error({error, {invalid_config_file, Config}}) -> + io_lib:format("Invalid configuration file specified: ~s", [Config]); to_error({error, {failed_to_parse, Spec}}) -> io_lib:format("Unable to parse spec ~s", [Spec]); to_error({error, {unable_to_create_output_dir, OutputDir}}) -> diff --git a/test/rclt_command_SUITE.erl b/test/rclt_command_SUITE.erl index 5967cc5..5adf54a 100644 --- a/test/rclt_command_SUITE.erl +++ b/test/rclt_command_SUITE.erl @@ -26,7 +26,8 @@ normal_passing_case/1, lib_fail_case/1, output_fail_case/1, - spec_parse_fail_case/1]). + spec_parse_fail_case/1, + config_fail_case/1]). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -41,7 +42,7 @@ end_per_suite(_Config) -> ok. all() -> - [normal_passing_case, lib_fail_case, output_fail_case]. + [normal_passing_case, lib_fail_case, output_fail_case, config_fail_case]. normal_passing_case(Config) -> DataDir = proplists:get_value(data_dir, Config), @@ -98,3 +99,9 @@ spec_parse_fail_case(_Config) -> CmdLine = ["-g", Spec], ?assertMatch({error, {failed_to_parse, _Spec}}, rcl_cmd_args:args2state(getopt:parse(relcool:opt_spec_list(), CmdLine))). + +config_fail_case(_Config) -> + ConfigFile = "does-not-exist", + CmdLine = [ConfigFile], + ?assertMatch({error, {invalid_config_file, ConfigFile}}, + rcl_cmd_args:args2state(getopt:parse(relcool:opt_spec_list(), CmdLine))). -- cgit v1.2.3