Improve CLI error reporting
This commit is contained in:
@@ -17,8 +17,9 @@ module Producer
|
||||
rescue ArgumentError => e
|
||||
stderr.puts e.message
|
||||
exit EX_USAGE
|
||||
rescue RuntimeError => e
|
||||
stderr.puts "#{e.class.name.split('::').last}: #{e.message}"
|
||||
rescue Exception => e
|
||||
ef = ErrorFormatter.new(force_cause: [RecipeEvaluationError])
|
||||
stderr.puts ef.format e
|
||||
exit EX_SOFTWARE
|
||||
end
|
||||
end
|
||||
|
53
lib/producer/core/error_formatter.rb
Normal file
53
lib/producer/core/error_formatter.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
module Producer
|
||||
module Core
|
||||
class ErrorFormatter
|
||||
def initialize(debug: false, force_cause: [])
|
||||
@debug = debug
|
||||
@force_cause = force_cause
|
||||
end
|
||||
|
||||
def debug?
|
||||
!!@debug
|
||||
end
|
||||
|
||||
def format(exception)
|
||||
lines = format_exception exception
|
||||
|
||||
if debug? && exception.cause
|
||||
lines << ''
|
||||
lines << 'cause:'
|
||||
lines << format_exception(exception.cause, filter: false)
|
||||
end
|
||||
|
||||
lines.join("\n")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_exception(exception, filter: true)
|
||||
[
|
||||
format_message(exception),
|
||||
*format_backtrace(exception.backtrace, filter: filter)
|
||||
]
|
||||
end
|
||||
|
||||
def format_message(exception)
|
||||
exception = exception.cause if @force_cause.include? exception.class
|
||||
"#{exception.class.name.split('::').last}: #{exception.message}"
|
||||
end
|
||||
|
||||
def format_backtrace(backtrace, filter: true)
|
||||
backtrace = filter_backtrace backtrace if filter
|
||||
indent_backtrace backtrace
|
||||
end
|
||||
|
||||
def filter_backtrace(backtrace)
|
||||
backtrace.reject { |l| l =~ /\/producer-\w+\/(?:bin|lib)\// }
|
||||
end
|
||||
|
||||
def indent_backtrace(backtrace)
|
||||
backtrace.map { |e| ' %s' % e }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -2,8 +2,10 @@ module Producer
|
||||
module Core
|
||||
Error = Class.new(StandardError)
|
||||
RuntimeError = Class.new(RuntimeError)
|
||||
|
||||
ArgumentError = Class.new(Error)
|
||||
ConditionNotMetError = Class.new(Error)
|
||||
RecipeEvaluationError = Class.new(RuntimeError)
|
||||
RemoteCommandExecutionError = Class.new(RuntimeError)
|
||||
RegistryKeyError = Class.new(RuntimeError)
|
||||
end
|
||||
|
@@ -5,7 +5,14 @@ module Producer
|
||||
class << self
|
||||
def evaluate(file_path, env)
|
||||
content = File.read(file_path)
|
||||
Recipe.new(env).tap { |o| o.instance_eval content, file_path }
|
||||
begin
|
||||
Recipe.new(env).tap { |o| o.instance_eval content, file_path }
|
||||
rescue Exception => e
|
||||
fail RecipeEvaluationError, e.message, [
|
||||
'%s (recipe)' % file_path,
|
||||
*e.backtrace
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user