Skip to content

Commit

Permalink
cmd: support generating index in JSON format
Browse files Browse the repository at this point in the history
This adds support for generating the repository index file in JSON
format using the `--json` flag. The index itself is still written
to `index.yaml`, which is fully backwards compatible as YAML is a
superset of JSON.

For big indexes (think multiple megabytes), this approach is however
more efficient in combination with the changes to the load logic,
as it prevents a YAML -> JSON roundtrip during decoding.

Signed-off-by: Hidde Beydals <hidde@hhh.computer>
  • Loading branch information
hiddeco committed Jul 21, 2023
1 parent e21c9cf commit 2544aa2
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 3 deletions.
15 changes: 12 additions & 3 deletions cmd/helm/repo_index.go
Expand Up @@ -43,6 +43,7 @@ type repoIndexOptions struct {
dir string
url string
merge string
json bool
}

func newRepoIndexCmd(out io.Writer) *cobra.Command {
Expand Down Expand Up @@ -70,6 +71,7 @@ func newRepoIndexCmd(out io.Writer) *cobra.Command {
f := cmd.Flags()
f.StringVar(&o.url, "url", "", "url of chart repository")
f.StringVar(&o.merge, "merge", "", "merge the generated index into the given index")
f.BoolVar(&o.json, "json", false, "output in JSON format")

return cmd
}
Expand All @@ -80,10 +82,10 @@ func (i *repoIndexOptions) run(out io.Writer) error {
return err
}

return index(path, i.url, i.merge)
return index(path, i.url, i.merge, i.json)
}

func index(dir, url, mergeTo string) error {
func index(dir, url, mergeTo string, json bool) error {
out := filepath.Join(dir, "index.yaml")

i, err := repo.IndexDirectory(dir, url)
Expand All @@ -95,7 +97,7 @@ func index(dir, url, mergeTo string) error {
var i2 *repo.IndexFile
if _, err := os.Stat(mergeTo); os.IsNotExist(err) {
i2 = repo.NewIndexFile()
i2.WriteFile(mergeTo, 0644)
writeIndexFile(i2, mergeTo, json)
} else {
i2, err = repo.LoadIndexFile(mergeTo)
if err != nil {
Expand All @@ -105,5 +107,12 @@ func index(dir, url, mergeTo string) error {
i.Merge(i2)
}
i.SortEntries()
return writeIndexFile(i, out, json)
}

func writeIndexFile(i *repo.IndexFile, out string, json bool) error {
if json {
return i.WriteJSONFile(out, 0644)
}
return i.WriteFile(out, 0644)
}
23 changes: 23 additions & 0 deletions cmd/helm/repo_index_test.go
Expand Up @@ -18,6 +18,7 @@ package main

import (
"bytes"
"encoding/json"
"io"
"os"
"path/filepath"
Expand Down Expand Up @@ -68,6 +69,28 @@ func TestRepoIndexCmd(t *testing.T) {
t.Errorf("expected %q, got %q", expectedVersion, vs[0].Version)
}

b, err := os.ReadFile(destIndex)
if err != nil {
t.Fatal(err)
}
if json.Valid(b) {
t.Error("did not expect index file to be valid json")
}

// Test with `--json`

c.ParseFlags([]string{"--json", "true"})
if err := c.RunE(c, []string{dir}); err != nil {
t.Error(err)
}

if b, err = os.ReadFile(destIndex); err != nil {
t.Fatal(err)
}
if !json.Valid(b) {
t.Error("index file is not valid json")
}

// Test with `--merge`

// Remove first two charts.
Expand Down
12 changes: 12 additions & 0 deletions pkg/repo/index.go
Expand Up @@ -233,6 +233,18 @@ func (i IndexFile) WriteFile(dest string, mode os.FileMode) error {
return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode)
}

// WriteJSONFile writes an index file in JSON format to the given destination
// path.
//
// The mode on the file is set to 'mode'.
func (i IndexFile) WriteJSONFile(dest string, mode os.FileMode) error {
b, err := json.MarshalIndent(i, "", " ")
if err != nil {
return err
}
return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode)
}

// Merge merges the given index file into this index.
//
// This merges by name and version.
Expand Down
22 changes: 22 additions & 0 deletions pkg/repo/index_test.go
Expand Up @@ -19,6 +19,7 @@ package repo
import (
"bufio"
"bytes"
"encoding/json"
"net/http"
"os"
"path/filepath"
Expand Down Expand Up @@ -553,6 +554,27 @@ func TestIndexWrite(t *testing.T) {
}
}

func TestIndexJSONWrite(t *testing.T) {
i := NewIndexFile()
if err := i.MustAdd(&chart.Metadata{APIVersion: "v2", Name: "clipper", Version: "0.1.0"}, "clipper-0.1.0.tgz", "http://example.com/charts", "sha256:1234567890"); err != nil {
t.Fatalf("unexpected error: %s", err)
}
dir := t.TempDir()
testpath := filepath.Join(dir, "test")
i.WriteJSONFile(testpath, 0600)

got, err := os.ReadFile(testpath)
if err != nil {
t.Fatal(err)
}
if !json.Valid(got) {
t.Fatal("Index files doesn't contain valid JSON")
}
if !strings.Contains(string(got), "clipper-0.1.0.tgz") {
t.Fatal("Index files doesn't contain expected content")
}
}

func TestAddFileIndexEntriesNil(t *testing.T) {
i := NewIndexFile()
i.APIVersion = chart.APIVersionV1
Expand Down

0 comments on commit 2544aa2

Please sign in to comment.