From 774f1998ed6fdb643286c9296929486ce8c6a962 Mon Sep 17 00:00:00 2001 From: Eric B Merritt Date: Tue, 30 Apr 2013 16:02:36 -0700 Subject: support the full range of possible arguments in the programmatic api --- src/rcl_cmd_args.erl | 94 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 15 deletions(-) (limited to 'src/rcl_cmd_args.erl') diff --git a/src/rcl_cmd_args.erl b/src/rcl_cmd_args.erl index bfb63b7..f5ebecd 100644 --- a/src/rcl_cmd_args.erl +++ b/src/rcl_cmd_args.erl @@ -21,7 +21,7 @@ %%% @doc Trivial utility file to help handle common tasks -module(rcl_cmd_args). --export([args2state/1, +-export([args2state/2, format_error/1]). -include_lib("relcool/include/relcool.hrl"). @@ -29,12 +29,10 @@ %%============================================================================ %% API %%============================================================================ --spec args2state({error, Reason::term()} | {[getopt:option()], [string()]}) -> +-spec args2state([getopt:option()], [string()]) -> {ok, {rcl_state:t(), [string()]}} | relcool:error(). -args2state({error, Detail}) -> - ?RCL_ERROR({opt_parse, Detail}); -args2state({ok, {Opts, Target}}) +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}}) -> +args2state(_Opts, Targets) -> ?RCL_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,7 +85,6 @@ format_error({invalid_log_level, LogLevel}) -> format_error({invalid_target, Target}) -> io_lib:format("Invalid action specified: ~s", [Target]). - %%%=================================================================== %%% Internal Functions %%%=================================================================== @@ -140,13 +137,46 @@ create_log(Opts, Acc) -> -spec create_goals([getopt:option()], rcl_state:cmd_args()) -> {ok, rcl_state:cmd_args()} | relcool: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 create_overrides([getopt:option()], rcl_state:cmd_args()) -> + {ok, rcl_state:cmd_args()} | relcool: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()]} | relcool: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]); + _ -> + ?RCL_ERROR({failed_to_parse_override, Override}) + end; +convert_overrides([QA | _], _) -> + ?RCL_ERROR({failed_to_parse_override, QA}). + -spec convert_goals([string()], [rcl_depsolver:constraint()]) -> {ok,[rcl_depsolver:constraint()]} | relcool:error(). @@ -154,12 +184,26 @@ convert_goals([], Specs) -> %% Reverse the specs because order matters to rcl_depsolver {ok, lists:reverse(Specs)}; convert_goals([RawSpec | Rest], Acc) -> + parse_goal(RawSpec, Rest, Acc). + +-spec parse_goal(string() | binary() | rcl_depsolver:constraint(), + [string() | binary() | rcl_depsolver:constraint()], + rcl_depsolver:constraints()) -> + {ok, rcl_depsolver:constraints()} | relcool: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 rcl_goal:parse(RawSpec) of {ok, Spec} -> convert_goals(Rest, [Spec | Acc]); {fail, _} -> ?RCL_ERROR({failed_to_parse, RawSpec}) end. + -spec create_output_dir([getopt:option()], rcl_state:cmd_args()) -> {ok, rcl_state:cmd_args()} | relcool:error(). create_output_dir(Opts, Acc) -> @@ -169,7 +213,8 @@ create_output_dir(Opts, Acc) -> -spec create_lib_dirs([getopt:option()], rcl_state:cmd_args()) -> {ok, rcl_state:cmd_args()} | relcool: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; @@ -193,8 +238,27 @@ create_root_dir(Opts, Acc) -> {ok, rcl_state:cmd_args()} | relcool:error(). create_disable_default_libs(Opts, Acc) -> Def = proplists:get_value(disable_default_libs, Opts, false), - {ok, [{disable_default_libs, Def} | Acc]}. + create_caller(Opts, [{disable_default_libs, Def} | Acc]). +-spec create_caller([getopt:option()], rcl_state:cmd_args()) -> + {ok, rcl_state:cmd_args()} | relcool: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 -> + ?RCL_ERROR({invalid_caller, Caller}) + end. -spec check_lib_dirs([string()]) -> ok | relcool:error(). check_lib_dirs([]) -> ok; -- cgit v1.2.3