telegraf/tools/generate_plugindata/main.go

158 lines
3.7 KiB
Go
Raw Normal View History

// generate_plugindata is a tool used to inject the sample configuration into all the plugins
// It extracts the sample configuration from the plugins README.md
// Then using the file plugin_name_sample_config.go as a template, and will be updated with the sample configuration
// This tool is then also used to revert these changes with the `--clean` flag
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"log" //nolint:revive
"os"
"strings"
"text/template"
"github.com/yuin/goldmark"
gast "github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/text"
)
func createSourceName(packageName string) string {
return fmt.Sprintf("%s_sample_config.go", packageName)
}
// extractPluginData reads the README.md to get the sample configuration
func extractPluginData() (string, error) {
readMe, err := os.ReadFile("README.md")
if err != nil {
return "", err
}
p := goldmark.DefaultParser()
r := text.NewReader(readMe)
root := p.Parse(r)
var currentSection string
for n := root.FirstChild(); n != nil; n = n.NextSibling() {
switch tok := n.(type) {
case *gast.Heading:
if tok.FirstChild() != nil {
currentSection = string(tok.FirstChild().Text(readMe))
}
case *gast.FencedCodeBlock:
if currentSection == "Configuration" && string(tok.Language(readMe)) == "toml" {
var config []byte
for i := 0; i < tok.Lines().Len(); i++ {
line := tok.Lines().At(i)
config = append(config, line.Value(readMe)...)
}
return string(config), nil
}
}
}
fmt.Printf("No configuration found for plugin: %s\n", os.Getenv("GOPACKAGE"))
return "", nil
}
// generatePluginData parses the main source file of the plugin as a template and updates it with the sample configuration
// The original source file is saved so that these changes can be reverted
func generatePluginData(packageName string, sampleConfig string) error {
sourceName := createSourceName(packageName)
plugin, err := os.ReadFile(sourceName)
if err != nil {
return err
}
generatedTemplate := template.Must(template.New("").Parse(string(plugin)))
f, err := os.Create(sourceName)
if err != nil {
return err
}
defer f.Close()
err = generatedTemplate.Execute(f, struct {
SampleConfig string
}{
SampleConfig: sampleConfig,
})
if err != nil {
return err
}
return nil
}
var newSampleConfigFunc = ` return ` + "`{{ .SampleConfig }}`\n"
// cleanGeneratedFiles will revert the changes made by generatePluginData
func cleanGeneratedFiles(packageName string) error {
sourceName := createSourceName(packageName)
sourcefile, err := os.Open(sourceName)
if err != nil {
return err
}
defer sourcefile.Close()
var c []byte
buf := bytes.NewBuffer(c)
scanner := bufio.NewScanner(sourcefile)
var sampleconfigSection bool
for scanner.Scan() {
if sampleconfigSection && strings.TrimSpace(scanner.Text()) == "}" {
sampleconfigSection = false
if _, err := buf.Write([]byte(newSampleConfigFunc)); err != nil {
return err
}
}
if !sampleconfigSection {
if _, err := buf.Write(scanner.Bytes()); err != nil {
return err
}
if _, err = buf.WriteString("\n"); err != nil {
return err
}
}
if !sampleconfigSection && strings.Contains(scanner.Text(), "SampleConfig() string") {
sampleconfigSection = true
}
}
err = os.WriteFile(sourceName, buf.Bytes(), 0664)
if err != nil {
return err
}
return nil
}
func main() {
clean := flag.Bool("clean", false, "Remove generated files")
flag.Parse()
goPackage := os.Getenv("GOPACKAGE")
if *clean {
err := cleanGeneratedFiles(goPackage)
if err != nil {
log.Fatal(err)
}
} else {
s, err := extractPluginData()
if err != nil {
log.Fatal(err)
}
err = generatePluginData(goPackage, s)
if err != nil {
log.Fatal(err)
}
}
}