Merge pull request #1923 from qwangrepos/local-path

feat(helm): add local path support for deps in requirements.yaml
pull/1954/head
Taylor Thomas 9 years ago committed by GitHub
commit 8dfea91056

@ -127,7 +127,7 @@ func (l *dependencyListCmd) run() error {
r, err := chartutil.LoadRequirements(c)
if err != nil {
if err == chartutil.ErrRequirementsNotFound {
fmt.Fprintf(l.out, "WARNING: no requirements at %s/charts", l.chartpath)
fmt.Fprintf(l.out, "WARNING: no requirements at %s/charts\n", l.chartpath)
return nil
}
return err

@ -39,6 +39,16 @@ appending '/index.yaml' to the URL, it should be able to retrieve the chart
repository's index. Note: 'repository' cannot be a repository alias. It must be
a URL.
Starting from 2.2.0, repository can be defined as the path to the directory of
the dependency charts stored locally. The path should start with a prefix of "file://".
For example,
# requirements.yaml
dependencies:
- name: nginx
version: "1.2.3"
repository: "file://../dependency_chart/nginx"
If the dependency chart is retrieved locally, it is not required to have the repository
added to helm by "helm add repo". Version matching is also supported for this case.
### Options inherited from parent commands

@ -116,7 +116,6 @@ func (m *Manager) Update() error {
}
return err
}
// Check that all of the repos we're dependent on actually exist and
// the repo index names.
repoNames, err := m.getRepoNames(req.Dependencies)
@ -201,6 +200,17 @@ func (m *Manager) downloadAll(deps []*chartutil.Dependency) error {
if err := m.safeDeleteDep(dep.Name, destPath); err != nil {
return err
}
if strings.HasPrefix(dep.Repository, "file://") {
fmt.Fprintf(m.Out, "Archiving %s from repo %s\n", dep.Name, dep.Repository)
ver, err := tarFromLocalDir(m.ChartPath, dep.Name, dep.Repository, dep.Version)
if err != nil {
return err
}
dep.Version = ver
continue
}
fmt.Fprintf(m.Out, "Downloading %s from repo %s\n", dep.Name, dep.Repository)
// Any failure to resolve/download a chart should fail:
@ -257,10 +267,16 @@ func (m *Manager) hasAllRepos(deps []*chartutil.Dependency) error {
return err
}
repos := rf.Repositories
// Verify that all repositories referenced in the deps are actually known
// by Helm.
missing := []string{}
for _, dd := range deps {
// If repo is from local path, continue
if strings.HasPrefix(dd.Repository, "file://") {
continue
}
found := false
if dd.Repository == "" {
found = true
@ -295,6 +311,24 @@ func (m *Manager) getRepoNames(deps []*chartutil.Dependency) (map[string]string,
// by Helm.
missing := []string{}
for _, dd := range deps {
// if dep chart is from local path, verify the path is valid
if strings.HasPrefix(dd.Repository, "file://") {
depPath, err := filepath.Abs(strings.TrimPrefix(dd.Repository, "file://"))
if err != nil {
return nil, err
}
if _, err = os.Stat(depPath); os.IsNotExist(err) {
return nil, fmt.Errorf("directory %s not found", depPath)
} else if err != nil {
return nil, err
}
fmt.Fprintf(m.Out, "Repository from local path: %s\n", dd.Repository)
reposMap[dd.Name] = dd.Repository
continue
}
found := false
for _, repo := range repos {
@ -480,3 +514,45 @@ func writeLock(chartpath string, lock *chartutil.RequirementsLock) error {
dest := filepath.Join(chartpath, "requirements.lock")
return ioutil.WriteFile(dest, data, 0644)
}
// archive a dep chart from local directory and save it into charts/
func tarFromLocalDir(chartpath string, name string, repo string, version string) (string, error) {
destPath := filepath.Join(chartpath, "charts")
if !strings.HasPrefix(repo, "file://") {
return "", fmt.Errorf("wrong format: chart %s repository %s", name, repo)
}
origPath, err := filepath.Abs(strings.TrimPrefix(repo, "file://"))
if err != nil {
return "", err
}
if _, err = os.Stat(origPath); os.IsNotExist(err) {
return "", fmt.Errorf("directory %s not found: %s", origPath, err)
} else if err != nil {
return "", err
}
ch, err := chartutil.LoadDir(origPath)
if err != nil {
return "", err
}
constraint, err := semver.NewConstraint(version)
if err != nil {
return "", fmt.Errorf("dependency %s has an invalid version/constraint format: %s", name, err)
}
v, err := semver.NewVersion(ch.Metadata.Version)
if err != nil {
return "", err
}
if constraint.Check(v) {
_, err = chartutil.Save(ch, destPath)
return ch.Metadata.Version, err
}
return "", fmt.Errorf("Can't get a valid version for dependency %s.", name)
}

@ -113,6 +113,13 @@ func TestGetRepoNames(t *testing.T) {
},
expect: map[string]string{"oedipus-rex": "testing"},
},
{
name: "repo from local path",
req: []*chartutil.Dependency{
{Name: "local-dep", Repository: "file://./testdata/signtest"},
},
expect: map[string]string{"local-dep": "file://./testdata/signtest"},
},
}
for _, tt := range tests {

@ -19,6 +19,8 @@ import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"time"
@ -55,6 +57,25 @@ func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]st
locked := make([]*chartutil.Dependency, len(reqs.Dependencies))
missing := []string{}
for i, d := range reqs.Dependencies {
if strings.HasPrefix(d.Repository, "file://") {
depPath, err := filepath.Abs(strings.TrimPrefix(d.Repository, "file://"))
if err != nil {
return nil, err
}
if _, err = os.Stat(depPath); os.IsNotExist(err) {
return nil, fmt.Errorf("directory %s not found", depPath)
} else if err != nil {
return nil, err
}
locked[i] = &chartutil.Dependency{
Name: d.Name,
Repository: d.Repository,
Version: d.Version,
}
continue
}
constraint, err := semver.NewConstraint(d.Version)
if err != nil {
return nil, fmt.Errorf("dependency %q has an invalid version/constraint format: %s", d.Name, err)

@ -77,6 +77,28 @@ func TestResolve(t *testing.T) {
},
},
},
{
name: "repo from valid local path",
req: &chartutil.Requirements{
Dependencies: []*chartutil.Dependency{
{Name: "signtest", Repository: "file://../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"},
},
},
expect: &chartutil.RequirementsLock{
Dependencies: []*chartutil.Dependency{
{Name: "signtest", Repository: "file://../../cmd/helm/testdata/testcharts/signtest", Version: "0.1.0"},
},
},
},
{
name: "repo from invalid local path",
req: &chartutil.Requirements{
Dependencies: []*chartutil.Dependency{
{Name: "notexist", Repository: "file://../testdata/notexist", Version: "0.1.0"},
},
},
err: true,
},
}
repoNames := map[string]string{"alpine": "kubernetes-charts", "redis": "kubernetes-charts"}

Loading…
Cancel
Save