mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-24 23:19:35 +02:00
Merge remote-tracking branch 'upstream/main' into limit-repo-size
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package base
|
||||
|
||||
type (
|
||||
// TplName template relative path type
|
||||
TplName string
|
||||
)
|
||||
@@ -41,8 +41,8 @@ func naturalSortAdvance(str string, pos int) (end int, isNumber bool) {
|
||||
return end, isNumber
|
||||
}
|
||||
|
||||
// NaturalSortLess compares two strings so that they could be sorted in natural order
|
||||
func NaturalSortLess(s1, s2 string) bool {
|
||||
// NaturalSortCompare compares two strings so that they could be sorted in natural order
|
||||
func NaturalSortCompare(s1, s2 string) int {
|
||||
// There is a bug in Golang's collate package: https://github.com/golang/go/issues/67997
|
||||
// text/collate: CompareString(collate.Numeric) returns wrong result for "0.0" vs "1.0" #67997
|
||||
// So we need to handle the number parts by ourselves
|
||||
@@ -55,16 +55,16 @@ func NaturalSortLess(s1, s2 string) bool {
|
||||
if isNum1 && isNum2 {
|
||||
if part1 != part2 {
|
||||
if len(part1) != len(part2) {
|
||||
return len(part1) < len(part2)
|
||||
return len(part1) - len(part2)
|
||||
}
|
||||
return part1 < part2
|
||||
return c.CompareString(part1, part2)
|
||||
}
|
||||
} else {
|
||||
if cmp := c.CompareString(part1, part2); cmp != 0 {
|
||||
return cmp < 0
|
||||
return cmp
|
||||
}
|
||||
}
|
||||
pos1, pos2 = end1, end2
|
||||
}
|
||||
return len(s1) < len(s2)
|
||||
return len(s1) - len(s2)
|
||||
}
|
||||
|
||||
@@ -11,12 +11,10 @@ import (
|
||||
|
||||
func TestNaturalSortLess(t *testing.T) {
|
||||
testLess := func(s1, s2 string) {
|
||||
assert.True(t, NaturalSortLess(s1, s2), "s1<s2 should be true: s1=%q, s2=%q", s1, s2)
|
||||
assert.False(t, NaturalSortLess(s2, s1), "s2<s1 should be false: s1=%q, s2=%q", s1, s2)
|
||||
assert.Negative(t, NaturalSortCompare(s1, s2), "s1<s2 should be true: s1=%q, s2=%q", s1, s2)
|
||||
}
|
||||
testEqual := func(s1, s2 string) {
|
||||
assert.False(t, NaturalSortLess(s1, s2), "s1<s2 should be false: s1=%q, s2=%q", s1, s2)
|
||||
assert.False(t, NaturalSortLess(s2, s1), "s2<s1 should be false: s1=%q, s2=%q", s1, s2)
|
||||
assert.Zero(t, NaturalSortCompare(s1, s2), "s1<s2 should be false: s1=%q, s2=%q", s1, s2)
|
||||
}
|
||||
|
||||
testEqual("", "")
|
||||
|
||||
+6
-116
@@ -8,22 +8,14 @@ import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
)
|
||||
@@ -38,20 +30,7 @@ func EncodeSha256(str string) string {
|
||||
// ShortSha is basically just truncating.
|
||||
// It is DEPRECATED and will be removed in the future.
|
||||
func ShortSha(sha1 string) string {
|
||||
return TruncateString(sha1, 10)
|
||||
}
|
||||
|
||||
// BasicAuthDecode decode basic auth string
|
||||
func BasicAuthDecode(encoded string) (string, string, error) {
|
||||
s, err := base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if username, password, ok := strings.Cut(string(s), ":"); ok {
|
||||
return username, password, nil
|
||||
}
|
||||
return "", "", errors.New("invalid basic authentication")
|
||||
return util.TruncateRunes(sha1, 10)
|
||||
}
|
||||
|
||||
// VerifyTimeLimitCode verify time limit code
|
||||
@@ -67,10 +46,7 @@ func VerifyTimeLimitCode(now time.Time, data string, minutes int, code string) b
|
||||
// check code
|
||||
retCode := CreateTimeLimitCode(data, aliveTime, startTimeStr, nil)
|
||||
if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
|
||||
retCode = CreateTimeLimitCode(data, aliveTime, startTimeStr, sha1.New()) // TODO: this is only for the support of legacy codes, remove this in/after 1.23
|
||||
if subtle.ConstantTimeCompare([]byte(retCode), []byte(code)) != 1 {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// check time is expired or not: startTime <= now && now < startTime + minutes
|
||||
@@ -126,27 +102,6 @@ func GetFileSize(s string) (int64, error) {
|
||||
return iv, err
|
||||
}
|
||||
|
||||
// EllipsisString returns a truncated short string,
|
||||
// it appends '...' in the end of the length of string is too large.
|
||||
func EllipsisString(str string, length int) string {
|
||||
if length <= 3 {
|
||||
return "..."
|
||||
}
|
||||
if utf8.RuneCountInString(str) <= length {
|
||||
return str
|
||||
}
|
||||
return string([]rune(str)[:length-3]) + "..."
|
||||
}
|
||||
|
||||
// TruncateString returns a truncated string with given limit,
|
||||
// it returns input string if length is not reached limit.
|
||||
func TruncateString(str string, limit int) string {
|
||||
if utf8.RuneCountInString(str) < limit {
|
||||
return str
|
||||
}
|
||||
return string([]rune(str)[:limit])
|
||||
}
|
||||
|
||||
// StringsToInt64s converts a slice of string to a slice of int64.
|
||||
func StringsToInt64s(strs []string) ([]int64, error) {
|
||||
if strs == nil {
|
||||
@@ -154,6 +109,9 @@ func StringsToInt64s(strs []string) ([]int64, error) {
|
||||
}
|
||||
ints := make([]int64, 0, len(strs))
|
||||
for _, s := range strs {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
n, err := strconv.ParseInt(s, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -171,71 +129,3 @@ func Int64sToStrings(ints []int64) []string {
|
||||
}
|
||||
return strs
|
||||
}
|
||||
|
||||
// EntryIcon returns the octicon class for displaying files/directories
|
||||
func EntryIcon(entry *git.TreeEntry) string {
|
||||
switch {
|
||||
case entry.IsLink():
|
||||
te, err := entry.FollowLink()
|
||||
if err != nil {
|
||||
log.Debug(err.Error())
|
||||
return "file-symlink-file"
|
||||
}
|
||||
if te.IsDir() {
|
||||
return "file-directory-symlink"
|
||||
}
|
||||
return "file-symlink-file"
|
||||
case entry.IsDir():
|
||||
return "file-directory-fill"
|
||||
case entry.IsSubModule():
|
||||
return "file-submodule"
|
||||
}
|
||||
|
||||
return "file"
|
||||
}
|
||||
|
||||
// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value
|
||||
func SetupGiteaRoot() string {
|
||||
giteaRoot := os.Getenv("GITEA_ROOT")
|
||||
if giteaRoot == "" {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
giteaRoot = strings.TrimSuffix(filename, "modules/base/tool.go")
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
rel, err := filepath.Rel(giteaRoot, wd)
|
||||
if err != nil && strings.HasPrefix(filepath.ToSlash(rel), "../") {
|
||||
giteaRoot = wd
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(giteaRoot, "gitea")); os.IsNotExist(err) {
|
||||
giteaRoot = ""
|
||||
} else if err := os.Setenv("GITEA_ROOT", giteaRoot); err != nil {
|
||||
giteaRoot = ""
|
||||
}
|
||||
}
|
||||
return giteaRoot
|
||||
}
|
||||
|
||||
// FormatNumberSI format a number
|
||||
func FormatNumberSI(data any) string {
|
||||
var num int64
|
||||
if num1, ok := data.(int64); ok {
|
||||
num = num1
|
||||
} else if num1, ok := data.(int); ok {
|
||||
num = int64(num1)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
|
||||
if num < 1000 {
|
||||
return fmt.Sprintf("%d", num)
|
||||
} else if num < 1000000 {
|
||||
num2 := float32(num) / float32(1000.0)
|
||||
return fmt.Sprintf("%.1fk", num2)
|
||||
} else if num < 1000000000 {
|
||||
num2 := float32(num) / float32(1000000.0)
|
||||
return fmt.Sprintf("%.1fM", num2)
|
||||
}
|
||||
num2 := float32(num) / float32(1000000000.0)
|
||||
return fmt.Sprintf("%.1fG", num2)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ package base
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -27,25 +26,6 @@ func TestShortSha(t *testing.T) {
|
||||
assert.Equal(t, "veryverylo", ShortSha("veryverylong"))
|
||||
}
|
||||
|
||||
func TestBasicAuthDecode(t *testing.T) {
|
||||
_, _, err := BasicAuthDecode("?")
|
||||
assert.Equal(t, "illegal base64 data at input byte 0", err.Error())
|
||||
|
||||
user, pass, err := BasicAuthDecode("Zm9vOmJhcg==")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "foo", user)
|
||||
assert.Equal(t, "bar", pass)
|
||||
|
||||
_, _, err = BasicAuthDecode("aW52YWxpZA==")
|
||||
assert.Error(t, err)
|
||||
|
||||
_, _, err = BasicAuthDecode("invalid")
|
||||
assert.Error(t, err)
|
||||
|
||||
_, _, err = BasicAuthDecode("YWxpY2U=") // "alice", no colon
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestVerifyTimeLimitCode(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.InstallLock, true)()
|
||||
initGeneralSecret := func(secret string) {
|
||||
@@ -87,13 +67,10 @@ JWT_SECRET = %s
|
||||
verifyDataCode := func(c string) bool {
|
||||
return VerifyTimeLimitCode(now, "data", 2, c)
|
||||
}
|
||||
code1 := CreateTimeLimitCode("data", 2, now, sha1.New())
|
||||
code2 := CreateTimeLimitCode("data", 2, now, nil)
|
||||
assert.True(t, verifyDataCode(code1))
|
||||
assert.True(t, verifyDataCode(code2))
|
||||
code := CreateTimeLimitCode("data", 2, now, nil)
|
||||
assert.True(t, verifyDataCode(code))
|
||||
initGeneralSecret("000_QLUd4fYVyxetjxC4eZkrBgWM2SndOOWDNtgUUko")
|
||||
assert.False(t, verifyDataCode(code1))
|
||||
assert.False(t, verifyDataCode(code2))
|
||||
assert.False(t, verifyDataCode(code))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -121,36 +98,6 @@ func TestGetFileSize(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestEllipsisString(t *testing.T) {
|
||||
assert.Equal(t, "...", EllipsisString("foobar", 0))
|
||||
assert.Equal(t, "...", EllipsisString("foobar", 1))
|
||||
assert.Equal(t, "...", EllipsisString("foobar", 2))
|
||||
assert.Equal(t, "...", EllipsisString("foobar", 3))
|
||||
assert.Equal(t, "f...", EllipsisString("foobar", 4))
|
||||
assert.Equal(t, "fo...", EllipsisString("foobar", 5))
|
||||
assert.Equal(t, "foobar", EllipsisString("foobar", 6))
|
||||
assert.Equal(t, "foobar", EllipsisString("foobar", 10))
|
||||
assert.Equal(t, "测...", EllipsisString("测试文本一二三四", 4))
|
||||
assert.Equal(t, "测试...", EllipsisString("测试文本一二三四", 5))
|
||||
assert.Equal(t, "测试文...", EllipsisString("测试文本一二三四", 6))
|
||||
assert.Equal(t, "测试文本一二三四", EllipsisString("测试文本一二三四", 10))
|
||||
}
|
||||
|
||||
func TestTruncateString(t *testing.T) {
|
||||
assert.Equal(t, "", TruncateString("foobar", 0))
|
||||
assert.Equal(t, "f", TruncateString("foobar", 1))
|
||||
assert.Equal(t, "fo", TruncateString("foobar", 2))
|
||||
assert.Equal(t, "foo", TruncateString("foobar", 3))
|
||||
assert.Equal(t, "foob", TruncateString("foobar", 4))
|
||||
assert.Equal(t, "fooba", TruncateString("foobar", 5))
|
||||
assert.Equal(t, "foobar", TruncateString("foobar", 6))
|
||||
assert.Equal(t, "foobar", TruncateString("foobar", 7))
|
||||
assert.Equal(t, "测试文本", TruncateString("测试文本一二三四", 4))
|
||||
assert.Equal(t, "测试文本一", TruncateString("测试文本一二三四", 5))
|
||||
assert.Equal(t, "测试文本一二", TruncateString("测试文本一二三四", 6))
|
||||
assert.Equal(t, "测试文本一二三", TruncateString("测试文本一二三四", 7))
|
||||
}
|
||||
|
||||
func TestStringsToInt64s(t *testing.T) {
|
||||
testSuccess := func(input []string, expected []int64) {
|
||||
result, err := StringsToInt64s(input)
|
||||
@@ -159,11 +106,12 @@ func TestStringsToInt64s(t *testing.T) {
|
||||
}
|
||||
testSuccess(nil, nil)
|
||||
testSuccess([]string{}, []int64{})
|
||||
testSuccess([]string{""}, []int64{})
|
||||
testSuccess([]string{"-1234"}, []int64{-1234})
|
||||
testSuccess([]string{"1", "4", "16", "64", "256"}, []int64{1, 4, 16, 64, 256})
|
||||
|
||||
ints, err := StringsToInt64s([]string{"-1", "a"})
|
||||
assert.Len(t, ints, 0)
|
||||
assert.Empty(t, ints)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
@@ -174,20 +122,3 @@ func TestInt64sToStrings(t *testing.T) {
|
||||
Int64sToStrings([]int64{1, 4, 16, 64, 256}),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Test EntryIcon
|
||||
|
||||
func TestSetupGiteaRoot(t *testing.T) {
|
||||
_ = os.Setenv("GITEA_ROOT", "test")
|
||||
assert.Equal(t, "test", SetupGiteaRoot())
|
||||
_ = os.Setenv("GITEA_ROOT", "")
|
||||
assert.NotEqual(t, "test", SetupGiteaRoot())
|
||||
}
|
||||
|
||||
func TestFormatNumberSI(t *testing.T) {
|
||||
assert.Equal(t, "125", FormatNumberSI(int(125)))
|
||||
assert.Equal(t, "1.3k", FormatNumberSI(int64(1317)))
|
||||
assert.Equal(t, "21.3M", FormatNumberSI(21317675))
|
||||
assert.Equal(t, "45.7G", FormatNumberSI(45721317675))
|
||||
assert.Equal(t, "", FormatNumberSI("test"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user