Skip to content

Commit

Permalink
repo: detect JSON and unmarshal efficiently
Browse files Browse the repository at this point in the history
When an index is in a JSON format, the `sigs.k8s.io/yaml` package uses
an inefficient approach to unmarshaling the data, as it does an
unnecessary roundtrip on the data to transform the YAML to valid JSON.

To prevent this from happening, detect if the bytes which we attempt
to load contain valid JSON, and unmarshal them directly using
`json.Unmarshal` instead.

Signed-off-by: Hidde Beydals <hidde@hhh.computer>
  • Loading branch information
hiddeco committed Jul 20, 2023
1 parent a50206f commit e21c9cf
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 1 deletion.
17 changes: 16 additions & 1 deletion pkg/repo/index.go
Expand Up @@ -18,6 +18,7 @@ package repo

import (
"bytes"
"encoding/json"
"log"
"os"
"path"
Expand Down Expand Up @@ -336,7 +337,7 @@ func loadIndex(data []byte, source string) (*IndexFile, error) {
return i, ErrEmptyIndexYaml
}

if err := yaml.UnmarshalStrict(data, i); err != nil {
if err := jsonOrYamlUnmarshal(data, i); err != nil {
return i, err
}

Expand All @@ -361,3 +362,17 @@ func loadIndex(data []byte, source string) (*IndexFile, error) {
}
return i, nil
}

// jsonOrYamlUnmarshal unmarshals the given byte slice containing JSON or YAML
// into the provided interface.
//
// It automatically detects whether the data is in JSON or YAML format by
// checking its validity as JSON. If the data is valid JSON, it will use the
// `encoding/json` package to unmarshal it. Otherwise, it will use the
// `sigs.k8s.io/yaml` package to unmarshal the YAML data.
func jsonOrYamlUnmarshal(b []byte, i interface{}) error {
if json.Valid(b) {
return json.Unmarshal(b, i)
}
return yaml.UnmarshalStrict(b, i)
}
5 changes: 5 additions & 0 deletions pkg/repo/index_test.go
Expand Up @@ -37,6 +37,7 @@ const (
annotationstestfile = "testdata/local-index-annotations.yaml"
chartmuseumtestfile = "testdata/chartmuseum-index.yaml"
unorderedTestfile = "testdata/local-index-unordered.yaml"
jsonTestfile = "testdata/local-index.json"
testRepo = "test-repo"
indexWithDuplicates = `
apiVersion: v1
Expand Down Expand Up @@ -145,6 +146,10 @@ func TestLoadIndex(t *testing.T) {
Name: "chartmuseum index file",
Filename: chartmuseumtestfile,
},
{
Name: "JSON index file",
Filename: jsonTestfile,
},
}

for _, tc := range tests {
Expand Down
53 changes: 53 additions & 0 deletions pkg/repo/testdata/local-index.json
@@ -0,0 +1,53 @@
{
"apiVersion": "v1",
"entries": {
"nginx": [
{
"urls": ["https://charts.helm.sh/stable/nginx-0.2.0.tgz"],
"name": "nginx",
"description": "string",
"version": "0.2.0",
"home": "https://github.com/something/else",
"digest": "sha256:1234567890abcdef",
"keywords": ["popular", "web server", "proxy"],
"apiVersion": "v2"
},
{
"urls": ["https://charts.helm.sh/stable/nginx-0.1.0.tgz"],
"name": "nginx",
"description": "string",
"version": "0.1.0",
"home": "https://github.com/something",
"digest": "sha256:1234567890abcdef",
"keywords": ["popular", "web server", "proxy"],
"apiVersion": "v2"
}
],
"alpine": [
{
"urls": [
"https://charts.helm.sh/stable/alpine-1.0.0.tgz",
"http://storage2.googleapis.com/kubernetes-charts/alpine-1.0.0.tgz"
],
"name": "alpine",
"description": "string",
"version": "1.0.0",
"home": "https://github.com/something",
"keywords": ["linux", "alpine", "small", "sumtin"],
"digest": "sha256:1234567890abcdef",
"apiVersion": "v2"
}
],
"chartWithNoURL": [
{
"name": "chartWithNoURL",
"description": "string",
"version": "1.0.0",
"home": "https://github.com/something",
"keywords": ["small", "sumtin"],
"digest": "sha256:1234567890abcdef",
"apiVersion": "v2"
}
]
}
}

0 comments on commit e21c9cf

Please sign in to comment.