diff --git a/v2/go.mod b/v2/go.mod index f1b040fe997..3846d37858b 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -22,6 +22,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.12.1 golang.org/x/crypto v0.0.0-20220214200702-86341886e292 + golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 k8s.io/api v0.24.0-beta.0 k8s.io/apiextensions-apiserver v0.23.5 diff --git a/v2/go.sum b/v2/go.sum index 180150353d2..40935786f6a 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -578,6 +578,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4= +golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/v2/internal/reflecthelpers/reflect_helpers.go b/v2/internal/reflecthelpers/reflect_helpers.go index 19297e09b2e..259ed0d46f4 100644 --- a/v2/internal/reflecthelpers/reflect_helpers.go +++ b/v2/internal/reflecthelpers/reflect_helpers.go @@ -12,6 +12,7 @@ import ( "github.com/pkg/errors" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/pkg/genruntime" ) @@ -62,30 +63,30 @@ func FindReferences(obj interface{}, t reflect.Type) (map[interface{}]struct{}, } // FindResourceReferences finds all the genruntime.ResourceReference's on the provided object -func FindResourceReferences(obj interface{}) (map[genruntime.ResourceReference]struct{}, error) { +func FindResourceReferences(obj interface{}) (set.Set[genruntime.ResourceReference], error) { untypedResult, err := FindReferences(obj, reflect.TypeOf(genruntime.ResourceReference{})) if err != nil { return nil, err } - result := make(map[genruntime.ResourceReference]struct{}) + result := set.Make[genruntime.ResourceReference]() for k := range untypedResult { - result[k.(genruntime.ResourceReference)] = struct{}{} + result.Add(k.(genruntime.ResourceReference)) } return result, nil } // FindSecretReferences finds all of the genruntime.SecretReference's on the provided object -func FindSecretReferences(obj interface{}) (map[genruntime.SecretReference]struct{}, error) { +func FindSecretReferences(obj interface{}) (set.Set[genruntime.SecretReference], error) { untypedResult, err := FindReferences(obj, reflect.TypeOf(genruntime.SecretReference{})) if err != nil { return nil, err } - result := make(map[genruntime.SecretReference]struct{}) + result := set.Make[genruntime.SecretReference]() for k := range untypedResult { - result[k.(genruntime.SecretReference)] = struct{}{} + result.Add(k.(genruntime.SecretReference)) } return result, nil diff --git a/v2/internal/resolver/resolver.go b/v2/internal/resolver/resolver.go index a52dbf3fdfd..9c9b8ea085e 100644 --- a/v2/internal/resolver/resolver.go +++ b/v2/internal/resolver/resolver.go @@ -15,6 +15,7 @@ import ( "k8s.io/apimachinery/pkg/types" "github.com/Azure/azure-service-operator/v2/internal/reflecthelpers" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/internal/util/kubeclient" "github.com/Azure/azure-service-operator/v2/pkg/genruntime" ) @@ -192,8 +193,8 @@ func (r *Resolver) findGVK(ref genruntime.NamespacedResourceReference) (schema.G // ResolveSecretReferences resolves all provided secret references func (r *Resolver) ResolveSecretReferences( ctx context.Context, - refs map[genruntime.NamespacedSecretReference]struct{}) (genruntime.ResolvedSecrets, error) { - + refs set.Set[genruntime.NamespacedSecretReference], +) (genruntime.ResolvedSecrets, error) { return r.kubeSecretResolver.ResolveSecretReferences(ctx, refs) } @@ -205,9 +206,9 @@ func (r *Resolver) ResolveResourceSecretReferences(ctx context.Context, metaObje } // Include the namespace - namespacedSecretRefs := make(map[genruntime.NamespacedSecretReference]struct{}) + namespacedSecretRefs := set.Make[genruntime.NamespacedSecretReference]() for ref := range refs { - namespacedSecretRefs[ref.ToNamespacedRef(metaObject.GetNamespace())] = struct{}{} + namespacedSecretRefs.Add(ref.ToNamespacedRef(metaObject.GetNamespace())) } // resolve them diff --git a/v2/internal/resolver/resolver_test.go b/v2/internal/resolver/resolver_test.go index d696aeb1442..ae83105222b 100644 --- a/v2/internal/resolver/resolver_test.go +++ b/v2/internal/resolver/resolver_test.go @@ -25,7 +25,9 @@ import ( mysql "github.com/Azure/azure-service-operator/v2/api/dbformysql/v1beta20210501" resources "github.com/Azure/azure-service-operator/v2/api/resources/v1beta20200601" storage "github.com/Azure/azure-service-operator/v2/api/storage/v1beta20210401" + "github.com/Azure/azure-service-operator/v2/internal/resolver" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/internal/testcommon" "github.com/Azure/azure-service-operator/v2/internal/util/kubeclient" "github.com/Azure/azure-service-operator/v2/pkg/genruntime" @@ -427,7 +429,7 @@ func Test_ResolveSecrets_ReturnsExpectedSecretValue(t *testing.T) { ref := genruntime.SecretReference{Name: secretName, Key: secretKey} namespacedRef := ref.ToNamespacedRef(testNamespace) - resolvedSecrets, err := test.resolver.ResolveSecretReferences(ctx, map[genruntime.NamespacedSecretReference]struct{}{namespacedRef: {}}) + resolvedSecrets, err := test.resolver.ResolveSecretReferences(ctx, set.Make(namespacedRef)) g.Expect(err).ToNot(HaveOccurred()) actualSecret, err := resolvedSecrets.LookupSecret(ref) @@ -448,7 +450,7 @@ func Test_ResolveSecrets_ReturnsReferenceNotFound(t *testing.T) { ref := genruntime.SecretReference{Name: secretName, Key: secretKey} namespacedRef := ref.ToNamespacedRef(testNamespace) - _, err = test.resolver.ResolveSecretReferences(ctx, map[genruntime.NamespacedSecretReference]struct{}{namespacedRef: {}}) + _, err = test.resolver.ResolveSecretReferences(ctx, set.Make(namespacedRef)) g.Expect(err).To(HaveOccurred()) g.Expect(errors.Unwrap(err)).To(BeAssignableToTypeOf(&resolver.SecretNotFound{})) } diff --git a/v2/internal/resolver/secret_resolver.go b/v2/internal/resolver/secret_resolver.go index ed392f26707..4a47870e59a 100644 --- a/v2/internal/resolver/secret_resolver.go +++ b/v2/internal/resolver/secret_resolver.go @@ -13,6 +13,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/internal/util/kubeclient" "github.com/Azure/azure-service-operator/v2/pkg/genruntime" ) @@ -20,7 +21,7 @@ import ( // SecretResolver is a secret resolver type SecretResolver interface { ResolveSecretReference(ctx context.Context, ref genruntime.NamespacedSecretReference) (string, error) - ResolveSecretReferences(ctx context.Context, refs map[genruntime.NamespacedSecretReference]struct{}) (genruntime.ResolvedSecrets, error) + ResolveSecretReferences(ctx context.Context, refs set.Set[genruntime.NamespacedSecretReference]) (genruntime.ResolvedSecrets, error) } // kubeSecretResolver resolves Kubernetes secrets @@ -66,7 +67,7 @@ func (r *kubeSecretResolver) ResolveSecretReference(ctx context.Context, ref gen } // ResolveSecretReferences resolves all provided secret references -func (r *kubeSecretResolver) ResolveSecretReferences(ctx context.Context, refs map[genruntime.NamespacedSecretReference]struct{}) (genruntime.ResolvedSecrets, error) { +func (r *kubeSecretResolver) ResolveSecretReferences(ctx context.Context, refs set.Set[genruntime.NamespacedSecretReference]) (genruntime.ResolvedSecrets, error) { result := make(map[genruntime.SecretReference]string) for ref := range refs { diff --git a/v2/internal/set/set.go b/v2/internal/set/set.go new file mode 100644 index 00000000000..2f6b0ad7d79 --- /dev/null +++ b/v2/internal/set/set.go @@ -0,0 +1,73 @@ +/* + * Copyright (c) Microsoft Corporation. + * Licensed under the MIT license. + */ + +package set + +import ( + "golang.org/x/exp/constraints" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" +) + +// Set provides a standard way to have a set of distinct things +type Set[T comparable] map[T]struct{} + +// Make creates a new set with the given values +func Make[T comparable](ts ...T) Set[T] { + result := make(Set[T], len(ts)) + + for _, x := range ts { + result.Add(x) + } + + return result +} + +// Contains does a check to see if the provided value is in the set +func (set Set[T]) Contains(x T) bool { + _, ok := set[x] + return ok +} + +// Add adds the provided value into the set +// Nothing happens if the value is already present +func (set Set[T]) Add(x T) { + set[x] = struct{}{} +} + +// Remove deletes the provided value from the set +// Nothing happens if the value is not present +func (set Set[T]) Remove(x T) { + delete(set, x) +} + +// Copy returns an independent copy of the set +func (set Set[T]) Copy() Set[T] { + return maps.Clone(set) +} + +/* compiler crashes at the moment: https://github.com/golang/go/issues/51840 + +func (set Set[T]) Equals(other Set[T]) bool { + return maps.Equal(set, other) +} + +*/ + +func AreEqual[T comparable](left, right Set[T]) bool { + return maps.Equal(left, right) +} + +// Values returns a slice of all the values in the set +func (set Set[T]) Values() []T { + return maps.Keys(set) +} + +// AsSortedSlice returns a sorted slice of values from this set +func AsSortedSlice[T constraints.Ordered](set Set[T]) []T { + result := maps.Keys(set) + slices.Sort(result) + return result +} diff --git a/v2/pkg/genruntime/resource_reference.go b/v2/pkg/genruntime/resource_reference.go index ef821b6b10c..c4880142e6a 100644 --- a/v2/pkg/genruntime/resource_reference.go +++ b/v2/pkg/genruntime/resource_reference.go @@ -12,6 +12,8 @@ import ( "github.com/pkg/errors" kerrors "k8s.io/apimachinery/pkg/util/errors" + + "github.com/Azure/azure-service-operator/v2/internal/set" ) // KnownResourceReference is a resource reference to a known type. @@ -160,7 +162,7 @@ func (ref ResourceReference) Copy() ResourceReference { } // ValidateResourceReferences calls Validate on each ResourceReference -func ValidateResourceReferences(refs map[ResourceReference]struct{}) error { +func ValidateResourceReferences(refs set.Set[ResourceReference]) error { var errs []error for ref := range refs { errs = append(errs, ref.Validate()) diff --git a/v2/pkg/genruntime/secrets.go b/v2/pkg/genruntime/secrets.go index 2b489ca188b..828c4917d8b 100644 --- a/v2/pkg/genruntime/secrets.go +++ b/v2/pkg/genruntime/secrets.go @@ -8,6 +8,7 @@ package genruntime import ( "fmt" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/pkg/errors" ) @@ -101,19 +102,19 @@ func makeKeyPair(dest *SecretDestination) secretKeyPair { // those secrets to overwrite one another. func ValidateSecretDestinations(destinations []*SecretDestination) error { // Map of secret -> keys - //locations := make(map[string]map[string]struct{}) - locations := make(map[secretKeyPair]struct{}) + locations := set.Make[secretKeyPair]() for _, dest := range destinations { if dest == nil { continue } + pair := makeKeyPair(dest) - if _, ok := locations[pair]; ok { + if locations.Contains(pair) { return errors.Errorf("cannot write more than one secret to destination %s", dest.String()) } - locations[pair] = struct{}{} + locations.Add(pair) } return nil diff --git a/v2/tools/generator/go.mod b/v2/tools/generator/go.mod index 2c56fa27c23..7c1cb1e2c30 100644 --- a/v2/tools/generator/go.mod +++ b/v2/tools/generator/go.mod @@ -47,6 +47,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergi/go-diff v1.0.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd // indirect golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 // indirect diff --git a/v2/tools/generator/go.sum b/v2/tools/generator/go.sum index ae330997fb3..dfa7852157e 100644 --- a/v2/tools/generator/go.sum +++ b/v2/tools/generator/go.sum @@ -359,6 +359,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4= +golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/v2/tools/generator/internal/astmodel/flagged_type.go b/v2/tools/generator/internal/astmodel/flagged_type.go index 246c1de551e..5b6d0134794 100644 --- a/v2/tools/generator/internal/astmodel/flagged_type.go +++ b/v2/tools/generator/internal/astmodel/flagged_type.go @@ -6,15 +6,16 @@ package astmodel import ( - "sort" "strings" "github.com/dave/dst" + + "github.com/Azure/azure-service-operator/v2/internal/set" ) type FlaggedType struct { element Type - flags map[TypeFlag]struct{} + flags set.Set[TypeFlag] } var _ Type = &FlaggedType{} @@ -25,19 +26,19 @@ var _ MetaType = &FlaggedType{} func NewFlaggedType(t Type, flags ...TypeFlag) *FlaggedType { result := &FlaggedType{ element: t, - flags: make(map[TypeFlag]struct{}), + flags: set.Make[TypeFlag](), } if ft, ok := t.(*FlaggedType); ok { // It's flagged type, so unwrap to avoid nesting result.element = ft.element for f := range ft.flags { - result.flags[f] = struct{}{} + result.flags.Add(f) } } for _, f := range flags { - result.flags[f] = struct{}{} + result.flags.Add(f) } return result @@ -50,8 +51,7 @@ func (ft *FlaggedType) Element() Type { // HasFlag tests to see if this flagged type has the specified flag func (ft *FlaggedType) HasFlag(flag TypeFlag) bool { - _, ok := ft.flags[flag] - return ok + return ft.flags.Contains(flag) } // WithFlag returns a new FlaggedType with the specified flag added @@ -71,12 +71,8 @@ func (ft *FlaggedType) WithoutFlag(flag TypeFlag) Type { return ft.element } - flags := make(map[TypeFlag]struct{}) - for f := range ft.flags { - if f != flag { - flags[f] = struct{}{} - } - } + flags := ft.flags.Copy() + flags.Remove(flag) return &FlaggedType{ element: ft.element, @@ -90,12 +86,7 @@ func (ft *FlaggedType) WithElement(t Type) *FlaggedType { return ft // short-circuit } - var flags []TypeFlag - for f := range ft.flags { - flags = append(flags, f) - } - - return NewFlaggedType(t, flags...) + return NewFlaggedType(t, ft.flags.Values()...) } // RequiredPackageReferences returns a set of packages imports required by this type @@ -137,16 +128,10 @@ func (ft *FlaggedType) Equals(t Type, overrides EqualityOverrides) bool { return false } - if len(ft.flags) != len(other.flags) { + if !set.AreEqual(ft.flags, other.flags) { return false } - for f := range ft.flags { - if !other.HasFlag(f) { - return false - } - } - return ft.element.Equals(other.element, overrides) } @@ -158,13 +143,7 @@ func (ft *FlaggedType) String() string { result.WriteString(ft.element.String()) if len(ft.flags) > 0 { - var flags []TypeFlag - for f := range ft.flags { - flags = append(flags, f) - } - sort.Slice(flags, func(i, j int) bool { - return flags[i] < flags[j] - }) + flags := set.AsSortedSlice(ft.flags) result.WriteRune('[') for i, f := range flags { diff --git a/v2/tools/generator/internal/astmodel/identifier_factory.go b/v2/tools/generator/internal/astmodel/identifier_factory.go index b8a5531a999..f01f8efccd0 100644 --- a/v2/tools/generator/internal/astmodel/identifier_factory.go +++ b/v2/tools/generator/internal/astmodel/identifier_factory.go @@ -10,6 +10,8 @@ import ( "strings" "sync" "unicode" + + "github.com/Azure/azure-service-operator/v2/internal/set" ) // \W is all non-word characters (https://golang.org/pkg/regexp/syntax/) @@ -39,7 +41,7 @@ type IdentifierFactory interface { type identifierFactory struct { renames map[string]string reservedWords map[string]string - forbiddenReceiverSuffixes StringSet + forbiddenReceiverSuffixes set.Set[string] idCache idCache receiverCache map[string]string @@ -224,12 +226,8 @@ func createReservedWords() map[string]string { } // createForbiddenReceiverSuffixes creates a case-sensitive list of words we don't want to use as receiver names -func createForbiddenReceiverSuffixes() StringSet { - result := MakeStringSet() - result.Add("Status") - result.Add("Spec") - result.Add("ARM") - return result +func createForbiddenReceiverSuffixes() set.Set[string] { + return set.Make("Status", "Spec", "ARM") } func (factory *identifierFactory) CreateGroupName(group string) string { diff --git a/v2/tools/generator/internal/astmodel/known_locals_set.go b/v2/tools/generator/internal/astmodel/known_locals_set.go index 6b25448d9ed..5e1feb822eb 100644 --- a/v2/tools/generator/internal/astmodel/known_locals_set.go +++ b/v2/tools/generator/internal/astmodel/known_locals_set.go @@ -10,10 +10,12 @@ import ( "strings" "github.com/gobuffalo/flect" + + "github.com/Azure/azure-service-operator/v2/internal/set" ) type KnownLocalsSet struct { - names map[string]struct{} + names set.Set[string] idFactory IdentifierFactory } @@ -21,7 +23,7 @@ type KnownLocalsSet struct { // idFactory is a reference to an identifier factory for creating valid Go identifiers func NewKnownLocalsSet(idFactory IdentifierFactory) *KnownLocalsSet { return &KnownLocalsSet{ - names: make(map[string]struct{}), + names: set.Make[string](), idFactory: idFactory, } } @@ -41,7 +43,6 @@ func (locals *KnownLocalsSet) CreatePluralLocal(nameHint string, suffixes ...str // CreateLocal creates a new unique Go local variable with one of the specified suffixes. // Has to be deterministic, so we use an incrementing number to make them unique if necessary. func (locals *KnownLocalsSet) CreateLocal(nameHint string, suffixes ...string) string { - // Ensure we have a safe base case if len(suffixes) == 0 { suffixes = []string{""} @@ -88,12 +89,12 @@ func (locals *KnownLocalsSet) TryCreateLocal(local string) bool { // successful (local hasn't been used before) or "" and false if not (local already exists) func (locals *KnownLocalsSet) tryCreateLocal(name string) (string, bool) { id := locals.idFactory.CreateLocal(name) - if _, found := locals.names[id]; found { + if locals.names.Contains(id) { // Failed to create the name return "", false } - locals.names[id] = struct{}{} + locals.names.Add(id) return id, true } @@ -101,25 +102,19 @@ func (locals *KnownLocalsSet) tryCreateLocal(name string) (string, bool) { func (locals *KnownLocalsSet) Add(identifiers ...string) { for _, id := range identifiers { name := locals.idFactory.CreateLocal(id) - locals.names[name] = struct{}{} + locals.names.Add(name) } } // HasName returns true if the specified name exists in the set, false otherwise func (locals *KnownLocalsSet) HasName(name string) bool { - _, ok := locals.names[name] - return ok + return locals.names.Contains(name) } // Clone clones the KnownLocalsSet func (locals *KnownLocalsSet) Clone() *KnownLocalsSet { - names := make(map[string]struct{}, len(locals.names)) - for n := range locals.names { - names[n] = struct{}{} - } - return &KnownLocalsSet{ idFactory: locals.idFactory, - names: names, + names: locals.names.Copy(), } } diff --git a/v2/tools/generator/internal/astmodel/string_set.go b/v2/tools/generator/internal/astmodel/string_set.go deleted file mode 100644 index bbf993c2d49..00000000000 --- a/v2/tools/generator/internal/astmodel/string_set.go +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) Microsoft Corporation. - * Licensed under the MIT license. - */ - -package astmodel - -import ( - "sort" -) - -// StringSet provides a standard way to have a set of distinct strings with no sort applied -type StringSet map[string]struct{} - -// MakeStringSet creates a new set with the supplied strings -func MakeStringSet(strings ...string) StringSet { - result := make(StringSet) - - for _, s := range strings { - result.Add(s) - } - - return result -} - -// Contains does a case-sensitive check to see if the provided string is in the set -func (set StringSet) Contains(s string) bool { - _, ok := set[s] - return ok -} - -// Add adds the provided string into the set -// Nothing happens if the string is already present -func (set StringSet) Add(s string) { - set[s] = struct{}{} -} - -// Remove deletes the provided string from the set -// Nothing happens if the string is not present -func (set StringSet) Remove(s string) { - delete(set, s) -} - -// Copy returns an independent copy of the set -func (set StringSet) Copy() StringSet { - result := MakeStringSet() - for s := range set { - result.Add(s) - } - - return result -} - -// AsSlice returns a sorted slice of strings from this set -func (set StringSet) AsSortedSlice() []string { - result := make([]string, 0, len(set)) - for s := range set { - result = append(result, s) - } - - sort.Strings(result) - return result -} diff --git a/v2/tools/generator/internal/codegen/pipeline/check_for_anytype.go b/v2/tools/generator/internal/codegen/pipeline/check_for_anytype.go index b0a595e0a88..ff9e12ffd2e 100644 --- a/v2/tools/generator/internal/codegen/pipeline/check_for_anytype.go +++ b/v2/tools/generator/internal/codegen/pipeline/check_for_anytype.go @@ -13,6 +13,7 @@ import ( "github.com/pkg/errors" "k8s.io/klog/v2" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" ) @@ -38,7 +39,7 @@ func EnsureDefinitionsDoNotUseAnyTypes() *Stage { } func checkForAnyType(description string, packages []string) *Stage { - expectedPackages := astmodel.MakeStringSet() + expectedPackages := set.Make[string]() for _, p := range packages { expectedPackages.Add(p) } @@ -105,7 +106,7 @@ func packageName(name astmodel.TypeName) string { func collectBadPackages( names []astmodel.TypeName, - expectedPackages astmodel.StringSet, + expectedPackages set.Set[string], ) ([]string, error) { grouped := make(map[string][]string) for _, name := range names { diff --git a/v2/tools/generator/internal/codegen/pipeline/recursivetypefixer/simple_recursive_type_fixer.go b/v2/tools/generator/internal/codegen/pipeline/recursivetypefixer/simple_recursive_type_fixer.go index ad9c3ec4649..b6c331befea 100644 --- a/v2/tools/generator/internal/codegen/pipeline/recursivetypefixer/simple_recursive_type_fixer.go +++ b/v2/tools/generator/internal/codegen/pipeline/recursivetypefixer/simple_recursive_type_fixer.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" "k8s.io/klog/v2" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" ) @@ -68,16 +69,14 @@ func (s *SimpleRecursiveTypeFixer) unrollObjectTypeProperty(ot *astmodel.ObjectT // quick scan for others. This is to deal with situations where there are multiple properties we need to remove. // Without this check, we end up generating N different types (each with 1 property removed) which isn't allowed // because types with the same name must match structurally when we go to add them to the type collection later. - toRemove := map[astmodel.PropertyName]struct{}{ - prop.PropertyName(): {}, - } + toRemove := set.Make(prop.PropertyName()) for _, p := range ot.Properties().AsSlice() { if _, ok := toRemove[p.PropertyName()]; ok { continue } if isPropertyMatchingTypeName(name, p) { - toRemove[p.PropertyName()] = struct{}{} + toRemove.Add(p.PropertyName()) } } diff --git a/v2/tools/generator/internal/codegen/pipeline/report_resource_versions.go b/v2/tools/generator/internal/codegen/pipeline/report_resource_versions.go index 03e8ab7a7cd..7b6acbfea7b 100644 --- a/v2/tools/generator/internal/codegen/pipeline/report_resource_versions.go +++ b/v2/tools/generator/internal/codegen/pipeline/report_resource_versions.go @@ -17,6 +17,7 @@ import ( "github.com/pkg/errors" "k8s.io/klog/v2" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/config" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/reporting" @@ -38,7 +39,7 @@ func ReportResourceVersions(configuration *config.Configuration) *Stage { } type ResourceVersionsReport struct { - groups astmodel.StringSet // A set of all our groups + groups set.Set[string] // A set of all our groups kinds map[string]astmodel.TypeDefinitionSet // For each group, the set of all available resources // A separate list of resources for each package lists map[astmodel.PackageReference][]astmodel.TypeDefinition @@ -46,7 +47,7 @@ type ResourceVersionsReport struct { func NewResourceVersionsReport(definitions astmodel.TypeDefinitionSet) *ResourceVersionsReport { result := &ResourceVersionsReport{ - groups: astmodel.MakeStringSet(), + groups: set.Make[string](), kinds: make(map[string]astmodel.TypeDefinitionSet), lists: make(map[astmodel.PackageReference][]astmodel.TypeDefinition), } @@ -92,26 +93,25 @@ func (report *ResourceVersionsReport) WriteTo(outputPath string, samplesURL stri report.WriteToBuffer(&buffer, samplesURL) if _, err := os.Stat(outputPath); os.IsNotExist(err) { - err = os.MkdirAll(outputPath, 0700) + err = os.MkdirAll(outputPath, 0o700) if err != nil { return errors.Wrapf(err, "Unable to create directory %q", outputPath) } } destination := path.Join(outputPath, "resources.md") - return ioutil.WriteFile(destination, []byte(buffer.String()), 0600) + return ioutil.WriteFile(destination, []byte(buffer.String()), 0o600) } // WriteToBuffer creates the report in the provided buffer func (report *ResourceVersionsReport) WriteToBuffer(buffer *strings.Builder, samplesURL string) { - buffer.WriteString("# Supported Resources\n\n") buffer.WriteString("These are the resources with Azure Service Operator support committed to our **main** branch, ") buffer.WriteString("grouped by the originating ARM service. ") buffer.WriteString("(Newly supported resources will appear in this list prior to inclusion in any ASO release.)\n\n") // Sort groups into increasing order - groups := report.groups.AsSortedSlice() + groups := set.AsSortedSlice(report.groups) for _, svc := range groups { buffer.WriteString(fmt.Sprintf("## %s\n\n", strings.Title(svc))) @@ -124,7 +124,8 @@ func (report *ResourceVersionsReport) WriteToBuffer(buffer *strings.Builder, sam func (report *ResourceVersionsReport) createTable( resources astmodel.TypeDefinitionSet, group string, - samplesURL string) *reporting.MarkdownTable { + samplesURL string, +) *reporting.MarkdownTable { const ( name = "Resource" armVersion = "ARM Version" diff --git a/v2/tools/generator/internal/codegen/pipeline/stage.go b/v2/tools/generator/internal/codegen/pipeline/stage.go index 9d58b1d7e2b..459c1538a29 100644 --- a/v2/tools/generator/internal/codegen/pipeline/stage.go +++ b/v2/tools/generator/internal/codegen/pipeline/stage.go @@ -14,6 +14,7 @@ import ( kerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/klog/v2" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" ) @@ -38,7 +39,8 @@ type Stage struct { func NewStage( id string, description string, - action func(context.Context, *State) (*State, error)) *Stage { + action func(context.Context, *State) (*State, error), +) *Stage { return &Stage{ id: id, description: description, @@ -52,8 +54,8 @@ func NewStage( func NewLegacyStage( id string, description string, - action func(context.Context, astmodel.TypeDefinitionSet) (astmodel.TypeDefinitionSet, error)) *Stage { - + action func(context.Context, astmodel.TypeDefinitionSet) (astmodel.TypeDefinitionSet, error), +) *Stage { if !knownLegacyStages.Contains(id) { msg := fmt.Sprintf( "No new legacy stages (use NewStage instead): %s is not the id of a known legacy stage", @@ -74,7 +76,7 @@ func NewLegacyStage( }) } -var knownLegacyStages = astmodel.MakeStringSet( +var knownLegacyStages = set.Make( "addCrossResourceReferences", "addCrossplaneAtProviderProperty", "addCrossplaneEmbeddedResourceSpec", @@ -221,7 +223,6 @@ func (stage *Stage) checkPreconditions(state *State) error { // checkPrerequisites returns an error if the prerequisites of this stage have not been met func (stage *Stage) checkPrerequisites(state *State) error { - var errs []error for _, prereq := range stage.prerequisites { satisfied := state.stagesSeen.Contains(prereq) diff --git a/v2/tools/generator/internal/codegen/pipeline/state.go b/v2/tools/generator/internal/codegen/pipeline/state.go index ddd905147fe..759adcde689 100644 --- a/v2/tools/generator/internal/codegen/pipeline/state.go +++ b/v2/tools/generator/internal/codegen/pipeline/state.go @@ -9,16 +9,17 @@ import ( "github.com/pkg/errors" kerrors "k8s.io/apimachinery/pkg/util/errors" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/codegen/storage" ) // State is an immutable instance that captures the information being passed along the pipeline type State struct { - definitions astmodel.TypeDefinitionSet // set of type definitions generated so far - conversionGraph *storage.ConversionGraph // graph of transitions between packages in our conversion graph - stagesSeen astmodel.StringSet // set of ids of the stages already run - stagesExpected map[string]astmodel.StringSet // set of ids of expected stages, each with a set of ids for the stages expecting them + definitions astmodel.TypeDefinitionSet // set of type definitions generated so far + conversionGraph *storage.ConversionGraph // graph of transitions between packages in our conversion graph + stagesSeen set.Set[string] // set of ids of the stages already run + stagesExpected map[string]set.Set[string] // set of ids of expected stages, each with a set of ids for the stages expecting them } /* @@ -39,8 +40,8 @@ func NewState(definitions ...astmodel.TypeDefinitionSet) *State { return &State{ definitions: defs, conversionGraph: nil, - stagesSeen: astmodel.MakeStringSet(), - stagesExpected: make(map[string]astmodel.StringSet), + stagesSeen: set.Make[string](), + stagesExpected: make(map[string]set.Set[string]), } } @@ -78,7 +79,7 @@ func (s *State) WithExpectation(earlierStage string, laterStage string) *State { return result } - set := astmodel.MakeStringSet(earlierStage) + set := set.Make(earlierStage) result.stagesExpected[laterStage] = set return result diff --git a/v2/tools/generator/internal/config/configuration_visitor_test.go b/v2/tools/generator/internal/config/configuration_visitor_test.go index 722a75c6383..c028a1a7938 100644 --- a/v2/tools/generator/internal/config/configuration_visitor_test.go +++ b/v2/tools/generator/internal/config/configuration_visitor_test.go @@ -10,6 +10,7 @@ import ( . "github.com/onsi/gomega" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/test" ) @@ -19,7 +20,7 @@ func TestConfigurationVisitor_WhenVisitingEveryType_VisitsExpectedTypes(t *testi g := NewGomegaWithT(t) omc := createTestObjectModelConfigurationForVisitor() - seen := astmodel.MakeStringSet() + seen := set.Make[string]() visitor := NewEveryTypeConfigurationVisitor( func(configuration *TypeConfiguration) error { seen.Add(configuration.name) @@ -37,7 +38,7 @@ func TestConfigurationVisitor_WhenVisitingASpecificType_VisitsExpectedType(t *te g := NewGomegaWithT(t) omc := createTestObjectModelConfigurationForVisitor() - seen := astmodel.MakeStringSet() + seen := set.Make[string]() name := astmodel.MakeTypeName(test.Pkg2022, "Person") visitor := NewSingleTypeConfigurationVisitor( name, @@ -56,7 +57,7 @@ func TestConfigurationVisitor_WhenVisitingEveryProperty_VisitsExpectedProperties g := NewGomegaWithT(t) omc := createTestObjectModelConfigurationForVisitor() - seen := astmodel.MakeStringSet() + seen := set.Make[string]() visitor := NewEveryPropertyConfigurationVisitor( func(configuration *PropertyConfiguration) error { seen.Add(configuration.name) @@ -77,7 +78,7 @@ func TestConfigurationVisitor_WhenVisitingASpecificProperty_VisitsExpectedProper g := NewGomegaWithT(t) omc := createTestObjectModelConfigurationForVisitor() - seen := astmodel.MakeStringSet() + seen := set.Make[string]() name := astmodel.MakeTypeName(test.Pkg2022, "Person") visitor := NewSinglePropertyConfigurationVisitor( name, @@ -93,7 +94,6 @@ func TestConfigurationVisitor_WhenVisitingASpecificProperty_VisitsExpectedProper } func createTestObjectModelConfigurationForVisitor() *ObjectModelConfiguration { - lastName := NewPropertyConfiguration("LastName") firstName := NewPropertyConfiguration("FirstName") diff --git a/v2/tools/generator/internal/config/group_configuration.go b/v2/tools/generator/internal/config/group_configuration.go index 7dfb8cea164..716bdec36a6 100644 --- a/v2/tools/generator/internal/config/group_configuration.go +++ b/v2/tools/generator/internal/config/group_configuration.go @@ -13,6 +13,7 @@ import ( "gopkg.in/yaml.v3" kerrors "k8s.io/apimachinery/pkg/util/errors" + "github.com/Azure/azure-service-operator/v2/internal/set" "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" ) @@ -73,7 +74,7 @@ func (gc *GroupConfiguration) visitVersions(visitor *configurationVisitor) error var errs []error // All our versions are listed under multiple keys, so we hedge against processing them multiple times - versionsSeen := astmodel.MakeStringSet() + versionsSeen := set.Make[string]() for _, v := range gc.versions { if versionsSeen.Contains(v.name) { continue @@ -171,7 +172,7 @@ func (gc *GroupConfiguration) configuredVersions() []string { var result []string // All our versions are listed twice, under two different keys, so we hedge against processing them multiple times - versionsSeen := astmodel.MakeStringSet() + versionsSeen := set.Make[string]() for _, v := range gc.versions { if versionsSeen.Contains(v.name) { continue diff --git a/v2/tools/generator/internal/config/typo_advisor.go b/v2/tools/generator/internal/config/typo_advisor.go index 699751293f7..0c523a38116 100644 --- a/v2/tools/generator/internal/config/typo_advisor.go +++ b/v2/tools/generator/internal/config/typo_advisor.go @@ -13,18 +13,18 @@ import ( "github.com/hbollon/go-edlib" "github.com/pkg/errors" - "github.com/Azure/azure-service-operator/v2/tools/generator/internal/astmodel" + "github.com/Azure/azure-service-operator/v2/internal/set" ) // TypoAdvisor is a utility that helps augment errors with guidance when mistakes are made in configuration. type TypoAdvisor struct { lock sync.RWMutex - terms astmodel.StringSet // set of terms we know to exist + terms set.Set[string] // set of terms we know to exist } func NewTypoAdvisor() *TypoAdvisor { return &TypoAdvisor{ - terms: make(astmodel.StringSet), + terms: set.Make[string](), } } @@ -54,7 +54,7 @@ func (advisor *TypoAdvisor) Wrapf(originalError error, typo string, format strin suggestion, err := edlib.FuzzySearch( strings.ToLower(typo), - advisor.terms.AsSortedSlice(), + set.AsSortedSlice(advisor.terms), edlib.Levenshtein) if err != nil { // Can't offer a suggestion