1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
# frozen_string_literal: true
# Some helper methods for throwing and populating errors.
#
# @api public
module Puppet::Util::Errors
# Throw a Puppet::DevError with the specified message. Used for unknown or
# internal application failures.
#
# @param msg [String] message used in raised error
# @raise [Puppet::DevError] always raised with the supplied message
def devfail(msg)
self.fail(Puppet::DevError, msg)
end
# Add line and file info to the supplied exception if info is available from
# this object, is appropriately populated and the supplied exception supports
# it. When other is supplied, the backtrace will be copied to the error
# object and the 'original' will be dropped from the error.
#
# @param error [Exception] exception that is populated with info
# @param other [Exception] original exception, source of backtrace info
# @return [Exception] error parameter
def adderrorcontext(error, other = nil)
error.line ||= line if error.respond_to?(:line=) and respond_to?(:line) and line
error.file ||= file if error.respond_to?(:file=) and respond_to?(:file) and file
error.original ||= other if error.respond_to?(:original=)
error.set_backtrace(other.backtrace) if other and other.respond_to?(:backtrace)
# It is not meaningful to keep the wrapped exception since its backtrace has already
# been adopted by the error. (The instance variable is private for good reasons).
error.instance_variable_set(:@original, nil)
error
end
# Return a human-readable string of this object's file, line, and pos attributes,
# if set.
#
# @param file [String] the file path for the error (nil or "", for not known)
# @param line [String] the line number for the error (nil or "", for not known)
# @param column [String] the column number for the error (nil or "", for not known)
# @return [String] description of file, line, and column
#
def self.error_location(file, line = nil, column = nil)
file = nil if file.is_a?(String) && file.empty?
line = nil if line.is_a?(String) && line.empty?
column = nil if column.is_a?(String) && column.empty?
if file and line and column
_("(file: %{file}, line: %{line}, column: %{column})") % { file: file, line: line, column: column }
elsif file and line
_("(file: %{file}, line: %{line})") % { file: file, line: line }
elsif line and column
_("(line: %{line}, column: %{column})") % { line: line, column: column }
elsif line
_("(line: %{line})") % { line: line }
elsif file
_("(file: %{file})") % { file: file }
else
''
end
end
# Return a human-readable string of this object's file, line, and pos attributes,
# with a proceeding space in the output
# if set.
#
# @param file [String] the file path for the error (nil or "", for not known)
# @param line [String] the line number for the error (nil or "", for not known)
# @param column [String] the column number for the error (nil or "", for not known)
# @return [String] description of file, line, and column
#
def self.error_location_with_space(file, line = nil, column = nil)
error_location_str = error_location(file, line, column)
if error_location_str.empty?
''
else
' ' + error_location_str
end
end
# Return a human-readable string of this object's file and line
# where unknown entries are listed as 'unknown'
#
# @param file [String] the file path for the error (nil or "", for not known)
# @param line [String] the line number for the error (nil or "", for not known)
# @return [String] description of file, and line
def self.error_location_with_unknowns(file, line)
file = nil if file.is_a?(String) && file.empty?
line = nil if line.is_a?(String) && line.empty?
file ||= _('unknown')
line ||= _('unknown')
error_location(file, line)
end
# Return a human-readable string of this object's file and line attributes,
# if set.
#
# @return [String] description of file and line with a leading space
def error_context
Puppet::Util::Errors.error_location_with_space(file, line)
end
# Wrap a call in such a way that we always throw the right exception and keep
# as much context as possible.
#
# @param options [Hash<Symbol,Object>] options used to create error
# @option options [Class] :type error type to raise, defaults to
# Puppet::DevError
# @option options [String] :message message to use in error, default mentions
# the name of this class
# @raise [Puppet::Error] re-raised with extra context if the block raises it
# @raise [Error] of type options[:type], when the block raises other
# exceptions
def exceptwrap(options = {})
options[:type] ||= Puppet::DevError
begin
return yield
rescue Puppet::Error => detail
raise adderrorcontext(detail)
rescue => detail
message = options[:message] || _("%{klass} failed with error %{error_type}: %{detail}") % { klass: self.class, error_type: detail.class, detail: detail }
error = options[:type].new(message)
# We can't use self.fail here because it always expects strings,
# not exceptions.
raise adderrorcontext(error, detail)
end
retval
end
# Throw an error, defaulting to a Puppet::Error.
#
# @overload fail(message, ..)
# Throw a Puppet::Error with a message concatenated from the given
# arguments.
# @param [String] message error message(s)
# @overload fail(error_klass, message, ..)
# Throw an exception of type error_klass with a message concatenated from
# the given arguments.
# @param [Class] type of error
# @param [String] message error message(s)
# @overload fail(error_klass, message, ..)
# Throw an exception of type error_klass with a message concatenated from
# the given arguments.
# @param [Class] type of error
# @param [String] message error message(s)
# @param [Exception] original exception, source of backtrace info
def fail(*args)
if args[0].is_a?(Class)
type = args.shift
else
type = Puppet::Error
end
other = args.count > 1 ? args.pop : nil
error = adderrorcontext(type.new(args.join(" ")), other)
raise error
end
end
|