github.com/x-helm/helm@v3.0.0-beta.3+incompatible/pkg/action/dependency.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package action 18 19 import ( 20 "fmt" 21 "io" 22 "os" 23 "path/filepath" 24 25 "github.com/Masterminds/semver" 26 "github.com/gosuri/uitable" 27 28 "helm.sh/helm/pkg/chart" 29 "helm.sh/helm/pkg/chart/loader" 30 ) 31 32 // Dependency is the action for building a given chart's dependency tree. 33 // 34 // It provides the implementation of 'helm dependency' and its respective subcommands. 35 type Dependency struct { 36 Verify bool 37 Keyring string 38 SkipRefresh bool 39 } 40 41 // NewDependency creates a new Dependency object with the given configuration. 42 func NewDependency() *Dependency { 43 return &Dependency{} 44 } 45 46 // List executes 'helm dependency list'. 47 func (d *Dependency) List(chartpath string, out io.Writer) error { 48 c, err := loader.Load(chartpath) 49 if err != nil { 50 return err 51 } 52 53 if c.Metadata.Dependencies == nil { 54 fmt.Fprintf(out, "WARNING: no dependencies at %s\n", filepath.Join(chartpath, "charts")) 55 return nil 56 } 57 58 d.printDependencies(chartpath, out, c.Metadata.Dependencies) 59 fmt.Fprintln(out) 60 d.printMissing(chartpath, out, c.Metadata.Dependencies) 61 return nil 62 } 63 64 func (d *Dependency) dependencyStatus(chartpath string, dep *chart.Dependency) string { 65 filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*") 66 67 switch archives, err := filepath.Glob(filepath.Join(chartpath, "charts", filename)); { 68 case err != nil: 69 return "bad pattern" 70 case len(archives) > 1: 71 return "too many matches" 72 case len(archives) == 1: 73 archive := archives[0] 74 if _, err := os.Stat(archive); err == nil { 75 c, err := loader.Load(archive) 76 if err != nil { 77 return "corrupt" 78 } 79 if c.Name() != dep.Name { 80 return "misnamed" 81 } 82 83 if c.Metadata.Version != dep.Version { 84 constraint, err := semver.NewConstraint(dep.Version) 85 if err != nil { 86 return "invalid version" 87 } 88 89 v, err := semver.NewVersion(c.Metadata.Version) 90 if err != nil { 91 return "invalid version" 92 } 93 94 if constraint.Check(v) { 95 return "ok" 96 } 97 return "wrong version" 98 } 99 return "ok" 100 } 101 } 102 103 folder := filepath.Join(chartpath, "charts", dep.Name) 104 if fi, err := os.Stat(folder); err != nil { 105 return "missing" 106 } else if !fi.IsDir() { 107 return "mispackaged" 108 } 109 110 c, err := loader.Load(folder) 111 if err != nil { 112 return "corrupt" 113 } 114 115 if c.Name() != dep.Name { 116 return "misnamed" 117 } 118 119 if c.Metadata.Version != dep.Version { 120 constraint, err := semver.NewConstraint(dep.Version) 121 if err != nil { 122 return "invalid version" 123 } 124 125 v, err := semver.NewVersion(c.Metadata.Version) 126 if err != nil { 127 return "invalid version" 128 } 129 130 if constraint.Check(v) { 131 return "unpacked" 132 } 133 return "wrong version" 134 } 135 136 return "unpacked" 137 } 138 139 // printDependencies prints all of the dependencies in the yaml file. 140 func (d *Dependency) printDependencies(chartpath string, out io.Writer, reqs []*chart.Dependency) { 141 table := uitable.New() 142 table.MaxColWidth = 80 143 table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS") 144 for _, row := range reqs { 145 table.AddRow(row.Name, row.Version, row.Repository, d.dependencyStatus(chartpath, row)) 146 } 147 fmt.Fprintln(out, table) 148 } 149 150 // printMissing prints warnings about charts that are present on disk, but are 151 // not in Charts.yaml. 152 func (d *Dependency) printMissing(chartpath string, out io.Writer, reqs []*chart.Dependency) { 153 folder := filepath.Join(chartpath, "charts/*") 154 files, err := filepath.Glob(folder) 155 if err != nil { 156 fmt.Fprintln(out, err) 157 return 158 } 159 160 for _, f := range files { 161 fi, err := os.Stat(f) 162 if err != nil { 163 fmt.Fprintf(out, "Warning: %s\n", err) 164 } 165 // Skip anything that is not a directory and not a tgz file. 166 if !fi.IsDir() && filepath.Ext(f) != ".tgz" { 167 continue 168 } 169 c, err := loader.Load(f) 170 if err != nil { 171 fmt.Fprintf(out, "WARNING: %q is not a chart.\n", f) 172 continue 173 } 174 found := false 175 for _, d := range reqs { 176 if d.Name == c.Name() { 177 found = true 178 break 179 } 180 } 181 if !found { 182 fmt.Fprintf(out, "WARNING: %q is not in Chart.yaml.\n", f) 183 } 184 } 185 }