Files
katenary/utils/utils.go
Patrice Ferlet 1fa07c29e5 Work in progress on compose-go v2
As explained in #102, the compose-go package changes types and needs
massive changes.
This branches is OK for now, but needs some tests.
It MUST be quickly fixed to be integrated in main branch.
2024-12-28 19:37:51 +01:00

194 lines
5.4 KiB
Go

package utils
import (
"bytes"
"fmt"
"log"
"path/filepath"
"strings"
"github.com/compose-spec/compose-go/v2/types"
"github.com/mitchellh/go-wordwrap"
"github.com/thediveo/netdb"
"gopkg.in/yaml.v3"
corev1 "k8s.io/api/core/v1"
)
// TplName returns the name of the kubernetes resource as a template string.
// It is used in the templates and defined in _helper.tpl file.
func TplName(serviceName, appname string, suffix ...string) string {
if len(suffix) > 0 {
suffix[0] = "-" + suffix[0]
}
for i, s := range suffix {
// replae all "_" with "-"
suffix[i] = strings.ReplaceAll(s, "_", "-")
}
serviceName = strings.ReplaceAll(serviceName, "_", "-")
return `{{ include "` + appname + `.fullname" . }}-` + serviceName + strings.Join(suffix, "-")
}
// Int32Ptr returns a pointer to an int32.
func Int32Ptr(i int32) *int32 { return &i }
// StrPtr returns a pointer to a string.
func StrPtr(s string) *string { return &s }
// CountStartingSpaces counts the number of spaces at the beginning of a string.
func CountStartingSpaces(line string) int {
count := 0
for _, char := range line {
if char == ' ' {
count++
} else {
break
}
}
return count
}
// GetKind returns the kind of the resource from the file path.
func GetKind(path string) (kind string) {
defer func() {
if r := recover(); r != nil {
kind = ""
}
}()
filename := filepath.Base(path)
parts := strings.Split(filename, ".")
if len(parts) == 2 {
kind = parts[0]
} else {
kind = strings.Split(path, ".")[1]
}
return
}
// Wrap wraps a string with a string above and below. It will respect the indentation of the src string.
func Wrap(src, above, below string) string {
spaces := strings.Repeat(" ", CountStartingSpaces(src))
return spaces + above + "\n" + src + "\n" + spaces + below
}
// GetServiceNameByPort returns the service name for a port. It the service name is not found, it returns an empty string.
func GetServiceNameByPort(port int) string {
name := ""
info := netdb.ServiceByPort(port, "tcp")
if info != nil {
name = info.Name
}
return name
}
// GetContainerByName returns a container by name and its index in the array. It returns nil, -1 if not found.
func GetContainerByName(name string, containers []corev1.Container) (*corev1.Container, int) {
for index, c := range containers {
if c.Name == name {
return &c, index
}
}
return nil, -1
}
// GetContainerByName returns a container by name and its index in the array.
func TplValue(serviceName, variable string, pipes ...string) string {
if len(pipes) == 0 {
return `{{ tpl .Values.` + serviceName + `.` + variable + ` $ }}`
} else {
return `{{ tpl .Values.` + serviceName + `.` + variable + ` $ | ` + strings.Join(pipes, " | ") + ` }}`
}
}
// PathToName converts a path to a kubernetes complient name.
func PathToName(path string) string {
if len(path) == 0 {
return ""
}
path = filepath.Clean(path)
if path[0] == '/' || path[0] == '.' {
path = path[1:]
}
path = strings.ReplaceAll(path, "_", "-")
path = strings.ReplaceAll(path, "/", "-")
path = strings.ReplaceAll(path, ".", "-")
path = strings.ToLower(path)
return path
}
// EnvConfig is a struct to hold the description of an environment variable.
type EnvConfig struct {
Service types.ServiceConfig
Description string
}
// GetValuesFromLabel returns a map of values from a label.
func GetValuesFromLabel(service types.ServiceConfig, LabelValues string) map[string]*EnvConfig {
descriptions := make(map[string]*EnvConfig)
if v, ok := service.Labels[LabelValues]; ok {
labelContent := []any{}
err := yaml.Unmarshal([]byte(v), &labelContent)
if err != nil {
log.Printf("Error parsing label %s: %s", v, err)
log.Fatal(err)
}
for _, value := range labelContent {
switch val := value.(type) {
case string:
descriptions[val] = nil
case map[string]interface{}:
for k, v := range value.(map[string]interface{}) {
descriptions[k] = &EnvConfig{Service: service, Description: v.(string)}
}
case map[interface{}]interface{}:
for k, v := range value.(map[interface{}]interface{}) {
descriptions[k.(string)] = &EnvConfig{Service: service, Description: v.(string)}
}
default:
log.Fatalf("Unknown type in label: %s %T", LabelValues, value)
}
}
}
return descriptions
}
// WordWrap wraps a string to a given line width. Warning: it may break the string. You need to check the result.
func WordWrap(text string, lineWidth int) string {
return wordwrap.WrapString(text, uint(lineWidth))
}
// Confirm asks a question and returns true if the answer is y.
func Confirm(question string, icon ...Icon) bool {
if len(icon) > 0 {
fmt.Printf("%s %s [y/N] ", icon[0], question)
} else {
fmt.Print(question + " [y/N] ")
}
var response string
fmt.Scanln(&response)
return strings.ToLower(response) == "y"
}
// EncodeBasicYaml encodes a basic yaml from an interface.
func EncodeBasicYaml(data any) ([]byte, error) {
buf := bytes.NewBuffer(nil)
enc := yaml.NewEncoder(buf)
enc.SetIndent(2)
err := enc.Encode(data)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// FixedResourceName returns a resource name without underscores to respect the kubernetes naming convention.
func FixedResourceName(name string) string {
return strings.ReplaceAll(name, "_", "-")
}
// AsResourceName returns a resource name with underscores to respect the kubernetes naming convention.
// It's the opposite of FixedResourceName.
func AsResourceName(name string) string {
return strings.ReplaceAll(name, "-", "_")
}