Skip to content

Commit 4e2772b

Browse files
authored
feat(cli): support negative filters (#339)
Output filtering (`-t`) now supports excluding objects, by prepending an exlamation mark (`!`) before the regular expression
1 parent a6d5fde commit 4e2772b

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

docs/docs/targets.md

+11
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,14 @@ apiVersion: apps/v1
7878
kind: Deployment
7979
# ...
8080
```
81+
82+
## Excluding
83+
84+
Sometimes it may be desirably to exclude a single object, instead of including all others.
85+
86+
To do so, prepend the regular expression with an exclamation mark (`!`), like so:
87+
88+
```bash
89+
# filter out all Deployments
90+
$ tk show . -t '!deployment/.*'
91+
```

pkg/process/filter.go

+45-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,16 @@ import (
99
)
1010

1111
// Filter returns all elements of the list that match at least one expression
12+
// and are not ignored
1213
func Filter(list manifest.List, exprs Matchers) manifest.List {
1314
out := make(manifest.List, 0, len(list))
1415
for _, m := range list {
1516
if !exprs.MatchString(m.KindName()) {
1617
continue
1718
}
19+
if exprs.IgnoreString(m.KindName()) {
20+
continue
21+
}
1822
out = append(out, m)
1923
}
2024
return out
@@ -26,7 +30,13 @@ type Matcher interface {
2630
MatchString(string) bool
2731
}
2832

33+
// Ignorer is like matcher, but for explicitely ignoring resources
34+
type Ignorer interface {
35+
IgnoreString(string) bool
36+
}
37+
2938
// Matchers is a collection of multiple expressions.
39+
// A matcher may also implement Ignorer to explicitely ignore fields
3040
type Matchers []Matcher
3141

3242
// MatchString returns whether at least one expression (OR) matches the string
@@ -38,6 +48,18 @@ func (e Matchers) MatchString(s string) bool {
3848
return b
3949
}
4050

51+
func (e Matchers) IgnoreString(s string) bool {
52+
b := false
53+
for _, exp := range e {
54+
i, ok := exp.(Ignorer)
55+
if !ok {
56+
continue
57+
}
58+
b = b || i.IgnoreString(s)
59+
}
60+
return b
61+
}
62+
4163
// RegExps is a helper to construct Matchers from regular expressions
4264
func RegExps(rs []*regexp.Regexp) Matchers {
4365
xprs := make(Matchers, 0, len(rs))
@@ -50,11 +72,20 @@ func RegExps(rs []*regexp.Regexp) Matchers {
5072
func StrExps(strs ...string) (Matchers, error) {
5173
exps := make(Matchers, 0, len(strs))
5274
for _, raw := range strs {
53-
s := fmt.Sprintf(`(?i)^%s$`, raw)
75+
// trim exlamation mark, not supported by regex
76+
s := fmt.Sprintf(`(?i)^%s$`, strings.TrimPrefix(raw, "!"))
77+
78+
// create regexp matcher
79+
var exp Matcher
5480
exp, err := regexp.Compile(s)
5581
if err != nil {
5682
return nil, ErrBadExpr{err}
5783
}
84+
85+
// if negative (!), invert regex behaviour
86+
if strings.HasPrefix(raw, "!") {
87+
exp = NegMatcher{exp: exp}
88+
}
5889
exps = append(exps, exp)
5990
}
6091
return exps, nil
@@ -76,3 +107,16 @@ type ErrBadExpr struct {
76107
func (e ErrBadExpr) Error() string {
77108
return fmt.Sprintf("%s.\nSee https://tanka.dev/output-filtering/#regular-expressions for details on regular expressions.", strings.Title(e.inner.Error()))
78109
}
110+
111+
// NexMatcher is a matcher that inverts the original behaviour
112+
type NegMatcher struct {
113+
exp Matcher
114+
}
115+
116+
func (n NegMatcher) MatchString(s string) bool {
117+
return true
118+
}
119+
120+
func (n NegMatcher) IgnoreString(s string) bool {
121+
return n.exp.MatchString(s)
122+
}

pkg/process/process_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ func TestProcess(t *testing.T) {
6464
`DePlOyMeNt/GrAfAnA`,
6565
),
6666
},
67+
{
68+
name: "targets-negative",
69+
deep: testDataDeep().Deep,
70+
flat: manifest.List{
71+
testDataDeep().Flat[".app.web.frontend.nodejs.express.service"],
72+
testDataDeep().Flat[".app.namespace"],
73+
},
74+
targets: MustStrExps(`!deployment/.*`),
75+
},
6776
{
6877
name: "unwrap-list",
6978
deep: loadFixture("list").Deep,

0 commit comments

Comments
 (0)