2019-08-02 22:58:08 +03:00
|
|
|
package includes
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
2023-01-03 18:54:04 +01:00
|
|
|
"os"
|
2019-08-02 22:58:08 +03:00
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
|
|
|
|
2022-10-19 16:43:12 +02:00
|
|
|
"gopkg.in/yaml.v3"
|
2019-08-02 22:58:08 +03:00
|
|
|
|
|
|
|
"github.com/reconquest/karma-go"
|
2020-11-03 17:12:51 +03:00
|
|
|
"github.com/reconquest/pkg/log"
|
2019-08-02 22:58:08 +03:00
|
|
|
)
|
|
|
|
|
2020-11-03 17:12:51 +03:00
|
|
|
// <!-- Include: <template path>
|
2023-01-03 18:54:04 +01:00
|
|
|
//
|
|
|
|
// (Delims: (none | "<left>","<right>"))?
|
|
|
|
// <optional yaml data> -->
|
2020-11-03 17:12:51 +03:00
|
|
|
var reIncludeDirective = regexp.MustCompile(
|
2022-06-07 10:16:24 +02:00
|
|
|
`(?s)` +
|
2022-06-07 14:21:11 +06:00
|
|
|
`<!--\s*Include:\s*(?P<template>.+?)\s*` +
|
|
|
|
`(?:\n\s*Delims:\s*(?:(none|"(?P<left>.*?)"\s*,\s*"(?P<right>.*?)")))?\s*` +
|
|
|
|
`(?:\n(?P<config>.*?))?-->`,
|
2022-06-07 10:16:24 +02:00
|
|
|
)
|
2019-08-02 22:58:08 +03:00
|
|
|
|
|
|
|
func LoadTemplate(
|
2022-02-02 18:02:01 +08:00
|
|
|
base string,
|
2023-10-17 12:53:10 +02:00
|
|
|
includePath string,
|
2019-08-02 22:58:08 +03:00
|
|
|
path string,
|
2022-06-07 10:16:24 +02:00
|
|
|
left string,
|
|
|
|
right string,
|
2019-08-02 22:58:08 +03:00
|
|
|
templates *template.Template,
|
2019-08-08 15:54:03 +03:00
|
|
|
) (*template.Template, error) {
|
2019-08-02 22:58:08 +03:00
|
|
|
var (
|
|
|
|
name = strings.TrimSuffix(path, filepath.Ext(path))
|
|
|
|
facts = karma.Describe("name", name)
|
|
|
|
)
|
|
|
|
|
|
|
|
if template := templates.Lookup(name); template != nil {
|
2019-08-08 15:54:03 +03:00
|
|
|
return template, nil
|
2019-08-02 22:58:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var body []byte
|
|
|
|
|
2023-01-03 18:54:04 +01:00
|
|
|
body, err := os.ReadFile(filepath.Join(base, path))
|
2019-08-02 22:58:08 +03:00
|
|
|
if err != nil {
|
2023-10-17 12:53:10 +02:00
|
|
|
if includePath != "" {
|
|
|
|
body, err = os.ReadFile(filepath.Join(includePath, path))
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
err = facts.Format(
|
|
|
|
err,
|
|
|
|
"unable to read template file",
|
|
|
|
)
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-08-02 22:58:08 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-11-08 20:15:59 +06:00
|
|
|
body = bytes.ReplaceAll(
|
|
|
|
body,
|
|
|
|
[]byte("\r\n"),
|
|
|
|
[]byte("\n"),
|
|
|
|
)
|
|
|
|
|
2022-06-07 10:16:24 +02:00
|
|
|
templates, err = templates.New(name).Delims(left, right).Parse(string(body))
|
2019-08-02 22:58:08 +03:00
|
|
|
if err != nil {
|
|
|
|
err = facts.Format(
|
|
|
|
err,
|
|
|
|
"unable to parse template",
|
|
|
|
)
|
|
|
|
|
2019-08-08 15:54:03 +03:00
|
|
|
return nil, err
|
2019-08-02 22:58:08 +03:00
|
|
|
}
|
|
|
|
|
2019-08-08 15:54:03 +03:00
|
|
|
return templates, nil
|
2019-08-02 22:58:08 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func ProcessIncludes(
|
2022-02-02 18:02:01 +08:00
|
|
|
base string,
|
2023-10-17 12:53:10 +02:00
|
|
|
includePath string,
|
2019-08-02 22:58:08 +03:00
|
|
|
contents []byte,
|
|
|
|
templates *template.Template,
|
|
|
|
) (*template.Template, []byte, bool, error) {
|
|
|
|
vardump := func(
|
|
|
|
facts *karma.Context,
|
|
|
|
data map[string]interface{},
|
|
|
|
) *karma.Context {
|
|
|
|
for key, value := range data {
|
|
|
|
key = "var " + key
|
|
|
|
facts = facts.Describe(
|
|
|
|
key,
|
|
|
|
strings.ReplaceAll(
|
|
|
|
fmt.Sprint(value),
|
|
|
|
"\n",
|
|
|
|
"\n"+strings.Repeat(" ", len(key)+2),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return facts
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
recurse bool
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
contents = reIncludeDirective.ReplaceAllFunc(
|
|
|
|
contents,
|
|
|
|
func(spec []byte) []byte {
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
groups := reIncludeDirective.FindSubmatch(spec)
|
|
|
|
|
|
|
|
var (
|
2022-06-07 14:21:11 +06:00
|
|
|
path = string(groups[1])
|
|
|
|
delimsNone = string(groups[2])
|
|
|
|
left = string(groups[3])
|
|
|
|
right = string(groups[4])
|
|
|
|
config = groups[5]
|
|
|
|
data = map[string]interface{}{}
|
2019-08-02 22:58:08 +03:00
|
|
|
|
|
|
|
facts = karma.Describe("path", path)
|
|
|
|
)
|
2022-06-07 14:21:11 +06:00
|
|
|
|
|
|
|
if delimsNone == "none" {
|
2022-06-07 10:16:24 +02:00
|
|
|
left = "\x00"
|
|
|
|
right = "\x01"
|
|
|
|
}
|
2022-06-07 14:21:11 +06:00
|
|
|
|
2019-08-02 22:58:08 +03:00
|
|
|
err = yaml.Unmarshal(config, &data)
|
|
|
|
if err != nil {
|
|
|
|
err = facts.
|
|
|
|
Describe("config", string(config)).
|
|
|
|
Format(
|
|
|
|
err,
|
|
|
|
"unable to unmarshal template data config",
|
|
|
|
)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Tracef(vardump(facts, data), "including template %q", path)
|
|
|
|
|
2023-10-17 12:53:10 +02:00
|
|
|
templates, err = LoadTemplate(base, includePath, path, left, right, templates)
|
2019-08-02 22:58:08 +03:00
|
|
|
if err != nil {
|
|
|
|
err = facts.Format(err, "unable to load template")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var buffer bytes.Buffer
|
|
|
|
|
2019-08-08 15:54:03 +03:00
|
|
|
err = templates.Execute(&buffer, data)
|
2019-08-02 22:58:08 +03:00
|
|
|
if err != nil {
|
|
|
|
err = vardump(facts, data).Format(
|
|
|
|
err,
|
|
|
|
"unable to execute template",
|
|
|
|
)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
recurse = true
|
|
|
|
|
|
|
|
return buffer.Bytes()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
return templates, contents, recurse, err
|
|
|
|
}
|