diff --git a/pkg/cmd/apiresources/apiresources.go b/pkg/cmd/apiresources/apiresources.go index aa558e75..af57fda2 100644 --- a/pkg/cmd/apiresources/apiresources.go +++ b/pkg/cmd/apiresources/apiresources.go @@ -42,6 +42,9 @@ var ( # Print the supported API Resources with more information kubectl api-resources -o wide + # Print the supported API Resources sorted by a column + kubectl api-resources --sort-by=name + # Print the supported namespaced resources kubectl api-resources --namespaced=true @@ -56,6 +59,7 @@ var ( // As new fields are added, add them here instead of referencing the cmd.Flags() type APIResourceOptions struct { Output string + SortBy string APIGroup string Namespaced bool Verbs []string @@ -101,6 +105,7 @@ func NewCmdAPIResources(f cmdutil.Factory, ioStreams genericclioptions.IOStreams cmd.Flags().StringVar(&o.APIGroup, "api-group", o.APIGroup, "Limit to resources in the specified API group.") cmd.Flags().BoolVar(&o.Namespaced, "namespaced", o.Namespaced, "If false, non-namespaced resources will be returned, otherwise returning namespaced resources by default.") cmd.Flags().StringSliceVar(&o.Verbs, "verbs", o.Verbs, "Limit to resources that support the specified verbs.") + cmd.Flags().StringVar(&o.SortBy, "sort-by", o.SortBy, "If non-empty, sort nodes list using specified field. The field can be either 'name' or 'kind'.") cmd.Flags().BoolVar(&o.Cached, "cached", o.Cached, "Use the cached list of resources if available.") return cmd } @@ -111,6 +116,12 @@ func (o *APIResourceOptions) Validate() error { if !supportedOutputTypes.Has(o.Output) { return fmt.Errorf("--output %v is not available", o.Output) } + supportedSortTypes := sets.NewString("", "name", "kind") + if len(o.SortBy) > 0 { + if !supportedSortTypes.Has(o.SortBy) { + return fmt.Errorf("--sort-by accepts only name or kind") + } + } return nil } @@ -185,7 +196,7 @@ func (o *APIResourceOptions) RunAPIResources(cmd *cobra.Command, f cmdutil.Facto } } - sort.Stable(sortableGroupResource(resources)) + sort.Stable(sortableResource{resources, o.SortBy}) for _, r := range resources { switch o.Output { case "name": @@ -233,16 +244,31 @@ func printContextHeaders(out io.Writer, output string) error { return err } -type sortableGroupResource []groupResource +type sortableResource struct { + resources []groupResource + sortBy string +} -func (s sortableGroupResource) Len() int { return len(s) } -func (s sortableGroupResource) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s sortableGroupResource) Less(i, j int) bool { - ret := strings.Compare(s[i].APIGroup, s[j].APIGroup) +func (s sortableResource) Len() int { return len(s.resources) } +func (s sortableResource) Swap(i, j int) { + s.resources[i], s.resources[j] = s.resources[j], s.resources[i] +} +func (s sortableResource) Less(i, j int) bool { + ret := strings.Compare(s.compareValues(i, j)) if ret > 0 { return false } else if ret == 0 { - return strings.Compare(s[i].APIResource.Name, s[j].APIResource.Name) < 0 + return strings.Compare(s.resources[i].APIResource.Name, s.resources[j].APIResource.Name) < 0 } return true } + +func (s sortableResource) compareValues(i, j int) (string, string) { + switch s.sortBy { + case "name": + return s.resources[i].APIResource.Name, s.resources[j].APIResource.Name + case "kind": + return s.resources[i].APIResource.Kind, s.resources[j].APIResource.Kind + } + return s.resources[i].APIGroup, s.resources[j].APIGroup +}