diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2022-04-02 00:34:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-02 00:34:57 +0800 |
commit | 4f27c289472a4cfafb5a9b0e38e6a3413c30c562 (patch) | |
tree | 4a9388cfaf2efe4e9d0ed0242736769ef7e3e083 /modules/util | |
parent | 4c5cb1e2f2c7a1fcc3b151192bd45bd1bbc090bd (diff) | |
download | gitea-4f27c289472a4cfafb5a9b0e38e6a3413c30c562.tar.gz gitea-4f27c289472a4cfafb5a9b0e38e6a3413c30c562.zip |
Remove legacy `unknwon/com` package (#19298)
Follows: #19284
* The `CopyDir` is only used inside test code
* Rewrite `ToSnakeCase` with more test cases
* The `RedisCacher` only put strings into cache, here we use internal `toStr` to replace the legacy `ToStr`
* The `UniqueQueue` can use string as ID directly, no need to call `ToStr`
Diffstat (limited to 'modules/util')
-rw-r--r-- | modules/util/legacy.go | 40 | ||||
-rw-r--r-- | modules/util/legacy_test.go | 33 | ||||
-rw-r--r-- | modules/util/string.go | 88 | ||||
-rw-r--r-- | modules/util/string_test.go | 48 |
4 files changed, 187 insertions, 22 deletions
diff --git a/modules/util/legacy.go b/modules/util/legacy.go index c7da541534..d319faad09 100644 --- a/modules/util/legacy.go +++ b/modules/util/legacy.go @@ -9,29 +9,37 @@ import ( "crypto/cipher" "crypto/rand" "errors" - - "github.com/unknwon/com" //nolint:depguard + "io" + "os" ) // CopyFile copies file from source to target path. func CopyFile(src, dest string) error { - return com.Copy(src, dest) -} + si, err := os.Lstat(src) + if err != nil { + return err + } -// CopyDir copy files recursively from source to target directory. -// It returns error when error occurs in underlying functions. -func CopyDir(srcPath, destPath string) error { - return com.CopyDir(srcPath, destPath) -} + sr, err := os.Open(src) + if err != nil { + return err + } + defer sr.Close() -// ToStr converts any interface to string. should be replaced. -func ToStr(value interface{}, args ...int) string { - return com.ToStr(value, args...) -} + dw, err := os.Create(dest) + if err != nil { + return err + } + defer dw.Close() -// ToSnakeCase converts a string to snake_case. should be replaced. -func ToSnakeCase(str string) string { - return com.ToSnakeCase(str) + if _, err = io.Copy(dw, sr); err != nil { + return err + } + + if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil { + return err + } + return os.Chmod(dest, si.Mode()) } // AESGCMEncrypt (from legacy package): encrypts plaintext with the given key using AES in GCM mode. should be replaced. diff --git a/modules/util/legacy_test.go b/modules/util/legacy_test.go index cfda93d3ad..c41f7a008c 100644 --- a/modules/util/legacy_test.go +++ b/modules/util/legacy_test.go @@ -7,12 +7,38 @@ package util import ( "crypto/aes" "crypto/rand" + "fmt" + "os" "testing" + "time" "github.com/stretchr/testify/assert" - "github.com/unknwon/com" //nolint:depguard ) +func TestCopyFile(t *testing.T) { + testContent := []byte("hello") + + tmpDir := os.TempDir() + now := time.Now() + srcFile := fmt.Sprintf("%s/copy-test-%d-src.txt", tmpDir, now.UnixMicro()) + dstFile := fmt.Sprintf("%s/copy-test-%d-dst.txt", tmpDir, now.UnixMicro()) + + _ = os.Remove(srcFile) + _ = os.Remove(dstFile) + defer func() { + _ = os.Remove(srcFile) + _ = os.Remove(dstFile) + }() + + err := os.WriteFile(srcFile, testContent, 0o777) + assert.NoError(t, err) + err = CopyFile(srcFile, dstFile) + assert.NoError(t, err) + dstContent, err := os.ReadFile(dstFile) + assert.NoError(t, err) + assert.Equal(t, testContent, dstContent) +} + func TestAESGCM(t *testing.T) { t.Parallel() @@ -29,9 +55,4 @@ func TestAESGCM(t *testing.T) { assert.NoError(t, err) assert.Equal(t, plaintext, decrypted) - - // at the moment, we make sure the result is the same as the legacy package, this assertion can be removed in next round refactoring - legacy, err := com.AESGCMDecrypt(key, ciphertext) - assert.NoError(t, err) - assert.Equal(t, legacy, plaintext) } diff --git a/modules/util/string.go b/modules/util/string.go new file mode 100644 index 0000000000..4301f75f99 --- /dev/null +++ b/modules/util/string.go @@ -0,0 +1,88 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package util + +import "github.com/yuin/goldmark/util" + +func isSnakeCaseUpper(c byte) bool { + return 'A' <= c && c <= 'Z' +} + +func isSnakeCaseLowerOrNumber(c byte) bool { + return 'a' <= c && c <= 'z' || '0' <= c && c <= '9' +} + +// ToSnakeCase convert the input string to snake_case format. +// +// Some samples. +// "FirstName" => "first_name" +// "HTTPServer" => "http_server" +// "NoHTTPS" => "no_https" +// "GO_PATH" => "go_path" +// "GO PATH" => "go_path" // space is converted to underscore. +// "GO-PATH" => "go_path" // hyphen is converted to underscore. +// +func ToSnakeCase(input string) string { + if len(input) == 0 { + return "" + } + + var res []byte + if len(input) == 1 { + c := input[0] + if isSnakeCaseUpper(c) { + res = []byte{c + 'a' - 'A'} + } else if isSnakeCaseLowerOrNumber(c) { + res = []byte{c} + } else { + res = []byte{'_'} + } + } else { + res = make([]byte, 0, len(input)*4/3) + pos := 0 + needSep := false + for pos < len(input) { + c := input[pos] + if c >= 0x80 { + res = append(res, c) + pos++ + continue + } + isUpper := isSnakeCaseUpper(c) + if isUpper || isSnakeCaseLowerOrNumber(c) { + end := pos + 1 + if isUpper { + // skip the following upper letters + for end < len(input) && isSnakeCaseUpper(input[end]) { + end++ + } + if end-pos > 1 && end < len(input) && isSnakeCaseLowerOrNumber(input[end]) { + end-- + } + } + // skip the following lower or number letters + for end < len(input) && (isSnakeCaseLowerOrNumber(input[end]) || input[end] >= 0x80) { + end++ + } + if needSep { + res = append(res, '_') + } + res = append(res, input[pos:end]...) + pos = end + needSep = true + } else { + res = append(res, '_') + pos++ + needSep = false + } + } + for i := 0; i < len(res); i++ { + if isSnakeCaseUpper(res[i]) { + res[i] += 'a' - 'A' + } + } + } + return util.BytesToReadOnlyString(res) +} diff --git a/modules/util/string_test.go b/modules/util/string_test.go new file mode 100644 index 0000000000..49de29ab67 --- /dev/null +++ b/modules/util/string_test.go @@ -0,0 +1,48 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestToSnakeCase(t *testing.T) { + cases := map[string]string{ + // all old cases from the legacy package + "HTTPServer": "http_server", + "_camelCase": "_camel_case", + "NoHTTPS": "no_https", + "Wi_thF": "wi_th_f", + "_AnotherTES_TCaseP": "_another_tes_t_case_p", + "ALL": "all", + "_HELLO_WORLD_": "_hello_world_", + "HELLO_WORLD": "hello_world", + "HELLO____WORLD": "hello____world", + "TW": "tw", + "_C": "_c", + + " sentence case ": "__sentence_case__", + " Mixed-hyphen case _and SENTENCE_case and UPPER-case": "_mixed_hyphen_case__and_sentence_case_and_upper_case", + + // new cases + " ": "_", + "A": "a", + "A0": "a0", + "a0": "a0", + "Aa0": "aa0", + "啊": "啊", + "A啊": "a啊", + "Aa啊b": "aa啊b", + "A啊B": "a啊_b", + "Aa啊B": "aa啊_b", + "TheCase2": "the_case2", + "ObjIDs": "obj_i_ds", // the strange database column name which already exists + } + for input, expected := range cases { + assert.Equal(t, expected, ToSnakeCase(input)) + } +} |