Skip to content

Commit

Permalink
feat: add render template subcommand for sealctl
Browse files Browse the repository at this point in the history
  • Loading branch information
fengxsong committed Sep 8, 2023
1 parent 3f5f706 commit 5da9d4e
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 4 deletions.
125 changes: 125 additions & 0 deletions cmd/sealctl/cmd/render.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright © 2023 sealos.
//
// 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 cmd

import (
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/cli/values"
"helm.sh/helm/v3/pkg/getter"

"github.com/labring/sealos/pkg/template"
fileutils "github.com/labring/sealos/pkg/utils/file"
"github.com/labring/sealos/pkg/utils/logger"
"github.com/labring/sealos/pkg/utils/maps"
)

func newRenderCommand() *cobra.Command {
var (
valueFiles []string
sets []string
)
cmd := &cobra.Command{
Use: "render",
Short: "render template files with values and envs",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return runRender(valueFiles, sets, args)
},
}
cmd.Flags().StringSliceVarP(&valueFiles, "values", "f", []string{}, "values files for context")
cmd.Flags().StringSliceVar(&sets, "set", []string{}, "k/v sets for context")
return cmd
}

func loadValues(valueFiles, sets []string) (map[string]interface{}, error) {
valueOpt := &values.Options{
ValueFiles: valueFiles,
Values: sets,
}
return valueOpt.MergeValues([]getter.Provider{{
Schemes: []string{"http", "https"},
New: getter.NewHTTPGetter,
}})
}

func findTemplateFiles(paths ...string) ([]string, error) {
var ret []string
for i := range paths {
files, err := fileutils.FindFilesMatchExtension(paths[i], ".tpl", ".tmpl")
if err != nil {
return nil, err
}
ret = append(ret, files...)
}
return ret, nil
}

func runRender(valueFiles, sets []string, args []string) error {
mergedValues, err := loadValues(valueFiles, sets)
if err != nil {
return err
}
envs := maps.FromSlice(os.Environ())
data := make(map[string]interface{})
// For compatibility with older templates
for k, v := range envs {
data[k] = v
}

data["Values"] = mergedValues
data["Env"] = envs

filepaths, err := findTemplateFiles(args...)
if err != nil {
return err
}
for i := range filepaths {
if err := func(fp string) error {
logger.Debug("found template file %s, trying to rendering", fp)
trimed := strings.TrimSuffix(fp, filepath.Ext(fp))
if fileutils.IsExist(trimed) {
logger.Debug("found existing file %s, override it", trimed)
}
file, err := os.OpenFile(trimed, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer file.Close()
b, err := fileutils.ReadAll(fp)
if err != nil {
return err
}
t, err := template.Parse(string(b))
if err != nil {
return err
}
if err = t.Execute(file, data); err != nil {
return err
}
logger.Info("render %s from %s completed", trimed, fp)
return nil
}(filepaths[i]); err != nil {
return err
}
}
return nil
}

func init() {
rootCmd.AddCommand(newRenderCommand())
}
4 changes: 0 additions & 4 deletions pkg/template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ func TryParse(text string) (*template.Template, bool, error) {
return tmp, !isFailed, err
}

func ParseFiles(filenames ...string) (*template.Template, error) {
return defaultTpl.ParseFiles(filenames...)
}

func Must(t *template.Template, err error) *template.Template {
return template.Must(t, err)
}
Expand Down
36 changes: 36 additions & 0 deletions pkg/utils/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"os"
"path/filepath"
"strings"

"k8s.io/apimachinery/pkg/util/sets"
)

// DiffWithCallback diff with callback function.
Expand Down Expand Up @@ -128,3 +130,37 @@ func Cmp(src, dest string, chunkSize int) (same bool, err error) {
}
}
}

func FindFilesMatchExtension(base string, exts ...string) ([]string, error) {
absPath, err := filepath.Abs(base)
if err != nil {
return nil, err
}
stat, err := os.Stat(absPath)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
if stat.Mode().IsRegular() {
return []string{absPath}, nil
} else if stat.IsDir() {
var ret []string
extensions := sets.NewString(exts...)
err = filepath.WalkDir(absPath, func(path string, de fs.DirEntry, err error) error {
if err != nil {
return err
}
if de.IsDir() {
return nil
}
if ext := filepath.Ext(path); extensions.Has(ext) {
ret = append(ret, path)
}
return nil
})
return ret, err
}
return nil, nil
}

0 comments on commit 5da9d4e

Please sign in to comment.