Files
katenary/generator/katenaryLabels.go
Patrice Ferlet 4367a01769 Big refactorization
- reduce complexity
- use better tools to format the code
- add more tests
- and too many things to list here

We are rewriting for V3, so these commits are sometimes big and not
fully detailed. Of course, further work will be more documented.
2024-05-06 21:11:36 +02:00

237 lines
6.2 KiB
Go

package generator
import (
"bytes"
_ "embed"
"fmt"
"regexp"
"sort"
"strings"
"text/tabwriter"
"text/template"
"sigs.k8s.io/yaml"
"katenary/utils"
)
var (
// Set the documentation of labels here
//
//go:embed katenaryLabelsDoc.yaml
labelFullHelpYAML []byte
// parsed yaml
labelFullHelp map[string]Help
)
// Label is a katenary label to find in compose files.
type Label = string
// Help is the documentation of a label.
type Help struct {
Short string `yaml:"short"`
Long string `yaml:"long"`
Example string `yaml:"example"`
Type string `yaml:"type"`
}
const katenaryLabelPrefix = "katenary.v3"
func Prefix() string {
return katenaryLabelPrefix
}
// Known labels.
const (
LabelMainApp Label = katenaryLabelPrefix + "/main-app"
LabelValues Label = katenaryLabelPrefix + "/values"
LabelSecrets Label = katenaryLabelPrefix + "/secrets"
LabelPorts Label = katenaryLabelPrefix + "/ports"
LabelIngress Label = katenaryLabelPrefix + "/ingress"
LabelMapEnv Label = katenaryLabelPrefix + "/map-env"
LabelHealthCheck Label = katenaryLabelPrefix + "/health-check"
LabelSamePod Label = katenaryLabelPrefix + "/same-pod"
LabelDescription Label = katenaryLabelPrefix + "/description"
LabelIgnore Label = katenaryLabelPrefix + "/ignore"
LabelDependencies Label = katenaryLabelPrefix + "/dependencies"
LabelConfigMapFiles Label = katenaryLabelPrefix + "/configmap-files"
LabelCronJob Label = katenaryLabelPrefix + "/cronjob"
LabelEnvFrom Label = katenaryLabelPrefix + "/env-from"
)
func init() {
if err := yaml.Unmarshal(labelFullHelpYAML, &labelFullHelp); err != nil {
panic(err)
}
}
func labelName(name string) Label {
return Label(katenaryLabelPrefix + "/" + name)
}
// Generate the help for the labels.
func GetLabelHelp(asMarkdown bool) string {
names := GetLabelNames() // sorted
if !asMarkdown {
return generatePlainHelp(names)
}
return generateMarkdownHelp(names)
}
func generatePlainHelp(names []string) string {
var builder strings.Builder
for _, name := range names {
help := labelFullHelp[name]
fmt.Fprintf(&builder, "%s:\t%s\t%s\n", labelName(name), help.Type, help.Short)
}
// use tabwriter to align the help text
buf := new(strings.Builder)
w := tabwriter.NewWriter(buf, 0, 8, 0, '\t', tabwriter.AlignRight)
fmt.Fprintln(w, builder.String())
w.Flush()
head := "To get more information about a label, use `katenary help-label <name_without_prefix>\ne.g. katenary help-label dependencies\n\n"
return head + buf.String()
}
func generateMarkdownHelp(names []string) string {
var builder strings.Builder
var maxNameLength, maxDescriptionLength, maxTypeLength int
max := func(a, b int) int {
if a > b {
return a
}
return b
}
for _, name := range names {
help := labelFullHelp[name]
maxNameLength = max(maxNameLength, len(name)+2+len(katenaryLabelPrefix))
maxDescriptionLength = max(maxDescriptionLength, len(help.Short))
maxTypeLength = max(maxTypeLength, len(help.Type))
}
fmt.Fprintf(&builder, "%s\n", generateTableHeader(maxNameLength, maxDescriptionLength, maxTypeLength))
fmt.Fprintf(&builder, "%s\n", generateTableHeaderSeparator(maxNameLength, maxDescriptionLength, maxTypeLength))
for _, name := range names {
help := labelFullHelp[name]
fmt.Fprintf(&builder, "| %-*s | %-*s | %-*s |\n",
maxNameLength, "`"+labelName(name)+"`", // enclose in backticks
maxDescriptionLength, help.Short,
maxTypeLength, help.Type,
)
}
return builder.String()
}
func generateTableHeader(maxNameLength, maxDescriptionLength, maxTypeLength int) string {
return fmt.Sprintf(
"| %-*s | %-*s | %-*s |",
maxNameLength, "Label name",
maxDescriptionLength, "Description",
maxTypeLength, "Type",
)
}
func generateTableHeaderSeparator(maxNameLength, maxDescriptionLength, maxTypeLength int) string {
return fmt.Sprintf(
"| %s | %s | %s |",
strings.Repeat("-", maxNameLength),
strings.Repeat("-", maxDescriptionLength),
strings.Repeat("-", maxTypeLength),
)
}
// GetLabelHelpFor returns the help for a specific label.
func GetLabelHelpFor(labelname string, asMarkdown bool) string {
help, ok := labelFullHelp[labelname]
if !ok {
return "No help available for " + labelname + "."
}
help.Long = strings.TrimPrefix(help.Long, "\n")
help.Example = strings.TrimPrefix(help.Example, "\n")
help.Short = strings.TrimPrefix(help.Short, "\n")
// get help template
helpTemplate := getHelpTemplate(asMarkdown)
if asMarkdown {
// enclose templates in backticks
help.Long = regexp.MustCompile(`\{\{(.*?)\}\}`).ReplaceAllString(help.Long, "`{{$1}}`")
help.Long = strings.ReplaceAll(help.Long, "__APP__", "`__APP__`")
} else {
help.Long = strings.ReplaceAll(help.Long, " \n", "\n")
help.Long = strings.ReplaceAll(help.Long, "`", "")
help.Long = strings.ReplaceAll(help.Long, "<code>", "")
help.Long = strings.ReplaceAll(help.Long, "</code>", "")
help.Long = utils.WordWrap(help.Long, 80)
}
var buf bytes.Buffer
template.Must(template.New("shorthelp").Parse(help.Long)).Execute(&buf, struct {
KatenaryPrefix string
}{
KatenaryPrefix: katenaryLabelPrefix,
})
help.Long = buf.String()
buf.Reset()
template.Must(template.New("example").Parse(help.Example)).Execute(&buf, struct {
KatenaryPrefix string
}{
KatenaryPrefix: katenaryLabelPrefix,
})
help.Example = buf.String()
buf.Reset()
template.Must(template.New("complete").Parse(helpTemplate)).Execute(&buf, struct {
Name string
Help Help
KatenaryPrefix string
}{
Name: labelname,
Help: help,
KatenaryPrefix: katenaryLabelPrefix,
})
return buf.String()
}
// GetLabelNames returns a sorted list of all katenary label names.
func GetLabelNames() []string {
var names []string
for name := range labelFullHelp {
names = append(names, name)
}
sort.Strings(names)
return names
}
func getHelpTemplate(asMarkdown bool) string {
if asMarkdown {
return `## {{ .KatenaryPrefix }}/{{ .Name }}
{{ .Help.Short }}
**Type**: ` + "`" + `{{ .Help.Type }}` + "`" + `
{{ .Help.Long }}
**Example:**` + "\n\n```yaml\n" + `{{ .Help.Example }}` + "\n```\n"
}
return `{{ .KatenaryPrefix }}/{{ .Name }}: {{ .Help.Short }}
Type: {{ .Help.Type }}
{{ .Help.Long }}
Example:
{{ .Help.Example }}
`
}