This commit is contained in:
ryan
2026-06-19 15:13:24 +08:00
parent 0b34792709
commit 32861c5db9
376 changed files with 3648 additions and 19957 deletions
+31 -19
View File
@@ -1,3 +1,4 @@
// Package utils provides shared formatting and string helper functions.
package utils
import (
@@ -5,48 +6,59 @@ import (
"strconv"
)
const (
secondsPerYear = 31104000 // 360 days
secondsPerMonth = 2592000 // 30 days
secondsPerDay = 86400
secondsPerHour = 3600
secondsPerMinute = 60
)
var sizeKB = 1024
var sizeMB = sizeKB * 1024
var sizeGB = sizeMB * 1024
// Bytes2Size converts a byte count to a human-readable string with unit (B, KB, MB, GB).
func Bytes2Size(num int64) string {
numStr := ""
unit := "B"
if num/int64(sizeGB) > 1 {
switch {
case num/int64(sizeGB) > 1:
numStr = fmt.Sprintf("%.2f", float64(num)/float64(sizeGB))
unit = "GB"
} else if num/int64(sizeMB) > 1 {
case num/int64(sizeMB) > 1:
numStr = fmt.Sprintf("%d", int(float64(num)/float64(sizeMB)))
unit = "MB"
} else if num/int64(sizeKB) > 1 {
case num/int64(sizeKB) > 1:
numStr = fmt.Sprintf("%d", int(float64(num)/float64(sizeKB)))
unit = "KB"
} else {
default:
numStr = fmt.Sprintf("%d", num)
}
return numStr + " " + unit
}
// Seconds2Time converts a number of seconds to a human-readable Chinese duration string.
func Seconds2Time(num int) (time string) {
if num/31104000 > 0 {
time += strconv.Itoa(num/31104000) + " 年 "
num %= 31104000
if num/secondsPerYear > 0 {
time += strconv.Itoa(num/secondsPerYear) + " 年 "
num %= secondsPerYear
}
if num/2592000 > 0 {
time += strconv.Itoa(num/2592000) + " 个月 "
num %= 2592000
if num/secondsPerMonth > 0 {
time += strconv.Itoa(num/secondsPerMonth) + " 个月 "
num %= secondsPerMonth
}
if num/86400 > 0 {
time += strconv.Itoa(num/86400) + " 天 "
num %= 86400
if num/secondsPerDay > 0 {
time += strconv.Itoa(num/secondsPerDay) + " 天 "
num %= secondsPerDay
}
if num/3600 > 0 {
time += strconv.Itoa(num/3600) + " 小时 "
num %= 3600
if num/secondsPerHour > 0 {
time += strconv.Itoa(num/secondsPerHour) + " 小时 "
num %= secondsPerHour
}
if num/60 > 0 {
time += strconv.Itoa(num/60) + " 分钟 "
num %= 60
if num/secondsPerMinute > 0 {
time += strconv.Itoa(num/secondsPerMinute) + " 分钟 "
num %= secondsPerMinute
}
time += strconv.Itoa(num) + " 秒"
return
+22 -15
View File
@@ -6,7 +6,8 @@ import (
"strings"
)
func GetIp() (ip string) {
// GetIP returns the first private IPv4 address found on the local network interfaces.
func GetIP() (ip string) {
ips, err := net.InterfaceAddrs()
if err != nil {
slog.Error("get interface addresses failed", "error", err)
@@ -14,21 +15,27 @@ func GetIp() (ip string) {
}
for _, a := range ips {
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ip = ipNet.IP.String()
if strings.HasPrefix(ip, "10") {
return
}
if strings.HasPrefix(ip, "172") {
return
}
if strings.HasPrefix(ip, "192.168") {
return
}
ip = ""
}
if candidate, ok := privateIPv4FromAddr(a); ok {
return candidate
}
}
return
}
func privateIPv4FromAddr(addr net.Addr) (string, bool) {
ipNet, ok := addr.(*net.IPNet)
if !ok || ipNet.IP.IsLoopback() || ipNet.IP.To4() == nil {
return "", false
}
ip := ipNet.IP.String()
if isPrivateIPv4(ip) {
return ip, true
}
return "", false
}
func isPrivateIPv4(ip string) bool {
return strings.HasPrefix(ip, "10") ||
strings.HasPrefix(ip, "172") ||
strings.HasPrefix(ip, "192.168")
}
+5 -4
View File
@@ -2,14 +2,15 @@ package utils
import "fmt"
// Interface2String converts a string, int, or float64 value to its string representation.
func Interface2String(inter interface{}) string {
switch inter.(type) {
switch v := inter.(type) {
case string:
return inter.(string)
return v
case int:
return fmt.Sprintf("%d", inter.(int))
return fmt.Sprintf("%d", v)
case float64:
return fmt.Sprintf("%f", inter.(float64))
return fmt.Sprintf("%f", v)
}
return "Not Implemented"
}
+11 -93
View File
@@ -5,6 +5,9 @@ import (
"strings"
)
const gitDescribeMinIdentifiers = 2
// VersionInfo holds the parsed components of a semantic version string.
type VersionInfo struct {
Valid bool
IsDev bool
@@ -14,6 +17,7 @@ type VersionInfo struct {
GitDescribeTail []string
}
// ParseVersionInfo parses a version string into a structured VersionInfo.
func ParseVersionInfo(version string) VersionInfo {
normalized := strings.TrimSpace(strings.TrimPrefix(version, "v"))
if normalized == "" || normalized == "dev" {
@@ -66,7 +70,7 @@ func ParseVersionInfo(version string) VersionInfo {
}
func parseGitDescribeIdentifiers(identifiers []string) (int, []string, bool) {
if len(identifiers) < 2 {
if len(identifiers) < gitDescribeMinIdentifiers {
return 0, nil, false
}
distance, err := strconv.Atoi(strings.TrimSpace(identifiers[0]))
@@ -109,100 +113,14 @@ func CompareVersions(local, remote string) int {
return 0
}
maxLen := len(left.Numbers)
if len(right.Numbers) > maxLen {
maxLen = len(right.Numbers)
if result := compareVersionNumbers(left, right); result != 0 {
return result
}
for index := 0; index < maxLen; index++ {
leftValue := 0
rightValue := 0
if index < len(left.Numbers) {
leftValue = left.Numbers[index]
}
if index < len(right.Numbers) {
rightValue = right.Numbers[index]
}
if leftValue < rightValue {
return -1
}
if leftValue > rightValue {
return 1
}
}
if left.GitDescribeDistance != right.GitDescribeDistance {
if left.GitDescribeDistance < right.GitDescribeDistance {
return -1
}
return 1
if result := compareGitDescribeDistance(left, right); result != 0 {
return result
}
if left.GitDescribeDistance > 0 || right.GitDescribeDistance > 0 {
maxLen = len(left.GitDescribeTail)
if len(right.GitDescribeTail) > maxLen {
maxLen = len(right.GitDescribeTail)
}
for index := 0; index < maxLen; index++ {
if index >= len(left.GitDescribeTail) {
return -1
}
if index >= len(right.GitDescribeTail) {
return 1
}
if left.GitDescribeTail[index] < right.GitDescribeTail[index] {
return -1
}
if left.GitDescribeTail[index] > right.GitDescribeTail[index] {
return 1
}
}
return 0
return compareGitDescribeTails(left, right)
}
if len(left.Prerelease) == 0 && len(right.Prerelease) == 0 {
return 0
}
if len(left.Prerelease) == 0 {
return 1
}
if len(right.Prerelease) == 0 {
return -1
}
maxLen = len(left.Prerelease)
if len(right.Prerelease) > maxLen {
maxLen = len(right.Prerelease)
}
for index := 0; index < maxLen; index++ {
if index >= len(left.Prerelease) {
return -1
}
if index >= len(right.Prerelease) {
return 1
}
leftPart := left.Prerelease[index]
rightPart := right.Prerelease[index]
leftNumber, leftErr := strconv.Atoi(leftPart)
rightNumber, rightErr := strconv.Atoi(rightPart)
switch {
case leftErr == nil && rightErr == nil:
if leftNumber < rightNumber {
return -1
}
if leftNumber > rightNumber {
return 1
}
case leftErr == nil:
return -1
case rightErr == nil:
return 1
default:
if leftPart < rightPart {
return -1
}
if leftPart > rightPart {
return 1
}
}
}
return 0
return comparePrereleaseIdentifiers(left, right)
}
+114
View File
@@ -0,0 +1,114 @@
package utils
import "strconv"
func compareVersionNumbers(left, right VersionInfo) int {
maxLen := len(left.Numbers)
if len(right.Numbers) > maxLen {
maxLen = len(right.Numbers)
}
for index := 0; index < maxLen; index++ {
leftValue := 0
rightValue := 0
if index < len(left.Numbers) {
leftValue = left.Numbers[index]
}
if index < len(right.Numbers) {
rightValue = right.Numbers[index]
}
if leftValue < rightValue {
return -1
}
if leftValue > rightValue {
return 1
}
}
return 0
}
func compareGitDescribeDistance(left, right VersionInfo) int {
if left.GitDescribeDistance == right.GitDescribeDistance {
return 0
}
if left.GitDescribeDistance < right.GitDescribeDistance {
return -1
}
return 1
}
func compareGitDescribeTails(left, right VersionInfo) int {
maxLen := len(left.GitDescribeTail)
if len(right.GitDescribeTail) > maxLen {
maxLen = len(right.GitDescribeTail)
}
for index := 0; index < maxLen; index++ {
if index >= len(left.GitDescribeTail) {
return -1
}
if index >= len(right.GitDescribeTail) {
return 1
}
if left.GitDescribeTail[index] < right.GitDescribeTail[index] {
return -1
}
if left.GitDescribeTail[index] > right.GitDescribeTail[index] {
return 1
}
}
return 0
}
func comparePrereleaseIdentifiers(left, right VersionInfo) int {
if len(left.Prerelease) == 0 && len(right.Prerelease) == 0 {
return 0
}
if len(left.Prerelease) == 0 {
return 1
}
if len(right.Prerelease) == 0 {
return -1
}
maxLen := len(left.Prerelease)
if len(right.Prerelease) > maxLen {
maxLen = len(right.Prerelease)
}
for index := 0; index < maxLen; index++ {
if index >= len(left.Prerelease) {
return -1
}
if index >= len(right.Prerelease) {
return 1
}
if result := comparePrereleasePart(left.Prerelease[index], right.Prerelease[index]); result != 0 {
return result
}
}
return 0
}
func comparePrereleasePart(leftPart, rightPart string) int {
leftNumber, leftErr := strconv.Atoi(leftPart)
rightNumber, rightErr := strconv.Atoi(rightPart)
switch {
case leftErr == nil && rightErr == nil:
if leftNumber < rightNumber {
return -1
}
if leftNumber > rightNumber {
return 1
}
case leftErr == nil:
return -1
case rightErr == nil:
return 1
default:
if leftPart < rightPart {
return -1
}
if leftPart > rightPart {
return 1
}
}
return 0
}