diff --git a/CHANGELOG.md b/CHANGELOG.md index 63237135..8e8092e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ ## Changelog +### 12.81.0 + +* `[knf/validators/network]` Added `HasIP` validator +* `[strutil]` Added method `ReplaceIgnoreCase` +* `[uuid]` `GenUUID4` renamed to `UUID4` +* `[uuid]` `GenUUID5` renamed to `UUID5` +* `[uuid]` Code refactoring + ### 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/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) 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", "????") + } +} diff --git a/uuid/example_test.go b/uuid/example_test.go index 86124f59..acd1b2cf 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 ExampleUUID4() { + fmt.Printf("UUID v4: %s\n", UUID4().String()) } -func ExampleGenUUID4() { - fmt.Printf("UUID v4: %s\n", GenUUID4()) -} - -func ExampleGenUUID5() { - fmt.Printf("UUID v5: %s\n", GenUUID5(NsURL, "http://www.domain.com")) +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 89ef00e9..747467ff 100644 --- a/uuid/uuid.go +++ b/uuid/uuid.go @@ -26,26 +26,26 @@ var ( // ////////////////////////////////////////////////////////////////////////////////// // -// GenUUID generates v4 UUID (Universally Unique Identifier) -func GenUUID() string { - return GenUUID4() -} +// UUID contains UUID data +type UUID []byte -// GenUUID4 generates random generated UUID -func GenUUID4() string { - uuid := make([]byte, 16) +// ////////////////////////////////////////////////////////////////////////////////// // + +// UUID4 generates random generated UUID v4 +func UUID4() UUID { + uuid := make(UUID, 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) + return UUID(uuid) } -// GenUUID5 generates UUID based on SHA-1 hash of namespace UUID and name -func GenUUID5(ns []byte, name string) string { - uuid := make([]byte, 16) +// 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) hash := sha1.New() hash.Write(ns) @@ -53,26 +53,52 @@ 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) + 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 aed27f77..5c51a7d2 100644 --- a/uuid/uuid_test.go +++ b/uuid/uuid_test.go @@ -25,18 +25,19 @@ var _ = Suite(&UUIDSuite{}) // ////////////////////////////////////////////////////////////////////////////////// // -func (s *UUIDSuite) TestGenUUID(c *C) { - c.Assert(GenUUID(), HasLen, 36) - c.Assert(GenUUID(), 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, 16) + c.Assert(UUID4().String(), 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, 16) + c.Assert(UUID5(NsURL, "TEST").String(), 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") }