From 70d9638b6217725e98c623f0ac5b00c0400ada35 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Mon, 9 Oct 2023 00:59:14 -0700 Subject: [PATCH] Fix hub file name parsing Signed-off-by: Tamal Saha --- hub/registry.go | 48 ++++++++++++++++- hub/registry_test.go | 121 +++++++++++++++++++++++++++++++++++++++++++ pkg/layouts/lib.go | 15 ++---- 3 files changed, 170 insertions(+), 14 deletions(-) create mode 100644 hub/registry_test.go diff --git a/hub/registry.go b/hub/registry.go index 3722556e2..0ef52c5f8 100644 --- a/hub/registry.go +++ b/hub/registry.go @@ -446,8 +446,15 @@ func (r *Registry) LoadByGVK(gvk schema.GroupVersionKind) (*v1alpha1.ResourceDes } func (r *Registry) LoadByName(name string) (*v1alpha1.ResourceDescriptor, error) { - filename := strings.Replace(name, "-", "/", 2) + ".yaml" - return r.LoadByFile(filename) + return r.LoadByFile(toFilename(name)) +} + +func toFilename(name string) string { + name = reverse(name) + name = strings.Replace(name, "-", "/", 2) + name = reverse(name) + filename := name + ".yaml" + return filename } func (r *Registry) LoadByFile(filename string) (*v1alpha1.ResourceDescriptor, error) { @@ -473,3 +480,40 @@ func IsUnregisteredErr(err error) bool { _, okp := err.(*UnregisteredErr) return err != nil && (ok || okp) } + +func ParseGVR(name string) (*schema.GroupVersionResource, error) { + name = reverse(name) + parts := strings.SplitN(name, "-", 3) + if len(parts) != 3 { + return nil, fmt.Errorf("%s is not a valid gvr encoded name", name) + } + gvr := schema.GroupVersionResource{ + Group: reverse(parts[2]), + Version: reverse(parts[1]), + Resource: reverse(parts[0]), + } + if gvr.Group == "core" { + gvr.Group = "" + } + return &gvr, nil +} + +// ref: https://groups.google.com/g/golang-nuts/c/oPuBaYJ17t4/m/PCmhdAyrNVkJ +func reverse(input string) string { + // Get Unicode code points. + n := 0 + rune := make([]int32, len(input)) + for _, r := range input { + rune[n] = r + n++ + } + rune = rune[0:n] + + // Reverse + for i := 0; i < n/2; i++ { + rune[i], rune[n-1-i] = rune[n-1-i], rune[i] + } + + // Convert back to UTF-8. + return string(rune) +} diff --git a/hub/registry_test.go b/hub/registry_test.go new file mode 100644 index 000000000..bc8df5e61 --- /dev/null +++ b/hub/registry_test.go @@ -0,0 +1,121 @@ +/* +Copyright AppsCode Inc. and Contributors + +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 hub + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestParseGVR(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + want schema.GroupVersionResource + wantErr assert.ErrorAssertionFunc + }{ + { + name: "core-v1-services", + args: args{ + name: "core-v1-services", + }, + want: schema.GroupVersionResource{ + Group: "", + Version: "v1", + Resource: "services", + }, + wantErr: assert.NoError, + }, + { + name: "apps-v1-deployments", + args: args{ + name: "apps-v1-deployments", + }, + want: schema.GroupVersionResource{ + Group: "apps", + Version: "v1", + Resource: "deployments", + }, + wantErr: assert.NoError, + }, + { + name: "charts.x-helm.dev-v1alpha1-clusterchartpresets", + args: args{ + name: "charts.x-helm.dev-v1alpha1-clusterchartpresets", + }, + want: schema.GroupVersionResource{ + Group: "charts.x-helm.dev", + Version: "v1alpha1", + Resource: "clusterchartpresets", + }, + wantErr: assert.NoError, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseGVR(tt.args.name) + if !tt.wantErr(t, err, fmt.Sprintf("ParseGVR(%v)", tt.args.name)) { + return + } + assert.Equalf(t, tt.want, *got, "ParseGVR(%v)", tt.args.name) + }) + } +} + +func Test_toFilename(t *testing.T) { + type args struct { + name string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "core-v1-services", + args: args{ + name: "core-v1-services", + }, + want: "core/v1/services.yaml", + }, + { + name: "apps-v1-deployments", + args: args{ + name: "apps-v1-deployments", + }, + want: "apps/v1/deployments.yaml", + }, + { + name: "charts.x-helm.dev-v1alpha1-clusterchartpresets", + args: args{ + name: "charts.x-helm.dev-v1alpha1-clusterchartpresets", + }, + want: "charts.x-helm.dev/v1alpha1/clusterchartpresets.yaml", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, toFilename(tt.args.name), "toFilename(%v)", tt.args.name) + }) + } +} diff --git a/pkg/layouts/lib.go b/pkg/layouts/lib.go index c78930db3..284cccef8 100644 --- a/pkg/layouts/lib.go +++ b/pkg/layouts/lib.go @@ -18,7 +18,6 @@ package layouts import ( "fmt" - "strings" kmapi "kmodules.xyz/client-go/api/v1" meta_util "kmodules.xyz/client-go/meta" @@ -151,19 +150,11 @@ func generateDefaultLayout(kc client.Client, rid kmapi.ResourceID) (*v1alpha1.Re func LoadResourceLayout(kc client.Client, name string) (*v1alpha1.ResourceLayout, error) { outline, err := resourceoutlines.LoadByName(name) if apierrors.IsNotFound(err) { - parts := strings.SplitN(name, "-", 3) - if len(parts) != 3 { + gvr, e2 := hub.ParseGVR(name) + if e2 != nil { return nil, err } - var group string - if parts[0] != "core" { - group = parts[0] - } - return LoadResourceLayoutForGVR(kc, schema.GroupVersionResource{ - Group: group, - Version: parts[1], - Resource: parts[2], - }) + return LoadResourceLayoutForGVR(kc, *gvr) } else if err != nil { return nil, err }