github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/application/files.go (about) 1 // Copyright © 2023 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package application 16 17 import ( 18 "bytes" 19 "errors" 20 "fmt" 21 "io" 22 "os" 23 "path/filepath" 24 25 "github.com/imdario/mergo" 26 "github.com/sealerio/sealer/pkg/env" 27 v2 "github.com/sealerio/sealer/types/api/v2" 28 osUtils "github.com/sealerio/sealer/utils/os" 29 "github.com/sirupsen/logrus" 30 "gopkg.in/yaml.v3" 31 ) 32 33 func newFileProcessor(appFile v2.AppFile) (FileProcessor, error) { 34 switch appFile.Strategy { 35 case v2.OverWriteStrategy: 36 return overWriteProcessor{appFile}, nil 37 case v2.MergeStrategy: 38 return mergeProcessor{appFile}, nil 39 } 40 41 return nil, fmt.Errorf("failed to init fileProcessor,%s is not register", appFile.Strategy) 42 } 43 44 // overWriteProcessor :this will overwrite the FilePath with the Values. 45 type overWriteProcessor struct { 46 v2.AppFile 47 } 48 49 func (r overWriteProcessor) Process(appRoot string) error { 50 target := filepath.Join(appRoot, r.Path) 51 52 logrus.Debugf("will do overwrite processor on the file : %s", target) 53 err := osUtils.NewCommonWriter(target).WriteFile([]byte(r.Data)) 54 if err != nil { 55 return fmt.Errorf("failed to write to file %s with raw mode: %v", target, err) 56 } 57 return nil 58 } 59 60 // mergeProcessor :this will merge the FilePath with the Values. 61 // Only files in yaml format are supported. 62 // if Strategy is "merge" will deeply merge each yaml file section. 63 type mergeProcessor struct { 64 v2.AppFile 65 } 66 67 func (m mergeProcessor) Process(appRoot string) error { 68 var ( 69 result [][]byte 70 srcDataMap = make(map[string]interface{}) 71 ) 72 73 err := yaml.Unmarshal([]byte(m.Data), &srcDataMap) 74 if err != nil { 75 return fmt.Errorf("failed to load config data: %v", err) 76 } 77 78 target := filepath.Join(appRoot, m.Path) 79 80 logrus.Debugf("will do merge processor on the file : %s", target) 81 82 f, err := os.Open(filepath.Clean(target)) 83 if err != nil { 84 return err 85 } 86 87 dec := yaml.NewDecoder(f) 88 for { 89 destDataMap := make(map[string]interface{}) 90 err = dec.Decode(destDataMap) 91 if errors.Is(err, io.EOF) { 92 break 93 } 94 if err != nil { 95 return fmt.Errorf("failed to unmarshal config data: %v", err) 96 } 97 98 err = mergo.Merge(&destDataMap, &srcDataMap, mergo.WithOverride) 99 if err != nil { 100 return fmt.Errorf("failed to merge config: %v", err) 101 } 102 103 out, err := yaml.Marshal(destDataMap) 104 if err != nil { 105 return err 106 } 107 108 result = append(result, out) 109 } 110 111 err = osUtils.NewCommonWriter(target).WriteFile(bytes.Join(result, []byte("\n---\n"))) 112 if err != nil { 113 return fmt.Errorf("failed to write to file %s with raw mode: %v", target, err) 114 } 115 return nil 116 } 117 118 // envRender :this will render the FilePath with the Values. 119 type envRender struct { 120 envData map[string]string 121 } 122 123 func (e envRender) Process(appRoot string) error { 124 if len(e.envData) == 0 { 125 return nil 126 } 127 128 logrus.Debugf("will render the dir : %s with the values: %+v\n", appRoot, e.envData) 129 130 return env.RenderTemplate(appRoot, e.envData) 131 }