-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunc_compatible.go
More file actions
93 lines (79 loc) · 2.75 KB
/
Copy pathfunc_compatible.go
File metadata and controls
93 lines (79 loc) · 2.75 KB
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
package xerror
import (
"errors"
"fmt"
"strings"
"github.com/gomooth/xerror/xcode"
)
// 兼容函数:提供与 pkg/errors 类似的函数签名。
//
// 注意:本组函数均通过 Wrap 实现,返回 XError 接口而非 error,
// 可使用 XError 的所有方法。Errorf 支持 %w 格式化动词。
// Errorf 格式化创建错误。支持 %w 包装动词,与 Go 1.13+ fmt.Errorf 行为一致。
func Errorf(format string, args ...any) XError {
if !strings.Contains(format, "%w") {
return New(fmt.Sprintf(format, args...))
}
// 支持 %w:使用 fmt.Errorf 创建链式错误,再包装为 XError
wrapped := fmt.Errorf(format, args...)
inner := errors.Unwrap(wrapped)
if inner == nil {
return New(wrapped.Error())
}
// 提取包装消息(去掉内部错误部分)
innerMsg := inner.Error()
fullMsg := wrapped.Error()
prefix := extractWrapPrefix(fullMsg, innerMsg)
if prefix == "" {
// %w 在开头或仅 %w:fullMsg 已包含内层消息,直接作为 chainMsg 避免重复
code := xcode.NewMessage(fullMsg)
var inheritedFields []Field
if xe, ok := asXErrorInternal(inner); ok {
inheritedFields = fieldsOf(xe)
}
return newWrapXError(inner, code, fullMsg, inheritedFields, captureStack(1))
}
return Wrap(inner, prefix)
}
// extractWrapPrefix 从 fmt.Errorf 生成的完整消息中提取包装前缀。
// fmt.Errorf("prefix: %w", inner) 产生 "prefix: innerMsg",
// 我们需要分离出 "prefix"。
// 使用 LastIndex 而非 HasSuffix,避免 innerMsg 含 ": " 时错误匹配。
//
// 边界行为:
// - innerMsg 为空:suffix = ": ",LastIndex 可能返回 0,得到空前缀
// - fullMsg == innerMsg:HasPrefix 匹配,返回空字符串
// - innerMsg 含 ": ":LastIndex 保证匹配最后出现的 ": ",避免误截
// - %w 在开头:fullMsg 以 innerMsg 开头,返回空字符串
func extractWrapPrefix(fullMsg, innerMsg string) string {
suffix := ": " + innerMsg
if idx := strings.LastIndex(fullMsg, suffix); idx >= 0 {
return fullMsg[:idx]
}
// %w 在开头:fullMsg 以 innerMsg 开头,无前缀
if strings.HasPrefix(fullMsg, innerMsg) {
return ""
}
// 非标准 ": " 分隔符:完整消息即为前缀
return fullMsg
}
func Wrapf(err error, format string, args ...any) XError {
if nil == err {
return nil
}
return Wrap(err, fmt.Sprintf(format, args...))
}
// WithMessage 为错误添加消息,等同于 Wrap(err, message)。
func WithMessage(err error, message string) XError {
if nil == err {
return nil
}
return Wrap(err, message)
}
// WithMessagef 为错误添加格式化消息,等同于 Wrapf(err, format, args...)。
func WithMessagef(err error, format string, args ...any) XError {
if nil == err {
return nil
}
return Wrap(err, fmt.Sprintf(format, args...))
}