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