diff --git a/cmd/catp/catp/app.go b/cmd/catp/catp/app.go index 615bf83..5ddcae7 100644 --- a/cmd/catp/catp/app.go +++ b/cmd/catp/catp/app.go @@ -29,7 +29,7 @@ func Main(options ...func(o *Options)) error { //nolint:funlen,cyclop,gocognit,g r := &runner{} flag.Var(flagFunc(func(v string) error { - r.filters = append(r.filters, filter{pass: true, ms: v, and: bytes.Split([]byte(v), []byte("^"))}) + r.filters = append(r.filters, filter{pass: true, and: bytes.Split([]byte(v), []byte("^"))}) return nil }), "pass", "filter matching, may contain multiple AND patterns separated by ^,\n"+ @@ -37,6 +37,11 @@ func Main(options ...func(o *Options)) error { //nolint:funlen,cyclop,gocognit,g "other -pass values are evaluated if preceding pass/skip did not match,\n"+ "for example, you can use \"-pass bar^baz -pass foo -skip fo\" to only keep lines that have (bar AND baz) OR foo, but not fox") + flag.Var(flagFunc(func(v string) error { + return r.loadCSVFilter(v, true) + }), "pass-csv", "filter matching, loads pass params from CSV file,\n"+ + "each line is treated as -pass, each column value is AND condition.") + flag.BoolFunc("pass-any", "finishes matching and gets the value even if previous -pass did not match,\n"+ "if previous -skip matched, the line would be skipped any way.", func(s string) error { r.filters = append(r.filters, filter{pass: true}) @@ -45,7 +50,12 @@ func Main(options ...func(o *Options)) error { //nolint:funlen,cyclop,gocognit,g }) flag.Var(flagFunc(func(v string) error { - r.filters = append(r.filters, filter{pass: false, ms: v, and: bytes.Split([]byte(v), []byte("^"))}) + return r.loadCSVFilter(v, false) + }), "skip-csv", "filter matching, loads skip params from CSV file,\n"+ + "each line is treated as -skip, each column value is AND condition.") + + flag.Var(flagFunc(func(v string) error { + r.filters = append(r.filters, filter{pass: false, and: bytes.Split([]byte(v), []byte("^"))}) return nil }), "skip", "filter matching, may contain multiple AND patterns separated by ^,\n"+ diff --git a/cmd/catp/catp/catp.go b/cmd/catp/catp/catp.go index 87c11a7..5ac34cf 100644 --- a/cmd/catp/catp/catp.go +++ b/cmd/catp/catp/catp.go @@ -4,6 +4,7 @@ import ( "bufio" "bytes" "context" + "encoding/csv" "encoding/json" "fmt" "io" @@ -69,7 +70,6 @@ type ( filter struct { pass bool // Skip is false. and [][]byte - ms string } flagFunc func(v string) error ) @@ -504,3 +504,28 @@ type Options struct { // You can use buf to avoid allocations for a result, and change its capacity if needed. PrepareLine func(filename string, lineNr int, line []byte, buf *[]byte) []byte } + +func (r *runner) loadCSVFilter(fn string, pass bool) error { + f, err := os.Open(fn) //nolint:gosec + if err != nil { + return fmt.Errorf("failed to open CSV file %s: %w", fn, err) + } + + cr := csv.NewReader(f) + + rows, err := cr.ReadAll() + if err != nil { + return fmt.Errorf("failed to read CSV file %s: %w", fn, err) + } + + for _, row := range rows { + var and [][]byte + for _, v := range row { + and = append(and, []byte(v)) + } + + r.filters = append(r.filters, filter{pass: pass, and: and}) + } + + return nil +}