Skip to content

Commit a863d18

Browse files
authored
Add regexp sync type (#142)
* Add new sync.Regexp type * Driveby: fix missing and incorrect docs
1 parent bec71f5 commit a863d18

File tree

3 files changed

+130
-6
lines changed

3 files changed

+130
-6
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ The fields have to be one of the types that the sync package supports in order t
4545
- sync.Bool, allows for concurrent bool manipulation
4646
- sync.Secret, allows for concurrent secret manipulation. Secrets can only be strings
4747
- sync.TimeDuration, allows for concurrent time.duration manipulation.
48+
- sync.Regexp, allows for concurrent *regexp.Regexp manipulation.
4849
- sync.StringMap, allows for concurrent map[string]string manipulation.
50+
- sync.StringSlice, allows for concurrent []string manipulation.
4951

5052
For sensitive configuration (passwords, tokens, etc.) that shouldn't be printed in log, you can use the `Secret` flavor of `sync` types. If one of these is selected, then at harvester log instead of the real value the text `***` will be displayed.
5153

sync/sync.go

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"bytes"
66
"encoding/json"
77
"fmt"
8+
"regexp"
89
"strconv"
910
"strings"
1011
"sync"
@@ -38,7 +39,7 @@ func (b *Bool) MarshalJSON() ([]byte, error) {
3839
return json.Marshal(b.value)
3940
}
4041

41-
// MarshalJSON returns the JSON encoding of the value.
42+
// UnmarshalJSON returns the JSON encoding of the value.
4243
func (b *Bool) UnmarshalJSON(d []byte) error {
4344
b.rw.RLock()
4445
defer b.rw.RUnlock()
@@ -92,7 +93,7 @@ func (i *Int64) MarshalJSON() ([]byte, error) {
9293
return json.Marshal(i.value)
9394
}
9495

95-
// MarshalJSON returns the JSON encoding of the value.
96+
// UnmarshalJSON returns the JSON encoding of the value.
9697
func (i *Int64) UnmarshalJSON(d []byte) error {
9798
i.rw.RLock()
9899
defer i.rw.RUnlock()
@@ -143,7 +144,7 @@ func (f *Float64) MarshalJSON() ([]byte, error) {
143144
return json.Marshal(f.value)
144145
}
145146

146-
// MarshalJSON returns the JSON encoding of the value.
147+
// UnmarshalJSON returns the JSON encoding of the value.
147148
func (f *Float64) UnmarshalJSON(d []byte) error {
148149
f.rw.RLock()
149150
defer f.rw.RUnlock()
@@ -194,7 +195,7 @@ func (s *String) MarshalJSON() ([]byte, error) {
194195
return json.Marshal(s.value)
195196
}
196197

197-
// MarshalJSON returns the JSON encoding of the value.
198+
// UnmarshalJSON returns the JSON encoding of the value.
198199
func (s *String) UnmarshalJSON(d []byte) error {
199200
s.rw.RLock()
200201
defer s.rw.RUnlock()
@@ -241,7 +242,7 @@ func (s *TimeDuration) MarshalJSON() ([]byte, error) {
241242
return json.Marshal(s.value)
242243
}
243244

244-
// MarshalJSON returns the JSON encoding of the value.
245+
// UnmarshalJSON returns the JSON encoding of the value.
245246
func (s *TimeDuration) UnmarshalJSON(d []byte) error {
246247
s.rw.RLock()
247248
defer s.rw.RUnlock()
@@ -290,7 +291,7 @@ func (s *Secret) MarshalJSON() (out []byte, err error) {
290291
return json.Marshal(s.String())
291292
}
292293

293-
// MarshalJSON returns the JSON encoding of the value.
294+
// UnmarshalJSON returns the JSON encoding of the value.
294295
func (s *Secret) UnmarshalJSON(d []byte) error {
295296
s.rw.RLock()
296297
defer s.rw.RUnlock()
@@ -308,6 +309,67 @@ func (s *Secret) SetString(val string) error {
308309
return nil
309310
}
310311

312+
type Regexp struct {
313+
rw sync.RWMutex
314+
value *regexp.Regexp
315+
}
316+
317+
// Get returns the internal value.
318+
func (r *Regexp) Get() *regexp.Regexp {
319+
r.rw.RLock()
320+
defer r.rw.RUnlock()
321+
return r.value
322+
}
323+
324+
// Set a value.
325+
func (r *Regexp) Set(value *regexp.Regexp) {
326+
r.rw.Lock()
327+
defer r.rw.Unlock()
328+
r.value = value
329+
}
330+
331+
// MarshalJSON returns the JSON encoding of the value.
332+
func (r *Regexp) MarshalJSON() ([]byte, error) {
333+
r.rw.RLock()
334+
defer r.rw.RUnlock()
335+
return json.Marshal(r.value.String())
336+
}
337+
338+
// UnmarshalJSON returns the JSON encoding of the value.
339+
func (r *Regexp) UnmarshalJSON(d []byte) error {
340+
var str string
341+
err := json.Unmarshal(d, &str)
342+
if err != nil {
343+
fmt.Println("json unmarshal")
344+
return err
345+
}
346+
regex, err := regexp.Compile(str)
347+
if err != nil {
348+
fmt.Println("regex compile")
349+
return err
350+
}
351+
r.Set(regex)
352+
return nil
353+
}
354+
355+
// String returns a string representation of the value.
356+
func (r *Regexp) String() string {
357+
r.rw.RLock()
358+
defer r.rw.RUnlock()
359+
return r.value.String()
360+
}
361+
362+
//
363+
// SetString parses and sets a value from string type.
364+
func (r *Regexp) SetString(val string) error {
365+
compiled, err := regexp.Compile(val)
366+
if err != nil {
367+
return err
368+
}
369+
r.Set(compiled)
370+
return nil
371+
}
372+
311373
// StringMap is a map[string]string type with concurrent access support.
312374
type StringMap struct {
313375
rw sync.RWMutex

sync/sync_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package sync
22

33
import (
44
"fmt"
5+
"regexp"
56
"testing"
67
"time"
78

@@ -207,6 +208,65 @@ func TestTimeDuration_UnmarshalJSON(t *testing.T) {
207208
assert.Equal(t, time.Duration(1), b.Get())
208209
}
209210

211+
func TestRegexp(t *testing.T) {
212+
regex := regexp.MustCompile(".*")
213+
214+
var r Regexp
215+
ch := make(chan struct{})
216+
go func() {
217+
r.Set(regex)
218+
ch <- struct{}{}
219+
}()
220+
<-ch
221+
assert.Equal(t, regex, r.Get())
222+
assert.Equal(t, regex.String(), r.String())
223+
224+
d, err := r.MarshalJSON()
225+
assert.NoError(t, err)
226+
assert.Equal(t, `".*"`, string(d))
227+
}
228+
229+
func TestRegexp_UnmarshalJSON(t *testing.T) {
230+
var r Regexp
231+
err := r.UnmarshalJSON([]byte(`invalid json`))
232+
assert.Error(t, err)
233+
assert.Nil(t, r.Get())
234+
235+
// Invalid regex:
236+
err = r.UnmarshalJSON([]byte(`"[a-z]++"`))
237+
assert.Error(t, err)
238+
assert.Nil(t, r.Get())
239+
240+
err = r.UnmarshalJSON([]byte(`"[a-z0-7]+"`))
241+
assert.NoError(t, err)
242+
assert.Equal(t, regexp.MustCompile("[a-z0-7]+"), r.Get())
243+
}
244+
245+
func TestRegexp_SetString(t *testing.T) {
246+
tests := []struct {
247+
name string
248+
input string
249+
result *regexp.Regexp
250+
throwsError bool
251+
}{
252+
{"empty", "", regexp.MustCompile(""), false},
253+
{"simple regex", ".*", regexp.MustCompile(".*"), false},
254+
{"invalid regex", "[0-9]++", nil, true},
255+
}
256+
for _, test := range tests {
257+
t.Run(test.name, func(t *testing.T) {
258+
sr := Regexp{}
259+
260+
err := sr.SetString(test.input)
261+
if test.throwsError {
262+
assert.Error(t, err)
263+
}
264+
265+
assert.Equal(t, test.result, sr.Get())
266+
})
267+
}
268+
}
269+
210270
func TestStringMap(t *testing.T) {
211271
var sm StringMap
212272
ch := make(chan struct{})

0 commit comments

Comments
 (0)