-
Notifications
You must be signed in to change notification settings - Fork 710
add filter option to list command #4187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -6,6 +6,7 @@ package main | |||||||
import ( | ||||||||
"bufio" | ||||||||
"bytes" | ||||||||
"encoding/json" | ||||||||
"errors" | ||||||||
"fmt" | ||||||||
"reflect" | ||||||||
|
@@ -57,6 +58,14 @@ The output can be presented in one of several formats, using the --format <forma | |||||||
--format yaml - Output in YAML format | ||||||||
--format table - Output in table format | ||||||||
--format '{{ <go template> }}' - If the format begins and ends with '{{ }}', then it is used as a go template. | ||||||||
|
||||||||
Filtering instances: | ||||||||
--filter EXPR - Filter instances using yq expression (this is equivalent to --yq 'select(EXPR)') | ||||||||
Can be specified multiple times and it works with all output formats. | ||||||||
Examples: | ||||||||
--filter '.status == "Running"' | ||||||||
--filter '.vmType == "vz"' | ||||||||
--filter '.status == "Running"' --filter '.vmType == "vz"' | ||||||||
` + store.FormatHelp + ` | ||||||||
The following legacy flags continue to function: | ||||||||
--json - equal to '--format json'`, | ||||||||
|
@@ -72,6 +81,7 @@ The following legacy flags continue to function: | |||||||
listCommand.Flags().BoolP("quiet", "q", false, "Only show names") | ||||||||
listCommand.Flags().Bool("all-fields", false, "Show all fields") | ||||||||
listCommand.Flags().StringArray("yq", nil, "Apply yq expression to each instance") | ||||||||
listCommand.Flags().StringArrayP("filter", "l", nil, "Filter instances using yq expression (equivalent to --yq 'select(EXPR)')") | ||||||||
|
||||||||
return listCommand | ||||||||
} | ||||||||
|
@@ -121,6 +131,10 @@ func listAction(cmd *cobra.Command, args []string) error { | |||||||
if err != nil { | ||||||||
return err | ||||||||
} | ||||||||
filter, err := cmd.Flags().GetStringArray("filter") | ||||||||
if err != nil { | ||||||||
return err | ||||||||
} | ||||||||
|
||||||||
if jsonFormat { | ||||||||
format = "json" | ||||||||
|
@@ -141,6 +155,14 @@ func listAction(cmd *cobra.Command, args []string) error { | |||||||
return errors.New("option --list-fields conflicts with option --yq") | ||||||||
} | ||||||||
} | ||||||||
if len(filter) != 0 { | ||||||||
if listFields { | ||||||||
return errors.New("option --list-fields conflicts with option --filter") | ||||||||
} | ||||||||
if len(yq) != 0 { | ||||||||
return errors.New("option --filter conflicts with option --yq") | ||||||||
} | ||||||||
Comment on lines
+162
to
+164
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should be able to combine So you could just drop the check here because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't too clear to me but is there anything wrong with the way it currently is? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes: ❯ l ls -l '.status == "Running"'
NAME STATUS SSH VMTYPE ARCH CPUS MEMORY DISK DIR
alpine-iso Running 127.0.0.1:50496 vz aarch64 4 4GiB 100GiB ~/.lima/alpine-iso
❯ l ls -l '.status == "Running"' --yq .name
FATA[0000] option --filter conflicts with option --yq
❯ l ls --yq 'select(.status == "Running")' --yq .name
alpine-iso I expect the last 2 commands to work exactly the same. There is no reason for the |
||||||||
} | ||||||||
|
||||||||
if quiet && format != "table" { | ||||||||
return errors.New("option --quiet can only be used with '--format table'") | ||||||||
|
@@ -220,15 +242,31 @@ func listAction(cmd *cobra.Command, args []string) error { | |||||||
options.TerminalWidth = w | ||||||||
} | ||||||||
} | ||||||||
// --yq implies --format json unless --format yaml has been explicitly specified | ||||||||
|
||||||||
// --yq implies --format json unless --format has been explicitly specified | ||||||||
if len(yq) != 0 && !cmd.Flags().Changed("format") { | ||||||||
format = "json" | ||||||||
} | ||||||||
|
||||||||
// Always pipe JSON and YAML through yq to colorize it if isTTY | ||||||||
if len(yq) == 0 && (format == "json" || format == "yaml") { | ||||||||
yq = append(yq, ".") | ||||||||
} | ||||||||
|
||||||||
for _, f := range filter { | ||||||||
yq = append(yq, "select("+f+")") | ||||||||
} | ||||||||
|
||||||||
// handle --filter with table and go-template formats | ||||||||
isGoTemplate := strings.HasPrefix(format, "{{") && strings.HasSuffix(format, "}}") | ||||||||
if len(filter) != 0 && (format == "table" || isGoTemplate) { | ||||||||
Comment on lines
+261
to
+262
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Despite what the ❯ l ls -f 'Name is: {{.Name}}'
Name is: alpine-iso
Name is: alpine-lima-3.22.2
Name is: foo |
||||||||
instances, err = filterInstances(instances, yq) | ||||||||
if err != nil { | ||||||||
return err | ||||||||
} | ||||||||
yq = nil | ||||||||
} | ||||||||
|
||||||||
if len(yq) == 0 { | ||||||||
err = store.PrintInstances(cmd.OutOrStdout(), instances, format, &options) | ||||||||
if err == nil && unmatchedInstances { | ||||||||
|
@@ -320,3 +358,31 @@ func listAction(cmd *cobra.Command, args []string) error { | |||||||
func listBashComplete(cmd *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { | ||||||||
return bashCompleteInstanceNames(cmd) | ||||||||
} | ||||||||
|
||||||||
// filterInstances applies yq expressions to instances and returns the filtered results. | ||||||||
func filterInstances(instances []*limatype.Instance, yqExprs []string) ([]*limatype.Instance, error) { | ||||||||
if len(yqExprs) == 0 { | ||||||||
return instances, nil | ||||||||
} | ||||||||
|
||||||||
yqExpr := strings.Join(yqExprs, " | ") | ||||||||
|
||||||||
var filteredInstances []*limatype.Instance | ||||||||
for _, instance := range instances { | ||||||||
jsonBytes, err := json.Marshal(instance) | ||||||||
if err != nil { | ||||||||
return nil, fmt.Errorf("failed to marshal instance %s: %w", instance.Name, err) | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Always use Also applies to the next error message. |
||||||||
} | ||||||||
|
||||||||
result, err := yqutil.EvaluateExpression(yqExpr, jsonBytes) | ||||||||
if err != nil { | ||||||||
return nil, fmt.Errorf("failed to apply filter %s: %w", yqExpr, err) | ||||||||
} | ||||||||
|
||||||||
if len(result) > 0 { | ||||||||
filteredInstances = append(filteredInstances, instance) | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
return filteredInstances, nil | ||||||||
} |
Uh oh!
There was an error while loading. Please reload this page.