github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/search_hub.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 cmd
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  
    23  	"github.com/gosuri/uitable"
    24  	"github.com/spf13/cobra"
    25  
    26  	"helm.sh/helm/v3/pkg/cli/output"
    27  )
    28  
    29  const searchHubDesc = `
    30  Search for Helm charts in the Artifact Hub or your own hub instance.
    31  
    32  Artifact Hub is a web-based application that enables finding, installing, and
    33  publishing packages and configurations for CNCF projects, including publicly
    34  available distributed charts Helm charts. It is a Cloud Native Computing
    35  Foundation sandbox project. You can browse the hub at https://artifacthub.io/
    36  
    37  The [KEYWORD] argument accepts either a keyword string, or quoted string of rich
    38  query options. For rich query options documentation, see
    39  https://artifacthub.github.io/hub/api/?urls.primaryName=Monocular%20compatible%20search%20API#/Monocular/get_api_chartsvc_v1_charts_search
    40  
    41  Previous versions of Helm used an instance of Monocular as the default
    42  'endpoint', so for backwards compatibility Artifact Hub is compatible with the
    43  Monocular search API. Similarly, when setting the 'endpoint' flag, the specified
    44  endpoint must also be implement a Monocular compatible search API endpoint.
    45  Note that when specifying a Monocular instance as the 'endpoint', rich queries
    46  are not supported. For API details, see https://github.com/helm/monocular
    47  `
    48  
    49  type searchHubOptions struct {
    50  	searchEndpoint string
    51  	maxColWidth    uint
    52  	outputFormat   output.Format
    53  	listRepoURL    bool
    54  }
    55  
    56  func newSearchHubCmd(out io.Writer) *cobra.Command {
    57  	o := &searchHubOptions{}
    58  
    59  	cmd := &cobra.Command{
    60  		Use:   "hub [KEYWORD]",
    61  		Short: "search for charts in the Artifact Hub or your own hub instance",
    62  		Long:  searchHubDesc,
    63  		// RunE: func(cmd *cobra.Command, args []string) error {
    64  		// 	// return o.run(out, args)
    65  		// },
    66  	}
    67  
    68  	f := cmd.Flags()
    69  	f.StringVar(&o.searchEndpoint, "endpoint", "https://hub.helm.sh", "Hub instance to query for charts")
    70  	f.UintVar(&o.maxColWidth, "max-col-width", 50, "maximum column width for output table")
    71  	f.BoolVar(&o.listRepoURL, "list-repo-url", false, "print charts repository URL")
    72  
    73  	bindOutputFlag(cmd, &o.outputFormat)
    74  
    75  	return cmd
    76  }
    77  
    78  // func (o *searchHubOptions) run(out io.Writer, args []string) error {
    79  // c, err := monocular.New(o.searchEndpoint)
    80  // if err != nil {
    81  // 	return errors.Wrap(err, fmt.Sprintf("unable to create connection to %q", o.searchEndpoint))
    82  // }
    83  
    84  // q := strings.Join(args, " ")
    85  // results, err := c.Search(q)
    86  // if err != nil {
    87  // 	debug("%s", err)
    88  // 	return fmt.Errorf("unable to perform search against %q", o.searchEndpoint)
    89  // }
    90  
    91  // return o.outputFormat.Write(out, newHubSearchWriter(results, o.searchEndpoint, o.maxColWidth, o.listRepoURL))
    92  // }
    93  
    94  type hubChartRepo struct {
    95  	URL  string `json:"url"`
    96  	Name string `json:"name"`
    97  }
    98  
    99  type hubChartElement struct {
   100  	URL         string       `json:"url"`
   101  	Version     string       `json:"version"`
   102  	AppVersion  string       `json:"app_version"`
   103  	Description string       `json:"description"`
   104  	Repository  hubChartRepo `json:"repository"`
   105  }
   106  
   107  type hubSearchWriter struct {
   108  	elements    []hubChartElement
   109  	columnWidth uint
   110  	listRepoURL bool
   111  }
   112  
   113  // func newHubSearchWriter(results []monocular.SearchResult, endpoint string, columnWidth uint, listRepoURL bool) *hubSearchWriter {
   114  // 	var elements []hubChartElement
   115  // 	for _, r := range results {
   116  // 		// Backwards compatibility for Monocular
   117  // 		url := endpoint + "/charts/" + r.ID
   118  
   119  // 		// Check for artifactHub compatibility
   120  // 		if r.ArtifactHub.PackageURL != "" {
   121  // 			url = r.ArtifactHub.PackageURL
   122  // 		}
   123  
   124  // 		elements = append(elements, hubChartElement{url, r.Relationships.LatestChartVersion.Data.Version, r.Relationships.LatestChartVersion.Data.AppVersion, r.Attributes.Description, hubChartRepo{URL: r.Attributes.Repo.URL, Name: r.Attributes.Repo.Name}})
   125  // 	}
   126  // 	return &hubSearchWriter{elements, columnWidth, listRepoURL}
   127  // }
   128  
   129  func (h *hubSearchWriter) WriteTable(out io.Writer) error {
   130  	if len(h.elements) == 0 {
   131  		_, err := out.Write([]byte("No results found\n"))
   132  		if err != nil {
   133  			return fmt.Errorf("unable to write results: %s", err)
   134  		}
   135  		return nil
   136  	}
   137  	table := uitable.New()
   138  	table.MaxColWidth = h.columnWidth
   139  
   140  	if h.listRepoURL {
   141  		table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION", "REPO URL")
   142  	} else {
   143  		table.AddRow("URL", "CHART VERSION", "APP VERSION", "DESCRIPTION")
   144  	}
   145  
   146  	for _, r := range h.elements {
   147  		if h.listRepoURL {
   148  			table.AddRow(r.URL, r.Version, r.AppVersion, r.Description, r.Repository.URL)
   149  		} else {
   150  			table.AddRow(r.URL, r.Version, r.AppVersion, r.Description)
   151  		}
   152  	}
   153  	return output.EncodeTable(out, table)
   154  }
   155  
   156  func (h *hubSearchWriter) WriteJSON(out io.Writer) error {
   157  	return h.encodeByFormat(out, output.JSON)
   158  }
   159  
   160  func (h *hubSearchWriter) WriteYAML(out io.Writer) error {
   161  	return h.encodeByFormat(out, output.YAML)
   162  }
   163  
   164  func (h *hubSearchWriter) encodeByFormat(out io.Writer, format output.Format) error {
   165  	// Initialize the array so no results returns an empty array instead of null
   166  	chartList := make([]hubChartElement, 0, len(h.elements))
   167  
   168  	for _, r := range h.elements {
   169  		chartList = append(chartList, hubChartElement{r.URL, r.Version, r.AppVersion, r.Description, r.Repository})
   170  	}
   171  
   172  	switch format {
   173  	case output.JSON:
   174  		return output.EncodeJSON(out, chartList)
   175  	case output.YAML:
   176  		return output.EncodeYAML(out, chartList)
   177  	}
   178  
   179  	// Because this is a non-exported function and only called internally by
   180  	// WriteJSON and WriteYAML, we shouldn't get invalid types
   181  	return nil
   182  }