[bugfix] Fix remote media pruning failing if media already gone (#548)

* fix error check of prune to allow missing files

* update go-store library, add test for pruning item with db entry but no file

Signed-off-by: kim <grufwub@gmail.com>

* remove now-unneccessary error check

Signed-off-by: kim <grufwub@gmail.com>

Co-authored-by: kim <grufwub@gmail.com>
This commit is contained in:
tobi
2022-05-08 19:49:45 +02:00
committed by GitHub
parent 26b74aefaf
commit 5004e0a9da
50 changed files with 4682 additions and 1785 deletions

View File

@@ -1 +0,0 @@
simple but powerful errors library that allows providing context information with errors

View File

@@ -1,107 +0,0 @@
package errors
import (
"fmt"
"sync"
"codeberg.org/gruf/go-format"
)
// KV is a structure for setting key-value pairs in ErrorData.
type KV struct {
Key string
Value interface{}
}
// ErrorData defines a way to set and access contextual error data.
// The default implementation of this is thread-safe.
type ErrorData interface {
// Value will attempt to fetch value for given key in ErrorData
Value(string) (interface{}, bool)
// Append adds the supplied key-values to ErrorData, similar keys DO overwrite
Append(...KV)
// Implement byte slice representation formatter.
format.Formattable
// Implement string representation formatter.
fmt.Stringer
}
// NewData returns a new ErrorData implementation.
func NewData() ErrorData {
return &errorData{
data: make([]KV, 0, 10),
}
}
// errorData is our ErrorData implementation, this is essentially
// just a thread-safe string-interface map implementation.
type errorData struct {
data []KV
mu sync.Mutex
}
func (d *errorData) set(key string, value interface{}) {
for i := range d.data {
if d.data[i].Key == key {
// Found existing, update!
d.data[i].Value = value
return
}
}
// Add new KV entry to slice
d.data = append(d.data, KV{
Key: key,
Value: value,
})
}
func (d *errorData) Value(key string) (interface{}, bool) {
d.mu.Lock()
for i := range d.data {
if d.data[i].Key == key {
v := d.data[i].Value
d.mu.Unlock()
return v, true
}
}
d.mu.Unlock()
return nil, false
}
func (d *errorData) Append(kvs ...KV) {
d.mu.Lock()
for i := range kvs {
d.set(kvs[i].Key, kvs[i].Value)
}
d.mu.Unlock()
}
func (d *errorData) AppendFormat(b []byte) []byte {
buf := format.Buffer{B: b}
d.mu.Lock()
buf.B = append(buf.B, '{')
// Append data as kv pairs
for i := range d.data {
key := d.data[i].Key
val := d.data[i].Value
format.Appendf(&buf, "{:k}={:v} ", key, val)
}
// Drop trailing space
if len(d.data) > 0 {
buf.Truncate(1)
}
buf.B = append(buf.B, '}')
d.mu.Unlock()
return buf.B
}
func (d *errorData) String() string {
return string(d.AppendFormat(nil))
}

View File

@@ -1,199 +0,0 @@
package errors
import "fmt"
// ErrorContext defines a wrappable error with the ability to hold extra contextual information
type ErrorContext interface {
// implement base error interface
error
// Is identifies whether the receiver contains / is the target
Is(error) bool
// Unwrap reveals the underlying wrapped error (if any!)
Unwrap() error
// Value attempts to fetch contextual data for given key from this ErrorContext
Value(string) (interface{}, bool)
// Append allows adding contextual data to this ErrorContext
Append(...KV) ErrorContext
// Data returns the contextual data structure associated with this ErrorContext
Data() ErrorData
}
// New returns a new ErrorContext created from string
func New(msg string) ErrorContext {
return stringError(msg)
}
// Newf returns a new ErrorContext created from format string
func Newf(s string, a ...interface{}) ErrorContext {
return stringError(fmt.Sprintf(s, a...))
}
// Wrap ensures supplied error is an ErrorContext, wrapping if necessary
func Wrap(err error) ErrorContext {
// Nil error, do nothing
if err == nil {
return nil
}
// Check if this is already wrapped somewhere in stack
if xerr, ok := err.(*errorContext); ok {
return xerr
} else if As(err, &xerr) {
// This is really not an ideal situation,
// but we try to make do by salvaging the
// contextual error data from earlier in
// stack, setting current error to the top
// and setting the unwrapped error to inner
return &errorContext{
data: xerr.data,
innr: Unwrap(err),
err: err,
}
}
// Return new Error type
return &errorContext{
data: NewData(),
innr: nil,
err: err,
}
}
// WrapMsg wraps supplied error as inner, returning an ErrorContext
// with a new outer error made from the supplied message string
func WrapMsg(err error, msg string) ErrorContext {
// Nil error, do nothing
if err == nil {
return nil
}
// Check if this is already wrapped
var xerr *errorContext
if As(err, &xerr) {
return &errorContext{
data: xerr.data,
innr: err,
err: New(msg),
}
}
// Return new wrapped error
return &errorContext{
data: NewData(),
innr: err,
err: stringError(msg),
}
}
// WrapMsgf wraps supplied error as inner, returning an ErrorContext with
// a new outer error made from the supplied message format string
func WrapMsgf(err error, msg string, a ...interface{}) ErrorContext {
return WrapMsg(err, fmt.Sprintf(msg, a...))
}
// ErrorData attempts fetch ErrorData from supplied error, returns nil otherwise
func Data(err error) ErrorData {
x, ok := err.(ErrorContext)
if ok {
return x.Data()
}
return nil
}
// UnwrapAll fully unwraps an error stack to produce a string output.
func UnwrapAll(err error) string {
if err == nil {
return ""
}
// Start error output
out := err.Error()
err = Unwrap(err)
// Unwrap and append each
for err != nil {
out += ": " + err.Error()
err = Unwrap(err)
}
return out
}
// stringError is the simplest ErrorContext implementation
type stringError string
func (e stringError) Error() string {
return string(e)
}
func (e stringError) Is(err error) bool {
se, ok := err.(stringError)
return ok && e == se
}
func (e stringError) Unwrap() error {
return nil
}
func (e stringError) Value(key string) (interface{}, bool) {
return nil, false
}
func (e stringError) Append(kvs ...KV) ErrorContext {
data := NewData()
data.Append(kvs...)
return &errorContext{
data: data,
innr: nil,
err: e,
}
}
func (e stringError) Data() ErrorData {
return nil
}
// errorContext is the *actual* ErrorContext implementation
type errorContext struct {
// data contains any appended context data, there will only ever be one
// instance of data within an ErrorContext stack
data ErrorData
// innr is the inner wrapped error in this structure, it is only accessible
// via .Unwrap() or via .Is()
innr error
// err is the top-level error in this wrapping structure, we identify
// as this error type via .Is() and return its error message
err error
}
func (e *errorContext) Error() string {
return e.err.Error()
}
func (e *errorContext) Is(err error) bool {
return Is(e.err, err) || Is(e.innr, err)
}
func (e *errorContext) Unwrap() error {
return e.innr
}
func (e *errorContext) Value(key string) (interface{}, bool) {
return e.data.Value(key)
}
func (e *errorContext) Append(kvs ...KV) ErrorContext {
e.data.Append(kvs...)
return e
}
func (e *errorContext) Data() ErrorData {
return e.data
}

View File

@@ -1,18 +0,0 @@
package errors
import "errors"
// Is wraps "errors".Is()
func Is(err, target error) bool {
return errors.Is(err, target)
}
// As wraps "errors".As()
func As(err error, target interface{}) bool {
return errors.As(err, target)
}
// Unwrap wraps "errors".Unwrap()
func Unwrap(err error) error {
return errors.Unwrap(err)
}

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 gruf
Copyright (c) 2022 gruf
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

5
vendor/codeberg.org/gruf/go-errors/v2/README.md generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# go-errors
simple but powerful errors library that allows easy wrapping and stacktracing of errors.
to disable stacktraces set the `notrace` build tag.

102
vendor/codeberg.org/gruf/go-errors/v2/callers.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
package errors
import (
"encoding/json"
"runtime"
"strconv"
"strings"
"unsafe"
)
// Callers is a stacktrace of caller PCs.
type Callers []uintptr
// GetCallers returns a Callers slice of PCs, of at most 'depth'.
func GetCallers(skip int, depth int) Callers {
rpc := make([]uintptr, depth)
n := runtime.Callers(skip+1, rpc)
return Callers(rpc[0:n])
}
// Frames fetches runtime frames for a slice of caller PCs.
func (f Callers) Frames() []runtime.Frame {
// Allocate expected frames slice
frames := make([]runtime.Frame, 0, len(f))
// Get frames iterator for PCs
iter := runtime.CallersFrames(f)
for {
// Get next frame in iter
frame, ok := iter.Next()
if !ok {
break
}
// Append to frames slice
frames = append(frames, frame)
}
return frames
}
// MarshalJSON implements json.Marshaler to provide an easy, simply default.
func (f Callers) MarshalJSON() ([]byte, error) {
// JSON-able frame type
type frame struct {
Func string `json:"func"`
File string `json:"file"`
Line int `json:"line"`
}
// Allocate expected frames slice
frames := make([]frame, 0, len(f))
// Get frames iterator for PCs
iter := runtime.CallersFrames(f)
for {
// Get next frame
f, ok := iter.Next()
if !ok {
break
}
// Append to frames slice
frames = append(frames, frame{
Func: funcname(f.Function),
File: f.File,
Line: f.Line,
})
}
// marshal converted frames
return json.Marshal(frames)
}
// String will return a simple string representation of receiving Callers slice.
func (f Callers) String() string {
// Guess-timate to reduce allocs
buf := make([]byte, 0, 64*len(f))
// Convert to frames
frames := f.Frames()
for i := 0; i < len(frames); i++ {
frame := frames[i]
// Append formatted caller info
funcname := funcname(frame.Function)
buf = append(buf, funcname+"()\n\t"+frame.File+":"...)
buf = strconv.AppendInt(buf, int64(frame.Line), 10)
buf = append(buf, '\n')
}
return *(*string)(unsafe.Pointer(&buf))
}
// funcname splits a function name with pkg from its path prefix.
func funcname(name string) string {
i := strings.LastIndex(name, "/")
return name[i+1:]
}

35
vendor/codeberg.org/gruf/go-errors/v2/error.go generated vendored Normal file
View File

@@ -0,0 +1,35 @@
//go:build !notrace
// +build !notrace
package errors
type errormsg struct {
msg string
wrap error
stack Callers
}
func create(msg string, wrap error) *errormsg {
return &errormsg{
msg: msg,
wrap: wrap,
stack: GetCallers(2, 10),
}
}
func (err *errormsg) Error() string {
return err.msg
}
func (err *errormsg) Is(target error) bool {
other, ok := target.(*errormsg)
return ok && (err.msg == other.msg)
}
func (err *errormsg) Unwrap() error {
return err.wrap
}
func (err *errormsg) Stacktrace() Callers {
return err.stack
}

33
vendor/codeberg.org/gruf/go-errors/v2/error_notrace.go generated vendored Normal file
View File

@@ -0,0 +1,33 @@
//go:build notrace
// +build notrace
package errors
type errormsg struct {
msg string
wrap error
}
func create(msg string, wrap error) *errormsg {
return &errormsg{
msg: msg,
wrap: wrap,
}
}
func (err *errormsg) Error() string {
return err.msg
}
func (err *errormsg) Is(target error) bool {
other, ok := target.(*errormsg)
return ok && (err.msg == other.msg)
}
func (err *errormsg) Unwrap() error {
return err.wrap
}
func (err *errormsg) Stacktrace() Callers {
return nil
}

36
vendor/codeberg.org/gruf/go-errors/v2/errors.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
package errors
import (
"fmt"
)
// New returns a new error created from message.
func New(msg string) error {
return create(msg, nil)
}
// Newf returns a new error created from message format and args.
func Newf(msgf string, args ...interface{}) error {
return create(fmt.Sprintf(msgf, args...), nil)
}
// Wrap will wrap supplied error within a new error created from message.
func Wrap(err error, msg string) error {
return create(msg, err)
}
// Wrapf will wrap supplied error within a new error created from message format and args.
func Wrapf(err error, msgf string, args ...interface{}) error {
return create(fmt.Sprintf(msgf, args...), err)
}
// Stacktrace fetches a stored stacktrace of callers from an error, or returns nil.
func Stacktrace(err error) Callers {
var callers Callers
if err, ok := err.(interface { //nolint
Stacktrace() Callers
}); ok {
callers = err.Stacktrace()
}
return callers
}

View File

@@ -5,19 +5,18 @@ import (
"unsafe"
)
// OnceError is an error structure that supports safe multi-threaded
// usage and setting only once (until reset)
type OnceError struct {
err unsafe.Pointer
}
// OnceError is an error structure that supports safe multi
// threaded usage and setting only once (until reset).
type OnceError struct{ err unsafe.Pointer }
// NewOnce returns a new OnceError instance
// NewOnce returns a new OnceError instance.
func NewOnce() OnceError {
return OnceError{
err: nil,
}
}
// Store will safely set the OnceError to value, no-op if nil.
func (e *OnceError) Store(err error) {
// Nothing to do
if err == nil {
@@ -32,14 +31,17 @@ func (e *OnceError) Store(err error) {
)
}
// Load will load the currently stored error.
func (e *OnceError) Load() error {
return *(*error)(atomic.LoadPointer(&e.err))
}
// IsSet returns whether OnceError has been set.
func (e *OnceError) IsSet() bool {
return (atomic.LoadPointer(&e.err) != nil)
}
// Reset will reset the OnceError value.
func (e *OnceError) Reset() {
atomic.StorePointer(&e.err, nil)
}

99
vendor/codeberg.org/gruf/go-errors/v2/standard.go generated vendored Normal file
View File

@@ -0,0 +1,99 @@
package errors
import (
"errors"
"reflect"
"codeberg.org/gruf/go-bitutil"
)
// Is reports whether any error in err's chain matches any of targets
// (up to a max of 64 targets).
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
func Is(err error, targets ...error) bool {
var flags bitutil.Flags64
if len(targets) > 64 {
panic("too many targets")
}
// Determine if each of targets are comparable
for i := 0; i < len(targets); {
// Drop nil errors
if targets[i] == nil {
targets = append(targets[:i], targets[i+1:]...)
continue
}
// Check if this error is directly comparable
if reflect.TypeOf(targets[i]).Comparable() {
flags = flags.Set(uint8(i))
}
i++
}
for err != nil {
var errorIs func(error) bool
// Check if this layer supports .Is interface
is, ok := err.(interface{ Is(error) bool })
if ok {
errorIs = is.Is
} else {
errorIs = neveris
}
for i := 0; i < len(targets); i++ {
// Try directly compare errors
if flags.Get(uint8(i)) &&
err == targets[i] {
return true
}
// Try use .Is() interface
if errorIs(targets[i]) {
return true
}
}
// Unwrap to next layer
err = errors.Unwrap(err)
}
return false
}
// As finds the first error in err's chain that matches target, and if one is found, sets
// target to that error value and returns true. Otherwise, it returns false.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// An error type might provide an As method so it can be treated as if it were a
// different error type.
//
// As panics if target is not a non-nil pointer to either a type that implements
// error, or to any interface type.
func As(err error, target interface{}) bool {
return errors.As(err, target)
}
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error. Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
return errors.Unwrap(err)
}
// neveris fits the .Is(error) bool interface function always returning false.
func neveris(error) bool { return false }