openpitrix crd
Signed-off-by: LiHui <andrewli@yunify.com> delete helm repo, release and app Signed-off-by: LiHui <andrewli@yunify.com> Fix Dockerfile Signed-off-by: LiHui <andrewli@yunify.com> add unit test for category controller Signed-off-by: LiHui <andrewli@yunify.com> resource api Signed-off-by: LiHui <andrewli@yunify.com> miscellaneous Signed-off-by: LiHui <andrewli@yunify.com> resource api Signed-off-by: LiHui <andrewli@yunify.com> add s3 repo indx Signed-off-by: LiHui <andrewli@yunify.com> attachment api Signed-off-by: LiHui <andrewli@yunify.com> repo controller test Signed-off-by: LiHui <andrewli@yunify.com> application controller test Signed-off-by: LiHui <andrewli@yunify.com> release metric Signed-off-by: LiHui <andrewli@yunify.com> helm release controller test Signed-off-by: LiHui <andrewli@yunify.com> move constants to /pkg/apis/application Signed-off-by: LiHui <andrewli@yunify.com> remove unused code Signed-off-by: LiHui <andrewli@yunify.com> add license header Signed-off-by: LiHui <andrewli@yunify.com> Fix bugs Signed-off-by: LiHui <andrewli@yunify.com> cluster cluent Signed-off-by: LiHui <andrewli@yunify.com> format code Signed-off-by: LiHui <andrewli@yunify.com> move workspace,cluster from spec to labels Signed-off-by: LiHui <andrewli@yunify.com> add license header Signed-off-by: LiHui <andrewli@yunify.com> openpitrix test Signed-off-by: LiHui <andrewli@yunify.com> add worksapce labels for app in appstore Signed-off-by: LiHui <andrewli@yunify.com>
This commit is contained in:
202
vendor/helm.sh/helm/v3/LICENSE
vendored
Normal file
202
vendor/helm.sh/helm/v3/LICENSE
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2016 The Kubernetes Authors All Rights Reserved
|
||||
|
||||
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.
|
||||
51
vendor/helm.sh/helm/v3/internal/fileutil/fileutil.go
vendored
Normal file
51
vendor/helm.sh/helm/v3/internal/fileutil/fileutil.go
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 fileutil
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"helm.sh/helm/v3/internal/third_party/dep/fs"
|
||||
)
|
||||
|
||||
// AtomicWriteFile atomically (as atomic as os.Rename allows) writes a file to a
|
||||
// disk.
|
||||
func AtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) error {
|
||||
tempFile, err := ioutil.TempFile(filepath.Split(filename))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tempName := tempFile.Name()
|
||||
|
||||
if _, err := io.Copy(tempFile, reader); err != nil {
|
||||
tempFile.Close() // return value is ignored as we are already on error path
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tempFile.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Chmod(tempName, mode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fs.RenameWithFallback(tempName, filename)
|
||||
}
|
||||
67
vendor/helm.sh/helm/v3/internal/ignore/doc.go
vendored
Normal file
67
vendor/helm.sh/helm/v3/internal/ignore/doc.go
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 ignore provides tools for writing ignore files (a la .gitignore).
|
||||
|
||||
This provides both an ignore parser and a file-aware processor.
|
||||
|
||||
The format of ignore files closely follows, but does not exactly match, the
|
||||
format for .gitignore files (https://git-scm.com/docs/gitignore).
|
||||
|
||||
The formatting rules are as follows:
|
||||
|
||||
- Parsing is line-by-line
|
||||
- Empty lines are ignored
|
||||
- Lines the begin with # (comments) will be ignored
|
||||
- Leading and trailing spaces are always ignored
|
||||
- Inline comments are NOT supported ('foo* # Any foo' does not contain a comment)
|
||||
- There is no support for multi-line patterns
|
||||
- Shell glob patterns are supported. See Go's "path/filepath".Match
|
||||
- If a pattern begins with a leading !, the match will be negated.
|
||||
- If a pattern begins with a leading /, only paths relatively rooted will match.
|
||||
- If the pattern ends with a trailing /, only directories will match
|
||||
- If a pattern contains no slashes, file basenames are tested (not paths)
|
||||
- The pattern sequence "**", while legal in a glob, will cause an error here
|
||||
(to indicate incompatibility with .gitignore).
|
||||
|
||||
Example:
|
||||
|
||||
# Match any file named foo.txt
|
||||
foo.txt
|
||||
|
||||
# Match any text file
|
||||
*.txt
|
||||
|
||||
# Match only directories named mydir
|
||||
mydir/
|
||||
|
||||
# Match only text files in the top-level directory
|
||||
/*.txt
|
||||
|
||||
# Match only the file foo.txt in the top-level directory
|
||||
/foo.txt
|
||||
|
||||
# Match any file named ab.txt, ac.txt, or ad.txt
|
||||
a[b-d].txt
|
||||
|
||||
Notable differences from .gitignore:
|
||||
- The '**' syntax is not supported.
|
||||
- The globbing library is Go's 'filepath.Match', not fnmatch(3)
|
||||
- Trailing spaces are always ignored (there is no supported escape sequence)
|
||||
- The evaluation of escape sequences has not been tested for compatibility
|
||||
- There is no support for '\!' as a special leading sequence.
|
||||
*/
|
||||
package ignore // import "helm.sh/helm/v3/internal/ignore"
|
||||
228
vendor/helm.sh/helm/v3/internal/ignore/rules.go
vendored
Normal file
228
vendor/helm.sh/helm/v3/internal/ignore/rules.go
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 ignore
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// HelmIgnore default name of an ignorefile.
|
||||
const HelmIgnore = ".helmignore"
|
||||
|
||||
// Rules is a collection of path matching rules.
|
||||
//
|
||||
// Parse() and ParseFile() will construct and populate new Rules.
|
||||
// Empty() will create an immutable empty ruleset.
|
||||
type Rules struct {
|
||||
patterns []*pattern
|
||||
}
|
||||
|
||||
// Empty builds an empty ruleset.
|
||||
func Empty() *Rules {
|
||||
return &Rules{patterns: []*pattern{}}
|
||||
}
|
||||
|
||||
// AddDefaults adds default ignore patterns.
|
||||
//
|
||||
// Ignore all dotfiles in "templates/"
|
||||
func (r *Rules) AddDefaults() {
|
||||
r.parseRule(`templates/.?*`)
|
||||
}
|
||||
|
||||
// ParseFile parses a helmignore file and returns the *Rules.
|
||||
func ParseFile(file string) (*Rules, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return Parse(f)
|
||||
}
|
||||
|
||||
// Parse parses a rules file
|
||||
func Parse(file io.Reader) (*Rules, error) {
|
||||
r := &Rules{patterns: []*pattern{}}
|
||||
|
||||
s := bufio.NewScanner(file)
|
||||
currentLine := 0
|
||||
utf8bom := []byte{0xEF, 0xBB, 0xBF}
|
||||
for s.Scan() {
|
||||
scannedBytes := s.Bytes()
|
||||
// We trim UTF8 BOM
|
||||
if currentLine == 0 {
|
||||
scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom)
|
||||
}
|
||||
line := string(scannedBytes)
|
||||
currentLine++
|
||||
|
||||
if err := r.parseRule(line); err != nil {
|
||||
return r, err
|
||||
}
|
||||
}
|
||||
return r, s.Err()
|
||||
}
|
||||
|
||||
// Ignore evaluates the file at the given path, and returns true if it should be ignored.
|
||||
//
|
||||
// Ignore evaluates path against the rules in order. Evaluation stops when a match
|
||||
// is found. Matching a negative rule will stop evaluation.
|
||||
func (r *Rules) Ignore(path string, fi os.FileInfo) bool {
|
||||
// Don't match on empty dirs.
|
||||
if path == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Disallow ignoring the current working directory.
|
||||
// See issue:
|
||||
// 1776 (New York City) Hamilton: "Pardon me, are you Aaron Burr, sir?"
|
||||
if path == "." || path == "./" {
|
||||
return false
|
||||
}
|
||||
for _, p := range r.patterns {
|
||||
if p.match == nil {
|
||||
log.Printf("ignore: no matcher supplied for %q", p.raw)
|
||||
return false
|
||||
}
|
||||
|
||||
// For negative rules, we need to capture and return non-matches,
|
||||
// and continue for matches.
|
||||
if p.negate {
|
||||
if p.mustDir && !fi.IsDir() {
|
||||
return true
|
||||
}
|
||||
if !p.match(path, fi) {
|
||||
return true
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// If the rule is looking for directories, and this is not a directory,
|
||||
// skip it.
|
||||
if p.mustDir && !fi.IsDir() {
|
||||
continue
|
||||
}
|
||||
if p.match(path, fi) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseRule parses a rule string and creates a pattern, which is then stored in the Rules object.
|
||||
func (r *Rules) parseRule(rule string) error {
|
||||
rule = strings.TrimSpace(rule)
|
||||
|
||||
// Ignore blank lines
|
||||
if rule == "" {
|
||||
return nil
|
||||
}
|
||||
// Comment
|
||||
if strings.HasPrefix(rule, "#") {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fail any rules that contain **
|
||||
if strings.Contains(rule, "**") {
|
||||
return errors.New("double-star (**) syntax is not supported")
|
||||
}
|
||||
|
||||
// Fail any patterns that can't compile. A non-empty string must be
|
||||
// given to Match() to avoid optimization that skips rule evaluation.
|
||||
if _, err := filepath.Match(rule, "abc"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := &pattern{raw: rule}
|
||||
|
||||
// Negation is handled at a higher level, so strip the leading ! from the
|
||||
// string.
|
||||
if strings.HasPrefix(rule, "!") {
|
||||
p.negate = true
|
||||
rule = rule[1:]
|
||||
}
|
||||
|
||||
// Directory verification is handled by a higher level, so the trailing /
|
||||
// is removed from the rule. That way, a directory named "foo" matches,
|
||||
// even if the supplied string does not contain a literal slash character.
|
||||
if strings.HasSuffix(rule, "/") {
|
||||
p.mustDir = true
|
||||
rule = strings.TrimSuffix(rule, "/")
|
||||
}
|
||||
|
||||
if strings.HasPrefix(rule, "/") {
|
||||
// Require path matches the root path.
|
||||
p.match = func(n string, fi os.FileInfo) bool {
|
||||
rule = strings.TrimPrefix(rule, "/")
|
||||
ok, err := filepath.Match(rule, n)
|
||||
if err != nil {
|
||||
log.Printf("Failed to compile %q: %s", rule, err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
} else if strings.Contains(rule, "/") {
|
||||
// require structural match.
|
||||
p.match = func(n string, fi os.FileInfo) bool {
|
||||
ok, err := filepath.Match(rule, n)
|
||||
if err != nil {
|
||||
log.Printf("Failed to compile %q: %s", rule, err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
} else {
|
||||
p.match = func(n string, fi os.FileInfo) bool {
|
||||
// When there is no slash in the pattern, we evaluate ONLY the
|
||||
// filename.
|
||||
n = filepath.Base(n)
|
||||
ok, err := filepath.Match(rule, n)
|
||||
if err != nil {
|
||||
log.Printf("Failed to compile %q: %s", rule, err)
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
}
|
||||
|
||||
r.patterns = append(r.patterns, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
// matcher is a function capable of computing a match.
|
||||
//
|
||||
// It returns true if the rule matches.
|
||||
type matcher func(name string, fi os.FileInfo) bool
|
||||
|
||||
// pattern describes a pattern to be matched in a rule set.
|
||||
type pattern struct {
|
||||
// raw is the unparsed string, with nothing stripped.
|
||||
raw string
|
||||
// match is the matcher function.
|
||||
match matcher
|
||||
// negate indicates that the rule's outcome should be negated.
|
||||
negate bool
|
||||
// mustDir indicates that the matched file must be a directory.
|
||||
mustDir bool
|
||||
}
|
||||
119
vendor/helm.sh/helm/v3/internal/sympath/walk.go
vendored
Normal file
119
vendor/helm.sh/helm/v3/internal/sympath/walk.go
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
Copyright (c) for portions of walk.go are held by The Go Authors, 2009 and are
|
||||
provided under the BSD license.
|
||||
|
||||
https://github.com/golang/go/blob/master/LICENSE
|
||||
|
||||
Copyright The Helm Authors.
|
||||
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 sympath
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Walk walks the file tree rooted at root, calling walkFn for each file or directory
|
||||
// in the tree, including root. All errors that arise visiting files and directories
|
||||
// are filtered by walkFn. The files are walked in lexical order, which makes the
|
||||
// output deterministic but means that for very large directories Walk can be
|
||||
// inefficient. Walk follows symbolic links.
|
||||
func Walk(root string, walkFn filepath.WalkFunc) error {
|
||||
info, err := os.Lstat(root)
|
||||
if err != nil {
|
||||
err = walkFn(root, nil, err)
|
||||
} else {
|
||||
err = symwalk(root, info, walkFn)
|
||||
}
|
||||
if err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// readDirNames reads the directory named by dirname and returns
|
||||
// a sorted list of directory entries.
|
||||
func readDirNames(dirname string) ([]string, error) {
|
||||
f, err := os.Open(dirname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
names, err := f.Readdirnames(-1)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// symwalk recursively descends path, calling walkFn.
|
||||
func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
|
||||
// Recursively walk symlinked directories.
|
||||
if IsSymlink(info) {
|
||||
resolved, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error evaluating symlink %s", path)
|
||||
}
|
||||
log.Printf("found symbolic link in path: %s resolves to %s", path, resolved)
|
||||
if info, err = os.Lstat(resolved); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := walkFn(path, info, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
names, err := readDirNames(path)
|
||||
if err != nil {
|
||||
return walkFn(path, info, err)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
filename := filepath.Join(path, name)
|
||||
fileInfo, err := os.Lstat(filename)
|
||||
if err != nil {
|
||||
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = symwalk(filename, fileInfo, walkFn)
|
||||
if err != nil {
|
||||
if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsSymlink is used to determine if the fileinfo is a symbolic link.
|
||||
func IsSymlink(fi os.FileInfo) bool {
|
||||
return fi.Mode()&os.ModeSymlink != 0
|
||||
}
|
||||
373
vendor/helm.sh/helm/v3/internal/third_party/dep/fs/fs.go
vendored
Normal file
373
vendor/helm.sh/helm/v3/internal/third_party/dep/fs/fs.go
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
Copyright (c) for portions of fs.go are held by The Go Authors, 2016 and are provided under
|
||||
the BSD license.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// fs contains a copy of a few functions from dep tool code to avoid a dependency on golang/dep.
|
||||
// This code is copied from https://github.com/golang/dep/blob/37d6c560cdf407be7b6cd035b23dba89df9275cf/internal/fs/fs.go
|
||||
// No changes to the code were made other than removing some unused functions
|
||||
|
||||
// RenameWithFallback attempts to rename a file or directory, but falls back to
|
||||
// copying in the event of a cross-device link error. If the fallback copy
|
||||
// succeeds, src is still removed, emulating normal rename behavior.
|
||||
func RenameWithFallback(src, dst string) error {
|
||||
_, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot stat %s", src)
|
||||
}
|
||||
|
||||
err = os.Rename(src, dst)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return renameFallback(err, src, dst)
|
||||
}
|
||||
|
||||
// renameByCopy attempts to rename a file or directory by copying it to the
|
||||
// destination and then removing the src thus emulating the rename behavior.
|
||||
func renameByCopy(src, dst string) error {
|
||||
var cerr error
|
||||
if dir, _ := IsDir(src); dir {
|
||||
cerr = CopyDir(src, dst)
|
||||
if cerr != nil {
|
||||
cerr = errors.Wrap(cerr, "copying directory failed")
|
||||
}
|
||||
} else {
|
||||
cerr = copyFile(src, dst)
|
||||
if cerr != nil {
|
||||
cerr = errors.Wrap(cerr, "copying file failed")
|
||||
}
|
||||
}
|
||||
|
||||
if cerr != nil {
|
||||
return errors.Wrapf(cerr, "rename fallback failed: cannot rename %s to %s", src, dst)
|
||||
}
|
||||
|
||||
return errors.Wrapf(os.RemoveAll(src), "cannot delete %s", src)
|
||||
}
|
||||
|
||||
var (
|
||||
errSrcNotDir = errors.New("source is not a directory")
|
||||
errDstExist = errors.New("destination already exists")
|
||||
)
|
||||
|
||||
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
|
||||
// Source directory must exist, destination directory must *not* exist.
|
||||
func CopyDir(src, dst string) error {
|
||||
src = filepath.Clean(src)
|
||||
dst = filepath.Clean(dst)
|
||||
|
||||
// We use os.Lstat() here to ensure we don't fall in a loop where a symlink
|
||||
// actually links to a one of its parent directories.
|
||||
fi, err := os.Lstat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !fi.IsDir() {
|
||||
return errSrcNotDir
|
||||
}
|
||||
|
||||
_, err = os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
return errDstExist
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dst, fi.Mode()); err != nil {
|
||||
return errors.Wrapf(err, "cannot mkdir %s", dst)
|
||||
}
|
||||
|
||||
entries, err := ioutil.ReadDir(src)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot read directory %s", dst)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
if err = CopyDir(srcPath, dstPath); err != nil {
|
||||
return errors.Wrap(err, "copying directory failed")
|
||||
}
|
||||
} else {
|
||||
// This will include symlinks, which is what we want when
|
||||
// copying things.
|
||||
if err = copyFile(srcPath, dstPath); err != nil {
|
||||
return errors.Wrap(err, "copying file failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// copyFile copies the contents of the file named src to the file named
|
||||
// by dst. The file will be created if it does not already exist. If the
|
||||
// destination file exists, all its contents will be replaced by the contents
|
||||
// of the source file. The file mode will be copied from the source.
|
||||
func copyFile(src, dst string) (err error) {
|
||||
if sym, err := IsSymlink(src); err != nil {
|
||||
return errors.Wrap(err, "symlink check failed")
|
||||
} else if sym {
|
||||
if err := cloneSymlink(src, dst); err != nil {
|
||||
if runtime.GOOS == "windows" {
|
||||
// If cloning the symlink fails on Windows because the user
|
||||
// does not have the required privileges, ignore the error and
|
||||
// fall back to copying the file contents.
|
||||
//
|
||||
// ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522):
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx
|
||||
if lerr, ok := err.(*os.LinkError); ok && lerr.Err != syscall.Errno(1314) {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(out, in); err != nil {
|
||||
out.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// Check for write errors on Close
|
||||
if err = out.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Temporary fix for Go < 1.9
|
||||
//
|
||||
// See: https://github.com/golang/dep/issues/774
|
||||
// and https://github.com/golang/go/issues/20829
|
||||
if runtime.GOOS == "windows" {
|
||||
dst = fixLongPath(dst)
|
||||
}
|
||||
err = os.Chmod(dst, si.Mode())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// cloneSymlink will create a new symlink that points to the resolved path of sl.
|
||||
// If sl is a relative symlink, dst will also be a relative symlink.
|
||||
func cloneSymlink(sl, dst string) error {
|
||||
resolved, err := os.Readlink(sl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Symlink(resolved, dst)
|
||||
}
|
||||
|
||||
// IsDir determines is the path given is a directory or not.
|
||||
func IsDir(name string) (bool, error) {
|
||||
fi, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !fi.IsDir() {
|
||||
return false, errors.Errorf("%q is not a directory", name)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// IsSymlink determines if the given path is a symbolic link.
|
||||
func IsSymlink(path string) (bool, error) {
|
||||
l, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return l.Mode()&os.ModeSymlink == os.ModeSymlink, nil
|
||||
}
|
||||
|
||||
// fixLongPath returns the extended-length (\\?\-prefixed) form of
|
||||
// path when needed, in order to avoid the default 260 character file
|
||||
// path limit imposed by Windows. If path is not easily converted to
|
||||
// the extended-length form (for example, if path is a relative path
|
||||
// or contains .. elements), or is short enough, fixLongPath returns
|
||||
// path unmodified.
|
||||
//
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
|
||||
func fixLongPath(path string) string {
|
||||
// Do nothing (and don't allocate) if the path is "short".
|
||||
// Empirically (at least on the Windows Server 2013 builder),
|
||||
// the kernel is arbitrarily okay with < 248 bytes. That
|
||||
// matches what the docs above say:
|
||||
// "When using an API to create a directory, the specified
|
||||
// path cannot be so long that you cannot append an 8.3 file
|
||||
// name (that is, the directory name cannot exceed MAX_PATH
|
||||
// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
|
||||
//
|
||||
// The MSDN docs appear to say that a normal path that is 248 bytes long
|
||||
// will work; empirically the path must be less then 248 bytes long.
|
||||
if len(path) < 248 {
|
||||
// Don't fix. (This is how Go 1.7 and earlier worked,
|
||||
// not automatically generating the \\?\ form)
|
||||
return path
|
||||
}
|
||||
|
||||
// The extended form begins with \\?\, as in
|
||||
// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
|
||||
// The extended form disables evaluation of . and .. path
|
||||
// elements and disables the interpretation of / as equivalent
|
||||
// to \. The conversion here rewrites / to \ and elides
|
||||
// . elements as well as trailing or duplicate separators. For
|
||||
// simplicity it avoids the conversion entirely for relative
|
||||
// paths or paths containing .. elements. For now,
|
||||
// \\server\share paths are not converted to
|
||||
// \\?\UNC\server\share paths because the rules for doing so
|
||||
// are less well-specified.
|
||||
if len(path) >= 2 && path[:2] == `\\` {
|
||||
// Don't canonicalize UNC paths.
|
||||
return path
|
||||
}
|
||||
if !isAbs(path) {
|
||||
// Relative path
|
||||
return path
|
||||
}
|
||||
|
||||
const prefix = `\\?`
|
||||
|
||||
pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
|
||||
copy(pathbuf, prefix)
|
||||
n := len(path)
|
||||
r, w := 0, len(prefix)
|
||||
for r < n {
|
||||
switch {
|
||||
case os.IsPathSeparator(path[r]):
|
||||
// empty block
|
||||
r++
|
||||
case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
|
||||
// /./
|
||||
r++
|
||||
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
|
||||
// /../ is currently unhandled
|
||||
return path
|
||||
default:
|
||||
pathbuf[w] = '\\'
|
||||
w++
|
||||
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
|
||||
pathbuf[w] = path[r]
|
||||
w++
|
||||
}
|
||||
}
|
||||
}
|
||||
// A drive's root directory needs a trailing \
|
||||
if w == len(`\\?\c:`) {
|
||||
pathbuf[w] = '\\'
|
||||
w++
|
||||
}
|
||||
return string(pathbuf[:w])
|
||||
}
|
||||
|
||||
func isAbs(path string) (b bool) {
|
||||
v := volumeName(path)
|
||||
if v == "" {
|
||||
return false
|
||||
}
|
||||
path = path[len(v):]
|
||||
if path == "" {
|
||||
return false
|
||||
}
|
||||
return os.IsPathSeparator(path[0])
|
||||
}
|
||||
|
||||
func volumeName(path string) (v string) {
|
||||
if len(path) < 2 {
|
||||
return ""
|
||||
}
|
||||
// with drive letter
|
||||
c := path[0]
|
||||
if path[1] == ':' &&
|
||||
('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
|
||||
'A' <= c && c <= 'Z') {
|
||||
return path[:2]
|
||||
}
|
||||
// is it UNC
|
||||
if l := len(path); l >= 5 && os.IsPathSeparator(path[0]) && os.IsPathSeparator(path[1]) &&
|
||||
!os.IsPathSeparator(path[2]) && path[2] != '.' {
|
||||
// first, leading `\\` and next shouldn't be `\`. its server name.
|
||||
for n := 3; n < l-1; n++ {
|
||||
// second, next '\' shouldn't be repeated.
|
||||
if os.IsPathSeparator(path[n]) {
|
||||
n++
|
||||
// third, following something characters. its share name.
|
||||
if !os.IsPathSeparator(path[n]) {
|
||||
if path[n] == '.' {
|
||||
break
|
||||
}
|
||||
for ; n < l; n++ {
|
||||
if os.IsPathSeparator(path[n]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return path[:n]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
58
vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename.go
vendored
Normal file
58
vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename.go
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright (c) for portions of rename.go are held by The Go Authors, 2016 and are provided under
|
||||
the BSD license.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// renameFallback attempts to determine the appropriate fallback to failed rename
|
||||
// operation depending on the resulting error.
|
||||
func renameFallback(err error, src, dst string) error {
|
||||
// Rename may fail if src and dst are on different devices; fall back to
|
||||
// copy if we detect that case. syscall.EXDEV is the common name for the
|
||||
// cross device link error which has varying output text across different
|
||||
// operating systems.
|
||||
terr, ok := err.(*os.LinkError)
|
||||
if !ok {
|
||||
return err
|
||||
} else if terr.Err != syscall.EXDEV {
|
||||
return errors.Wrapf(terr, "link error: cannot rename %s to %s", src, dst)
|
||||
}
|
||||
|
||||
return renameByCopy(src, dst)
|
||||
}
|
||||
69
vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename_windows.go
vendored
Normal file
69
vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename_windows.go
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright (c) for portions of rename_windows.go are held by The Go Authors, 2016 and are provided under
|
||||
the BSD license.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package fs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// renameFallback attempts to determine the appropriate fallback to failed rename
|
||||
// operation depending on the resulting error.
|
||||
func renameFallback(err error, src, dst string) error {
|
||||
// Rename may fail if src and dst are on different devices; fall back to
|
||||
// copy if we detect that case. syscall.EXDEV is the common name for the
|
||||
// cross device link error which has varying output text across different
|
||||
// operating systems.
|
||||
terr, ok := err.(*os.LinkError)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
if terr.Err != syscall.EXDEV {
|
||||
// In windows it can drop down to an operating system call that
|
||||
// returns an operating system error with a different number and
|
||||
// message. Checking for that as a fall back.
|
||||
noerr, ok := terr.Err.(syscall.Errno)
|
||||
|
||||
// 0x11 (ERROR_NOT_SAME_DEVICE) is the windows error.
|
||||
// See https://msdn.microsoft.com/en-us/library/cc231199.aspx
|
||||
if ok && noerr != 0x11 {
|
||||
return errors.Wrapf(terr, "link error: cannot rename %s to %s", src, dst)
|
||||
}
|
||||
}
|
||||
|
||||
return renameByCopy(src, dst)
|
||||
}
|
||||
58
vendor/helm.sh/helm/v3/internal/tlsutil/cfg.go
vendored
Normal file
58
vendor/helm.sh/helm/v3/internal/tlsutil/cfg.go
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 tlsutil
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Options represents configurable options used to create client and server TLS configurations.
|
||||
type Options struct {
|
||||
CaCertFile string
|
||||
// If either the KeyFile or CertFile is empty, ClientConfig() will not load them.
|
||||
KeyFile string
|
||||
CertFile string
|
||||
// Client-only options
|
||||
InsecureSkipVerify bool
|
||||
}
|
||||
|
||||
// ClientConfig returns a TLS configuration for use by a Helm client.
|
||||
func ClientConfig(opts Options) (cfg *tls.Config, err error) {
|
||||
var cert *tls.Certificate
|
||||
var pool *x509.CertPool
|
||||
|
||||
if opts.CertFile != "" || opts.KeyFile != "" {
|
||||
if cert, err = CertFromFilePair(opts.CertFile, opts.KeyFile); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, errors.Wrapf(err, "could not load x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile)
|
||||
}
|
||||
return nil, errors.Wrapf(err, "could not read x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile)
|
||||
}
|
||||
}
|
||||
if !opts.InsecureSkipVerify && opts.CaCertFile != "" {
|
||||
if pool, err = CertPoolFromFile(opts.CaCertFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool}
|
||||
return cfg, nil
|
||||
}
|
||||
76
vendor/helm.sh/helm/v3/internal/tlsutil/tls.go
vendored
Normal file
76
vendor/helm.sh/helm/v3/internal/tlsutil/tls.go
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 tlsutil
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// NewClientTLS returns tls.Config appropriate for client auth.
|
||||
func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) {
|
||||
config := tls.Config{}
|
||||
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := CertFromFilePair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.Certificates = []tls.Certificate{*cert}
|
||||
}
|
||||
|
||||
if caFile != "" {
|
||||
cp, err := CertPoolFromFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.RootCAs = cp
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
// CertPoolFromFile returns an x509.CertPool containing the certificates
|
||||
// in the given PEM-encoded file.
|
||||
// Returns an error if the file could not be read, a certificate could not
|
||||
// be parsed, or if the file does not contain any certificates
|
||||
func CertPoolFromFile(filename string) (*x509.CertPool, error) {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("can't read CA file: %v", filename)
|
||||
}
|
||||
cp := x509.NewCertPool()
|
||||
if !cp.AppendCertsFromPEM(b) {
|
||||
return nil, errors.Errorf("failed to append certificates from file: %s", filename)
|
||||
}
|
||||
return cp, nil
|
||||
}
|
||||
|
||||
// CertFromFilePair returns an tls.Certificate containing the
|
||||
// certificates public/private key pair from a pair of given PEM-encoded files.
|
||||
// Returns an error if the file could not be read, a certificate could not
|
||||
// be parsed, or if the file does not contain any certificates
|
||||
func CertFromFilePair(certFile, keyFile string) (*tls.Certificate, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't load key pair from cert %s and key %s", certFile, keyFile)
|
||||
}
|
||||
return &cert, err
|
||||
}
|
||||
73
vendor/helm.sh/helm/v3/internal/urlutil/urlutil.go
vendored
Normal file
73
vendor/helm.sh/helm/v3/internal/urlutil/urlutil.go
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 urlutil
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// URLJoin joins a base URL to one or more path components.
|
||||
//
|
||||
// It's like filepath.Join for URLs. If the baseURL is pathish, this will still
|
||||
// perform a join.
|
||||
//
|
||||
// If the URL is unparsable, this returns an error.
|
||||
func URLJoin(baseURL string, paths ...string) (string, error) {
|
||||
u, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// We want path instead of filepath because path always uses /.
|
||||
all := []string{u.Path}
|
||||
all = append(all, paths...)
|
||||
u.Path = path.Join(all...)
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
// Equal normalizes two URLs and then compares for equality.
|
||||
func Equal(a, b string) bool {
|
||||
au, err := url.Parse(a)
|
||||
if err != nil {
|
||||
a = filepath.Clean(a)
|
||||
b = filepath.Clean(b)
|
||||
// If urls are paths, return true only if they are an exact match
|
||||
return a == b
|
||||
}
|
||||
bu, err := url.Parse(b)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, u := range []*url.URL{au, bu} {
|
||||
if u.Path == "" {
|
||||
u.Path = "/"
|
||||
}
|
||||
u.Path = filepath.Clean(u.Path)
|
||||
}
|
||||
return au.String() == bu.String()
|
||||
}
|
||||
|
||||
// ExtractHostname returns hostname from URL
|
||||
func ExtractHostname(addr string) (string, error) {
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return u.Hostname(), nil
|
||||
}
|
||||
82
vendor/helm.sh/helm/v3/internal/version/version.go
vendored
Normal file
82
vendor/helm.sh/helm/v3/internal/version/version.go
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 version // import "helm.sh/helm/v3/internal/version"
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// version is the current version of Helm.
|
||||
// Update this whenever making a new release.
|
||||
// The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata]
|
||||
//
|
||||
// Increment major number for new feature additions and behavioral changes.
|
||||
// Increment minor number for bug fixes and performance enhancements.
|
||||
// Increment patch number for critical fixes to existing releases.
|
||||
version = "v3.3"
|
||||
|
||||
// metadata is extra build time data
|
||||
metadata = ""
|
||||
// gitCommit is the git sha1
|
||||
gitCommit = ""
|
||||
// gitTreeState is the state of the git tree
|
||||
gitTreeState = ""
|
||||
)
|
||||
|
||||
// BuildInfo describes the compile time information.
|
||||
type BuildInfo struct {
|
||||
// Version is the current semver.
|
||||
Version string `json:"version,omitempty"`
|
||||
// GitCommit is the git sha1.
|
||||
GitCommit string `json:"git_commit,omitempty"`
|
||||
// GitTreeState is the state of the git tree.
|
||||
GitTreeState string `json:"git_tree_state,omitempty"`
|
||||
// GoVersion is the version of the Go compiler used.
|
||||
GoVersion string `json:"go_version,omitempty"`
|
||||
}
|
||||
|
||||
// GetVersion returns the semver string of the version
|
||||
func GetVersion() string {
|
||||
if metadata == "" {
|
||||
return version
|
||||
}
|
||||
return version + "+" + metadata
|
||||
}
|
||||
|
||||
// GetUserAgent returns a user agent for user with an HTTP client
|
||||
func GetUserAgent() string {
|
||||
return "Helm/" + strings.TrimPrefix(GetVersion(), "v")
|
||||
}
|
||||
|
||||
// Get returns build info
|
||||
func Get() BuildInfo {
|
||||
v := BuildInfo{
|
||||
Version: GetVersion(),
|
||||
GitCommit: gitCommit,
|
||||
GitTreeState: gitTreeState,
|
||||
GoVersion: runtime.Version(),
|
||||
}
|
||||
|
||||
// HACK(bacongobbler): strip out GoVersion during a test run for consistent test output
|
||||
if flag.Lookup("test.v") != nil {
|
||||
v.GoVersion = ""
|
||||
}
|
||||
return v
|
||||
}
|
||||
169
vendor/helm.sh/helm/v3/pkg/chart/chart.go
vendored
Normal file
169
vendor/helm.sh/helm/v3/pkg/chart/chart.go
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// APIVersionV1 is the API version number for version 1.
|
||||
const APIVersionV1 = "v1"
|
||||
|
||||
// APIVersionV2 is the API version number for version 2.
|
||||
const APIVersionV2 = "v2"
|
||||
|
||||
// Chart is a helm package that contains metadata, a default config, zero or more
|
||||
// optionally parameterizable templates, and zero or more charts (dependencies).
|
||||
type Chart struct {
|
||||
// Raw contains the raw contents of the files originally contained in the chart archive.
|
||||
//
|
||||
// This should not be used except in special cases like `helm show values`,
|
||||
// where we want to display the raw values, comments and all.
|
||||
Raw []*File `json:"-"`
|
||||
// Metadata is the contents of the Chartfile.
|
||||
Metadata *Metadata `json:"metadata"`
|
||||
// Lock is the contents of Chart.lock.
|
||||
Lock *Lock `json:"lock"`
|
||||
// Templates for this chart.
|
||||
Templates []*File `json:"templates"`
|
||||
// Values are default config for this chart.
|
||||
Values map[string]interface{} `json:"values"`
|
||||
// Schema is an optional JSON schema for imposing structure on Values
|
||||
Schema []byte `json:"schema"`
|
||||
// Files are miscellaneous files in a chart archive,
|
||||
// e.g. README, LICENSE, etc.
|
||||
Files []*File `json:"files"`
|
||||
|
||||
parent *Chart
|
||||
dependencies []*Chart
|
||||
}
|
||||
|
||||
type CRD struct {
|
||||
// Name is the File.Name for the crd file
|
||||
Name string
|
||||
// Filename is the File obj Name including (sub-)chart.ChartFullPath
|
||||
Filename string
|
||||
// File is the File obj for the crd
|
||||
File *File
|
||||
}
|
||||
|
||||
// SetDependencies replaces the chart dependencies.
|
||||
func (ch *Chart) SetDependencies(charts ...*Chart) {
|
||||
ch.dependencies = nil
|
||||
ch.AddDependency(charts...)
|
||||
}
|
||||
|
||||
// Name returns the name of the chart.
|
||||
func (ch *Chart) Name() string {
|
||||
if ch.Metadata == nil {
|
||||
return ""
|
||||
}
|
||||
return ch.Metadata.Name
|
||||
}
|
||||
|
||||
// AddDependency determines if the chart is a subchart.
|
||||
func (ch *Chart) AddDependency(charts ...*Chart) {
|
||||
for i, x := range charts {
|
||||
charts[i].parent = ch
|
||||
ch.dependencies = append(ch.dependencies, x)
|
||||
}
|
||||
}
|
||||
|
||||
// Root finds the root chart.
|
||||
func (ch *Chart) Root() *Chart {
|
||||
if ch.IsRoot() {
|
||||
return ch
|
||||
}
|
||||
return ch.Parent().Root()
|
||||
}
|
||||
|
||||
// Dependencies are the charts that this chart depends on.
|
||||
func (ch *Chart) Dependencies() []*Chart { return ch.dependencies }
|
||||
|
||||
// IsRoot determines if the chart is the root chart.
|
||||
func (ch *Chart) IsRoot() bool { return ch.parent == nil }
|
||||
|
||||
// Parent returns a subchart's parent chart.
|
||||
func (ch *Chart) Parent() *Chart { return ch.parent }
|
||||
|
||||
// ChartPath returns the full path to this chart in dot notation.
|
||||
func (ch *Chart) ChartPath() string {
|
||||
if !ch.IsRoot() {
|
||||
return ch.Parent().ChartPath() + "." + ch.Name()
|
||||
}
|
||||
return ch.Name()
|
||||
}
|
||||
|
||||
// ChartFullPath returns the full path to this chart.
|
||||
func (ch *Chart) ChartFullPath() string {
|
||||
if !ch.IsRoot() {
|
||||
return ch.Parent().ChartFullPath() + "/charts/" + ch.Name()
|
||||
}
|
||||
return ch.Name()
|
||||
}
|
||||
|
||||
// Validate validates the metadata.
|
||||
func (ch *Chart) Validate() error {
|
||||
return ch.Metadata.Validate()
|
||||
}
|
||||
|
||||
// AppVersion returns the appversion of the chart.
|
||||
func (ch *Chart) AppVersion() string {
|
||||
if ch.Metadata == nil {
|
||||
return ""
|
||||
}
|
||||
return ch.Metadata.AppVersion
|
||||
}
|
||||
|
||||
// CRDs returns a list of File objects in the 'crds/' directory of a Helm chart.
|
||||
// Deprecated: use CRDObjects()
|
||||
func (ch *Chart) CRDs() []*File {
|
||||
files := []*File{}
|
||||
// Find all resources in the crds/ directory
|
||||
for _, f := range ch.Files {
|
||||
if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) {
|
||||
files = append(files, f)
|
||||
}
|
||||
}
|
||||
// Get CRDs from dependencies, too.
|
||||
for _, dep := range ch.Dependencies() {
|
||||
files = append(files, dep.CRDs()...)
|
||||
}
|
||||
return files
|
||||
}
|
||||
|
||||
// CRDObjects returns a list of CRD objects in the 'crds/' directory of a Helm chart & subcharts
|
||||
func (ch *Chart) CRDObjects() []CRD {
|
||||
crds := []CRD{}
|
||||
// Find all resources in the crds/ directory
|
||||
for _, f := range ch.Files {
|
||||
if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) {
|
||||
mycrd := CRD{Name: f.Name, Filename: filepath.Join(ch.ChartFullPath(), f.Name), File: f}
|
||||
crds = append(crds, mycrd)
|
||||
}
|
||||
}
|
||||
// Get CRDs from dependencies, too.
|
||||
for _, dep := range ch.Dependencies() {
|
||||
crds = append(crds, dep.CRDObjects()...)
|
||||
}
|
||||
return crds
|
||||
}
|
||||
|
||||
func hasManifestExtension(fname string) bool {
|
||||
ext := filepath.Ext(fname)
|
||||
return strings.EqualFold(ext, ".yaml") || strings.EqualFold(ext, ".yml") || strings.EqualFold(ext, ".json")
|
||||
}
|
||||
62
vendor/helm.sh/helm/v3/pkg/chart/dependency.go
vendored
Normal file
62
vendor/helm.sh/helm/v3/pkg/chart/dependency.go
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
import "time"
|
||||
|
||||
// Dependency describes a chart upon which another chart depends.
|
||||
//
|
||||
// Dependencies can be used to express developer intent, or to capture the state
|
||||
// of a chart.
|
||||
type Dependency struct {
|
||||
// Name is the name of the dependency.
|
||||
//
|
||||
// This must mach the name in the dependency's Chart.yaml.
|
||||
Name string `json:"name"`
|
||||
// Version is the version (range) of this chart.
|
||||
//
|
||||
// A lock file will always produce a single version, while a dependency
|
||||
// may contain a semantic version range.
|
||||
Version string `json:"version,omitempty"`
|
||||
// The URL to the repository.
|
||||
//
|
||||
// Appending `index.yaml` to this string should result in a URL that can be
|
||||
// used to fetch the repository index.
|
||||
Repository string `json:"repository"`
|
||||
// A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled )
|
||||
Condition string `json:"condition,omitempty"`
|
||||
// Tags can be used to group charts for enabling/disabling together
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
// Enabled bool determines if chart should be loaded
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
// ImportValues holds the mapping of source values to parent key to be imported. Each item can be a
|
||||
// string or pair of child/parent sublist items.
|
||||
ImportValues []interface{} `json:"import-values,omitempty"`
|
||||
// Alias usable alias to be used for the chart
|
||||
Alias string `json:"alias,omitempty"`
|
||||
}
|
||||
|
||||
// Lock is a lock file for dependencies.
|
||||
//
|
||||
// It represents the state that the dependencies should be in.
|
||||
type Lock struct {
|
||||
// Generated is the date the lock file was last generated.
|
||||
Generated time.Time `json:"generated"`
|
||||
// Digest is a hash of the dependencies in Chart.yaml.
|
||||
Digest string `json:"digest"`
|
||||
// Dependencies is the list of dependencies that this lock file has locked.
|
||||
Dependencies []*Dependency `json:"dependencies"`
|
||||
}
|
||||
23
vendor/helm.sh/helm/v3/pkg/chart/errors.go
vendored
Normal file
23
vendor/helm.sh/helm/v3/pkg/chart/errors.go
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
// ValidationError represents a data validation error.
|
||||
type ValidationError string
|
||||
|
||||
func (v ValidationError) Error() string {
|
||||
return "validation: " + string(v)
|
||||
}
|
||||
27
vendor/helm.sh/helm/v3/pkg/chart/file.go
vendored
Normal file
27
vendor/helm.sh/helm/v3/pkg/chart/file.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
// File represents a file as a name/value pair.
|
||||
//
|
||||
// By convention, name is a relative path within the scope of the chart's
|
||||
// base directory.
|
||||
type File struct {
|
||||
// Name is the path-like name of the template.
|
||||
Name string `json:"name"`
|
||||
// Data is the template as byte data.
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
196
vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go
vendored
Normal file
196
vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 loader
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`)
|
||||
|
||||
// FileLoader loads a chart from a file
|
||||
type FileLoader string
|
||||
|
||||
// Load loads a chart
|
||||
func (l FileLoader) Load() (*chart.Chart, error) {
|
||||
return LoadFile(string(l))
|
||||
}
|
||||
|
||||
// LoadFile loads from an archive file.
|
||||
func LoadFile(name string) (*chart.Chart, error) {
|
||||
if fi, err := os.Stat(name); err != nil {
|
||||
return nil, err
|
||||
} else if fi.IsDir() {
|
||||
return nil, errors.New("cannot load a directory")
|
||||
}
|
||||
|
||||
raw, err := os.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer raw.Close()
|
||||
|
||||
err = ensureArchive(name, raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := LoadArchive(raw)
|
||||
if err != nil {
|
||||
if err == gzip.ErrHeader {
|
||||
return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err)
|
||||
}
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
// ensureArchive's job is to return an informative error if the file does not appear to be a gzipped archive.
|
||||
//
|
||||
// Sometimes users will provide a values.yaml for an argument where a chart is expected. One common occurrence
|
||||
// of this is invoking `helm template values.yaml mychart` which would otherwise produce a confusing error
|
||||
// if we didn't check for this.
|
||||
func ensureArchive(name string, raw *os.File) error {
|
||||
defer raw.Seek(0, 0) // reset read offset to allow archive loading to proceed.
|
||||
|
||||
// Check the file format to give us a chance to provide the user with more actionable feedback.
|
||||
buffer := make([]byte, 512)
|
||||
_, err := raw.Read(buffer)
|
||||
if err != nil && err != io.EOF {
|
||||
return fmt.Errorf("file '%s' cannot be read: %s", name, err)
|
||||
}
|
||||
if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" {
|
||||
// TODO: Is there a way to reliably test if a file content is YAML? ghodss/yaml accepts a wide
|
||||
// variety of content (Makefile, .zshrc) as valid YAML without errors.
|
||||
|
||||
// Wrong content type. Let's check if it's yaml and give an extra hint?
|
||||
if strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") {
|
||||
return fmt.Errorf("file '%s' seems to be a YAML file, but expected a gzipped archive", name)
|
||||
}
|
||||
return fmt.Errorf("file '%s' does not appear to be a gzipped archive; got '%s'", name, contentType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadArchiveFiles reads in files out of an archive into memory. This function
|
||||
// performs important path security checks and should always be used before
|
||||
// expanding a tarball
|
||||
func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) {
|
||||
unzipped, err := gzip.NewReader(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer unzipped.Close()
|
||||
|
||||
files := []*BufferedFile{}
|
||||
tr := tar.NewReader(unzipped)
|
||||
for {
|
||||
b := bytes.NewBuffer(nil)
|
||||
hd, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if hd.FileInfo().IsDir() {
|
||||
// Use this instead of hd.Typeflag because we don't have to do any
|
||||
// inference chasing.
|
||||
continue
|
||||
}
|
||||
|
||||
switch hd.Typeflag {
|
||||
// We don't want to process these extension header files.
|
||||
case tar.TypeXGlobalHeader, tar.TypeXHeader:
|
||||
continue
|
||||
}
|
||||
|
||||
// Archive could contain \ if generated on Windows
|
||||
delimiter := "/"
|
||||
if strings.ContainsRune(hd.Name, '\\') {
|
||||
delimiter = "\\"
|
||||
}
|
||||
|
||||
parts := strings.Split(hd.Name, delimiter)
|
||||
n := strings.Join(parts[1:], delimiter)
|
||||
|
||||
// Normalize the path to the / delimiter
|
||||
n = strings.ReplaceAll(n, delimiter, "/")
|
||||
|
||||
if path.IsAbs(n) {
|
||||
return nil, errors.New("chart illegally contains absolute paths")
|
||||
}
|
||||
|
||||
n = path.Clean(n)
|
||||
if n == "." {
|
||||
// In this case, the original path was relative when it should have been absolute.
|
||||
return nil, errors.Errorf("chart illegally contains content outside the base directory: %q", hd.Name)
|
||||
}
|
||||
if strings.HasPrefix(n, "..") {
|
||||
return nil, errors.New("chart illegally references parent directory")
|
||||
}
|
||||
|
||||
// In some particularly arcane acts of path creativity, it is possible to intermix
|
||||
// UNIX and Windows style paths in such a way that you produce a result of the form
|
||||
// c:/foo even after all the built-in absolute path checks. So we explicitly check
|
||||
// for this condition.
|
||||
if drivePathPattern.MatchString(n) {
|
||||
return nil, errors.New("chart contains illegally named files")
|
||||
}
|
||||
|
||||
if parts[0] == "Chart.yaml" {
|
||||
return nil, errors.New("chart yaml not in base directory")
|
||||
}
|
||||
|
||||
if _, err := io.Copy(b, tr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := bytes.TrimPrefix(b.Bytes(), utf8bom)
|
||||
|
||||
files = append(files, &BufferedFile{Name: n, Data: data})
|
||||
b.Reset()
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return nil, errors.New("no files in chart archive")
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// LoadArchive loads from a reader containing a compressed tar archive.
|
||||
func LoadArchive(in io.Reader) (*chart.Chart, error) {
|
||||
files, err := LoadArchiveFiles(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return LoadFiles(files)
|
||||
}
|
||||
120
vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go
vendored
Normal file
120
vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/internal/ignore"
|
||||
"helm.sh/helm/v3/internal/sympath"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
var utf8bom = []byte{0xEF, 0xBB, 0xBF}
|
||||
|
||||
// DirLoader loads a chart from a directory
|
||||
type DirLoader string
|
||||
|
||||
// Load loads the chart
|
||||
func (l DirLoader) Load() (*chart.Chart, error) {
|
||||
return LoadDir(string(l))
|
||||
}
|
||||
|
||||
// LoadDir loads from a directory.
|
||||
//
|
||||
// This loads charts only from directories.
|
||||
func LoadDir(dir string) (*chart.Chart, error) {
|
||||
topdir, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Just used for errors.
|
||||
c := &chart.Chart{}
|
||||
|
||||
rules := ignore.Empty()
|
||||
ifile := filepath.Join(topdir, ignore.HelmIgnore)
|
||||
if _, err := os.Stat(ifile); err == nil {
|
||||
r, err := ignore.ParseFile(ifile)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
rules = r
|
||||
}
|
||||
rules.AddDefaults()
|
||||
|
||||
files := []*BufferedFile{}
|
||||
topdir += string(filepath.Separator)
|
||||
|
||||
walk := func(name string, fi os.FileInfo, err error) error {
|
||||
n := strings.TrimPrefix(name, topdir)
|
||||
if n == "" {
|
||||
// No need to process top level. Avoid bug with helmignore .* matching
|
||||
// empty names. See issue 1779.
|
||||
return nil
|
||||
}
|
||||
|
||||
// Normalize to / since it will also work on Windows
|
||||
n = filepath.ToSlash(n)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// Directory-based ignore rules should involve skipping the entire
|
||||
// contents of that directory.
|
||||
if rules.Ignore(n, fi) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If a .helmignore file matches, skip this file.
|
||||
if rules.Ignore(n, fi) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Irregular files include devices, sockets, and other uses of files that
|
||||
// are not regular files. In Go they have a file mode type bit set.
|
||||
// See https://golang.org/pkg/os/#FileMode for examples.
|
||||
if !fi.Mode().IsRegular() {
|
||||
return fmt.Errorf("cannot load irregular file %s as it has file mode type bits set", name)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(name)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error reading %s", n)
|
||||
}
|
||||
|
||||
data = bytes.TrimPrefix(data, utf8bom)
|
||||
|
||||
files = append(files, &BufferedFile{Name: n, Data: data})
|
||||
return nil
|
||||
}
|
||||
if err = sympath.Walk(topdir, walk); err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
return LoadFiles(files)
|
||||
}
|
||||
185
vendor/helm.sh/helm/v3/pkg/chart/loader/load.go
vendored
Normal file
185
vendor/helm.sh/helm/v3/pkg/chart/loader/load.go
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
)
|
||||
|
||||
// ChartLoader loads a chart.
|
||||
type ChartLoader interface {
|
||||
Load() (*chart.Chart, error)
|
||||
}
|
||||
|
||||
// Loader returns a new ChartLoader appropriate for the given chart name
|
||||
func Loader(name string) (ChartLoader, error) {
|
||||
fi, err := os.Stat(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fi.IsDir() {
|
||||
return DirLoader(name), nil
|
||||
}
|
||||
return FileLoader(name), nil
|
||||
|
||||
}
|
||||
|
||||
// Load takes a string name, tries to resolve it to a file or directory, and then loads it.
|
||||
//
|
||||
// This is the preferred way to load a chart. It will discover the chart encoding
|
||||
// and hand off to the appropriate chart reader.
|
||||
//
|
||||
// If a .helmignore file is present, the directory loader will skip loading any files
|
||||
// matching it. But .helmignore is not evaluated when reading out of an archive.
|
||||
func Load(name string) (*chart.Chart, error) {
|
||||
l, err := Loader(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return l.Load()
|
||||
}
|
||||
|
||||
// BufferedFile represents an archive file buffered for later processing.
|
||||
type BufferedFile struct {
|
||||
Name string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// LoadFiles loads from in-memory files.
|
||||
func LoadFiles(files []*BufferedFile) (*chart.Chart, error) {
|
||||
c := new(chart.Chart)
|
||||
subcharts := make(map[string][]*BufferedFile)
|
||||
|
||||
for _, f := range files {
|
||||
c.Raw = append(c.Raw, &chart.File{Name: f.Name, Data: f.Data})
|
||||
switch {
|
||||
case f.Name == "Chart.yaml":
|
||||
if c.Metadata == nil {
|
||||
c.Metadata = new(chart.Metadata)
|
||||
}
|
||||
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load Chart.yaml")
|
||||
}
|
||||
// NOTE(bacongobbler): while the chart specification says that APIVersion must be set,
|
||||
// Helm 2 accepted charts that did not provide an APIVersion in their chart metadata.
|
||||
// Because of that, if APIVersion is unset, we should assume we're loading a v1 chart.
|
||||
if c.Metadata.APIVersion == "" {
|
||||
c.Metadata.APIVersion = chart.APIVersionV1
|
||||
}
|
||||
case f.Name == "Chart.lock":
|
||||
c.Lock = new(chart.Lock)
|
||||
if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load Chart.lock")
|
||||
}
|
||||
case f.Name == "values.yaml":
|
||||
c.Values = make(map[string]interface{})
|
||||
if err := yaml.Unmarshal(f.Data, &c.Values); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load values.yaml")
|
||||
}
|
||||
case f.Name == "values.schema.json":
|
||||
c.Schema = f.Data
|
||||
|
||||
// Deprecated: requirements.yaml is deprecated use Chart.yaml.
|
||||
// We will handle it for you because we are nice people
|
||||
case f.Name == "requirements.yaml":
|
||||
if c.Metadata == nil {
|
||||
c.Metadata = new(chart.Metadata)
|
||||
}
|
||||
if c.Metadata.APIVersion != chart.APIVersionV1 {
|
||||
log.Printf("Warning: Dependencies are handled in Chart.yaml since apiVersion \"v2\". We recommend migrating dependencies to Chart.yaml.")
|
||||
}
|
||||
if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load requirements.yaml")
|
||||
}
|
||||
if c.Metadata.APIVersion == chart.APIVersionV1 {
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
}
|
||||
// Deprecated: requirements.lock is deprecated use Chart.lock.
|
||||
case f.Name == "requirements.lock":
|
||||
c.Lock = new(chart.Lock)
|
||||
if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil {
|
||||
return c, errors.Wrap(err, "cannot load requirements.lock")
|
||||
}
|
||||
if c.Metadata.APIVersion == chart.APIVersionV1 {
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
}
|
||||
|
||||
case strings.HasPrefix(f.Name, "templates/"):
|
||||
c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data})
|
||||
case strings.HasPrefix(f.Name, "charts/"):
|
||||
if filepath.Ext(f.Name) == ".prov" {
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
continue
|
||||
}
|
||||
|
||||
fname := strings.TrimPrefix(f.Name, "charts/")
|
||||
cname := strings.SplitN(fname, "/", 2)[0]
|
||||
subcharts[cname] = append(subcharts[cname], &BufferedFile{Name: fname, Data: f.Data})
|
||||
default:
|
||||
c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data})
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.Validate(); err != nil {
|
||||
return c, err
|
||||
}
|
||||
|
||||
for n, files := range subcharts {
|
||||
var sc *chart.Chart
|
||||
var err error
|
||||
switch {
|
||||
case strings.IndexAny(n, "_.") == 0:
|
||||
continue
|
||||
case filepath.Ext(n) == ".tgz":
|
||||
file := files[0]
|
||||
if file.Name != n {
|
||||
return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name)
|
||||
}
|
||||
// Untar the chart and add to c.Dependencies
|
||||
sc, err = LoadArchive(bytes.NewBuffer(file.Data))
|
||||
default:
|
||||
// We have to trim the prefix off of every file, and ignore any file
|
||||
// that is in charts/, but isn't actually a chart.
|
||||
buff := make([]*BufferedFile, 0, len(files))
|
||||
for _, f := range files {
|
||||
parts := strings.SplitN(f.Name, "/", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
f.Name = parts[1]
|
||||
buff = append(buff, f)
|
||||
}
|
||||
sc, err = LoadFiles(buff)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name())
|
||||
}
|
||||
c.AddDependency(sc)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
94
vendor/helm.sh/helm/v3/pkg/chart/metadata.go
vendored
Normal file
94
vendor/helm.sh/helm/v3/pkg/chart/metadata.go
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 chart
|
||||
|
||||
// Maintainer describes a Chart maintainer.
|
||||
type Maintainer struct {
|
||||
// Name is a user name or organization name
|
||||
Name string `json:"name,omitempty"`
|
||||
// Email is an optional email address to contact the named maintainer
|
||||
Email string `json:"email,omitempty"`
|
||||
// URL is an optional URL to an address for the named maintainer
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// Metadata for a Chart file. This models the structure of a Chart.yaml file.
|
||||
type Metadata struct {
|
||||
// The name of the chart
|
||||
Name string `json:"name,omitempty"`
|
||||
// The URL to a relevant project page, git repo, or contact person
|
||||
Home string `json:"home,omitempty"`
|
||||
// Source is the URL to the source code of this chart
|
||||
Sources []string `json:"sources,omitempty"`
|
||||
// A SemVer 2 conformant version string of the chart
|
||||
Version string `json:"version,omitempty"`
|
||||
// A one-sentence description of the chart
|
||||
Description string `json:"description,omitempty"`
|
||||
// A list of string keywords
|
||||
Keywords []string `json:"keywords,omitempty"`
|
||||
// A list of name and URL/email address combinations for the maintainer(s)
|
||||
Maintainers []*Maintainer `json:"maintainers,omitempty"`
|
||||
// The URL to an icon file.
|
||||
Icon string `json:"icon,omitempty"`
|
||||
// The API Version of this chart.
|
||||
APIVersion string `json:"apiVersion,omitempty"`
|
||||
// The condition to check to enable chart
|
||||
Condition string `json:"condition,omitempty"`
|
||||
// The tags to check to enable chart
|
||||
Tags string `json:"tags,omitempty"`
|
||||
// The version of the application enclosed inside of this chart.
|
||||
AppVersion string `json:"appVersion,omitempty"`
|
||||
// Whether or not this chart is deprecated
|
||||
Deprecated bool `json:"deprecated,omitempty"`
|
||||
// Annotations are additional mappings uninterpreted by Helm,
|
||||
// made available for inspection by other applications.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
// KubeVersion is a SemVer constraint specifying the version of Kubernetes required.
|
||||
KubeVersion string `json:"kubeVersion,omitempty"`
|
||||
// Dependencies are a list of dependencies for a chart.
|
||||
Dependencies []*Dependency `json:"dependencies,omitempty"`
|
||||
// Specifies the chart type: application or library
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the metadata for known issues, returning an error if metadata is not correct
|
||||
func (md *Metadata) Validate() error {
|
||||
if md == nil {
|
||||
return ValidationError("chart.metadata is required")
|
||||
}
|
||||
if md.APIVersion == "" {
|
||||
return ValidationError("chart.metadata.apiVersion is required")
|
||||
}
|
||||
if md.Name == "" {
|
||||
return ValidationError("chart.metadata.name is required")
|
||||
}
|
||||
if md.Version == "" {
|
||||
return ValidationError("chart.metadata.version is required")
|
||||
}
|
||||
if !isValidChartType(md.Type) {
|
||||
return ValidationError("chart.metadata.type must be application or library")
|
||||
}
|
||||
// TODO validate valid semver here?
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidChartType(in string) bool {
|
||||
switch in {
|
||||
case "", "application", "library":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
140
vendor/helm.sh/helm/v3/pkg/cli/environment.go
vendored
Normal file
140
vendor/helm.sh/helm/v3/pkg/cli/environment.go
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 cli describes the operating environment for the Helm CLI.
|
||||
|
||||
Helm's environment encapsulates all of the service dependencies Helm has.
|
||||
These dependencies are expressed as interfaces so that alternate implementations
|
||||
(mocks, etc.) can be easily generated.
|
||||
*/
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
|
||||
"helm.sh/helm/v3/pkg/helmpath"
|
||||
)
|
||||
|
||||
// EnvSettings describes all of the environment settings.
|
||||
type EnvSettings struct {
|
||||
namespace string
|
||||
config *genericclioptions.ConfigFlags
|
||||
|
||||
// KubeConfig is the path to the kubeconfig file
|
||||
KubeConfig string
|
||||
// KubeContext is the name of the kubeconfig context.
|
||||
KubeContext string
|
||||
// Bearer KubeToken used for authentication
|
||||
KubeToken string
|
||||
// Kubernetes API Server Endpoint for authentication
|
||||
KubeAPIServer string
|
||||
// Debug indicates whether or not Helm is running in Debug mode.
|
||||
Debug bool
|
||||
// RegistryConfig is the path to the registry config file.
|
||||
RegistryConfig string
|
||||
// RepositoryConfig is the path to the repositories file.
|
||||
RepositoryConfig string
|
||||
// RepositoryCache is the path to the repository cache directory.
|
||||
RepositoryCache string
|
||||
// PluginsDirectory is the path to the plugins directory.
|
||||
PluginsDirectory string
|
||||
}
|
||||
|
||||
func New() *EnvSettings {
|
||||
env := &EnvSettings{
|
||||
namespace: os.Getenv("HELM_NAMESPACE"),
|
||||
KubeContext: os.Getenv("HELM_KUBECONTEXT"),
|
||||
KubeToken: os.Getenv("HELM_KUBETOKEN"),
|
||||
KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"),
|
||||
PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")),
|
||||
RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry.json")),
|
||||
RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")),
|
||||
RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")),
|
||||
}
|
||||
env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG"))
|
||||
|
||||
// bind to kubernetes config flags
|
||||
env.config = &genericclioptions.ConfigFlags{
|
||||
Namespace: &env.namespace,
|
||||
Context: &env.KubeContext,
|
||||
BearerToken: &env.KubeToken,
|
||||
APIServer: &env.KubeAPIServer,
|
||||
KubeConfig: &env.KubeConfig,
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
// AddFlags binds flags to the given flagset.
|
||||
func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVarP(&s.namespace, "namespace", "n", s.namespace, "namespace scope for this request")
|
||||
fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to the kubeconfig file")
|
||||
fs.StringVar(&s.KubeContext, "kube-context", s.KubeContext, "name of the kubeconfig context to use")
|
||||
fs.StringVar(&s.KubeToken, "kube-token", s.KubeToken, "bearer token used for authentication")
|
||||
fs.StringVar(&s.KubeAPIServer, "kube-apiserver", s.KubeAPIServer, "the address and the port for the Kubernetes API server")
|
||||
fs.BoolVar(&s.Debug, "debug", s.Debug, "enable verbose output")
|
||||
fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file")
|
||||
fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs")
|
||||
fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the file containing cached repository indexes")
|
||||
}
|
||||
|
||||
func envOr(name, def string) string {
|
||||
if v, ok := os.LookupEnv(name); ok {
|
||||
return v
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func (s *EnvSettings) EnvVars() map[string]string {
|
||||
envvars := map[string]string{
|
||||
"HELM_BIN": os.Args[0],
|
||||
"HELM_CACHE_HOME": helmpath.CachePath(""),
|
||||
"HELM_CONFIG_HOME": helmpath.ConfigPath(""),
|
||||
"HELM_DATA_HOME": helmpath.DataPath(""),
|
||||
"HELM_DEBUG": fmt.Sprint(s.Debug),
|
||||
"HELM_PLUGINS": s.PluginsDirectory,
|
||||
"HELM_REGISTRY_CONFIG": s.RegistryConfig,
|
||||
"HELM_REPOSITORY_CACHE": s.RepositoryCache,
|
||||
"HELM_REPOSITORY_CONFIG": s.RepositoryConfig,
|
||||
"HELM_NAMESPACE": s.Namespace(),
|
||||
|
||||
// broken, these are populated from helm flags and not kubeconfig.
|
||||
"HELM_KUBECONTEXT": s.KubeContext,
|
||||
"HELM_KUBETOKEN": s.KubeToken,
|
||||
"HELM_KUBEAPISERVER": s.KubeAPIServer,
|
||||
}
|
||||
if s.KubeConfig != "" {
|
||||
envvars["KUBECONFIG"] = s.KubeConfig
|
||||
}
|
||||
return envvars
|
||||
}
|
||||
|
||||
// Namespace gets the namespace from the configuration
|
||||
func (s *EnvSettings) Namespace() string {
|
||||
if ns, _, err := s.config.ToRawKubeConfigLoader().Namespace(); err == nil {
|
||||
return ns
|
||||
}
|
||||
return "default"
|
||||
}
|
||||
|
||||
// RESTClientGetter gets the kubeconfig from EnvSettings
|
||||
func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter {
|
||||
return s.config
|
||||
}
|
||||
21
vendor/helm.sh/helm/v3/pkg/getter/doc.go
vendored
Normal file
21
vendor/helm.sh/helm/v3/pkg/getter/doc.go
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 getter provides a generalize tool for fetching data by scheme.
|
||||
|
||||
This provides a method by which the plugin system can load arbitrary protocol
|
||||
handlers based upon a URL scheme.
|
||||
*/
|
||||
package getter
|
||||
150
vendor/helm.sh/helm/v3/pkg/getter/getter.go
vendored
Normal file
150
vendor/helm.sh/helm/v3/pkg/getter/getter.go
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
)
|
||||
|
||||
// options are generic parameters to be provided to the getter during instantiation.
|
||||
//
|
||||
// Getters may or may not ignore these parameters as they are passed in.
|
||||
type options struct {
|
||||
url string
|
||||
certFile string
|
||||
keyFile string
|
||||
caFile string
|
||||
insecureSkipVerifyTLS bool
|
||||
username string
|
||||
password string
|
||||
userAgent string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// Option allows specifying various settings configurable by the user for overriding the defaults
|
||||
// used when performing Get operations with the Getter.
|
||||
type Option func(*options)
|
||||
|
||||
// WithURL informs the getter the server name that will be used when fetching objects. Used in conjunction with
|
||||
// WithTLSClientConfig to set the TLSClientConfig's server name.
|
||||
func WithURL(url string) Option {
|
||||
return func(opts *options) {
|
||||
opts.url = url
|
||||
}
|
||||
}
|
||||
|
||||
// WithBasicAuth sets the request's Authorization header to use the provided credentials
|
||||
func WithBasicAuth(username, password string) Option {
|
||||
return func(opts *options) {
|
||||
opts.username = username
|
||||
opts.password = password
|
||||
}
|
||||
}
|
||||
|
||||
// WithUserAgent sets the request's User-Agent header to use the provided agent name.
|
||||
func WithUserAgent(userAgent string) Option {
|
||||
return func(opts *options) {
|
||||
opts.userAgent = userAgent
|
||||
}
|
||||
}
|
||||
|
||||
// WithInsecureSkipVerifyTLS determines if a TLS Certificate will be checked
|
||||
func WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS bool) Option {
|
||||
return func(opts *options) {
|
||||
opts.insecureSkipVerifyTLS = insecureSkipVerifyTLS
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSClientConfig sets the client auth with the provided credentials.
|
||||
func WithTLSClientConfig(certFile, keyFile, caFile string) Option {
|
||||
return func(opts *options) {
|
||||
opts.certFile = certFile
|
||||
opts.keyFile = keyFile
|
||||
opts.caFile = caFile
|
||||
}
|
||||
}
|
||||
|
||||
// WithTimeout sets the timeout for requests
|
||||
func WithTimeout(timeout time.Duration) Option {
|
||||
return func(opts *options) {
|
||||
opts.timeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// Getter is an interface to support GET to the specified URL.
|
||||
type Getter interface {
|
||||
// Get file content by url string
|
||||
Get(url string, options ...Option) (*bytes.Buffer, error)
|
||||
}
|
||||
|
||||
// Constructor is the function for every getter which creates a specific instance
|
||||
// according to the configuration
|
||||
type Constructor func(options ...Option) (Getter, error)
|
||||
|
||||
// Provider represents any getter and the schemes that it supports.
|
||||
//
|
||||
// For example, an HTTP provider may provide one getter that handles both
|
||||
// 'http' and 'https' schemes.
|
||||
type Provider struct {
|
||||
Schemes []string
|
||||
New Constructor
|
||||
}
|
||||
|
||||
// Provides returns true if the given scheme is supported by this Provider.
|
||||
func (p Provider) Provides(scheme string) bool {
|
||||
for _, i := range p.Schemes {
|
||||
if i == scheme {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Providers is a collection of Provider objects.
|
||||
type Providers []Provider
|
||||
|
||||
// ByScheme returns a Provider that handles the given scheme.
|
||||
//
|
||||
// If no provider handles this scheme, this will return an error.
|
||||
func (p Providers) ByScheme(scheme string) (Getter, error) {
|
||||
for _, pp := range p {
|
||||
if pp.Provides(scheme) {
|
||||
return pp.New()
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("scheme %q not supported", scheme)
|
||||
}
|
||||
|
||||
var httpProvider = Provider{
|
||||
Schemes: []string{"http", "https"},
|
||||
New: NewHTTPGetter,
|
||||
}
|
||||
|
||||
// All finds all of the registered getters as a list of Provider instances.
|
||||
// Currently, the built-in getters and the discovered plugins with downloader
|
||||
// notations are collected.
|
||||
func All(settings *cli.EnvSettings) Providers {
|
||||
result := Providers{httpProvider}
|
||||
pluginDownloaders, _ := collectPlugins(settings)
|
||||
result = append(result, pluginDownloaders...)
|
||||
return result
|
||||
}
|
||||
126
vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go
vendored
Normal file
126
vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/internal/tlsutil"
|
||||
"helm.sh/helm/v3/internal/urlutil"
|
||||
"helm.sh/helm/v3/internal/version"
|
||||
)
|
||||
|
||||
// HTTPGetter is the default HTTP(/S) backend handler
|
||||
type HTTPGetter struct {
|
||||
opts options
|
||||
}
|
||||
|
||||
//Get performs a Get from repo.Getter and returns the body.
|
||||
func (g *HTTPGetter) Get(href string, options ...Option) (*bytes.Buffer, error) {
|
||||
for _, opt := range options {
|
||||
opt(&g.opts)
|
||||
}
|
||||
return g.get(href)
|
||||
}
|
||||
|
||||
func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
// Set a helm specific user agent so that a repo server and metrics can
|
||||
// separate helm calls from other tools interacting with repos.
|
||||
req, err := http.NewRequest("GET", href, nil)
|
||||
if err != nil {
|
||||
return buf, err
|
||||
}
|
||||
|
||||
req.Header.Set("User-Agent", version.GetUserAgent())
|
||||
if g.opts.userAgent != "" {
|
||||
req.Header.Set("User-Agent", g.opts.userAgent)
|
||||
}
|
||||
|
||||
if g.opts.username != "" && g.opts.password != "" {
|
||||
req.SetBasicAuth(g.opts.username, g.opts.password)
|
||||
}
|
||||
|
||||
client, err := g.httpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return buf, err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return buf, errors.Errorf("failed to fetch %s : %s", href, resp.Status)
|
||||
}
|
||||
|
||||
_, err = io.Copy(buf, resp.Body)
|
||||
resp.Body.Close()
|
||||
return buf, err
|
||||
}
|
||||
|
||||
// NewHTTPGetter constructs a valid http/https client as a Getter
|
||||
func NewHTTPGetter(options ...Option) (Getter, error) {
|
||||
var client HTTPGetter
|
||||
|
||||
for _, opt := range options {
|
||||
opt(&client.opts)
|
||||
}
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
|
||||
func (g *HTTPGetter) httpClient() (*http.Client, error) {
|
||||
transport := &http.Transport{
|
||||
DisableCompression: true,
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
}
|
||||
if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" {
|
||||
tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "can't create TLS config for client")
|
||||
}
|
||||
tlsConf.BuildNameToCertificate()
|
||||
|
||||
sni, err := urlutil.ExtractHostname(g.opts.url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConf.ServerName = sni
|
||||
|
||||
transport.TLSClientConfig = tlsConf
|
||||
}
|
||||
|
||||
if g.opts.insecureSkipVerifyTLS {
|
||||
transport.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: transport,
|
||||
Timeout: g.opts.timeout,
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
102
vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go
vendored
Normal file
102
vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 getter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/plugin"
|
||||
)
|
||||
|
||||
// collectPlugins scans for getter plugins.
|
||||
// This will load plugins according to the cli.
|
||||
func collectPlugins(settings *cli.EnvSettings) (Providers, error) {
|
||||
plugins, err := plugin.FindPlugins(settings.PluginsDirectory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result Providers
|
||||
for _, plugin := range plugins {
|
||||
for _, downloader := range plugin.Metadata.Downloaders {
|
||||
result = append(result, Provider{
|
||||
Schemes: downloader.Protocols,
|
||||
New: NewPluginGetter(
|
||||
downloader.Command,
|
||||
settings,
|
||||
plugin.Metadata.Name,
|
||||
plugin.Dir,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// pluginGetter is a generic type to invoke custom downloaders,
|
||||
// implemented in plugins.
|
||||
type pluginGetter struct {
|
||||
command string
|
||||
settings *cli.EnvSettings
|
||||
name string
|
||||
base string
|
||||
opts options
|
||||
}
|
||||
|
||||
// Get runs downloader plugin command
|
||||
func (p *pluginGetter) Get(href string, options ...Option) (*bytes.Buffer, error) {
|
||||
for _, opt := range options {
|
||||
opt(&p.opts)
|
||||
}
|
||||
commands := strings.Split(p.command, " ")
|
||||
argv := append(commands[1:], p.opts.certFile, p.opts.keyFile, p.opts.caFile, href)
|
||||
prog := exec.Command(filepath.Join(p.base, commands[0]), argv...)
|
||||
plugin.SetupPluginEnv(p.settings, p.name, p.base)
|
||||
prog.Env = os.Environ()
|
||||
buf := bytes.NewBuffer(nil)
|
||||
prog.Stdout = buf
|
||||
prog.Stderr = os.Stderr
|
||||
if err := prog.Run(); err != nil {
|
||||
if eerr, ok := err.(*exec.ExitError); ok {
|
||||
os.Stderr.Write(eerr.Stderr)
|
||||
return nil, errors.Errorf("plugin %q exited with error", p.command)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// NewPluginGetter constructs a valid plugin getter
|
||||
func NewPluginGetter(command string, settings *cli.EnvSettings, name, base string) Constructor {
|
||||
return func(options ...Option) (Getter, error) {
|
||||
result := &pluginGetter{
|
||||
command: command,
|
||||
settings: settings,
|
||||
name: name,
|
||||
base: base,
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(&result.opts)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
44
vendor/helm.sh/helm/v3/pkg/helmpath/home.go
vendored
Normal file
44
vendor/helm.sh/helm/v3/pkg/helmpath/home.go
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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 helmpath calculates filesystem paths to Helm's configuration, cache and data.
|
||||
package helmpath
|
||||
|
||||
// This helper builds paths to Helm's configuration, cache and data paths.
|
||||
const lp = lazypath("helm")
|
||||
|
||||
// ConfigPath returns the path where Helm stores configuration.
|
||||
func ConfigPath(elem ...string) string { return lp.configPath(elem...) }
|
||||
|
||||
// CachePath returns the path where Helm stores cached objects.
|
||||
func CachePath(elem ...string) string { return lp.cachePath(elem...) }
|
||||
|
||||
// DataPath returns the path where Helm stores data.
|
||||
func DataPath(elem ...string) string { return lp.dataPath(elem...) }
|
||||
|
||||
// CacheIndexFile returns the path to an index for the given named repository.
|
||||
func CacheIndexFile(name string) string {
|
||||
if name != "" {
|
||||
name += "-"
|
||||
}
|
||||
return name + "index.yaml"
|
||||
}
|
||||
|
||||
// CacheChartsFile returns the path to a text file listing all the charts
|
||||
// within the given named repository.
|
||||
func CacheChartsFile(name string) string {
|
||||
if name != "" {
|
||||
name += "-"
|
||||
}
|
||||
return name + "charts.txt"
|
||||
}
|
||||
72
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go
vendored
Normal file
72
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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 helmpath
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"helm.sh/helm/v3/pkg/helmpath/xdg"
|
||||
)
|
||||
|
||||
const (
|
||||
// CacheHomeEnvVar is the environment variable used by Helm
|
||||
// for the cache directory. When no value is set a default is used.
|
||||
CacheHomeEnvVar = "HELM_CACHE_HOME"
|
||||
|
||||
// ConfigHomeEnvVar is the environment variable used by Helm
|
||||
// for the config directory. When no value is set a default is used.
|
||||
ConfigHomeEnvVar = "HELM_CONFIG_HOME"
|
||||
|
||||
// DataHomeEnvVar is the environment variable used by Helm
|
||||
// for the data directory. When no value is set a default is used.
|
||||
DataHomeEnvVar = "HELM_DATA_HOME"
|
||||
)
|
||||
|
||||
// lazypath is an lazy-loaded path buffer for the XDG base directory specification.
|
||||
type lazypath string
|
||||
|
||||
func (l lazypath) path(helmEnvVar, xdgEnvVar string, defaultFn func() string, elem ...string) string {
|
||||
|
||||
// There is an order to checking for a path.
|
||||
// 1. See if a Helm specific environment variable has been set.
|
||||
// 2. Check if an XDG environment variable is set
|
||||
// 3. Fall back to a default
|
||||
base := os.Getenv(helmEnvVar)
|
||||
if base != "" {
|
||||
return filepath.Join(base, filepath.Join(elem...))
|
||||
}
|
||||
base = os.Getenv(xdgEnvVar)
|
||||
if base == "" {
|
||||
base = defaultFn()
|
||||
}
|
||||
return filepath.Join(base, string(l), filepath.Join(elem...))
|
||||
}
|
||||
|
||||
// cachePath defines the base directory relative to which user specific non-essential data files
|
||||
// should be stored.
|
||||
func (l lazypath) cachePath(elem ...string) string {
|
||||
return l.path(CacheHomeEnvVar, xdg.CacheHomeEnvVar, cacheHome, filepath.Join(elem...))
|
||||
}
|
||||
|
||||
// configPath defines the base directory relative to which user specific configuration files should
|
||||
// be stored.
|
||||
func (l lazypath) configPath(elem ...string) string {
|
||||
return l.path(ConfigHomeEnvVar, xdg.ConfigHomeEnvVar, configHome, filepath.Join(elem...))
|
||||
}
|
||||
|
||||
// dataPath defines the base directory relative to which user specific data files should be stored.
|
||||
func (l lazypath) dataPath(elem ...string) string {
|
||||
return l.path(DataHomeEnvVar, xdg.DataHomeEnvVar, dataHome, filepath.Join(elem...))
|
||||
}
|
||||
34
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go
vendored
Normal file
34
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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.
|
||||
|
||||
// +build darwin
|
||||
|
||||
package helmpath
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
func dataHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), "Library")
|
||||
}
|
||||
|
||||
func configHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), "Library", "Preferences")
|
||||
}
|
||||
|
||||
func cacheHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), "Library", "Caches")
|
||||
}
|
||||
45
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go
vendored
Normal file
45
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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.
|
||||
|
||||
// +build !windows,!darwin
|
||||
|
||||
package helmpath
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/client-go/util/homedir"
|
||||
)
|
||||
|
||||
// dataHome defines the base directory relative to which user specific data files should be stored.
|
||||
//
|
||||
// If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share is used.
|
||||
func dataHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), ".local", "share")
|
||||
}
|
||||
|
||||
// configHome defines the base directory relative to which user specific configuration files should
|
||||
// be stored.
|
||||
//
|
||||
// If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config is used.
|
||||
func configHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), ".config")
|
||||
}
|
||||
|
||||
// cacheHome defines the base directory relative to which user specific non-essential data files
|
||||
// should be stored.
|
||||
//
|
||||
// If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache is used.
|
||||
func cacheHome() string {
|
||||
return filepath.Join(homedir.HomeDir(), ".cache")
|
||||
}
|
||||
24
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go
vendored
Normal file
24
vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright The Helm Authors.
|
||||
// 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.
|
||||
|
||||
// +build windows
|
||||
|
||||
package helmpath
|
||||
|
||||
import "os"
|
||||
|
||||
func dataHome() string { return configHome() }
|
||||
|
||||
func configHome() string { return os.Getenv("APPDATA") }
|
||||
|
||||
func cacheHome() string { return os.Getenv("TEMP") }
|
||||
34
vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go
vendored
Normal file
34
vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 xdg holds constants pertaining to XDG Base Directory Specification.
|
||||
//
|
||||
// The XDG Base Directory Specification https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
// specifies the environment variables that define user-specific base directories for various categories of files.
|
||||
package xdg
|
||||
|
||||
const (
|
||||
// CacheHomeEnvVar is the environment variable used by the
|
||||
// XDG base directory specification for the cache directory.
|
||||
CacheHomeEnvVar = "XDG_CACHE_HOME"
|
||||
|
||||
// ConfigHomeEnvVar is the environment variable used by the
|
||||
// XDG base directory specification for the config directory.
|
||||
ConfigHomeEnvVar = "XDG_CONFIG_HOME"
|
||||
|
||||
// DataHomeEnvVar is the environment variable used by the
|
||||
// XDG base directory specification for the data directory.
|
||||
DataHomeEnvVar = "XDG_DATA_HOME"
|
||||
)
|
||||
29
vendor/helm.sh/helm/v3/pkg/plugin/hooks.go
vendored
Normal file
29
vendor/helm.sh/helm/v3/pkg/plugin/hooks.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 plugin // import "helm.sh/helm/v3/pkg/plugin"
|
||||
|
||||
// Types of hooks
|
||||
const (
|
||||
// Install is executed after the plugin is added.
|
||||
Install = "install"
|
||||
// Delete is executed after the plugin is removed.
|
||||
Delete = "delete"
|
||||
// Update is executed after the plugin is updated.
|
||||
Update = "update"
|
||||
)
|
||||
|
||||
// Hooks is a map of events to commands.
|
||||
type Hooks map[string]string
|
||||
225
vendor/helm.sh/helm/v3/pkg/plugin/plugin.go
vendored
Normal file
225
vendor/helm.sh/helm/v3/pkg/plugin/plugin.go
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 plugin // import "helm.sh/helm/v3/pkg/plugin"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
)
|
||||
|
||||
const PluginFileName = "plugin.yaml"
|
||||
|
||||
// Downloaders represents the plugins capability if it can retrieve
|
||||
// charts from special sources
|
||||
type Downloaders struct {
|
||||
// Protocols are the list of schemes from the charts URL.
|
||||
Protocols []string `json:"protocols"`
|
||||
// Command is the executable path with which the plugin performs
|
||||
// the actual download for the corresponding Protocols
|
||||
Command string `json:"command"`
|
||||
}
|
||||
|
||||
// PlatformCommand represents a command for a particular operating system and architecture
|
||||
type PlatformCommand struct {
|
||||
OperatingSystem string `json:"os"`
|
||||
Architecture string `json:"arch"`
|
||||
Command string `json:"command"`
|
||||
}
|
||||
|
||||
// Metadata describes a plugin.
|
||||
//
|
||||
// This is the plugin equivalent of a chart.Metadata.
|
||||
type Metadata struct {
|
||||
// Name is the name of the plugin
|
||||
Name string `json:"name"`
|
||||
|
||||
// Version is a SemVer 2 version of the plugin.
|
||||
Version string `json:"version"`
|
||||
|
||||
// Usage is the single-line usage text shown in help
|
||||
Usage string `json:"usage"`
|
||||
|
||||
// Description is a long description shown in places like `helm help`
|
||||
Description string `json:"description"`
|
||||
|
||||
// Command is the command, as a single string.
|
||||
//
|
||||
// The command will be passed through environment expansion, so env vars can
|
||||
// be present in this command. Unless IgnoreFlags is set, this will
|
||||
// also merge the flags passed from Helm.
|
||||
//
|
||||
// Note that command is not executed in a shell. To do so, we suggest
|
||||
// pointing the command to a shell script.
|
||||
//
|
||||
// The following rules will apply to processing commands:
|
||||
// - If platformCommand is present, it will be searched first
|
||||
// - If both OS and Arch match the current platform, search will stop and the command will be executed
|
||||
// - If OS matches and there is no more specific match, the command will be executed
|
||||
// - If no OS/Arch match is found, the default command will be executed
|
||||
// - If no command is present and no matches are found in platformCommand, Helm will exit with an error
|
||||
PlatformCommand []PlatformCommand `json:"platformCommand"`
|
||||
Command string `json:"command"`
|
||||
|
||||
// IgnoreFlags ignores any flags passed in from Helm
|
||||
//
|
||||
// For example, if the plugin is invoked as `helm --debug myplugin`, if this
|
||||
// is false, `--debug` will be appended to `--command`. If this is true,
|
||||
// the `--debug` flag will be discarded.
|
||||
IgnoreFlags bool `json:"ignoreFlags"`
|
||||
|
||||
// Hooks are commands that will run on events.
|
||||
Hooks Hooks
|
||||
|
||||
// Downloaders field is used if the plugin supply downloader mechanism
|
||||
// for special protocols.
|
||||
Downloaders []Downloaders `json:"downloaders"`
|
||||
}
|
||||
|
||||
// Plugin represents a plugin.
|
||||
type Plugin struct {
|
||||
// Metadata is a parsed representation of a plugin.yaml
|
||||
Metadata *Metadata
|
||||
// Dir is the string path to the directory that holds the plugin.
|
||||
Dir string
|
||||
}
|
||||
|
||||
// The following rules will apply to processing the Plugin.PlatformCommand.Command:
|
||||
// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution
|
||||
// - If OS matches and there is no more specific match, the command will be prepared for execution
|
||||
// - If no OS/Arch match is found, return nil
|
||||
func getPlatformCommand(cmds []PlatformCommand) []string {
|
||||
var command []string
|
||||
eq := strings.EqualFold
|
||||
for _, c := range cmds {
|
||||
if eq(c.OperatingSystem, runtime.GOOS) {
|
||||
command = strings.Split(os.ExpandEnv(c.Command), " ")
|
||||
}
|
||||
if eq(c.OperatingSystem, runtime.GOOS) && eq(c.Architecture, runtime.GOARCH) {
|
||||
return strings.Split(os.ExpandEnv(c.Command), " ")
|
||||
}
|
||||
}
|
||||
return command
|
||||
}
|
||||
|
||||
// PrepareCommand takes a Plugin.PlatformCommand.Command, a Plugin.Command and will applying the following processing:
|
||||
// - If platformCommand is present, it will be searched first
|
||||
// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution
|
||||
// - If OS matches and there is no more specific match, the command will be prepared for execution
|
||||
// - If no OS/Arch match is found, the default command will be prepared for execution
|
||||
// - If no command is present and no matches are found in platformCommand, will exit with an error
|
||||
//
|
||||
// It merges extraArgs into any arguments supplied in the plugin. It
|
||||
// returns the name of the command and an args array.
|
||||
//
|
||||
// The result is suitable to pass to exec.Command.
|
||||
func (p *Plugin) PrepareCommand(extraArgs []string) (string, []string, error) {
|
||||
var parts []string
|
||||
platCmdLen := len(p.Metadata.PlatformCommand)
|
||||
if platCmdLen > 0 {
|
||||
parts = getPlatformCommand(p.Metadata.PlatformCommand)
|
||||
}
|
||||
if platCmdLen == 0 || parts == nil {
|
||||
parts = strings.Split(os.ExpandEnv(p.Metadata.Command), " ")
|
||||
}
|
||||
if len(parts) == 0 || parts[0] == "" {
|
||||
return "", nil, fmt.Errorf("No plugin command is applicable")
|
||||
}
|
||||
|
||||
main := parts[0]
|
||||
baseArgs := []string{}
|
||||
if len(parts) > 1 {
|
||||
baseArgs = parts[1:]
|
||||
}
|
||||
if !p.Metadata.IgnoreFlags {
|
||||
baseArgs = append(baseArgs, extraArgs...)
|
||||
}
|
||||
return main, baseArgs, nil
|
||||
}
|
||||
|
||||
// LoadDir loads a plugin from the given directory.
|
||||
func LoadDir(dirname string) (*Plugin, error) {
|
||||
data, err := ioutil.ReadFile(filepath.Join(dirname, PluginFileName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plug := &Plugin{Dir: dirname}
|
||||
if err := yaml.Unmarshal(data, &plug.Metadata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plug, nil
|
||||
}
|
||||
|
||||
// LoadAll loads all plugins found beneath the base directory.
|
||||
//
|
||||
// This scans only one directory level.
|
||||
func LoadAll(basedir string) ([]*Plugin, error) {
|
||||
plugins := []*Plugin{}
|
||||
// We want basedir/*/plugin.yaml
|
||||
scanpath := filepath.Join(basedir, "*", PluginFileName)
|
||||
matches, err := filepath.Glob(scanpath)
|
||||
if err != nil {
|
||||
return plugins, err
|
||||
}
|
||||
|
||||
if matches == nil {
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
for _, yaml := range matches {
|
||||
dir := filepath.Dir(yaml)
|
||||
p, err := LoadDir(dir)
|
||||
if err != nil {
|
||||
return plugins, err
|
||||
}
|
||||
plugins = append(plugins, p)
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
|
||||
// FindPlugins returns a list of YAML files that describe plugins.
|
||||
func FindPlugins(plugdirs string) ([]*Plugin, error) {
|
||||
found := []*Plugin{}
|
||||
// Let's get all UNIXy and allow path separators
|
||||
for _, p := range filepath.SplitList(plugdirs) {
|
||||
matches, err := LoadAll(p)
|
||||
if err != nil {
|
||||
return matches, err
|
||||
}
|
||||
found = append(found, matches...)
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// SetupPluginEnv prepares os.Env for plugins. It operates on os.Env because
|
||||
// the plugin subsystem itself needs access to the environment variables
|
||||
// created here.
|
||||
func SetupPluginEnv(settings *cli.EnvSettings, name, base string) {
|
||||
env := settings.EnvVars()
|
||||
env["HELM_PLUGIN_NAME"] = name
|
||||
env["HELM_PLUGIN_DIR"] = base
|
||||
for key, val := range env {
|
||||
os.Setenv(key, val)
|
||||
}
|
||||
}
|
||||
37
vendor/helm.sh/helm/v3/pkg/provenance/doc.go
vendored
Normal file
37
vendor/helm.sh/helm/v3/pkg/provenance/doc.go
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 provenance provides tools for establishing the authenticity of a chart.
|
||||
|
||||
In Helm, provenance is established via several factors. The primary factor is the
|
||||
cryptographic signature of a chart. Chart authors may sign charts, which in turn
|
||||
provide the necessary metadata to ensure the integrity of the chart file, the
|
||||
Chart.yaml, and the referenced Docker images.
|
||||
|
||||
A provenance file is clear-signed. This provides cryptographic verification that
|
||||
a particular block of information (Chart.yaml, archive file, images) have not
|
||||
been tampered with or altered. To learn more, read the GnuPG documentation on
|
||||
clear signatures:
|
||||
https://www.gnupg.org/gph/en/manual/x135.html
|
||||
|
||||
The cryptography used by Helm should be compatible with OpenGPG. For example,
|
||||
you should be able to verify a signature by importing the desired public key
|
||||
and using `gpg --verify`, `keybase pgp verify`, or similar:
|
||||
|
||||
$ gpg --verify some.sig
|
||||
gpg: Signature made Mon Jul 25 17:23:44 2016 MDT using RSA key ID 1FC18762
|
||||
gpg: Good signature from "Helm Testing (This key should only be used for testing. DO NOT TRUST.) <helm-testing@helm.sh>" [ultimate]
|
||||
*/
|
||||
package provenance // import "helm.sh/helm/v3/pkg/provenance"
|
||||
409
vendor/helm.sh/helm/v3/pkg/provenance/sign.go
vendored
Normal file
409
vendor/helm.sh/helm/v3/pkg/provenance/sign.go
vendored
Normal file
@@ -0,0 +1,409 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
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 provenance
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/clearsign"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
hapi "helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
)
|
||||
|
||||
var defaultPGPConfig = packet.Config{
|
||||
DefaultHash: crypto.SHA512,
|
||||
}
|
||||
|
||||
// SumCollection represents a collection of file and image checksums.
|
||||
//
|
||||
// Files are of the form:
|
||||
// FILENAME: "sha256:SUM"
|
||||
// Images are of the form:
|
||||
// "IMAGE:TAG": "sha256:SUM"
|
||||
// Docker optionally supports sha512, and if this is the case, the hash marker
|
||||
// will be 'sha512' instead of 'sha256'.
|
||||
type SumCollection struct {
|
||||
Files map[string]string `json:"files"`
|
||||
Images map[string]string `json:"images,omitempty"`
|
||||
}
|
||||
|
||||
// Verification contains information about a verification operation.
|
||||
type Verification struct {
|
||||
// SignedBy contains the entity that signed a chart.
|
||||
SignedBy *openpgp.Entity
|
||||
// FileHash is the hash, prepended with the scheme, for the file that was verified.
|
||||
FileHash string
|
||||
// FileName is the name of the file that FileHash verifies.
|
||||
FileName string
|
||||
}
|
||||
|
||||
// Signatory signs things.
|
||||
//
|
||||
// Signatories can be constructed from a PGP private key file using NewFromFiles
|
||||
// or they can be constructed manually by setting the Entity to a valid
|
||||
// PGP entity.
|
||||
//
|
||||
// The same Signatory can be used to sign or validate multiple charts.
|
||||
type Signatory struct {
|
||||
// The signatory for this instance of Helm. This is used for signing.
|
||||
Entity *openpgp.Entity
|
||||
// The keyring for this instance of Helm. This is used for verification.
|
||||
KeyRing openpgp.EntityList
|
||||
}
|
||||
|
||||
// NewFromFiles constructs a new Signatory from the PGP key in the given filename.
|
||||
//
|
||||
// This will emit an error if it cannot find a valid GPG keyfile (entity) at the
|
||||
// given location.
|
||||
//
|
||||
// Note that the keyfile may have just a public key, just a private key, or
|
||||
// both. The Signatory methods may have different requirements of the keys. For
|
||||
// example, ClearSign must have a valid `openpgp.Entity.PrivateKey` before it
|
||||
// can sign something.
|
||||
func NewFromFiles(keyfile, keyringfile string) (*Signatory, error) {
|
||||
e, err := loadKey(keyfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ring, err := loadKeyRing(keyringfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Signatory{
|
||||
Entity: e,
|
||||
KeyRing: ring,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewFromKeyring reads a keyring file and creates a Signatory.
|
||||
//
|
||||
// If id is not the empty string, this will also try to find an Entity in the
|
||||
// keyring whose name matches, and set that as the signing entity. It will return
|
||||
// an error if the id is not empty and also not found.
|
||||
func NewFromKeyring(keyringfile, id string) (*Signatory, error) {
|
||||
ring, err := loadKeyRing(keyringfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &Signatory{KeyRing: ring}
|
||||
|
||||
// If the ID is empty, we can return now.
|
||||
if id == "" {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// We're gonna go all GnuPG on this and look for a string that _contains_. If
|
||||
// two or more keys contain the string and none are a direct match, we error
|
||||
// out.
|
||||
var candidate *openpgp.Entity
|
||||
vague := false
|
||||
for _, e := range ring {
|
||||
for n := range e.Identities {
|
||||
if n == id {
|
||||
s.Entity = e
|
||||
return s, nil
|
||||
}
|
||||
if strings.Contains(n, id) {
|
||||
if candidate != nil {
|
||||
vague = true
|
||||
}
|
||||
candidate = e
|
||||
}
|
||||
}
|
||||
}
|
||||
if vague {
|
||||
return s, errors.Errorf("more than one key contain the id %q", id)
|
||||
}
|
||||
|
||||
s.Entity = candidate
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// PassphraseFetcher returns a passphrase for decrypting keys.
|
||||
//
|
||||
// This is used as a callback to read a passphrase from some other location. The
|
||||
// given name is the Name field on the key, typically of the form:
|
||||
//
|
||||
// USER_NAME (COMMENT) <EMAIL>
|
||||
type PassphraseFetcher func(name string) ([]byte, error)
|
||||
|
||||
// DecryptKey decrypts a private key in the Signatory.
|
||||
//
|
||||
// If the key is not encrypted, this will return without error.
|
||||
//
|
||||
// If the key does not exist, this will return an error.
|
||||
//
|
||||
// If the key exists, but cannot be unlocked with the passphrase returned by
|
||||
// the PassphraseFetcher, this will return an error.
|
||||
//
|
||||
// If the key is successfully unlocked, it will return nil.
|
||||
func (s *Signatory) DecryptKey(fn PassphraseFetcher) error {
|
||||
if s.Entity == nil {
|
||||
return errors.New("private key not found")
|
||||
} else if s.Entity.PrivateKey == nil {
|
||||
return errors.New("provided key is not a private key. Try providing a keyring with secret keys")
|
||||
}
|
||||
|
||||
// Nothing else to do if key is not encrypted.
|
||||
if !s.Entity.PrivateKey.Encrypted {
|
||||
return nil
|
||||
}
|
||||
|
||||
fname := "Unknown"
|
||||
for i := range s.Entity.Identities {
|
||||
if i != "" {
|
||||
fname = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
p, err := fn(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Entity.PrivateKey.Decrypt(p)
|
||||
}
|
||||
|
||||
// ClearSign signs a chart with the given key.
|
||||
//
|
||||
// This takes the path to a chart archive file and a key, and it returns a clear signature.
|
||||
//
|
||||
// The Signatory must have a valid Entity.PrivateKey for this to work. If it does
|
||||
// not, an error will be returned.
|
||||
func (s *Signatory) ClearSign(chartpath string) (string, error) {
|
||||
if s.Entity == nil {
|
||||
return "", errors.New("private key not found")
|
||||
} else if s.Entity.PrivateKey == nil {
|
||||
return "", errors.New("provided key is not a private key. Try providing a keyring with secret keys")
|
||||
}
|
||||
|
||||
if fi, err := os.Stat(chartpath); err != nil {
|
||||
return "", err
|
||||
} else if fi.IsDir() {
|
||||
return "", errors.New("cannot sign a directory")
|
||||
}
|
||||
|
||||
out := bytes.NewBuffer(nil)
|
||||
|
||||
b, err := messageBlock(chartpath)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// Sign the buffer
|
||||
w, err := clearsign.Encode(out, s.Entity.PrivateKey, &defaultPGPConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, err = io.Copy(w, b)
|
||||
w.Close()
|
||||
return out.String(), err
|
||||
}
|
||||
|
||||
// Verify checks a signature and verifies that it is legit for a chart.
|
||||
func (s *Signatory) Verify(chartpath, sigpath string) (*Verification, error) {
|
||||
ver := &Verification{}
|
||||
for _, fname := range []string{chartpath, sigpath} {
|
||||
if fi, err := os.Stat(fname); err != nil {
|
||||
return ver, err
|
||||
} else if fi.IsDir() {
|
||||
return ver, errors.Errorf("%s cannot be a directory", fname)
|
||||
}
|
||||
}
|
||||
|
||||
// First verify the signature
|
||||
sig, err := s.decodeSignature(sigpath)
|
||||
if err != nil {
|
||||
return ver, errors.Wrap(err, "failed to decode signature")
|
||||
}
|
||||
|
||||
by, err := s.verifySignature(sig)
|
||||
if err != nil {
|
||||
return ver, err
|
||||
}
|
||||
ver.SignedBy = by
|
||||
|
||||
// Second, verify the hash of the tarball.
|
||||
sum, err := DigestFile(chartpath)
|
||||
if err != nil {
|
||||
return ver, err
|
||||
}
|
||||
_, sums, err := parseMessageBlock(sig.Plaintext)
|
||||
if err != nil {
|
||||
return ver, err
|
||||
}
|
||||
|
||||
sum = "sha256:" + sum
|
||||
basename := filepath.Base(chartpath)
|
||||
if sha, ok := sums.Files[basename]; !ok {
|
||||
return ver, errors.Errorf("provenance does not contain a SHA for a file named %q", basename)
|
||||
} else if sha != sum {
|
||||
return ver, errors.Errorf("sha256 sum does not match for %s: %q != %q", basename, sha, sum)
|
||||
}
|
||||
ver.FileHash = sum
|
||||
ver.FileName = basename
|
||||
|
||||
// TODO: when image signing is added, verify that here.
|
||||
|
||||
return ver, nil
|
||||
}
|
||||
|
||||
func (s *Signatory) decodeSignature(filename string) (*clearsign.Block, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, _ := clearsign.Decode(data)
|
||||
if block == nil {
|
||||
// There was no sig in the file.
|
||||
return nil, errors.New("signature block not found")
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// verifySignature verifies that the given block is validly signed, and returns the signer.
|
||||
func (s *Signatory) verifySignature(block *clearsign.Block) (*openpgp.Entity, error) {
|
||||
return openpgp.CheckDetachedSignature(
|
||||
s.KeyRing,
|
||||
bytes.NewBuffer(block.Bytes),
|
||||
block.ArmoredSignature.Body,
|
||||
)
|
||||
}
|
||||
|
||||
func messageBlock(chartpath string) (*bytes.Buffer, error) {
|
||||
var b *bytes.Buffer
|
||||
// Checksum the archive
|
||||
chash, err := DigestFile(chartpath)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
base := filepath.Base(chartpath)
|
||||
sums := &SumCollection{
|
||||
Files: map[string]string{
|
||||
base: "sha256:" + chash,
|
||||
},
|
||||
}
|
||||
|
||||
// Load the archive into memory.
|
||||
chart, err := loader.LoadFile(chartpath)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
// Buffer a hash + checksums YAML file
|
||||
data, err := yaml.Marshal(chart.Metadata)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
|
||||
// FIXME: YAML uses ---\n as a file start indicator, but this is not legal in a PGP
|
||||
// clearsign block. So we use ...\n, which is the YAML document end marker.
|
||||
// http://yaml.org/spec/1.2/spec.html#id2800168
|
||||
b = bytes.NewBuffer(data)
|
||||
b.WriteString("\n...\n")
|
||||
|
||||
data, err = yaml.Marshal(sums)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
b.Write(data)
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// parseMessageBlock
|
||||
func parseMessageBlock(data []byte) (*hapi.Metadata, *SumCollection, error) {
|
||||
// This sucks.
|
||||
parts := bytes.Split(data, []byte("\n...\n"))
|
||||
if len(parts) < 2 {
|
||||
return nil, nil, errors.New("message block must have at least two parts")
|
||||
}
|
||||
|
||||
md := &hapi.Metadata{}
|
||||
sc := &SumCollection{}
|
||||
|
||||
if err := yaml.Unmarshal(parts[0], md); err != nil {
|
||||
return md, sc, err
|
||||
}
|
||||
err := yaml.Unmarshal(parts[1], sc)
|
||||
return md, sc, err
|
||||
}
|
||||
|
||||
// loadKey loads a GPG key found at a particular path.
|
||||
func loadKey(keypath string) (*openpgp.Entity, error) {
|
||||
f, err := os.Open(keypath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
pr := packet.NewReader(f)
|
||||
return openpgp.ReadEntity(pr)
|
||||
}
|
||||
|
||||
func loadKeyRing(ringpath string) (openpgp.EntityList, error) {
|
||||
f, err := os.Open(ringpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return openpgp.ReadKeyRing(f)
|
||||
}
|
||||
|
||||
// DigestFile calculates a SHA256 hash (like Docker) for a given file.
|
||||
//
|
||||
// It takes the path to the archive file, and returns a string representation of
|
||||
// the SHA256 sum.
|
||||
//
|
||||
// The intended use of this function is to generate a sum of a chart TGZ file.
|
||||
func DigestFile(filename string) (string, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return Digest(f)
|
||||
}
|
||||
|
||||
// Digest hashes a reader and returns a SHA256 digest.
|
||||
//
|
||||
// Helm uses SHA256 as its default hash for all non-cryptographic applications.
|
||||
func Digest(in io.Reader) (string, error) {
|
||||
hash := crypto.SHA256.New()
|
||||
if _, err := io.Copy(hash, in); err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return hex.EncodeToString(hash.Sum(nil)), nil
|
||||
}
|
||||
285
vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go
vendored
Normal file
285
vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 repo // import "helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/helmpath"
|
||||
"helm.sh/helm/v3/pkg/provenance"
|
||||
)
|
||||
|
||||
// Entry represents a collection of parameters for chart repository
|
||||
type Entry struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
CertFile string `json:"certFile"`
|
||||
KeyFile string `json:"keyFile"`
|
||||
CAFile string `json:"caFile"`
|
||||
InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"`
|
||||
}
|
||||
|
||||
// ChartRepository represents a chart repository
|
||||
type ChartRepository struct {
|
||||
Config *Entry
|
||||
ChartPaths []string
|
||||
IndexFile *IndexFile
|
||||
Client getter.Getter
|
||||
CachePath string
|
||||
}
|
||||
|
||||
// NewChartRepository constructs ChartRepository
|
||||
func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) {
|
||||
u, err := url.Parse(cfg.URL)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("invalid chart URL format: %s", cfg.URL)
|
||||
}
|
||||
|
||||
client, err := getters.ByScheme(u.Scheme)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("could not find protocol handler for: %s", u.Scheme)
|
||||
}
|
||||
|
||||
return &ChartRepository{
|
||||
Config: cfg,
|
||||
IndexFile: NewIndexFile(),
|
||||
Client: client,
|
||||
CachePath: helmpath.CachePath("repository"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Load loads a directory of charts as if it were a repository.
|
||||
//
|
||||
// It requires the presence of an index.yaml file in the directory.
|
||||
func (r *ChartRepository) Load() error {
|
||||
dirInfo, err := os.Stat(r.Config.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !dirInfo.IsDir() {
|
||||
return errors.Errorf("%q is not a directory", r.Config.Name)
|
||||
}
|
||||
|
||||
// FIXME: Why are we recursively walking directories?
|
||||
// FIXME: Why are we not reading the repositories.yaml to figure out
|
||||
// what repos to use?
|
||||
filepath.Walk(r.Config.Name, func(path string, f os.FileInfo, err error) error {
|
||||
if !f.IsDir() {
|
||||
if strings.Contains(f.Name(), "-index.yaml") {
|
||||
i, err := LoadIndexFile(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
r.IndexFile = i
|
||||
} else if strings.HasSuffix(f.Name(), ".tgz") {
|
||||
r.ChartPaths = append(r.ChartPaths, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadIndexFile fetches the index from a repository.
|
||||
func (r *ChartRepository) DownloadIndexFile() (string, error) {
|
||||
parsedURL, err := url.Parse(r.Config.URL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
parsedURL.RawPath = path.Join(parsedURL.RawPath, "index.yaml")
|
||||
parsedURL.Path = path.Join(parsedURL.Path, "index.yaml")
|
||||
|
||||
indexURL := parsedURL.String()
|
||||
// TODO add user-agent
|
||||
resp, err := r.Client.Get(indexURL,
|
||||
getter.WithURL(r.Config.URL),
|
||||
getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify),
|
||||
getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile),
|
||||
getter.WithBasicAuth(r.Config.Username, r.Config.Password),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
index, err := ioutil.ReadAll(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
indexFile, err := loadIndex(index)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Create the chart list file in the cache directory
|
||||
var charts strings.Builder
|
||||
for name := range indexFile.Entries {
|
||||
fmt.Fprintln(&charts, name)
|
||||
}
|
||||
chartsFile := filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name))
|
||||
os.MkdirAll(filepath.Dir(chartsFile), 0755)
|
||||
ioutil.WriteFile(chartsFile, []byte(charts.String()), 0644)
|
||||
|
||||
// Create the index file in the cache directory
|
||||
fname := filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name))
|
||||
os.MkdirAll(filepath.Dir(fname), 0755)
|
||||
return fname, ioutil.WriteFile(fname, index, 0644)
|
||||
}
|
||||
|
||||
// Index generates an index for the chart repository and writes an index.yaml file.
|
||||
func (r *ChartRepository) Index() error {
|
||||
err := r.generateIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.saveIndexFile()
|
||||
}
|
||||
|
||||
func (r *ChartRepository) saveIndexFile() error {
|
||||
index, err := yaml.Marshal(r.IndexFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filepath.Join(r.Config.Name, indexPath), index, 0644)
|
||||
}
|
||||
|
||||
func (r *ChartRepository) generateIndex() error {
|
||||
for _, path := range r.ChartPaths {
|
||||
ch, err := loader.Load(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
digest, err := provenance.DigestFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !r.IndexFile.Has(ch.Name(), ch.Metadata.Version) {
|
||||
r.IndexFile.Add(ch.Metadata, path, r.Config.URL, digest)
|
||||
}
|
||||
// TODO: If a chart exists, but has a different Digest, should we error?
|
||||
}
|
||||
r.IndexFile.SortEntries()
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindChartInRepoURL finds chart in chart repository pointed by repoURL
|
||||
// without adding repo to repositories
|
||||
func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
|
||||
return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters)
|
||||
}
|
||||
|
||||
// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL
|
||||
// without adding repo to repositories, like FindChartInRepoURL,
|
||||
// but it also receives credentials for the chart repository.
|
||||
func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) {
|
||||
|
||||
// Download and write the index file to a temporary location
|
||||
buf := make([]byte, 20)
|
||||
rand.Read(buf)
|
||||
name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-")
|
||||
|
||||
c := Entry{
|
||||
URL: repoURL,
|
||||
Username: username,
|
||||
Password: password,
|
||||
CertFile: certFile,
|
||||
KeyFile: keyFile,
|
||||
CAFile: caFile,
|
||||
Name: name,
|
||||
}
|
||||
r, err := NewChartRepository(&c, getters)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
idx, err := r.DownloadIndexFile()
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL)
|
||||
}
|
||||
|
||||
// Read the index file for the repository to get chart information and return chart URL
|
||||
repoIndex, err := LoadIndexFile(idx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
errMsg := fmt.Sprintf("chart %q", chartName)
|
||||
if chartVersion != "" {
|
||||
errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion)
|
||||
}
|
||||
cv, err := repoIndex.Get(chartName, chartVersion)
|
||||
if err != nil {
|
||||
return "", errors.Errorf("%s not found in %s repository", errMsg, repoURL)
|
||||
}
|
||||
|
||||
if len(cv.URLs) == 0 {
|
||||
return "", errors.Errorf("%s has no downloadable URLs", errMsg)
|
||||
}
|
||||
|
||||
chartURL := cv.URLs[0]
|
||||
|
||||
absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to make chart URL absolute")
|
||||
}
|
||||
|
||||
return absoluteChartURL, nil
|
||||
}
|
||||
|
||||
// ResolveReferenceURL resolves refURL relative to baseURL.
|
||||
// If refURL is absolute, it simply returns refURL.
|
||||
func ResolveReferenceURL(baseURL, refURL string) (string, error) {
|
||||
parsedBaseURL, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to parse %s as URL", baseURL)
|
||||
}
|
||||
|
||||
parsedRefURL, err := url.Parse(refURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to parse %s as URL", refURL)
|
||||
}
|
||||
|
||||
// We need a trailing slash for ResolveReference to work, but make sure there isn't already one
|
||||
parsedBaseURL.Path = strings.TrimSuffix(parsedBaseURL.Path, "/") + "/"
|
||||
return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil
|
||||
}
|
||||
|
||||
func (e *Entry) String() string {
|
||||
buf, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
return string(buf)
|
||||
}
|
||||
93
vendor/helm.sh/helm/v3/pkg/repo/doc.go
vendored
Normal file
93
vendor/helm.sh/helm/v3/pkg/repo/doc.go
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 repo implements the Helm Chart Repository.
|
||||
|
||||
A chart repository is an HTTP server that provides information on charts. A local
|
||||
repository cache is an on-disk representation of a chart repository.
|
||||
|
||||
There are two important file formats for chart repositories.
|
||||
|
||||
The first is the 'index.yaml' format, which is expressed like this:
|
||||
|
||||
apiVersion: v1
|
||||
entries:
|
||||
frobnitz:
|
||||
- created: 2016-09-29T12:14:34.830161306-06:00
|
||||
description: This is a frobnitz.
|
||||
digest: 587bd19a9bd9d2bc4a6d25ab91c8c8e7042c47b4ac246e37bf8e1e74386190f4
|
||||
home: http://example.com
|
||||
keywords:
|
||||
- frobnitz
|
||||
- sprocket
|
||||
- dodad
|
||||
maintainers:
|
||||
- email: helm@example.com
|
||||
name: The Helm Team
|
||||
- email: nobody@example.com
|
||||
name: Someone Else
|
||||
name: frobnitz
|
||||
urls:
|
||||
- http://example-charts.com/testdata/repository/frobnitz-1.2.3.tgz
|
||||
version: 1.2.3
|
||||
sprocket:
|
||||
- created: 2016-09-29T12:14:34.830507606-06:00
|
||||
description: This is a sprocket"
|
||||
digest: 8505ff813c39502cc849a38e1e4a8ac24b8e6e1dcea88f4c34ad9b7439685ae6
|
||||
home: http://example.com
|
||||
keywords:
|
||||
- frobnitz
|
||||
- sprocket
|
||||
- dodad
|
||||
maintainers:
|
||||
- email: helm@example.com
|
||||
name: The Helm Team
|
||||
- email: nobody@example.com
|
||||
name: Someone Else
|
||||
name: sprocket
|
||||
urls:
|
||||
- http://example-charts.com/testdata/repository/sprocket-1.2.0.tgz
|
||||
version: 1.2.0
|
||||
generated: 2016-09-29T12:14:34.829721375-06:00
|
||||
|
||||
An index.yaml file contains the necessary descriptive information about what
|
||||
charts are available in a repository, and how to get them.
|
||||
|
||||
The second file format is the repositories.yaml file format. This file is for
|
||||
facilitating local cached copies of one or more chart repositories.
|
||||
|
||||
The format of a repository.yaml file is:
|
||||
|
||||
apiVersion: v1
|
||||
generated: TIMESTAMP
|
||||
repositories:
|
||||
- name: stable
|
||||
url: http://example.com/charts
|
||||
cache: stable-index.yaml
|
||||
- name: incubator
|
||||
url: http://example.com/incubator
|
||||
cache: incubator-index.yaml
|
||||
|
||||
This file maps three bits of information about a repository:
|
||||
|
||||
- The name the user uses to refer to it
|
||||
- The fully qualified URL to the repository (index.yaml will be appended)
|
||||
- The name of the local cachefile
|
||||
|
||||
The format for both files was changed after Helm v2.0.0-Alpha.4. Helm is not
|
||||
backwards compatible with those earlier versions.
|
||||
*/
|
||||
package repo
|
||||
292
vendor/helm.sh/helm/v3/pkg/repo/index.go
vendored
Normal file
292
vendor/helm.sh/helm/v3/pkg/repo/index.go
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 repo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"helm.sh/helm/v3/internal/fileutil"
|
||||
"helm.sh/helm/v3/internal/urlutil"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/provenance"
|
||||
)
|
||||
|
||||
var indexPath = "index.yaml"
|
||||
|
||||
// APIVersionV1 is the v1 API version for index and repository files.
|
||||
const APIVersionV1 = "v1"
|
||||
|
||||
var (
|
||||
// ErrNoAPIVersion indicates that an API version was not specified.
|
||||
ErrNoAPIVersion = errors.New("no API version specified")
|
||||
// ErrNoChartVersion indicates that a chart with the given version is not found.
|
||||
ErrNoChartVersion = errors.New("no chart version found")
|
||||
// ErrNoChartName indicates that a chart with the given name is not found.
|
||||
ErrNoChartName = errors.New("no chart name found")
|
||||
)
|
||||
|
||||
// ChartVersions is a list of versioned chart references.
|
||||
// Implements a sorter on Version.
|
||||
type ChartVersions []*ChartVersion
|
||||
|
||||
// Len returns the length.
|
||||
func (c ChartVersions) Len() int { return len(c) }
|
||||
|
||||
// Swap swaps the position of two items in the versions slice.
|
||||
func (c ChartVersions) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
|
||||
|
||||
// Less returns true if the version of entry a is less than the version of entry b.
|
||||
func (c ChartVersions) Less(a, b int) bool {
|
||||
// Failed parse pushes to the back.
|
||||
i, err := semver.NewVersion(c[a].Version)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
j, err := semver.NewVersion(c[b].Version)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return i.LessThan(j)
|
||||
}
|
||||
|
||||
// IndexFile represents the index file in a chart repository
|
||||
type IndexFile struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Entries map[string]ChartVersions `json:"entries"`
|
||||
PublicKeys []string `json:"publicKeys,omitempty"`
|
||||
}
|
||||
|
||||
// NewIndexFile initializes an index.
|
||||
func NewIndexFile() *IndexFile {
|
||||
return &IndexFile{
|
||||
APIVersion: APIVersionV1,
|
||||
Generated: time.Now(),
|
||||
Entries: map[string]ChartVersions{},
|
||||
PublicKeys: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadIndexFile takes a file at the given path and returns an IndexFile object
|
||||
func LoadIndexFile(path string) (*IndexFile, error) {
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return loadIndex(b)
|
||||
}
|
||||
|
||||
// Add adds a file to the index
|
||||
// This can leave the index in an unsorted state
|
||||
func (i IndexFile) Add(md *chart.Metadata, filename, baseURL, digest string) {
|
||||
u := filename
|
||||
if baseURL != "" {
|
||||
var err error
|
||||
_, file := filepath.Split(filename)
|
||||
u, err = urlutil.URLJoin(baseURL, file)
|
||||
if err != nil {
|
||||
u = path.Join(baseURL, file)
|
||||
}
|
||||
}
|
||||
cr := &ChartVersion{
|
||||
URLs: []string{u},
|
||||
Metadata: md,
|
||||
Digest: digest,
|
||||
Created: time.Now(),
|
||||
}
|
||||
if ee, ok := i.Entries[md.Name]; !ok {
|
||||
i.Entries[md.Name] = ChartVersions{cr}
|
||||
} else {
|
||||
i.Entries[md.Name] = append(ee, cr)
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if the index has an entry for a chart with the given name and exact version.
|
||||
func (i IndexFile) Has(name, version string) bool {
|
||||
_, err := i.Get(name, version)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// SortEntries sorts the entries by version in descending order.
|
||||
//
|
||||
// In canonical form, the individual version records should be sorted so that
|
||||
// the most recent release for every version is in the 0th slot in the
|
||||
// Entries.ChartVersions array. That way, tooling can predict the newest
|
||||
// version without needing to parse SemVers.
|
||||
func (i IndexFile) SortEntries() {
|
||||
for _, versions := range i.Entries {
|
||||
sort.Sort(sort.Reverse(versions))
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the ChartVersion for the given name.
|
||||
//
|
||||
// If version is empty, this will return the chart with the latest stable version,
|
||||
// prerelease versions will be skipped.
|
||||
func (i IndexFile) Get(name, version string) (*ChartVersion, error) {
|
||||
vs, ok := i.Entries[name]
|
||||
if !ok {
|
||||
return nil, ErrNoChartName
|
||||
}
|
||||
if len(vs) == 0 {
|
||||
return nil, ErrNoChartVersion
|
||||
}
|
||||
|
||||
var constraint *semver.Constraints
|
||||
if version == "" {
|
||||
constraint, _ = semver.NewConstraint("*")
|
||||
} else {
|
||||
var err error
|
||||
constraint, err = semver.NewConstraint(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// when customer input exact version, check whether have exact match one first
|
||||
if len(version) != 0 {
|
||||
for _, ver := range vs {
|
||||
if version == ver.Version {
|
||||
return ver, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, ver := range vs {
|
||||
test, err := semver.NewVersion(ver.Version)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if constraint.Check(test) {
|
||||
return ver, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("no chart version found for %s-%s", name, version)
|
||||
}
|
||||
|
||||
// WriteFile writes an index file to the given destination path.
|
||||
//
|
||||
// The mode on the file is set to 'mode'.
|
||||
func (i IndexFile) WriteFile(dest string, mode os.FileMode) error {
|
||||
b, err := yaml.Marshal(i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode)
|
||||
}
|
||||
|
||||
// Merge merges the given index file into this index.
|
||||
//
|
||||
// This merges by name and version.
|
||||
//
|
||||
// If one of the entries in the given index does _not_ already exist, it is added.
|
||||
// In all other cases, the existing record is preserved.
|
||||
//
|
||||
// This can leave the index in an unsorted state
|
||||
func (i *IndexFile) Merge(f *IndexFile) {
|
||||
for _, cvs := range f.Entries {
|
||||
for _, cv := range cvs {
|
||||
if !i.Has(cv.Name, cv.Version) {
|
||||
e := i.Entries[cv.Name]
|
||||
i.Entries[cv.Name] = append(e, cv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChartVersion represents a chart entry in the IndexFile
|
||||
type ChartVersion struct {
|
||||
*chart.Metadata
|
||||
URLs []string `json:"urls"`
|
||||
Created time.Time `json:"created,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
Digest string `json:"digest,omitempty"`
|
||||
}
|
||||
|
||||
// IndexDirectory reads a (flat) directory and generates an index.
|
||||
//
|
||||
// It indexes only charts that have been packaged (*.tgz).
|
||||
//
|
||||
// The index returned will be in an unsorted state
|
||||
func IndexDirectory(dir, baseURL string) (*IndexFile, error) {
|
||||
archives, err := filepath.Glob(filepath.Join(dir, "*.tgz"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
moreArchives, err := filepath.Glob(filepath.Join(dir, "**/*.tgz"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
archives = append(archives, moreArchives...)
|
||||
|
||||
index := NewIndexFile()
|
||||
for _, arch := range archives {
|
||||
fname, err := filepath.Rel(dir, arch)
|
||||
if err != nil {
|
||||
return index, err
|
||||
}
|
||||
|
||||
var parentDir string
|
||||
parentDir, fname = filepath.Split(fname)
|
||||
// filepath.Split appends an extra slash to the end of parentDir. We want to strip that out.
|
||||
parentDir = strings.TrimSuffix(parentDir, string(os.PathSeparator))
|
||||
parentURL, err := urlutil.URLJoin(baseURL, parentDir)
|
||||
if err != nil {
|
||||
parentURL = path.Join(baseURL, parentDir)
|
||||
}
|
||||
|
||||
c, err := loader.Load(arch)
|
||||
if err != nil {
|
||||
// Assume this is not a chart.
|
||||
continue
|
||||
}
|
||||
hash, err := provenance.DigestFile(arch)
|
||||
if err != nil {
|
||||
return index, err
|
||||
}
|
||||
index.Add(c.Metadata, fname, parentURL, hash)
|
||||
}
|
||||
return index, nil
|
||||
}
|
||||
|
||||
// loadIndex loads an index file and does minimal validity checking.
|
||||
//
|
||||
// This will fail if API Version is not set (ErrNoAPIVersion) or if the unmarshal fails.
|
||||
func loadIndex(data []byte) (*IndexFile, error) {
|
||||
i := &IndexFile{}
|
||||
if err := yaml.Unmarshal(data, i); err != nil {
|
||||
return i, err
|
||||
}
|
||||
i.SortEntries()
|
||||
if i.APIVersion == "" {
|
||||
return i, ErrNoAPIVersion
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
123
vendor/helm.sh/helm/v3/pkg/repo/repo.go
vendored
Normal file
123
vendor/helm.sh/helm/v3/pkg/repo/repo.go
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
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 repo // import "helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// File represents the repositories.yaml file
|
||||
type File struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Generated time.Time `json:"generated"`
|
||||
Repositories []*Entry `json:"repositories"`
|
||||
}
|
||||
|
||||
// NewFile generates an empty repositories file.
|
||||
//
|
||||
// Generated and APIVersion are automatically set.
|
||||
func NewFile() *File {
|
||||
return &File{
|
||||
APIVersion: APIVersionV1,
|
||||
Generated: time.Now(),
|
||||
Repositories: []*Entry{},
|
||||
}
|
||||
}
|
||||
|
||||
// LoadFile takes a file at the given path and returns a File object
|
||||
func LoadFile(path string) (*File, error) {
|
||||
r := new(File)
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return r, errors.Wrapf(err, "couldn't load repositories file (%s)", path)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(b, r)
|
||||
return r, err
|
||||
}
|
||||
|
||||
// Add adds one or more repo entries to a repo file.
|
||||
func (r *File) Add(re ...*Entry) {
|
||||
r.Repositories = append(r.Repositories, re...)
|
||||
}
|
||||
|
||||
// Update attempts to replace one or more repo entries in a repo file. If an
|
||||
// entry with the same name doesn't exist in the repo file it will add it.
|
||||
func (r *File) Update(re ...*Entry) {
|
||||
for _, target := range re {
|
||||
r.update(target)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *File) update(e *Entry) {
|
||||
for j, repo := range r.Repositories {
|
||||
if repo.Name == e.Name {
|
||||
r.Repositories[j] = e
|
||||
return
|
||||
}
|
||||
}
|
||||
r.Add(e)
|
||||
}
|
||||
|
||||
// Has returns true if the given name is already a repository name.
|
||||
func (r *File) Has(name string) bool {
|
||||
entry := r.Get(name)
|
||||
return entry != nil
|
||||
}
|
||||
|
||||
// Get returns an entry with the given name if it exists, otherwise returns nil
|
||||
func (r *File) Get(name string) *Entry {
|
||||
for _, entry := range r.Repositories {
|
||||
if entry.Name == name {
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes the entry from the list of repositories.
|
||||
func (r *File) Remove(name string) bool {
|
||||
cp := []*Entry{}
|
||||
found := false
|
||||
for _, rf := range r.Repositories {
|
||||
if rf.Name == name {
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
cp = append(cp, rf)
|
||||
}
|
||||
r.Repositories = cp
|
||||
return found
|
||||
}
|
||||
|
||||
// WriteFile writes a repositories file to the given path.
|
||||
func (r *File) WriteFile(path string, perm os.FileMode) error {
|
||||
data, err := yaml.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(path, data, perm)
|
||||
}
|
||||
Reference in New Issue
Block a user