aboutsummaryrefslogtreecommitdiffstats
path: root/modules/templates
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2023-03-20 20:56:48 +0000
committerGitHub <noreply@github.com>2023-03-20 15:56:48 -0500
commit8f3aaef3747e8c656cfe2562996dc1806b4d8a0f (patch)
treeb5bd7187bcaee6b7d47d9250a1c947a2fa4057e8 /modules/templates
parent529bac1950adf4fb72433cb67f66b0eec49224fe (diff)
downloadgitea-8f3aaef3747e8c656cfe2562996dc1806b4d8a0f.tar.gz
gitea-8f3aaef3747e8c656cfe2562996dc1806b4d8a0f.zip
Improve template error reporting (#23396)
There are multiple duplicate reports of errors during template rendering due to broken custom templates. Unfortunately the error returned here is somewhat difficult for users to understand and it doesn't return the context of the error. This PR attempts to parse the error returned by the template renderer to add in some further context including the filename of the template AND the preceding lines within that template file. Ref #23274 --------- Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'modules/templates')
-rw-r--r--modules/templates/htmlrenderer.go43
1 files changed, 25 insertions, 18 deletions
diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go
index 5a328043eb..96dc010796 100644
--- a/modules/templates/htmlrenderer.go
+++ b/modules/templates/htmlrenderer.go
@@ -118,7 +118,7 @@ func handleGenericTemplateError(err error) (string, []interface{}) {
lineNumber, _ := strconv.Atoi(lineNumberStr)
- line := getLineFromAsset(templateName, lineNumber, "")
+ line := GetLineFromTemplate(templateName, lineNumber, "", -1)
return "PANIC: Unable to compile templates!\n%s in template file %s at line %d:\n\n%s\nStacktrace:\n\n%s", []interface{}{message, filename, lineNumber, log.NewColoredValue(line, log.Reset), log.Stack(2)}
}
@@ -140,7 +140,7 @@ func handleNotDefinedPanicError(err error) (string, []interface{}) {
lineNumber, _ := strconv.Atoi(lineNumberStr)
- line := getLineFromAsset(templateName, lineNumber, functionName)
+ line := GetLineFromTemplate(templateName, lineNumber, functionName, -1)
return "PANIC: Unable to compile templates!\nUndefined function %q in template file %s at line %d:\n\n%s", []interface{}{functionName, filename, lineNumber, log.NewColoredValue(line, log.Reset)}
}
@@ -161,7 +161,7 @@ func handleUnexpected(err error) (string, []interface{}) {
lineNumber, _ := strconv.Atoi(lineNumberStr)
- line := getLineFromAsset(templateName, lineNumber, unexpected)
+ line := GetLineFromTemplate(templateName, lineNumber, unexpected, -1)
return "PANIC: Unable to compile templates!\nUnexpected %q in template file %s at line %d:\n\n%s", []interface{}{unexpected, filename, lineNumber, log.NewColoredValue(line, log.Reset)}
}
@@ -181,14 +181,15 @@ func handleExpectedEnd(err error) (string, []interface{}) {
lineNumber, _ := strconv.Atoi(lineNumberStr)
- line := getLineFromAsset(templateName, lineNumber, unexpected)
+ line := GetLineFromTemplate(templateName, lineNumber, unexpected, -1)
return "PANIC: Unable to compile templates!\nMissing end with unexpected %q in template file %s at line %d:\n\n%s", []interface{}{unexpected, filename, lineNumber, log.NewColoredValue(line, log.Reset)}
}
const dashSeparator = "----------------------------------------------------------------------\n"
-func getLineFromAsset(templateName string, targetLineNum int, target string) string {
+// GetLineFromTemplate returns a line from a template with some context
+func GetLineFromTemplate(templateName string, targetLineNum int, target string, position int) string {
bs, err := GetAsset("templates/" + templateName + ".tmpl")
if err != nil {
return fmt.Sprintf("(unable to read template file: %v)", err)
@@ -229,23 +230,29 @@ func getLineFromAsset(templateName string, targetLineNum int, target string) str
// If there is a provided target to look for in the line add a pointer to it
// e.g. ^^^^^^^
if target != "" {
- idx := bytes.Index(lineBs, []byte(target))
-
- if idx >= 0 {
- // take the current line and replace preceding text with whitespace (except for tab)
- for i := range lineBs[:idx] {
- if lineBs[i] != '\t' {
- lineBs[i] = ' '
- }
+ targetPos := bytes.Index(lineBs, []byte(target))
+ if targetPos >= 0 {
+ position = targetPos
+ }
+ }
+ if position >= 0 {
+ // take the current line and replace preceding text with whitespace (except for tab)
+ for i := range lineBs[:position] {
+ if lineBs[i] != '\t' {
+ lineBs[i] = ' '
}
+ }
- // write the preceding "space"
- _, _ = sb.Write(lineBs[:idx])
+ // write the preceding "space"
+ _, _ = sb.Write(lineBs[:position])
- // Now write the ^^ pointer
- _, _ = sb.WriteString(strings.Repeat("^", len(target)))
- _ = sb.WriteByte('\n')
+ // Now write the ^^ pointer
+ targetLen := len(target)
+ if targetLen == 0 {
+ targetLen = 1
}
+ _, _ = sb.WriteString(strings.Repeat("^", targetLen))
+ _ = sb.WriteByte('\n')
}
// Finally write the footer