Permalink
Browse files

make sure errors carry the name of the module that created them

This allows errors to be printed at the source
  • Loading branch information...
1 parent 79a28e0 commit 49a45620c2c0431583969192fbefe44ee6f7850c @ericbmerritt ericbmerritt committed Sep 18, 2012
View
@@ -18,3 +18,10 @@
-define(RCL_ERROR, 0).
-define(RCL_INFO, 1).
-define(RCL_DEBUG, 2).
+
+%% This is the default form of error messages for the Relcool
+%% system. It is expected that everything that returns an error use
+%% this and that they all expose a format_error/1 message that returns
+%% an iolist.
+-define(RCL_ERROR(Reason),
+ {error, {?MODULE, Reason}}).
View
@@ -42,6 +42,7 @@
name/2,
vsn/1,
vsn/2,
+ vsn_as_string/1,
dir/1,
dir/2,
active_deps/1,
@@ -54,6 +55,8 @@
-export_type([t/0]).
+-include_lib("relcool/include/relcool.hrl").
+
-record(app_info_t, {name :: atom(),
vsn :: ec_semver:semver(),
dir :: file:name(),
@@ -76,15 +79,15 @@ new() ->
%% @doc build a complete version of the app info with all fields set.
-spec new(atom(), string(), file:name(), [atom()], [atom()]) ->
- {ok, t()} | {error, Reason::term()}.
+ {ok, t()} | relcool:error().
new(AppName, Vsn, Dir, ActiveDeps, LibraryDeps)
when erlang:is_atom(AppName),
erlang:is_list(Dir),
erlang:is_list(ActiveDeps),
erlang:is_list(LibraryDeps) ->
case parse_version(Vsn) of
{fail, _} ->
- {error, {vsn_parse, AppName}};
+ ?RCL_ERROR({vsn_parse, AppName});
ParsedVsn ->
{ok, #app_info_t{name=AppName, vsn=ParsedVsn, dir=Dir,
active_deps=ActiveDeps,
@@ -104,17 +107,20 @@ name(AppInfo=#app_info_t{}, AppName)
vsn(#app_info_t{vsn=Vsn}) ->
Vsn.
--spec vsn(t(), string()) -> {ok, t()} | {error, Reason::term()}.
+-spec vsn_as_string(t()) -> string().
+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().
vsn(AppInfo=#app_info_t{name=AppName}, AppVsn)
when erlang:is_list(AppVsn) ->
case parse_version(AppVsn) of
{fail, _} ->
- {error, {vsn_parse, AppName}};
+ ?RCL_ERROR({vsn_parse, AppName});
ParsedVsn ->
{ok, AppInfo#app_info_t{vsn=ParsedVsn}}
end.
-
-spec dir(t()) -> file:name().
dir(#app_info_t{dir=Dir}) ->
Dir.
@@ -139,10 +145,10 @@ library_deps(AppInfo=#app_info_t{}, LibraryDeps)
when erlang:is_list(LibraryDeps) ->
AppInfo#app_info_t{library_deps=LibraryDeps}.
--spec format_error({error, Reason::term()}) -> iolist().
-format_error({error, {vsn_parse, AppName, AppDir}}) ->
- io_lib:format("Error parsing version for ~p at ~s",
- [AppName, AppDir]).
+-spec format_error(Reason::term()) -> iolist().
+format_error({vsn_parse, AppName}) ->
+ io_lib:format("Error parsing version for ~p",
+ [AppName]).
-spec format(t()) -> iolist().
format(AppInfo) ->
@@ -158,8 +164,6 @@ format(Indent, #app_info_t{name=Name, vsn=Vsn, dir=Dir,
rcl_util:indent(Indent + 1), "Library Dependencies:\n",
[[rcl_util:indent(Indent + 2), erlang:atom_to_list(LibDep), ",\n"] || LibDep <- LibDeps]].
-
-
%%%===================================================================
%%% Internal Functions
%%%===================================================================
View
@@ -21,19 +21,17 @@
%%% @doc Trivial utility file to help handle common tasks
-module(rcl_cmd_args).
--export([args2state/1]).
-
-%%============================================================================
-%% types
-%%============================================================================
+-export([args2state/1,
+ format_error/1]).
+-include_lib("relcool/include/relcool.hrl").
%%============================================================================
%% API
%%============================================================================
-spec args2state({error, Reason::term()} | {[getopt:option()], [string()]}) ->
- {error, Reason::term()} |
- {ok, {rcl_state:t(), [string()]}}.
+ {ok, {rcl_state:t(), [string()]}} |
+ relcool:error().
args2state(Error={error, _}) ->
Error;
args2state({ok, {Opts, Targets}}) ->
@@ -53,11 +51,40 @@ args2state({ok, {Opts, Targets}}) ->
end
end.
+-spec format_error(Reason::term()) -> iolist().
+format_error({invalid_option_arg, Arg}) ->
+ case Arg of
+ {goals, Goal} ->
+ io_lib:format("Invalid Goal argument -g ~p~n", [Goal]);
+ {relname, RelName} ->
+ io_lib:format("Invalid Release Name argument -n ~p~n", [RelName]);
+ {relvsn, RelVsn} ->
+ io_lib:format("Invalid Release Version argument -n ~p~n", [RelVsn]);
+ {output_dir, Outdir} ->
+ io_lib:format("Invalid Output Directory argument -n ~p~n", [Outdir]);
+ {lib_dir, LibDir} ->
+ io_lib:format("Invalid Library Directory argument -n ~p~n", [LibDir]);
+ {log_level, LogLevel} ->
+ io_lib:format("Invalid Library Directory argument -n ~p~n", [LogLevel])
+ end;
+format_error({invalid_config_file, Config}) ->
+ io_lib:format("Invalid configuration file specified: ~s", [Config]);
+format_error({failed_to_parse, Spec}) ->
+ io_lib:format("Unable to parse spec ~s", [Spec]);
+format_error({unable_to_create_output_dir, OutputDir}) ->
+ io_lib:format("Unable to create output directory (possible permissions issue): ~s",
+ [OutputDir]);
+format_error({not_directory, Dir}) ->
+ io_lib:format("Library directory does not exist: ~s", [Dir]);
+format_error({invalid_log_level, LogLevel}) ->
+ io_lib:format("Invalid log level specified -V ~p, log level must be in the"
+ " range 0..2", [LogLevel]).
+
%%%===================================================================
%%% Internal Functions
%%%===================================================================
-spec validate_configs([file:filename()]) ->
- {ok, [file:filename()]} | {error, Reason::term()}.
+ {ok, [file:filename()]} | relcool:error().
validate_configs(Configs) ->
Result =
lists:foldl(fun(_Config, Err = {error, _}) ->
@@ -67,7 +94,7 @@ validate_configs(Configs) ->
true ->
[filename:absname(Config) | Acc];
false ->
- {error, {invalid_config_file, Config}}
+ ?RCL_ERROR({invalid_config_file, Config})
end
end, [], Configs),
case Result of
@@ -80,29 +107,29 @@ validate_configs(Configs) ->
end.
-spec create_log([getopt:option()], rcl_state:cmd_args()) ->
- {ok, rcl_state:cmd_args()} | {error, Reason::term()}.
+ {ok, rcl_state:cmd_args()} | relcool: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]);
true ->
- {error, {invalid_log_level, LogLevel}}
+ ?RCL_ERROR({invalid_log_level, LogLevel})
end.
-spec create_goals([getopt:option()], rcl_state:cmd_args()) ->
- {ok, rcl_state:cmd_args()} | {error, Reason::term()}.
+ {ok, rcl_state:cmd_args()} | relcool:error().
create_goals(Opts, Acc) ->
case convert_goals(proplists:get_all_values(goals, Opts), []) of
- Error={error, {failed_to_parse, _Spec}} ->
+ Error={error, _} ->
Error;
{ok, Specs} ->
create_output_dir(Opts, [{goals, Specs} | Acc])
end.
-spec convert_goals([string()], [depsolver:constraint()]) ->
- {error,{failed_to_parse, string()}} |
- {ok,[depsolver:constraint()]}.
+ {ok,[depsolver:constraint()]} |
+ relcool:error().
convert_goals([], Specs) ->
%% Reverse the specs because order matters to depsolver
{ok, lists:reverse(Specs)};
@@ -111,10 +138,10 @@ convert_goals([RawSpec | Rest], Acc) ->
{ok, Spec} ->
convert_goals(Rest, [Spec | Acc]);
{fail, _} ->
- {error, {failed_to_parse, RawSpec}}
+ ?RCL_ERROR({failed_to_parse, RawSpec})
end.
-spec create_output_dir([getopt:option()], rcl_state:cmd_args()) ->
- {ok, rcl_state:cmd_args()} | {error, Reason::term()}.
+ {ok, rcl_state:cmd_args()} | relcool:error().
create_output_dir(Opts, Acc) ->
OutputDir = proplists:get_value(output_dir, Opts, "./relcool_output"),
case filelib:is_dir(OutputDir) of
@@ -123,14 +150,14 @@ create_output_dir(Opts, Acc) ->
ok ->
create_lib_dirs(Opts, [{output_dir, OutputDir} | Acc]);
{error, _} ->
- {error, {unable_to_create_output_dir, OutputDir}}
+ ?RCL_ERROR({unable_to_create_output_dir, OutputDir})
end;
true ->
create_lib_dirs(Opts, [{output_dir, OutputDir} | Acc])
end.
-spec create_lib_dirs([getopt:option()], rcl_state:cmd_args()) ->
- {ok, rcl_state:cmd_args()} | {error, Reason::term()}.
+ {ok, rcl_state:cmd_args()} | relcool:error().
create_lib_dirs(Opts, Acc) ->
Dirs = proplists:get_all_values(lib_dir, Opts),
case check_lib_dirs(Dirs) of
@@ -140,13 +167,13 @@ create_lib_dirs(Opts, Acc) ->
{ok, [{lib_dirs, [filename:absname(Dir) || Dir <- Dirs]} | Acc]}
end.
--spec check_lib_dirs([string()]) -> ok | {error, {Reason::atom(), Dir::string()}}.
+-spec check_lib_dirs([string()]) -> ok | relcool:error().
check_lib_dirs([]) ->
ok;
check_lib_dirs([Dir | Rest]) ->
case filelib:is_dir(Dir) of
false ->
- {error, {not_directory, Dir}};
+ ?RCL_ERROR({not_directory, Dir});
true ->
check_lib_dirs(Rest)
end.
View
@@ -8,19 +8,25 @@
-module(rcl_provider).
%% API
--export([new/2, do/2, format_error/2, format/1]).
+-export([new/2,
+ do/2,
+ format_error/1,
+ format_error/2,
+ format/1]).
-export_type([t/0]).
+-include_lib("relcool/include/relcool.hrl").
+
%%%===================================================================
%%% Types
%%%===================================================================
-opaque t() :: {?MODULE, module()}.
--callback init(rcl_state:t()) -> {ok, rcl_state:t()} | {error, Reason::term()}.
--callback do(rcl_state:t()) -> {error, Reason::term()} | {ok, rcl_state:t()}.
--callback format_error({error, Reason::term()}) -> iolist().
+-callback init(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error().
+-callback do(rcl_state:t()) -> {ok, rcl_state:t()} | relcool:error().
+-callback format_error(Reason::term()) -> iolist().
%%%===================================================================
%%% API
@@ -32,32 +38,35 @@
%% @param ModuleName The module name.
%% @param State0 The current state of the system
-spec new(module(), rcl_state:t()) ->
- {t(), {ok, rcl_state:t()} | {error, Reason::term()}}.
+ {t(), {ok, rcl_state:t()}} | relcool:error().
new(ModuleName, State0) when is_atom(ModuleName) ->
State1 = ModuleName:init(State0),
case code:which(ModuleName) of
non_existing ->
- erlang:error({non_existing, ModuleName});
+ ?RCL_ERROR({non_existing, ModuleName});
_ ->
- ok
- end,
- {{?MODULE, ModuleName}, State1}.
+ {{?MODULE, ModuleName}, State1}
+ end.
%% @doc Manipulate the state of the system, that new state
%%
%% @param Provider the provider object
%% @param State the current state of the system
-spec do(Provider::t(), rcl_state:t()) ->
- {error, Reason::term()} | {ok, rcl_state:t()}.
+ {ok, rcl_state:t()} | relcool:error().
do({?MODULE, Mod}, State) ->
Mod:do(State).
%% @doc format an error produced from a provider.
--spec format_error(t(), {error, Reason::term()}) -> iolist().
+-spec format_error(Reason::term()) -> iolist().
+format_error({non_existing, ModuleName}) ->
+ io_lib:format("~p does not exist in the system", [ModuleName]).
+
+%% @doc format an error produced from a provider.
+-spec format_error(t(), Reason::term()) -> iolist().
format_error({?MODULE, Mod}, Error) ->
Mod:format_error(Error).
-
%% @doc print the provider module name
%%
%% @param T - The provider
Oops, something went wrong.

0 comments on commit 49a4562

Please sign in to comment.