From fb373c0d367edffcd70dd59baa6a48a57814e6a3 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Mon, 16 Oct 2023 13:46:42 +0300 Subject: [PATCH 1/5] [strutil] Add method 'ReplaceIgnoreCase' --- CHANGELOG.md | 4 ++++ ek.go | 2 +- strutil/example_test.go | 9 +++++++++ strutil/strutil.go | 35 ++++++++++++++++++++++++++++++++--- strutil/strutil_test.go | 13 +++++++++++++ 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63237135..9dc4f53f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Changelog +### 12.81.0 + +* `[strutil]` Added method `ReplaceIgnoreCase` + ### 12.80.0 * `[system]` Added ANSI color info to `OSInfo` diff --git a/ek.go b/ek.go index 71e3c8e3..d5cfa933 100644 --- a/ek.go +++ b/ek.go @@ -20,7 +20,7 @@ import ( // ////////////////////////////////////////////////////////////////////////////////// // // VERSION is current ek package version -const VERSION = "12.80.0" +const VERSION = "12.81.0" // ////////////////////////////////////////////////////////////////////////////////// // diff --git a/strutil/example_test.go b/strutil/example_test.go index 3f0464cd..b9205a79 100644 --- a/strutil/example_test.go +++ b/strutil/example_test.go @@ -122,6 +122,15 @@ func ExampleReplaceAll() { // M???ag? } +func ExampleReplaceIgnoreCase() { + fmt.Println(ReplaceIgnoreCase( + "User bob has no item. Add items to user Bob?", "bob", "[Bob]", + )) + + // Output: + // User [Bob] has no item. Add items to user [Bob]? +} + func ExampleFields() { fmt.Printf("%#v\n", Fields("Bob Alice, 'Mary Key', \"John Dow\"")) diff --git a/strutil/strutil.go b/strutil/strutil.go index 7666d431..186904ae 100644 --- a/strutil/strutil.go +++ b/strutil/strutil.go @@ -234,8 +234,8 @@ func SuffixSize(str string, suffix rune) int { return result } -// ReplaceAll replaces all symbols in given string -func ReplaceAll(source, from, to string) string { +// ReplaceAll replaces all symbols from replset in string +func ReplaceAll(source, replset, to string) string { if source == "" { return "" } @@ -244,7 +244,7 @@ func ReplaceAll(source, from, to string) string { SOURCELOOP: for _, sourceSym := range source { - for _, fromSym := range from { + for _, fromSym := range replset { if fromSym == sourceSym { result.WriteString(to) continue SOURCELOOP @@ -257,6 +257,35 @@ SOURCELOOP: return result.String() } +// ReplaceIgnoreCase replaces part of the string ignoring case +func ReplaceIgnoreCase(source, from, to string) string { + if source == "" || from == "" { + return source + } + + var result strings.Builder + + from = strings.ToLower(from) + lowSource := strings.ToLower(source) + + for { + index := strings.Index(lowSource, from) + + if index == -1 { + result.WriteString(source) + break + } + + result.WriteString(source[:index]) + result.WriteString(to) + + source = source[index+len(from):] + lowSource = lowSource[index+len(from):] + } + + return result.String() +} + // Exclude excludes substring from given string func Exclude(data, substr string) string { if len(data) == 0 || len(substr) == 0 { diff --git a/strutil/strutil_test.go b/strutil/strutil_test.go index 5e2f38f1..0acb6a86 100644 --- a/strutil/strutil_test.go +++ b/strutil/strutil_test.go @@ -125,6 +125,13 @@ func (s *StrUtilSuite) TestReplaceAll(c *C) { c.Assert(ReplaceAll("", "AB12", "?"), Equals, "") } +func (s *StrUtilSuite) TestReplaceIgnoreCase(c *C) { + c.Assert(ReplaceIgnoreCase("ABCD1234abcd1234AbCd11ABcd", "abcd", "????"), Equals, "????1234????1234????11????") + c.Assert(ReplaceIgnoreCase("TESTtestTEST", "abcd", "????"), Equals, "TESTtestTEST") + c.Assert(ReplaceIgnoreCase("", "abcd", "????"), Equals, "") + c.Assert(ReplaceIgnoreCase("ABCD1234abcd1234AbCd11ABcd", "abcd", ""), Equals, "1234123411") +} + func (s *StrUtilSuite) TestFields(c *C) { c.Assert(Fields(""), IsNil) c.Assert(Fields(""), HasLen, 0) @@ -252,3 +259,9 @@ func (s *StrUtilSuite) BenchmarkReplaceAll(c *C) { ReplaceAll("ABCDABCD12341234", "AB12", "?") } } + +func (s *StrUtilSuite) BenchmarkReplaceIgnoreCase(c *C) { + for i := 0; i < c.N; i++ { + ReplaceIgnoreCase("ABCD1234abcd1234AbCd11ABcd", "abcd", "????") + } +} From a7c7846a4c0c3e36347de62f4e3c98e13a8fe31e Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Mon, 16 Oct 2023 14:19:25 +0300 Subject: [PATCH 2/5] [uuid] Code refactoring --- CHANGELOG.md | 3 +++ uuid/uuid.go | 33 ++++++++++++++++++++++++++++----- uuid/uuid_test.go | 16 +++++++++++----- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dc4f53f..a8c20f22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ### 12.81.0 * `[strutil]` Added method `ReplaceIgnoreCase` +* `[uuid]` `GenUUID` renamed to `UUID` +* `[uuid]` `GenUUID4` renamed to `UUID4` +* `[uuid]` `GenUUID5` renamed to `UUID5` ### 12.80.0 diff --git a/uuid/uuid.go b/uuid/uuid.go index 89ef00e9..dd87259b 100644 --- a/uuid/uuid.go +++ b/uuid/uuid.go @@ -27,24 +27,47 @@ var ( // ////////////////////////////////////////////////////////////////////////////////// // // GenUUID generates v4 UUID (Universally Unique Identifier) +// +// Deprecated: Use method UUID instead func GenUUID() string { - return GenUUID4() + return UUID4() +} + +// UUID4 generates v4 UUID (Universally Unique Identifier) +func UUID() string { + return UUID4() } // GenUUID4 generates random generated UUID +// +// Deprecated: Use method UUID4 instead func GenUUID4() string { + return UUID4() +} + +// UUID4 generates random generated UUID +// +// Deprecated: Use method UUID4 instead +func UUID4() string { uuid := make([]byte, 16) rand.Read(uuid) - uuid[6] = (uuid[6] & 0X0F) | 0X40 - uuid[8] = (uuid[8] & 0X3F) | 0X80 + uuid[6] = (uuid[6] & 0x0F) | 0x40 + uuid[8] = (uuid[8] & 0x3F) | 0x80 return toString(uuid) } // GenUUID5 generates UUID based on SHA-1 hash of namespace UUID and name +// +// Deprecated: Use method UUID5 instead func GenUUID5(ns []byte, name string) string { + return UUID5(ns, name) +} + +// UUID5 generates UUID based on SHA-1 hash of namespace UUID and name +func UUID5(ns []byte, name string) string { uuid := make([]byte, 16) hash := sha1.New() @@ -53,8 +76,8 @@ func GenUUID5(ns []byte, name string) string { copy(uuid, hash.Sum(nil)) - uuid[6] = (uuid[6] & 0X0F) | 0x50 - uuid[8] = (uuid[8] & 0X3F) | 0x80 + uuid[6] = (uuid[6] & 0x0F) | 0x50 + uuid[8] = (uuid[8] & 0x3F) | 0x80 return toString(uuid) } diff --git a/uuid/uuid_test.go b/uuid/uuid_test.go index aed27f77..aeddb8b6 100644 --- a/uuid/uuid_test.go +++ b/uuid/uuid_test.go @@ -26,17 +26,23 @@ var _ = Suite(&UUIDSuite{}) // ////////////////////////////////////////////////////////////////////////////////// // func (s *UUIDSuite) TestGenUUID(c *C) { - c.Assert(GenUUID(), HasLen, 36) - c.Assert(GenUUID(), Not(Equals), "00000000-0000-0000-0000-000000000000") + c.Assert(UUID(), HasLen, 36) + c.Assert(UUID(), Not(Equals), "00000000-0000-0000-0000-000000000000") } func (s *UUIDSuite) TestGenUUID4(c *C) { - c.Assert(GenUUID4(), HasLen, 36) - c.Assert(GenUUID4(), Not(Equals), "00000000-0000-0000-0000-000000000000") + c.Assert(UUID4(), HasLen, 36) + c.Assert(UUID4(), Not(Equals), "00000000-0000-0000-0000-000000000000") } func (s *UUIDSuite) TestGenUUID5(c *C) { - c.Assert(GenUUID5(NsURL, "TEST"), HasLen, 36) + c.Assert(UUID5(NsURL, "TEST"), HasLen, 36) + c.Assert(UUID5(NsURL, "TEST"), Not(Equals), "00000000-0000-0000-0000-000000000000") +} + +func (s *UUIDSuite) TestDeprecated(c *C) { + c.Assert(GenUUID(), Not(Equals), "00000000-0000-0000-0000-000000000000") + c.Assert(GenUUID4(), Not(Equals), "00000000-0000-0000-0000-000000000000") c.Assert(GenUUID5(NsURL, "TEST"), Not(Equals), "00000000-0000-0000-0000-000000000000") } From c926a0db9929fc111c5e72b41888cb8715901fe4 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Mon, 16 Oct 2023 15:27:31 +0300 Subject: [PATCH 3/5] [uuid] Code refactoring --- CHANGELOG.md | 1 + uuid/example_test.go | 8 ++--- uuid/uuid.go | 79 +++++++++++++++++++++++--------------------- uuid/uuid_test.go | 13 +++----- 4 files changed, 48 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c20f22..bcf8e1cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * `[uuid]` `GenUUID` renamed to `UUID` * `[uuid]` `GenUUID4` renamed to `UUID4` * `[uuid]` `GenUUID5` renamed to `UUID5` +* `[uuid]` Code refactoring ### 12.80.0 diff --git a/uuid/example_test.go b/uuid/example_test.go index 86124f59..518a8ae5 100644 --- a/uuid/example_test.go +++ b/uuid/example_test.go @@ -13,14 +13,10 @@ import ( // ////////////////////////////////////////////////////////////////////////////////// // -func ExampleGenUUID() { - fmt.Printf("UUID: %s\n", GenUUID()) -} - func ExampleGenUUID4() { - fmt.Printf("UUID v4: %s\n", GenUUID4()) + fmt.Printf("UUID v4: %s\n", UUID4().String()) } func ExampleGenUUID5() { - fmt.Printf("UUID v5: %s\n", GenUUID5(NsURL, "http://www.domain.com")) + fmt.Printf("UUID v5: %s\n", UUID5(NsURL, "http://www.domain.com").String()) } diff --git a/uuid/uuid.go b/uuid/uuid.go index dd87259b..787561a3 100644 --- a/uuid/uuid.go +++ b/uuid/uuid.go @@ -26,49 +26,26 @@ var ( // ////////////////////////////////////////////////////////////////////////////////// // -// GenUUID generates v4 UUID (Universally Unique Identifier) -// -// Deprecated: Use method UUID instead -func GenUUID() string { - return UUID4() -} +// UUID contains UUID data +type UUID []byte -// UUID4 generates v4 UUID (Universally Unique Identifier) -func UUID() string { - return UUID4() -} - -// GenUUID4 generates random generated UUID -// -// Deprecated: Use method UUID4 instead -func GenUUID4() string { - return UUID4() -} +// ////////////////////////////////////////////////////////////////////////////////// // // UUID4 generates random generated UUID -// -// Deprecated: Use method UUID4 instead -func UUID4() string { - uuid := make([]byte, 16) +func UUID4() UUID { + uuid := make(UUID, 16) rand.Read(uuid) uuid[6] = (uuid[6] & 0x0F) | 0x40 uuid[8] = (uuid[8] & 0x3F) | 0x80 - return toString(uuid) -} - -// GenUUID5 generates UUID based on SHA-1 hash of namespace UUID and name -// -// Deprecated: Use method UUID5 instead -func GenUUID5(ns []byte, name string) string { - return UUID5(ns, name) + return UUID(uuid) } // UUID5 generates UUID based on SHA-1 hash of namespace UUID and name -func UUID5(ns []byte, name string) string { - uuid := make([]byte, 16) +func UUID5(ns []byte, name string) UUID { + uuid := make(UUID, 16) hash := sha1.New() hash.Write(ns) @@ -79,23 +56,49 @@ func UUID5(ns []byte, name string) string { uuid[6] = (uuid[6] & 0x0F) | 0x50 uuid[8] = (uuid[8] & 0x3F) | 0x80 - return toString(uuid) + return UUID(uuid) } // ////////////////////////////////////////////////////////////////////////////////// // -func toString(uuid []byte) string { +// String returns string representation of UUID +func (u UUID) String() string { buf := make([]byte, 36) - hex.Encode(buf[0:8], uuid[0:4]) + hex.Encode(buf[0:8], u[0:4]) buf[8] = '-' - hex.Encode(buf[9:13], uuid[4:6]) + hex.Encode(buf[9:13], u[4:6]) buf[13] = '-' - hex.Encode(buf[14:18], uuid[6:8]) + hex.Encode(buf[14:18], u[6:8]) buf[18] = '-' - hex.Encode(buf[19:23], uuid[8:10]) + hex.Encode(buf[19:23], u[8:10]) buf[23] = '-' - hex.Encode(buf[24:], uuid[10:]) + hex.Encode(buf[24:], u[10:]) return string(buf) } + +// ////////////////////////////////////////////////////////////////////////////////// // + +// GenUUID generates v4 UUID (Universally Unique Identifier) +// +// Deprecated: Use method UUID4.String() instead +func GenUUID() string { + return UUID4().String() +} + +// GenUUID4 generates random generated UUID +// +// Deprecated: Use method UUID4.String() instead +func GenUUID4() string { + return UUID4().String() +} + +// GenUUID5 generates UUID based on SHA-1 hash of namespace UUID and name +// +// Deprecated: Use method UUID5.String() instead +func GenUUID5(ns []byte, name string) string { + return UUID5(ns, name).String() +} + +// ////////////////////////////////////////////////////////////////////////////////// // diff --git a/uuid/uuid_test.go b/uuid/uuid_test.go index aeddb8b6..5c51a7d2 100644 --- a/uuid/uuid_test.go +++ b/uuid/uuid_test.go @@ -25,19 +25,14 @@ var _ = Suite(&UUIDSuite{}) // ////////////////////////////////////////////////////////////////////////////////// // -func (s *UUIDSuite) TestGenUUID(c *C) { - c.Assert(UUID(), HasLen, 36) - c.Assert(UUID(), Not(Equals), "00000000-0000-0000-0000-000000000000") -} - func (s *UUIDSuite) TestGenUUID4(c *C) { - c.Assert(UUID4(), HasLen, 36) - c.Assert(UUID4(), Not(Equals), "00000000-0000-0000-0000-000000000000") + c.Assert(UUID4(), HasLen, 16) + c.Assert(UUID4().String(), Not(Equals), "00000000-0000-0000-0000-000000000000") } func (s *UUIDSuite) TestGenUUID5(c *C) { - c.Assert(UUID5(NsURL, "TEST"), HasLen, 36) - c.Assert(UUID5(NsURL, "TEST"), Not(Equals), "00000000-0000-0000-0000-000000000000") + c.Assert(UUID5(NsURL, "TEST"), HasLen, 16) + c.Assert(UUID5(NsURL, "TEST").String(), Not(Equals), "00000000-0000-0000-0000-000000000000") } func (s *UUIDSuite) TestDeprecated(c *C) { From 2eb430a48be2572b3a408dcda826c88121fc4cc3 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Mon, 16 Oct 2023 15:54:25 +0300 Subject: [PATCH 4/5] [uuid] Code refactoring --- CHANGELOG.md | 1 - uuid/example_test.go | 4 ++-- uuid/uuid.go | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcf8e1cb..59578fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,6 @@ ### 12.81.0 * `[strutil]` Added method `ReplaceIgnoreCase` -* `[uuid]` `GenUUID` renamed to `UUID` * `[uuid]` `GenUUID4` renamed to `UUID4` * `[uuid]` `GenUUID5` renamed to `UUID5` * `[uuid]` Code refactoring diff --git a/uuid/example_test.go b/uuid/example_test.go index 518a8ae5..acd1b2cf 100644 --- a/uuid/example_test.go +++ b/uuid/example_test.go @@ -13,10 +13,10 @@ import ( // ////////////////////////////////////////////////////////////////////////////////// // -func ExampleGenUUID4() { +func ExampleUUID4() { fmt.Printf("UUID v4: %s\n", UUID4().String()) } -func ExampleGenUUID5() { +func ExampleUUID5() { fmt.Printf("UUID v5: %s\n", UUID5(NsURL, "http://www.domain.com").String()) } diff --git a/uuid/uuid.go b/uuid/uuid.go index 787561a3..747467ff 100644 --- a/uuid/uuid.go +++ b/uuid/uuid.go @@ -31,7 +31,7 @@ type UUID []byte // ////////////////////////////////////////////////////////////////////////////////// // -// UUID4 generates random generated UUID +// UUID4 generates random generated UUID v4 func UUID4() UUID { uuid := make(UUID, 16) @@ -43,7 +43,7 @@ func UUID4() UUID { return UUID(uuid) } -// UUID5 generates UUID based on SHA-1 hash of namespace UUID and name +// UUID5 generates UUID v5 based on SHA-1 hash of namespace UUID and name func UUID5(ns []byte, name string) UUID { uuid := make(UUID, 16) From f93a10f9278583b5a3b895bb12b69b1803d8d6d9 Mon Sep 17 00:00:00 2001 From: Anton Novojilov Date: Mon, 16 Oct 2023 23:27:40 +0300 Subject: [PATCH 5/5] [knf/validators/network] Added 'HasIP' validator --- CHANGELOG.md | 1 + knf/validators/network/validators.go | 39 +++++++++++++++++++++-- knf/validators/network/validators_test.go | 22 +++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59578fa7..8e8092e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### 12.81.0 +* `[knf/validators/network]` Added `HasIP` validator * `[strutil]` Added method `ReplaceIgnoreCase` * `[uuid]` `GenUUID4` renamed to `UUID4` * `[uuid]` `GenUUID5` renamed to `UUID5` diff --git a/knf/validators/network/validators.go b/knf/validators/network/validators.go index 80713ba5..34c9522b 100644 --- a/knf/validators/network/validators.go +++ b/knf/validators/network/validators.go @@ -33,6 +33,9 @@ var ( // URL returns error if config property isn't a valid URL URL = validateURL + + // HasIP returns error if system doesn't have interface with IP from config property + HasIP = validateHasIP ) // ////////////////////////////////////////////////////////////////////////////////// // @@ -82,7 +85,7 @@ func validateMAC(config *knf.Config, prop string, value any) error { return fmt.Errorf("%s is not a valid MAC address: %v", macStr, err) } - return err + return nil } func validateCIDR(config *knf.Config, prop string, value any) error { @@ -98,7 +101,7 @@ func validateCIDR(config *knf.Config, prop string, value any) error { return fmt.Errorf("%s is not a valid CIDR address: %v", cidrStr, err) } - return err + return nil } func validateURL(config *knf.Config, prop string, value any) error { @@ -114,5 +117,35 @@ func validateURL(config *knf.Config, prop string, value any) error { return fmt.Errorf("%s is not a valid URL address: %v", urlStr, err) } - return err + return nil +} + +func validateHasIP(config *knf.Config, prop string, value any) error { + ipStr := config.GetS(prop) + + if ipStr == "" { + return nil + } + + interfaces, err := net.Interfaces() + + if err != nil { + return fmt.Errorf("Can't get interfaces info for check: %v", err) + } + + for _, i := range interfaces { + addr, err := i.Addrs() + + if err != nil { + continue + } + + for _, a := range addr { + if ipStr == a.(*net.IPNet).IP.String() { + return nil + } + } + } + + return fmt.Errorf("The system does not have an interface with the address %s", ipStr) } diff --git a/knf/validators/network/validators_test.go b/knf/validators/network/validators_test.go index 5729b20a..802c0926 100644 --- a/knf/validators/network/validators_test.go +++ b/knf/validators/network/validators_test.go @@ -23,6 +23,7 @@ const _CONFIG_DATA = ` test0: test1: 127.0.0.1 test2: 300.0.400.5 + test3: 192.168.1.254 [port] test0: @@ -83,6 +84,27 @@ func (s *ValidatorSuite) TestIPValidator(c *C) { c.Assert(errs[0].Error(), Equals, "300.0.400.5 is not a valid IP address") } +func (s *ValidatorSuite) TestHasIPValidator(c *C) { + configFile := createConfig(c, _CONFIG_DATA) + + err := knf.Global(configFile) + c.Assert(err, IsNil) + + errs := knf.Validate([]*knf.Validator{ + {"ip:test0", HasIP, nil}, + {"ip:test1", HasIP, nil}, + }) + + c.Assert(errs, HasLen, 0) + + errs = knf.Validate([]*knf.Validator{ + {"ip:test3", HasIP, nil}, + }) + + c.Assert(errs, HasLen, 1) + c.Assert(errs[0].Error(), Equals, "The system does not have an interface with the address 192.168.1.254") +} + func (s *ValidatorSuite) TestPortValidator(c *C) { configFile := createConfig(c, _CONFIG_DATA)