Merge pull request #1361 from technosophos/fix/1334-merge-indices

fix(helm): allow entries to be merged into index
pull/1364/head
Matt Butcher 8 years ago committed by GitHub
commit ab6a73a0b5

@ -25,10 +25,22 @@ import (
"k8s.io/helm/pkg/repo" "k8s.io/helm/pkg/repo"
) )
const repoIndexDesc = `
Read the current directory and generate an index file based on the charts found.
This tool is used for creating an 'index.yaml' file for a chart repository. To
set an absolute URL to the charts, use '--url' flag.
To merge the generated index with an existing index file, use the '--merge'
flag. In this case, the charts found in the current directory will be merged
into the existing index, with local charts taking priority over existing charts.
`
type repoIndexCmd struct { type repoIndexCmd struct {
dir string dir string
url string url string
out io.Writer out io.Writer
merge string
} }
func newRepoIndexCmd(out io.Writer) *cobra.Command { func newRepoIndexCmd(out io.Writer) *cobra.Command {
@ -39,6 +51,7 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "index [flags] [DIR]", Use: "index [flags] [DIR]",
Short: "generate an index file given a directory containing packaged charts", Short: "generate an index file given a directory containing packaged charts",
Long: repoIndexDesc,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
if err := checkArgsLength(len(args), "path to a directory"); err != nil { if err := checkArgsLength(len(args), "path to a directory"); err != nil {
return err return err
@ -52,6 +65,7 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command {
f := cmd.Flags() f := cmd.Flags()
f.StringVar(&index.url, "url", "", "url of chart repository") f.StringVar(&index.url, "url", "", "url of chart repository")
f.StringVar(&index.merge, "merge", "", "merge the generated index into the given index")
return cmd return cmd
} }
@ -62,14 +76,22 @@ func (i *repoIndexCmd) run() error {
return err return err
} }
return index(path, i.url) return index(path, i.url, i.merge)
} }
func index(dir, url string) error { func index(dir, url, mergeTo string) error {
chartRepo, err := repo.LoadChartRepository(dir, url) chartRepo, err := repo.LoadChartRepository(dir, url)
if err != nil { if err != nil {
return err return err
} }
if mergeTo != "" {
old, err := repo.LoadIndexFile(mergeTo)
if err != nil {
return err
}
return chartRepo.MergeIndex(old)
}
return chartRepo.Index() return chartRepo.Index()
} }

@ -33,7 +33,9 @@ func TestRepoIndexCmd(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
if err := os.Link("testdata/testcharts/compressedchart-0.1.0.tgz", filepath.Join(dir, "compressedchart-0.1.0.tgz")); err != nil {
comp := filepath.Join(dir, "compressedchart-0.1.0.tgz")
if err := os.Link("testdata/testcharts/compressedchart-0.1.0.tgz", comp); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -41,16 +43,42 @@ func TestRepoIndexCmd(t *testing.T) {
c := newRepoIndexCmd(buf) c := newRepoIndexCmd(buf)
if err := c.RunE(c, []string{dir}); err != nil { if err := c.RunE(c, []string{dir}); err != nil {
t.Errorf("%q", err) t.Error(err)
} }
index, err := repo.LoadIndexFile(filepath.Join(dir, "index.yaml")) destIndex := filepath.Join(dir, "index.yaml")
index, err := repo.LoadIndexFile(destIndex)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if len(index.Entries) != 1 { if len(index.Entries) != 1 {
t.Errorf("expected 1 entry, got %v: %#v", len(index.Entries), index.Entries) t.Errorf("expected 1 entry, got %d: %#v", len(index.Entries), index.Entries)
}
// Test with `--merge`
// Remove first chart.
if err := os.Remove(comp); err != nil {
t.Fatal(err)
}
// Add another chart.
if err := os.Link("testdata/testcharts/reqtest-0.1.0.tgz", filepath.Join(dir, "reqtest-0.1.0.tgz")); err != nil {
t.Fatal(err)
} }
c.ParseFlags([]string{"--merge", destIndex})
if err := c.RunE(c, []string{dir}); err != nil {
t.Error(err)
}
index, err = repo.LoadIndexFile(destIndex)
if err != nil {
t.Fatal(err)
}
if len(index.Entries) != 2 {
t.Errorf("expected 2 entry, got %d: %#v", len(index.Entries), index.Entries)
}
} }

@ -82,6 +82,67 @@ func TestLoadIndexFile(t *testing.T) {
verifyLocalIndex(t, i) verifyLocalIndex(t, i)
} }
func TestMergeIndex(t *testing.T) {
dirName, err := ioutil.TempDir("", "tmp")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dirName)
ind := NewIndexFile()
ind.Add(&chart.Metadata{
Name: "dreadnought",
Version: "0.1.0",
}, "dreadnought-0.1.0.tgz", "http://example.com", "aaaa")
cr := &ChartRepository{
IndexFile: ind,
RootPath: dirName,
}
if err := cr.saveIndexFile(); err != nil {
t.Fatal(err)
}
ind2 := NewIndexFile()
ind2.Add(&chart.Metadata{
Name: "dreadnought",
Version: "0.2.0",
}, "dreadnought-0.2.0.tgz", "http://example.com", "aaaabbbb")
ind2.Add(&chart.Metadata{
Name: "doughnut",
Version: "0.2.0",
}, "doughnut-0.2.0.tgz", "http://example.com", "ccccbbbb")
cr.IndexFile = ind2
ind3, err := LoadIndexFile(filepath.Join(dirName, "index.yaml"))
if err != nil {
t.Fatal(err)
}
if err := cr.MergeIndex(ind3); err != nil {
t.Fatal(err)
}
ind4, err := LoadIndexFile(filepath.Join(dirName, "index.yaml"))
if err != nil {
t.Fatal(err)
}
if len(ind4.Entries) != 2 {
t.Errorf("Expected 2 entries, got %d", len(ind4.Entries))
vs := ind4.Entries["dreadnaught"]
if len(vs) != 2 {
t.Errorf("Expected 2 versions, got %d", len(vs))
}
v := vs[0]
if v.Version != "0.2.0" {
t.Errorf("Expected %q version to be 0.2.0, got %s", v.Name, v.Version)
}
}
}
func TestDownloadIndexFile(t *testing.T) { func TestDownloadIndexFile(t *testing.T) {
fileBytes, err := ioutil.ReadFile("testdata/local-index.yaml") fileBytes, err := ioutil.ReadFile("testdata/local-index.yaml")
if err != nil { if err != nil {

@ -191,6 +191,35 @@ func (r *ChartRepository) saveIndexFile() error {
// Index generates an index for the chart repository and writes an index.yaml file. // Index generates an index for the chart repository and writes an index.yaml file.
func (r *ChartRepository) Index() error { func (r *ChartRepository) Index() error {
err := r.generateIndex()
if err != nil {
return err
}
return r.saveIndexFile()
}
// MergeIndex merges the given index file into this index, and then writes the result.
//
// This provides a parallel function to the Index() method, but with the additional merge step.
func (r *ChartRepository) MergeIndex(f *IndexFile) error {
err := r.generateIndex()
if err != nil {
return err
}
for _, cvs := range f.Entries {
for _, cv := range cvs {
if !r.IndexFile.Has(cv.Name, cv.Version) {
e := r.IndexFile.Entries[cv.Name]
r.IndexFile.Entries[cv.Name] = append(e, cv)
}
}
}
return r.saveIndexFile()
}
func (r *ChartRepository) generateIndex() error {
if r.IndexFile == nil { if r.IndexFile == nil {
r.IndexFile = NewIndexFile() r.IndexFile = NewIndexFile()
} }
@ -212,5 +241,5 @@ func (r *ChartRepository) Index() error {
// TODO: If a chart exists, but has a different Digest, should we error? // TODO: If a chart exists, but has a different Digest, should we error?
} }
r.IndexFile.SortEntries() r.IndexFile.SortEntries()
return r.saveIndexFile() return nil
} }

Loading…
Cancel
Save