reformatExecErrorMsg takes an error message for template rendering and formats it into a formatted multi-line error string
(filename string, err error)
| 450 | // reformatExecErrorMsg takes an error message for template rendering and formats it into a formatted |
| 451 | // multi-line error string |
| 452 | func reformatExecErrorMsg(filename string, err error) error { |
| 453 | // This function parses the error message produced by text/template package. |
| 454 | // If it can parse out details from that error message such as the line number, template it failed on, |
| 455 | // and error description, then it will construct a new error that displays these details in a structured way. |
| 456 | // If there are issues with parsing the error message, the err passed into the function should return instead. |
| 457 | var execError template.ExecError |
| 458 | if !errors.As(err, &execError) { |
| 459 | return err |
| 460 | } |
| 461 | |
| 462 | tokens := strings.SplitN(err.Error(), ": ", 3) |
| 463 | if len(tokens) != 3 { |
| 464 | // This might happen if a non-templating error occurs |
| 465 | return fmt.Errorf("execution error in (%s): %w", filename, err) |
| 466 | } |
| 467 | |
| 468 | // The first token is "template" |
| 469 | // The second token is either "filename:lineno" or "filename:lineNo:columnNo" |
| 470 | location := tokens[1] |
| 471 | |
| 472 | parts := warnRegex.FindStringSubmatch(tokens[2]) |
| 473 | if len(parts) >= 2 { |
| 474 | return fmt.Errorf("execution error at (%s): %s", location, parts[1]) |
| 475 | } |
| 476 | current := err |
| 477 | var fileLocations []TraceableError |
| 478 | for current != nil { |
| 479 | if tr, ok := parseTemplateExecErrorString(current.Error()); ok { |
| 480 | if len(fileLocations) == 0 || fileLocations[len(fileLocations)-1] != tr { |
| 481 | fileLocations = append(fileLocations, tr) |
| 482 | } |
| 483 | } else { |
| 484 | return err |
| 485 | } |
| 486 | current = errors.Unwrap(current) |
| 487 | } |
| 488 | |
| 489 | var finalErrorString strings.Builder |
| 490 | for _, fileLocation := range fileLocations { |
| 491 | _, _ = fmt.Fprintf(&finalErrorString, "%s", fileLocation.String()) |
| 492 | } |
| 493 | |
| 494 | return errors.New(strings.TrimSpace(finalErrorString.String())) |
| 495 | } |
| 496 | |
| 497 | func sortTemplates(tpls map[string]renderable) []string { |
| 498 | keys := make([]string, len(tpls)) |
no test coverage detected
searching dependent graphs…