From 417210dd1d62fd82e02ef67d25075cf1bfff1768 Mon Sep 17 00:00:00 2001 From: Pablo Caraballo Llorente Date: Fri, 19 Nov 2021 17:58:49 +0100 Subject: [PATCH] feat(*): add --output flag to 'helm dependency list' Signed-off-by: Pablo Caraballo Llorente --- cmd/helm/dependency.go | 24 --------- cmd/helm/dependency_list.go | 104 ++++++++++++++++++++++++++++++++++++ pkg/action/dependency.go | 43 ++++++++------- 3 files changed, 125 insertions(+), 46 deletions(-) create mode 100644 cmd/helm/dependency_list.go diff --git a/cmd/helm/dependency.go b/cmd/helm/dependency.go index 03874742c..4001a3737 100644 --- a/cmd/helm/dependency.go +++ b/cmd/helm/dependency.go @@ -17,7 +17,6 @@ package main import ( "io" - "path/filepath" "github.com/spf13/cobra" @@ -97,26 +96,3 @@ func newDependencyCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { return cmd } - -func newDependencyListCmd(out io.Writer) *cobra.Command { - client := action.NewDependency() - cmd := &cobra.Command{ - Use: "list CHART", - Aliases: []string{"ls"}, - Short: "list the dependencies for the given chart", - Long: dependencyListDesc, - Args: require.MaximumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - chartpath := "." - if len(args) > 0 { - chartpath = filepath.Clean(args[0]) - } - return client.List(chartpath, out) - }, - } - - f := cmd.Flags() - - f.UintVar(&client.ColumnWidth, "max-col-width", 80, "maximum column width for output table") - return cmd -} diff --git a/cmd/helm/dependency_list.go b/cmd/helm/dependency_list.go new file mode 100644 index 000000000..0bbc3298e --- /dev/null +++ b/cmd/helm/dependency_list.go @@ -0,0 +1,104 @@ +/* +Copyright The Helm Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package main + +import ( + "io" + "path/filepath" + + "github.com/gosuri/uitable" + "github.com/spf13/cobra" + + "helm.sh/helm/v3/cmd/helm/require" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/cli/output" +) + +func newDependencyListCmd(out io.Writer) *cobra.Command { + var outfmt output.Format + client := action.NewDependency() + cmd := &cobra.Command{ + Use: "list CHART", + Aliases: []string{"ls"}, + Short: "list the dependencies for the given chart", + Long: dependencyListDesc, + Args: require.MaximumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + chartpath := "." + if len(args) > 0 { + chartpath = filepath.Clean(args[0]) + } + + dependencies, err := action.ListDependencies(chartpath, out) + + if err != nil { + return err + } + + if dependencies != nil { + if outfmt == output.Table { + action.PrintMissing(chartpath, out, dependencies) + } + + var deplist = make([]dependencyElement, 0, len(dependencies)) + + for _, d := range dependencies { + deplist = append(deplist, dependencyElement{Name: d.Name, Version: d.Version, Repository: d.Repository, Status: d.Status}) + } + + return outfmt.Write(out, &dependencyListWriter{deps: deplist, columnWidth: client.ColumnWidth}) + } + + return nil + }, + } + + f := cmd.Flags() + + f.UintVar(&client.ColumnWidth, "max-col-width", 80, "maximum column width for output table") + bindOutputFlag(cmd, &outfmt) + + return cmd +} + +type dependencyElement struct { + Name string `json:"name"` + Version string `json:"version"` + Repository string `json:"repository"` + Status string `json:"status"` +} + +type dependencyListWriter struct { + deps []dependencyElement + columnWidth uint +} + +func (d *dependencyListWriter) WriteTable(out io.Writer) error { + table := uitable.New() + table.MaxColWidth = d.columnWidth + table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS") + for _, row := range d.deps { + table.AddRow(row.Name, row.Version, row.Repository, row.Status) + } + return output.EncodeTable(out, table) +} + +func (d *dependencyListWriter) WriteJSON(out io.Writer) error { + return output.EncodeJSON(out, d.deps) +} + +func (d *dependencyListWriter) WriteYAML(out io.Writer) error { + return output.EncodeYAML(out, d.deps) +} diff --git a/pkg/action/dependency.go b/pkg/action/dependency.go index 3265f1f17..ff4aaf68f 100644 --- a/pkg/action/dependency.go +++ b/pkg/action/dependency.go @@ -24,7 +24,6 @@ import ( "strings" "github.com/Masterminds/semver/v3" - "github.com/gosuri/uitable" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" @@ -40,6 +39,14 @@ type Dependency struct { ColumnWidth uint } +// DependencyEntry is the representation of a chart dependency, returned back to the user after running `helm dep list` +type DependencyEntry struct { + Name string + Version string + Repository string + Status string +} + // NewDependency creates a new Dependency object with the given configuration. func NewDependency() *Dependency { return &Dependency{ @@ -48,25 +55,28 @@ func NewDependency() *Dependency { } // List executes 'helm dependency list'. -func (d *Dependency) List(chartpath string, out io.Writer) error { +func ListDependencies(chartpath string, out io.Writer) ([]DependencyEntry, error) { c, err := loader.Load(chartpath) if err != nil { - return err + return nil, err } if c.Metadata.Dependencies == nil { fmt.Fprintf(out, "WARNING: no dependencies at %s\n", filepath.Join(chartpath, "charts")) - return nil + return nil, nil + } + + var deplist = make([]DependencyEntry, 0, len(c.Metadata.Dependencies)) + + for _, d := range c.Metadata.Dependencies { + deplist = append(deplist, DependencyEntry{Name: d.Name, Version: d.Version, Repository: d.Repository, Status: DependencyStatus(chartpath, d, c)}) } - d.printDependencies(chartpath, out, c) - fmt.Fprintln(out) - d.printMissing(chartpath, out, c.Metadata.Dependencies) - return nil + return deplist, nil } -// dependencyStatus returns a string describing the status of a dependency viz a viz the parent chart. -func (d *Dependency) dependencyStatus(chartpath string, dep *chart.Dependency, parent *chart.Chart) string { +// DependencyStatus returns a string describing the status of a dependency viz a viz the parent chart. +func DependencyStatus(chartpath string, dep *chart.Dependency, parent *chart.Chart) string { filename := fmt.Sprintf("%s-%s.tgz", dep.Name, "*") // If a chart is unpacked, this will check the unpacked chart's `charts/` directory for tarballs. @@ -181,20 +191,9 @@ func statArchiveForStatus(archive string, dep *chart.Dependency) string { return "" } -// printDependencies prints all of the dependencies in the yaml file. -func (d *Dependency) printDependencies(chartpath string, out io.Writer, c *chart.Chart) { - table := uitable.New() - table.MaxColWidth = d.ColumnWidth - table.AddRow("NAME", "VERSION", "REPOSITORY", "STATUS") - for _, row := range c.Metadata.Dependencies { - table.AddRow(row.Name, row.Version, row.Repository, d.dependencyStatus(chartpath, row, c)) - } - fmt.Fprintln(out, table) -} - // printMissing prints warnings about charts that are present on disk, but are // not in Chart.yaml. -func (d *Dependency) printMissing(chartpath string, out io.Writer, reqs []*chart.Dependency) { +func PrintMissing(chartpath string, out io.Writer, reqs []DependencyEntry) { folder := filepath.Join(chartpath, "charts/*") files, err := filepath.Glob(folder) if err != nil {