feat(cli): support XDG base directory specification

Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com>
pull/5443/head
Matthew Fisher 6 years ago
parent d360705c83
commit c728611e5a
No known key found for this signature in database
GPG Key ID: 92AA783CBAAE8E3B

@ -68,13 +68,13 @@ test: test-unit
test-unit: vendor
@echo
@echo "==> Running unit tests <=="
HELM_HOME=/no_such_dir go test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS)
go test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS)
.PHONY: test-coverage
test-coverage: vendor
@echo
@echo "==> Running unit tests with coverage <=="
@ HELM_HOME=/no_such_dir ./scripts/coverage.sh
@ ./scripts/coverage.sh
.PHONY: test-style
test-style: vendor $(GOLANGCI_LINT)

@ -26,6 +26,7 @@ import (
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/helmpath"
)
const createDesc = `
@ -86,7 +87,7 @@ func (o *createOptions) run(out io.Writer) error {
if o.starter != "" {
// Create from the starter
lstarter := filepath.Join(settings.Home.Starters(), o.starter)
lstarter := filepath.Join(helmpath.Starters(), o.starter)
// If path is absolute, we dont want to prefix it with helm starters folder
if filepath.IsAbs(o.starter) {
lstarter = o.starter

@ -23,16 +23,18 @@ import (
"path/filepath"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chart/loader"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/helmpath"
)
func TestCreateCmd(t *testing.T) {
tdir := testTempDir(t)
defer testChdir(t, tdir)()
cname := "testchart"
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
defer testChdir(t, helmpath.CachePath())()
// Run a create
if _, _, err := executeActionCommand("create " + cname); err != nil {
@ -61,17 +63,14 @@ func TestCreateCmd(t *testing.T) {
}
func TestCreateStarterCmd(t *testing.T) {
defer resetEnv()()
cname := "testchart"
// Make a temp dir
tdir := testTempDir(t)
hh := testHelmHome(t)
settings.Home = hh
defer resetEnv()()
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
defer testChdir(t, helmpath.CachePath())()
// Create a starter.
starterchart := hh.Starters()
starterchart := helmpath.Starters()
os.Mkdir(starterchart, 0755)
if dest, err := chartutil.Create("starterchart", starterchart); err != nil {
t.Fatalf("Could not create chart: %s", err)
@ -83,10 +82,8 @@ func TestCreateStarterCmd(t *testing.T) {
t.Fatalf("Could not write template: %s", err)
}
defer testChdir(t, tdir)()
// Run a create
if _, _, err := executeActionCommand(fmt.Sprintf("--home='%s' create --starter=starterchart %s", hh.String(), cname)); err != nil {
if _, _, err := executeActionCommand(fmt.Sprintf("create --starter=starterchart %s", cname)); err != nil {
t.Errorf("Failed to run create: %s", err)
return
}
@ -131,16 +128,12 @@ func TestCreateStarterCmd(t *testing.T) {
func TestCreateStarterAbsoluteCmd(t *testing.T) {
defer resetEnv()()
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
cname := "testchart"
// Make a temp dir
tdir := testTempDir(t)
hh := testHelmHome(t)
settings.Home = hh
// Create a starter.
starterchart := hh.Starters()
starterchart := helmpath.Starters()
os.Mkdir(starterchart, 0755)
if dest, err := chartutil.Create("starterchart", starterchart); err != nil {
t.Fatalf("Could not create chart: %s", err)
@ -152,12 +145,12 @@ func TestCreateStarterAbsoluteCmd(t *testing.T) {
t.Fatalf("Could not write template: %s", err)
}
defer testChdir(t, tdir)()
defer testChdir(t, helmpath.CachePath())()
starterChartPath := filepath.Join(starterchart, "starterchart")
// Run a create
if _, _, err := executeActionCommand(fmt.Sprintf("--home='%s' create --starter=%s %s", hh.String(), starterChartPath, cname)); err != nil {
if _, _, err := executeActionCommand(fmt.Sprintf("create --starter=%s %s", starterChartPath, cname)); err != nil {
t.Errorf("Failed to run create: %s", err)
return
}

@ -56,7 +56,6 @@ func newDependencyBuildCmd(out io.Writer) *cobra.Command {
man := &downloader.Manager{
Out: out,
ChartPath: chartpath,
HelmHome: settings.Home,
Keyring: client.Keyring,
Getters: getter.All(settings),
}

@ -18,9 +18,12 @@ package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/provenance"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/repo/repotest"
@ -29,21 +32,21 @@ import (
func TestDependencyBuildCmd(t *testing.T) {
defer resetEnv()()
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
srv := repotest.NewServer(hh.String())
srv := repotest.NewServer(helmpath.ConfigPath())
defer srv.Stop()
if _, err := srv.CopyCharts("testdata/testcharts/*.tgz"); err != nil {
t.Fatal(err)
}
chartname := "depbuild"
if err := createTestingChart(hh.String(), chartname, srv.URL()); err != nil {
if err := createTestingChart(helmpath.DataPath(), chartname, srv.URL()); err != nil {
t.Fatal(err)
}
cmd := fmt.Sprintf("--home='%s' dependency build '%s'", hh, hh.Path(chartname))
cmd := fmt.Sprintf("dependency build '%s'", filepath.Join(helmpath.DataPath(), chartname))
_, out, err := executeActionCommand(cmd)
// In the first pass, we basically want the same results as an update.
@ -57,14 +60,14 @@ func TestDependencyBuildCmd(t *testing.T) {
}
// Make sure the actual file got downloaded.
expect := hh.Path(chartname, "charts/reqtest-0.1.0.tgz")
expect := filepath.Join(helmpath.DataPath(), chartname, "charts/reqtest-0.1.0.tgz")
if _, err := os.Stat(expect); err != nil {
t.Fatal(err)
}
// In the second pass, we want to remove the chart's request dependency,
// then see if it restores from the lock.
lockfile := hh.Path(chartname, "Chart.lock")
lockfile := filepath.Join(helmpath.DataPath(), chartname, "Chart.lock")
if _, err := os.Stat(lockfile); err != nil {
t.Fatal(err)
}
@ -79,7 +82,7 @@ func TestDependencyBuildCmd(t *testing.T) {
}
// Now repeat the test that the dependency exists.
expect = hh.Path(chartname, "charts/reqtest-0.1.0.tgz")
expect = filepath.Join(helmpath.DataPath(), chartname, "charts/reqtest-0.1.0.tgz")
if _, err := os.Stat(expect); err != nil {
t.Fatal(err)
}
@ -90,7 +93,7 @@ func TestDependencyBuildCmd(t *testing.T) {
t.Fatal(err)
}
i, err := repo.LoadIndexFile(hh.CacheIndex("test"))
i, err := repo.LoadIndexFile(helmpath.CacheIndex("test"))
if err != nil {
t.Fatal(err)
}

@ -60,7 +60,6 @@ func newDependencyUpdateCmd(out io.Writer) *cobra.Command {
man := &downloader.Manager{
Out: out,
ChartPath: chartpath,
HelmHome: settings.Home,
Keyring: client.Keyring,
SkipUpdate: client.SkipRefresh,
Getters: getter.All(settings),

@ -23,8 +23,10 @@ import (
"strings"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/provenance"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/repo/repotest"
@ -33,10 +35,10 @@ import (
func TestDependencyUpdateCmd(t *testing.T) {
defer resetEnv()()
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
srv := repotest.NewServer(hh.String())
srv := repotest.NewServer(helmpath.ConfigPath())
defer srv.Stop()
copied, err := srv.CopyCharts("testdata/testcharts/*.tgz")
if err != nil {
@ -48,11 +50,11 @@ func TestDependencyUpdateCmd(t *testing.T) {
chartname := "depup"
ch := createTestingMetadata(chartname, srv.URL())
md := ch.Metadata
if err := chartutil.SaveDir(ch, hh.String()); err != nil {
if err := chartutil.SaveDir(ch, helmpath.DataPath()); err != nil {
t.Fatal(err)
}
_, out, err := executeActionCommand(fmt.Sprintf("--home='%s' dependency update '%s'", hh.String(), hh.Path(chartname)))
_, out, err := executeActionCommand(fmt.Sprintf("dependency update '%s'", filepath.Join(helmpath.DataPath(), chartname)))
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
@ -64,7 +66,7 @@ func TestDependencyUpdateCmd(t *testing.T) {
}
// Make sure the actual file got downloaded.
expect := hh.Path(chartname, "charts/reqtest-0.1.0.tgz")
expect := filepath.Join(helmpath.DataPath(), chartname, "charts/reqtest-0.1.0.tgz")
if _, err := os.Stat(expect); err != nil {
t.Fatal(err)
}
@ -74,7 +76,7 @@ func TestDependencyUpdateCmd(t *testing.T) {
t.Fatal(err)
}
i, err := repo.LoadIndexFile(hh.CacheIndex("test"))
i, err := repo.LoadIndexFile(helmpath.CacheIndex("test"))
if err != nil {
t.Fatal(err)
}
@ -90,12 +92,12 @@ func TestDependencyUpdateCmd(t *testing.T) {
{Name: "reqtest", Version: "0.1.0", Repository: srv.URL()},
{Name: "compressedchart", Version: "0.3.0", Repository: srv.URL()},
}
dir := hh.Path(chartname, "Chart.yaml")
dir := filepath.Join(helmpath.DataPath(), chartname, "Chart.yaml")
if err := chartutil.SaveChartfile(dir, md); err != nil {
t.Fatal(err)
}
_, out, err = executeActionCommand(fmt.Sprintf("--home='%s' dependency update '%s'", hh, hh.Path(chartname)))
_, out, err = executeActionCommand(fmt.Sprintf("dependency update '%s'", filepath.Join(helmpath.DataPath(), chartname)))
if err != nil {
t.Logf("Output: %s", out)
t.Fatal(err)
@ -103,11 +105,11 @@ func TestDependencyUpdateCmd(t *testing.T) {
// In this second run, we should see compressedchart-0.3.0.tgz, and not
// the 0.1.0 version.
expect = hh.Path(chartname, "charts/compressedchart-0.3.0.tgz")
expect = filepath.Join(helmpath.DataPath(), chartname, "charts/compressedchart-0.3.0.tgz")
if _, err := os.Stat(expect); err != nil {
t.Fatalf("Expected %q: %s", expect, err)
}
dontExpect := hh.Path(chartname, "charts/compressedchart-0.1.0.tgz")
dontExpect := filepath.Join(helmpath.DataPath(), chartname, "charts/compressedchart-0.1.0.tgz")
if _, err := os.Stat(dontExpect); err == nil {
t.Fatalf("Unexpected %q", dontExpect)
}
@ -116,10 +118,10 @@ func TestDependencyUpdateCmd(t *testing.T) {
func TestDependencyUpdateCmd_SkipRefresh(t *testing.T) {
defer resetEnv()()
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
srv := repotest.NewServer(hh.String())
srv := repotest.NewServer(helmpath.ConfigPath())
defer srv.Stop()
copied, err := srv.CopyCharts("testdata/testcharts/*.tgz")
if err != nil {
@ -129,11 +131,11 @@ func TestDependencyUpdateCmd_SkipRefresh(t *testing.T) {
t.Logf("Listening on directory %s", srv.Root())
chartname := "depup"
if err := createTestingChart(hh.String(), chartname, srv.URL()); err != nil {
if err := createTestingChart(helmpath.DataPath(), chartname, srv.URL()); err != nil {
t.Fatal(err)
}
_, out, err := executeActionCommand(fmt.Sprintf("--home='%s' dependency update --skip-refresh %s", hh, hh.Path(chartname)))
_, out, err := executeActionCommand(fmt.Sprintf("dependency update --skip-refresh %s", filepath.Join(helmpath.DataPath(), chartname)))
if err == nil {
t.Fatal("Expected failure to find the repo with skipRefresh")
}
@ -147,10 +149,10 @@ func TestDependencyUpdateCmd_SkipRefresh(t *testing.T) {
func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
defer resetEnv()()
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
srv := repotest.NewServer(hh.String())
srv := repotest.NewServer(helmpath.ConfigPath())
defer srv.Stop()
copied, err := srv.CopyCharts("testdata/testcharts/*.tgz")
if err != nil {
@ -160,11 +162,11 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
t.Logf("Listening on directory %s", srv.Root())
chartname := "depupdelete"
if err := createTestingChart(hh.String(), chartname, srv.URL()); err != nil {
if err := createTestingChart(helmpath.DataPath(), chartname, srv.URL()); err != nil {
t.Fatal(err)
}
_, output, err := executeActionCommand(fmt.Sprintf("--home='%s' dependency update %s", hh, hh.Path(chartname)))
_, output, err := executeActionCommand(fmt.Sprintf("dependency update %s", filepath.Join(helmpath.DataPath(), chartname)))
if err != nil {
t.Logf("Output: %s", output)
t.Fatal(err)
@ -173,14 +175,14 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
// Chart repo is down
srv.Stop()
_, output, err = executeActionCommand(fmt.Sprintf("--home='%s' dependency update %s", hh, hh.Path(chartname)))
_, output, err = executeActionCommand(fmt.Sprintf("dependency update %s", filepath.Join(helmpath.DataPath(), chartname)))
if err == nil {
t.Logf("Output: %s", output)
t.Fatal("Expected error, got nil")
}
// Make sure charts dir still has dependencies
files, err := ioutil.ReadDir(filepath.Join(hh.Path(chartname), "charts"))
files, err := ioutil.ReadDir(filepath.Join(filepath.Join(helmpath.DataPath(), chartname), "charts"))
if err != nil {
t.Fatal(err)
}
@ -196,7 +198,7 @@ func TestDependencyUpdateCmd_DontDeleteOldChartsOnError(t *testing.T) {
}
// Make sure tmpcharts is deleted
if _, err := os.Stat(filepath.Join(hh.Path(chartname), "tmpcharts")); !os.IsNotExist(err) {
if _, err := os.Stat(filepath.Join(filepath.Join(helmpath.DataPath(), chartname), "tmpcharts")); !os.IsNotExist(err) {
t.Fatalf("tmpcharts dir still exists")
}
}

@ -30,10 +30,8 @@ import (
"helm.sh/helm/internal/test"
"helm.sh/helm/pkg/action"
"helm.sh/helm/pkg/chartutil"
"helm.sh/helm/pkg/helmpath"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/release"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/storage"
"helm.sh/helm/pkg/storage/driver"
)
@ -45,20 +43,10 @@ func init() {
}
func TestMain(m *testing.M) {
os.Unsetenv("HELM_HOME")
exitCode := m.Run()
os.Exit(exitCode)
}
func testTempDir(t *testing.T) string {
t.Helper()
d, err := ioutil.TempDir("", "helm")
if err != nil {
t.Fatal(err)
}
return d
}
func runTestCmd(t *testing.T, tests []cmdTestCase) {
t.Helper()
for _, tt := range tests {
@ -144,48 +132,6 @@ func executeActionCommand(cmd string) (*cobra.Command, string, error) {
return executeActionCommandC(storageFixture(), cmd)
}
// ensureTestHome creates a home directory like ensureHome, but without remote references.
func ensureTestHome(t *testing.T, home helmpath.Home) {
t.Helper()
for _, p := range []string{
home.String(),
home.Repository(),
home.Cache(),
home.Plugins(),
home.Starters(),
} {
if err := os.MkdirAll(p, 0755); err != nil {
t.Fatal(err)
}
}
repoFile := home.RepositoryFile()
if _, err := os.Stat(repoFile); err != nil {
rf := repo.NewFile()
rf.Add(&repo.Entry{
Name: "charts",
URL: "http://example.com/foo",
Cache: "charts-index.yaml",
})
if err := rf.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
if r, err := repo.LoadFile(repoFile); err == repo.ErrRepoOutOfDate {
if err := r.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
}
// testHelmHome sets up a Helm Home in a temp dir.
func testHelmHome(t *testing.T) helmpath.Home {
t.Helper()
dir := helmpath.Home(testTempDir(t))
ensureTestHome(t, dir)
return dir
}
func resetEnv() func() {
origSettings, origEnv := settings, os.Environ()
return func() {

@ -1,52 +0,0 @@
/*
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 main
import (
"fmt"
"io"
"github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require"
)
var longHomeHelp = `
This command displays the location of HELM_HOME. This is where
any helm configuration files live.
`
func newHomeCmd(out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "home",
Short: "displays the location of HELM_HOME",
Long: longHomeHelp,
Args: require.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
h := settings.Home
fmt.Fprintln(out, h)
if settings.Debug {
fmt.Fprintf(out, "Repository: %s\n", h.Repository())
fmt.Fprintf(out, "RepositoryFile: %s\n", h.RepositoryFile())
fmt.Fprintf(out, "Cache: %s\n", h.Cache())
fmt.Fprintf(out, "Starters: %s\n", h.Starters())
fmt.Fprintf(out, "Plugins: %s\n", h.Plugins())
}
},
}
return cmd
}

@ -35,14 +35,28 @@ import (
)
const initDesc = `
This command sets up local configuration in $HELM_HOME (default ~/.helm/).
This command sets up local configuration.
Helm stores configuration based on the XDG base directory specification, so
- cached files are stored in $XDG_CACHE_HOME/helm
- configuration is stored in $XDG_CONFIG_HOME/helm
- data is stored in $XDG_DATA_HOME/helm
By default, the default directories depend on the Operating System. The defaults are listed below:
+------------------+---------------------------+--------------------------------+-------------------------+
| Operating System | Cache Path | Configuration Path | Data Path |
+------------------+---------------------------+--------------------------------+-------------------------+
| Linux | $HOME/.cache/helm | $HOME/.config/helm | $HOME/.local/share/helm |
| macOS | $HOME/Library/Caches/helm | $HOME/Library/Preferences/helm | $HOME/Library/helm |
| Windows | %TEMP%\helm | %APPDATA%\helm | %APPDATA%\helm |
+------------------+---------------------------+--------------------------------+-------------------------+
`
type initOptions struct {
skipRefresh bool // --skip-refresh
pluginsFilename string // --plugins
home helmpath.Home
}
type pluginsFileEntry struct {
@ -63,7 +77,6 @@ func newInitCmd(out io.Writer) *cobra.Command {
Long: initDesc,
Args: require.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
o.home = settings.Home
return o.run(out)
},
}
@ -77,13 +90,13 @@ func newInitCmd(out io.Writer) *cobra.Command {
// run initializes local config.
func (o *initOptions) run(out io.Writer) error {
if err := ensureDirectories(o.home, out); err != nil {
if err := ensureDirectories(out); err != nil {
return err
}
if err := ensureReposFile(o.home, out, o.skipRefresh); err != nil {
if err := ensureReposFile(out, o.skipRefresh); err != nil {
return err
}
if err := ensureRepoFileFormat(o.home.RepositoryFile(), out); err != nil {
if err := ensureRepoFileFormat(helmpath.RepositoryFile(), out); err != nil {
return err
}
if o.pluginsFilename != "" {
@ -91,24 +104,29 @@ func (o *initOptions) run(out io.Writer) error {
return err
}
}
fmt.Fprintf(out, "$HELM_HOME has been configured at %s.\n", settings.Home)
fmt.Fprintln(out, "Helm is now configured to use the following directories:")
fmt.Fprintf(out, "Cache: %s\n", helmpath.CachePath())
fmt.Fprintf(out, "Configuration: %s\n", helmpath.ConfigPath())
fmt.Fprintf(out, "Data: %s\n", helmpath.DataPath())
fmt.Fprintln(out, "Happy Helming!")
return nil
}
// ensureDirectories checks to see if $HELM_HOME exists.
// ensureDirectories checks to see if the directories Helm uses exists.
//
// If $HELM_HOME does not exist, this function will create it.
func ensureDirectories(home helmpath.Home, out io.Writer) error {
configDirectories := []string{
home.String(),
home.Repository(),
home.Cache(),
home.Plugins(),
home.Starters(),
home.Archive(),
// If they do not exist, this function will create it.
func ensureDirectories(out io.Writer) error {
directories := []string{
helmpath.CachePath(),
helmpath.ConfigPath(),
helmpath.DataPath(),
helmpath.RepositoryCache(),
helmpath.Plugins(),
helmpath.PluginCache(),
helmpath.Starters(),
helmpath.Archive(),
}
for _, p := range configDirectories {
for _, p := range directories {
if fi, err := os.Stat(p); err != nil {
fmt.Fprintf(out, "Creating %s \n", p)
if err := os.MkdirAll(p, 0755); err != nil {
@ -122,8 +140,8 @@ func ensureDirectories(home helmpath.Home, out io.Writer) error {
return nil
}
func ensureReposFile(home helmpath.Home, out io.Writer, skipRefresh bool) error {
repoFile := home.RepositoryFile()
func ensureReposFile(out io.Writer, skipRefresh bool) error {
repoFile := helmpath.RepositoryFile()
if fi, err := os.Stat(repoFile); err != nil {
fmt.Fprintf(out, "Creating %s \n", repoFile)
f := repo.NewFile()
@ -168,7 +186,7 @@ func ensurePluginsInstalled(pluginsFilename string, out io.Writer) error {
}
func ensurePluginInstalled(requiredPlugin *pluginsFileEntry, pluginsFilename string, out io.Writer) error {
i, err := installer.NewForSource(requiredPlugin.URL, requiredPlugin.Version, settings.Home)
i, err := installer.NewForSource(requiredPlugin.URL, requiredPlugin.Version)
if err != nil {
return err
}

@ -21,33 +21,34 @@ import (
"os"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
)
const testPluginsFile = "testdata/plugins.yaml"
func TestEnsureHome(t *testing.T) {
hh := helmpath.Home(testTempDir(t))
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
b := bytes.NewBuffer(nil)
settings.Home = hh
if err := ensureDirectories(hh, b); err != nil {
if err := ensureDirectories(b); err != nil {
t.Error(err)
}
if err := ensureReposFile(hh, b, false); err != nil {
if err := ensureReposFile(b, false); err != nil {
t.Error(err)
}
if err := ensureReposFile(hh, b, true); err != nil {
if err := ensureReposFile(b, true); err != nil {
t.Error(err)
}
if err := ensureRepoFileFormat(hh.RepositoryFile(), b); err != nil {
if err := ensureRepoFileFormat(helmpath.RepositoryFile(), b); err != nil {
t.Error(err)
}
if err := ensurePluginsInstalled(testPluginsFile, b); err != nil {
t.Error(err)
}
expectedDirs := []string{hh.String(), hh.Repository(), hh.Cache()}
expectedDirs := []string{helmpath.CachePath(), helmpath.ConfigPath(), helmpath.DataPath()}
for _, dir := range expectedDirs {
if fi, err := os.Stat(dir); err != nil {
t.Errorf("%s", err)
@ -56,13 +57,13 @@ func TestEnsureHome(t *testing.T) {
}
}
if fi, err := os.Stat(hh.RepositoryFile()); err != nil {
if fi, err := os.Stat(helmpath.RepositoryFile()); err != nil {
t.Error(err)
} else if fi.IsDir() {
t.Errorf("%s should not be a directory", fi)
}
if plugins, err := findPlugins(settings.PluginDirs()); err != nil {
if plugins, err := findPlugins(helmpath.Plugins()); err != nil {
t.Error(err)
} else if len(plugins) != 1 {
t.Errorf("Expected 1 plugin, got %d", len(plugins))

@ -195,7 +195,6 @@ func runInstall(args []string, client *action.Install, out io.Writer) (*release.
man := &downloader.Manager{
Out: out,
ChartPath: cp,
HelmHome: settings.Home,
Keyring: client.ChartPathOptions.Keyring,
SkipUpdate: false,
Getters: getter.All(settings),

@ -26,6 +26,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/plugin"
)
@ -41,8 +42,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
return
}
// debug("HELM_PLUGIN_DIRS=%s", settings.PluginDirs())
found, err := findPlugins(settings.PluginDirs())
found, err := findPlugins(helmpath.Plugins())
if err != nil {
fmt.Fprintf(os.Stderr, "failed to load plugins: %s", err)
return
@ -113,7 +113,7 @@ func loadPlugins(baseCmd *cobra.Command, out io.Writer) {
func manuallyProcessArgs(args []string) ([]string, []string) {
known := []string{}
unknown := []string{}
kvargs := []string{"--context", "--home", "--namespace"}
kvargs := []string{"--context", "--namespace"}
knownArg := func(a string) bool {
for _, pre := range kvargs {
if strings.HasPrefix(a, pre+"=") {
@ -126,7 +126,7 @@ func manuallyProcessArgs(args []string) ([]string, []string) {
switch a := args[i]; a {
case "--debug":
known = append(known, a)
case "--context", "--home", "--namespace":
case "--context", "--namespace":
known = append(known, a, args[i+1])
i++
default:

@ -74,7 +74,6 @@ func newPackageCmd(out io.Writer) *cobra.Command {
downloadManager := &downloader.Manager{
Out: ioutil.Discard,
ChartPath: path,
HelmHome: settings.Home,
Keyring: client.Keyring,
Getters: getter.All(settings),
Debug: settings.Debug,

@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chart/loader"
"helm.sh/helm/pkg/chartutil"
@ -137,19 +138,16 @@ func TestPackage(t *testing.T) {
if err != nil {
t.Fatal(err)
}
tmp := testTempDir(t)
t.Logf("Running tests in %s", tmp)
defer testChdir(t, tmp)()
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
t.Logf("Running tests in %s", helmpath.CachePath())
defer testChdir(t, helmpath.CachePath())()
if err := os.Mkdir("toot", 0777); err != nil {
t.Fatal(err)
}
ensureTestHome(t, helmpath.Home(tmp))
settings.Home = helmpath.Home(tmp)
for _, tt := range tests {
buf := bytes.NewBuffer(nil)
c := newPackageCmd(buf)
@ -203,14 +201,13 @@ func TestSetAppVersion(t *testing.T) {
var ch *chart.Chart
expectedAppVersion := "app-version-foo"
tmp := testTempDir(t)
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
c := newPackageCmd(&bytes.Buffer{})
flags := map[string]string{
"destination": tmp,
"destination": helmpath.CachePath(),
"app-version": expectedAppVersion,
}
setFlags(c, flags)
@ -218,7 +215,7 @@ func TestSetAppVersion(t *testing.T) {
t.Errorf("unexpected error %q", err)
}
chartPath := filepath.Join(tmp, "alpine-0.1.0.tgz")
chartPath := filepath.Join(helmpath.CachePath(), "alpine-0.1.0.tgz")
if fi, err := os.Stat(chartPath); err != nil {
t.Errorf("expected file %q, got err %q", chartPath, err)
} else if fi.Size() == 0 {
@ -270,8 +267,8 @@ func TestPackageValues(t *testing.T) {
},
}
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
for _, tc := range testCases {
var files []string
@ -292,7 +289,7 @@ func TestPackageValues(t *testing.T) {
func runAndVerifyPackageCommandValues(t *testing.T, args []string, flags map[string]string, valueFiles string, expected chartutil.Values) {
t.Helper()
outputDir := testTempDir(t)
outputDir := ensure.TempDir(t)
if len(flags) == 0 {
flags = make(map[string]string)
@ -321,7 +318,7 @@ func runAndVerifyPackageCommandValues(t *testing.T, args []string, flags map[str
}
func createValuesFile(t *testing.T, data string) string {
outputDir := testTempDir(t)
outputDir := ensure.TempDir(t)
outputFile := filepath.Join(outputDir, "values.yaml")
if err := ioutil.WriteFile(outputFile, []byte(data), 0755); err != nil {

@ -0,0 +1,79 @@
/*
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 main
import (
"fmt"
"io"
"github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/helmpath"
)
var longPathHelp = `
This command displays the locations where Helm stores files.
To display a specific location, use 'helm path [config|data|cache]'.
`
var pathArgMap = map[string]string{
"config": helmpath.ConfigPath(),
"data": helmpath.DataPath(),
"cache": helmpath.CachePath(),
}
func newPathCmd(out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "path",
Short: "displays the locations where Helm stores files",
Aliases: []string{"home"},
Long: longPathHelp,
Args: require.MinimumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
if p, ok := pathArgMap[args[0]]; ok {
fmt.Fprintln(out, p)
} else {
var validArgs []string
for arg := range pathArgMap {
validArgs = append(validArgs, arg)
}
return fmt.Errorf("invalid argument '%s'. Must be one of: %s", args[0], validArgs)
}
} else {
// NOTE(bacongobbler): the order here is important: we want to display the config path
// first so users can parse the first line to replicate Helm 2's `helm home`.
fmt.Fprintln(out, helmpath.ConfigPath())
fmt.Fprintln(out, helmpath.DataPath())
fmt.Fprintln(out, helmpath.CachePath())
if settings.Debug {
fmt.Fprintf(out, "Archive: %s\n", helmpath.Archive())
fmt.Fprintf(out, "PluginCache: %s\n", helmpath.PluginCache())
fmt.Fprintf(out, "Plugins: %s\n", helmpath.Plugins())
fmt.Fprintf(out, "Registry: %s\n", helmpath.Registry())
fmt.Fprintf(out, "RepositoryCache: %s\n", helmpath.RepositoryCache())
fmt.Fprintf(out, "RepositoryFile: %s\n", helmpath.RepositoryFile())
fmt.Fprintf(out, "Starters: %s\n", helmpath.Starters())
}
}
return nil
},
}
return cmd
}

@ -22,7 +22,6 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/plugin"
"helm.sh/helm/pkg/plugin/installer"
)
@ -30,7 +29,6 @@ import (
type pluginInstallOptions struct {
source string
version string
home helmpath.Home
}
const pluginInstallDesc = `
@ -60,14 +58,13 @@ func newPluginInstallCmd(out io.Writer) *cobra.Command {
func (o *pluginInstallOptions) complete(args []string) error {
o.source = args[0]
o.home = settings.Home
return nil
}
func (o *pluginInstallOptions) run(out io.Writer) error {
installer.Debug = settings.Debug
i, err := installer.NewForSource(o.source, o.version, o.home)
i, err := installer.NewForSource(o.source, o.version)
if err != nil {
return err
}

@ -25,35 +25,25 @@ import (
"helm.sh/helm/pkg/helmpath"
)
type pluginListOptions struct {
home helmpath.Home
}
func newPluginListCmd(out io.Writer) *cobra.Command {
o := &pluginListOptions{}
cmd := &cobra.Command{
Use: "list",
Short: "list installed Helm plugins",
RunE: func(cmd *cobra.Command, args []string) error {
o.home = settings.Home
return o.run(out)
debug("pluginDirs: %s", helmpath.Plugins())
plugins, err := findPlugins(helmpath.Plugins())
if err != nil {
return err
}
table := uitable.New()
table.AddRow("NAME", "VERSION", "DESCRIPTION")
for _, p := range plugins {
table.AddRow(p.Metadata.Name, p.Metadata.Version, p.Metadata.Description)
}
fmt.Fprintln(out, table)
return nil
},
}
return cmd
}
func (o *pluginListOptions) run(out io.Writer) error {
debug("pluginDirs: %s", settings.PluginDirs())
plugins, err := findPlugins(settings.PluginDirs())
if err != nil {
return err
}
table := uitable.New()
table.AddRow("NAME", "VERSION", "DESCRIPTION")
for _, p := range plugins {
table.AddRow(p.Metadata.Name, p.Metadata.Version, p.Metadata.Description)
}
fmt.Fprintln(out, table)
return nil
}

@ -30,7 +30,6 @@ import (
type pluginRemoveOptions struct {
names []string
home helmpath.Home
}
func newPluginRemoveCmd(out io.Writer) *cobra.Command {
@ -53,13 +52,12 @@ func (o *pluginRemoveOptions) complete(args []string) error {
return errors.New("please provide plugin name to remove")
}
o.names = args
o.home = settings.Home
return nil
}
func (o *pluginRemoveOptions) run(out io.Writer) error {
debug("loading installed plugins from %s", settings.PluginDirs())
plugins, err := findPlugins(settings.PluginDirs())
debug("loading installed plugins from %s", helmpath.Plugins())
plugins, err := findPlugins(helmpath.Plugins())
if err != nil {
return err
}

@ -26,6 +26,7 @@ import (
"github.com/spf13/cobra"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
"helm.sh/helm/pkg/plugin"
)
@ -39,11 +40,11 @@ func TestManuallyProcessArgs(t *testing.T) {
}
expectKnown := []string{
"--debug", "--context", "test1", "--home=/tmp",
"--debug", "--context", "test1",
}
expectUnknown := []string{
"--foo", "bar", "command",
"--foo", "bar", "--home=/tmp", "command",
}
known, unknown := manuallyProcessArgs(input)
@ -64,10 +65,9 @@ func TestManuallyProcessArgs(t *testing.T) {
func TestLoadPlugins(t *testing.T) {
defer resetEnv()()
settings.Home = "testdata/helmhome"
os.Setenv("HELM_HOME", settings.Home.String())
hh := settings.Home
os.Setenv(xdg.CacheHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.ConfigHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.DataHomeEnvVar, "testdata/helmhome")
out := bytes.NewBuffer(nil)
cmd := &cobra.Command{}
@ -75,12 +75,13 @@ func TestLoadPlugins(t *testing.T) {
envs := strings.Join([]string{
"fullenv",
hh.Plugins() + "/fullenv",
hh.Plugins(),
hh.String(),
hh.Repository(),
hh.RepositoryFile(),
hh.Cache(),
helmpath.Plugins() + "/fullenv",
helmpath.Plugins(),
helmpath.CachePath(),
helmpath.ConfigPath(),
helmpath.DataPath(),
helmpath.RepositoryFile(),
helmpath.RepositoryCache(),
os.Args[0],
}, "\n")
@ -94,7 +95,7 @@ func TestLoadPlugins(t *testing.T) {
}{
{"args", "echo args", "This echos args", "-a -b -c\n", []string{"-a", "-b", "-c"}},
{"echo", "echo stuff", "This echos stuff", "hello\n", []string{}},
{"env", "env stuff", "show the env", hh.String() + "\n", []string{}},
{"env", "env stuff", "show the env", helmpath.DataPath() + "\n", []string{}},
{"fullenv", "show env vars", "show all env vars", envs + "\n", []string{}},
}
@ -134,7 +135,7 @@ func TestLoadPlugins(t *testing.T) {
func TestLoadPlugins_HelmNoPlugins(t *testing.T) {
defer resetEnv()()
settings.Home = "testdata/helmhome"
os.Setenv(xdg.DataHomeEnvVar, "testdata/helmhome")
os.Setenv("HELM_NO_PLUGINS", "1")
@ -151,8 +152,8 @@ func TestLoadPlugins_HelmNoPlugins(t *testing.T) {
func TestSetupEnv(t *testing.T) {
defer resetEnv()()
name := "pequod"
settings.Home = helmpath.Home("testdata/helmhome")
base := filepath.Join(settings.Home.Plugins(), name)
os.Setenv(xdg.DataHomeEnvVar, "testdata/helmhome")
base := filepath.Join(helmpath.Plugins(), name)
settings.Debug = true
defer func() {
settings.Debug = false
@ -165,13 +166,13 @@ func TestSetupEnv(t *testing.T) {
}{
{"HELM_PLUGIN_NAME", name},
{"HELM_PLUGIN_DIR", base},
{"HELM_PLUGIN", settings.Home.Plugins()},
{"HELM_DEBUG", "1"},
{"HELM_HOME", settings.Home.String()},
{"HELM_PATH_REPOSITORY", settings.Home.Repository()},
{"HELM_PATH_REPOSITORY_FILE", settings.Home.RepositoryFile()},
{"HELM_PATH_CACHE", settings.Home.Cache()},
{"HELM_PATH_STARTER", settings.Home.Starters()},
{"HELM_PATH_REPOSITORY_FILE", helmpath.RepositoryFile()},
{"HELM_PATH_CACHE", helmpath.CachePath()},
{"HELM_PATH_CONFIG", helmpath.ConfigPath()},
{"HELM_PATH_DATA", helmpath.DataPath()},
{"HELM_PATH_STARTER", helmpath.Starters()},
{"HELM_PLUGIN", helmpath.Plugins()},
} {
if got := os.Getenv(tt.name); got != tt.expect {
t.Errorf("Expected $%s=%q, got %q", tt.name, tt.expect, got)

@ -31,7 +31,6 @@ import (
type pluginUpdateOptions struct {
names []string
home helmpath.Home
}
func newPluginUpdateCmd(out io.Writer) *cobra.Command {
@ -54,14 +53,13 @@ func (o *pluginUpdateOptions) complete(args []string) error {
return errors.New("please provide plugin name to update")
}
o.names = args
o.home = settings.Home
return nil
}
func (o *pluginUpdateOptions) run(out io.Writer) error {
installer.Debug = settings.Debug
debug("loading installed plugins from %s", settings.PluginDirs())
plugins, err := findPlugins(settings.PluginDirs())
debug("loading installed plugins from %s", helmpath.Plugins())
plugins, err := findPlugins(helmpath.Plugins())
if err != nil {
return err
}
@ -69,7 +67,7 @@ func (o *pluginUpdateOptions) run(out io.Writer) error {
for _, name := range o.names {
if found := findPlugin(plugins, name); found != nil {
if err := updatePlugin(found, o.home); err != nil {
if err := updatePlugin(found); err != nil {
errorPlugins = append(errorPlugins, fmt.Sprintf("Failed to update plugin %s, got error (%v)", name, err))
} else {
fmt.Fprintf(out, "Updated plugin: %s\n", name)
@ -84,7 +82,7 @@ func (o *pluginUpdateOptions) run(out io.Writer) error {
return nil
}
func updatePlugin(p *plugin.Plugin, home helmpath.Home) error {
func updatePlugin(p *plugin.Plugin) error {
exactLocation, err := filepath.EvalSymlinks(p.Dir)
if err != nil {
return err
@ -94,7 +92,7 @@ func updatePlugin(p *plugin.Plugin, home helmpath.Home) error {
return err
}
i, err := installer.FindSource(absExactLocation, home)
i, err := installer.FindSource(absExactLocation)
if err != nil {
return err
}

@ -24,19 +24,27 @@ import (
"strings"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/repo/repotest"
)
func TestPullCmd(t *testing.T) {
defer resetEnv()()
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
hh := testHelmHome(t)
settings.Home = hh
srv := repotest.NewServer(hh.String())
srv, err := repotest.NewTempServer("testdata/testcharts/*.tgz*")
if err != nil {
t.Fatal(err)
}
defer srv.Stop()
// all flags will get "--home=TMDIR -d outdir" appended.
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
// all flags will get "-d outdir" appended.
tests := []struct {
name string
args []string
@ -117,19 +125,12 @@ func TestPullCmd(t *testing.T) {
},
}
if _, err := srv.CopyCharts("testdata/testcharts/*.tgz*"); err != nil {
t.Fatal(err)
}
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
for _, tt := range tests {
outdir := hh.Path("testout")
outdir := filepath.Join(helmpath.DataPath(), "testout")
os.RemoveAll(outdir)
os.Mkdir(outdir, 0755)
cmd := strings.Join(append(tt.args, "-d", "'"+outdir+"'", "--home", "'"+hh.String()+"'"), " ")
cmd := strings.Join(append(tt.args, "-d", "'"+outdir+"'"), " ")
_, out, err := executeActionCommand("fetch " + cmd)
if err != nil {
if tt.wantError {

@ -34,7 +34,6 @@ type repoAddOptions struct {
url string
username string
password string
home helmpath.Home
noupdate bool
certFile string
@ -52,7 +51,6 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
o.name = args[0]
o.url = args[1]
o.home = settings.Home
return o.run(out)
},
@ -70,15 +68,15 @@ func newRepoAddCmd(out io.Writer) *cobra.Command {
}
func (o *repoAddOptions) run(out io.Writer) error {
if err := addRepository(o.name, o.url, o.username, o.password, o.home, o.certFile, o.keyFile, o.caFile, o.noupdate); err != nil {
if err := addRepository(o.name, o.url, o.username, o.password, o.certFile, o.keyFile, o.caFile, o.noupdate); err != nil {
return err
}
fmt.Fprintf(out, "%q has been added to your repositories\n", o.name)
return nil
}
func addRepository(name, url, username, password string, home helmpath.Home, certFile, keyFile, caFile string, noUpdate bool) error {
f, err := repo.LoadFile(home.RepositoryFile())
func addRepository(name, url, username, password string, certFile, keyFile, caFile string, noUpdate bool) error {
f, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return err
}
@ -87,10 +85,8 @@ func addRepository(name, url, username, password string, home helmpath.Home, cer
return errors.Errorf("repository name (%s) already exists, please specify a different name", name)
}
cif := home.CacheIndex(name)
c := repo.Entry{
Name: name,
Cache: cif,
URL: url,
Username: username,
Password: password,
@ -104,11 +100,11 @@ func addRepository(name, url, username, password string, home helmpath.Home, cer
return err
}
if err := r.DownloadIndexFile(home.Cache()); err != nil {
if err := r.DownloadIndexFile(); err != nil {
return errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", url)
}
f.Update(&c)
return f.WriteFile(home.RepositoryFile(), 0644)
return f.WriteFile(helmpath.RepositoryFile(), 0644)
}

@ -21,6 +21,8 @@ import (
"os"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/repo/repotest"
)
@ -28,21 +30,35 @@ import (
func TestRepoAddCmd(t *testing.T) {
defer resetEnv()()
srv, hh, err := repotest.NewTempServer("testdata/testserver/*.*")
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
srv, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer func() {
srv.Stop()
os.RemoveAll(hh.String())
}()
ensureTestHome(t, hh)
settings.Home = hh
defer srv.Stop()
repoFile := helmpath.RepositoryFile()
if _, err := os.Stat(repoFile); err != nil {
rf := repo.NewFile()
rf.Add(&repo.Entry{
Name: "charts",
URL: "http://example.com/foo",
})
if err := rf.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
if r, err := repo.LoadFile(repoFile); err == repo.ErrRepoOutOfDate {
if err := r.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
tests := []cmdTestCase{{
name: "add a repository",
cmd: fmt.Sprintf("repo add test-name %s --home '%s'", srv.URL(), hh),
cmd: fmt.Sprintf("repo add test-name %s", srv.URL()),
golden: "output/repo-add.txt",
}}
@ -52,38 +68,52 @@ func TestRepoAddCmd(t *testing.T) {
func TestRepoAdd(t *testing.T) {
defer resetEnv()()
ts, hh, err := repotest.NewTempServer("testdata/testserver/*.*")
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
ts, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer func() {
ts.Stop()
os.RemoveAll(hh.String())
}()
ensureTestHome(t, hh)
settings.Home = hh
defer ts.Stop()
repoFile := helmpath.RepositoryFile()
if _, err := os.Stat(repoFile); err != nil {
rf := repo.NewFile()
rf.Add(&repo.Entry{
Name: "charts",
URL: "http://example.com/foo",
})
if err := rf.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
if r, err := repo.LoadFile(repoFile); err == repo.ErrRepoOutOfDate {
if err := r.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
const testRepoName = "test-name"
if err := addRepository(testRepoName, ts.URL(), "", "", hh, "", "", "", true); err != nil {
if err := addRepository(testRepoName, ts.URL(), "", "", "", "", "", true); err != nil {
t.Error(err)
}
f, err := repo.LoadFile(hh.RepositoryFile())
f, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
t.Error(err)
}
if !f.Has(testRepoName) {
t.Errorf("%s was not successfully inserted into %s", testRepoName, hh.RepositoryFile())
t.Errorf("%s was not successfully inserted into %s", testRepoName, helmpath.RepositoryFile())
}
if err := addRepository(testRepoName, ts.URL(), "", "", hh, "", "", "", false); err != nil {
if err := addRepository(testRepoName, ts.URL(), "", "", "", "", "", false); err != nil {
t.Errorf("Repository was not updated: %s", err)
}
if err := addRepository(testRepoName, ts.URL(), "", "", hh, "", "", "", false); err != nil {
if err := addRepository(testRepoName, ts.URL(), "", "", "", "", "", false); err != nil {
t.Errorf("Duplicate repository name was added")
}
}

@ -23,12 +23,13 @@ import (
"path/filepath"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/repo"
)
func TestRepoIndexCmd(t *testing.T) {
dir := testTempDir(t)
dir := ensure.TempDir(t)
comp := filepath.Join(dir, "compressedchart-0.1.0.tgz")
if err := linkOrCopy("testdata/testcharts/compressedchart-0.1.0.tgz", comp); err != nil {

@ -29,39 +29,28 @@ import (
"helm.sh/helm/pkg/repo"
)
type repoListOptions struct {
home helmpath.Home
}
func newRepoListCmd(out io.Writer) *cobra.Command {
o := &repoListOptions{}
cmd := &cobra.Command{
Use: "list",
Short: "list chart repositories",
Args: require.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
o.home = settings.Home
return o.run(out)
f, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return err
}
if len(f.Repositories) == 0 {
return errors.New("no repositories to show")
}
table := uitable.New()
table.AddRow("NAME", "URL")
for _, re := range f.Repositories {
table.AddRow(re.Name, re.URL)
}
fmt.Fprintln(out, table)
return nil
},
}
return cmd
}
func (o *repoListOptions) run(out io.Writer) error {
f, err := repo.LoadFile(o.home.RepositoryFile())
if err != nil {
return err
}
if len(f.Repositories) == 0 {
return errors.New("no repositories to show")
}
table := uitable.New()
table.AddRow("NAME", "URL")
for _, re := range f.Repositories {
table.AddRow(re.Name, re.URL)
}
fmt.Fprintln(out, table)
return nil
}

@ -29,36 +29,22 @@ import (
"helm.sh/helm/pkg/repo"
)
type repoRemoveOptions struct {
name string
home helmpath.Home
}
func newRepoRemoveCmd(out io.Writer) *cobra.Command {
o := &repoRemoveOptions{}
cmd := &cobra.Command{
Use: "remove [NAME]",
Aliases: []string{"rm"},
Short: "remove a chart repository",
Args: require.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
o.name = args[0]
o.home = settings.Home
return o.run(out)
return removeRepoLine(out, args[0])
},
}
return cmd
}
func (r *repoRemoveOptions) run(out io.Writer) error {
return removeRepoLine(out, r.name, r.home)
}
func removeRepoLine(out io.Writer, name string, home helmpath.Home) error {
repoFile := home.RepositoryFile()
func removeRepoLine(out io.Writer, name string) error {
repoFile := helmpath.RepositoryFile()
r, err := repo.LoadFile(repoFile)
if err != nil {
return err
@ -71,7 +57,7 @@ func removeRepoLine(out io.Writer, name string, home helmpath.Home) error {
return err
}
if err := removeRepoCache(name, home); err != nil {
if err := removeRepoCache(name); err != nil {
return err
}
@ -80,9 +66,9 @@ func removeRepoLine(out io.Writer, name string, home helmpath.Home) error {
return nil
}
func removeRepoCache(name string, home helmpath.Home) error {
if _, err := os.Stat(home.CacheIndex(name)); err == nil {
err = os.Remove(home.CacheIndex(name))
func removeRepoCache(name string) error {
if _, err := os.Stat(helmpath.CacheIndex(name)); err == nil {
err = os.Remove(helmpath.CacheIndex(name))
if err != nil {
return err
}

@ -22,6 +22,8 @@ import (
"strings"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/repo/repotest"
)
@ -29,44 +31,58 @@ import (
func TestRepoRemove(t *testing.T) {
defer resetEnv()()
ts, hh, err := repotest.NewTempServer("testdata/testserver/*.*")
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
ts, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer func() {
ts.Stop()
os.RemoveAll(hh.String())
}()
ensureTestHome(t, hh)
settings.Home = hh
defer ts.Stop()
repoFile := helmpath.RepositoryFile()
if _, err := os.Stat(repoFile); err != nil {
rf := repo.NewFile()
rf.Add(&repo.Entry{
Name: "charts",
URL: "http://example.com/foo",
})
if err := rf.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
if r, err := repo.LoadFile(repoFile); err == repo.ErrRepoOutOfDate {
if err := r.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
const testRepoName = "test-name"
b := bytes.NewBuffer(nil)
if err := removeRepoLine(b, testRepoName, hh); err == nil {
if err := removeRepoLine(b, testRepoName); err == nil {
t.Errorf("Expected error removing %s, but did not get one.", testRepoName)
}
if err := addRepository(testRepoName, ts.URL(), "", "", hh, "", "", "", true); err != nil {
if err := addRepository(testRepoName, ts.URL(), "", "", "", "", "", true); err != nil {
t.Error(err)
}
mf, _ := os.Create(hh.CacheIndex(testRepoName))
mf, _ := os.Create(helmpath.CacheIndex(testRepoName))
mf.Close()
b.Reset()
if err := removeRepoLine(b, testRepoName, hh); err != nil {
if err := removeRepoLine(b, testRepoName); err != nil {
t.Errorf("Error removing %s from repositories", testRepoName)
}
if !strings.Contains(b.String(), "has been removed") {
t.Errorf("Unexpected output: %s", b.String())
}
if _, err := os.Stat(hh.CacheIndex(testRepoName)); err == nil {
if _, err := os.Stat(helmpath.CacheIndex(testRepoName)); err == nil {
t.Errorf("Error cache file was not removed for repository %s", testRepoName)
}
f, err := repo.LoadFile(hh.RepositoryFile())
f, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
t.Error(err)
}

@ -41,8 +41,7 @@ future releases.
var errNoRepositories = errors.New("no repositories found. You must add one before updating")
type repoUpdateOptions struct {
update func([]*repo.ChartRepository, io.Writer, helmpath.Home)
home helmpath.Home
update func([]*repo.ChartRepository, io.Writer)
}
func newRepoUpdateCmd(out io.Writer) *cobra.Command {
@ -55,7 +54,6 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command {
Long: updateDesc,
Args: require.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
o.home = settings.Home
return o.run(out)
},
}
@ -63,7 +61,7 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command {
}
func (o *repoUpdateOptions) run(out io.Writer) error {
f, err := repo.LoadFile(o.home.RepositoryFile())
f, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return err
}
@ -80,18 +78,18 @@ func (o *repoUpdateOptions) run(out io.Writer) error {
repos = append(repos, r)
}
o.update(repos, out, o.home)
o.update(repos, out)
return nil
}
func updateCharts(repos []*repo.ChartRepository, out io.Writer, home helmpath.Home) {
func updateCharts(repos []*repo.ChartRepository, out io.Writer) {
fmt.Fprintln(out, "Hang tight while we grab the latest from your chart repositories...")
var wg sync.WaitGroup
for _, re := range repos {
wg.Add(1)
go func(re *repo.ChartRepository) {
defer wg.Done()
if err := re.DownloadIndexFile(home.Cache()); err != nil {
if err := re.DownloadIndexFile(); err != nil {
fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", re.Config.Name, re.Config.URL, err)
} else {
fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", re.Config.Name)

@ -23,8 +23,10 @@ import (
"strings"
"testing"
"helm.sh/helm/pkg/getter"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/getter"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/repo/repotest"
)
@ -32,20 +34,36 @@ import (
func TestUpdateCmd(t *testing.T) {
defer resetEnv()()
hh := testHelmHome(t)
settings.Home = hh
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
repoFile := helmpath.RepositoryFile()
if _, err := os.Stat(repoFile); err != nil {
rf := repo.NewFile()
rf.Add(&repo.Entry{
Name: "charts",
URL: "http://example.com/foo",
})
if err := rf.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
if r, err := repo.LoadFile(repoFile); err == repo.ErrRepoOutOfDate {
if err := r.WriteFile(repoFile, 0644); err != nil {
t.Fatal(err)
}
}
out := bytes.NewBuffer(nil)
// Instead of using the HTTP updater, we provide our own for this test.
// The TestUpdateCharts test verifies the HTTP behavior independently.
updater := func(repos []*repo.ChartRepository, out io.Writer, hh helmpath.Home) {
updater := func(repos []*repo.ChartRepository, out io.Writer) {
for _, re := range repos {
fmt.Fprintln(out, re.Config.Name)
}
}
o := &repoUpdateOptions{
update: updater,
home: hh,
}
if err := o.run(out); err != nil {
t.Fatal(err)
@ -59,29 +77,25 @@ func TestUpdateCmd(t *testing.T) {
func TestUpdateCharts(t *testing.T) {
defer resetEnv()()
ts, hh, err := repotest.NewTempServer("testdata/testserver/*.*")
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
ts, err := repotest.NewTempServer("testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer func() {
ts.Stop()
os.RemoveAll(hh.String())
}()
ensureTestHome(t, hh)
settings.Home = hh
defer ts.Stop()
r, err := repo.NewChartRepository(&repo.Entry{
Name: "charts",
URL: ts.URL(),
Cache: hh.CacheIndex("charts"),
Name: "charts",
URL: ts.URL(),
}, getter.All(settings))
if err != nil {
t.Error(err)
}
b := bytes.NewBuffer(nil)
updateCharts([]*repo.ChartRepository{r}, b, hh)
updateCharts([]*repo.ChartRepository{r}, b)
got := b.String()
if strings.Contains(got, "Unable to get an update") {

@ -26,6 +26,7 @@ import (
"helm.sh/helm/cmd/helm/require"
"helm.sh/helm/pkg/action"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/registry"
)
@ -100,7 +101,9 @@ Common actions from this point include:
- helm list: list releases of charts
Environment:
$HELM_HOME set an alternative location for Helm files. By default, these are stored in ~/.helm
$XDG_CACHE_HOME set an alternative location for storing cached files.
$XDG_CONFIG_HOME set an alternative location for storing Helm configuration.
$XDG_DATA_HOME set an alternative location for storing Helm data.
$HELM_DRIVER set the backend storage driver. Values are: configmap, secret, memory
$HELM_NO_PLUGINS disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins.
$KUBECONFIG set an alternative Kubernetes configuration file (default "~/.kube/config")
@ -127,7 +130,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
// Add the registry client based on settings
// TODO: Move this elsewhere (first, settings.Init() must move)
// TODO: handle errors, dont panic
credentialsFile := filepath.Join(settings.Home.Registry(), registry.CredentialsFileBasename)
credentialsFile := filepath.Join(helmpath.Registry(), registry.CredentialsFileBasename)
client, err := auth.NewClient(credentialsFile)
if err != nil {
panic(err)
@ -145,7 +148,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
Resolver: registry.Resolver{
Resolver: resolver,
},
CacheRootDir: settings.Home.Registry(),
CacheRootDir: helmpath.Registry(),
})
cmd.AddCommand(
@ -177,7 +180,7 @@ func newRootCmd(actionConfig *action.Configuration, out io.Writer, args []string
newUpgradeCmd(actionConfig, out),
newCompletionCmd(out),
newHomeCmd(out),
newPathCmd(out),
newInitCmd(out),
newPluginCmd(out),
newVersionCmd(out),

@ -21,74 +21,77 @@ import (
"path/filepath"
"testing"
"k8s.io/client-go/util/homedir"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
)
func TestRootCmd(t *testing.T) {
defer resetEnv()()
tests := []struct {
name, args, home string
envars map[string]string
name, args, cachePath, configPath, dataPath string
envars map[string]string
}{
{
name: "defaults",
args: "home",
home: filepath.Join(homedir.HomeDir(), ".helm"),
},
{
name: "with --home set",
args: "--home /foo",
home: "/foo",
name: "with $XDG_CACHE_HOME set",
args: "home",
envars: map[string]string{xdg.CacheHomeEnvVar: "/bar"},
cachePath: "/bar/helm",
},
{
name: "subcommands with --home set",
args: "home --home /foo",
home: "/foo",
name: "with $XDG_CONFIG_HOME set",
args: "home",
envars: map[string]string{xdg.ConfigHomeEnvVar: "/bar"},
configPath: "/bar/helm",
},
{
name: "with $HELM_HOME set",
args: "home",
envars: map[string]string{"HELM_HOME": "/bar"},
home: "/bar",
},
{
name: "subcommands with $HELM_HOME set",
args: "home",
envars: map[string]string{"HELM_HOME": "/bar"},
home: "/bar",
},
{
name: "with $HELM_HOME and --home set",
args: "home --home /foo",
envars: map[string]string{"HELM_HOME": "/bar"},
home: "/foo",
name: "with $XDG_DATA_HOME set",
args: "home",
envars: map[string]string{xdg.DataHomeEnvVar: "/bar"},
dataPath: "/bar/helm",
},
}
// ensure not set locally
os.Unsetenv("HELM_HOME")
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer os.Unsetenv("HELM_HOME")
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
for k, v := range tt.envars {
os.Setenv(k, v)
}
cmd, _, err := executeActionCommand(tt.args)
if err != nil {
if _, _, err := executeActionCommand(tt.args); err != nil {
t.Fatalf("unexpected error: %s", err)
}
if settings.Home.String() != tt.home {
t.Errorf("expected home %q, got %q", tt.home, settings.Home)
// NOTE(bacongobbler): we need to check here after calling ensure.HelmHome so we
// load the proper paths after XDG_*_HOME is set
if tt.cachePath == "" {
tt.cachePath = filepath.Join(os.Getenv(xdg.CacheHomeEnvVar), "helm")
}
if tt.configPath == "" {
tt.configPath = filepath.Join(os.Getenv(xdg.ConfigHomeEnvVar), "helm")
}
if tt.dataPath == "" {
tt.dataPath = filepath.Join(os.Getenv(xdg.DataHomeEnvVar), "helm")
}
if helmpath.CachePath() != tt.cachePath {
t.Errorf("expected cache path %q, got %q", tt.cachePath, helmpath.CachePath())
}
if helmpath.ConfigPath() != tt.configPath {
t.Errorf("expected config path %q, got %q", tt.configPath, helmpath.ConfigPath())
}
homeFlag := cmd.Flag("home").Value.String()
homeFlag = os.ExpandEnv(homeFlag)
if homeFlag != tt.home {
t.Errorf("expected home %q, got %q", tt.home, homeFlag)
if helmpath.DataPath() != tt.dataPath {
t.Errorf("expected data path %q, got %q", tt.dataPath, helmpath.DataPath())
}
})
}

@ -42,8 +42,6 @@ Repositories are managed with 'helm repo' commands.
const searchMaxScore = 25
type searchOptions struct {
helmhome helmpath.Home
versions bool
regexp bool
version string
@ -57,7 +55,6 @@ func newSearchCmd(out io.Writer) *cobra.Command {
Short: "search for a keyword in charts",
Long: searchDesc,
RunE: func(cmd *cobra.Command, args []string) error {
o.helmhome = settings.Home
return o.run(out, args)
},
}
@ -141,7 +138,7 @@ func (o *searchOptions) formatSearchResults(res []*search.Result) string {
func (o *searchOptions) buildIndex(out io.Writer) (*search.Index, error) {
// Load the repositories.yaml
rf, err := repo.LoadFile(o.helmhome.RepositoryFile())
rf, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return nil, err
}
@ -149,7 +146,7 @@ func (o *searchOptions) buildIndex(out io.Writer) (*search.Index, error) {
i := search.NewIndex()
for _, re := range rf.Repositories {
n := re.Name
f := o.helmhome.CacheIndex(n)
f := helmpath.CacheIndex(n)
ind, err := repo.LoadIndexFile(f)
if err != nil {
// TODO should print to stderr

@ -17,55 +17,58 @@ limitations under the License.
package main
import (
"os"
"testing"
"helm.sh/helm/pkg/helmpath/xdg"
)
func TestSearchCmd(t *testing.T) {
defer resetEnv()()
setHome := func(cmd string) string {
return cmd + " --home=testdata/helmhome"
}
os.Setenv(xdg.CacheHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.ConfigHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.DataHomeEnvVar, "testdata/helmhome")
tests := []cmdTestCase{{
name: "search for 'maria', expect one match",
cmd: setHome("search maria"),
cmd: "search maria",
golden: "output/search-single.txt",
}, {
name: "search for 'alpine', expect two matches",
cmd: setHome("search alpine"),
cmd: "search alpine",
golden: "output/search-multiple.txt",
}, {
name: "search for 'alpine' with versions, expect three matches",
cmd: setHome("search alpine --versions"),
cmd: "search alpine --versions",
golden: "output/search-multiple-versions.txt",
}, {
name: "search for 'alpine' with version constraint, expect one match with version 0.1.0",
cmd: setHome("search alpine --version '>= 0.1, < 0.2'"),
cmd: "search alpine --version '>= 0.1, < 0.2'",
golden: "output/search-constraint.txt",
}, {
name: "search for 'alpine' with version constraint, expect one match with version 0.1.0",
cmd: setHome("search alpine --versions --version '>= 0.1, < 0.2'"),
cmd: "search alpine --versions --version '>= 0.1, < 0.2'",
golden: "output/search-versions-constraint.txt",
}, {
name: "search for 'alpine' with version constraint, expect one match with version 0.2.0",
cmd: setHome("search alpine --version '>= 0.1'"),
cmd: "search alpine --version '>= 0.1'",
golden: "output/search-constraint-single.txt",
}, {
name: "search for 'alpine' with version constraint and --versions, expect two matches",
cmd: setHome("search alpine --versions --version '>= 0.1'"),
cmd: "search alpine --versions --version '>= 0.1'",
golden: "output/search-multiple-versions-constraints.txt",
}, {
name: "search for 'syzygy', expect no matches",
cmd: setHome("search syzygy"),
cmd: "search syzygy",
golden: "output/search-not-found.txt",
}, {
name: "search for 'alp[a-z]+', expect two matches",
cmd: setHome("search alp[a-z]+ --regexp"),
cmd: "search alp[a-z]+ --regexp",
golden: "output/search-regex.txt",
}, {
name: "search for 'alp[', expect failure to compile regexp",
cmd: setHome("search alp[ --regexp"),
cmd: "search alp[ --regexp",
wantError: true,
}}
runTestCmd(t, tests)

@ -1,4 +1,4 @@
name: env
usage: "env stuff"
description: "show the env"
command: "echo $HELM_HOME"
command: "echo $HELM_PATH_CONFIG"

@ -2,8 +2,9 @@
echo $HELM_PLUGIN_NAME
echo $HELM_PLUGIN_DIR
echo $HELM_PLUGIN
echo $HELM_HOME
echo $HELM_PATH_REPOSITORY
echo $HELM_PATH_REPOSITORY_FILE
echo $HELM_PATH_CACHE
echo $HELM_PATH_CONFIG
echo $HELM_PATH_DATA
echo $HELM_PATH_REPOSITORY_FILE
echo $HELM_PATH_REPOSITORY_CACHE
echo $HELM_BIN

@ -23,6 +23,7 @@ import (
"strings"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/chart/loader"
"helm.sh/helm/pkg/chartutil"
@ -30,7 +31,7 @@ import (
)
func TestUpgradeCmd(t *testing.T) {
tmpChart := testTempDir(t)
tmpChart := ensure.TempDir(t)
cfile := &chart.Chart{
Metadata: &chart.Metadata{
APIVersion: chart.APIVersionV1,
@ -224,7 +225,7 @@ func TestUpgradeWithValuesFile(t *testing.T) {
}
func prepareMockRelease(releaseName string, t *testing.T) (func(n string, v int, ch *chart.Chart) *release.Release, *chart.Chart, string) {
tmpChart := testTempDir(t)
tmpChart := ensure.TempDir(t)
configmapData, err := ioutil.ReadFile("testdata/testcharts/upgradetest/templates/configmap.yaml")
if err != nil {
t.Fatalf("Error loading template yaml %v", err)

@ -0,0 +1,84 @@
/*
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 ensure
import (
"io/ioutil"
"os"
"testing"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
)
// HelmHome sets up a Helm Home in a temp dir.
func HelmHome(t *testing.T) {
t.Helper()
cachePath := TempDir(t)
configPath := TempDir(t)
dataPath := TempDir(t)
os.Setenv(xdg.CacheHomeEnvVar, cachePath)
os.Setenv(xdg.ConfigHomeEnvVar, configPath)
os.Setenv(xdg.DataHomeEnvVar, dataPath)
HomeDirs(t)
}
// HomeDirs creates a home directory like ensureHome, but without remote references.
func HomeDirs(t *testing.T) {
t.Helper()
for _, p := range []string{
helmpath.CachePath(),
helmpath.ConfigPath(),
helmpath.DataPath(),
helmpath.RepositoryCache(),
helmpath.Plugins(),
helmpath.PluginCache(),
helmpath.Starters(),
} {
if err := os.MkdirAll(p, 0755); err != nil {
t.Fatal(err)
}
}
}
// CleanHomeDirs removes the directories created by HomeDirs.
func CleanHomeDirs(t *testing.T) {
t.Helper()
for _, p := range []string{
helmpath.CachePath(),
helmpath.ConfigPath(),
helmpath.DataPath(),
helmpath.RepositoryCache(),
helmpath.Plugins(),
helmpath.PluginCache(),
helmpath.Starters(),
} {
if err := os.RemoveAll(p); err != nil {
t.Log(err)
}
}
}
// TempDir ensures a scratch test directory for unit testing purposes.
func TempDir(t *testing.T) string {
t.Helper()
d, err := ioutil.TempDir("", "helm")
if err != nil {
t.Fatal(err)
}
return d
}

@ -38,6 +38,7 @@ import (
"helm.sh/helm/pkg/downloader"
"helm.sh/helm/pkg/engine"
"helm.sh/helm/pkg/getter"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/hooks"
kubefake "helm.sh/helm/pkg/kube/fake"
"helm.sh/helm/pkg/release"
@ -574,7 +575,6 @@ OUTER:
// Order of resolution:
// - relative to current working directory
// - if path is absolute or begins with '.', error out here
// - chart repos in $HELM_HOME
// - URL
//
// If 'verify' is true, this will attempt to also verify the chart.
@ -598,16 +598,10 @@ func (c *ChartPathOptions) LocateChart(name string, settings cli.EnvSettings) (s
return name, errors.Errorf("path %q not found", name)
}
crepo := filepath.Join(settings.Home.Repository(), name)
if _, err := os.Stat(crepo); err == nil {
return filepath.Abs(crepo)
}
dl := downloader.ChartDownloader{
HelmHome: settings.Home,
Out: os.Stdout,
Keyring: c.Keyring,
Getters: getter.All(settings),
Out: os.Stdout,
Keyring: c.Keyring,
Getters: getter.All(settings),
Options: []getter.Option{
getter.WithBasicAuth(c.Username, c.Password),
},
@ -624,11 +618,11 @@ func (c *ChartPathOptions) LocateChart(name string, settings cli.EnvSettings) (s
name = chartURL
}
if _, err := os.Stat(settings.Home.Archive()); os.IsNotExist(err) {
os.MkdirAll(settings.Home.Archive(), 0744)
if _, err := os.Stat(helmpath.Archive()); os.IsNotExist(err) {
os.MkdirAll(helmpath.Archive(), 0744)
}
filename, _, err := dl.DownloadTo(name, version, settings.Home.Archive())
filename, _, err := dl.DownloadTo(name, version, helmpath.Archive())
if err == nil {
lname, err := filepath.Abs(filename)
if err != nil {

@ -57,11 +57,10 @@ func (p *Pull) Run(chartRef string) (string, error) {
var out strings.Builder
c := downloader.ChartDownloader{
HelmHome: p.Settings.Home,
Out: &out,
Keyring: p.Keyring,
Verify: downloader.VerifyNever,
Getters: getter.All(p.Settings),
Out: &out,
Keyring: p.Keyring,
Verify: downloader.VerifyNever,
Getters: getter.All(p.Settings),
Options: []getter.Option{
getter.WithBasicAuth(p.Username, p.Password),
},

@ -24,21 +24,12 @@ package cli
import (
"os"
"path/filepath"
"github.com/spf13/pflag"
"k8s.io/client-go/util/homedir"
"helm.sh/helm/pkg/helmpath"
)
// defaultHelmHome is the default HELM_HOME.
var defaultHelmHome = filepath.Join(homedir.HomeDir(), ".helm")
// EnvSettings describes all of the environment settings.
type EnvSettings struct {
// Home is the local path to the Helm home directory.
Home helmpath.Home
// Namespace is the namespace scope.
Namespace string
// KubeConfig is the path to the kubeconfig file.
@ -51,7 +42,6 @@ type EnvSettings struct {
// AddFlags binds flags to the given flagset.
func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
fs.StringVar((*string)(&s.Home), "home", defaultHelmHome, "location of your Helm config. Overrides $HELM_HOME")
fs.StringVarP(&s.Namespace, "namespace", "n", "", "namespace scope for this request")
fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to the kubeconfig file")
fs.StringVar(&s.KubeContext, "kube-context", "", "name of the kubeconfig context to use")
@ -65,18 +55,9 @@ func (s *EnvSettings) Init(fs *pflag.FlagSet) {
}
}
// PluginDirs is the path to the plugin directories.
func (s EnvSettings) PluginDirs() string {
if d, ok := os.LookupEnv("HELM_PLUGIN"); ok {
return d
}
return s.Home.Plugins()
}
// envMap maps flag names to envvars
var envMap = map[string]string{
"debug": "HELM_DEBUG",
"home": "HELM_HOME",
"namespace": "HELM_NAMESPACE",
}

@ -22,8 +22,6 @@ import (
"testing"
"github.com/spf13/pflag"
"helm.sh/helm/pkg/helmpath"
)
func TestEnvSettings(t *testing.T) {
@ -35,39 +33,31 @@ func TestEnvSettings(t *testing.T) {
envars map[string]string
// expected values
home, ns, kcontext, plugins string
debug bool
ns, kcontext string
debug bool
}{
{
name: "defaults",
home: defaultHelmHome,
plugins: helmpath.Home(defaultHelmHome).Plugins(),
ns: "",
name: "defaults",
ns: "",
},
{
name: "with flags set",
args: "--home /foo --debug --namespace=myns",
home: "/foo",
plugins: helmpath.Home("/foo").Plugins(),
ns: "myns",
debug: true,
name: "with flags set",
args: "--debug --namespace=myns",
ns: "myns",
debug: true,
},
{
name: "with envvars set",
envars: map[string]string{"HELM_HOME": "/bar", "HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
home: "/bar",
plugins: helmpath.Home("/bar").Plugins(),
ns: "yourns",
debug: true,
name: "with envvars set",
envars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
ns: "yourns",
debug: true,
},
{
name: "with flags and envvars set",
args: "--home /foo --debug --namespace=myns",
envars: map[string]string{"HELM_HOME": "/bar", "HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns", "HELM_PLUGIN": "glade"},
home: "/foo",
plugins: "glade",
ns: "myns",
debug: true,
name: "with flags and envvars set",
args: "--debug --namespace=myns",
envars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns"},
ns: "myns",
debug: true,
},
}
@ -87,12 +77,6 @@ func TestEnvSettings(t *testing.T) {
settings.Init(flags)
if settings.Home != helmpath.Home(tt.home) {
t.Errorf("expected home %q, got %q", tt.home, settings.Home)
}
if settings.PluginDirs() != tt.plugins {
t.Errorf("expected plugins %q, got %q", tt.plugins, settings.PluginDirs())
}
if settings.Debug != tt.debug {
t.Errorf("expected debug %t, got %t", tt.debug, settings.Debug)
}

@ -64,8 +64,6 @@ type ChartDownloader struct {
Verify VerificationStrategy
// Keyring is the keyring file used for verification.
Keyring string
// HelmHome is the $HELM_HOME.
HelmHome helmpath.Home
// Getter collection for the operation
Getters getter.Providers
// Options provide parameters to be passed along to the Getter being initialized.
@ -159,7 +157,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
}
c.Options = append(c.Options, getter.WithURL(ref))
rf, err := repo.LoadFile(c.HelmHome.RepositoryFile())
rf, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return u, err
}
@ -220,7 +218,7 @@ func (c *ChartDownloader) ResolveChartVersion(ref, version string) (*url.URL, er
}
// Next, we need to load the index, and actually look up the chart.
i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(r.Config.Name))
i, err := repo.LoadIndexFile(helmpath.CacheIndex(r.Config.Name))
if err != nil {
return u, errors.Wrap(err, "no cached repo found. (try 'helm repo update')")
}
@ -339,7 +337,7 @@ func (c *ChartDownloader) scanReposForURL(u string, rf *repo.File) (*repo.Entry,
return nil, err
}
i, err := repo.LoadIndexFile(c.HelmHome.CacheIndex(r.Config.Name))
i, err := repo.LoadIndexFile(helmpath.CacheIndex(r.Config.Name))
if err != nil {
return nil, errors.Wrap(err, "no cached repo found. (try 'helm repo update')")
}

@ -16,20 +16,24 @@ limitations under the License.
package downloader
import (
"io/ioutil"
"net/http"
"os"
"path/filepath"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/getter"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
"helm.sh/helm/pkg/repo"
"helm.sh/helm/pkg/repo/repotest"
)
func TestResolveChartRef(t *testing.T) {
os.Setenv(xdg.CacheHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.ConfigHomeEnvVar, "testdata/helmhome")
tests := []struct {
name, ref, expect, version string
fail bool
@ -52,9 +56,8 @@ func TestResolveChartRef(t *testing.T) {
}
c := ChartDownloader{
HelmHome: helmpath.Home("testdata/helmhome"),
Out: os.Stderr,
Getters: getter.All(cli.EnvSettings{}),
Out: os.Stderr,
Getters: getter.All(cli.EnvSettings{}),
}
for _, tt := range tests {
@ -102,97 +105,17 @@ func TestIsTar(t *testing.T) {
}
func TestDownloadTo(t *testing.T) {
tmp, err := ioutil.TempDir("", "helm-downloadto-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
dest := helmpath.CachePath()
hh := helmpath.Home(tmp)
dest := filepath.Join(hh.String(), "dest")
configDirectories := []string{
hh.String(),
hh.Repository(),
hh.Cache(),
dest,
}
for _, p := range configDirectories {
if fi, err := os.Stat(p); err != nil {
if err := os.MkdirAll(p, 0755); err != nil {
t.Fatalf("Could not create %s: %s", p, err)
}
} else if !fi.IsDir() {
t.Fatalf("%s must be a directory", p)
}
}
// Set up a fake repo
srv := repotest.NewServer(tmp)
defer srv.Stop()
// Set up a fake repo with basic auth enabled
srv := repotest.NewServer(helmpath.CachePath())
srv.Stop()
if _, err := srv.CopyCharts("testdata/*.tgz*"); err != nil {
t.Error(err)
return
}
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
c := ChartDownloader{
HelmHome: hh,
Out: os.Stderr,
Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub",
Getters: getter.All(cli.EnvSettings{}),
}
cname := "/signtest-0.1.0.tgz"
where, v, err := c.DownloadTo(srv.URL()+cname, "", dest)
if err != nil {
t.Error(err)
return
}
if expect := filepath.Join(dest, cname); where != expect {
t.Errorf("Expected download to %s, got %s", expect, where)
}
if v.FileHash == "" {
t.Error("File hash was empty, but verification is required.")
}
if _, err := os.Stat(filepath.Join(dest, cname)); err != nil {
t.Error(err)
return
}
}
func TestDownloadTo_WithOptions(t *testing.T) {
tmp, err := ioutil.TempDir("", "helm-downloadto-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
hh := helmpath.Home(tmp)
dest := filepath.Join(hh.String(), "dest")
configDirectories := []string{
hh.String(),
hh.Repository(),
hh.Cache(),
dest,
}
for _, p := range configDirectories {
if fi, err := os.Stat(p); err != nil {
if err := os.MkdirAll(p, 0755); err != nil {
t.Fatalf("Could not create %s: %s", p, err)
}
} else if !fi.IsDir() {
t.Fatalf("%s must be a directory", p)
}
}
// Set up a fake repo with basic auth enabled
srv := repotest.NewServer(tmp)
srv.Stop()
srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok || username != "username" || password != "password" {
@ -201,20 +124,19 @@ func TestDownloadTo_WithOptions(t *testing.T) {
}))
srv.Start()
defer srv.Stop()
if _, err := srv.CopyCharts("testdata/*.tgz*"); err != nil {
t.Error(err)
return
if err := srv.CreateIndex(); err != nil {
t.Fatal(err)
}
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
c := ChartDownloader{
HelmHome: hh,
Out: os.Stderr,
Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub",
Getters: getter.All(cli.EnvSettings{}),
Out: os.Stderr,
Verify: VerifyAlways,
Keyring: "testdata/helm-test-key.pub",
Getters: getter.All(cli.EnvSettings{}),
Options: []getter.Option{
getter.WithBasicAuth("username", "password"),
},
@ -222,8 +144,7 @@ func TestDownloadTo_WithOptions(t *testing.T) {
cname := "/signtest-0.1.0.tgz"
where, v, err := c.DownloadTo(srv.URL()+cname, "", dest)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
if expect := filepath.Join(dest, cname); where != expect {
@ -236,57 +157,34 @@ func TestDownloadTo_WithOptions(t *testing.T) {
if _, err := os.Stat(filepath.Join(dest, cname)); err != nil {
t.Error(err)
return
}
}
func TestDownloadTo_VerifyLater(t *testing.T) {
tmp, err := ioutil.TempDir("", "helm-downloadto-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
hh := helmpath.Home(tmp)
dest := filepath.Join(hh.String(), "dest")
configDirectories := []string{
hh.String(),
hh.Repository(),
hh.Cache(),
dest,
}
for _, p := range configDirectories {
if fi, err := os.Stat(p); err != nil {
if err := os.MkdirAll(p, 0755); err != nil {
t.Fatalf("Could not create %s: %s", p, err)
}
} else if !fi.IsDir() {
t.Fatalf("%s must be a directory", p)
}
}
dest := helmpath.CachePath()
// Set up a fake repo
srv := repotest.NewServer(tmp)
defer srv.Stop()
if _, err := srv.CopyCharts("testdata/*.tgz*"); err != nil {
t.Error(err)
return
srv, err := repotest.NewTempServer("testdata/*.tgz*")
if err != nil {
t.Fatal(err)
}
defer srv.Stop()
if err := srv.LinkIndices(); err != nil {
t.Fatal(err)
}
c := ChartDownloader{
HelmHome: hh,
Out: os.Stderr,
Verify: VerifyLater,
Getters: getter.All(cli.EnvSettings{}),
Out: os.Stderr,
Verify: VerifyLater,
Getters: getter.All(cli.EnvSettings{}),
}
cname := "/signtest-0.1.0.tgz"
where, _, err := c.DownloadTo(srv.URL()+cname, "", dest)
if err != nil {
t.Error(err)
return
t.Fatal(err)
}
if expect := filepath.Join(dest, cname); where != expect {
@ -294,26 +192,25 @@ func TestDownloadTo_VerifyLater(t *testing.T) {
}
if _, err := os.Stat(filepath.Join(dest, cname)); err != nil {
t.Error(err)
return
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(dest, cname+".prov")); err != nil {
t.Error(err)
return
t.Fatal(err)
}
}
func TestScanReposForURL(t *testing.T) {
hh := helmpath.Home("testdata/helmhome")
os.Setenv(xdg.CacheHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.ConfigHomeEnvVar, "testdata/helmhome")
c := ChartDownloader{
HelmHome: hh,
Out: os.Stderr,
Verify: VerifyLater,
Getters: getter.All(cli.EnvSettings{}),
Out: os.Stderr,
Verify: VerifyLater,
Getters: getter.All(cli.EnvSettings{}),
}
u := "http://example.com/alpine-0.2.0.tgz"
rf, err := repo.LoadFile(c.HelmHome.RepositoryFile())
rf, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
t.Fatal(err)
}

@ -16,8 +16,8 @@ limitations under the License.
/*Package downloader provides a library for downloading charts.
This package contains various tools for downloading charts from repository
servers, and then storing them in Helm-specific directory structures (like
HELM_HOME). This library contains many functions that depend on a specific
servers, and then storing them in Helm-specific directory structures. This
library contains many functions that depend on a specific
filesystem layout.
*/
package downloader

@ -46,8 +46,6 @@ type Manager struct {
Out io.Writer
// ChartPath is the path to the unpacked base chart upon which this operates.
ChartPath string
// HelmHome is the $HELM_HOME directory
HelmHome helmpath.Home
// Verification indicates whether the chart should be verified.
Verify VerificationStrategy
// Debug is the global "--debug" flag
@ -170,7 +168,7 @@ func (m *Manager) loadChartDir() (*chart.Chart, error) {
//
// This returns a lock file, which has all of the dependencies normalized to a specific version.
func (m *Manager) resolve(req []*chart.Dependency, repoNames map[string]string) (*chart.Lock, error) {
res := resolver.New(m.ChartPath, m.HelmHome)
res := resolver.New(m.ChartPath)
return res.Resolve(req, repoNames)
}
@ -231,11 +229,10 @@ func (m *Manager) downloadAll(deps []*chart.Dependency) error {
}
dl := ChartDownloader{
Out: m.Out,
Verify: m.Verify,
Keyring: m.Keyring,
HelmHome: m.HelmHome,
Getters: m.Getters,
Out: m.Out,
Verify: m.Verify,
Keyring: m.Keyring,
Getters: m.Getters,
Options: []getter.Option{
getter.WithBasicAuth(username, password),
},
@ -314,7 +311,7 @@ func (m *Manager) safeDeleteDep(name, dir string) error {
// hasAllRepos ensures that all of the referenced deps are in the local repo cache.
func (m *Manager) hasAllRepos(deps []*chart.Dependency) error {
rf, err := repo.LoadFile(m.HelmHome.RepositoryFile())
rf, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return err
}
@ -348,7 +345,7 @@ Loop:
// getRepoNames returns the repo names of the referenced deps which can be used to fetch the cahced index file.
func (m *Manager) getRepoNames(deps []*chart.Dependency) (map[string]string, error) {
rf, err := repo.LoadFile(m.HelmHome.RepositoryFile())
rf, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return nil, err
}
@ -415,7 +412,7 @@ repository, use "https://charts.example.com/" or "@example" instead of
// UpdateRepositories updates all of the local repos to the latest.
func (m *Manager) UpdateRepositories() error {
rf, err := repo.LoadFile(m.HelmHome.RepositoryFile())
rf, err := repo.LoadFile(helmpath.RepositoryFile())
if err != nil {
return err
}
@ -440,7 +437,7 @@ func (m *Manager) parallelRepoUpdate(repos []*repo.Entry) error {
}
wg.Add(1)
go func(r *repo.ChartRepository) {
if err := r.DownloadIndexFile(m.HelmHome.Cache()); err != nil {
if err := r.DownloadIndexFile(); err != nil {
fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", r.Config.Name, r.Config.URL, err)
} else {
fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", r.Config.Name)
@ -552,7 +549,7 @@ func normalizeURL(baseURL, urlOrPath string) (string, error) {
// The key is the local name (which is only present in the repositories.yaml).
func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, error) {
indices := map[string]*repo.ChartRepository{}
repoyaml := m.HelmHome.RepositoryFile()
repoyaml := helmpath.RepositoryFile()
// Load repositories.yaml file
rf, err := repo.LoadFile(repoyaml)
@ -562,8 +559,7 @@ func (m *Manager) loadChartRepositories() (map[string]*repo.ChartRepository, err
for _, re := range rf.Repositories {
lname := re.Name
cacheindex := m.HelmHome.CacheIndex(lname)
index, err := repo.LoadIndexFile(cacheindex)
index, err := repo.LoadIndexFile(helmpath.CacheIndex(lname))
if err != nil {
return indices, err
}

@ -17,11 +17,12 @@ package downloader
import (
"bytes"
"os"
"reflect"
"testing"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
)
func TestVersionEquals(t *testing.T) {
@ -63,10 +64,12 @@ func TestNormalizeURL(t *testing.T) {
}
func TestFindChartURL(t *testing.T) {
os.Setenv(xdg.CacheHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.ConfigHomeEnvVar, "testdata/helmhome")
b := bytes.NewBuffer(nil)
m := &Manager{
Out: b,
HelmHome: helmpath.Home("testdata/helmhome"),
Out: b,
}
repos, err := m.loadChartRepositories()
if err != nil {
@ -93,10 +96,12 @@ func TestFindChartURL(t *testing.T) {
}
func TestGetRepoNames(t *testing.T) {
os.Setenv(xdg.CacheHomeEnvVar, "testdata/helmhome")
os.Setenv(xdg.ConfigHomeEnvVar, "testdata/helmhome")
b := bytes.NewBuffer(nil)
m := &Manager{
Out: b,
HelmHome: helmpath.Home("testdata/helmhome"),
Out: b,
}
tests := []struct {
name string

@ -18,6 +18,9 @@ package getter
import (
"os"
"testing"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/helmpath/xdg"
)
func TestProvider(t *testing.T) {
@ -50,13 +53,9 @@ func TestProviders(t *testing.T) {
}
func TestAll(t *testing.T) {
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
os.Setenv(xdg.DataHomeEnvVar, "testdata")
all := All(env)
all := All(cli.EnvSettings{})
if len(all) != 3 {
t.Errorf("expected 3 providers (default plus two plugins), got %d", len(all))
}
@ -67,15 +66,12 @@ func TestAll(t *testing.T) {
}
func TestByScheme(t *testing.T) {
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
os.Setenv(xdg.DataHomeEnvVar, "testdata")
env := hh(false)
if _, err := ByScheme("test", env); err != nil {
if _, err := ByScheme("test", cli.EnvSettings{}); err != nil {
t.Error(err)
}
if _, err := ByScheme("https", env); err != nil {
if _, err := ByScheme("https", cli.EnvSettings{}); err != nil {
t.Error(err)
}
}

@ -25,13 +25,14 @@ import (
"github.com/pkg/errors"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/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.PluginDirs())
plugins, err := plugin.FindPlugins(helmpath.Plugins())
if err != nil {
return nil, err
}

@ -17,34 +17,18 @@ package getter
import (
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
)
func hh(debug bool) cli.EnvSettings {
apath, err := filepath.Abs("./testdata")
if err != nil {
panic(err)
}
hp := helmpath.Home(apath)
return cli.EnvSettings{
Home: hp,
Debug: debug,
}
}
func TestCollectPlugins(t *testing.T) {
// Reset HELM HOME to testdata.
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
os.Setenv(xdg.DataHomeEnvVar, "testdata")
env := hh(false)
env := cli.EnvSettings{}
p, err := collectPlugins(env)
if err != nil {
t.Fatal(err)
@ -72,11 +56,9 @@ func TestPluginGetter(t *testing.T) {
t.Skip("TODO: refactor this test to work on windows")
}
oldhh := os.Getenv("HELM_HOME")
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
os.Setenv(xdg.DataHomeEnvVar, "testdata")
env := hh(false)
env := cli.EnvSettings{}
pg := NewPluginGetter("echo", env, "test", ".")
g, err := pg()
if err != nil {
@ -104,7 +86,7 @@ func TestPluginSubCommands(t *testing.T) {
defer os.Setenv("HELM_HOME", oldhh)
os.Setenv("HELM_HOME", "")
env := hh(false)
env := cli.EnvSettings{}
pg := NewPluginGetter("echo -n", env, "test", ".")
g, err := pg()
if err != nil {

@ -1,82 +0,0 @@
/*
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 (
"fmt"
"os"
"path/filepath"
)
// Home describes the location of a CLI configuration.
//
// This helper builds paths relative to a Helm Home directory.
type Home string
// String returns Home as a string.
//
// Implements fmt.Stringer.
func (h Home) String() string {
return os.ExpandEnv(string(h))
}
// Path returns Home with elements appended.
func (h Home) Path(elem ...string) string {
p := []string{h.String()}
p = append(p, elem...)
return filepath.Join(p...)
}
// Registry returns the path to the local registry cache.
func (h Home) Registry() string {
return h.Path("registry")
}
// Repository returns the path to the local repository.
func (h Home) Repository() string {
return h.Path("repository")
}
// RepositoryFile returns the path to the repositories.yaml file.
func (h Home) RepositoryFile() string {
return h.Path("repository", "repositories.yaml")
}
// Cache returns the path to the local cache.
func (h Home) Cache() string {
return h.Path("repository", "cache")
}
// CacheIndex returns the path to an index for the given named repository.
func (h Home) CacheIndex(name string) string {
target := fmt.Sprintf("%s-index.yaml", name)
return h.Path("repository", "cache", target)
}
// Starters returns the path to the Helm starter packs.
func (h Home) Starters() string {
return h.Path("starters")
}
// Plugins returns the path to the plugins directory.
func (h Home) Plugins() string {
return h.Path("plugins")
}
// Archive returns the path to download chart archives.
func (h Home) Archive() string {
return h.Path("cache", "archive")
}

@ -1,47 +0,0 @@
// 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 dragonfly freebsd linux nacl netbsd openbsd solaris
// +build !windows
package helmpath
import (
"runtime"
"testing"
)
func TestHelmHome(t *testing.T) {
hh := Home("/r/users/helmtest")
isEq := func(t *testing.T, a, b string) {
if a != b {
t.Error(runtime.GOOS)
t.Errorf("Expected %q, got %q", a, b)
}
}
isEq(t, hh.String(), "/r/users/helmtest")
isEq(t, hh.Registry(), "/r/users/helmtest/registry")
isEq(t, hh.Repository(), "/r/users/helmtest/repository")
isEq(t, hh.RepositoryFile(), "/r/users/helmtest/repository/repositories.yaml")
isEq(t, hh.Cache(), "/r/users/helmtest/repository/cache")
isEq(t, hh.CacheIndex("t"), "/r/users/helmtest/repository/cache/t-index.yaml")
isEq(t, hh.Starters(), "/r/users/helmtest/starters")
isEq(t, hh.Archive(), "/r/users/helmtest/cache/archive")
}
func TestHelmHome_expand(t *testing.T) {
if Home("$HOME").String() == "$HOME" {
t.Error("expected variable expansion")
}
}

@ -0,0 +1,81 @@
// 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 (
"fmt"
"path/filepath"
)
// This helper builds paths to Helm's configuration, cache and data paths.
var lp = lazypath{name: "helm"}
// ConfigPath returns the path where Helm stores configuration.
func ConfigPath() string {
return lp.configPath("")
}
// CachePath returns the path where Helm stores cached objects.
func CachePath() string {
return lp.cachePath("")
}
// DataPath returns the path where Helm stores data.
func DataPath() string {
return lp.dataPath("")
}
// Registry returns the path to the local registry cache.
func Registry() string {
return lp.cachePath("registry")
}
// RepositoryFile returns the path to the repositories.yaml file.
func RepositoryFile() string {
return lp.configPath("repositories.yaml")
}
// RepositoryCache returns the cache path for repository metadata.
func RepositoryCache() string {
return lp.cachePath("repository")
}
// CacheIndex returns the path to an index for the given named repository.
func CacheIndex(name string) string {
target := fmt.Sprintf("%s-index.yaml", name)
if name == "" {
target = "index.yaml"
}
return filepath.Join(RepositoryCache(), target)
}
// Starters returns the path to the Helm starter packs.
func Starters() string {
return lp.dataPath("starters")
}
// PluginCache returns the cache path for plugins.
func PluginCache() string {
return lp.cachePath("plugins")
}
// Plugins returns the path to the plugins directory.
func Plugins() string {
return lp.dataPath("plugins")
}
// Archive returns the path to download chart archives.
func Archive() string {
return lp.cachePath("archive")
}

@ -0,0 +1,52 @@
// 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"
"runtime"
"testing"
"helm.sh/helm/pkg/helmpath/xdg"
)
func TestHelmHome(t *testing.T) {
os.Setenv(xdg.CacheHomeEnvVar, "/cache")
os.Setenv(xdg.ConfigHomeEnvVar, "/config")
os.Setenv(xdg.DataHomeEnvVar, "/data")
isEq := func(t *testing.T, got, expected string) {
t.Helper()
if expected != got {
t.Error(runtime.GOOS)
t.Errorf("Expected %q, got %q", expected, got)
}
}
isEq(t, CachePath(), "/cache/helm")
isEq(t, ConfigPath(), "/config/helm")
isEq(t, DataPath(), "/data/helm")
isEq(t, RepositoryFile(), "/config/helm/repositories.yaml")
isEq(t, RepositoryCache(), "/cache/helm/repository")
isEq(t, CacheIndex("t"), "/cache/helm/repository/t-index.yaml")
isEq(t, CacheIndex(""), "/cache/helm/repository/index.yaml")
isEq(t, Starters(), "/data/helm/starters")
isEq(t, Archive(), "/cache/helm/archive")
// test to see if lazy-loading environment variables at runtime works
os.Setenv(xdg.CacheHomeEnvVar, "/cache2")
isEq(t, CachePath(), "/cache2/helm")
}

@ -16,23 +16,34 @@
package helmpath
import (
"os"
"testing"
"helm.sh/helm/pkg/helmpath/xdg"
)
func TestHelmHome(t *testing.T) {
hh := Home("r:\\users\\helmtest")
os.Setenv(xdg.XDGCacheHomeEnvVar, "c:\\")
os.Setenv(xdg.XDGConfigHomeEnvVar, "d:\\")
os.Setenv(xdg.XDGDataHomeEnvVar, "e:\\")
isEq := func(t *testing.T, a, b string) {
if a != b {
t.Errorf("Expected %q, got %q", b, a)
}
}
isEq(t, hh.String(), "r:\\users\\helmtest")
isEq(t, hh.Registry(), "r:\\users\\helmtest\\registry")
isEq(t, hh.Repository(), "r:\\users\\helmtest\\repository")
isEq(t, hh.RepositoryFile(), "r:\\users\\helmtest\\repository\\repositories.yaml")
isEq(t, hh.Cache(), "r:\\users\\helmtest\\repository\\cache")
isEq(t, hh.CacheIndex("t"), "r:\\users\\helmtest\\repository\\cache\\t-index.yaml")
isEq(t, hh.Starters(), "r:\\users\\helmtest\\starters")
isEq(t, hh.Archive(), "r:\\users\\helmtest\\cache\\archive")
isEq(t, CachePath(), "c:\\helm")
isEq(t, ConfigPath(), "d:\\helm")
isEq(t, DataPath(), "e:\\helm")
isEq(t, RepositoryFile(), "d:\\helm\\repositories.yaml")
isEq(t, RepositoryCache(), "c:\\helm\\repository")
isEq(t, CacheIndex("t"), "c:\\helm\\repository\\t-index.yaml")
isEq(t, CacheIndex(""), "c:\\helm\\repository\\index.yaml")
isEq(t, Starters(), "e:\\helm\\starters")
isEq(t, Archive(), "c:\\helm\\archive")
// test to see if lazy-loading environment variables at runtime works
os.Setenv(xdg.CacheHomeEnvVar, "f:\\")
isEq(t, CachePath(), "f:\\helm")
}

@ -0,0 +1,52 @@
// 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/pkg/helmpath/xdg"
)
// lazypath is an lazy-loaded path buffer for the XDG base directory specification.
//
// name is the base name of the application referenced in the base directories.
type lazypath struct {
name string
}
func (l lazypath) path(envVar string, defaultFn func() string, file string) string {
base := os.Getenv(envVar)
if base == "" {
base = defaultFn()
}
return filepath.Join(base, l.name, file)
}
// cachePath defines the base directory relative to which user specific non-essential data files
// should be stored.
func (l lazypath) cachePath(file string) string {
return l.path(xdg.CacheHomeEnvVar, cacheHome, file)
}
// configPath defines the base directory relative to which user specific configuration files should
// be stored.
func (l lazypath) configPath(file string) string {
return l.path(xdg.ConfigHomeEnvVar, configHome, file)
}
// dataPath defines the base directory relative to which user specific data files should be stored.
func (l lazypath) dataPath(file string) string {
return l.path(xdg.DataHomeEnvVar, dataHome, 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")
}

@ -0,0 +1,86 @@
// 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 (
"os"
"path/filepath"
"testing"
"helm.sh/helm/pkg/helmpath/xdg"
"k8s.io/client-go/util/homedir"
)
const (
appName string = "helm"
testFile string = "test.txt"
)
var lazy = lazypath{name: appName}
func TestDataPath(t *testing.T) {
os.Unsetenv(xdg.DataHomeEnvVar)
expected := filepath.Join(homedir.HomeDir(), "Library", appName, testFile)
if lazy.dataPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile))
}
os.Setenv(xdg.DataHomeEnvVar, "/tmp")
expected = filepath.Join("/tmp", appName, testFile)
if lazy.dataPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile))
}
}
func TestConfigPath(t *testing.T) {
os.Unsetenv(xdg.ConfigHomeEnvVar)
expected := filepath.Join(homedir.HomeDir(), "Library", "Preferences", appName, testFile)
if lazy.configPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile))
}
os.Setenv(xdg.ConfigHomeEnvVar, "/tmp")
expected = filepath.Join("/tmp", appName, testFile)
if lazy.configPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile))
}
}
func TestCachePath(t *testing.T) {
os.Unsetenv(xdg.CacheHomeEnvVar)
expected := filepath.Join(homedir.HomeDir(), "Library", "Caches", appName, testFile)
if lazy.cachePath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile))
}
os.Setenv(xdg.CacheHomeEnvVar, "/tmp")
expected = filepath.Join("/tmp", appName, testFile)
if lazy.cachePath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile))
}
}

@ -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")
}

@ -0,0 +1,87 @@
// 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 (
"os"
"path/filepath"
"testing"
"k8s.io/client-go/util/homedir"
"helm.sh/helm/pkg/helmpath/xdg"
)
const (
appName string = "helm"
testFile string = "test.txt"
)
var lazy = lazypath{name: appName}
func TestDataPath(t *testing.T) {
os.Unsetenv(xdg.DataHomeEnvVar)
expected := filepath.Join(homedir.HomeDir(), ".local", "share", appName, testFile)
if lazy.dataPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile))
}
os.Setenv(xdg.DataHomeEnvVar, "/tmp")
expected = filepath.Join("/tmp", appName, testFile)
if lazy.dataPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile))
}
}
func TestConfigPath(t *testing.T) {
os.Unsetenv(xdg.ConfigHomeEnvVar)
expected := filepath.Join(homedir.HomeDir(), ".config", appName, testFile)
if lazy.configPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile))
}
os.Setenv(xdg.ConfigHomeEnvVar, "/tmp")
expected = filepath.Join("/tmp", appName, testFile)
if lazy.configPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile))
}
}
func TestCachePath(t *testing.T) {
os.Unsetenv(xdg.CacheHomeEnvVar)
expected := filepath.Join(homedir.HomeDir(), ".cache", appName, testFile)
if lazy.cachePath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile))
}
os.Setenv(xdg.CacheHomeEnvVar, "/tmp")
expected = filepath.Join("/tmp", appName, testFile)
if lazy.cachePath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile))
}
}

@ -0,0 +1,30 @@
// 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")
}

@ -0,0 +1,88 @@
// 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"
"path/filepath"
"testing"
"k8s.io/client-go/util/homedir"
)
const (
appName string = "helm"
testFile string = "test.txt"
)
var lazy = lazypath{name: appName}
func TestDataPath(t *testing.T) {
os.Unsetenv(DataHomeEnvVar)
os.Setenv("APPDATA", filepath.Join(homedir.HomeDir(), "foo"))
expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile)
if lazy.dataPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile))
}
os.Setenv(DataHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")))
expected = filepath.Join(homedir.HomeDir(), "xdg" appName, testFile)
if lazy.dataPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.dataPath(testFile))
}
}
func TestConfigPath(t *testing.T) {
os.Unsetenv(xdg.ConfigHomeEnvVar)
os.Setenv("APPDATA", filepath.Join(homedir.HomeDir(), "foo"))
expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile)
if lazy.configPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile))
}
os.Setenv(xdg.ConfigHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")))
expected = filepath.Join(homedir.HomeDir(), "xdg" appName, testFile)
if lazy.configPath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.configPath(testFile))
}
}
func TestCachePath(t *testing.T) {
os.Unsetenv(CacheHomeEnvVar)
os.Setenv("APPDATA", filepath.Join(homedir.HomeDir(), "foo"))
expected := filepath.Join(homedir.HomeDir(), "foo", appName, testFile)
if lazy.cachePath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile))
}
os.Setenv(CacheHomeEnvVar, filepath.Join(homedir.HomeDir(), "xdg")))
expected = filepath.Join(homedir.HomeDir(), "xdg" appName, testFile)
if lazy.cachePath(testFile) != expected {
t.Errorf("expected '%s', got '%s'", expected, lazy.cachePath(testFile))
}
}

@ -0,0 +1,28 @@
// 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
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"
)

@ -25,15 +25,13 @@ import (
type base struct {
// Source is the reference to a plugin
Source string
// HelmHome is the $HELM_HOME directory
HelmHome helmpath.Home
}
func newBase(source string, home helmpath.Home) base {
return base{source, home}
func newBase(source string) base {
return base{source}
}
// link creates a symlink from the plugin source to $HELM_HOME.
// link creates a symlink from the plugin source to the base path.
func (b *base) link(from string) error {
debug("symlinking %s to %s", from, b.Path())
return os.Symlink(from, b.Path())
@ -44,5 +42,5 @@ func (b *base) Path() string {
if b.Source == "" {
return ""
}
return filepath.Join(b.HelmHome.Plugins(), filepath.Base(b.Source))
return filepath.Join(helmpath.Plugins(), filepath.Base(b.Source))
}

@ -67,7 +67,7 @@ func NewExtractor(source string) (Extractor, error) {
}
// NewHTTPInstaller creates a new HttpInstaller.
func NewHTTPInstaller(source string, home helmpath.Home) (*HTTPInstaller, error) {
func NewHTTPInstaller(source string) (*HTTPInstaller, error) {
key, err := cache.Key(source)
if err != nil {
@ -90,9 +90,9 @@ func NewHTTPInstaller(source string, home helmpath.Home) (*HTTPInstaller, error)
}
i := &HTTPInstaller{
CacheDir: home.Path("cache", "plugins", key),
CacheDir: filepath.Join(helmpath.PluginCache(), key),
PluginName: stripPluginName(filepath.Base(source)),
base: newBase(source, home),
base: newBase(source),
extractor: extractor,
getter: get,
}
@ -112,7 +112,8 @@ func stripPluginName(name string) string {
return re.ReplaceAllString(strippedName, `$1`)
}
// Install downloads and extracts the tarball into the cache directory and creates a symlink to the plugin directory in $HELM_HOME.
// Install downloads and extracts the tarball into the cache directory
// and creates a symlink to the plugin directory.
//
// Implements Installer.
func (i *HTTPInstaller) Install() error {
@ -156,7 +157,7 @@ func (i HTTPInstaller) Path() string {
if i.base.Source == "" {
return ""
}
return filepath.Join(i.base.HelmHome.Plugins(), i.PluginName)
return filepath.Join(helmpath.Plugins(), i.PluginName)
}
// Extract extracts compressed archives

@ -18,12 +18,13 @@ package installer // import "helm.sh/helm/pkg/plugin/installer"
import (
"bytes"
"encoding/base64"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/pkg/errors"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
)
@ -57,18 +58,14 @@ func TestStripName(t *testing.T) {
func TestHTTPInstaller(t *testing.T) {
source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz"
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
if err := os.MkdirAll(helmpath.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", helmpath.Plugins(), err)
}
i, err := NewForSource(source, "0.0.1", home)
i, err := NewForSource(source, "0.0.1")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
@ -93,8 +90,8 @@ func TestHTTPInstaller(t *testing.T) {
if err := Install(i); err != nil {
t.Error(err)
}
if i.Path() != home.Path("plugins", "fake-plugin") {
t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path())
if i.Path() != filepath.Join(helmpath.Plugins(), "fake-plugin") {
t.Errorf("expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path())
}
// Install again to test plugin exists error
@ -108,18 +105,14 @@ func TestHTTPInstaller(t *testing.T) {
func TestHTTPInstallerNonExistentVersion(t *testing.T) {
source := "https://repo.localdomain/plugins/fake-plugin-0.0.2.tar.gz"
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
if err := os.MkdirAll(helmpath.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", helmpath.Plugins(), err)
}
i, err := NewForSource(source, "0.0.2", home)
i, err := NewForSource(source, "0.0.2")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
@ -144,18 +137,14 @@ func TestHTTPInstallerNonExistentVersion(t *testing.T) {
func TestHTTPInstallerUpdate(t *testing.T) {
source := "https://repo.localdomain/plugins/fake-plugin-0.0.1.tar.gz"
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
if err := os.MkdirAll(helmpath.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", helmpath.Plugins(), err)
}
i, err := NewForSource(source, "0.0.1", home)
i, err := NewForSource(source, "0.0.1")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
@ -180,8 +169,8 @@ func TestHTTPInstallerUpdate(t *testing.T) {
if err := Install(i); err != nil {
t.Error(err)
}
if i.Path() != home.Path("plugins", "fake-plugin") {
t.Errorf("expected path '$HELM_HOME/plugins/fake-plugin', got %q", i.Path())
if i.Path() != filepath.Join(helmpath.Plugins(), "fake-plugin") {
t.Errorf("expected path '$XDG_CONFIG_HOME/helm/plugins/fake-plugin', got %q", i.Path())
}
// Update plugin, should fail because it is not implemented

@ -23,8 +23,6 @@ import (
"strings"
"github.com/pkg/errors"
"helm.sh/helm/pkg/helmpath"
)
// ErrMissingMetadata indicates that plugin.yaml is missing.
@ -35,18 +33,18 @@ var Debug bool
// Installer provides an interface for installing helm client plugins.
type Installer interface {
// Install adds a plugin to $HELM_HOME.
// Install adds a plugin.
Install() error
// Path is the directory of the installed plugin.
Path() string
// Update updates a plugin to $HELM_HOME.
// Update updates a plugin.
Update() error
}
// Install installs a plugin to $HELM_HOME.
// Install installs a plugin.
func Install(i Installer) error {
if _, pathErr := os.Stat(path.Dir(i.Path())); os.IsNotExist(pathErr) {
return errors.New(`plugin home "$HELM_HOME/plugins" does not exist`)
return errors.New(`plugin home "$XDG_CONFIG_HOME/helm/plugins" does not exist`)
}
if _, pathErr := os.Stat(i.Path()); !os.IsNotExist(pathErr) {
@ -56,7 +54,7 @@ func Install(i Installer) error {
return i.Install()
}
// Update updates a plugin in $HELM_HOME.
// Update updates a plugin.
func Update(i Installer) error {
if _, pathErr := os.Stat(i.Path()); os.IsNotExist(pathErr) {
return errors.New("plugin does not exist")
@ -66,19 +64,19 @@ func Update(i Installer) error {
}
// NewForSource determines the correct Installer for the given source.
func NewForSource(source, version string, home helmpath.Home) (Installer, error) {
func NewForSource(source, version string) (Installer, error) {
// Check if source is a local directory
if isLocalReference(source) {
return NewLocalInstaller(source, home)
return NewLocalInstaller(source)
} else if isRemoteHTTPArchive(source) {
return NewHTTPInstaller(source, home)
return NewHTTPInstaller(source)
}
return NewVCSInstaller(source, version, home)
return NewVCSInstaller(source, version)
}
// FindSource determines the correct Installer for the given source.
func FindSource(location string, home helmpath.Home) (Installer, error) {
installer, err := existingVCSRepo(location, home)
func FindSource(location string) (Installer, error) {
installer, err := existingVCSRepo(location)
if err != nil && err.Error() == "Cannot detect VCS" {
return installer, errors.New("cannot get information about plugin source")
}

@ -19,8 +19,6 @@ import (
"path/filepath"
"github.com/pkg/errors"
"helm.sh/helm/pkg/helmpath"
)
// LocalInstaller installs plugins from the filesystem.
@ -29,18 +27,18 @@ type LocalInstaller struct {
}
// NewLocalInstaller creates a new LocalInstaller.
func NewLocalInstaller(source string, home helmpath.Home) (*LocalInstaller, error) {
func NewLocalInstaller(source string) (*LocalInstaller, error) {
src, err := filepath.Abs(source)
if err != nil {
return nil, errors.Wrap(err, "unable to get absolute path to plugin")
}
i := &LocalInstaller{
base: newBase(src, home),
base: newBase(src),
}
return i, nil
}
// Install creates a symlink to the plugin directory in $HELM_HOME.
// Install creates a symlink to the plugin directory.
//
// Implements Installer.
func (i *LocalInstaller) Install() error {

@ -21,22 +21,15 @@ import (
"path/filepath"
"testing"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
)
var _ Installer = new(LocalInstaller)
func TestLocalInstaller(t *testing.T) {
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
}
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
// Make a temp dir
tdir, err := ioutil.TempDir("", "helm-installer-")
@ -49,7 +42,7 @@ func TestLocalInstaller(t *testing.T) {
}
source := "../testdata/plugdir/echo"
i, err := NewForSource(source, "", home)
i, err := NewForSource(source, "")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
@ -58,7 +51,7 @@ func TestLocalInstaller(t *testing.T) {
t.Error(err)
}
if i.Path() != home.Path("plugins", "echo") {
t.Errorf("expected path '$HELM_HOME/plugins/helm-env', got %q", i.Path())
if i.Path() != filepath.Join(helmpath.Plugins(), "echo") {
t.Errorf("expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path())
}
}

@ -17,6 +17,7 @@ package installer // import "helm.sh/helm/pkg/plugin/installer"
import (
"os"
"path/filepath"
"sort"
"github.com/Masterminds/semver"
@ -34,25 +35,25 @@ type VCSInstaller struct {
base
}
func existingVCSRepo(location string, home helmpath.Home) (Installer, error) {
func existingVCSRepo(location string) (Installer, error) {
repo, err := vcs.NewRepo("", location)
if err != nil {
return nil, err
}
i := &VCSInstaller{
Repo: repo,
base: newBase(repo.Remote(), home),
base: newBase(repo.Remote()),
}
return i, err
}
// NewVCSInstaller creates a new VCSInstaller.
func NewVCSInstaller(source, version string, home helmpath.Home) (*VCSInstaller, error) {
func NewVCSInstaller(source, version string) (*VCSInstaller, error) {
key, err := cache.Key(source)
if err != nil {
return nil, err
}
cachedpath := home.Path("cache", "plugins", key)
cachedpath := filepath.Join(helmpath.PluginCache(), key)
repo, err := vcs.NewRepo(source, cachedpath)
if err != nil {
return nil, err
@ -60,12 +61,12 @@ func NewVCSInstaller(source, version string, home helmpath.Home) (*VCSInstaller,
i := &VCSInstaller{
Repo: repo,
Version: version,
base: newBase(source, home),
base: newBase(source),
}
return i, err
}
// Install clones a remote repository and creates a symlink to the plugin directory in HELM_HOME.
// Install clones a remote repository and creates a symlink to the plugin directory.
//
// Implements Installer.
func (i *VCSInstaller) Install() error {

@ -17,13 +17,13 @@ package installer // import "helm.sh/helm/pkg/plugin/installer"
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/Masterminds/vcs"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/helmpath"
)
@ -49,15 +49,11 @@ func (r *testRepo) UpdateVersion(version string) error {
}
func TestVCSInstaller(t *testing.T) {
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
if err := os.MkdirAll(helmpath.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", helmpath.Plugins(), err)
}
source := "https://github.com/adamreese/helm-env"
@ -67,7 +63,7 @@ func TestVCSInstaller(t *testing.T) {
tags: []string{"0.1.0", "0.1.1"},
}
i, err := NewForSource(source, "~0.1.0", home)
i, err := NewForSource(source, "~0.1.0")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@ -87,8 +83,8 @@ func TestVCSInstaller(t *testing.T) {
if repo.current != "0.1.1" {
t.Errorf("expected version '0.1.1', got %q", repo.current)
}
if i.Path() != home.Path("plugins", "helm-env") {
t.Errorf("expected path '$HELM_HOME/plugins/helm-env', got %q", i.Path())
if i.Path() != filepath.Join(helmpath.Plugins(), "helm-env") {
t.Errorf("expected path '$XDG_CONFIG_HOME/helm/plugins/helm-env', got %q", i.Path())
}
// Install again to test plugin exists error
@ -99,7 +95,7 @@ func TestVCSInstaller(t *testing.T) {
}
//Testing FindSource method, expect error because plugin code is not a cloned repository
if _, err := FindSource(i.Path(), home); err == nil {
if _, err := FindSource(i.Path()); err == nil {
t.Error("expected error for inability to find plugin source, got none")
} else if err.Error() != "cannot get information about plugin source" {
t.Errorf("expected error for inability to find plugin source, got (%v)", err)
@ -107,21 +103,13 @@ func TestVCSInstaller(t *testing.T) {
}
func TestVCSInstallerNonExistentVersion(t *testing.T) {
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
}
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
source := "https://github.com/adamreese/helm-env"
version := "0.2.0"
i, err := NewForSource(source, version, home)
i, err := NewForSource(source, version)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@ -139,21 +127,12 @@ func TestVCSInstallerNonExistentVersion(t *testing.T) {
}
}
func TestVCSInstallerUpdate(t *testing.T) {
hh, err := ioutil.TempDir("", "helm-home-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(hh)
home := helmpath.Home(hh)
if err := os.MkdirAll(home.Plugins(), 0755); err != nil {
t.Fatalf("Could not create %s: %s", home.Plugins(), err)
}
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
source := "https://github.com/adamreese/helm-env"
i, err := NewForSource(source, "", home)
i, err := NewForSource(source, "")
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
@ -176,7 +155,7 @@ func TestVCSInstallerUpdate(t *testing.T) {
}
// Test FindSource method for positive result
pluginInfo, err := FindSource(i.Path(), home)
pluginInfo, err := FindSource(i.Path())
if err != nil {
t.Fatal(err)
}

@ -26,6 +26,7 @@ import (
"sigs.k8s.io/yaml"
helm_env "helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/helmpath"
)
const pluginFileName = "plugin.yaml"
@ -220,17 +221,15 @@ func SetupPluginEnv(settings helm_env.EnvSettings,
"HELM_PLUGIN_NAME": shortName,
"HELM_PLUGIN_DIR": base,
"HELM_BIN": os.Args[0],
// Set vars that may not have been set, and save client the
// trouble of re-parsing.
"HELM_PLUGIN": settings.PluginDirs(),
"HELM_HOME": settings.Home.String(),
"HELM_PLUGIN": helmpath.Plugins(),
// Set vars that convey common information.
"HELM_PATH_REPOSITORY": settings.Home.Repository(),
"HELM_PATH_REPOSITORY_FILE": settings.Home.RepositoryFile(),
"HELM_PATH_CACHE": settings.Home.Cache(),
"HELM_PATH_STARTER": settings.Home.Starters(),
"HELM_PATH_REPOSITORY_FILE": helmpath.RepositoryFile(),
"HELM_PATH_REPOSITORY_CACHE": helmpath.RepositoryCache(),
"HELM_PATH_STARTER": helmpath.Starters(),
"HELM_PATH_CACHE": helmpath.CachePath(),
"HELM_PATH_CONFIG": helmpath.ConfigPath(),
"HELM_PATH_DATA": helmpath.DataPath(),
} {
os.Setenv(key, val)
}

@ -7,7 +7,7 @@ echo $*
echo "ENVIRONMENT"
echo $TILLER_HOST
echo $HELM_HOME
echo $HELM_PATH_CONFIG
$HELM_BIN --host $TILLER_HOST ls --all

@ -17,6 +17,8 @@ limitations under the License.
package repo // import "helm.sh/helm/pkg/repo"
import (
"crypto/rand"
"encoding/base64"
"fmt"
"io/ioutil"
"net/url"
@ -29,13 +31,13 @@ import (
"helm.sh/helm/pkg/chart/loader"
"helm.sh/helm/pkg/getter"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/provenance"
)
// Entry represents a collection of parameters for chart repository
type Entry struct {
Name string `json:"name"`
Cache string `json:"cache"`
URL string `json:"url"`
Username string `json:"username"`
Password string `json:"password"`
@ -112,10 +114,7 @@ func (r *ChartRepository) Load() error {
}
// DownloadIndexFile fetches the index from a repository.
//
// cachePath is prepended to any index that does not have an absolute path. This
// is for pre-2.2.0 repo files.
func (r *ChartRepository) DownloadIndexFile(cachePath string) error {
func (r *ChartRepository) DownloadIndexFile() error {
var indexURL string
parsedURL, err := url.Parse(r.Config.URL)
if err != nil {
@ -139,18 +138,7 @@ func (r *ChartRepository) DownloadIndexFile(cachePath string) error {
return err
}
// In Helm 2.2.0 the config.cache was accidentally switched to an absolute
// path, which broke backward compatibility. This fixes it by prepending a
// global cache path to relative paths.
//
// It is changed on DownloadIndexFile because that was the method that
// originally carried the cache path.
cp := r.Config.Cache
if !filepath.IsAbs(cp) {
cp = filepath.Join(cachePath, cp)
}
return ioutil.WriteFile(cp, index, 0644)
return ioutil.WriteFile(helmpath.CacheIndex(r.Config.Name), index, 0644)
}
// Index generates an index for the chart repository and writes an index.yaml file.
@ -203,11 +191,9 @@ func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caF
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
tempIndexFile, err := ioutil.TempFile("", "tmp-repo-file")
if err != nil {
return "", errors.Errorf("cannot write index file for repository requested")
}
defer os.Remove(tempIndexFile.Name())
buf := make([]byte, 20)
rand.Read(buf)
name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-")
c := Entry{
URL: repoURL,
@ -216,17 +202,18 @@ func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion
CertFile: certFile,
KeyFile: keyFile,
CAFile: caFile,
Name: name,
}
r, err := NewChartRepository(&c, getters)
if err != nil {
return "", err
}
if err := r.DownloadIndexFile(tempIndexFile.Name()); err != nil {
if err := r.DownloadIndexFile(); 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(tempIndexFile.Name())
repoIndex, err := LoadIndexFile(helmpath.CacheIndex(name))
if err != nil {
return "", err
}

@ -28,11 +28,14 @@ import (
"testing"
"time"
"sigs.k8s.io/yaml"
"helm.sh/helm/internal/test/ensure"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/getter"
"sigs.k8s.io/yaml"
"helm.sh/helm/pkg/helmpath"
"helm.sh/helm/pkg/helmpath/xdg"
)
const (
@ -129,6 +132,9 @@ func (g *CustomGetter) Get(href string) (*bytes.Buffer, error) {
}
func TestIndexCustomSchemeDownload(t *testing.T) {
ensure.HelmHome(t)
defer ensure.CleanHomeDirs(t)
repoName := "gcs-repo"
repoURL := "gs://some-gcs-bucket"
myCustomGetter := &CustomGetter{}
@ -155,7 +161,7 @@ func TestIndexCustomSchemeDownload(t *testing.T) {
}
defer os.Remove(tempIndexFile.Name())
if err := repo.DownloadIndexFile(tempIndexFile.Name()); err != nil {
if err := repo.DownloadIndexFile(); err != nil {
t.Fatalf("Failed to download index file: %v", err)
}
@ -276,6 +282,8 @@ func startLocalServerForTests(handler http.Handler) (*httptest.Server, error) {
}
func TestFindChartInRepoURL(t *testing.T) {
setupCacheHome(t)
srv, err := startLocalServerForTests(nil)
if err != nil {
t.Fatal(err)
@ -300,6 +308,8 @@ func TestFindChartInRepoURL(t *testing.T) {
}
func TestErrorFindChartInRepoURL(t *testing.T) {
setupCacheHome(t)
_, err := FindChartInRepoURL("http://someserver/something", "nginx", "", "", "", "", getter.All(cli.EnvSettings{}))
if err == nil {
t.Errorf("Expected error for bad chart URL, but did not get any errors")
@ -364,3 +374,16 @@ func TestResolveReferenceURL(t *testing.T) {
t.Errorf("%s", chartURL)
}
}
func setupCacheHome(t *testing.T) {
t.Helper()
d, err := ioutil.TempDir("", "helm")
if err != nil {
t.Fatal(err)
}
os.Setenv(xdg.CacheHomeEnvVar, d)
if err := os.MkdirAll(helmpath.RepositoryCache(), 0755); err != nil {
t.Fatal(err)
}
}

@ -19,12 +19,12 @@ package repo
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"helm.sh/helm/pkg/chart"
"helm.sh/helm/pkg/cli"
"helm.sh/helm/pkg/getter"
"helm.sh/helm/pkg/helmpath"
)
const (
@ -135,31 +135,25 @@ func TestDownloadIndexFile(t *testing.T) {
}
defer srv.Close()
dirName, err := ioutil.TempDir("", "tmp")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dirName)
setupCacheHome(t)
indexFilePath := filepath.Join(dirName, testRepo+"-index.yaml")
r, err := NewChartRepository(&Entry{
Name: testRepo,
URL: srv.URL,
Cache: indexFilePath,
Name: testRepo,
URL: srv.URL,
}, getter.All(cli.EnvSettings{}))
if err != nil {
t.Errorf("Problem creating chart repository from %s: %v", testRepo, err)
}
if err := r.DownloadIndexFile(""); err != nil {
if err := r.DownloadIndexFile(); err != nil {
t.Errorf("%#v", err)
}
if _, err := os.Stat(indexFilePath); err != nil {
if _, err := os.Stat(helmpath.CacheIndex(testRepo)); err != nil {
t.Errorf("error finding created index file: %#v", err)
}
b, err := ioutil.ReadFile(indexFilePath)
b, err := ioutil.ReadFile(helmpath.CacheIndex(testRepo))
if err != nil {
t.Errorf("error reading index file: %#v", err)
}

@ -17,7 +17,6 @@ limitations under the License.
package repo // import "helm.sh/helm/pkg/repo"
import (
"fmt"
"io/ioutil"
"os"
"time"
@ -30,7 +29,7 @@ import (
// is fixable.
var ErrRepoOutOfDate = errors.New("repository file is out of date")
// File represents the repositories.yaml file in $HELM_HOME
// File represents the repositories.yaml file
type File struct {
APIVersion string `json:"apiVersion"`
Generated time.Time `json:"generated"`
@ -76,9 +75,8 @@ func LoadFile(path string) (*File, error) {
r := NewFile()
for k, v := range m {
r.Add(&Entry{
Name: k,
URL: v,
Cache: fmt.Sprintf("%s-index.yaml", k),
Name: k,
URL: v,
})
}
return r, ErrRepoOutOfDate

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save