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 }