143 lines
3.7 KiB
Go
143 lines
3.7 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
"text/template"
|
||
|
"text/template/parse"
|
||
|
)
|
||
|
|
||
|
func extractIncludes(tmpl *template.Template) []string {
|
||
|
var includes []string
|
||
|
for _, node := range tmpl.Root.Nodes {
|
||
|
if n, ok := node.(*parse.TemplateNode); ok {
|
||
|
includes = append(includes, n.Name)
|
||
|
}
|
||
|
}
|
||
|
return includes
|
||
|
}
|
||
|
|
||
|
func absolutePath(root, fn string) (string, error) {
|
||
|
pwd, err := filepath.Abs(fn)
|
||
|
if err != nil {
|
||
|
return "", fmt.Errorf("cannot determine absolute location of %q: %w", fn, err)
|
||
|
}
|
||
|
pwd, err = filepath.Rel(root, filepath.Dir(pwd))
|
||
|
if err != nil {
|
||
|
return "", fmt.Errorf("cannot determine location of %q relative to %q: %w", pwd, root, err)
|
||
|
}
|
||
|
return string(filepath.Separator) + pwd, nil
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
// Estimate Telegraf root to be able to handle absolute paths
|
||
|
cwd, err := os.Getwd()
|
||
|
if err != nil {
|
||
|
log.Fatalf("Cannot get working directory: %v", err)
|
||
|
}
|
||
|
cwd, err = filepath.Abs(cwd)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Cannot resolve working directory: %v", err)
|
||
|
}
|
||
|
|
||
|
var root string
|
||
|
idx := strings.LastIndex(cwd, filepath.FromSlash("/plugins/"))
|
||
|
if idx <= 0 {
|
||
|
log.Fatalln("Cannot determine include root!")
|
||
|
}
|
||
|
root = cwd[:idx]
|
||
|
|
||
|
var parent, inputFilename, outputFilename string
|
||
|
switch len(os.Args) {
|
||
|
case 1:
|
||
|
parent = strings.TrimPrefix(filepath.ToSlash(cwd[idx:]), "/plugins/")
|
||
|
parent = strings.ReplaceAll(parent, "/", ".")
|
||
|
inputFilename = "sample.conf.in"
|
||
|
outputFilename = "sample.conf"
|
||
|
case 2:
|
||
|
parent = os.Args[1]
|
||
|
inputFilename = "sample.conf.in"
|
||
|
outputFilename = "sample.conf"
|
||
|
case 3:
|
||
|
parent = os.Args[1]
|
||
|
inputFilename = os.Args[2]
|
||
|
if !strings.HasSuffix(inputFilename, ".in") {
|
||
|
log.Fatalf("Template filename %q does not have '.in' suffix!", inputFilename)
|
||
|
}
|
||
|
outputFilename = strings.TrimSuffix(inputFilename, ".in")
|
||
|
case 4:
|
||
|
parent = os.Args[1]
|
||
|
inputFilename = os.Args[2]
|
||
|
outputFilename = os.Args[3]
|
||
|
default:
|
||
|
log.Fatalln("Invalid number of arguments")
|
||
|
}
|
||
|
|
||
|
roottmpl := template.New(inputFilename)
|
||
|
known := make(map[string]bool)
|
||
|
inroot, err := absolutePath(root, inputFilename)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
unresolved := map[string]string{inputFilename: filepath.Join(inroot, inputFilename)}
|
||
|
for {
|
||
|
if len(unresolved) == 0 {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
newUnresolved := make(map[string]string)
|
||
|
for name, fn := range unresolved {
|
||
|
if strings.HasPrefix(filepath.ToSlash(fn), "/") {
|
||
|
fn = filepath.Join(root, fn)
|
||
|
}
|
||
|
|
||
|
if known[name] {
|
||
|
// Include already resolved, skipping
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
tmpl, err := template.ParseFiles(fn)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Reading template %q failed: %v", fn, err)
|
||
|
}
|
||
|
known[name] = true
|
||
|
if _, err := roottmpl.AddParseTree(name, tmpl.Tree); err != nil {
|
||
|
log.Fatalf("Adding include %q failed: %v", fn, err)
|
||
|
}
|
||
|
|
||
|
// For relative paths we need to make it relative to the include
|
||
|
pwd, err := filepath.Abs(fn)
|
||
|
if err != nil {
|
||
|
log.Fatalf("Cannot determine absolute location of %q: %v", fn, err)
|
||
|
}
|
||
|
pwd, err = filepath.Rel(root, filepath.Dir(pwd))
|
||
|
if err != nil {
|
||
|
log.Fatalf("Cannot determine location of %q relative to %q: %v", pwd, root, err)
|
||
|
}
|
||
|
pwd = string(filepath.Separator) + pwd
|
||
|
for _, iname := range extractIncludes(tmpl) {
|
||
|
if !strings.HasPrefix(iname, "/") {
|
||
|
newUnresolved[iname] = filepath.Join(pwd, iname)
|
||
|
} else {
|
||
|
newUnresolved[iname] = iname
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
unresolved = newUnresolved
|
||
|
}
|
||
|
|
||
|
defines := map[string]string{"parent": parent}
|
||
|
var buf bytes.Buffer
|
||
|
if err := roottmpl.Execute(&buf, defines); err != nil {
|
||
|
log.Fatalf("Executing template failed: %v", err)
|
||
|
}
|
||
|
|
||
|
if err := os.WriteFile(outputFilename, buf.Bytes(), 0640); err != nil {
|
||
|
log.Fatalf("Writing output %q failed: %v", outputFilename, err)
|
||
|
}
|
||
|
}
|