feat: generate the plugins sample config (#10886)
This commit is contained in:
parent
6cb25207fd
commit
5d6748fcb5
|
|
@ -78,6 +78,7 @@ commands:
|
|||
key: windows-go-<< parameters.cache_version >>-{{ checksum "go.sum" }}
|
||||
- run: 'sh ./scripts/installgo_windows.sh'
|
||||
- run: choco install mingw
|
||||
- run: 'make generate'
|
||||
- run: mkdir -p test-results
|
||||
- run: ./scripts/install_gotestsum.sh << parameters.os >> << parameters.gotestsum >>
|
||||
- unless:
|
||||
|
|
@ -120,7 +121,7 @@ commands:
|
|||
paths:
|
||||
- 'C:\Go'
|
||||
- 'C:\Users\circleci\project\gotestsum.exe'
|
||||
|
||||
- run: 'make generate-clean'
|
||||
package-build:
|
||||
parameters:
|
||||
type:
|
||||
|
|
|
|||
17
Makefile
17
Makefile
|
|
@ -109,10 +109,21 @@ versioninfo:
|
|||
go run scripts/generate_versioninfo/main.go; \
|
||||
go generate cmd/telegraf/telegraf_windows.go; \
|
||||
|
||||
.PHONY: telegraf
|
||||
telegraf:
|
||||
.PHONY: generate
|
||||
generate:
|
||||
go generate -run="plugindata/main.go$$" ./plugins/inputs/... ./plugins/outputs/... ./plugins/processors/... ./plugins/aggregators/...
|
||||
|
||||
.PHONY: generate-clean
|
||||
generate-clean:
|
||||
go generate -run="plugindata/main.go --clean" ./plugins/inputs/... ./plugins/outputs/... ./plugins/processors/... ./plugins/aggregators/...
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build -ldflags "$(LDFLAGS)" ./cmd/telegraf
|
||||
|
||||
.PHONY: telegraf
|
||||
telegraf: generate build generate-clean
|
||||
|
||||
# Used by dockerfile builds
|
||||
.PHONY: go-install
|
||||
go-install:
|
||||
|
|
@ -312,7 +323,7 @@ darwin-arm64:
|
|||
include_packages := $(mips) $(mipsel) $(arm64) $(amd64) $(static) $(armel) $(armhf) $(riscv64) $(s390x) $(ppc64le) $(i386) $(windows) $(darwin-amd64) $(darwin-arm64)
|
||||
|
||||
.PHONY: package
|
||||
package: $(include_packages)
|
||||
package: generate $(include_packages) generate-clean
|
||||
|
||||
.PHONY: $(include_packages)
|
||||
$(include_packages):
|
||||
|
|
|
|||
|
|
@ -678,23 +678,24 @@ func printConfig(name string, p telegraf.PluginDescriber, op string, commented b
|
|||
if commented {
|
||||
comment = "# "
|
||||
}
|
||||
fmt.Printf("\n%s# %s\n%s[[%s.%s]]", comment, p.Description(), comment, op, name)
|
||||
|
||||
if di.Since != "" {
|
||||
removalNote := ""
|
||||
if di.RemovalIn != "" {
|
||||
removalNote = " and will be removed in " + di.RemovalIn
|
||||
}
|
||||
fmt.Printf("\n%s ## DEPRECATED: The '%s' plugin is deprecated in version %s%s, %s.", comment, name, di.Since, removalNote, di.Notice)
|
||||
fmt.Printf("\n%s ## DEPRECATED: The '%s' plugin is deprecated in version %s%s, %s.", comment, name, di.Since, removalNote, di.Notice)
|
||||
}
|
||||
|
||||
config := p.SampleConfig()
|
||||
if config == "" {
|
||||
fmt.Printf("\n#[[%s.%s]]", op, name)
|
||||
fmt.Printf("\n%s # no configuration\n\n", comment)
|
||||
} else {
|
||||
lines := strings.Split(config, "\n")
|
||||
fmt.Print("\n")
|
||||
for i, line := range lines {
|
||||
if i == 0 || i == len(lines)-1 {
|
||||
if i == len(lines)-1 {
|
||||
fmt.Print("\n")
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -678,7 +678,6 @@ type MockupInputPluginParserOld struct {
|
|||
}
|
||||
|
||||
func (m *MockupInputPluginParserOld) SampleConfig() string { return "Mockup old parser test plugin" }
|
||||
func (m *MockupInputPluginParserOld) Description() string { return "Mockup old parser test plugin" }
|
||||
func (m *MockupInputPluginParserOld) Gather(acc telegraf.Accumulator) error { return nil }
|
||||
func (m *MockupInputPluginParserOld) SetParser(parser parsers.Parser) { m.Parser = parser }
|
||||
func (m *MockupInputPluginParserOld) SetParserFunc(f parsers.ParserFunc) { m.ParserFunc = f }
|
||||
|
|
@ -690,7 +689,6 @@ type MockupInputPluginParserNew struct {
|
|||
}
|
||||
|
||||
func (m *MockupInputPluginParserNew) SampleConfig() string { return "Mockup old parser test plugin" }
|
||||
func (m *MockupInputPluginParserNew) Description() string { return "Mockup old parser test plugin" }
|
||||
func (m *MockupInputPluginParserNew) Gather(acc telegraf.Accumulator) error { return nil }
|
||||
func (m *MockupInputPluginParserNew) SetParser(parser telegraf.Parser) { m.Parser = parser }
|
||||
func (m *MockupInputPluginParserNew) SetParserFunc(f telegraf.ParserFunc) { m.ParserFunc = f }
|
||||
|
|
@ -714,7 +712,6 @@ type MockupInputPlugin struct {
|
|||
}
|
||||
|
||||
func (m *MockupInputPlugin) SampleConfig() string { return "Mockup test input plugin" }
|
||||
func (m *MockupInputPlugin) Description() string { return "Mockup test input plugin" }
|
||||
func (m *MockupInputPlugin) Gather(acc telegraf.Accumulator) error { return nil }
|
||||
func (m *MockupInputPlugin) SetParser(parser telegraf.Parser) { m.parser = parser }
|
||||
|
||||
|
|
@ -730,7 +727,6 @@ type MockupOuputPlugin struct {
|
|||
|
||||
func (m *MockupOuputPlugin) Connect() error { return nil }
|
||||
func (m *MockupOuputPlugin) Close() error { return nil }
|
||||
func (m *MockupOuputPlugin) Description() string { return "Mockup test output plugin" }
|
||||
func (m *MockupOuputPlugin) SampleConfig() string { return "Mockup test output plugin" }
|
||||
func (m *MockupOuputPlugin) Write(metrics []telegraf.Metric) error { return nil }
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ 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.
|
||||
* The `SampleConfig` function should return valid toml that describes how the
|
||||
plugin can be configured. This is included in `telegraf config`. Please
|
||||
consult the [Sample Config][] page for the latest style guidelines.
|
||||
* The `Description` function should say in one line what this aggregator does.
|
||||
* 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`.
|
||||
Please consult the [Sample Config][] page for the latest style guidelines.
|
||||
* 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,6 +22,8 @@ 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
|
||||
package min
|
||||
|
||||
// min.go
|
||||
|
|
@ -44,26 +46,10 @@ func NewMin() telegraf.Aggregator {
|
|||
return m
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
## period is the flush & clear interval of the aggregator.
|
||||
period = "30s"
|
||||
## If true drop_original will drop the original metrics and
|
||||
## only send aggregates.
|
||||
drop_original = false
|
||||
`
|
||||
|
||||
func (m *Min) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Min) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (m *Min) Description() string {
|
||||
return "Keep the aggregate min of each metric passing through."
|
||||
}
|
||||
|
||||
func (m *Min) Add(in telegraf.Metric) {
|
||||
id := in.HashID()
|
||||
if _, ok := m.nameCache[id]; !ok {
|
||||
|
|
@ -127,6 +113,19 @@ 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
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ 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.
|
||||
- The `SampleConfig` function should return valid toml that describes how the
|
||||
plugin can be configured. This is included in `telegraf config`. Please
|
||||
consult the [Sample Config][] page for the latest style
|
||||
guidelines.
|
||||
- The `Description` function should say in one line what this plugin does.
|
||||
- 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`.
|
||||
Please consult the [Sample Config][] page for the latest style guidelines.
|
||||
- Follow the recommended [Code Style][].
|
||||
|
||||
Let's say you've written a plugin that emits metrics about processes on the
|
||||
|
|
@ -28,10 +27,10 @@ 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
|
||||
package simple
|
||||
|
||||
// simple.go
|
||||
|
||||
import (
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/plugins/inputs"
|
||||
|
|
@ -42,17 +41,6 @@ type Simple struct {
|
|||
Log telegraf.Logger `toml:"-"`
|
||||
}
|
||||
|
||||
func (s *Simple) Description() string {
|
||||
return "a demo plugin"
|
||||
}
|
||||
|
||||
func (s *Simple) SampleConfig() string {
|
||||
return `
|
||||
## Indicate if everything is fine
|
||||
ok = true
|
||||
`
|
||||
}
|
||||
|
||||
// Init is for setup, and validating config.
|
||||
func (s *Simple) Init() error {
|
||||
return nil
|
||||
|
|
@ -73,6 +61,17 @@ 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
|
||||
|
|
@ -101,7 +100,7 @@ You can then utilize the parser internally in your plugin, parsing data as you
|
|||
see fit. Telegraf's configuration layer will take care of instantiating and
|
||||
creating the `Parser` object.
|
||||
|
||||
Add the following to the `SampleConfig()`:
|
||||
Add the following to the sample configuration in the README.md:
|
||||
|
||||
```toml
|
||||
## Data format to consume.
|
||||
|
|
|
|||
|
|
@ -11,15 +11,17 @@ 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.
|
||||
- The `SampleConfig` function should return valid toml that describes how the
|
||||
plugin can be configured. This is included in `telegraf config`. Please
|
||||
consult the [Sample Config][] page for the latest style guidelines.
|
||||
- The `Description` function should say in one line what this output does.
|
||||
- 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`.
|
||||
Please consult the [Sample Config][] page for the latest style guidelines.
|
||||
- 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
|
||||
package simpleoutput
|
||||
|
||||
// simpleoutput.go
|
||||
|
|
@ -34,16 +36,6 @@ type Simple struct {
|
|||
Log telegraf.Logger `toml:"-"`
|
||||
}
|
||||
|
||||
func (s *Simple) Description() string {
|
||||
return "a demo output"
|
||||
}
|
||||
|
||||
func (s *Simple) SampleConfig() string {
|
||||
return `
|
||||
ok = true
|
||||
`
|
||||
}
|
||||
|
||||
// Init is for setup, and validating config.
|
||||
func (s *Simple) Init() error {
|
||||
return nil
|
||||
|
|
@ -76,6 +68,19 @@ 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
|
||||
|
|
|
|||
|
|
@ -9,18 +9,17 @@ 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.
|
||||
* The `SampleConfig` function should return valid toml that describes how the
|
||||
processor can be configured. This is include in the output of `telegraf
|
||||
config`.
|
||||
* The `SampleConfig` function should return valid toml that describes how the
|
||||
plugin can be configured. This is included in `telegraf config`. Please
|
||||
consult the [Sample Config][] page for the latest style guidelines.
|
||||
* The `Description` function should say in one line what this processor does.
|
||||
* 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`.
|
||||
Please consult the [Sample Config][] page for the latest style guidelines.
|
||||
* 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
|
||||
package printer
|
||||
|
||||
// printer.go
|
||||
|
|
@ -36,17 +35,6 @@ type Printer struct {
|
|||
Log telegraf.Logger `toml:"-"`
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
`
|
||||
|
||||
func (p *Printer) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (p *Printer) Description() string {
|
||||
return "Print all metrics that pass through this filter."
|
||||
}
|
||||
|
||||
// Init is for setup, and validating config.
|
||||
func (p *Printer) Init() error {
|
||||
return nil
|
||||
|
|
@ -66,6 +54,19 @@ 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
|
||||
|
|
@ -102,17 +103,6 @@ type Printer struct {
|
|||
Log telegraf.Logger `toml:"-"`
|
||||
}
|
||||
|
||||
var sampleConfig = `
|
||||
`
|
||||
|
||||
func (p *Printer) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
func (p *Printer) Description() string {
|
||||
return "Print all metrics that pass through this filter."
|
||||
}
|
||||
|
||||
// Init is for setup, and validating config.
|
||||
func (p *Printer) Init() error {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
# Sample Configuration
|
||||
|
||||
The sample config file is generated from a results of the `SampleConfig()` and
|
||||
`Description()` functions of the plugins.
|
||||
The sample config file is generated from a results of the `SampleConfig()` functions of the plugin.
|
||||
|
||||
You can generate a full sample
|
||||
config:
|
||||
|
|
|
|||
1
go.mod
1
go.mod
|
|
@ -137,6 +137,7 @@ require (
|
|||
github.com/wavefronthq/wavefront-sdk-go v0.9.10
|
||||
github.com/wvanbergen/kafka v0.0.0-20171203153745-e2edea948ddf
|
||||
github.com/xdg/scram v1.0.3
|
||||
github.com/yuin/goldmark v1.4.1
|
||||
go.mongodb.org/mongo-driver v1.8.3
|
||||
go.opentelemetry.io/collector/model v0.44.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.27.0
|
||||
|
|
|
|||
1
go.sum
1
go.sum
|
|
@ -2261,6 +2261,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1 h1:/vn0k+RBvwlxEmP5E7SZMqNxPhfMVFEJiykr15/0XKM=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/gopher-lua v0.0.0-20200603152657-dc2b0ca8b37e/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da h1:NimzV1aGyq29m5ukMK0AMWEhFaL/lrEOaephfuoiARg=
|
||||
|
|
|
|||
|
|
@ -26,11 +26,8 @@ type Initializer interface {
|
|||
// not part of the interface, but will receive an injected logger if it's set.
|
||||
// eg: Log telegraf.Logger `toml:"-"`
|
||||
type PluginDescriber interface {
|
||||
// SampleConfig returns the default configuration of the Processor
|
||||
// SampleConfig returns the default configuration of the Plugin
|
||||
SampleConfig() string
|
||||
|
||||
// Description returns a one-sentence description on the Processor
|
||||
Description() string
|
||||
}
|
||||
|
||||
// Logger defines an plugin-related interface for logging.
|
||||
|
|
|
|||
|
|
@ -34,16 +34,6 @@ func TestLoadConfig(t *testing.T) {
|
|||
require.Equal(t, `test"\test`, inp.SecretValue)
|
||||
}
|
||||
|
||||
func TestDefaultImportedPluginsSelfRegisters(t *testing.T) {
|
||||
inputs.Add("test", func() telegraf.Input {
|
||||
return &testInput{}
|
||||
})
|
||||
|
||||
cfg, err := LoadConfig(nil)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test", cfg.Input.Description())
|
||||
}
|
||||
|
||||
func TestLoadingSpecialTypes(t *testing.T) {
|
||||
inputs.Add("test", func() telegraf.Input {
|
||||
return &testDurationInput{}
|
||||
|
|
|
|||
|
|
@ -66,10 +66,6 @@ func (i *erroringInput) SampleConfig() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (i *erroringInput) Description() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (i *erroringInput) Gather(acc telegraf.Accumulator) error {
|
||||
acc.AddError(errors.New("intentional"))
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -24,10 +24,6 @@ func (sp *streamingProcessor) SampleConfig() string {
|
|||
return sp.processor.SampleConfig()
|
||||
}
|
||||
|
||||
func (sp *streamingProcessor) Description() string {
|
||||
return sp.processor.Description()
|
||||
}
|
||||
|
||||
func (sp *streamingProcessor) Start(acc telegraf.Accumulator) error {
|
||||
sp.acc = acc
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
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)
|
||||
}
|
||||
Loading…
Reference in New Issue