github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/repo_update.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  	"sync"
    23  
    24  	"github.com/pkg/errors"
    25  	"github.com/spf13/cobra"
    26  
    27  	"helm.sh/helm/v3/cmd/helm/require"
    28  	"helm.sh/helm/v3/pkg/getter"
    29  	"helm.sh/helm/v3/pkg/repo"
    30  )
    31  
    32  const updateDesc = `
    33  Update gets the latest information about charts from the respective chart repositories.
    34  Information is cached locally, where it is used by commands like 'helm search'.
    35  
    36  You can optionally specify a list of repositories you want to update.
    37  	$ helm repo update <repo_name> ...
    38  To update all the repositories, use 'helm repo update'.
    39  `
    40  
    41  var errNoRepositories = errors.New("no repositories found. You must add one before updating")
    42  
    43  type repoUpdateOptions struct {
    44  	update               func([]*repo.ChartRepository, io.Writer, bool) error
    45  	repoFile             string
    46  	repoCache            string
    47  	names                []string
    48  	failOnRepoUpdateFail bool
    49  }
    50  
    51  func newRepoUpdateCmd(out io.Writer) *cobra.Command {
    52  	o := &repoUpdateOptions{update: updateCharts}
    53  
    54  	cmd := &cobra.Command{
    55  		Use:     "update [REPO1 [REPO2 ...]]",
    56  		Aliases: []string{"up"},
    57  		Short:   "update information of available charts locally from chart repositories",
    58  		Long:    updateDesc,
    59  		Args:    require.MinimumNArgs(0),
    60  		ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    61  			return compListRepos(toComplete, args), cobra.ShellCompDirectiveNoFileComp
    62  		},
    63  		RunE: func(cmd *cobra.Command, args []string) error {
    64  			o.repoFile = settings.RepositoryConfig
    65  			o.repoCache = settings.RepositoryCache
    66  			o.names = args
    67  			return o.run(out)
    68  		},
    69  	}
    70  
    71  	f := cmd.Flags()
    72  
    73  	// Adding this flag for Helm 3 as stop gap functionality for https://github.com/helm/helm/issues/10016.
    74  	// This should be deprecated in Helm 4 by update to the behaviour of `helm repo update` command.
    75  	f.BoolVar(&o.failOnRepoUpdateFail, "fail-on-repo-update-fail", false, "update fails if any of the repository updates fail")
    76  
    77  	return cmd
    78  }
    79  
    80  func (o *repoUpdateOptions) run(out io.Writer) error {
    81  	f, err := repo.LoadFile(o.repoFile)
    82  	switch {
    83  	case isNotExist(err):
    84  		return errNoRepositories
    85  	case err != nil:
    86  		return errors.Wrapf(err, "failed loading file: %s", o.repoFile)
    87  	case len(f.Repositories) == 0:
    88  		return errNoRepositories
    89  	}
    90  
    91  	var repos []*repo.ChartRepository
    92  	updateAllRepos := len(o.names) == 0
    93  
    94  	if !updateAllRepos {
    95  		// Fail early if the user specified an invalid repo to update
    96  		if err := checkRequestedRepos(o.names, f.Repositories); err != nil {
    97  			return err
    98  		}
    99  	}
   100  
   101  	for _, cfg := range f.Repositories {
   102  		if updateAllRepos || isRepoRequested(cfg.Name, o.names) {
   103  			r, err := repo.NewChartRepository(cfg, getter.All(settings))
   104  			if err != nil {
   105  				return err
   106  			}
   107  			if o.repoCache != "" {
   108  				r.CachePath = o.repoCache
   109  			}
   110  			repos = append(repos, r)
   111  		}
   112  	}
   113  
   114  	return o.update(repos, out, o.failOnRepoUpdateFail)
   115  }
   116  
   117  func updateCharts(repos []*repo.ChartRepository, out io.Writer, failOnRepoUpdateFail bool) error {
   118  	fmt.Fprintln(out, "Hang tight while we grab the latest from your chart repositories...")
   119  	var wg sync.WaitGroup
   120  	var repoFailList []string
   121  	for _, re := range repos {
   122  		wg.Add(1)
   123  		go func(re *repo.ChartRepository) {
   124  			defer wg.Done()
   125  			if _, err := re.DownloadIndexFile(); err != nil {
   126  				fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", re.Config.Name, re.Config.URL, err)
   127  				repoFailList = append(repoFailList, re.Config.URL)
   128  			} else {
   129  				fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", re.Config.Name)
   130  			}
   131  		}(re)
   132  	}
   133  	wg.Wait()
   134  
   135  	if len(repoFailList) > 0 && failOnRepoUpdateFail {
   136  		return fmt.Errorf("Failed to update the following repositories: %s",
   137  			repoFailList)
   138  	}
   139  
   140  	fmt.Fprintln(out, "Update Complete. ⎈Happy Helming!⎈")
   141  	return nil
   142  }
   143  
   144  func checkRequestedRepos(requestedRepos []string, validRepos []*repo.Entry) error {
   145  	for _, requestedRepo := range requestedRepos {
   146  		found := false
   147  		for _, repo := range validRepos {
   148  			if requestedRepo == repo.Name {
   149  				found = true
   150  				break
   151  			}
   152  		}
   153  		if !found {
   154  			return errors.Errorf("no repositories found matching '%s'.  Nothing will be updated", requestedRepo)
   155  		}
   156  	}
   157  	return nil
   158  }
   159  
   160  func isRepoRequested(repoName string, requestedRepos []string) bool {
   161  	for _, requestedRepo := range requestedRepos {
   162  		if repoName == requestedRepo {
   163  			return true
   164  		}
   165  	}
   166  	return false
   167  }