expression exclude fixed

This commit is contained in:
Pavel Vorobyov
2020-06-01 11:22:46 +03:00
parent f6ee512c95
commit 04e4442ac2
4 changed files with 95 additions and 31 deletions

View File

@@ -4,8 +4,6 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"strings" "strings"
"github.com/viert/xc/stringslice"
) )
type tokenType int type tokenType int
@@ -49,19 +47,6 @@ func newToken() *token {
return ct return ct
} }
func maybeAddHost(hostlist *[]string, host string, exclude bool) {
newHl := *hostlist
if exclude {
hIdx := stringslice.Index(newHl, host)
if hIdx >= 0 {
newHl = append(newHl[:hIdx], newHl[hIdx+1:]...)
}
} else {
newHl = append(newHl, host)
}
*hostlist = newHl
}
func parseExpression(expr []rune) ([]*token, error) { func parseExpression(expr []rune) ([]*token, error) {
ct := newToken() ct := newToken()
res := make([]*token, 0) res := make([]*token, 0)

View File

@@ -22,6 +22,12 @@ type Store struct {
naturalSort bool naturalSort bool
} }
// expandedToken represents one token expanded into a hostlist
type expandedToken struct {
exclude bool
hosts []string
}
func (s *Store) reinitStore() { func (s *Store) reinitStore() {
s.datacenters = new(dcstore) s.datacenters = new(dcstore)
s.datacenters._id = make(map[string]*Datacenter) s.datacenters._id = make(map[string]*Datacenter)
@@ -163,14 +169,19 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
return nil, err return nil, err
} }
hostlist := make([][]string, 0) expanded := make([]expandedToken, 0)
for _, token := range tokens { for _, token := range tokens {
singleTokenHosts := make([]string, 0)
etoken := expandedToken{
exclude: token.Exclude,
hosts: make([]string, 0),
}
switch token.Type { switch token.Type {
case tTypeHostRegexp: case tTypeHostRegexp:
for _, host := range s.matchHost(token.RegexpFilter) { for _, host := range s.matchHost(token.RegexpFilter) {
maybeAddHost(&singleTokenHosts, host, token.Exclude) etoken.hosts = append(etoken.hosts, host)
} }
case tTypeHost: case tTypeHost:
@@ -191,7 +202,7 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
} }
} }
} }
maybeAddHost(&singleTokenHosts, host, token.Exclude) etoken.hosts = append(etoken.hosts, host)
} }
case tTypeGroup: case tTypeGroup:
@@ -221,7 +232,7 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
continue continue
} }
} }
maybeAddHost(&singleTokenHosts, host.FQDN, token.Exclude) etoken.hosts = append(etoken.hosts, host.FQDN)
} }
} }
@@ -271,27 +282,31 @@ func (s *Store) HostList(expr []rune) ([]string, error) {
} }
} }
maybeAddHost(&singleTokenHosts, host.FQDN, token.Exclude) etoken.hosts = append(etoken.hosts, host.FQDN)
} }
} }
} }
if len(singleTokenHosts) > 0 { if len(etoken.hosts) > 0 {
hostlist = append(hostlist, singleTokenHosts) expanded = append(expanded, etoken)
} }
} }
results := make([]string, 0) results := make([]string, 0)
for _, sthosts := range hostlist { for _, etoken := range expanded {
// sorting within one expression token only // sorting within one expression token only
// the order of tokens themselves should be respected // the order of tokens themselves should be respected
if s.naturalSort { if s.naturalSort {
natsort.Sort(sthosts) natsort.Sort(etoken.hosts)
} else { } else {
sort.Strings(sthosts) sort.Strings(etoken.hosts)
} }
for _, host := range sthosts { if etoken.exclude {
results = append(results, host) for _, exhost := range etoken.hosts {
stringslice.Remove(&results, exhost)
}
} else {
results = append(results, etoken.hosts...)
} }
} }
return results, nil return results, nil

View File

@@ -60,7 +60,15 @@ func (fb *FakeBackend) Load() error {
Tags: []string{"special"}, Tags: []string{"special"},
} }
fb.groups = append(fb.groups, group1, group2, group3) group4 := &Group{
ID: "g4",
Name: "group4",
WorkGroupID: "wg1",
ParentID: "",
Tags: []string{},
}
fb.groups = append(fb.groups, group1, group2, group3, group4)
dc1 := &Datacenter{ dc1 := &Datacenter{
ID: "dc1", ID: "dc1",
@@ -93,7 +101,25 @@ func (fb *FakeBackend) Load() error {
DatacenterID: "dc2", DatacenterID: "dc2",
} }
fb.hosts = append(fb.hosts, host, host2) host3 := &Host{
ID: "h3",
FQDN: "host3.example.com",
Aliases: []string{"host3", "host3.i"},
Tags: []string{},
GroupID: "g4",
DatacenterID: "dc2",
}
host4 := &Host{
ID: "h4",
FQDN: "host4.example.com",
Aliases: []string{"host4", "host4.i"},
Tags: []string{},
GroupID: "g4",
DatacenterID: "dc2",
}
fb.hosts = append(fb.hosts, host, host2, host3, host4)
return nil return nil
} }
@@ -214,7 +240,7 @@ func TestHostlist1(t *testing.T) {
} }
if len(hostlist) != 1 { if len(hostlist) != 1 {
t.Errorf("hostlist %%group1#special is expected to contain exactly 1 element") t.Errorf("hostlist %%group1#special is expected to contain exactly 1 element, %v", hostlist)
return return
} }
@@ -244,3 +270,33 @@ func TestHostlist2(t *testing.T) {
return return
} }
} }
func TestExclude(t *testing.T) {
fb := newFB()
fb.Load()
s, err := CreateStore(fb)
if err != nil {
t.Error(err)
return
}
hostlist, err := s.HostList([]rune("%group4"))
if err != nil {
t.Error(err)
}
if len(hostlist) != 2 {
t.Errorf("hostlist is expected to consist of exactly two elements, %v", hostlist)
}
hostlist, err = s.HostList([]rune("%group4,-host3.example.com"))
if err != nil {
t.Error(err)
}
if len(hostlist) != 1 {
t.Errorf("hostlist is expected to consist of exactly one element, %v", hostlist)
}
}

View File

@@ -14,3 +14,11 @@ func Index(arr []string, item string) int {
func Contains(arr []string, item string) bool { func Contains(arr []string, item string) bool {
return Index(arr, item) >= 0 return Index(arr, item) >= 0
} }
// Remove removes an item from array if it's in there
func Remove(arr *[]string, item string) {
idx := Index(*arr, item)
if idx >= 0 {
*arr = append((*arr)[0:idx], (*arr)[idx+1:len(*arr)]...)
}
}