diff --git a/cmd/helm/pull.go b/cmd/helm/pull.go index 378301196..ee8e066c7 100644 --- a/cmd/helm/pull.go +++ b/cmd/helm/pull.go @@ -80,9 +80,12 @@ func newPullCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.Untar, "untar", false, "if set to true, will untar the chart after downloading it") f.BoolVar(&client.VerifyLater, "prov", false, "fetch the provenance file, but don't perform verification") f.StringVar(&client.UntarDir, "untardir", ".", "if untar is specified, this flag specifies the name of the directory into which the chart is expanded") + f.StringVar(&client.UntarDirName, "untardirname", ".", "if untarname is specified, this flag overrides the name of the directory into which the chart is expanded") f.StringVarP(&client.DestDir, "destination", "d", ".", "location to write the chart. If this and untardir are specified, untardir is appended to this") addChartPathOptionsFlags(f, &client.ChartPathOptions) + cmd.MarkFlagsMutuallyExclusive("untardir", "untardirname") + err := cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if len(args) != 1 { return nil, cobra.ShellCompDirectiveNoFileComp diff --git a/cmd/helm/pull_test.go b/cmd/helm/pull_test.go index 41ac237f4..1dd1bd77b 100644 --- a/cmd/helm/pull_test.go +++ b/cmd/helm/pull_test.go @@ -125,6 +125,17 @@ func TestPullCmd(t *testing.T) { expectVerify: true, expectSha: "sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55", }, + { + name: "Fetch, untar with mutually exclusive untardirname", + args: "test/signtest --untar --untardir signtest --untardirname signtest2", + wantError: true, + wantErrorMsg: fmt.Sprintf("if any flags in the group [untardir untardirname] are set none of the others can be; [untardir untardirname] were all set, not equal to expected error if any flags in the group [untardir untardirname] are set none of the others can be; [untardir untardirname] were all set"), + }, + { + name: "Fetch and untardirname", + args: "test/reqtest --untar --untardirname reg", + expectFile: "./reg/Chart.yaml", + }, { name: "Chart fetch using repo URL", expectFile: "./signtest-0.1.0.tgz", diff --git a/pkg/action/pull.go b/pkg/action/pull.go index b4018869e..8c91b6553 100644 --- a/pkg/action/pull.go +++ b/pkg/action/pull.go @@ -41,12 +41,13 @@ type Pull struct { Settings *cli.EnvSettings // TODO: refactor this out of pkg/action - Devel bool - Untar bool - VerifyLater bool - UntarDir string - DestDir string - cfg *Configuration + Devel bool + Untar bool + VerifyLater bool + UntarDir string + UntarDirName string + DestDir string + cfg *Configuration } type PullOpt func(*Pull) @@ -146,6 +147,9 @@ func (p *Pull) Run(chartRef string) (string, error) { udCheck := ud if udCheck == "." { _, udCheck = filepath.Split(chartRef) + if p.UntarDirName != "" { + udCheck = p.UntarDirName + } } else { _, chartName := filepath.Split(chartRef) udCheck = filepath.Join(udCheck, chartName) @@ -160,7 +164,7 @@ func (p *Pull) Run(chartRef string) (string, error) { return out.String(), errors.Errorf("failed to untar: a file or directory with the name %s already exists", udCheck) } - return out.String(), chartutil.ExpandFile(ud, saved) + return out.String(), chartutil.ExpandDir(ud, saved, p.UntarDirName) } return out.String(), nil } diff --git a/pkg/chartutil/expand.go b/pkg/chartutil/expand.go index 6ad09e417..de680bd58 100644 --- a/pkg/chartutil/expand.go +++ b/pkg/chartutil/expand.go @@ -32,28 +32,40 @@ import ( // Expand uncompresses and extracts a chart into the specified directory. func Expand(dir string, r io.Reader) error { + return ExpandDirName(dir, "", r) +} + +func ExpandDirName(dir, dirName string, r io.Reader) error { files, err := loader.LoadArchiveFiles(r) if err != nil { return err } - // Get the name of the chart - var chartName string - for _, file := range files { - if file.Name == "Chart.yaml" { - ch := &chart.Metadata{} - if err := yaml.Unmarshal(file.Data, ch); err != nil { - return errors.Wrap(err, "cannot load Chart.yaml") + getDirName := func() (string, error) { + if dirName != "" { + return dirName, nil + } + + for _, file := range files { + if file.Name == "Chart.yaml" { + ch := &chart.Metadata{} + if err := yaml.Unmarshal(file.Data, ch); err != nil { + return "", errors.Wrap(err, "cannot load Chart.yaml") + } + return ch.Name, nil } - chartName = ch.Name } + + return "", nil } - if chartName == "" { - return errors.New("chart name not specified") + + chartDirName, err := getDirName() + if err != nil { + return errors.Wrapf(err, "chart directory name not specified") } // Find the base directory - chartdir, err := securejoin.SecureJoin(dir, chartName) + chartdir, err := securejoin.SecureJoin(dir, chartDirName) if err != nil { return err } @@ -89,3 +101,13 @@ func ExpandFile(dest, src string) error { defer h.Close() return Expand(dest, h) } + +// ExpandDir expands the src file into the dest directory with the given dirName. +func ExpandDir(dest, src, dirName string) error { + h, err := os.Open(src) + if err != nil { + return err + } + defer h.Close() + return ExpandDirName(dest, dirName, h) +} diff --git a/pkg/chartutil/expand_test.go b/pkg/chartutil/expand_test.go index f31a3d290..558e7dc46 100644 --- a/pkg/chartutil/expand_test.go +++ b/pkg/chartutil/expand_test.go @@ -122,3 +122,51 @@ func TestExpandFile(t *testing.T) { } } } + +func TestExpandDir(t *testing.T) { + dest := t.TempDir() + + if err := ExpandDir(dest, "testdata/frobnitz-1.2.3.tgz", "oh-my-frobnitz"); err != nil { + t.Fatal(err) + } + + expectedChartPath := filepath.Join(dest, "oh-my-frobnitz") + fi, err := os.Stat(expectedChartPath) + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Fatalf("expected a chart directory at %s", expectedChartPath) + } + + dir, err := os.Open(expectedChartPath) + if err != nil { + t.Fatal(err) + } + + fis, err := dir.Readdir(0) + if err != nil { + t.Fatal(err) + } + + expectLen := 11 + if len(fis) != expectLen { + t.Errorf("Expected %d files, but got %d", expectLen, len(fis)) + } + + for _, fi := range fis { + expect, err := os.Stat(filepath.Join("testdata", "frobnitz", fi.Name())) + if err != nil { + t.Fatal(err) + } + // os.Stat can return different values for directories, based on the OS + // for Linux, for example, os.Stat alwaty returns the size of the directory + // (value-4096) regardless of the size of the contents of the directory + mode := expect.Mode() + if !mode.IsDir() { + if fi.Size() != expect.Size() { + t.Errorf("Expected %s to have size %d, got %d", fi.Name(), expect.Size(), fi.Size()) + } + } + } +}