1
0
Fork 0

Clean Documentation

This commit is contained in:
Nicolas Mengin 2025-08-25 14:35:04 +02:00 committed by GitHub
parent 8ac8473554
commit 1997bc7432
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 2561 additions and 1247 deletions

View file

@ -5,23 +5,17 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"reflect"
"sort"
"strconv"
"strings"
"github.com/BurntSushi/toml"
"github.com/rs/zerolog/log"
"github.com/traefik/paerser/env"
"github.com/traefik/paerser/flag"
"github.com/traefik/paerser/generator"
"github.com/traefik/paerser/parser"
"github.com/traefik/traefik/v3/cmd"
"github.com/traefik/traefik/v3/pkg/collector/hydratation"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/config/static"
"gopkg.in/yaml.v3"
)
@ -30,6 +24,12 @@ var commentGenerated = `## CODE GENERATED AUTOMATICALLY
`
func main() {
genRoutingConfDoc()
genInstallConfDoc()
}
// Generate the Routing Configuration YAML and TOML files.
func genRoutingConfDoc() {
logger := log.With().Logger()
dynConf := &dynamic.Configuration{}
@ -46,118 +46,14 @@ func main() {
clean(dynConf.TCP.Services)
clean(dynConf.UDP.Services)
err = tomlWrite("./docs/content/reference/dynamic-configuration/file.toml", dynConf)
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/dynamic-configuration/file.yaml", dynConf)
err = yamlWrite("./docs/content/reference/routing-configuration/other-providers/file.yaml", dynConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
err = labelsWrite("./docs/content/reference/dynamic-configuration", dynConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
staticConf := &static.Configuration{}
err = hydratation.Hydrate(staticConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
delete(staticConf.EntryPoints, "EntryPoint1")
err = tomlWrite("./docs/content/reference/static-configuration/file.toml", staticConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
err = yamlWrite("./docs/content/reference/static-configuration/file.yaml", staticConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
genStaticConfDoc("./docs/content/reference/static-configuration/env-ref.md", "", func(i interface{}) ([]parser.Flat, error) {
return env.Encode(env.DefaultNamePrefix, i)
})
genStaticConfDoc("./docs/content/reference/static-configuration/cli-ref.md", "--", flag.Encode)
genKVDynConfDoc("./docs/content/reference/dynamic-configuration/kv-ref.md")
}
func labelsWrite(outputDir string, element *dynamic.Configuration) error {
cleanServers(element)
etnOpts := parser.EncoderToNodeOpts{OmitEmpty: true, TagName: parser.TagLabel, AllowSliceAsStruct: true}
node, err := parser.EncodeToNode(element, parser.DefaultRootName, etnOpts)
if err != nil {
return err
}
metaOpts := parser.MetadataOpts{TagName: parser.TagLabel, AllowSliceAsStruct: true}
err = parser.AddMetadata(element, node, metaOpts)
if err != nil {
return err
}
labels := make(map[string]string)
encodeNode(labels, node.Name, node)
var keys []string
for k := range labels {
keys = append(keys, k)
}
sort.Strings(keys)
dockerLabels, err := os.Create(filepath.Join(outputDir, "docker-labels.yml"))
if err != nil {
return err
}
defer dockerLabels.Close()
// Write the comment at the beginning of the file
if _, err := dockerLabels.WriteString(commentGenerated); err != nil {
return err
}
for _, k := range keys {
v := labels[k]
if v != "" {
if v == "42000000000" {
v = "42s"
}
fmt.Fprintln(dockerLabels, `- "`+strings.ToLower(k)+`=`+v+`"`)
}
}
return nil
}
func cleanServers(element *dynamic.Configuration) {
for _, svc := range element.HTTP.Services {
if svc.LoadBalancer != nil {
server := svc.LoadBalancer.Servers[0]
svc.LoadBalancer.Servers = nil
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
}
}
for _, svc := range element.TCP.Services {
if svc.LoadBalancer != nil {
server := svc.LoadBalancer.Servers[0]
svc.LoadBalancer.Servers = nil
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
}
}
for _, svc := range element.UDP.Services {
if svc.LoadBalancer != nil {
server := svc.LoadBalancer.Servers[0]
svc.LoadBalancer.Servers = nil
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
}
}
}
func yamlWrite(outputFile string, element any) error {
@ -167,7 +63,7 @@ func yamlWrite(outputFile string, element any) error {
}
defer file.Close()
// Write the comment at the beginning of the file
// Write the comment at the beginning of the file.
if _, err := file.WriteString(commentGenerated); err != nil {
return err
}
@ -191,7 +87,7 @@ func tomlWrite(outputFile string, element any) error {
}
defer file.Close()
// Write the comment at the beginning of the file
// Write the comment at the beginning of the file.
if _, err := file.WriteString(commentGenerated); err != nil {
return err
}
@ -229,14 +125,16 @@ func clean(element any) {
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s1", valueSvcRoot.Type().Name())), reflect.Value{})
}
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
// 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 := encodeFn(element)
flats, err := flag.Encode(element)
if err != nil {
logger.Fatal().Err(err).Send()
}
@ -259,9 +157,14 @@ func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]p
CODE GENERATED AUTOMATICALLY
THIS FILE MUST NOT BE EDITED BY HAND
-->`)
w.writeln()
w.writeln(`# Install Configuration Options`)
w.writeln(`## Configuration Options`)
for i, flat := range flats {
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
@ -271,21 +174,15 @@ THIS FILE MUST NOT BE EDITED BY HAND
continue
}
if prefix == "" {
w.writeln("`" + prefix + strings.ReplaceAll(flat.Name, "[0]", "_n") + "`: ")
} else {
w.writeln("`" + prefix + strings.ReplaceAll(flat.Name, "[0]", "[n]") + "`: ")
}
line := "| " + strings.ReplaceAll(strings.ReplaceAll(flat.Name, "<", "_"), ">", "_") + " | " + flat.Description + " | "
if flat.Default == "" {
w.writeln(flat.Description)
line += "|"
} else {
w.writeln(flat.Description + " (Default: ```" + flat.Default + "```)")
line += flat.Default + " |"
}
if i < len(flats)-1 {
w.writeln()
}
w.writeln(line)
}
if w.err != nil {
@ -305,106 +202,3 @@ func (ew *errWriter) writeln(a ...interface{}) {
_, ew.err = fmt.Fprintln(ew.w, a...)
}
func genKVDynConfDoc(outputFile string) {
dynConfPath := "./docs/content/reference/dynamic-configuration/file.toml"
conf := map[string]interface{}{}
_, err := toml.DecodeFile(dynConfPath, &conf)
if err != nil {
log.Fatal().Err(err).Send()
}
file, err := os.Create(outputFile)
if err != nil {
log.Fatal().Err(err).Send()
}
store := storeWriter{data: map[string]string{}}
c := client{store: store}
err = c.load("traefik", conf)
if err != nil {
log.Fatal().Err(err).Send()
}
var keys []string
for k := range store.data {
keys = append(keys, k)
}
sort.Strings(keys)
_, _ = fmt.Fprintf(file, `<!--
CODE GENERATED AUTOMATICALLY
THIS FILE MUST NOT BE EDITED BY HAND
-->
`)
_, _ = fmt.Fprintf(file, `
| Key (Path) | Value |
|------------|-------|
`)
for _, k := range keys {
_, _ = fmt.Fprintf(file, "| `%s` | `%s` |\n", k, store.data[k])
}
}
type storeWriter struct {
data map[string]string
}
func (f storeWriter) Put(key string, value []byte, _ []string) error {
f.data[key] = string(value)
return nil
}
type client struct {
store storeWriter
}
func (c client) load(parentKey string, conf map[string]interface{}) error {
for k, v := range conf {
switch entry := v.(type) {
case map[string]interface{}:
key := path.Join(parentKey, k)
if len(entry) == 0 {
err := c.store.Put(key, nil, nil)
if err != nil {
return err
}
} else {
err := c.load(key, entry)
if err != nil {
return err
}
}
case []map[string]interface{}:
for i, o := range entry {
key := path.Join(parentKey, k, strconv.Itoa(i))
if err := c.load(key, o); err != nil {
return err
}
}
case []interface{}:
for i, o := range entry {
key := path.Join(parentKey, k, strconv.Itoa(i))
err := c.store.Put(key, []byte(fmt.Sprintf("%v", o)), nil)
if err != nil {
return err
}
}
default:
key := path.Join(parentKey, k)
err := c.store.Put(key, []byte(fmt.Sprintf("%v", v)), nil)
if err != nil {
return err
}
}
}
return nil
}

View file

@ -1,66 +0,0 @@
package main
import (
"fmt"
"reflect"
"strings"
"github.com/traefik/paerser/parser"
)
func encodeNode(labels map[string]string, root string, node *parser.Node) {
for _, child := range node.Children {
if child.Disabled {
continue
}
var sep string
if child.Name[0] != '[' {
sep = "."
}
childName := root + sep + child.Name
if child.RawValue != nil {
encodeRawValue(labels, childName, child.RawValue)
continue
}
if strings.Contains(child.Tag.Get(parser.TagLabel), parser.TagLabelAllowEmpty) {
labels[childName] = "true"
}
if len(child.Children) > 0 {
encodeNode(labels, childName, child)
} else if len(child.Name) > 0 {
labels[childName] = child.Value
}
}
}
func encodeRawValue(labels map[string]string, root string, rawValue interface{}) {
if rawValue == nil {
return
}
tValue := reflect.TypeOf(rawValue)
if tValue.Kind() == reflect.Map && tValue.Elem().Kind() == reflect.Interface {
r := reflect.ValueOf(rawValue).
Convert(reflect.TypeFor[map[string]interface{}]()).
Interface().(map[string]interface{})
for k, v := range r {
switch tv := v.(type) {
case string:
labels[root+"."+k] = tv
case []interface{}:
for i, e := range tv {
encodeRawValue(labels, fmt.Sprintf("%s.%s[%d]", root, k, i), e)
}
default:
encodeRawValue(labels, root+"."+k, v)
}
}
}
}