diff --git a/.golangci.yml b/.golangci.yml index db6d2f49e..fa2747cf8 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -13,6 +13,7 @@ linters: - bidichk - bodyclose - copyloopvar + - depguard - dogsled - dupl - errcheck @@ -44,6 +45,12 @@ linters: - unused - whitespace settings: + depguard: + rules: + forbid-pkg-errors: + deny: + - pkg: sort + desc: Should be replaced with slices package forbidigo: forbid: - pattern: context.Background diff --git a/cmd/helpgen/main.go b/cmd/helpgen/main.go index b7b81a892..d6a9528de 100644 --- a/cmd/helpgen/main.go +++ b/cmd/helpgen/main.go @@ -6,7 +6,7 @@ import ( "go/format" "io" "os" - "sort" + "slices" "strings" flag "github.com/spf13/pflag" @@ -152,7 +152,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { for typ := range byType { typeNames = append(typeNames, typ) } - sort.Strings(typeNames) + slices.Sort(typeNames) outContent := new(bytes.Buffer) if headerText == "" { diff --git a/pkg/crd/flatten.go b/pkg/crd/flatten.go index cf02c9b71..927f67622 100644 --- a/pkg/crd/flatten.go +++ b/pkg/crd/flatten.go @@ -19,7 +19,7 @@ package crd import ( "fmt" "reflect" - "sort" + "slices" "strings" "sync" @@ -176,7 +176,7 @@ func flattenAllOfInto(dst *apiext.JSONSchemaProps, src apiext.JSONSchemaProps, e dst.Required = append(dst.Required, req) } // be deterministic - sort.Strings(dst.Required) + slices.Sort(dst.Required) } } diff --git a/pkg/crd/gen.go b/pkg/crd/gen.go index 5fad65a71..e50545ab9 100644 --- a/pkg/crd/gen.go +++ b/pkg/crd/gen.go @@ -20,7 +20,7 @@ import ( "fmt" "go/ast" "go/types" - "sort" + "slices" "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -328,8 +328,8 @@ func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) []schema.GroupKind for groupKind := range kubeKinds { groupKindList = append(groupKindList, groupKind) } - sort.Slice(groupKindList, func(i, j int) bool { - return groupKindList[i].String() < groupKindList[j].String() + slices.SortStableFunc(groupKindList, func(a, b schema.GroupKind) int { + return strings.Compare(a.String(), b.String()) }) return groupKindList diff --git a/pkg/crd/schema.go b/pkg/crd/schema.go index 4a95a1ced..05ae5a20f 100644 --- a/pkg/crd/schema.go +++ b/pkg/crd/schema.go @@ -22,7 +22,7 @@ import ( "go/ast" "go/token" "go/types" - "sort" + "slices" "strings" apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -173,10 +173,10 @@ func applyMarkers(ctx *schemaContext, markerSet markers.MarkerValues, props *api } } - cmpPriority := func(markers []schemaMarkerWithName, i, j int) bool { + cmpPriority := func(i, j schemaMarkerWithName) int { var iPriority, jPriority crdmarkers.ApplyPriority - switch m := markers[i].SchemaMarker.(type) { + switch m := i.SchemaMarker.(type) { case crdmarkers.ApplyPriorityMarker: iPriority = m.ApplyPriority() case applyFirstMarker: @@ -185,7 +185,7 @@ func applyMarkers(ctx *schemaContext, markerSet markers.MarkerValues, props *api iPriority = crdmarkers.ApplyPriorityDefault } - switch m := markers[j].SchemaMarker.(type) { + switch m := j.SchemaMarker.(type) { case crdmarkers.ApplyPriorityMarker: jPriority = m.ApplyPriority() case applyFirstMarker: @@ -194,10 +194,10 @@ func applyMarkers(ctx *schemaContext, markerSet markers.MarkerValues, props *api jPriority = crdmarkers.ApplyPriorityDefault } - return iPriority < jPriority + return int(iPriority - jPriority) } - sort.Slice(markers, func(i, j int) bool { return cmpPriority(markers, i, j) }) - sort.Slice(itemsMarkers, func(i, j int) bool { return cmpPriority(itemsMarkers, i, j) }) + slices.SortStableFunc(markers, func(i, j schemaMarkerWithName) int { return cmpPriority(i, j) }) + slices.SortStableFunc(itemsMarkers, func(i, j schemaMarkerWithName) int { return cmpPriority(i, j) }) for _, schemaMarker := range markers { if err := schemaMarker.SchemaMarker.ApplyToSchema(props); err != nil { @@ -519,7 +519,7 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON } // Ensure the required fields are always listed alphabetically. - sort.Strings(props.Required) + slices.Sort(props.Required) return props } diff --git a/pkg/crd/spec.go b/pkg/crd/spec.go index be9808570..4dee1cb69 100644 --- a/pkg/crd/spec.go +++ b/pkg/crd/spec.go @@ -18,7 +18,7 @@ package crd import ( "fmt" - "sort" + "slices" "strings" "github.com/gobuffalo/flect" @@ -139,7 +139,7 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) { // it is necessary to make sure the order of CRD versions in crd.Spec.Versions is stable and explicitly set crd.Spec.Version. // Otherwise, crd.Spec.Version may point to different CRD versions across different runs. - sort.Slice(crd.Spec.Versions, func(i, j int) bool { return crd.Spec.Versions[i].Name < crd.Spec.Versions[j].Name }) + slices.SortStableFunc(crd.Spec.Versions, func(a, b apiext.CustomResourceDefinitionVersion) int { return strings.Compare(a.Name, b.Name) }) // make sure we have *a* storage version // (default it if we only have one, otherwise, bail) diff --git a/pkg/deepcopy/deepcopy_integration_test.go b/pkg/deepcopy/deepcopy_integration_test.go index e0272995f..798b41023 100644 --- a/pkg/deepcopy/deepcopy_integration_test.go +++ b/pkg/deepcopy/deepcopy_integration_test.go @@ -19,7 +19,7 @@ package deepcopy_test import ( "io" "os" - "sort" + "slices" "github.com/google/go-cmp/cmp" . "github.com/onsi/ginkgo" @@ -46,7 +46,7 @@ func (m outputToMap) fileList() []string { for path := range m { ret = append(ret, path) } - sort.Strings(ret) + slices.Sort(ret) return ret } diff --git a/pkg/deepcopy/gen.go b/pkg/deepcopy/gen.go index a85cc8577..df436ec57 100644 --- a/pkg/deepcopy/gen.go +++ b/pkg/deepcopy/gen.go @@ -22,7 +22,7 @@ import ( "go/ast" "go/format" "io" - "sort" + "slices" "strings" "sigs.k8s.io/controller-tools/pkg/genall" @@ -273,7 +273,7 @@ func writeMethods(pkg *loader.Package, out io.Writer, byType map[string][]byte) for name := range byType { sortedNames = append(sortedNames, name) } - sort.Strings(sortedNames) + slices.Sort(sortedNames) for _, name := range sortedNames { _, err := out.Write(byType[name]) diff --git a/pkg/genall/help/sort.go b/pkg/genall/help/sort.go index 53c923e34..c30cd7f12 100644 --- a/pkg/genall/help/sort.go +++ b/pkg/genall/help/sort.go @@ -24,8 +24,8 @@ import ( // SortGroup knows how to sort and group marker definitions. type SortGroup interface { - // Less is equivalent to the Less function from sort, and is used to sort the markers. - Less(*markers.Definition, *markers.Definition) bool + // Compare is equivalent to the compare function from slices, and is used to sort the markers. + Compare(*markers.Definition, *markers.Definition) int // Group returns the "group" that a given marker belongs to. Group(*markers.Definition, *markers.DefinitionHelp) string } @@ -46,13 +46,13 @@ func (sortByCategory) Group(_ *markers.Definition, help *markers.DefinitionHelp) } return help.Category } -func (sortByCategory) Less(i, j *markers.Definition) bool { - return i.Name < j.Name +func (sortByCategory) Compare(i, j *markers.Definition) int { + return strings.Compare(j.Name, i.Name) } type optionsSort struct{} -func (optionsSort) Less(i, j *markers.Definition) bool { +func (optionsSort) Compare(i, j *markers.Definition) int { iParts := strings.Split(i.Name, ":") jParts := strings.Split(j.Name, ":") @@ -83,10 +83,10 @@ func (optionsSort) Less(i, j *markers.Definition) bool { } if iGen != jGen { - return iGen > jGen + return strings.Compare(iGen, jGen) } - return iRule < jRule + return strings.Compare(jRule, iRule) } func (optionsSort) Group(def *markers.Definition, _ *markers.DefinitionHelp) string { parts := strings.Split(def.Name, ":") diff --git a/pkg/genall/help/types.go b/pkg/genall/help/types.go index be1110432..57cdad4b0 100644 --- a/pkg/genall/help/types.go +++ b/pkg/genall/help/types.go @@ -17,7 +17,7 @@ limitations under the License. package help import ( - "sort" + "slices" "strings" "sigs.k8s.io/controller-tools/pkg/markers" @@ -166,7 +166,7 @@ func ForDefinition(defn *markers.Definition, maybeHelp *markers.DefinitionHelp) res.Fields = append(res.Fields, fieldHelp) } - sort.Slice(res.Fields, func(i, j int) bool { return res.Fields[i].Name < res.Fields[j].Name }) + slices.SortStableFunc(res.Fields, func(a, b FieldHelp) int { return strings.Compare(a.Name, b.Name) }) return res } @@ -191,17 +191,17 @@ func ByCategory(reg *markers.Registry, sorter SortGroup) []CategoryDoc { allGroups = append(allGroups, groupName) } - sort.Strings(allGroups) + slices.Sort(allGroups) res := make([]CategoryDoc, len(allGroups)) for i, groupName := range allGroups { - markers := groupedMarkers[groupName] - sort.Slice(markers, func(i, j int) bool { - return sorter.Less(markers[i], markers[j]) + mks := groupedMarkers[groupName] + slices.SortStableFunc(mks, func(a, b *markers.Definition) int { + return sorter.Compare(a, b) }) - markerDocs := make([]MarkerDoc, len(markers)) - for i, marker := range markers { + markerDocs := make([]MarkerDoc, len(mks)) + for i, marker := range mks { markerDocs[i] = ForDefinition(marker, reg.HelpFor(marker)) } diff --git a/pkg/rbac/parser.go b/pkg/rbac/parser.go index 6521d2658..54a0c0aa8 100644 --- a/pkg/rbac/parser.go +++ b/pkg/rbac/parser.go @@ -24,7 +24,7 @@ package rbac import ( "fmt" - "sort" + "slices" "strings" rbacv1 "k8s.io/api/rbac/v1" @@ -74,13 +74,6 @@ func (key ruleKey) String() string { return fmt.Sprintf("%s + %s + %s + %s", key.Groups, key.Resources, key.ResourceNames, key.URLs) } -// ruleKeys implements sort.Interface -type ruleKeys []ruleKey - -func (keys ruleKeys) Len() int { return len(keys) } -func (keys ruleKeys) Swap(i, j int) { keys[i], keys[j] = keys[j], keys[i] } -func (keys ruleKeys) Less(i, j int) bool { return keys[i].String() < keys[j].String() } - // key normalizes the Rule and returns a ruleKey object. func (r *Rule) key() ruleKey { r.normalize() @@ -139,7 +132,7 @@ func removeDupAndSort(strs []string) []string { for str := range set { result = append(result, str) } - sort.Strings(result) + slices.Sort(result) return result } @@ -304,7 +297,9 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{ for key := range ruleMap { keys = append(keys, key) } - sort.Sort(ruleKeys(keys)) + slices.SortStableFunc(keys, func(a, b ruleKey) int { + return strings.Compare(a.String(), b.String()) + }) // Normalize rule verbs to "*" if any verb in the rule is an asterisk for _, rule := range ruleMap { @@ -327,7 +322,7 @@ func GenerateRoles(ctx *genall.GenerationContext, roleName string) ([]interface{ for ns := range rulesByNSResource { namespaces = append(namespaces, ns) } - sort.Strings(namespaces) + slices.Sort(namespaces) // process the items in rulesByNS by the order specified in `namespaces` to make sure that the Role order is stable var objs []interface{} diff --git a/pkg/webhook/parser.go b/pkg/webhook/parser.go index 2737562be..28bdbca7b 100644 --- a/pkg/webhook/parser.go +++ b/pkg/webhook/parser.go @@ -25,7 +25,6 @@ package webhook import ( "fmt" "slices" - "sort" "strings" admissionregv1 "k8s.io/api/admissionregistration/v1" @@ -484,8 +483,8 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error { } cfgs := markerSet[ConfigDefinition.Name] - sort.SliceStable(cfgs, func(i, j int) bool { - return cfgs[i].(Config).Name < cfgs[j].(Config).Name + slices.SortStableFunc(cfgs, func(a, b any) int { + return strings.Compare(a.(Config).Name, b.(Config).Name) }) for _, cfg := range cfgs {