| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2018-08-25 03:03:55 +08:00
										 |  |  | Copyright The Helm Authors. | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | You may obtain a copy of the License at | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | See the License for the specific language governing permissions and | 
					
						
							|  |  |  | limitations under the License. | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package downloader | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 	"crypto" | 
					
						
							|  |  |  | 	"encoding/hex" | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2020-02-05 16:38:30 +08:00
										 |  |  | 	"log" | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2016-10-07 06:07:22 +08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-04 01:42:59 +08:00
										 |  |  | 	"github.com/Masterminds/semver/v3" | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 	"github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2019-07-12 22:52:15 +08:00
										 |  |  | 	"sigs.k8s.io/yaml" | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 	"helm.sh/helm/v3/internal/experimental/registry" | 
					
						
							| 
									
										
										
										
											2019-10-04 02:27:05 +08:00
										 |  |  | 	"helm.sh/helm/v3/internal/resolver" | 
					
						
							| 
									
										
										
										
											2019-10-23 11:57:35 +08:00
										 |  |  | 	"helm.sh/helm/v3/internal/third_party/dep/fs" | 
					
						
							| 
									
										
										
										
											2019-10-04 02:27:05 +08:00
										 |  |  | 	"helm.sh/helm/v3/internal/urlutil" | 
					
						
							|  |  |  | 	"helm.sh/helm/v3/pkg/chart" | 
					
						
							|  |  |  | 	"helm.sh/helm/v3/pkg/chart/loader" | 
					
						
							|  |  |  | 	"helm.sh/helm/v3/pkg/chartutil" | 
					
						
							|  |  |  | 	"helm.sh/helm/v3/pkg/getter" | 
					
						
							|  |  |  | 	"helm.sh/helm/v3/pkg/helmpath" | 
					
						
							|  |  |  | 	"helm.sh/helm/v3/pkg/repo" | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-22 23:03:25 +08:00
										 |  |  | // ErrRepoNotFound indicates that chart repositories can't be found in local repo cache.
 | 
					
						
							|  |  |  | // The value of Repos is missing repos.
 | 
					
						
							|  |  |  | type ErrRepoNotFound struct { | 
					
						
							|  |  |  | 	Repos []string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Error implements the error interface.
 | 
					
						
							|  |  |  | func (e ErrRepoNotFound) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("no repository definition for %s", strings.Join(e.Repos, ", ")) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | // Manager handles the lifecycle of fetching, resolving, and storing dependencies.
 | 
					
						
							|  |  |  | type Manager struct { | 
					
						
							|  |  |  | 	// Out is used to print warnings and notifications.
 | 
					
						
							|  |  |  | 	Out io.Writer | 
					
						
							|  |  |  | 	// ChartPath is the path to the unpacked base chart upon which this operates.
 | 
					
						
							|  |  |  | 	ChartPath string | 
					
						
							|  |  |  | 	// Verification indicates whether the chart should be verified.
 | 
					
						
							|  |  |  | 	Verify VerificationStrategy | 
					
						
							| 
									
										
										
										
											2017-02-25 07:19:37 +08:00
										 |  |  | 	// Debug is the global "--debug" flag
 | 
					
						
							|  |  |  | 	Debug bool | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	// Keyring is the key ring file.
 | 
					
						
							|  |  |  | 	Keyring string | 
					
						
							| 
									
										
										
										
											2017-02-24 08:22:03 +08:00
										 |  |  | 	// SkipUpdate indicates that the repository should not be updated first.
 | 
					
						
							|  |  |  | 	SkipUpdate bool | 
					
						
							| 
									
										
										
										
											2017-04-16 01:30:39 +08:00
										 |  |  | 	// Getter collection for the operation
 | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 	Getters          []getter.Provider | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 	RegistryClient   *registry.Client | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 	RepositoryConfig string | 
					
						
							|  |  |  | 	RepositoryCache  string | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Build rebuilds a local charts directory from a lockfile.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If the lockfile is not present, this will run a Manager.Update()
 | 
					
						
							| 
									
										
										
										
											2017-02-24 08:22:03 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // If SkipUpdate is set, this will not update the repository.
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | func (m *Manager) Build() error { | 
					
						
							|  |  |  | 	c, err := m.loadChartDir() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If a lock file is found, run a build from that. Otherwise, just do
 | 
					
						
							|  |  |  | 	// an update.
 | 
					
						
							| 
									
										
										
										
											2018-08-30 05:43:37 +08:00
										 |  |  | 	lock := c.Lock | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 	if lock == nil { | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		return m.Update() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-13 01:35:48 +08:00
										 |  |  | 	// Check that all of the repos we're dependent on actually exist.
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:20:33 +08:00
										 |  |  | 	req := c.Metadata.Dependencies | 
					
						
							| 
									
										
										
										
											2020-02-21 15:10:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If using apiVersion v1, calculate the hash before resolve repo names
 | 
					
						
							|  |  |  | 	// because resolveRepoNames will change req if req uses repo alias
 | 
					
						
							|  |  |  | 	// and Helm 2 calculate the digest from the original req
 | 
					
						
							|  |  |  | 	// Fix for: https://github.com/helm/helm/issues/7619
 | 
					
						
							|  |  |  | 	var v2Sum string | 
					
						
							|  |  |  | 	if c.Metadata.APIVersion == chart.APIVersionV1 { | 
					
						
							|  |  |  | 		v2Sum, err = resolver.HashV2Req(req) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return errors.New("the lock file (requirements.lock) is out of sync with the dependencies file (requirements.yaml). Please update the dependencies") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | 	if _, err := m.resolveRepoNames(req); err != nil { | 
					
						
							| 
									
										
										
										
											2019-11-13 01:35:48 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-22 11:38:49 +08:00
										 |  |  | 	if sum, err := resolver.HashReq(req, lock.Dependencies); err != nil || sum != lock.Digest { | 
					
						
							| 
									
										
										
										
											2020-02-05 16:38:30 +08:00
										 |  |  | 		// If lock digest differs and chart is apiVersion v1, it maybe because the lock was built
 | 
					
						
							|  |  |  | 		// with Helm 2 and therefore should be checked with Helm v2 hash
 | 
					
						
							|  |  |  | 		// Fix for: https://github.com/helm/helm/issues/7233
 | 
					
						
							|  |  |  | 		if c.Metadata.APIVersion == chart.APIVersionV1 { | 
					
						
							|  |  |  | 			log.Println("warning: a valid Helm v3 hash was not found. Checking against Helm v2 hash...") | 
					
						
							| 
									
										
										
										
											2020-02-21 15:10:11 +08:00
										 |  |  | 			if v2Sum != lock.Digest { | 
					
						
							| 
									
										
										
										
											2020-02-05 16:38:30 +08:00
										 |  |  | 				return errors.New("the lock file (requirements.lock) is out of sync with the dependencies file (requirements.yaml). Please update the dependencies") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return errors.New("the lock file (Chart.lock) is out of sync with the dependencies file (Chart.yaml). Please update the dependencies") | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | 	// Check that all of the repos we're dependent on actually exist.
 | 
					
						
							|  |  |  | 	if err := m.hasAllRepos(lock.Dependencies); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 08:22:03 +08:00
										 |  |  | 	if !m.SkipUpdate { | 
					
						
							|  |  |  | 		// For each repo in the file, update the cached copy of that repo
 | 
					
						
							|  |  |  | 		if err := m.UpdateRepositories(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now we need to fetch every package here into charts/
 | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 	return m.downloadAll(lock.Dependencies) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update updates a local charts directory.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2018-08-30 05:05:37 +08:00
										 |  |  | // It first reads the Chart.yaml file, and then attempts to
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | // negotiate versions based on that. It will download the versions
 | 
					
						
							| 
									
										
										
										
											2017-02-24 08:22:03 +08:00
										 |  |  | // from remote chart repositories unless SkipUpdate is true.
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | func (m *Manager) Update() error { | 
					
						
							|  |  |  | 	c, err := m.loadChartDir() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:20:33 +08:00
										 |  |  | 	// If no dependencies are found, we consider this a successful
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	// completion.
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:20:33 +08:00
										 |  |  | 	req := c.Metadata.Dependencies | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 	if req == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-24 04:14:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 	// Get the names of the repositories the dependencies need that Helm is
 | 
					
						
							|  |  |  | 	// configured to know about.
 | 
					
						
							| 
									
										
										
										
											2019-11-13 01:35:48 +08:00
										 |  |  | 	repoNames, err := m.resolveRepoNames(req) | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 	// For the repositories Helm is not configured to know about, ensure Helm
 | 
					
						
							|  |  |  | 	// has some information about them and, when possible, the index files
 | 
					
						
							|  |  |  | 	// locally.
 | 
					
						
							| 
									
										
										
										
											2020-07-18 03:44:50 +08:00
										 |  |  | 	// TODO(mattfarina): Repositories should be explicitly added by end users
 | 
					
						
							|  |  |  | 	// rather than automattic. In Helm v4 require users to add repositories. They
 | 
					
						
							|  |  |  | 	// should have to add them in order to make sure they are aware of the
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | 	// respoitories and opt-in to any locations, for security.
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 	repoNames, err = m.ensureMissingRepos(repoNames, req) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// For each of the repositories Helm is configured to know about, update
 | 
					
						
							|  |  |  | 	// the index information locally.
 | 
					
						
							| 
									
										
										
										
											2017-02-24 08:22:03 +08:00
										 |  |  | 	if !m.SkipUpdate { | 
					
						
							|  |  |  | 		if err := m.UpdateRepositories(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now we need to find out which version of a chart best satisfies the
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:20:33 +08:00
										 |  |  | 	// dependencies in the Chart.yaml
 | 
					
						
							| 
									
										
										
										
											2019-06-12 07:09:21 +08:00
										 |  |  | 	lock, err := m.resolve(req, repoNames) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now we need to fetch every package here into charts/
 | 
					
						
							|  |  |  | 	if err := m.downloadAll(lock.Dependencies); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-04 22:25:50 +08:00
										 |  |  | 	// downloadAll might overwrite dependency version, recalculate lock digest
 | 
					
						
							|  |  |  | 	newDigest, err := resolver.HashReq(req, lock.Dependencies) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	lock.Digest = newDigest | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-25 08:24:35 +08:00
										 |  |  | 	// If the lock file hasn't changed, don't write a new one.
 | 
					
						
							| 
									
										
										
										
											2018-08-30 05:43:37 +08:00
										 |  |  | 	oldLock := c.Lock | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 	if oldLock != nil && oldLock.Digest == lock.Digest { | 
					
						
							| 
									
										
										
										
											2016-10-25 08:24:35 +08:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	// Finally, we need to write the lockfile.
 | 
					
						
							| 
									
										
										
										
											2019-12-12 01:07:05 +08:00
										 |  |  | 	return writeLock(m.ChartPath, lock, c.Metadata.APIVersion == chart.APIVersionV1) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *Manager) loadChartDir() (*chart.Chart, error) { | 
					
						
							|  |  |  | 	if fi, err := os.Stat(m.ChartPath); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 		return nil, errors.Wrapf(err, "could not find %s", m.ChartPath) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} else if !fi.IsDir() { | 
					
						
							|  |  |  | 		return nil, errors.New("only unpacked charts can be updated") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 	return loader.LoadDir(m.ChartPath) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:20:33 +08:00
										 |  |  | // resolve takes a list of dependencies and translates them into an exact version to download.
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:20:33 +08:00
										 |  |  | // This returns a lock file, which has all of the dependencies normalized to a specific version.
 | 
					
						
							| 
									
										
										
										
											2019-06-12 07:09:21 +08:00
										 |  |  | func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) { | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 	res := resolver.New(m.ChartPath, m.RepositoryCache) | 
					
						
							| 
									
										
										
										
											2019-06-12 07:09:21 +08:00
										 |  |  | 	return res.Resolve(req, repoNames) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // downloadAll takes a list of dependencies and downloads them into charts/
 | 
					
						
							| 
									
										
										
										
											2017-02-04 06:52:16 +08:00
										 |  |  | //
 | 
					
						
							|  |  |  | // It will delete versions of the chart that exist on disk and might cause
 | 
					
						
							|  |  |  | // a conflict.
 | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | func (m *Manager) downloadAll(deps []*chart.Dependency) error { | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	repos, err := m.loadChartRepositories() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-12 08:59:45 +08:00
										 |  |  | 	destPath := filepath.Join(m.ChartPath, "charts") | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 	tmpPath := filepath.Join(m.ChartPath, "tmpcharts") | 
					
						
							| 
									
										
										
										
											2016-10-12 08:59:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create 'charts' directory if it doesn't already exist.
 | 
					
						
							|  |  |  | 	if fi, err := os.Stat(destPath); err != nil { | 
					
						
							|  |  |  | 		if err := os.MkdirAll(destPath, 0755); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if !fi.IsDir() { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 		return errors.Errorf("%q is not a directory", destPath) | 
					
						
							| 
									
										
										
										
											2016-10-12 08:59:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 04:41:00 +08:00
										 |  |  | 	if err := fs.RenameWithFallback(destPath, tmpPath); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 		return errors.Wrap(err, "unable to move current charts to tmp dir") | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := os.MkdirAll(destPath, 0755); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2017-07-06 00:08:20 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-06 00:08:20 +08:00
										 |  |  | 	fmt.Fprintf(m.Out, "Saving %d charts\n", len(deps)) | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 	var saveError error | 
					
						
							| 
									
										
										
										
											2020-04-04 09:22:43 +08:00
										 |  |  | 	churls := make(map[string]struct{}) | 
					
						
							| 
									
										
										
										
											2017-07-06 00:08:20 +08:00
										 |  |  | 	for _, dep := range deps { | 
					
						
							| 
									
										
										
										
											2019-10-09 23:35:55 +08:00
										 |  |  | 		// No repository means the chart is in charts directory
 | 
					
						
							|  |  |  | 		if dep.Repository == "" { | 
					
						
							|  |  |  | 			fmt.Fprintf(m.Out, "Dependency %s did not declare a repository. Assuming it exists in the charts directory\n", dep.Name) | 
					
						
							|  |  |  | 			chartPath := filepath.Join(tmpPath, dep.Name) | 
					
						
							|  |  |  | 			ch, err := loader.LoadDir(chartPath) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return fmt.Errorf("Unable to load chart: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			constraint, err := semver.NewConstraint(dep.Version) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return fmt.Errorf("Dependency %s has an invalid version/constraint format: %s", dep.Name, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			v, err := semver.NewVersion(ch.Metadata.Version) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return fmt.Errorf("Invalid version %s for dependency %s: %s", dep.Version, dep.Name, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if !constraint.Check(v) { | 
					
						
							|  |  |  | 				saveError = fmt.Errorf("Dependency %s at version %s does not satisfy the constraint %s", dep.Name, ch.Metadata.Version, dep.Version) | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 		if strings.HasPrefix(dep.Repository, "file://") { | 
					
						
							| 
									
										
										
										
											2017-02-25 07:19:37 +08:00
										 |  |  | 			if m.Debug { | 
					
						
							|  |  |  | 				fmt.Fprintf(m.Out, "Archiving %s from repo %s\n", dep.Name, dep.Repository) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 			ver, err := tarFromLocalDir(m.ChartPath, dep.Name, dep.Repository, dep.Version) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 				saveError = err | 
					
						
							|  |  |  | 				break | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			dep.Version = ver | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-27 06:54:20 +08:00
										 |  |  | 		// Any failure to resolve/download a chart should fail:
 | 
					
						
							| 
									
										
										
										
											2018-11-29 02:08:38 +08:00
										 |  |  | 		// https://github.com/helm/helm/issues/1439
 | 
					
						
							| 
									
										
										
										
											2019-09-25 01:03:30 +08:00
										 |  |  | 		churl, username, password, err := m.findChartURL(dep.Name, dep.Version, dep.Repository, repos) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 			saveError = errors.Wrapf(err, "could not find %s", churl) | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 			break | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-04 09:22:43 +08:00
										 |  |  | 		if _, ok := churls[churl]; ok { | 
					
						
							|  |  |  | 			fmt.Fprintf(m.Out, "Already downloaded %s from repo %s\n", dep.Name, dep.Repository) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		fmt.Fprintf(m.Out, "Downloading %s from repo %s\n", dep.Name, dep.Repository) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 		dl := ChartDownloader{ | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 			Out:              m.Out, | 
					
						
							|  |  |  | 			Verify:           m.Verify, | 
					
						
							|  |  |  | 			Keyring:          m.Keyring, | 
					
						
							|  |  |  | 			RepositoryConfig: m.RepositoryConfig, | 
					
						
							|  |  |  | 			RepositoryCache:  m.RepositoryCache, | 
					
						
							|  |  |  | 			Getters:          m.Getters, | 
					
						
							| 
									
										
										
										
											2019-06-20 05:59:07 +08:00
										 |  |  | 			Options: []getter.Option{ | 
					
						
							|  |  |  | 				getter.WithBasicAuth(username, password), | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-19 06:29:15 +08:00
										 |  |  | 		version := "" | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 		if strings.HasPrefix(churl, "oci://") { | 
					
						
							|  |  |  | 			if !resolver.FeatureGateOCI.IsEnabled() { | 
					
						
							|  |  |  | 				return errors.Wrapf(resolver.FeatureGateOCI.Error(), | 
					
						
							|  |  |  | 					"the repository %s is an OCI registry", churl) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			churl, version, err = parseOCIRef(churl) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return errors.Wrapf(err, "could not parse OCI reference") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			dl.Options = append(dl.Options, | 
					
						
							|  |  |  | 				getter.WithRegistryClient(m.RegistryClient), | 
					
						
							|  |  |  | 				getter.WithTagName(version)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-19 06:29:15 +08:00
										 |  |  | 		_, _, err = dl.DownloadTo(churl, version, destPath) | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 			saveError = errors.Wrapf(err, "could not download %s", churl) | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-04-04 09:22:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		churls[churl] = struct{}{} | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if saveError == nil { | 
					
						
							|  |  |  | 		fmt.Fprintln(m.Out, "Deleting outdated charts") | 
					
						
							|  |  |  | 		for _, dep := range deps { | 
					
						
							| 
									
										
										
										
											2019-10-09 23:35:55 +08:00
										 |  |  | 			// Chart from local charts directory stays in place
 | 
					
						
							|  |  |  | 			if dep.Repository != "" { | 
					
						
							|  |  |  | 				if err := m.safeDeleteDep(dep.Name, tmpPath); err != nil { | 
					
						
							|  |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-24 15:32:44 +08:00
										 |  |  | 		if err := move(tmpPath, destPath); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 		if err := os.RemoveAll(tmpPath); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 			return errors.Wrapf(err, "failed to remove %v", tmpPath) | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		fmt.Fprintln(m.Out, "Save error occurred: ", saveError) | 
					
						
							|  |  |  | 		fmt.Fprintln(m.Out, "Deleting newly downloaded charts, restoring pre-update state") | 
					
						
							|  |  |  | 		for _, dep := range deps { | 
					
						
							|  |  |  | 			if err := m.safeDeleteDep(dep.Name, destPath); err != nil { | 
					
						
							|  |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := os.RemoveAll(destPath); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 			return errors.Wrapf(err, "failed to remove %v", destPath) | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-10-23 04:41:00 +08:00
										 |  |  | 		if err := fs.RenameWithFallback(tmpPath, destPath); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 			return errors.Wrap(err, "unable to move current charts to tmp dir") | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-10 23:11:10 +08:00
										 |  |  | 		return saveError | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | func parseOCIRef(chartRef string) (string, string, error) { | 
					
						
							|  |  |  | 	refTagRegexp := regexp.MustCompile(`^(oci://[^:]+(:[0-9]{1,5})?[^:]+):(.*)$`) | 
					
						
							|  |  |  | 	caps := refTagRegexp.FindStringSubmatch(chartRef) | 
					
						
							|  |  |  | 	if len(caps) != 4 { | 
					
						
							|  |  |  | 		return "", "", errors.Errorf("improperly formatted oci chart reference: %s", chartRef) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	chartRef = caps[1] | 
					
						
							|  |  |  | 	tag := caps[3] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return chartRef, tag, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-04 06:52:16 +08:00
										 |  |  | // safeDeleteDep deletes any versions of the given dependency in the given directory.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // It does this by first matching the file name to an expected pattern, then loading
 | 
					
						
							|  |  |  | // the file to verify that it is a chart with the same name as the given name.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Because it requires tar file introspection, it is more intensive than a basic delete.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will only return errors that should stop processing entirely. Other errors
 | 
					
						
							|  |  |  | // will emit log messages or be ignored.
 | 
					
						
							|  |  |  | func (m *Manager) safeDeleteDep(name, dir string) error { | 
					
						
							|  |  |  | 	files, err := filepath.Glob(filepath.Join(dir, name+"-*.tgz")) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// Only for ErrBadPattern
 | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, fname := range files { | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 		ch, err := loader.LoadFile(fname) | 
					
						
							| 
									
										
										
										
											2017-02-04 06:52:16 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			fmt.Fprintf(m.Out, "Could not verify %s for deletion: %s (Skipping)", fname, err) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 		if ch.Name() != name { | 
					
						
							| 
									
										
										
										
											2017-02-04 06:52:16 +08:00
										 |  |  | 			// This is not the file you are looking for.
 | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err := os.Remove(fname); err != nil { | 
					
						
							|  |  |  | 			fmt.Fprintf(m.Out, "Could not delete %s: %s (Skipping)", fname, err) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | // hasAllRepos ensures that all of the referenced deps are in the local repo cache.
 | 
					
						
							|  |  |  | func (m *Manager) hasAllRepos(deps []*chart.Dependency) error { | 
					
						
							|  |  |  | 	rf, err := loadRepoConfig(m.RepositoryConfig) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	repos := rf.Repositories | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify that all repositories referenced in the deps are actually known
 | 
					
						
							|  |  |  | 	// by Helm.
 | 
					
						
							|  |  |  | 	missing := []string{} | 
					
						
							|  |  |  | Loop: | 
					
						
							|  |  |  | 	for _, dd := range deps { | 
					
						
							|  |  |  | 		// If repo is from local path, continue
 | 
					
						
							|  |  |  | 		if strings.HasPrefix(dd.Repository, "file://") { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if dd.Repository == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for _, repo := range repos { | 
					
						
							|  |  |  | 			if urlutil.Equal(repo.URL, strings.TrimSuffix(dd.Repository, "/")) { | 
					
						
							|  |  |  | 				continue Loop | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		missing = append(missing, dd.Repository) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(missing) > 0 { | 
					
						
							|  |  |  | 		return ErrRepoNotFound{missing} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | // ensureMissingRepos attempts to ensure the repository information for repos
 | 
					
						
							|  |  |  | // not managed by Helm is present. This takes in the repoNames Helm is configured
 | 
					
						
							|  |  |  | // to work with along with the chart dependencies. It will find the deps not
 | 
					
						
							|  |  |  | // in a known repo and attempt to ensure the data is present for steps like
 | 
					
						
							|  |  |  | // version resolution.
 | 
					
						
							|  |  |  | func (m *Manager) ensureMissingRepos(repoNames map[string]string, deps []*chart.Dependency) (map[string]string, error) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ru []*repo.Entry | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	for _, dd := range deps { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-28 22:39:26 +08:00
										 |  |  | 		// If the chart is in the local charts directory no repository needs
 | 
					
						
							|  |  |  | 		// to be specified.
 | 
					
						
							|  |  |  | 		if dd.Repository == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 		// When the repoName for a dependency is known we can skip ensuring
 | 
					
						
							|  |  |  | 		if _, ok := repoNames[dd.Name]; ok { | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 		// The generated repository name, which will result in an index being
 | 
					
						
							|  |  |  | 		// locally cached, has a name pattern of "helm-manager-" followed by a
 | 
					
						
							|  |  |  | 		// sha256 of the repo name. This assumes end users will never create
 | 
					
						
							|  |  |  | 		// repositories with these names pointing to other repositories. Using
 | 
					
						
							|  |  |  | 		// this method of naming allows the existing repository pulling and
 | 
					
						
							|  |  |  | 		// resolution code to do most of the work.
 | 
					
						
							|  |  |  | 		rn, err := key(dd.Repository) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return repoNames, err | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | 		rn = managerKeyPrefix + rn | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		repoNames[dd.Name] = rn | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Assuming the repository is generally available. For Helm managed
 | 
					
						
							|  |  |  | 		// access controls the repository needs to be added through the user
 | 
					
						
							|  |  |  | 		// managed system. This path will work for public charts, like those
 | 
					
						
							|  |  |  | 		// supplied by Bitnami, but not for protected charts, like corp ones
 | 
					
						
							|  |  |  | 		// behind a username and pass.
 | 
					
						
							|  |  |  | 		ri := &repo.Entry{ | 
					
						
							|  |  |  | 			Name: rn, | 
					
						
							|  |  |  | 			URL:  dd.Repository, | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 		ru = append(ru, ri) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Calls to UpdateRepositories (a public function) will only update
 | 
					
						
							|  |  |  | 	// repositories configured by the user. Here we update repos found in
 | 
					
						
							|  |  |  | 	// the dependencies that are not known to the user if update skipping
 | 
					
						
							|  |  |  | 	// is not configured.
 | 
					
						
							|  |  |  | 	if !m.SkipUpdate && len(ru) > 0 { | 
					
						
							|  |  |  | 		fmt.Fprintln(m.Out, "Getting updates for unmanaged Helm repositories...") | 
					
						
							|  |  |  | 		if err := m.parallelRepoUpdate(ru); err != nil { | 
					
						
							|  |  |  | 			return repoNames, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return repoNames, nil | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-13 01:35:48 +08:00
										 |  |  | // resolveRepoNames returns the repo names of the referenced deps which can be used to fetch the cached index file
 | 
					
						
							|  |  |  | // and replaces aliased repository URLs into resolved URLs in dependencies.
 | 
					
						
							|  |  |  | func (m *Manager) resolveRepoNames(deps []*chart.Dependency) (map[string]string, error) { | 
					
						
							| 
									
										
										
										
											2019-08-29 05:13:49 +08:00
										 |  |  | 	rf, err := loadRepoConfig(m.RepositoryConfig) | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 		if os.IsNotExist(err) { | 
					
						
							|  |  |  | 			return make(map[string]string), nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	repos := rf.Repositories | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	reposMap := make(map[string]string) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Verify that all repositories referenced in the deps are actually known
 | 
					
						
							|  |  |  | 	// by Helm.
 | 
					
						
							|  |  |  | 	missing := []string{} | 
					
						
							|  |  |  | 	for _, dd := range deps { | 
					
						
							| 
									
										
										
										
											2019-10-09 23:35:55 +08:00
										 |  |  | 		// Don't map the repository, we don't need to download chart from charts directory
 | 
					
						
							|  |  |  | 		if dd.Repository == "" { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 		// if dep chart is from local path, verify the path is valid
 | 
					
						
							|  |  |  | 		if strings.HasPrefix(dd.Repository, "file://") { | 
					
						
							| 
									
										
										
										
											2017-03-28 08:31:01 +08:00
										 |  |  | 			if _, err := resolver.GetLocalPath(dd.Repository, m.ChartPath); err != nil { | 
					
						
							| 
									
										
										
										
											2017-02-11 03:16:28 +08:00
										 |  |  | 				return nil, err | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-25 07:19:37 +08:00
										 |  |  | 			if m.Debug { | 
					
						
							|  |  |  | 				fmt.Fprintf(m.Out, "Repository from local path: %s\n", dd.Repository) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 			reposMap[dd.Name] = dd.Repository | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 		if strings.HasPrefix(dd.Repository, "oci://") { | 
					
						
							|  |  |  | 			reposMap[dd.Name] = dd.Repository | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 		found := false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, repo := range repos { | 
					
						
							| 
									
										
										
										
											2017-03-24 04:14:34 +08:00
										 |  |  | 			if (strings.HasPrefix(dd.Repository, "@") && strings.TrimPrefix(dd.Repository, "@") == repo.Name) || | 
					
						
							|  |  |  | 				(strings.HasPrefix(dd.Repository, "alias:") && strings.TrimPrefix(dd.Repository, "alias:") == repo.Name) { | 
					
						
							|  |  |  | 				found = true | 
					
						
							|  |  |  | 				dd.Repository = repo.URL | 
					
						
							|  |  |  | 				reposMap[dd.Name] = repo.Name | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} else if urlutil.Equal(repo.URL, dd.Repository) { | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 				found = true | 
					
						
							|  |  |  | 				reposMap[dd.Name] = repo.Name | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !found { | 
					
						
							| 
									
										
										
										
											2019-09-25 01:03:30 +08:00
										 |  |  | 			repository := dd.Repository | 
					
						
							|  |  |  | 			// Add if URL
 | 
					
						
							|  |  |  | 			_, err := url.ParseRequestURI(repository) | 
					
						
							|  |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				reposMap[repository] = repository | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			missing = append(missing, repository) | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(missing) > 0 { | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 		errorMessage := fmt.Sprintf("no repository definition for %s. Please add them via 'helm repo add'", strings.Join(missing, ", ")) | 
					
						
							|  |  |  | 		// It is common for people to try to enter "stable" as a repository instead of the actual URL.
 | 
					
						
							|  |  |  | 		// For this case, let's give them a suggestion.
 | 
					
						
							|  |  |  | 		containsNonURL := false | 
					
						
							|  |  |  | 		for _, repo := range missing { | 
					
						
							|  |  |  | 			if !strings.Contains(repo, "//") && !strings.HasPrefix(repo, "@") && !strings.HasPrefix(repo, "alias:") { | 
					
						
							|  |  |  | 				containsNonURL = true | 
					
						
							| 
									
										
										
										
											2017-11-09 16:15:08 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if containsNonURL { | 
					
						
							|  |  |  | 			errorMessage += ` | 
					
						
							| 
									
										
										
										
											2019-07-27 00:27:18 +08:00
										 |  |  | Note that repositories must be URLs or aliases. For example, to refer to the "example" | 
					
						
							|  |  |  | repository, use "https://charts.example.com/" or "@example" instead of | 
					
						
							|  |  |  | "example". Don't forget to add the repo, too ('helm repo add').` | 
					
						
							| 
									
										
										
										
											2017-11-09 16:15:08 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 		return nil, errors.New(errorMessage) | 
					
						
							| 
									
										
										
										
											2016-11-16 07:50:19 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return reposMap, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | // UpdateRepositories updates all of the local repos to the latest.
 | 
					
						
							|  |  |  | func (m *Manager) UpdateRepositories() error { | 
					
						
							| 
									
										
										
										
											2019-08-29 05:13:49 +08:00
										 |  |  | 	rf, err := loadRepoConfig(m.RepositoryConfig) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	repos := rf.Repositories | 
					
						
							|  |  |  | 	if len(repos) > 0 { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 		fmt.Fprintln(m.Out, "Hang tight while we grab the latest from your chart repositories...") | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		// This prints warnings straight to out.
 | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 		if err := m.parallelRepoUpdate(repos); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 		fmt.Fprintln(m.Out, "Update Complete. ⎈Happy Helming!⎈") | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-09 19:25:37 +08:00
										 |  |  | func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	var wg sync.WaitGroup | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 	for _, c := range repos { | 
					
						
							| 
									
										
										
										
											2017-04-16 01:30:39 +08:00
										 |  |  | 		r, err := repo.NewChartRepository(c, m.Getters) | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		wg.Add(1) | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 		go func(r *repo.ChartRepository) { | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 			if _, err := r.DownloadIndexFile(); err != nil { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 				// For those dependencies that are not known to helm and using a
 | 
					
						
							|  |  |  | 				// generated key name we display the repo url.
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | 				if strings.HasPrefix(r.Config.Name, managerKeyPrefix) { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 					fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository:\n\t%s\n", r.Config.URL, err) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					fmt.Fprintf(m.Out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", r.Config.Name, r.Config.URL, err) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 				// For those dependencies that are not known to helm and using a
 | 
					
						
							|  |  |  | 				// generated key name we display the repo url.
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | 				if strings.HasPrefix(r.Config.Name, managerKeyPrefix) { | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 					fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.URL) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					fmt.Fprintf(m.Out, "...Successfully got an update from the %q chart repository\n", r.Config.Name) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			wg.Done() | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 		}(r) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	wg.Wait() | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | // findChartURL searches the cache of repo data for a chart that has the name and the repoURL specified.
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-10-07 06:07:22 +08:00
										 |  |  | // 'name' is the name of the chart. Version is an exact semver, or an empty string. If empty, the
 | 
					
						
							|  |  |  | // newest version will be returned.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | // repoURL is the repository to search
 | 
					
						
							| 
									
										
										
										
											2016-10-07 06:07:22 +08:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | // If it finds a URL that is "relative", it will prepend the repoURL.
 | 
					
						
							| 
									
										
										
										
											2019-09-25 01:03:30 +08:00
										 |  |  | func (m *Manager) findChartURL(name, version, repoURL string, repos map[string]*repo.ChartRepository) (url, username, password string, err error) { | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 	if strings.HasPrefix(repoURL, "oci://") { | 
					
						
							|  |  |  | 		return fmt.Sprintf("%s/%s:%s", repoURL, name, version), "", "", nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	for _, cr := range repos { | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-09 10:48:51 +08:00
										 |  |  | 		if urlutil.Equal(repoURL, cr.Config.URL) { | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 			var entry repo.ChartVersions | 
					
						
							|  |  |  | 			entry, err = findEntryByName(name, cr) | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 				return | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 			var ve *repo.ChartVersion | 
					
						
							|  |  |  | 			ve, err = findVersionedEntry(version, entry) | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | 			if err != nil { | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 				return | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-21 01:56:48 +08:00
										 |  |  | 			url, err = normalizeURL(repoURL, ve.URLs[0]) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			username = cr.Config.Username | 
					
						
							|  |  |  | 			password = cr.Config.Password | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-09-25 01:03:30 +08:00
										 |  |  | 	url, err = repo.FindChartInRepoURL(repoURL, name, version, "", "", "", m.Getters) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 		return url, username, password, err | 
					
						
							| 
									
										
										
										
											2019-09-25 01:03:30 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-02 19:43:53 +08:00
										 |  |  | 	err = errors.Errorf("chart %s not found in %s: %s", name, repoURL, err) | 
					
						
							| 
									
										
										
										
											2020-10-02 05:37:44 +08:00
										 |  |  | 	return url, username, password, err | 
					
						
							| 
									
										
										
										
											2016-10-06 02:43:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // findEntryByName finds an entry in the chart repository whose name matches the given name.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // It returns the ChartVersions for that entry.
 | 
					
						
							|  |  |  | func findEntryByName(name string, cr *repo.ChartRepository) (repo.ChartVersions, error) { | 
					
						
							|  |  |  | 	for ename, entry := range cr.IndexFile.Entries { | 
					
						
							|  |  |  | 		if ename == name { | 
					
						
							|  |  |  | 			return entry, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, errors.New("entry not found") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // findVersionedEntry takes a ChartVersions list and returns a single chart version that satisfies the version constraints.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If version is empty, the first chart found is returned.
 | 
					
						
							|  |  |  | func findVersionedEntry(version string, vers repo.ChartVersions) (*repo.ChartVersion, error) { | 
					
						
							|  |  |  | 	for _, verEntry := range vers { | 
					
						
							|  |  |  | 		if len(verEntry.URLs) == 0 { | 
					
						
							|  |  |  | 			// Not a legit entry.
 | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if version == "" || versionEquals(version, verEntry.Version) { | 
					
						
							|  |  |  | 			return verEntry, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, errors.New("no matching version") | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-07 06:07:22 +08:00
										 |  |  | func versionEquals(v1, v2 string) bool { | 
					
						
							|  |  |  | 	sv1, err := semver.NewVersion(v1) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		// Fallback to string comparison.
 | 
					
						
							|  |  |  | 		return v1 == v2 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sv2, err := semver.NewVersion(v2) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return sv1.Equal(sv2) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func normalizeURL(baseURL, urlOrPath string) (string, error) { | 
					
						
							|  |  |  | 	u, err := url.Parse(urlOrPath) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return urlOrPath, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if u.IsAbs() { | 
					
						
							|  |  |  | 		return u.String(), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	u2, err := url.Parse(baseURL) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 		return urlOrPath, errors.Wrap(err, "base URL failed to parse") | 
					
						
							| 
									
										
										
										
											2016-10-07 06:07:22 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	u2.Path = path.Join(u2.Path, urlOrPath) | 
					
						
							|  |  |  | 	return u2.String(), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | // loadChartRepositories reads the repositories.yaml, and then builds a map of
 | 
					
						
							|  |  |  | // ChartRepositories.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // The key is the local name (which is only present in the repositories.yaml).
 | 
					
						
							|  |  |  | func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, error) { | 
					
						
							|  |  |  | 	indices := map[string]*repo.ChartRepository{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Load repositories.yaml file
 | 
					
						
							| 
									
										
										
										
											2019-08-29 05:13:49 +08:00
										 |  |  | 	rf, err := loadRepoConfig(m.RepositoryConfig) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 		return indices, errors.Wrapf(err, "failed to load %s", m.RepositoryConfig) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-29 08:51:12 +08:00
										 |  |  | 	for _, re := range rf.Repositories { | 
					
						
							|  |  |  | 		lname := re.Name | 
					
						
							| 
									
										
										
										
											2019-08-23 14:31:50 +08:00
										 |  |  | 		idxFile := filepath.Join(m.RepositoryCache, helmpath.CacheIndexFile(lname)) | 
					
						
							|  |  |  | 		index, err := repo.LoadIndexFile(idxFile) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return indices, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 		// TODO: use constructor
 | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 		cr := &repo.ChartRepository{ | 
					
						
							| 
									
										
										
										
											2016-11-23 17:17:23 +08:00
										 |  |  | 			Config:    re, | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 			IndexFile: index, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		indices[lname] = cr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return indices, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // writeLock writes a lockfile to disk
 | 
					
						
							| 
									
										
										
										
											2019-12-12 01:07:05 +08:00
										 |  |  | func writeLock(chartpath string, lock *chart.Lock, legacyLockfile bool) error { | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	data, err := yaml.Marshal(lock) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-12-12 01:07:05 +08:00
										 |  |  | 	lockfileName := "Chart.lock" | 
					
						
							|  |  |  | 	if legacyLockfile { | 
					
						
							|  |  |  | 		lockfileName = "requirements.lock" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dest := filepath.Join(chartpath, lockfileName) | 
					
						
							| 
									
										
										
										
											2016-09-17 12:19:23 +08:00
										 |  |  | 	return ioutil.WriteFile(dest, data, 0644) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // archive a dep chart from local directory and save it into charts/
 | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | func tarFromLocalDir(chartpath, name, repo, version string) (string, error) { | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 	destPath := filepath.Join(chartpath, "charts") | 
					
						
							| 
									
										
										
										
											2017-02-11 03:16:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if !strings.HasPrefix(repo, "file://") { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 		return "", errors.Errorf("wrong format: chart %s repository %s", name, repo) | 
					
						
							| 
									
										
										
										
											2017-02-11 03:16:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-28 08:31:01 +08:00
										 |  |  | 	origPath, err := resolver.GetLocalPath(repo, chartpath) | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-25 02:28:29 +08:00
										 |  |  | 	ch, err := loader.LoadDir(origPath) | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	constraint, err := semver.NewConstraint(version) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 		return "", errors.Wrapf(err, "dependency %s has an invalid version/constraint format", name) | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	v, err := semver.NewVersion(ch.Metadata.Version) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "", err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if constraint.Check(v) { | 
					
						
							|  |  |  | 		_, err = chartutil.Save(ch, destPath) | 
					
						
							|  |  |  | 		return ch.Metadata.Version, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 	return "", errors.Errorf("can't get a valid version for dependency %s", name) | 
					
						
							| 
									
										
										
										
											2017-02-10 03:43:18 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-08-24 15:32:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // move files from tmppath to destpath
 | 
					
						
							|  |  |  | func move(tmpPath, destPath string) error { | 
					
						
							|  |  |  | 	files, _ := ioutil.ReadDir(tmpPath) | 
					
						
							|  |  |  | 	for _, file := range files { | 
					
						
							|  |  |  | 		filename := file.Name() | 
					
						
							|  |  |  | 		tmpfile := filepath.Join(tmpPath, filename) | 
					
						
							|  |  |  | 		destfile := filepath.Join(destPath, filename) | 
					
						
							| 
									
										
										
										
											2019-10-23 04:41:00 +08:00
										 |  |  | 		if err := fs.RenameWithFallback(tmpfile, destfile); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-11 00:34:41 +08:00
										 |  |  | 			return errors.Wrap(err, "unable to move local charts to charts dir") | 
					
						
							| 
									
										
										
										
											2017-08-24 15:32:44 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-23 03:51:27 +08:00
										 |  |  | // The prefix to use for cache keys created by the manager for repo names
 | 
					
						
							|  |  |  | const managerKeyPrefix = "helm-manager-" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-17 23:54:44 +08:00
										 |  |  | // key is used to turn a name, such as a repository url, into a filesystem
 | 
					
						
							|  |  |  | // safe name that is unique for querying. To accomplish this a unique hash of
 | 
					
						
							|  |  |  | // the string is used.
 | 
					
						
							|  |  |  | func key(name string) (string, error) { | 
					
						
							|  |  |  | 	in := strings.NewReader(name) | 
					
						
							|  |  |  | 	hash := crypto.SHA256.New() | 
					
						
							|  |  |  | 	if _, err := io.Copy(hash, in); err != nil { | 
					
						
							|  |  |  | 		return "", nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return hex.EncodeToString(hash.Sum(nil)), nil | 
					
						
							|  |  |  | } |