github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/kustomize/dependencies.go (about) 1 /** 2 Code for parsing Kustomize YAML and analyzing dependencies. 3 4 Adapted from 5 https://github.com/GoogleContainerTools/skaffold/blob/511c77f1736b657415500eb9b820ae7e4f753347/pkg/skaffold/deploy/kustomize.go 6 7 Copyright 2018 The Skaffold Authors 8 9 Licensed under the Apache License, Version 2.0 (the "License"); 10 you may not use this file except in compliance with the License. 11 You may obtain a copy of the License at 12 13 http://www.apache.org/licenses/LICENSE-2.0 14 15 Unless required by applicable law or agreed to in writing, software 16 distributed under the License is distributed on an "AS IS" BASIS, 17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 See the License for the specific language governing permissions and 19 limitations under the License. 20 */ 21 22 package kustomize 23 24 import ( 25 "fmt" 26 "os" 27 "path/filepath" 28 "strings" 29 30 "github.com/tilt-dev/tilt/internal/ospath" 31 32 yaml "gopkg.in/yaml.v2" 33 "sigs.k8s.io/kustomize/api/konfig" 34 "sigs.k8s.io/kustomize/api/types" 35 ) 36 37 // Mostly taken from the [kustomize source code](https://github.com/kubernetes-sigs/kustomize/blob/ee68a9c450bc884b0d657fb7e3d62eb1ac59d14f/pkg/target/kusttarget.go#L97) itself. 38 func loadKustFile(dir string) ([]byte, string, error) { 39 var content []byte 40 var path string 41 match := 0 42 for _, kf := range konfig.RecognizedKustomizationFileNames() { 43 p := filepath.Join(dir, kf) 44 c, err := os.ReadFile(p) 45 if err == nil { 46 path = p 47 match += 1 48 content = c 49 } 50 } 51 52 switch match { 53 case 0: 54 return nil, "", fmt.Errorf( 55 "unable to find one of %v in directory '%s'", 56 konfig.RecognizedKustomizationFileNames(), dir) 57 case 1: 58 return content, path, nil 59 default: 60 return nil, "", fmt.Errorf( 61 "Found multiple kustomization files under: %s\n", dir) 62 } 63 } 64 65 // Code for parsing Kustomize adapted from Kustomize 66 // https://github.com/kubernetes-sigs/kustomize/blob/ee68a9c450bc884b0d657fb7e3d62eb1ac59d14f/pkg/target/kusttarget.go#L97 67 // 68 // Code for parsing out dependencies copied from Skaffold 69 // https://github.com/GoogleContainerTools/skaffold/blob/511c77f1736b657415500eb9b820ae7e4f753347/pkg/skaffold/deploy/kustomize.go 70 func dependenciesForKustomization(dir string) ([]string, error) { 71 var deps []string 72 73 buf, path, err := loadKustFile(dir) 74 if err != nil { 75 return nil, err 76 } 77 78 content := types.Kustomization{} 79 if err := yaml.Unmarshal(buf, &content); err != nil { 80 return nil, err 81 } 82 83 errs := content.EnforceFields() 84 if len(errs) > 0 { 85 return nil, fmt.Errorf("Failed to read kustomization file under %s:\n"+strings.Join(errs, "\n"), dir) 86 } 87 88 paths := append([]string{}, content.Bases...) 89 paths = append(paths, content.Resources...) 90 91 for _, p := range paths { 92 abs := filepath.Join(dir, p) 93 if ospath.IsDir(abs) { 94 curDeps, err := dependenciesForKustomization(filepath.Join(dir, p)) 95 if err != nil { 96 return nil, err 97 } 98 deps = append(deps, curDeps...) 99 } else { 100 deps = append(deps, abs) 101 } 102 } 103 104 deps = append(deps, path) 105 for _, patch := range content.Patches { 106 if patch.Path != "" { 107 deps = append(deps, filepath.Join(dir, patch.Path)) 108 } 109 } 110 for _, patch := range content.PatchesStrategicMerge { 111 deps = append(deps, filepath.Join(dir, string(patch))) 112 } 113 deps = append(deps, joinPaths(dir, content.Crds)...) 114 for _, patch := range content.PatchesJson6902 { 115 deps = append(deps, filepath.Join(dir, patch.Path)) 116 } 117 for _, generator := range content.ConfigMapGenerator { 118 deps = append(deps, joinPaths(dir, generator.FileSources)...) 119 } 120 121 return deps, nil 122 } 123 124 func Deps(baseDir string) ([]string, error) { 125 deps, err := dependenciesForKustomization(baseDir) 126 if err != nil { 127 return nil, err 128 } 129 130 return uniqDependencies(deps), nil 131 } 132 133 func joinPaths(root string, paths []string) []string { 134 var list []string 135 136 for _, path := range paths { 137 list = append(list, filepath.Join(root, path)) 138 } 139 140 return list 141 } 142 143 func uniqDependencies(deps []string) []string { 144 seen := make(map[string]struct{}, len(deps)) 145 j := 0 146 for _, v := range deps { 147 if _, ok := seen[v]; ok { 148 continue 149 } 150 seen[v] = struct{}{} 151 deps[j] = v 152 j++ 153 } 154 155 return deps[:j] 156 }