chore: Embed sample configurations into README for aggregators (#11190)

This commit is contained in:
Sven Rebhan 2022-05-25 18:25:51 +02:00 committed by GitHub
parent e04d62dd16
commit 1b0bf3579b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 176 additions and 457 deletions

View File

@ -119,25 +119,18 @@ versioninfo:
build_generator:
go build -o ./tools/readme_config_includer/generator ./tools/readme_config_includer/generator.go
insert_config_to_readme_%: build_generator
embed_readme_%: build_generator
go generate -run="readme_config_includer/generator$$" ./plugins/$*/...
generate_plugins_%: build_generator
go generate -run="plugindata/main.go$$" ./plugins/$*/...
.PHONY: generate
generate: insert_config_to_readme_inputs insert_config_to_readme_outputs insert_config_to_readme_processors generate_plugins_aggregators
.PHONY: generate-clean
generate-clean:
go generate -run="plugindata/main.go --clean" ./plugins/aggregators/...
generate: embed_readme_inputs embed_readme_outputs embed_readme_processors embed_readme_aggregators
.PHONY: build
build:
go build -ldflags "$(LDFLAGS)" ./cmd/telegraf
.PHONY: telegraf
telegraf: generate build generate-clean
telegraf: generate build
# Used by dockerfile builds
.PHONY: go-install
@ -340,7 +333,7 @@ darwin-arm64:
include_packages := $(mips) $(mipsel) $(arm64) $(amd64) $(static) $(armel) $(armhf) $(riscv64) $(s390x) $(ppc64le) $(i386) $(windows) $(darwin-amd64) $(darwin-arm64)
.PHONY: package
package: generate $(include_packages) generate-clean
package: generate $(include_packages)
.PHONY: $(include_packages)
$(include_packages):

View File

@ -9,10 +9,11 @@ This section is for developers who want to create a new aggregator plugin.
register themselves. See below for a quick example.
* To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdata/telegraf/plugins/aggregators/all/all.go` file.
* Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
This file is automatically updated during the build process to include the sample configuration from the `README.md`.
* Each plugin requires a file called `sample.conf` containing the sample configuration
for the plugin in TOML format.
Please consult the [Sample Config][] page for the latest style guidelines.
* Each plugin `README.md` file should include the `sample.conf` file in a section
describing the configuration by specifying a `toml` section in the form `toml @sample.conf`. The specified file(s) are then injected automatically into the Readme.
* The Aggregator plugin will need to keep caches of metrics that have passed
through it. This should be done using the builtin `HashID()` function of
each metric.
@ -22,17 +23,22 @@ This section is for developers who want to create a new aggregator plugin.
### Aggregator Plugin Example
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
//go:generate ../../../tools/readme_config_includer/generator
package min
// min.go
import (
_ "embed"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Min struct {
// caches for metric fields, names, and tags
fieldCache map[uint64]map[string]float64
@ -46,6 +52,10 @@ func NewMin() telegraf.Aggregator {
return m
}
func (*Min) SampleConfig() string {
return sampleConfig
}
func (m *Min) Init() error {
return nil
}
@ -112,20 +122,3 @@ func init() {
})
}
```
### Sample Configuration Template
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
[telegraf.Aggregator]: https://godoc.org/github.com/influxdata/telegraf#Aggregator
[Sample Config]: https://github.com/influxdata/telegraf/blob/master/docs/developers/SAMPLE_CONFIG.md
[Code Style]: https://github.com/influxdata/telegraf/blob/master/docs/developers/CODE_STYLE.md

View File

@ -15,10 +15,11 @@ and submit new inputs.
themselves. See below for a quick example.
- Input Plugins must be added to the
`github.com/influxdata/telegraf/plugins/inputs/all/all.go` file.
- Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
This file is automatically updated during the build process to include the sample configuration from the `README.md`.
- Each plugin requires a file called `sample.conf` containing the sample
configuration for the plugin in TOML format.
Please consult the [Sample Config][] page for the latest style guidelines.
- Each plugin `README.md` file should include the `sample.conf` file in a section
describing the configuration by specifying a `toml` section in the form `toml @sample.conf`. The specified file(s) are then injected automatically into the Readme.
- Follow the recommended [Code Style][].
Let's say you've written a plugin that emits metrics about processes on the
@ -27,20 +28,29 @@ current host.
## Input Plugin Example
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
//go:generate ../../../tools/readme_config_includer/generator
package simple
import (
_ "embed"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/inputs"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Simple struct {
Ok bool `toml:"ok"`
Log telegraf.Logger `toml:"-"`
}
func (*Simple) SampleConfig() string {
return sampleConfig
}
// Init is for setup, and validating config.
func (s *Simple) Init() error {
return nil
@ -61,17 +71,6 @@ func init() {
}
```
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
### Development
- Run `make static` followed by `make plugin-[pluginName]` to spin up a docker

View File

@ -11,31 +11,41 @@ similar constructs.
themselves. See below for a quick example.
- To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdata/telegraf/plugins/outputs/all/all.go` file.
- Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
This file is automatically updated during the build process to include the sample configuration from the `README.md`.
- Each plugin requires a file called `sample.conf` containing the sample
configuration for the plugin in TOML format.
Please consult the [Sample Config][] page for the latest style guidelines.
- Each plugin `README.md` file should include the `sample.conf` file in a section
describing the configuration by specifying a `toml` section in the form `toml @sample.conf`. The specified file(s) are then injected automatically into the Readme.
- Follow the recommended [Code Style][].
## Output Plugin Example
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
//go:generate ../../../tools/readme_config_includer/generator
package simpleoutput
// simpleoutput.go
import (
_ "embed"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/outputs"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Simple struct {
Ok bool `toml:"ok"`
Log telegraf.Logger `toml:"-"`
}
func (*Simple) SampleConfig() string {
return sampleConfig
}
// Init is for setup, and validating config.
func (s *Simple) Init() error {
return nil
@ -68,19 +78,6 @@ func init() {
```
### Sample Configuration Template
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
## Data Formats
Some output plugins, such as the [file][] plugin, can write in any supported

View File

@ -9,32 +9,41 @@ This section is for developers who want to create a new processor plugin.
themselves. See below for a quick example.
* To be available within Telegraf itself, plugins must add themselves to the
`github.com/influxdata/telegraf/plugins/processors/all/all.go` file.
* Each plugin requires a file called `<plugin_name>_sample_config.go`, where `<plugin_name>` is replaced with the actual plugin name.
Copy the [example template](#sample-configuration-template) into this file, also updating `<plugin_name>` were appropriate.
This file is automatically updated during the build process to include the sample configuration from the `README.md`.
* Each plugin requires a file called `sample.conf` containing the sample
configuration for the plugin in TOML format.
Please consult the [Sample Config][] page for the latest style guidelines.
* Each plugin `README.md` file should include the `sample.conf` file in a section
describing the configuration by specifying a `toml` section in the form `toml @sample.conf`. The specified file(s) are then injected automatically into the Readme.
* Follow the recommended [Code Style][].
## Processor Plugin Example
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
//go:generate ../../../tools/readme_config_includer/generator
package printer
// printer.go
import (
_ "embed"
"fmt"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Printer struct {
Log telegraf.Logger `toml:"-"`
}
func (*Printer) SampleConfig() string {
return sampleConfig
}
// Init is for setup, and validating config.
func (p *Printer) Init() error {
return nil
@ -54,19 +63,6 @@ func init() {
}
```
### Sample Configuration Template
```go
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package <plugin_package>
func (k *<plugin_struct>) SampleConfig() string {
return `{{ .SampleConfig }}`
}
```
## Streaming Processors
Streaming processors are a new processor type available to you. They are
@ -88,21 +84,31 @@ Some differences from classic Processors:
## Streaming Processor Example
```go
//go:generate ../../../tools/readme_config_includer/generator
package printer
// printer.go
import (
_ "embed"
"fmt"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Printer struct {
Log telegraf.Logger `toml:"-"`
}
func (*Printer) SampleConfig() string {
return sampleConfig
}
// Init is for setup, and validating config.
func (p *Printer) Init() error {
return nil

View File

@ -5,7 +5,7 @@ emitting the aggregate every `period` seconds.
## Configuration
```toml
```toml @sample.conf
# Keep the aggregate basicstats of each metric passing through.
[[aggregators.basicstats]]
## The period on which to flush & clear the aggregator.

View File

@ -1,6 +1,8 @@
//go:generate ../../../tools/readme_config_includer/generator
package basicstats
import (
_ "embed"
"math"
"time"
@ -8,6 +10,10 @@ import (
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type BasicStats struct {
Stats []string `toml:"stats"`
Log telegraf.Logger
@ -57,6 +63,10 @@ type basicstats struct {
TIME time.Time //intermediate value for rate
}
func (*BasicStats) SampleConfig() string {
return sampleConfig
}
func (b *BasicStats) Add(in telegraf.Metric) {
id := in.HashID()
if _, ok := b.cache[id]; !ok {

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package basicstats
func (*BasicStats) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -137,7 +137,7 @@ Using `max_roll_over` with a value greater 0 may be important, if you need to de
## Configuration
```toml
```toml @sample.conf
# Calculates a derivative for every field.
[[aggregators.derivative]]
## Specific Derivative Aggregator Arguments:

View File

@ -1,6 +1,8 @@
//go:generate ../../../tools/readme_config_includer/generator
package derivative
import (
_ "embed"
"strings"
"time"
@ -8,6 +10,10 @@ import (
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Derivative struct {
Variable string `toml:"variable"`
Suffix string `toml:"suffix"`
@ -38,6 +44,10 @@ func NewDerivative() *Derivative {
return derivative
}
func (*Derivative) SampleConfig() string {
return sampleConfig
}
func (d *Derivative) Add(in telegraf.Metric) {
id := in.HashID()
current, ok := d.cache[id]

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package derivative
func (d *Derivative) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -13,7 +13,7 @@ When a series has not been updated within the time defined in
## Configuration
```toml
```toml @sample.conf
# Report the final metric of a series
[[aggregators.final]]
## The period on which to flush & clear the aggregator.

View File

@ -1,6 +1,8 @@
//go:generate ../../../tools/readme_config_includer/generator
package final
import (
_ "embed"
"time"
"github.com/influxdata/telegraf"
@ -8,6 +10,10 @@ import (
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Final struct {
SeriesTimeout config.Duration `toml:"series_timeout"`
@ -22,6 +28,10 @@ func NewFinal() *Final {
}
}
func (*Final) SampleConfig() string {
return sampleConfig
}
func (m *Final) Add(in telegraf.Metric) {
id := in.HashID()
m.metricCache[id] = in

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package final
func (m *Final) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -26,7 +26,7 @@ of the algorithm which is implemented in the Prometheus
## Configuration
```toml
```toml @sample.conf
# Configuration for aggregate histogram metrics
[[aggregators.histogram]]
## The period in which to flush the aggregator.

View File

@ -1,6 +1,8 @@
//go:generate ../../../tools/readme_config_includer/generator
package histogram
import (
_ "embed"
"sort"
"strconv"
"time"
@ -10,6 +12,10 @@ import (
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
// bucketRightTag is the tag, which contains right bucket border
const bucketRightTag = "le"
@ -82,6 +88,10 @@ func NewHistogramAggregator() *HistogramAggregator {
return h
}
func (*HistogramAggregator) SampleConfig() string {
return sampleConfig
}
// Add adds new hit to the buckets
func (h *HistogramAggregator) Add(in telegraf.Metric) {
addTime := timeNow()

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package histogram
func (h *HistogramAggregator) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -9,7 +9,7 @@ be handled more efficiently by the output.
## Configuration
```toml
```toml @sample.conf
# Merge metrics into multifield metrics by series key
[[aggregators.merge]]
## If true, the original metric will be dropped by the

View File

@ -1,6 +1,8 @@
//go:generate ../../../tools/readme_config_includer/generator
package merge
import (
_ "embed"
"time"
"github.com/influxdata/telegraf"
@ -8,10 +10,18 @@ import (
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Merge struct {
grouper *metric.SeriesGrouper
}
func (*Merge) SampleConfig() string {
return sampleConfig
}
func (a *Merge) Init() error {
a.grouper = metric.NewSeriesGrouper()
return nil

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package merge
func (a *Merge) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -5,7 +5,7 @@ emitting the aggrate every `period` seconds.
## Configuration
```toml
```toml @sample.conf
# Keep the aggregate min/max of each metric passing through.
[[aggregators.minmax]]
## General Aggregator Arguments:

View File

@ -1,10 +1,17 @@
//go:generate ../../../tools/readme_config_includer/generator
package minmax
import (
_ "embed"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type MinMax struct {
cache map[uint64]aggregate
}
@ -26,6 +33,10 @@ type minmax struct {
max float64
}
func (*MinMax) SampleConfig() string {
return sampleConfig
}
func (m *MinMax) Add(in telegraf.Metric) {
id := in.HashID()
if _, ok := m.cache[id]; !ok {

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package minmax
func (m *MinMax) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -5,7 +5,7 @@ per metric it sees and emits the quantiles every `period`.
## Configuration
```toml
```toml @sample.conf
# Keep the aggregate quantiles of each metric passing through.
[[aggregators.quantile]]
## General Aggregator Arguments:

View File

@ -1,12 +1,18 @@
//go:generate ../../../tools/readme_config_includer/generator
package quantile
import (
_ "embed"
"fmt"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Quantile struct {
Quantiles []float64 `toml:"quantiles"`
Compression float64 `toml:"compression"`
@ -26,6 +32,10 @@ type aggregate struct {
type newAlgorithmFunc func(compression float64) (algorithm, error)
func (*Quantile) SampleConfig() string {
return sampleConfig
}
func (q *Quantile) Add(in telegraf.Metric) {
id := in.HashID()
if cached, ok := q.cache[id]; ok {

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package quantile
func (q *Quantile) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -18,7 +18,7 @@ functions.
## Configuration
```toml
```toml @sample.conf
# Aggregate metrics using a Starlark script
[[aggregators.starlark]]
## The Starlark source can be set as a string in this configuration file, or

View File

@ -1,16 +1,28 @@
//go:generate ../../../tools/readme_config_includer/generator
package starlark
import (
_ "embed"
"go.starlark.net/starlark"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/aggregators"
common "github.com/influxdata/telegraf/plugins/common/starlark"
"go.starlark.net/starlark"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type Starlark struct {
common.StarlarkCommon
}
func (*Starlark) SampleConfig() string {
return sampleConfig
}
func (s *Starlark) Init() error {
// Execute source
err := s.StarlarkCommon.Init()

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package starlark
func (s *Starlark) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -17,7 +17,7 @@ limited set of values.
## Configuration
```toml
```toml @sample.conf
# Count the occurrence of values in fields.
[[aggregators.valuecounter]]
## General Aggregator Arguments:

View File

@ -1,12 +1,18 @@
//go:generate ../../../tools/readme_config_includer/generator
package valuecounter
import (
_ "embed"
"fmt"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/aggregators"
)
// DO NOT REMOVE THE NEXT TWO LINES! This is required to embedd the sampleConfig data.
//go:embed sample.conf
var sampleConfig string
type aggregate struct {
name string
tags map[string]string
@ -27,6 +33,10 @@ func NewValueCounter() telegraf.Aggregator {
return vc
}
func (*ValueCounter) SampleConfig() string {
return sampleConfig
}
// Add is run on every metric which passes the plugin
func (vc *ValueCounter) Add(in telegraf.Metric) {
id := in.HashID()

View File

@ -1,8 +0,0 @@
//go:generate go run ../../../tools/generate_plugindata/main.go
//go:generate go run ../../../tools/generate_plugindata/main.go --clean
// DON'T EDIT; This file is used as a template by tools/generate_plugindata
package valuecounter
func (vc *ValueCounter) SampleConfig() string {
return `{{ .SampleConfig }}`
}

View File

@ -1,157 +0,0 @@
// 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)
}
}
}

View File

@ -1,133 +0,0 @@
package main
import (
"os"
"testing"
"github.com/stretchr/testify/require"
)
var originalPlugin = `package main
func (*Plugin) SampleConfig() string {
return ` + "`{{ .SampleConfig }}`" + `
}
`
func TestGeneratePluginData(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
readme := `# plugin
## Configuration
` + "```" + `toml
# test plugin
[[input.plugin]]
# No configuration
` + "```"
r, err := os.Create("README.md")
require.NoError(t, err)
_, err = r.Write([]byte(readme))
require.NoError(t, err)
err = r.Close()
require.NoError(t, err)
sourceFile, err := os.Create("test_sample_config.go")
require.NoError(t, err)
_, err = sourceFile.Write([]byte(originalPlugin))
require.NoError(t, err)
err = sourceFile.Close()
require.NoError(t, err)
defer func() {
err = os.Remove("test_sample_config.go")
require.NoError(t, err)
err = os.Remove("README.md")
require.NoError(t, err)
}()
s, err := extractPluginData()
require.NoError(t, err)
err = generatePluginData("test", s)
require.NoError(t, err)
expected := `package main
func (*Plugin) SampleConfig() string {
return ` + "`" + `# test plugin
[[input.plugin]]
# No configuration
` + "`" + `
}
`
newSourceFile, err := os.ReadFile("test_sample_config.go")
require.NoError(t, err)
require.Equal(t, expected, string(newSourceFile))
}
func TestGeneratePluginDataNoConfig(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
readme := `# plugin`
r, err := os.Create("README.md")
require.NoError(t, err)
_, err = r.Write([]byte(readme))
require.NoError(t, err)
err = r.Close()
require.NoError(t, err)
defer func() {
err = os.Remove("README.md")
require.NoError(t, err)
}()
s, err := extractPluginData()
require.NoError(t, err)
require.Empty(t, s)
}
func setupGeneratedPluginFile(t *testing.T, fileName string) {
// Create files that will be cleaned up
r, err := os.Create(fileName)
require.NoError(t, err)
defer r.Close()
updatePlugin := `package main
func (*Plugin) SampleConfig() string {
return "I am a sample config"
}
`
_, err = r.Write([]byte(updatePlugin))
require.NoError(t, err)
}
func TestCleanGeneratedFiles(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}
filename := "testClean_sample_config.go"
setupGeneratedPluginFile(t, filename)
err := cleanGeneratedFiles("testClean")
require.NoError(t, err)
b, err := os.ReadFile(filename)
require.NoError(t, err)
require.Equal(t, originalPlugin, string(b))
err = os.Remove(filename)
require.NoError(t, err)
}