Files
sealos/pkg/utils/strings/strings.go
T
Zihan Li 25ac669cd6 feature: sealos create support for environment variable based template rendering (#4222)
* feature: environment variable based template rendering in sealos create

* add: goimports tools

* update: goimports tools

* update: goimports tools

* fix golangci lint error

* remove docs

* remove docs

* fix: refactor template rendering logic, abstract common func

* fix ci
2023-11-02 23:44:07 +08:00

237 lines
5.5 KiB
Go

/*
Copyright 2021 cuisongliu@qq.com.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package strings
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"unicode"
"github.com/labring/sealos/pkg/constants"
"github.com/labring/sealos/pkg/template"
"github.com/labring/sealos/pkg/utils/file"
"golang.org/x/exp/slices"
"github.com/labring/sealos/pkg/utils/logger"
)
func NotInIPList(slice []string, key string) bool {
for _, s := range slice {
if key == strings.Split(s, ":")[0] {
return false
}
}
return true
}
var emptyLineRe = regexp.MustCompile(`^\s*$`)
func IsEmptyLine(str string) bool {
return emptyLineRe.MatchString(str)
}
func TrimWS(str string) string {
return strings.Trim(str, "\n\t")
}
func TrimSpaceWS(str string) string {
return strings.TrimRight(str, " \n\t")
}
func FilterNonEmptyFromSlice(list []string) (ret []string) {
for i := range list {
if strings.TrimSpace(list[i]) != "" {
ret = append(ret, list[i])
}
}
return
}
func FilterNonEmptyFromString(s, sep string) []string {
data := strings.Split(s, sep)
return FilterNonEmptyFromSlice(data)
}
// RemoveDuplicate removes duplicate entry in the list.
func RemoveDuplicate(list []string) []string {
var result []string
flagMap := map[string]struct{}{}
for _, v := range list {
if _, ok := flagMap[v]; !ok {
flagMap[v] = struct{}{}
result = append(result, v)
}
}
return result
}
// RemoveSubSlice remove dst element from src slice
func RemoveSubSlice(src, dst []string) []string {
var ret []string
for _, s := range src {
if !slices.Contains(dst, s) {
ret = append(ret, s)
}
}
return ret
}
func RemoveFromSlice(ss []string, s string) (result []string) {
for _, v := range ss {
if v != s {
result = append(result, v)
}
}
return
}
func Merge(ss []string, s string) []string {
var ret []string
for i := range ss {
if ss[i] != s {
ret = append(ret, ss[i])
}
}
ret = append(ret, s)
return ret
}
func FormatSize(size int64) (Size string) {
if size < 1024 {
Size = fmt.Sprintf("%.2fB", float64(size)/float64(1))
} else if size < (1024 * 1024) {
Size = fmt.Sprintf("%.2fKB", float64(size)/float64(1024))
} else if size < (1024 * 1024 * 1024) {
Size = fmt.Sprintf("%.2fMB", float64(size)/float64(1024*1024))
} else {
Size = fmt.Sprintf("%.2fGB", float64(size)/float64(1024*1024*1024))
}
return
}
func IsLetterOrNumber(k string) bool {
for _, r := range k {
if r == '_' {
continue
}
if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
return false
}
}
return true
}
func RenderShellWithEnv(shell string, envs map[string]string) string {
var env string
for k, v := range envs {
env = fmt.Sprintf("%s%s=\"%s\" ", env, k, v)
}
if env == "" {
return shell
}
return fmt.Sprintf("export %s; %s", env, shell)
}
func RenderTextWithEnv(text string, envs map[string]string) string {
replaces := make(map[string]string, 0)
for k, v := range envs {
replaces[fmt.Sprintf("$(%s)", k)] = v
replaces[fmt.Sprintf("${%s}", k)] = v
replaces[fmt.Sprintf("$%s", k)] = v
}
logger.Debug("renderTextFromEnv: replaces: %+v ; text: %s", replaces, text)
for o, n := range replaces {
text = strings.ReplaceAll(text, o, n)
}
return text
}
func RenderTemplatesWithEnv(filePaths string, envs map[string]string) error {
var (
renderEtc = filepath.Join(filePaths, constants.EtcDirName)
renderScripts = filepath.Join(filePaths, constants.ScriptsDirName)
renderManifests = filepath.Join(filePaths, constants.ManifestsDirName)
)
for _, dir := range []string{renderEtc, renderScripts, renderManifests} {
logger.Debug("render env dir: %s", dir)
if !file.IsExist(dir) {
logger.Debug("Directory %s does not exist, skipping", dir)
continue
}
if err := filepath.Walk(dir, func(path string, info os.FileInfo, errIn error) error {
if errIn != nil {
return errIn
}
if info.IsDir() || !strings.HasSuffix(info.Name(), constants.TemplateSuffix) {
return nil
}
fileName := strings.TrimSuffix(path, constants.TemplateSuffix)
if file.IsExist(fileName) {
if err := os.Remove(fileName); err != nil {
logger.Warn("failed to remove existing file [%s]: %v", fileName, err)
}
}
writer, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to open file [%s] for rendering: %v", path, err)
}
defer writer.Close()
body, err := file.ReadAll(path)
if err != nil {
return err
}
t, isOk, err := template.TryParse(string(body))
if isOk {
if err != nil {
return fmt.Errorf("failed to create template: %s %v", path, err)
}
if err := t.Execute(writer, envs); err != nil {
return fmt.Errorf("failed to render env template: %s %v", path, err)
}
} else {
return errors.New("parse template failed")
}
return nil
}); err != nil {
return fmt.Errorf("failed to render templates in directory %s: %v", dir, err)
}
}
return nil
}
func TrimQuotes(s string) string {
if len(s) >= 2 {
if c := s[len(s)-1]; s[0] == c && (c == '"' || c == '\'') {
return s[1 : len(s)-1]
}
}
return s
}