github.com/strongmonkey/helm@v2.7.2+incompatible/cmd/helm/search.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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 main
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"strings"
    23  
    24  	"github.com/Masterminds/semver"
    25  	"github.com/gosuri/uitable"
    26  	"github.com/spf13/cobra"
    27  
    28  	"k8s.io/helm/cmd/helm/search"
    29  	"k8s.io/helm/pkg/helm/helmpath"
    30  	"k8s.io/helm/pkg/repo"
    31  )
    32  
    33  const searchDesc = `
    34  Search reads through all of the repositories configured on the system, and
    35  looks for matches.
    36  
    37  Repositories are managed with 'helm repo' commands.
    38  `
    39  
    40  // searchMaxScore suggests that any score higher than this is not considered a match.
    41  const searchMaxScore = 25
    42  
    43  type searchCmd struct {
    44  	out      io.Writer
    45  	helmhome helmpath.Home
    46  
    47  	versions bool
    48  	regexp   bool
    49  	version  string
    50  }
    51  
    52  func newSearchCmd(out io.Writer) *cobra.Command {
    53  	sc := &searchCmd{out: out}
    54  
    55  	cmd := &cobra.Command{
    56  		Use:   "search [keyword]",
    57  		Short: "search for a keyword in charts",
    58  		Long:  searchDesc,
    59  		RunE: func(cmd *cobra.Command, args []string) error {
    60  			sc.helmhome = settings.Home
    61  			return sc.run(args)
    62  		},
    63  	}
    64  
    65  	f := cmd.Flags()
    66  	f.BoolVarP(&sc.regexp, "regexp", "r", false, "use regular expressions for searching")
    67  	f.BoolVarP(&sc.versions, "versions", "l", false, "show the long listing, with each version of each chart on its own line")
    68  	f.StringVarP(&sc.version, "version", "v", "", "search using semantic versioning constraints")
    69  
    70  	return cmd
    71  }
    72  
    73  func (s *searchCmd) run(args []string) error {
    74  	index, err := s.buildIndex()
    75  	if err != nil {
    76  		return err
    77  	}
    78  
    79  	var res []*search.Result
    80  	if len(args) == 0 {
    81  		res = index.All()
    82  	} else {
    83  		q := strings.Join(args, " ")
    84  		res, err = index.Search(q, searchMaxScore, s.regexp)
    85  		if err != nil {
    86  			return nil
    87  		}
    88  	}
    89  
    90  	search.SortScore(res)
    91  	data, err := s.applyConstraint(res)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	fmt.Fprintln(s.out, s.formatSearchResults(data))
    97  
    98  	return nil
    99  }
   100  
   101  func (s *searchCmd) applyConstraint(res []*search.Result) ([]*search.Result, error) {
   102  	if len(s.version) == 0 {
   103  		return res, nil
   104  	}
   105  
   106  	constraint, err := semver.NewConstraint(s.version)
   107  	if err != nil {
   108  		return res, fmt.Errorf("an invalid version/constraint format: %s", err)
   109  	}
   110  
   111  	data := res[:0]
   112  	for _, r := range res {
   113  		v, err := semver.NewVersion(r.Chart.Version)
   114  		if err != nil || constraint.Check(v) {
   115  			data = append(data, r)
   116  		}
   117  	}
   118  
   119  	return data, nil
   120  }
   121  
   122  func (s *searchCmd) formatSearchResults(res []*search.Result) string {
   123  	if len(res) == 0 {
   124  		return "No results found"
   125  	}
   126  	table := uitable.New()
   127  	table.MaxColWidth = 50
   128  	table.AddRow("NAME", "VERSION", "DESCRIPTION")
   129  	for _, r := range res {
   130  		table.AddRow(r.Name, r.Chart.Version, r.Chart.Description)
   131  	}
   132  	return table.String()
   133  }
   134  
   135  func (s *searchCmd) buildIndex() (*search.Index, error) {
   136  	// Load the repositories.yaml
   137  	rf, err := repo.LoadRepositoriesFile(s.helmhome.RepositoryFile())
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	i := search.NewIndex()
   143  	for _, re := range rf.Repositories {
   144  		n := re.Name
   145  		f := s.helmhome.CacheIndex(n)
   146  		ind, err := repo.LoadIndexFile(f)
   147  		if err != nil {
   148  			fmt.Fprintf(s.out, "WARNING: Repo %q is corrupt or missing. Try 'helm repo update'.", n)
   149  			continue
   150  		}
   151  
   152  		i.AddRepo(n, ind, s.versions)
   153  	}
   154  	return i, nil
   155  }