github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/build/kubefile/parser/utils.go (about) 1 // Copyright © 2022 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 parser 16 17 import ( 18 "fmt" 19 "io/fs" 20 "os" 21 "path/filepath" 22 "strings" 23 24 "github.com/sealerio/sealer/pkg/define/application" 25 osi "github.com/sealerio/sealer/utils/os" 26 27 "github.com/sirupsen/logrus" 28 ) 29 30 const ( 31 schemeLocal = "local://" 32 schemeHTTP = "http://" 33 schemeHTTPS = "https://" 34 ) 35 36 func mergeLines(lines ...string) string { 37 return strings.Join(lines, "\n") 38 } 39 40 func makeItDir(str string) string { 41 if !strings.HasSuffix(str, "/") { 42 return str + "/" 43 } 44 return str 45 } 46 47 func isLocal(str string) bool { 48 return strings.HasPrefix(str, schemeLocal) 49 } 50 51 func trimLocal(str string) string { 52 return strings.TrimPrefix(str, schemeLocal) 53 } 54 55 func isRemote(str string) bool { 56 return strings.HasPrefix(str, schemeHTTP) || strings.HasPrefix(str, schemeHTTPS) 57 } 58 59 func isHelm(sources ...string) (bool, error) { 60 isChartsArtifactEnough := func(path string) bool { 61 return osi.IsFileExist(filepath.Join(path, "Chart.yaml")) && 62 osi.IsFileExist(filepath.Join(path, "values.yaml")) && 63 osi.IsFileExist(filepath.Join(path, "templates")) 64 } 65 66 isHelmInDir := func(dirPath string) (bool, error) { 67 isH := false 68 err := filepath.WalkDir(dirPath, func(path string, d fs.DirEntry, err error) error { 69 if err != nil { 70 return err 71 } 72 73 isH = isChartsArtifactEnough(path) 74 return filepath.SkipDir 75 }) 76 77 if err == filepath.SkipDir { 78 err = nil 79 } 80 81 return isH, err 82 } 83 84 chartInTargetsRoot := 0 85 oneOfChartsArtifact := func(str string) { 86 switch { 87 case strings.HasSuffix(str, "Chart.yaml"): 88 chartInTargetsRoot |= 1 89 case strings.HasSuffix(str, "values.yaml"): 90 chartInTargetsRoot |= 2 91 case strings.HasSuffix(str, "templates"): 92 chartInTargetsRoot |= 4 93 } 94 } 95 96 for _, source := range sources { 97 s, err := os.Stat(source) 98 if err != nil { 99 return false, fmt.Errorf("failed to stat %s: %v", source, err) 100 } 101 102 if s.IsDir() { 103 if isH, err := isHelmInDir(source); err != nil { 104 return false, fmt.Errorf("error in calling isHelmInDir: %v", err) 105 } else if isH { 106 return true, nil 107 } 108 109 files, err := os.ReadDir(source) 110 if err != nil { 111 return false, fmt.Errorf("failed to read dir (%s) in isHelm: %s", source, err) 112 } 113 for _, f := range files { 114 if !f.IsDir() { 115 oneOfChartsArtifact(f.Name()) 116 } 117 } 118 } else { 119 oneOfChartsArtifact(source) 120 } 121 } 122 123 return chartInTargetsRoot == 7, nil 124 } 125 126 // getApplicationType: 127 // walk through files to copy,try to find obvious application type, 128 // we only support helm,kube,shell at present, and it is a strict match file suffix. 129 // if not found, will return "". 130 func getApplicationType(sources []string) (string, error) { 131 isHelmType, helmErr := isHelm(sources...) 132 if helmErr != nil { 133 return "", helmErr 134 } 135 136 if isHelmType { 137 return application.HelmApp, nil 138 } 139 140 appTypeFunc := func(fileName string) string { 141 ext := strings.ToLower(filepath.Ext(fileName)) 142 if ext == ".sh" { 143 return application.ShellApp 144 } 145 146 if ext == ".yaml" || ext == ".yml" { 147 return application.KubeApp 148 } 149 150 return application.UnknownApp 151 } 152 153 var appTypeList []string 154 for _, source := range sources { 155 s, err := os.Stat(source) 156 if err != nil { 157 return "", fmt.Errorf("failed to stat %s: %v", source, err) 158 } 159 160 // get app type by dir 161 if s.IsDir() { 162 err = filepath.Walk(source, func(path string, f fs.FileInfo, err error) error { 163 if err != nil { 164 return err 165 } 166 if f.IsDir() { 167 return nil 168 } 169 170 appTypeList = append(appTypeList, appTypeFunc(f.Name())) 171 return nil 172 }) 173 174 if err != nil { 175 return "", fmt.Errorf("failed to walk copy dir %s: %v", source, err) 176 } 177 continue 178 } 179 180 // get app type by file 181 appTypeList = append(appTypeList, appTypeFunc(source)) 182 } 183 184 //matches the file suffix strictly 185 var isShell, isKube bool 186 for _, appType := range appTypeList { 187 if appType == application.UnknownApp { 188 logrus.Debugf("application type not detected in %s,%s,%s", 189 application.KubeApp, application.HelmApp, application.ShellApp) 190 return "", nil 191 } 192 193 if appType == application.ShellApp { 194 isShell = true 195 } 196 197 if appType == application.KubeApp { 198 isKube = true 199 } 200 } 201 202 if isShell && !isKube { 203 return application.ShellApp, nil 204 } 205 206 if isKube && !isShell { 207 return application.KubeApp, nil 208 } 209 210 return "", nil 211 } 212 213 // getApplicationFiles: get application files 214 func getApplicationFiles(appName, appType string, sources []string) ([]string, error) { 215 if appType == "" { 216 return nil, nil 217 } 218 219 if appType == application.HelmApp { 220 return []string{appName}, nil 221 } 222 223 var launchFiles []string 224 225 for _, source := range sources { 226 s, err := os.Stat(source) 227 if err != nil { 228 return nil, fmt.Errorf("failed to stat %s: %v", source, err) 229 } 230 231 // get app launchFile if source is a dir 232 if s.IsDir() { 233 err = filepath.Walk(source, func(path string, f fs.FileInfo, err error) error { 234 if err != nil { 235 return err 236 } 237 238 if f.IsDir() { 239 return nil 240 } 241 242 launchFiles = append(launchFiles, strings.TrimPrefix(path, source)) 243 return nil 244 }) 245 if err != nil { 246 return nil, fmt.Errorf("failed to walk application dir %s: %v", source, err) 247 } 248 249 // if type is shell, only use first build context 250 if appType == application.ShellApp { 251 return launchFiles, nil 252 } 253 continue 254 } 255 // get app launchFile if source is a file 256 launchFiles = append(launchFiles, filepath.Base(source)) 257 258 // if type is shell, only use first build context 259 if appType == application.ShellApp { 260 return launchFiles, nil 261 } 262 } 263 264 return launchFiles, nil 265 }