|
7 | 7 | "os/exec" |
8 | 8 | "path/filepath" |
9 | 9 | "reflect" |
| 10 | + "regexp" |
10 | 11 | "strconv" |
11 | 12 | "strings" |
12 | 13 | "time" |
@@ -287,6 +288,35 @@ func defaultConfig() Config { |
287 | 288 |
|
288 | 289 | var GlobalConfig = defaultConfig() |
289 | 290 |
|
| 291 | +// configFriendlyError maps a YAML error substring to a user-friendly hint. |
| 292 | +type configFriendlyError struct { |
| 293 | + substring string |
| 294 | + hint string |
| 295 | +} |
| 296 | + |
| 297 | +var knownConfigErrors = []configFriendlyError{ |
| 298 | + { |
| 299 | + substring: "cannot unmarshal !!map into string", |
| 300 | + hint: "string value is required, but a map was found. A value like {STRING} is interpreted as a YAML map, not a string. Use quotes (e.g. '{STRING}')", |
| 301 | + }, |
| 302 | +} |
| 303 | + |
| 304 | +var yamlLineRe = regexp.MustCompile(`line (\d+):`) |
| 305 | + |
| 306 | +func wrapConfigDecodeError(configPath string, err error) error { |
| 307 | + msg := err.Error() |
| 308 | + for _, known := range knownConfigErrors { |
| 309 | + if strings.Contains(msg, known.substring) { |
| 310 | + lineInfo := "" |
| 311 | + if m := yamlLineRe.FindStringSubmatch(msg); m != nil { |
| 312 | + lineInfo = fmt.Sprintf("line %s:", m[1]) |
| 313 | + } |
| 314 | + return fmt.Errorf("decode config file path %s failed: %s %s\nOriginal error: %w", configPath, lineInfo, known.hint, err) |
| 315 | + } |
| 316 | + } |
| 317 | + return fmt.Errorf("decode config file path %s failed: %w", configPath, err) |
| 318 | +} |
| 319 | + |
290 | 320 | func ParseFlags(args []string) error { |
291 | 321 | if len(args) < 2 { |
292 | 322 | return nil |
@@ -317,7 +347,7 @@ func ParseFlags(args []string) error { |
317 | 347 | decoder := yaml.NewDecoder(file) |
318 | 348 | err = decoder.Decode(&GlobalConfig) |
319 | 349 | if err != nil { |
320 | | - return fmt.Errorf("decode config file path %s failed: %w", GlobalConfig.ConfigPath, err) |
| 350 | + return wrapConfigDecodeError(GlobalConfig.ConfigPath, err) |
321 | 351 | } |
322 | 352 |
|
323 | 353 | return copyFlagsValue(&GlobalConfig.Options, result) |
|
0 commit comments