tag v0.155.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.155.0 ---------------- * Fedora 43: add shadow-utils when LockRoot is enabled, update cloud-init service name (osbuild/images#1618) * Author: Achilleas Koutsou, Reviewers: Gianluca Zuccarelli, Michael Vogt * Update osbuild dependency commit ID to latest (osbuild/images#1609) * Author: SchutzBot, Reviewers: Achilleas Koutsou, Simon de Vlieger, Tomáš Hozza * Update snapshots to 20250626 (osbuild/images#1623) * Author: SchutzBot, Reviewers: Achilleas Koutsou, Simon de Vlieger * distro/rhel9: xz compress azure-cvm image type [HMS-8587] (osbuild/images#1620) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza * distro/rhel: introduce new image type: Azure SAP Apps [HMS-8738] (osbuild/images#1612) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza * distro/rhel: move ansible-core to sap_extras_pkgset (osbuild/images#1624) * Author: Achilleas Koutsou, Reviewers: Brian C. Lane, Tomáš Hozza * github/create-tag: allow passing the version when run manually (osbuild/images#1621) * Author: Achilleas Koutsou, Reviewers: Lukáš Zapletal, Tomáš Hozza * rhel9: move image-config into pure YAML (HMS-8593) (osbuild/images#1616) * Author: Michael Vogt, Reviewers: Achilleas Koutsou, Simon de Vlieger * test: split manifest checksums into separate files (osbuild/images#1625) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza — Somewhere on the Internet, 2025-06-30 --- tag v0.156.0 Tagger: imagebuilder-bot <imagebuilder-bots+imagebuilder-bot@redhat.com> Changes with 0.156.0 ---------------- * Many: delete repositories for EOL distributions (HMS-7044) (osbuild/images#1607) * Author: Tomáš Hozza, Reviewers: Michael Vogt, Simon de Vlieger * RHSM/facts: add 'image-builder CLI' API type (osbuild/images#1640) * Author: Tomáš Hozza, Reviewers: Brian C. Lane, Simon de Vlieger * Update dependencies 2025-06-29 (osbuild/images#1628) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * Update osbuild dependency commit ID to latest (osbuild/images#1627) * Author: SchutzBot, Reviewers: Simon de Vlieger, Tomáš Hozza * [RFC] image: drop `InstallWeakDeps` from image.DiskImage (osbuild/images#1642) * Author: Michael Vogt, Reviewers: Brian C. Lane, Simon de Vlieger, Tomáš Hozza * build(deps): bump the go-deps group across 1 directory with 3 updates (osbuild/images#1632) * Author: dependabot[bot], Reviewers: SchutzBot, Tomáš Hozza * distro/rhel10: xz compress azure-cvm image type (osbuild/images#1638) * Author: Achilleas Koutsou, Reviewers: Brian C. Lane, Simon de Vlieger * distro: cleanup/refactor distro/{defs,generic} (HMS-8744) (osbuild/images#1570) * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza * distro: remove some hardcoded values from generic/images.go (osbuild/images#1636) * Author: Michael Vogt, Reviewers: Simon de Vlieger, Tomáš Hozza * distro: small tweaks for the YAML based imagetypes (osbuild/images#1622) * Author: Michael Vogt, Reviewers: Brian C. Lane, Simon de Vlieger * fedora/wsl: packages and locale (osbuild/images#1635) * Author: Simon de Vlieger, Reviewers: Michael Vogt, Tomáš Hozza * image/many: make compression more generic (osbuild/images#1634) * Author: Simon de Vlieger, Reviewers: Brian C. Lane, Michael Vogt * manifest: handle content template name with spaces (osbuild/images#1641) * Author: Bryttanie, Reviewers: Brian C. Lane, Michael Vogt, Tomáš Hozza * many: implement gzip (osbuild/images#1633) * Author: Simon de Vlieger, Reviewers: Michael Vogt, Tomáš Hozza * rhel/azure: set GRUB_TERMINAL based on architecture [RHEL-91383] (osbuild/images#1626) * Author: Achilleas Koutsou, Reviewers: Simon de Vlieger, Tomáš Hozza — Somewhere on the Internet, 2025-07-07 ---
298 lines
7.4 KiB
Go
298 lines
7.4 KiB
Go
// Package errs provides a simple error package with stack traces.
|
|
package errs
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"runtime"
|
|
)
|
|
|
|
// Namer is implemented by all errors returned in this package. It returns a
|
|
// name for the class of error it is, and a boolean indicating if the name is
|
|
// valid.
|
|
type Namer interface{ Name() (string, bool) }
|
|
|
|
// Causer is implemented by all errors returned in this package. It returns
|
|
// the underlying cause of the error, or nil if there is no underlying cause.
|
|
//
|
|
// Deprecated: check for the 'Unwrap()' interface from the stdlib errors package
|
|
// instead.
|
|
type Causer interface{ Cause() error }
|
|
|
|
// New returns an error not contained in any class. This is the same as calling
|
|
// fmt.Errorf(...) except it captures a stack trace on creation.
|
|
func New(format string, args ...interface{}) error {
|
|
return (*Class).create(nil, 3, fmt.Errorf(format, args...))
|
|
}
|
|
|
|
// Wrap returns an error not contained in any class. It just associates a stack
|
|
// trace with the error. Wrap returns nil if err is nil.
|
|
func Wrap(err error) error {
|
|
return (*Class).create(nil, 3, err)
|
|
}
|
|
|
|
// WrapP stores into the error pointer if it contains a non-nil error an error not
|
|
// contained in any class. It just associates a stack trace with the error. WrapP
|
|
// does nothing if the pointer or pointed at error is nil.
|
|
func WrapP(err *error) {
|
|
if err != nil && *err != nil {
|
|
*err = (*Class).create(nil, 3, *err)
|
|
}
|
|
}
|
|
|
|
// Often, we call Unwrap as much as possible. Since comparing arbitrary
|
|
// interfaces with equality isn't panic safe, we only loop up to 100
|
|
// times to ensure that a poor implementation that causes a cycle does
|
|
// not run forever.
|
|
const maxUnwrap = 100
|
|
|
|
// Unwrap returns the final, most underlying error, if any, or just the error.
|
|
//
|
|
// Deprecated: Prefer errors.Is() and errors.As().
|
|
func Unwrap(err error) error {
|
|
for i := 0; err != nil && i < maxUnwrap; i++ {
|
|
var nerr error
|
|
|
|
switch e := err.(type) {
|
|
case Causer:
|
|
nerr = e.Cause()
|
|
|
|
case interface{ Unwrap() error }:
|
|
nerr = e.Unwrap()
|
|
|
|
case interface{ Ungroup() []error }:
|
|
// consider the first error to be the "main" error.
|
|
errs := e.Ungroup()
|
|
if len(errs) > 0 {
|
|
nerr = errs[0]
|
|
}
|
|
case interface{ Unwrap() []error }:
|
|
// consider the first error to be the "main" error.
|
|
errs := e.Unwrap()
|
|
if len(errs) > 0 {
|
|
nerr = errs[0]
|
|
}
|
|
}
|
|
|
|
if nerr == nil {
|
|
return err
|
|
}
|
|
err = nerr
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// Classes returns all the classes that have wrapped the error.
|
|
func Classes(err error) (classes []*Class) {
|
|
IsFunc(err, func(err error) bool {
|
|
if e, ok := err.(*errorT); ok {
|
|
classes = append(classes, e.class)
|
|
}
|
|
return false
|
|
})
|
|
return classes
|
|
}
|
|
|
|
// IsFunc checks if any of the underlying errors matches the func
|
|
func IsFunc(err error, is func(err error) bool) bool {
|
|
for {
|
|
if is(err) {
|
|
return true
|
|
}
|
|
|
|
switch u := err.(type) {
|
|
case interface{ Unwrap() error }:
|
|
err = u.Unwrap()
|
|
case Causer:
|
|
err = u.Cause()
|
|
|
|
case interface{ Ungroup() []error }:
|
|
for _, err := range u.Ungroup() {
|
|
if IsFunc(err, is) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
case interface{ Unwrap() []error }:
|
|
for _, err := range u.Unwrap() {
|
|
if IsFunc(err, is) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// error classes
|
|
//
|
|
|
|
// Class represents a class of errors. You can construct errors, and check if
|
|
// errors are part of the class.
|
|
type Class string
|
|
|
|
// Has returns true if the passed in error (or any error wrapped by it) has
|
|
// this class.
|
|
func (c *Class) Has(err error) bool {
|
|
return IsFunc(err, func(err error) bool {
|
|
errt, ok := err.(*errorT)
|
|
return ok && errt.class == c
|
|
})
|
|
}
|
|
|
|
// New constructs an error with the format string that will be contained by
|
|
// this class. This is the same as calling Wrap(fmt.Errorf(...)).
|
|
func (c *Class) New(format string, args ...interface{}) error {
|
|
return c.create(3, fmt.Errorf(format, args...))
|
|
}
|
|
|
|
// Wrap returns a new error based on the passed in error that is contained in
|
|
// this class. Wrap returns nil if err is nil.
|
|
func (c *Class) Wrap(err error) error {
|
|
return c.create(3, err)
|
|
}
|
|
|
|
// WrapP stores into the error pointer if it contains a non-nil error an error contained
|
|
// in this class. WrapP does nothing if the pointer or pointed at error is nil.
|
|
func (c *Class) WrapP(err *error) {
|
|
if err != nil && *err != nil {
|
|
*err = c.create(3, *err)
|
|
}
|
|
}
|
|
|
|
// Instance creates a class membership object which implements the error
|
|
// interface and allows errors.Is() to check whether given errors are
|
|
// (or contain) an instance of this class.
|
|
//
|
|
// This makes possible a construct like the following:
|
|
//
|
|
// if errors.Is(err, MyClass.Instance()) {
|
|
// fmt.Printf("err is an instance of MyClass")
|
|
// }
|
|
//
|
|
// ..without requiring the Class type to implement the error interface itself,
|
|
// as that would open the door to sundry misunderstandings and misusage.
|
|
func (c *Class) Instance() error {
|
|
return (*classMembershipChecker)(c)
|
|
}
|
|
|
|
// create constructs the error, or just adds the class to the error, keeping
|
|
// track of the stack if it needs to construct it.
|
|
func (c *Class) create(depth int, err error) error {
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
var pcs []uintptr
|
|
if err, ok := err.(*errorT); ok {
|
|
if c == nil || err.class == c {
|
|
return err
|
|
}
|
|
pcs = err.pcs
|
|
}
|
|
|
|
errt := &errorT{
|
|
class: c,
|
|
err: err,
|
|
pcs: pcs,
|
|
}
|
|
|
|
if errt.pcs == nil {
|
|
errt.pcs = make([]uintptr, 64)
|
|
n := runtime.Callers(depth, errt.pcs)
|
|
errt.pcs = errt.pcs[:n:n]
|
|
}
|
|
|
|
return errt
|
|
}
|
|
|
|
type classMembershipChecker Class
|
|
|
|
func (cmc *classMembershipChecker) Error() string {
|
|
panic("classMembershipChecker used as concrete error! don't do that")
|
|
}
|
|
|
|
//
|
|
// errors
|
|
//
|
|
|
|
// errorT is the type of errors returned from this package.
|
|
type errorT struct {
|
|
class *Class
|
|
err error
|
|
pcs []uintptr
|
|
}
|
|
|
|
var ( // ensure *errorT implements the helper interfaces.
|
|
_ Namer = (*errorT)(nil)
|
|
_ Causer = (*errorT)(nil)
|
|
_ error = (*errorT)(nil)
|
|
)
|
|
|
|
// Stack returns the pcs for the stack trace associated with the error.
|
|
func (e *errorT) Stack() []uintptr { return e.pcs }
|
|
|
|
// errorT implements the error interface.
|
|
func (e *errorT) Error() string {
|
|
return fmt.Sprintf("%v", e)
|
|
}
|
|
|
|
// Format handles the formatting of the error. Using a "+" on the format string
|
|
// specifier will also write the stack trace.
|
|
func (e *errorT) Format(f fmt.State, c rune) {
|
|
sep := ""
|
|
if e.class != nil && *e.class != "" {
|
|
fmt.Fprintf(f, "%s", string(*e.class))
|
|
sep = ": "
|
|
}
|
|
if text := e.err.Error(); len(text) > 0 {
|
|
fmt.Fprintf(f, "%s%v", sep, text)
|
|
}
|
|
if f.Flag(int('+')) {
|
|
summarizeStack(f, e.pcs)
|
|
}
|
|
}
|
|
|
|
// Cause implements the interface wrapping errors were previously
|
|
// expected to implement to allow getting at underlying causes.
|
|
func (e *errorT) Cause() error {
|
|
return e.err
|
|
}
|
|
|
|
// Unwrap returns the immediate underlying error.
|
|
func (e *errorT) Unwrap() error {
|
|
return e.err
|
|
}
|
|
|
|
// Name returns the name for the error, which is the first wrapping class.
|
|
func (e *errorT) Name() (string, bool) {
|
|
if e.class == nil {
|
|
return "", false
|
|
}
|
|
return string(*e.class), true
|
|
}
|
|
|
|
// Is determines whether an error is an instance of the given error class.
|
|
//
|
|
// Use with (*Class).Instance().
|
|
func (e *errorT) Is(err error) bool {
|
|
cmc, ok := err.(*classMembershipChecker)
|
|
return ok && e.class == (*Class)(cmc)
|
|
}
|
|
|
|
// summarizeStack writes stack line entries to the writer.
|
|
func summarizeStack(w io.Writer, pcs []uintptr) {
|
|
frames := runtime.CallersFrames(pcs)
|
|
for {
|
|
frame, more := frames.Next()
|
|
if !more {
|
|
return
|
|
}
|
|
fmt.Fprintf(w, "\n\t%s:%d", frame.Function, frame.Line)
|
|
}
|
|
}
|