From 80cd05d5bb4edabe24a9e84cbfd499c899d81347 Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:45:49 +0200 Subject: [PATCH 1/6] feat: allow configuring default sort columns for each resource --- internal/cmd/base/list.go | 8 +- internal/cmd/base/list_test.go | 83 ++++++++++-- internal/cmd/certificate/list.go | 2 + internal/cmd/config/helptext/preferences.txt | 95 ++++++++++---- internal/cmd/datacenter/list.go | 2 + internal/cmd/firewall/list.go | 2 + internal/cmd/floatingip/list.go | 2 + internal/cmd/image/list.go | 3 + internal/cmd/iso/list.go | 3 + internal/cmd/loadbalancer/list.go | 3 + internal/cmd/loadbalancertype/list.go | 5 +- internal/cmd/location/list.go | 2 + internal/cmd/network/list.go | 2 + internal/cmd/placementgroup/list.go | 2 + internal/cmd/primaryip/list.go | 2 + internal/cmd/server/list.go | 5 +- internal/cmd/servertype/list.go | 5 +- internal/cmd/sshkey/list.go | 2 + internal/cmd/volume/list.go | 2 + internal/state/config/options.go | 128 +++++++++++++++++++ 20 files changed, 316 insertions(+), 42 deletions(-) diff --git a/internal/cmd/base/list.go b/internal/cmd/base/list.go index a878a653..3efcef27 100644 --- a/internal/cmd/base/list.go +++ b/internal/cmd/base/list.go @@ -10,11 +10,13 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" ) // ListCmd allows defining commands for listing resources type ListCmd struct { + SortOption *config.Option[[]string] ResourceNamePlural string // e.g. "servers" JSONKeyGetByName string // e.g. "servers" DefaultColumns []string @@ -48,7 +50,7 @@ func (lc *ListCmd) CobraCommand(s state.State) *cobra.Command { if lc.AdditionalFlags != nil { lc.AdditionalFlags(cmd) } - cmd.Flags().StringSliceP("sort", "s", []string{"id:asc"}, "Determine the sorting of the result") + cmd.Flags().StringSliceP("sort", "s", []string{}, "Determine the sorting of the result") return cmd } @@ -61,7 +63,11 @@ func (lc *ListCmd) Run(s state.State, cmd *cobra.Command) error { LabelSelector: labelSelector, PerPage: 50, } + sorts, _ := cmd.Flags().GetStringSlice("sort") + if !cmd.Flags().Changed("sort") { + sorts = lc.SortOption.Get(s.Config()) + } resources, err := lc.Fetch(s, cmd.Flags(), listOpts, sorts) if err != nil { diff --git a/internal/cmd/base/list_test.go b/internal/cmd/base/list_test.go index 8b51c7a0..088667cb 100644 --- a/internal/cmd/base/list_test.go +++ b/internal/cmd/base/list_test.go @@ -1,15 +1,19 @@ package base_test import ( + "cmp" "fmt" + "slices" "testing" "github.com/spf13/pflag" "github.com/hetznercloud/cli/internal/cmd/base" "github.com/hetznercloud/cli/internal/cmd/output" + "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/cli/internal/testutil" "github.com/hetznercloud/hcloud-go/v2/hcloud" ) @@ -36,30 +40,62 @@ var fakeListCmd = &base.ListCmd{ DefaultColumns: []string{"id", "name"}, - Fetch: func(s state.State, set *pflag.FlagSet, opts hcloud.ListOpts, strings []string) ([]interface{}, error) { - return []interface{}{ - &fakeResource{ + Fetch: func(s state.State, set *pflag.FlagSet, opts hcloud.ListOpts, sort []string) ([]interface{}, error) { + resources := []*fakeResource{ + { + ID: 456, + Name: "test2", + }, + { ID: 123, Name: "test", }, - &fakeResource{ - ID: 321, - Name: "test2", - }, - &fakeResource{ - ID: 42, + { + ID: 789, Name: "test3", }, - }, nil + } + if len(sort) > 0 { + switch sort[0] { + case "id:asc": + slices.SortFunc(resources, func(a, b *fakeResource) int { + return cmp.Compare(a.ID, b.ID) + }) + case "id:desc": + slices.SortFunc(resources, func(a, b *fakeResource) int { + return cmp.Compare(b.ID, a.ID) + }) + case "name:asc": + slices.SortFunc(resources, func(a, b *fakeResource) int { + return cmp.Compare(a.Name, b.Name) + }) + case "name:desc": + slices.SortFunc(resources, func(a, b *fakeResource) int { + return cmp.Compare(b.Name, a.Name) + }) + } + } + return util.ToAnySlice(resources), nil }, } func TestList(t *testing.T) { - const resourceSchema = `[{"id": 123, "name": "test"}, {"id": 321, "name": "test2"}, {"id": 42, "name": "test3"}]` + sortOpt, cleanup := config.NewTestOption( + "sort.fakeresource", + "", + []string{"id:asc"}, + (config.DefaultPreferenceFlags&^config.OptionFlagPFlag)|config.OptionFlagSlice, + nil, + ) + defer cleanup() + + fakeListCmd.SortOption = sortOpt + + const resourceSchema = `[{"id": 123, "name": "test"}, {"id": 456, "name": "test2"}, {"id": 789, "name": "test3"}]` testutil.TestCommand(t, fakeListCmd, map[string]testutil.TestCase{ "no flags": { Args: []string{"list"}, - ExpOut: "ID NAME\n123 test\n321 test2\n42 test3\n", + ExpOut: "ID NAME\n123 test\n456 test2\n789 test3\n", }, "json": { Args: []string{"list", "-o=json"}, @@ -73,7 +109,7 @@ func TestList(t *testing.T) { }, "quiet": { Args: []string{"list", "--quiet"}, - ExpOut: "ID NAME\n123 test\n321 test2\n42 test3\n", + ExpOut: "ID NAME\n123 test\n456 test2\n789 test3\n", }, "json quiet": { Args: []string{"list", "-o=json", "--quiet"}, @@ -85,5 +121,26 @@ func TestList(t *testing.T) { ExpOut: resourceSchema, ExpOutType: testutil.DataTypeYAML, }, + "sort": { + Args: []string{"list", "--sort", "id:desc", "-o=json"}, + ExpOut: `[{"id": 789, "name": "test3"}, {"id": 456, "name": "test2"}, {"id": 123, "name": "test"}]`, + ExpOutType: testutil.DataTypeJSON, + }, + "no sort": { + Args: []string{"list", "--sort=", "-o=json"}, + ExpOut: `[{"id": 456, "name": "test2"}, {"id": 123, "name": "test"}, {"id": 789, "name": "test3"}]`, + ExpOutType: testutil.DataTypeJSON, + }, + "sort with option": { + Args: []string{"list", "-o=json"}, + PreRun: func(t *testing.T, fx *testutil.Fixture) { + sortOpt.Override(fx.Config, []string{"id:desc"}) + t.Cleanup(func() { + sortOpt.Override(fx.Config, nil) + }) + }, + ExpOut: `[{"id": 789, "name": "test3"}, {"id": 456, "name": "test2"}, {"id": 123, "name": "test"}]`, + ExpOutType: testutil.DataTypeJSON, + }, }) } diff --git a/internal/cmd/certificate/list.go b/internal/cmd/certificate/list.go index 9acc0a19..58005e35 100644 --- a/internal/cmd/certificate/list.go +++ b/internal/cmd/certificate/list.go @@ -11,6 +11,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -19,6 +20,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Certificates", JSONKeyGetByName: "certificates", DefaultColumns: []string{"id", "name", "type", "domain_names", "not_valid_after", "age"}, + SortOption: config.OptionSortCertificate, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.CertificateListOpts{ListOpts: listOpts} diff --git a/internal/cmd/config/helptext/preferences.txt b/internal/cmd/config/helptext/preferences.txt index 7c686bff..f82b07dd 100644 --- a/internal/cmd/config/helptext/preferences.txt +++ b/internal/cmd/config/helptext/preferences.txt @@ -1,22 +1,73 @@ -┌──────────────────┬──────────────────────┬─────────────┬──────────────────┬─────────────────────────┬─────────────────┐ -│ OPTION │ DESCRIPTION │ TYPE │ CONFIG KEY │ ENVIRONMENT VARIABLE │ FLAG │ -├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ -│ debug │ Enable debug output │ boolean │ debug │ HCLOUD_DEBUG │ --debug │ -├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ -│ debug-file │ File to write debug │ string │ debug_file │ HCLOUD_DEBUG_FILE │ --debug-file │ -│ │ output to │ │ │ │ │ -├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ -│ default-ssh-keys │ Default SSH keys for │ string list │ default_ssh_keys │ HCLOUD_DEFAULT_SSH_KEYS │ │ -│ │ new servers │ │ │ │ │ -├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ -│ endpoint │ Hetzner Cloud API │ string │ endpoint │ HCLOUD_ENDPOINT │ --endpoint │ -│ │ endpoint │ │ │ │ │ -├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ -│ poll-interval │ Interval at which to │ duration │ poll_interval │ HCLOUD_POLL_INTERVAL │ --poll-interval │ -│ │ poll information, │ │ │ │ │ -│ │ for example action │ │ │ │ │ -│ │ progress │ │ │ │ │ -├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ -│ quiet │ If true, only print │ boolean │ quiet │ HCLOUD_QUIET │ --quiet │ -│ │ error messages │ │ │ │ │ -└──────────────────┴──────────────────────┴─────────────┴──────────────────┴─────────────────────────┴─────────────────┘ +┌───────────────────────┬──────────────────────┬─────────────┬───────────────────────┬──────────────────────────────┬─────────────────┐ +│ OPTION │ DESCRIPTION │ TYPE │ CONFIG KEY │ ENVIRONMENT VARIABLE │ FLAG │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ debug │ Enable debug output │ boolean │ debug │ HCLOUD_DEBUG │ --debug │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ debug-file │ File to write debug │ string │ debug_file │ HCLOUD_DEBUG_FILE │ --debug-file │ +│ │ output to │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ default-ssh-keys │ Default SSH keys for │ string list │ default_ssh_keys │ HCLOUD_DEFAULT_SSH_KEYS │ │ +│ │ new servers │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ endpoint │ Hetzner Cloud API │ string │ endpoint │ HCLOUD_ENDPOINT │ --endpoint │ +│ │ endpoint │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ poll-interval │ Interval at which to │ duration │ poll_interval │ HCLOUD_POLL_INTERVAL │ --poll-interval │ +│ │ poll information, │ │ │ │ │ +│ │ for example action │ │ │ │ │ +│ │ progress │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ quiet │ If true, only print │ boolean │ quiet │ HCLOUD_QUIET │ --quiet │ +│ │ error messages │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.certificate │ Default sorting for │ string list │ sort.certificate │ HCLOUD_SORT.CERTIFICATE │ │ +│ │ Certificate resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.datacenter │ Default sorting for │ string list │ sort.datacenter │ HCLOUD_SORT.DATACENTER │ │ +│ │ Datacenter resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.firewall │ Default sorting for │ string list │ sort.firewall │ HCLOUD_SORT.FIREWALL │ │ +│ │ Firewall resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.floatingip │ Default sorting for │ string list │ sort.floatingip │ HCLOUD_SORT.FLOATINGIP │ │ +│ │ Floating IP resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.image │ Default sorting for │ string list │ sort.image │ HCLOUD_SORT.IMAGE │ │ +│ │ Image resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.iso │ Default sorting for │ string list │ sort.iso │ HCLOUD_SORT.ISO │ │ +│ │ ISO resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.loadbalancer │ Default sorting for │ string list │ sort.loadbalancer │ HCLOUD_SORT.LOADBALANCER │ │ +│ │ Load Balancer │ │ │ │ │ +│ │ resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.loadbalancertype │ Default sorting for │ string list │ sort.loadbalancertype │ HCLOUD_SORT.LOADBALANCERTYPE │ │ +│ │ Load Balancer Type │ │ │ │ │ +│ │ resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.location │ Default sorting for │ string list │ sort.location │ HCLOUD_SORT.LOCATION │ │ +│ │ Location resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.network │ Default sorting for │ string list │ sort.network │ HCLOUD_SORT.NETWORK │ │ +│ │ Network resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.placementgroup │ Default sorting for │ string list │ sort.placementgroup │ HCLOUD_SORT.PLACEMENTGROUP │ │ +│ │ Placement Group │ │ │ │ │ +│ │ resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.primaryip │ Default sorting for │ string list │ sort.primaryip │ HCLOUD_SORT.PRIMARYIP │ │ +│ │ Primary IP resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.server │ Default sorting for │ string list │ sort.server │ HCLOUD_SORT.SERVER │ │ +│ │ Server resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.servertype │ Default sorting for │ string list │ sort.servertype │ HCLOUD_SORT.SERVERTYPE │ │ +│ │ Server Type resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.sshkey │ Default sorting for │ string list │ sort.sshkey │ HCLOUD_SORT.SSHKEY │ │ +│ │ SSH Key resource │ │ │ │ │ +├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ +│ sort.volume │ Default sorting for │ string list │ sort.volume │ HCLOUD_SORT.VOLUME │ │ +│ │ Volume resource │ │ │ │ │ +└───────────────────────┴──────────────────────┴─────────────┴───────────────────────┴──────────────────────────────┴─────────────────┘ diff --git a/internal/cmd/datacenter/list.go b/internal/cmd/datacenter/list.go index 0894c0d0..a01355e7 100644 --- a/internal/cmd/datacenter/list.go +++ b/internal/cmd/datacenter/list.go @@ -7,6 +7,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -15,6 +16,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Datacenters", JSONKeyGetByName: "datacenters", DefaultColumns: []string{"id", "name", "description", "location"}, + SortOption: config.OptionSortDatacenter, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.DatacenterListOpts{ListOpts: listOpts} diff --git a/internal/cmd/firewall/list.go b/internal/cmd/firewall/list.go index a983840e..ae7a96e2 100644 --- a/internal/cmd/firewall/list.go +++ b/internal/cmd/firewall/list.go @@ -9,6 +9,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -17,6 +18,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Firewalls", JSONKeyGetByName: "firewalls", DefaultColumns: []string{"id", "name", "rules_count", "applied_to_count"}, + SortOption: config.OptionSortFirewall, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.FirewallListOpts{ListOpts: listOpts} diff --git a/internal/cmd/floatingip/list.go b/internal/cmd/floatingip/list.go index c2710642..a73ed540 100644 --- a/internal/cmd/floatingip/list.go +++ b/internal/cmd/floatingip/list.go @@ -12,6 +12,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -20,6 +21,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Floating IPs", JSONKeyGetByName: "floating_ips", DefaultColumns: []string{"id", "type", "name", "description", "ip", "home", "server", "dns", "age"}, + SortOption: config.OptionSortFloatingIP, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.FloatingIPListOpts{ListOpts: listOpts} diff --git a/internal/cmd/image/list.go b/internal/cmd/image/list.go index 5cdcc5b6..2a88165b 100644 --- a/internal/cmd/image/list.go +++ b/internal/cmd/image/list.go @@ -15,6 +15,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -23,6 +24,8 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Images", JSONKeyGetByName: "images", DefaultColumns: []string{"id", "type", "name", "description", "architecture", "image_size", "disk_size", "created", "deprecated"}, + SortOption: config.OptionSortImage, + AdditionalFlags: func(cmd *cobra.Command) { cmd.Flags().StringSliceP("type", "t", []string{}, "Only show images of given type: system|app|snapshot|backup") cmd.RegisterFlagCompletionFunc("type", cmpl.SuggestCandidates("backup", "snapshot", "system", "app")) diff --git a/internal/cmd/iso/list.go b/internal/cmd/iso/list.go index 2eebd966..4ab42208 100644 --- a/internal/cmd/iso/list.go +++ b/internal/cmd/iso/list.go @@ -13,6 +13,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -21,6 +22,8 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "ISOs", JSONKeyGetByName: "isos", DefaultColumns: []string{"id", "name", "description", "type", "architecture"}, + SortOption: config.OptionSortISO, + AdditionalFlags: func(cmd *cobra.Command) { cmd.Flags().StringSlice("architecture", []string{}, "Only show images of given architecture: x86|arm") cmd.RegisterFlagCompletionFunc("architecture", cmpl.SuggestCandidates(string(hcloud.ArchitectureX86), string(hcloud.ArchitectureARM))) diff --git a/internal/cmd/loadbalancer/list.go b/internal/cmd/loadbalancer/list.go index 3039143a..bbe31b96 100644 --- a/internal/cmd/loadbalancer/list.go +++ b/internal/cmd/loadbalancer/list.go @@ -11,6 +11,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -19,6 +20,8 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Load Balancer", JSONKeyGetByName: "load_balancers", DefaultColumns: []string{"id", "name", "health", "ipv4", "ipv6", "type", "location", "network_zone", "age"}, + SortOption: config.OptionSortLoadBalancer, + Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.LoadBalancerListOpts{ListOpts: listOpts} if len(sorts) > 0 { diff --git a/internal/cmd/loadbalancertype/list.go b/internal/cmd/loadbalancertype/list.go index 20fff54a..6c73d7c1 100644 --- a/internal/cmd/loadbalancertype/list.go +++ b/internal/cmd/loadbalancertype/list.go @@ -7,6 +7,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -14,8 +15,8 @@ import ( var ListCmd = base.ListCmd{ ResourceNamePlural: "Load Balancer Types", JSONKeyGetByName: "load_balancer_types", - - DefaultColumns: []string{"id", "name", "description", "max_services", "max_connections", "max_targets"}, + DefaultColumns: []string{"id", "name", "description", "max_services", "max_connections", "max_targets"}, + SortOption: config.OptionSortLoadBalancerType, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.LoadBalancerTypeListOpts{ListOpts: listOpts} diff --git a/internal/cmd/location/list.go b/internal/cmd/location/list.go index 25f2b14f..eaf16214 100644 --- a/internal/cmd/location/list.go +++ b/internal/cmd/location/list.go @@ -7,6 +7,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -15,6 +16,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "locations", JSONKeyGetByName: "locations", DefaultColumns: []string{"id", "name", "description", "network_zone", "country", "city"}, + SortOption: config.OptionSortLocation, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.LocationListOpts{ListOpts: listOpts} diff --git a/internal/cmd/network/list.go b/internal/cmd/network/list.go index d6da407f..26d5ef55 100644 --- a/internal/cmd/network/list.go +++ b/internal/cmd/network/list.go @@ -12,6 +12,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -20,6 +21,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Networks", JSONKeyGetByName: "networks", DefaultColumns: []string{"id", "name", "ip_range", "servers", "age"}, + SortOption: config.OptionSortNetwork, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.NetworkListOpts{ListOpts: listOpts} diff --git a/internal/cmd/placementgroup/list.go b/internal/cmd/placementgroup/list.go index 487b620b..959c339e 100644 --- a/internal/cmd/placementgroup/list.go +++ b/internal/cmd/placementgroup/list.go @@ -11,6 +11,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -19,6 +20,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Placement Groups", JSONKeyGetByName: "placement_groups", DefaultColumns: []string{"id", "name", "servers", "type", "age"}, + SortOption: config.OptionSortPlacementGroup, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.PlacementGroupListOpts{ListOpts: listOpts} diff --git a/internal/cmd/primaryip/list.go b/internal/cmd/primaryip/list.go index 5996d042..a06f23c6 100644 --- a/internal/cmd/primaryip/list.go +++ b/internal/cmd/primaryip/list.go @@ -12,6 +12,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -20,6 +21,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Primary IPs", JSONKeyGetByName: "primary_ips", DefaultColumns: []string{"id", "type", "name", "ip", "assignee", "dns", "auto_delete", "age"}, + SortOption: config.OptionSortPrimaryIP, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.PrimaryIPListOpts{ListOpts: listOpts} diff --git a/internal/cmd/server/list.go b/internal/cmd/server/list.go index 4ae20539..9ee33baa 100644 --- a/internal/cmd/server/list.go +++ b/internal/cmd/server/list.go @@ -17,6 +17,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -36,8 +37,8 @@ var serverStatusStrings = []string{ var ListCmd = base.ListCmd{ ResourceNamePlural: "Servers", JSONKeyGetByName: "servers", - - DefaultColumns: []string{"id", "name", "status", "ipv4", "ipv6", "private_net", "datacenter", "age"}, + DefaultColumns: []string{"id", "name", "status", "ipv4", "ipv6", "private_net", "datacenter", "age"}, + SortOption: config.OptionSortServer, AdditionalFlags: func(cmd *cobra.Command) { cmd.Flags().StringSlice("status", nil, "Only servers with one of these statuses are displayed") diff --git a/internal/cmd/servertype/list.go b/internal/cmd/servertype/list.go index c55755a8..68cd0424 100644 --- a/internal/cmd/servertype/list.go +++ b/internal/cmd/servertype/list.go @@ -10,6 +10,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -17,8 +18,8 @@ import ( var ListCmd = base.ListCmd{ ResourceNamePlural: "Server Types", JSONKeyGetByName: "server_types", - - DefaultColumns: []string{"id", "name", "cores", "cpu_type", "architecture", "memory", "disk", "storage_type", "traffic"}, + DefaultColumns: []string{"id", "name", "cores", "cpu_type", "architecture", "memory", "disk", "storage_type", "traffic"}, + SortOption: config.OptionSortServerType, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.ServerTypeListOpts{ListOpts: listOpts} diff --git a/internal/cmd/sshkey/list.go b/internal/cmd/sshkey/list.go index 996d4030..79099629 100644 --- a/internal/cmd/sshkey/list.go +++ b/internal/cmd/sshkey/list.go @@ -10,6 +10,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -18,6 +19,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "SSH keys", JSONKeyGetByName: "ssh_keys", DefaultColumns: []string{"id", "name", "fingerprint", "age"}, + SortOption: config.OptionSortSSHKey, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.SSHKeyListOpts{ListOpts: listOpts} diff --git a/internal/cmd/volume/list.go b/internal/cmd/volume/list.go index 713e14d5..2e85720b 100644 --- a/internal/cmd/volume/list.go +++ b/internal/cmd/volume/list.go @@ -12,6 +12,7 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -20,6 +21,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Volumes", JSONKeyGetByName: "volumes", DefaultColumns: []string{"id", "name", "size", "server", "location", "age"}, + SortOption: config.OptionSortVolume, Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.VolumeListOpts{ListOpts: listOpts} diff --git a/internal/state/config/options.go b/internal/state/config/options.go index a52cc68f..b1542a70 100644 --- a/internal/state/config/options.go +++ b/internal/state/config/options.go @@ -141,6 +141,134 @@ var ( (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, nil, ) + + OptionSortCertificate = newOpt( + "sort.certificate", + "Default sorting for Certificate resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortDatacenter = newOpt( + "sort.datacenter", + "Default sorting for Datacenter resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortFirewall = newOpt( + "sort.firewall", + "Default sorting for Firewall resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortFloatingIP = newOpt( + "sort.floatingip", + "Default sorting for Floating IP resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortImage = newOpt( + "sort.image", + "Default sorting for Image resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortISO = newOpt( + "sort.iso", + "Default sorting for ISO resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortLoadBalancer = newOpt( + "sort.loadbalancer", + "Default sorting for Load Balancer resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortLoadBalancerType = newOpt( + "sort.loadbalancertype", + "Default sorting for Load Balancer Type resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortLocation = newOpt( + "sort.location", + "Default sorting for Location resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortNetwork = newOpt( + "sort.network", + "Default sorting for Network resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortPlacementGroup = newOpt( + "sort.placementgroup", + "Default sorting for Placement Group resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortPrimaryIP = newOpt( + "sort.primaryip", + "Default sorting for Primary IP resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortServer = newOpt( + "sort.server", + "Default sorting for Server resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortServerType = newOpt( + "sort.servertype", + "Default sorting for Server Type resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortSSHKey = newOpt( + "sort.sshkey", + "Default sorting for SSH Key resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) + + OptionSortVolume = newOpt( + "sort.volume", + "Default sorting for Volume resource", + []string{"id:asc"}, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + nil, + ) ) type Option[T any] struct { From 138b895e814160a940efece19a69b036766eb0c2 Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:56:45 +0200 Subject: [PATCH 2/6] rename options --- internal/state/config/options.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/internal/state/config/options.go b/internal/state/config/options.go index b1542a70..44338834 100644 --- a/internal/state/config/options.go +++ b/internal/state/config/options.go @@ -167,7 +167,7 @@ var ( ) OptionSortFloatingIP = newOpt( - "sort.floatingip", + "sort.floating-ip", "Default sorting for Floating IP resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, @@ -191,7 +191,7 @@ var ( ) OptionSortLoadBalancer = newOpt( - "sort.loadbalancer", + "sort.load-balancer", "Default sorting for Load Balancer resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, @@ -199,7 +199,7 @@ var ( ) OptionSortLoadBalancerType = newOpt( - "sort.loadbalancertype", + "sort.load-balancer-type", "Default sorting for Load Balancer Type resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, @@ -223,7 +223,7 @@ var ( ) OptionSortPlacementGroup = newOpt( - "sort.placementgroup", + "sort.placement-group", "Default sorting for Placement Group resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, @@ -231,7 +231,7 @@ var ( ) OptionSortPrimaryIP = newOpt( - "sort.primaryip", + "sort.primary-ip", "Default sorting for Primary IP resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, @@ -247,7 +247,7 @@ var ( ) OptionSortServerType = newOpt( - "sort.servertype", + "sort.server-type", "Default sorting for Server Type resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, @@ -255,7 +255,7 @@ var ( ) OptionSortSSHKey = newOpt( - "sort.sshkey", + "sort.ssh-key", "Default sorting for SSH Key resource", []string{"id:asc"}, (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, From dedc6549cb350c3c05c721b10f8584fe5d57d46e Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 3 Jul 2024 15:00:25 +0200 Subject: [PATCH 3/6] adjust help text --- internal/cmd/config/helptext/generate.go | 21 ++++- internal/cmd/config/helptext/preferences.txt | 98 +++++--------------- internal/state/config/options.go | 41 ++++---- 3 files changed, 67 insertions(+), 93 deletions(-) diff --git a/internal/cmd/config/helptext/generate.go b/internal/cmd/config/helptext/generate.go index 0f48c431..1bb759bf 100644 --- a/internal/cmd/config/helptext/generate.go +++ b/internal/cmd/config/helptext/generate.go @@ -16,11 +16,19 @@ import ( //go:generate go run $GOFILE func main() { - generateTable("preferences.txt", config.OptionFlagPreference, true) - generateTable("other.txt", config.OptionFlagPreference, false) + generateTable( + "preferences.txt", + config.OptionFlagPreference|config.OptionFlagHidden, + config.OptionFlagPreference, + table.Row{"sort.", "Default sorting for resource", "string list", "sort.", "HCLOUD_SORT_", ""}, + ) + generateTable("other.txt", + config.OptionFlagPreference|config.OptionFlagHidden, + 0, + ) } -func generateTable(outFile string, filterFlag config.OptionFlag, hasFlag bool) { +func generateTable(outFile string, mask, filter config.OptionFlag, extraRows ...table.Row) { f, err := os.OpenFile(outFile, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { panic(err) @@ -46,7 +54,7 @@ func generateTable(outFile string, filterFlag config.OptionFlag, hasFlag bool) { var opts []config.IOption for _, opt := range config.Options { - if opt.HasFlags(filterFlag) != hasFlag { + if opt.GetFlags()&mask != filter { continue } opts = append(opts, opt) @@ -61,6 +69,11 @@ func generateTable(outFile string, filterFlag config.OptionFlag, hasFlag bool) { t.AppendSeparator() } + for _, row := range extraRows { + t.AppendRow(row) + t.AppendSeparator() + } + t.Render() } diff --git a/internal/cmd/config/helptext/preferences.txt b/internal/cmd/config/helptext/preferences.txt index f82b07dd..7049798a 100644 --- a/internal/cmd/config/helptext/preferences.txt +++ b/internal/cmd/config/helptext/preferences.txt @@ -1,73 +1,25 @@ -┌───────────────────────┬──────────────────────┬─────────────┬───────────────────────┬──────────────────────────────┬─────────────────┐ -│ OPTION │ DESCRIPTION │ TYPE │ CONFIG KEY │ ENVIRONMENT VARIABLE │ FLAG │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ debug │ Enable debug output │ boolean │ debug │ HCLOUD_DEBUG │ --debug │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ debug-file │ File to write debug │ string │ debug_file │ HCLOUD_DEBUG_FILE │ --debug-file │ -│ │ output to │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ default-ssh-keys │ Default SSH keys for │ string list │ default_ssh_keys │ HCLOUD_DEFAULT_SSH_KEYS │ │ -│ │ new servers │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ endpoint │ Hetzner Cloud API │ string │ endpoint │ HCLOUD_ENDPOINT │ --endpoint │ -│ │ endpoint │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ poll-interval │ Interval at which to │ duration │ poll_interval │ HCLOUD_POLL_INTERVAL │ --poll-interval │ -│ │ poll information, │ │ │ │ │ -│ │ for example action │ │ │ │ │ -│ │ progress │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ quiet │ If true, only print │ boolean │ quiet │ HCLOUD_QUIET │ --quiet │ -│ │ error messages │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.certificate │ Default sorting for │ string list │ sort.certificate │ HCLOUD_SORT.CERTIFICATE │ │ -│ │ Certificate resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.datacenter │ Default sorting for │ string list │ sort.datacenter │ HCLOUD_SORT.DATACENTER │ │ -│ │ Datacenter resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.firewall │ Default sorting for │ string list │ sort.firewall │ HCLOUD_SORT.FIREWALL │ │ -│ │ Firewall resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.floatingip │ Default sorting for │ string list │ sort.floatingip │ HCLOUD_SORT.FLOATINGIP │ │ -│ │ Floating IP resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.image │ Default sorting for │ string list │ sort.image │ HCLOUD_SORT.IMAGE │ │ -│ │ Image resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.iso │ Default sorting for │ string list │ sort.iso │ HCLOUD_SORT.ISO │ │ -│ │ ISO resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.loadbalancer │ Default sorting for │ string list │ sort.loadbalancer │ HCLOUD_SORT.LOADBALANCER │ │ -│ │ Load Balancer │ │ │ │ │ -│ │ resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.loadbalancertype │ Default sorting for │ string list │ sort.loadbalancertype │ HCLOUD_SORT.LOADBALANCERTYPE │ │ -│ │ Load Balancer Type │ │ │ │ │ -│ │ resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.location │ Default sorting for │ string list │ sort.location │ HCLOUD_SORT.LOCATION │ │ -│ │ Location resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.network │ Default sorting for │ string list │ sort.network │ HCLOUD_SORT.NETWORK │ │ -│ │ Network resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.placementgroup │ Default sorting for │ string list │ sort.placementgroup │ HCLOUD_SORT.PLACEMENTGROUP │ │ -│ │ Placement Group │ │ │ │ │ -│ │ resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.primaryip │ Default sorting for │ string list │ sort.primaryip │ HCLOUD_SORT.PRIMARYIP │ │ -│ │ Primary IP resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.server │ Default sorting for │ string list │ sort.server │ HCLOUD_SORT.SERVER │ │ -│ │ Server resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.servertype │ Default sorting for │ string list │ sort.servertype │ HCLOUD_SORT.SERVERTYPE │ │ -│ │ Server Type resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.sshkey │ Default sorting for │ string list │ sort.sshkey │ HCLOUD_SORT.SSHKEY │ │ -│ │ SSH Key resource │ │ │ │ │ -├───────────────────────┼──────────────────────┼─────────────┼───────────────────────┼──────────────────────────────┼─────────────────┤ -│ sort.volume │ Default sorting for │ string list │ sort.volume │ HCLOUD_SORT.VOLUME │ │ -│ │ Volume resource │ │ │ │ │ -└───────────────────────┴──────────────────────┴─────────────┴───────────────────────┴──────────────────────────────┴─────────────────┘ +┌──────────────────┬──────────────────────┬─────────────┬──────────────────┬─────────────────────────┬─────────────────┐ +│ OPTION │ DESCRIPTION │ TYPE │ CONFIG KEY │ ENVIRONMENT VARIABLE │ FLAG │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ debug │ Enable debug output │ boolean │ debug │ HCLOUD_DEBUG │ --debug │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ debug-file │ File to write debug │ string │ debug_file │ HCLOUD_DEBUG_FILE │ --debug-file │ +│ │ output to │ │ │ │ │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ default-ssh-keys │ Default SSH keys for │ string list │ default_ssh_keys │ HCLOUD_DEFAULT_SSH_KEYS │ │ +│ │ new servers │ │ │ │ │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ endpoint │ Hetzner Cloud API │ string │ endpoint │ HCLOUD_ENDPOINT │ --endpoint │ +│ │ endpoint │ │ │ │ │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ poll-interval │ Interval at which to │ duration │ poll_interval │ HCLOUD_POLL_INTERVAL │ --poll-interval │ +│ │ poll information, │ │ │ │ │ +│ │ for example action │ │ │ │ │ +│ │ progress │ │ │ │ │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ quiet │ If true, only print │ boolean │ quiet │ HCLOUD_QUIET │ --quiet │ +│ │ error messages │ │ │ │ │ +├──────────────────┼──────────────────────┼─────────────┼──────────────────┼─────────────────────────┼─────────────────┤ +│ sort. │ Default sorting for │ string list │ sort. │ HCLOUD_SORT_ │ │ +│ │ resource │ │ │ │ │ +└──────────────────┴──────────────────────┴─────────────┴──────────────────┴─────────────────────────┴─────────────────┘ diff --git a/internal/state/config/options.go b/internal/state/config/options.go index 44338834..9e27092d 100644 --- a/internal/state/config/options.go +++ b/internal/state/config/options.go @@ -27,6 +27,8 @@ const ( OptionFlagSensitive // OptionFlagSlice indicates that the option value is a slice OptionFlagSlice + // OptionFlagHidden indicates that the option should not be shown in the help output + OptionFlagHidden DefaultPreferenceFlags = OptionFlagPreference | OptionFlagConfig | OptionFlagPFlag | OptionFlagEnv ) @@ -46,6 +48,8 @@ type IOption interface { FlagName() string // HasFlags returns true if the option has all the provided flags set HasFlags(src OptionFlag) bool + // GetFlags returns all flags set for the option + GetFlags() OptionFlag // GetAsAny reads the option value from the config and returns it as an any GetAsAny(c Config) (any, error) // OverrideAny sets the option value in the config to the provided any value @@ -146,7 +150,7 @@ var ( "sort.certificate", "Default sorting for Certificate resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -154,7 +158,7 @@ var ( "sort.datacenter", "Default sorting for Datacenter resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -162,7 +166,7 @@ var ( "sort.firewall", "Default sorting for Firewall resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -170,7 +174,7 @@ var ( "sort.floating-ip", "Default sorting for Floating IP resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -178,7 +182,7 @@ var ( "sort.image", "Default sorting for Image resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -186,7 +190,7 @@ var ( "sort.iso", "Default sorting for ISO resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -194,7 +198,7 @@ var ( "sort.load-balancer", "Default sorting for Load Balancer resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -202,7 +206,7 @@ var ( "sort.load-balancer-type", "Default sorting for Load Balancer Type resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -210,7 +214,7 @@ var ( "sort.location", "Default sorting for Location resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -218,7 +222,7 @@ var ( "sort.network", "Default sorting for Network resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -226,7 +230,7 @@ var ( "sort.placement-group", "Default sorting for Placement Group resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -234,7 +238,7 @@ var ( "sort.primary-ip", "Default sorting for Primary IP resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -242,7 +246,7 @@ var ( "sort.server", "Default sorting for Server resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -250,7 +254,7 @@ var ( "sort.server-type", "Default sorting for Server Type resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -258,7 +262,7 @@ var ( "sort.ssh-key", "Default sorting for SSH Key resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) @@ -266,7 +270,7 @@ var ( "sort.volume", "Default sorting for Volume resource", []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice, + (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, nil, ) ) @@ -338,6 +342,11 @@ func (o *Option[T]) HasFlags(src OptionFlag) bool { return (^o.Flags)&src == 0 } +func (o *Option[T]) GetFlags() OptionFlag { + return o.Flags + +} + func (o *Option[T]) GetName() string { return o.Name } From 23ce28c8bec3741e08ac8928593adf9109f692a0 Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 10 Jul 2024 13:41:01 +0200 Subject: [PATCH 4/6] fix after rebase --- internal/cmd/base/list.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/cmd/base/list.go b/internal/cmd/base/list.go index 3efcef27..71df13ef 100644 --- a/internal/cmd/base/list.go +++ b/internal/cmd/base/list.go @@ -66,7 +66,11 @@ func (lc *ListCmd) Run(s state.State, cmd *cobra.Command) error { sorts, _ := cmd.Flags().GetStringSlice("sort") if !cmd.Flags().Changed("sort") { - sorts = lc.SortOption.Get(s.Config()) + var err error + sorts, err = lc.SortOption.Get(s.Config()) + if err != nil { + return err + } } resources, err := lc.Fetch(s, cmd.Flags(), listOpts, sorts) From 5edb18501dec7c188d029f24b2a9b98561893aac Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:38:35 +0200 Subject: [PATCH 5/6] remove options for unsupported resources --- internal/cmd/base/list.go | 2 +- internal/cmd/iso/list.go | 3 +- internal/cmd/iso/list_test.go | 2 +- internal/cmd/loadbalancertype/list.go | 3 +- internal/cmd/loadbalancertype/list_test.go | 2 +- internal/cmd/network/list.go | 3 +- internal/cmd/network/list_test.go | 2 +- internal/cmd/servertype/list.go | 3 +- internal/cmd/servertype/list_test.go | 4 +-- internal/state/config/options.go | 32 ---------------------- 10 files changed, 10 insertions(+), 46 deletions(-) diff --git a/internal/cmd/base/list.go b/internal/cmd/base/list.go index 71df13ef..0559dc71 100644 --- a/internal/cmd/base/list.go +++ b/internal/cmd/base/list.go @@ -65,7 +65,7 @@ func (lc *ListCmd) Run(s state.State, cmd *cobra.Command) error { } sorts, _ := cmd.Flags().GetStringSlice("sort") - if !cmd.Flags().Changed("sort") { + if lc.SortOption != nil && !cmd.Flags().Changed("sort") { var err error sorts, err = lc.SortOption.Get(s.Config()) if err != nil { diff --git a/internal/cmd/iso/list.go b/internal/cmd/iso/list.go index 4ab42208..b3ad4a90 100644 --- a/internal/cmd/iso/list.go +++ b/internal/cmd/iso/list.go @@ -13,7 +13,6 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" - "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -22,7 +21,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "ISOs", JSONKeyGetByName: "isos", DefaultColumns: []string{"id", "name", "description", "type", "architecture"}, - SortOption: config.OptionSortISO, + SortOption: nil, // ISOs does not support sorting AdditionalFlags: func(cmd *cobra.Command) { cmd.Flags().StringSlice("architecture", []string{}, "Only show images of given architecture: x86|arm") diff --git a/internal/cmd/iso/list_test.go b/internal/cmd/iso/list_test.go index 31e87a12..a7295ae8 100644 --- a/internal/cmd/iso/list_test.go +++ b/internal/cmd/iso/list_test.go @@ -26,7 +26,7 @@ func TestList(t *testing.T) { gomock.Any(), hcloud.ISOListOpts{ ListOpts: hcloud.ListOpts{PerPage: 50}, - Sort: []string{"id:asc"}, + Sort: nil, // ISOs do not support sorting }, ). Return([]*hcloud.ISO{ diff --git a/internal/cmd/loadbalancertype/list.go b/internal/cmd/loadbalancertype/list.go index 6c73d7c1..01a9acdc 100644 --- a/internal/cmd/loadbalancertype/list.go +++ b/internal/cmd/loadbalancertype/list.go @@ -7,7 +7,6 @@ import ( "github.com/hetznercloud/cli/internal/cmd/output" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" - "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -16,7 +15,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Load Balancer Types", JSONKeyGetByName: "load_balancer_types", DefaultColumns: []string{"id", "name", "description", "max_services", "max_connections", "max_targets"}, - SortOption: config.OptionSortLoadBalancerType, + SortOption: nil, // Load Balancer Types do not support sorting Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.LoadBalancerTypeListOpts{ListOpts: listOpts} diff --git a/internal/cmd/loadbalancertype/list_test.go b/internal/cmd/loadbalancertype/list_test.go index c3ed2f41..f384dee3 100644 --- a/internal/cmd/loadbalancertype/list_test.go +++ b/internal/cmd/loadbalancertype/list_test.go @@ -26,7 +26,7 @@ func TestList(t *testing.T) { gomock.Any(), hcloud.LoadBalancerTypeListOpts{ ListOpts: hcloud.ListOpts{PerPage: 50}, - Sort: []string{"id:asc"}, + Sort: nil, // Load Balancer Types do not support sorting }, ). Return([]*hcloud.LoadBalancerType{ diff --git a/internal/cmd/network/list.go b/internal/cmd/network/list.go index 26d5ef55..aaaebc98 100644 --- a/internal/cmd/network/list.go +++ b/internal/cmd/network/list.go @@ -12,7 +12,6 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" - "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -21,7 +20,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Networks", JSONKeyGetByName: "networks", DefaultColumns: []string{"id", "name", "ip_range", "servers", "age"}, - SortOption: config.OptionSortNetwork, + SortOption: nil, // Networks do not support sorting Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.NetworkListOpts{ListOpts: listOpts} diff --git a/internal/cmd/network/list_test.go b/internal/cmd/network/list_test.go index 79518e3b..ee2518a4 100644 --- a/internal/cmd/network/list_test.go +++ b/internal/cmd/network/list_test.go @@ -28,7 +28,7 @@ func TestList(t *testing.T) { PerPage: 50, LabelSelector: "foo=bar", }, - Sort: []string{"id:asc"}, + Sort: nil, // Networks do not support sorting }, ). Return([]*hcloud.Network{ diff --git a/internal/cmd/servertype/list.go b/internal/cmd/servertype/list.go index 68cd0424..5294914f 100644 --- a/internal/cmd/servertype/list.go +++ b/internal/cmd/servertype/list.go @@ -10,7 +10,6 @@ import ( "github.com/hetznercloud/cli/internal/cmd/util" "github.com/hetznercloud/cli/internal/hcapi2" "github.com/hetznercloud/cli/internal/state" - "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/hcloud-go/v2/hcloud" "github.com/hetznercloud/hcloud-go/v2/hcloud/schema" ) @@ -19,7 +18,7 @@ var ListCmd = base.ListCmd{ ResourceNamePlural: "Server Types", JSONKeyGetByName: "server_types", DefaultColumns: []string{"id", "name", "cores", "cpu_type", "architecture", "memory", "disk", "storage_type", "traffic"}, - SortOption: config.OptionSortServerType, + SortOption: nil, // Server Types do not support sorting Fetch: func(s state.State, _ *pflag.FlagSet, listOpts hcloud.ListOpts, sorts []string) ([]interface{}, error) { opts := hcloud.ServerTypeListOpts{ListOpts: listOpts} diff --git a/internal/cmd/servertype/list_test.go b/internal/cmd/servertype/list_test.go index 4b8668b0..8b107774 100644 --- a/internal/cmd/servertype/list_test.go +++ b/internal/cmd/servertype/list_test.go @@ -27,7 +27,7 @@ func TestList(t *testing.T) { gomock.Any(), hcloud.ServerTypeListOpts{ ListOpts: hcloud.ListOpts{PerPage: 50}, - Sort: []string{"id:asc"}, + Sort: nil, // Server Types do not support sorting }, ). Return([]*hcloud.ServerType{ @@ -69,7 +69,7 @@ func TestListColumnDeprecated(t *testing.T) { gomock.Any(), hcloud.ServerTypeListOpts{ ListOpts: hcloud.ListOpts{PerPage: 50}, - Sort: []string{"id:asc"}, + Sort: nil, // Server Types do not support sorting }, ). Return([]*hcloud.ServerType{ diff --git a/internal/state/config/options.go b/internal/state/config/options.go index 9e27092d..2e593c8e 100644 --- a/internal/state/config/options.go +++ b/internal/state/config/options.go @@ -186,14 +186,6 @@ var ( nil, ) - OptionSortISO = newOpt( - "sort.iso", - "Default sorting for ISO resource", - []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, - nil, - ) - OptionSortLoadBalancer = newOpt( "sort.load-balancer", "Default sorting for Load Balancer resource", @@ -202,14 +194,6 @@ var ( nil, ) - OptionSortLoadBalancerType = newOpt( - "sort.load-balancer-type", - "Default sorting for Load Balancer Type resource", - []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, - nil, - ) - OptionSortLocation = newOpt( "sort.location", "Default sorting for Location resource", @@ -218,14 +202,6 @@ var ( nil, ) - OptionSortNetwork = newOpt( - "sort.network", - "Default sorting for Network resource", - []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, - nil, - ) - OptionSortPlacementGroup = newOpt( "sort.placement-group", "Default sorting for Placement Group resource", @@ -250,14 +226,6 @@ var ( nil, ) - OptionSortServerType = newOpt( - "sort.server-type", - "Default sorting for Server Type resource", - []string{"id:asc"}, - (DefaultPreferenceFlags&^OptionFlagPFlag)|OptionFlagSlice|OptionFlagHidden, - nil, - ) - OptionSortSSHKey = newOpt( "sort.ssh-key", "Default sorting for SSH Key resource", From c5f5823b040e6f272d3b70a3aab5b8e8e69a3236 Mon Sep 17 00:00:00 2001 From: phm07 <22707808+phm07@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:46:10 +0200 Subject: [PATCH 6/6] add warning message --- internal/cmd/base/list.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/cmd/base/list.go b/internal/cmd/base/list.go index 0559dc71..bfbdc032 100644 --- a/internal/cmd/base/list.go +++ b/internal/cmd/base/list.go @@ -2,6 +2,7 @@ package base import ( "fmt" + "os" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -64,8 +65,14 @@ func (lc *ListCmd) Run(s state.State, cmd *cobra.Command) error { PerPage: 50, } - sorts, _ := cmd.Flags().GetStringSlice("sort") - if lc.SortOption != nil && !cmd.Flags().Changed("sort") { + var sorts []string + if cmd.Flags().Changed("sort") { + if lc.SortOption == nil { + _, _ = fmt.Fprintln(os.Stderr, "Warning: resource does not support sorting. Ignoring --sort flag.") + } else { + sorts, _ = cmd.Flags().GetStringSlice("sort") + } + } else if lc.SortOption != nil { var err error sorts, err = lc.SortOption.Get(s.Config()) if err != nil {