github.com/tilt-dev/tilt@v0.36.0/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.Components...) 90 paths = append(paths, content.Resources...) 91 92 for _, p := range paths { 93 abs := filepath.Join(dir, p) 94 if ospath.IsDir(abs) { 95 curDeps, err := dependenciesForKustomization(filepath.Join(dir, p)) 96 if err != nil { 97 return nil, err 98 } 99 deps = append(deps, curDeps...) 100 } else { 101 deps = append(deps, abs) 102 } 103 } 104 105 deps = append(deps, path) 106 for _, patch := range content.Patches { 107 if patch.Path != "" { 108 deps = append(deps, filepath.Join(dir, patch.Path)) 109 } 110 } 111 for _, patch := range content.PatchesStrategicMerge { 112 deps = append(deps, filepath.Join(dir, string(patch))) 113 } 114 deps = append(deps, joinPaths(dir, content.Crds)...) 115 for _, patch := range content.PatchesJson6902 { 116 deps = append(deps, filepath.Join(dir, patch.Path)) 117 } 118 for _, generator := range content.ConfigMapGenerator { 119 deps = append(deps, joinPaths(dir, generator.FileSources)...) 120 } 121 122 return deps, nil 123 } 124 125 func Deps(baseDir string) ([]string, error) { 126 deps, err := dependenciesForKustomization(baseDir) 127 if err != nil { 128 return nil, err 129 } 130 131 return uniqDependencies(deps), nil 132 } 133 134 func joinPaths(root string, paths []string) []string { 135 var list []string 136 137 for _, path := range paths { 138 list = append(list, filepath.Join(root, path)) 139 } 140 141 return list 142 } 143 144 func uniqDependencies(deps []string) []string { 145 seen := make(map[string]struct{}, len(deps)) 146 j := 0 147 for _, v := range deps { 148 if _, ok := seen[v]; ok { 149 continue 150 } 151 seen[v] = struct{}{} 152 deps[j] = v 153 j++ 154 } 155 156 return deps[:j] 157 }