mirror of
				https://github.com/traefik/traefik.git
				synced 2025-11-04 02:11:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			206 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"reflect"
 | 
						|
	"sort"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/BurntSushi/toml"
 | 
						|
	"github.com/rs/zerolog/log"
 | 
						|
	"github.com/traefik/paerser/flag"
 | 
						|
	"github.com/traefik/paerser/generator"
 | 
						|
	"github.com/traefik/traefik/v3/cmd"
 | 
						|
	"github.com/traefik/traefik/v3/pkg/collector/hydratation"
 | 
						|
	"github.com/traefik/traefik/v3/pkg/config/dynamic"
 | 
						|
	"gopkg.in/yaml.v3"
 | 
						|
)
 | 
						|
 | 
						|
var commentGenerated = `## CODE GENERATED AUTOMATICALLY
 | 
						|
## THIS FILE MUST NOT BE EDITED BY HAND
 | 
						|
`
 | 
						|
 | 
						|
func main() {
 | 
						|
	genRoutingConfDoc()
 | 
						|
	genInstallConfDoc()
 | 
						|
	genAnchors()
 | 
						|
}
 | 
						|
 | 
						|
// Generate the Routing Configuration YAML and TOML files.
 | 
						|
func genRoutingConfDoc() {
 | 
						|
	logger := log.With().Logger()
 | 
						|
 | 
						|
	dynConf := &dynamic.Configuration{}
 | 
						|
 | 
						|
	err := hydratation.Hydrate(dynConf)
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
 | 
						|
	dynConf.HTTP.Models = map[string]*dynamic.Model{}
 | 
						|
	clean(dynConf.HTTP.Middlewares)
 | 
						|
	clean(dynConf.TCP.Middlewares)
 | 
						|
	clean(dynConf.HTTP.Services)
 | 
						|
	clean(dynConf.TCP.Services)
 | 
						|
	clean(dynConf.UDP.Services)
 | 
						|
 | 
						|
	err = tomlWrite("./docs/content/reference/routing-configuration/other-providers/file.toml", dynConf)
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
	err = yamlWrite("./docs/content/reference/routing-configuration/other-providers/file.yaml", dynConf)
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func yamlWrite(outputFile string, element any) error {
 | 
						|
	file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer file.Close()
 | 
						|
 | 
						|
	// Write the comment at the beginning of the file.
 | 
						|
	if _, err := file.WriteString(commentGenerated); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	buf := new(bytes.Buffer)
 | 
						|
	encoder := yaml.NewEncoder(buf)
 | 
						|
	encoder.SetIndent(2)
 | 
						|
	err = encoder.Encode(element)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	_, err = file.Write(buf.Bytes())
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func tomlWrite(outputFile string, element any) error {
 | 
						|
	file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer file.Close()
 | 
						|
 | 
						|
	// Write the comment at the beginning of the file.
 | 
						|
	if _, err := file.WriteString(commentGenerated); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return toml.NewEncoder(file).Encode(element)
 | 
						|
}
 | 
						|
 | 
						|
func clean(element any) {
 | 
						|
	valSvcs := reflect.ValueOf(element)
 | 
						|
 | 
						|
	key := valSvcs.MapKeys()[0]
 | 
						|
	valueSvcRoot := valSvcs.MapIndex(key).Elem()
 | 
						|
 | 
						|
	var svcFieldNames []string
 | 
						|
	for i := range valueSvcRoot.NumField() {
 | 
						|
		field := valueSvcRoot.Type().Field(i)
 | 
						|
		// do not create empty node for hidden config.
 | 
						|
		if field.Tag.Get("file") == "-" && field.Tag.Get("kv") == "-" && field.Tag.Get("label") == "-" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		svcFieldNames = append(svcFieldNames, field.Name)
 | 
						|
	}
 | 
						|
 | 
						|
	sort.Strings(svcFieldNames)
 | 
						|
 | 
						|
	for i, fieldName := range svcFieldNames {
 | 
						|
		v := reflect.New(valueSvcRoot.Type())
 | 
						|
		v.Elem().FieldByName(fieldName).Set(valueSvcRoot.FieldByName(fieldName))
 | 
						|
 | 
						|
		valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s%.2d", valueSvcRoot.Type().Name(), i+1)), v)
 | 
						|
	}
 | 
						|
 | 
						|
	valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s0", valueSvcRoot.Type().Name())), reflect.Value{})
 | 
						|
	valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s1", valueSvcRoot.Type().Name())), reflect.Value{})
 | 
						|
}
 | 
						|
 | 
						|
// Generate the Install Configuration in a table.
 | 
						|
func genInstallConfDoc() {
 | 
						|
	outputFile := "./docs/content/reference/install-configuration/configuration-options.md"
 | 
						|
	logger := log.With().Str("file", outputFile).Logger()
 | 
						|
 | 
						|
	element := &cmd.NewTraefikConfiguration().Configuration
 | 
						|
 | 
						|
	generator.Generate(element)
 | 
						|
 | 
						|
	flats, err := flag.Encode(element)
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
 | 
						|
	err = os.RemoveAll(outputFile)
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
 | 
						|
	file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
 | 
						|
	if err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
 | 
						|
	defer file.Close()
 | 
						|
 | 
						|
	w := errWriter{w: file}
 | 
						|
 | 
						|
	w.writeln(`<!--
 | 
						|
CODE GENERATED AUTOMATICALLY
 | 
						|
THIS FILE MUST NOT BE EDITED BY HAND
 | 
						|
-->`)
 | 
						|
	w.writeln(`# Install Configuration Options`)
 | 
						|
	w.writeln(`## Configuration Options`)
 | 
						|
 | 
						|
	w.writeln(`
 | 
						|
| Field | Description | Default | 
 | 
						|
|:-------|:------------|:-------|`)
 | 
						|
 | 
						|
	for _, flat := range flats {
 | 
						|
		// TODO must be move into the flats creation.
 | 
						|
		if flat.Name == "experimental.plugins.<name>" || flat.Name == "TRAEFIK_EXPERIMENTAL_PLUGINS_<NAME>" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		if strings.HasPrefix(flat.Name, "pilot.") || strings.HasPrefix(flat.Name, "TRAEFIK_PILOT_") {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		line := "| " + strings.ReplaceAll(strings.ReplaceAll(flat.Name, "<", "_"), ">", "_") + " | " + flat.Description + " | "
 | 
						|
 | 
						|
		if flat.Default == "" {
 | 
						|
			line += "|"
 | 
						|
		} else {
 | 
						|
			line += flat.Default + " |"
 | 
						|
		}
 | 
						|
 | 
						|
		w.writeln(line)
 | 
						|
	}
 | 
						|
 | 
						|
	if w.err != nil {
 | 
						|
		logger.Fatal().Err(err).Send()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type errWriter struct {
 | 
						|
	w   io.Writer
 | 
						|
	err error
 | 
						|
}
 | 
						|
 | 
						|
func (ew *errWriter) writeln(a ...interface{}) {
 | 
						|
	if ew.err != nil {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	_, ew.err = fmt.Fprintln(ew.w, a...)
 | 
						|
}
 |