Compare commits

...

18 Commits

Author SHA1 Message Date
spiritysdx
956f65941e update 2024-07-01 17:15:27 +08:00
spiritysdx
6d1f806e94 update 2024-07-01 17:04:37 +08:00
spiritysdx
d727d6b778 update 2024-07-01 16:58:02 +08:00
spiritysdx
ea891861b3 update 2024-07-01 16:40:35 +08:00
spiritysdx
e0826a80c8 update 2024-07-01 16:38:45 +08:00
spiritysdx
74868a918e update 2024-07-01 16:34:36 +08:00
spiritysdx
889ecee3f3 update 2024-07-01 16:32:36 +08:00
spiritysdx
f6dd0bbb56 update 2024-07-01 15:03:54 +08:00
spiritysdx
01686f3e9d update 2024-07-01 13:44:03 +08:00
spiritysdx
5a6cd7d671 update 2024-07-01 13:31:44 +08:00
spiritysdx
35e183b640 update 2024-07-01 13:14:49 +08:00
spiritysdx
a684052966 update 2024-07-01 12:29:18 +08:00
spiritysdx
2beb74c319 update 2024-07-01 12:22:39 +08:00
spiritysdx
5218c95162 update 2024-07-01 12:10:56 +08:00
spiritysdx
83be2066c8 update 2024-07-01 12:00:52 +08:00
spiritysdx
975bcbfc00 update 2024-07-01 11:51:35 +08:00
spiritysdx
dbddbc29a3 update 2024-07-01 11:50:33 +08:00
spiritysdx
af3894a908 update 2024-06-30 23:28:34 +08:00
7 changed files with 447 additions and 151 deletions

View File

@@ -28,3 +28,7 @@ Shell版本 https://github.com/spiritLHLS/ecs
## 说明 ## 说明
开发中,勿要使用 开发中,勿要使用
```
curl -L https://raw.githubusercontent.com/oneclickvirt/ecs/master/goecs.sh -o goecs.sh && chmod +x goecs.sh
```

10
go.mod
View File

@@ -7,14 +7,15 @@ require (
github.com/oneclickvirt/CommonMediaTests v0.0.2-20240630023003 github.com/oneclickvirt/CommonMediaTests v0.0.2-20240630023003
github.com/oneclickvirt/UnlockTests v0.0.10-20240630044930 github.com/oneclickvirt/UnlockTests v0.0.10-20240630044930
github.com/oneclickvirt/backtrace v0.0.4-20240624090335 github.com/oneclickvirt/backtrace v0.0.4-20240624090335
github.com/oneclickvirt/basics v0.0.3-20240625075226 github.com/oneclickvirt/basics v0.0.3-20240701085439
github.com/oneclickvirt/cputest v0.0.6-20240630144058 github.com/oneclickvirt/cputest v0.0.7-20240701020012
github.com/oneclickvirt/defaultset v0.0.2-20240624082446 github.com/oneclickvirt/defaultset v0.0.2-20240624082446
github.com/oneclickvirt/disktest v0.0.3-20240629152513 github.com/oneclickvirt/disktest v0.0.3-20240629152513
github.com/oneclickvirt/gostun v0.0.2-20240625025941
github.com/oneclickvirt/memorytest v0.0.1-20240624151629 github.com/oneclickvirt/memorytest v0.0.1-20240624151629
github.com/oneclickvirt/nt3 v0.0.1-20240630131017 github.com/oneclickvirt/nt3 v0.0.2-20240630152642
github.com/oneclickvirt/portchecker v0.0.1-20240624155429 github.com/oneclickvirt/portchecker v0.0.1-20240624155429
github.com/oneclickvirt/security v0.0.2-20240630142358 github.com/oneclickvirt/security v0.0.3-20240701065755
github.com/oneclickvirt/speedtest v0.0.6-20240630114816 github.com/oneclickvirt/speedtest v0.0.6-20240630114816
) )
@@ -47,7 +48,6 @@ require (
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nxtrace/NTrace-core v1.3.1 // indirect github.com/nxtrace/NTrace-core v1.3.1 // indirect
github.com/oneclickvirt/gostun v0.0.2-20240625025941 // indirect
github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/onsi/ginkgo/v2 v2.19.0 // indirect
github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect

16
go.sum
View File

@@ -83,8 +83,12 @@ github.com/oneclickvirt/backtrace v0.0.4-20240624090335 h1:0LP5KyA6GLlqQAtOF0uyB
github.com/oneclickvirt/backtrace v0.0.4-20240624090335/go.mod h1:zvsC7xY/WZqs5KL2JB967OVnuqjNbxu9bW6wXRLo5h8= github.com/oneclickvirt/backtrace v0.0.4-20240624090335/go.mod h1:zvsC7xY/WZqs5KL2JB967OVnuqjNbxu9bW6wXRLo5h8=
github.com/oneclickvirt/basics v0.0.3-20240625075226 h1:K9VriCHIYnXPZXBSn9PRQX+jBS6AIFH8tBVb/i8VGAw= github.com/oneclickvirt/basics v0.0.3-20240625075226 h1:K9VriCHIYnXPZXBSn9PRQX+jBS6AIFH8tBVb/i8VGAw=
github.com/oneclickvirt/basics v0.0.3-20240625075226/go.mod h1:dTB+/oyFQYfTYX55rFJVWatum5F9g62zjfmHCM6Vj1s= github.com/oneclickvirt/basics v0.0.3-20240625075226/go.mod h1:dTB+/oyFQYfTYX55rFJVWatum5F9g62zjfmHCM6Vj1s=
github.com/oneclickvirt/cputest v0.0.6-20240630144058 h1:bFOM4MS+uaU7slFaZR91/bJ57AFM23RWPEik+GTFS2w= github.com/oneclickvirt/basics v0.0.3-20240701085006 h1:wYimtnZuVmWxncwDevEzo4JZ/Xc2hj07vvbX3jgQLME=
github.com/oneclickvirt/cputest v0.0.6-20240630144058/go.mod h1:MmaHN9+XMntI3rLycwj8Ne31fG18IfNoa8N2utDK1CY= github.com/oneclickvirt/basics v0.0.3-20240701085006/go.mod h1:dTB+/oyFQYfTYX55rFJVWatum5F9g62zjfmHCM6Vj1s=
github.com/oneclickvirt/basics v0.0.3-20240701085439 h1:1PE7Womqy4AW2c9PlyFdHsBocZXSo02V5uJDSzQLzgs=
github.com/oneclickvirt/basics v0.0.3-20240701085439/go.mod h1:dTB+/oyFQYfTYX55rFJVWatum5F9g62zjfmHCM6Vj1s=
github.com/oneclickvirt/cputest v0.0.7-20240701020012 h1:U5cCI+6ZU3pudoAlmb1b3yB9IQNm5AnDXi1TQAZJCIA=
github.com/oneclickvirt/cputest v0.0.7-20240701020012/go.mod h1:MmaHN9+XMntI3rLycwj8Ne31fG18IfNoa8N2utDK1CY=
github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc= github.com/oneclickvirt/defaultset v0.0.2-20240624082446 h1:5Pg3mK/u/vQvSz7anu0nxzrNdELi/AcDAU1mMsmPzyc=
github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E= github.com/oneclickvirt/defaultset v0.0.2-20240624082446/go.mod h1:e9Jt4tf2sbemCtc84/XgKcHy9EZ2jkc5x2sW1NiJS+E=
github.com/oneclickvirt/disktest v0.0.3-20240629152513 h1:ZW7MBMd2HxQi1ktg/ztVI2A10JzF4ZI6I7ATZvcK9w8= github.com/oneclickvirt/disktest v0.0.3-20240629152513 h1:ZW7MBMd2HxQi1ktg/ztVI2A10JzF4ZI6I7ATZvcK9w8=
@@ -93,12 +97,12 @@ github.com/oneclickvirt/gostun v0.0.2-20240625025941 h1:h+ZL8jkjXR6QE0qEX34FjWTv
github.com/oneclickvirt/gostun v0.0.2-20240625025941/go.mod h1:f7DPEXAxbmwXSW33dbxtb0/KzqvOBWhTs2Or5xBerQA= github.com/oneclickvirt/gostun v0.0.2-20240625025941/go.mod h1:f7DPEXAxbmwXSW33dbxtb0/KzqvOBWhTs2Or5xBerQA=
github.com/oneclickvirt/memorytest v0.0.1-20240624151629 h1:2rJAB3gFGlFPocIb/WRVWYqs4nr2jGYokfDOgqFicD4= github.com/oneclickvirt/memorytest v0.0.1-20240624151629 h1:2rJAB3gFGlFPocIb/WRVWYqs4nr2jGYokfDOgqFicD4=
github.com/oneclickvirt/memorytest v0.0.1-20240624151629/go.mod h1:+YNzy+NeVg61d0kNwSyVDqHyVtKzjuRe1NvMzsDLg0I= github.com/oneclickvirt/memorytest v0.0.1-20240624151629/go.mod h1:+YNzy+NeVg61d0kNwSyVDqHyVtKzjuRe1NvMzsDLg0I=
github.com/oneclickvirt/nt3 v0.0.1-20240630131017 h1:L9PkTk8ij7J/aN6WZ4VPRc6hALfre/HyHnHj1vVNAZw= github.com/oneclickvirt/nt3 v0.0.2-20240630152642 h1:BkpR1j9JaDxMzx7iIwtsnFDxSldjYr2TUYpZE7m8z/Y=
github.com/oneclickvirt/nt3 v0.0.1-20240630131017/go.mod h1:Vb724PgpP17W09mLw5I2UZZAuYbY8WwGlKZdxRDFr0Y= github.com/oneclickvirt/nt3 v0.0.2-20240630152642/go.mod h1:UojPmtangn17TiQaDccVrZbn6sZwJOtzBgg3idp68cA=
github.com/oneclickvirt/portchecker v0.0.1-20240624155429 h1:+wapaOcFrg1iWJDhBKThDzppyIMY7hWxK7F5RBkZg4o= github.com/oneclickvirt/portchecker v0.0.1-20240624155429 h1:+wapaOcFrg1iWJDhBKThDzppyIMY7hWxK7F5RBkZg4o=
github.com/oneclickvirt/portchecker v0.0.1-20240624155429/go.mod h1:HQxSTrqM8/QFqHMTBZ7S8H9eEO5FkUXU1eb7ZX5Mk+k= github.com/oneclickvirt/portchecker v0.0.1-20240624155429/go.mod h1:HQxSTrqM8/QFqHMTBZ7S8H9eEO5FkUXU1eb7ZX5Mk+k=
github.com/oneclickvirt/security v0.0.2-20240630142358 h1:yioMtHuW9wbJ7payL8GCPnj1ScEqNoqbNHt3+4Z4VAg= github.com/oneclickvirt/security v0.0.3-20240701065755 h1:eHZDuyvzufOu2yDUIMggK2iRtMWJaFlCzG4+leQn5+0=
github.com/oneclickvirt/security v0.0.2-20240630142358/go.mod h1:cUNNOldoVQuovyc0EtAVAZlAT4y2xA1e0uA80aj1ly8= github.com/oneclickvirt/security v0.0.3-20240701065755/go.mod h1:cUNNOldoVQuovyc0EtAVAZlAT4y2xA1e0uA80aj1ly8=
github.com/oneclickvirt/speedtest v0.0.6-20240630114816 h1:gI2hqV0IwcvGqYzLhlt4w2oZvYhCL+73jftUuJYBsuI= github.com/oneclickvirt/speedtest v0.0.6-20240630114816 h1:gI2hqV0IwcvGqYzLhlt4w2oZvYhCL+73jftUuJYBsuI=
github.com/oneclickvirt/speedtest v0.0.6-20240630114816/go.mod h1:zd5ZgIGslmtQLQehEfRjyumlvgDHTpCSMchKfKXoASI= github.com/oneclickvirt/speedtest v0.0.6-20240630114816/go.mod h1:zd5ZgIGslmtQLQehEfRjyumlvgDHTpCSMchKfKXoASI=
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=

317
goecs.go
View File

@@ -3,6 +3,9 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"github.com/oneclickvirt/CommonMediaTests/commediatests"
backtraceori "github.com/oneclickvirt/backtrace/bk"
basicmodel "github.com/oneclickvirt/basics/model"
"github.com/oneclickvirt/ecs/backtrace" "github.com/oneclickvirt/ecs/backtrace"
"github.com/oneclickvirt/ecs/commediatest" "github.com/oneclickvirt/ecs/commediatest"
"github.com/oneclickvirt/ecs/cputest" "github.com/oneclickvirt/ecs/cputest"
@@ -12,18 +15,25 @@ import (
"github.com/oneclickvirt/ecs/speedtest" "github.com/oneclickvirt/ecs/speedtest"
"github.com/oneclickvirt/ecs/unlocktest" "github.com/oneclickvirt/ecs/unlocktest"
"github.com/oneclickvirt/ecs/utils" "github.com/oneclickvirt/ecs/utils"
gostunmodel "github.com/oneclickvirt/gostun/model"
"github.com/oneclickvirt/portchecker/email" "github.com/oneclickvirt/portchecker/email"
speedtestmodel "github.com/oneclickvirt/speedtest/model"
"os" "os"
"path/filepath" "os/signal"
"regexp" "regexp"
"runtime" "runtime"
"strings"
"sync" "sync"
"syscall"
"time" "time"
) )
var ( var (
ecsVersion = "2024.06.30" ecsVersion = "v0.0.21"
menuMode bool
input, choice string
showVersion bool showVersion bool
enableLogger bool
language string language string
cpuTestMethod, cpuTestThreadMode string cpuTestMethod, cpuTestThreadMode string
memoryTestMethod string memoryTestMethod string
@@ -32,76 +42,275 @@ var (
nt3CheckType, nt3Location string nt3CheckType, nt3Location string
spNum int spNum int
width = 84 width = 84
basicStatus, cpuTestStatus, memoryTestStatus, diskTestStatus bool
commTestStatus, utTestStatus, securityTestStatus, emailTestStatus bool
backtraceStatus, nt3Status, speedTestStatus bool
filePath = "goecs.txt"
enabelUpload = true
) )
func main() { func main() {
flag.BoolVar(&showVersion, "v", false, "Show version information") flag.BoolVar(&showVersion, "v", false, "Display version information")
flag.StringVar(&language, "l", "zh", "Specify language (supported: en, zh)") flag.BoolVar(&menuMode, "menu", true, "Enable/Disable menu mode, disable example: -menu=false") // true 默认启用菜单栏模式
flag.StringVar(&cpuTestMethod, "cpum", "sysbench", "Specify CPU test method (supported: sysbench, geekbench, winsat)") flag.StringVar(&language, "l", "zh", "Set language (supported: en, zh)")
flag.StringVar(&cpuTestThreadMode, "cput", "multi", "Specify CPU test thread mode (supported: single multi)") flag.BoolVar(&basicStatus, "basic", true, "Enable/Disable basic test")
flag.StringVar(&memoryTestMethod, "memorym", "dd", "Specify Memory test method (supported: sysbench, dd, winsat)") flag.BoolVar(&cpuTestStatus, "cpu", true, "Enable/Disable CPU test")
flag.StringVar(&diskTestMethod, "diskm", "fio", "Specify Disk test method (supported: fio, dd, winsat)") flag.BoolVar(&memoryTestStatus, "memory", true, "Enable/Disable memory test")
flag.StringVar(&diskTestPath, "diskp", "", "Specify Disk test path, example: -diskp /root") flag.BoolVar(&diskTestStatus, "disk", true, "Enable/Disable disk test")
flag.BoolVar(&diskMultiCheck, "diskmc", false, "Enable multiple disk checks, example: -diskmc=false") flag.BoolVar(&commTestStatus, "comm", true, "Enable/Disable common media test")
flag.StringVar(&nt3Location, "nt3loc", "GZ", "指定三网回程路由检测的地址,支持 GZ, SH, BJ, CD 对应 广州,上海,北京,成都") flag.BoolVar(&utTestStatus, "ut", true, "Enable/Disable unlock media test")
flag.StringVar(&nt3CheckType, "nt3t", "ipv4", "指定三网回程路由检测的类型,支持 both, ipv4, ipv6") flag.BoolVar(&securityTestStatus, "security", true, "Enable/Disable security test")
flag.IntVar(&spNum, "spnum", 2, "Specify speedtest each operator servers num") flag.BoolVar(&emailTestStatus, "email", true, "Enable/Disable email port test")
flag.BoolVar(&backtraceStatus, "backtrace", true, "Enable/Disable backtrace test (in 'en' language or on `windows` it always false)")
flag.BoolVar(&nt3Status, "nt3", true, "Enable/Disable NT3 test (in 'en' language or on `windows` it always false)")
flag.BoolVar(&speedTestStatus, "speed", true, "Enable/Disable speed test")
flag.StringVar(&cpuTestMethod, "cpum", "sysbench", "Set CPU test method (supported: sysbench, geekbench, winsat)")
flag.StringVar(&cpuTestThreadMode, "cput", "multi", "Set CPU test thread mode (supported: single, multi)")
flag.StringVar(&memoryTestMethod, "memorym", "dd", "Set memory test method (supported: sysbench, dd, winsat)")
flag.StringVar(&diskTestMethod, "diskm", "fio", "Set disk test method (supported: fio, dd, winsat)")
flag.StringVar(&diskTestPath, "diskp", "", "Set disk test path, e.g., -diskp /root")
flag.BoolVar(&diskMultiCheck, "diskmc", false, "Enable/Disable multiple disk checks, e.g., -diskmc=false")
flag.StringVar(&nt3Location, "nt3loc", "GZ", "Specify NT3 test location (supported: GZ, SH, BJ, CD for Guangzhou, Shanghai, Beijing, Chengdu)")
flag.StringVar(&nt3CheckType, "nt3t", "ipv4", "Set NT3 test type (supported: both, ipv4, ipv6)")
flag.IntVar(&spNum, "spnum", 2, "Set the number of servers per operator for speed test")
flag.BoolVar(&enableLogger, "log", false, "Enable/Disable logging in the current path")
flag.Parse() flag.Parse()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
if showVersion { if showVersion {
fmt.Println(ecsVersion) fmt.Println(ecsVersion)
return return
} }
if enableLogger {
basicmodel.EnableLoger = true
speedtestmodel.EnableLoger = true
gostunmodel.EnableLoger = true
commediatests.EnableLoger = true
backtraceori.EnableLoger = true
}
if menuMode {
basicStatus, cpuTestStatus, memoryTestStatus, diskTestStatus = false, false, false, false
commTestStatus, utTestStatus, securityTestStatus, emailTestStatus = false, false, false, false
backtraceStatus, nt3Status, speedTestStatus = false, false, false
switch language {
case "zh":
fmt.Println("1. 融合怪完全体")
fmt.Println("2. 极简版(系统信息+CPU+内存+磁盘+测速节点5个)")
fmt.Println("3. 精简版(系统信息+CPU+内存+磁盘+御三家+常用流媒体+回程+路由+测速节点5个)")
fmt.Println("4. 精简网络版(系统信息+CPU+内存+磁盘+回程+路由+测速节点5个)")
fmt.Println("5. 精简解锁版(系统信息+CPU+内存+磁盘IO+御三家+常用流媒体+测速节点5个)")
fmt.Println("6. 网络单项(IP质量检测+三网回程+三网路由与延迟+测速节点11个)")
fmt.Println("7. 解锁单项(御三家解锁+常用流媒体解锁)")
fmt.Println("8. 硬件单项(基础系统信息+CPU+内存+dd磁盘测试+fio磁盘测试)")
fmt.Println("9. IP质量检测(15个数据库的IP检测+邮件端口检测)")
fmt.Println("10. 三网回程线路+广州三网路由+全国三网延迟")
case "en":
fmt.Println("1. VPS Fusion Monster Test Comprehensive Test Suite")
fmt.Println("2. Minimal Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)")
fmt.Println("3. Standard Test Suite (System Info + CPU + Memory + Disk + Basic Unlock Tests + Common Streaming Services + 5 Speed Test Nodes)")
fmt.Println("4. Network-Focused Test Suite (System Info + CPU + Memory + Disk + 5 Speed Test Nodes)")
fmt.Println("5. Unlock-Focused Test Suite (System Info + CPU + Memory + Disk IO + Basic Unlock Tests + Common Streaming Services + 5 Speed Test Nodes)")
fmt.Println("6. Network-Only Test (IP Quality Test + 5 Speed Test Nodes)")
fmt.Println("7. Unlock-Only Test (Basic Unlock Tests + Common Streaming Services Unlock)")
fmt.Println("8. Hardware-Only Test (Basic System Info + CPU + Memory + dd Disk Test + fio Disk Test)")
fmt.Println("9. IP Quality Test (IP Test with 15 Databases + Email Port Test)")
}
Loop:
for {
fmt.Print("请输入选项 / Please enter your choice: ")
fmt.Scanln(&input)
input = strings.TrimSpace(input)
input = strings.TrimRight(input, "\n")
re := regexp.MustCompile(`^\d+$`) // 正则表达式匹配纯数字
if re.MatchString(input) {
choice = input
switch choice {
case "1":
basicStatus = true
cpuTestStatus = true
memoryTestStatus = true
diskTestStatus = true
commTestStatus = true
utTestStatus = true
securityTestStatus = true
emailTestStatus = true
backtraceStatus = true
nt3Status = true
speedTestStatus = true
break Loop
case "2":
basicStatus = true
cpuTestStatus = true
memoryTestStatus = true
diskTestStatus = true
speedTestStatus = true
break Loop
case "3":
basicStatus = true
cpuTestStatus = true
memoryTestStatus = true
diskTestStatus = true
commTestStatus = true
utTestStatus = true
securityTestStatus = true
backtraceStatus = true
nt3Status = true
speedTestStatus = true
break Loop
case "4":
basicStatus = true
cpuTestStatus = true
memoryTestStatus = true
diskTestStatus = true
backtraceStatus = true
nt3Status = true
speedTestStatus = true
break Loop
case "5":
basicStatus = true
cpuTestStatus = true
memoryTestStatus = true
diskTestStatus = true
securityTestStatus = true
speedTestStatus = true
break Loop
case "6":
speedTestStatus = true
backtraceStatus = true
nt3Status = true
break Loop
case "7":
securityTestStatus = true
commTestStatus = true
break Loop
case "8":
basicStatus = true
cpuTestStatus = true
memoryTestStatus = true
diskTestStatus = true
break Loop
case "9":
emailTestStatus = true
break Loop
case "10":
backtraceStatus = true
nt3Status = true
speedTestStatus = true
break Loop
default:
if language == "zh" {
fmt.Println("无效的选项")
} else {
fmt.Println("Invalid choice")
}
}
} else {
if language == "zh" {
fmt.Println("输入错误,请输入一个纯数字")
} else {
fmt.Println("Invalid input, please enter a number")
}
}
}
}
if language == "en" {
backtraceStatus = false
nt3Status = false
}
startTime := time.Now() startTime := time.Now()
var ( var (
wg sync.WaitGroup wg1, wg2 sync.WaitGroup
basicInfo, securityInfo, emailInfo, mediaInfo string basicInfo, securityInfo, emailInfo, mediaInfo string
output, tempOutput string output, tempOutput string
) )
// 启动一个goroutine来等待信号
go func() {
// 等待信号
<-sig
utils.ProcessAndUpload(output, filePath, enabelUpload)
os.Exit(1) // 使用非零状态码退出,表示意外退出
}()
output = utils.PrintAndCapture(func() { output = utils.PrintAndCapture(func() {
switch language { switch language {
case "zh": case "zh":
utils.PrintHead(language, width, ecsVersion) utils.PrintHead(language, width, ecsVersion)
if basicStatus || securityTestStatus {
if basicStatus {
utils.PrintCenteredTitle("基础信息", width) utils.PrintCenteredTitle("基础信息", width)
basicInfo, securityInfo, nt3CheckType = utils.SecurityCheck(language, nt3CheckType) }
basicInfo, securityInfo, nt3CheckType = utils.SecurityCheck(language, nt3CheckType, securityTestStatus)
if basicStatus {
fmt.Printf(basicInfo) fmt.Printf(basicInfo)
}
}
if cpuTestStatus {
utils.PrintCenteredTitle(fmt.Sprintf("CPU测试-通过%s测试", cpuTestMethod), width) utils.PrintCenteredTitle(fmt.Sprintf("CPU测试-通过%s测试", cpuTestMethod), width)
cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode) cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode)
}
if memoryTestStatus {
utils.PrintCenteredTitle(fmt.Sprintf("内存测试-通过%s测试", cpuTestMethod), width) utils.PrintCenteredTitle(fmt.Sprintf("内存测试-通过%s测试", cpuTestMethod), width)
memorytest.MemoryTest(language, memoryTestMethod) memorytest.MemoryTest(language, memoryTestMethod)
}
if diskTestStatus {
utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", diskTestMethod), width) utils.PrintCenteredTitle(fmt.Sprintf("硬盘测试-通过%s测试", diskTestMethod), width)
disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck) disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck)
utils.PrintCenteredTitle("御三家流媒体解锁", width) }
wg.Add(2) if emailTestStatus {
wg2.Add(1)
go func() { go func() {
defer wg.Done() defer wg2.Done()
emailInfo = email.EmailCheck() emailInfo = email.EmailCheck()
}() }()
}
if utTestStatus {
wg1.Add(1)
go func() { go func() {
defer wg.Done() defer wg1.Done()
mediaInfo = unlocktest.MediaTest(language) mediaInfo = unlocktest.MediaTest(language)
}() }()
}
if commTestStatus {
utils.PrintCenteredTitle("御三家流媒体解锁", width)
commediatest.ComMediaTest(language) commediatest.ComMediaTest(language)
}
if utTestStatus {
utils.PrintCenteredTitle("跨国流媒体解锁", width) utils.PrintCenteredTitle("跨国流媒体解锁", width)
wg.Wait() // 后台任务含流媒体测试和邮件测试 wg1.Wait()
fmt.Printf(mediaInfo) fmt.Printf(mediaInfo)
}
if securityTestStatus {
utils.PrintCenteredTitle("IP质量检测", width) utils.PrintCenteredTitle("IP质量检测", width)
fmt.Printf(securityInfo) fmt.Printf(securityInfo)
}
if emailTestStatus {
utils.PrintCenteredTitle("邮件端口检测", width) utils.PrintCenteredTitle("邮件端口检测", width)
wg2.Wait()
fmt.Println(emailInfo) fmt.Println(emailInfo)
}
if runtime.GOOS != "windows" { if runtime.GOOS != "windows" {
if backtraceStatus {
utils.PrintCenteredTitle("三网回程", width) utils.PrintCenteredTitle("三网回程", width)
backtrace.BackTrace() backtrace.BackTrace()
}
// nexttrace 在win上不支持检测报错 bind: An invalid argument was supplied. // nexttrace 在win上不支持检测报错 bind: An invalid argument was supplied.
if nt3Status {
utils.PrintCenteredTitle("路由检测", width) utils.PrintCenteredTitle("路由检测", width)
ntrace.TraceRoute3(language, nt3Location, nt3CheckType) ntrace.TraceRoute3(language, nt3Location, nt3CheckType)
} }
}
if speedTestStatus {
utils.PrintCenteredTitle("就近节点测速", width) utils.PrintCenteredTitle("就近节点测速", width)
speedtest.ShowHead(language) speedtest.ShowHead(language)
if (menuMode && choice == "1") || !menuMode {
speedtest.NearbySP() speedtest.NearbySP()
speedtest.CustomSP("net", "global", 4) speedtest.CustomSP("net", "global", 2)
speedtest.CustomSP("net", "cu", spNum) speedtest.CustomSP("net", "cu", spNum)
speedtest.CustomSP("net", "ct", spNum) speedtest.CustomSP("net", "ct", spNum)
speedtest.CustomSP("net", "cmcc", spNum) speedtest.CustomSP("net", "cmcc", spNum)
} else if menuMode && choice == "2" || choice == "3" || choice == "4" || choice == "5" {
speedtest.CustomSP("net", "global", 4)
}
}
utils.PrintCenteredTitle("", width) utils.PrintCenteredTitle("", width)
endTime := time.Now() endTime := time.Now()
duration := endTime.Sub(startTime) duration := endTime.Sub(startTime)
@@ -113,34 +322,57 @@ func main() {
utils.PrintCenteredTitle("", width) utils.PrintCenteredTitle("", width)
case "en": case "en":
utils.PrintHead(language, width, ecsVersion) utils.PrintHead(language, width, ecsVersion)
if basicStatus || securityTestStatus {
if basicStatus {
utils.PrintCenteredTitle("Basic Information", width) utils.PrintCenteredTitle("Basic Information", width)
basicInfo, securityInfo, nt3CheckType = utils.SecurityCheck(language, nt3CheckType) }
basicInfo, securityInfo, nt3CheckType = utils.SecurityCheck(language, nt3CheckType, securityTestStatus)
if basicStatus {
fmt.Printf(basicInfo) fmt.Printf(basicInfo)
}
}
if cpuTestStatus {
utils.PrintCenteredTitle(fmt.Sprintf("CPU Test - %s Method", cpuTestMethod), width) utils.PrintCenteredTitle(fmt.Sprintf("CPU Test - %s Method", cpuTestMethod), width)
cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode) cputest.CpuTest(language, cpuTestMethod, cpuTestThreadMode)
}
if memoryTestStatus {
utils.PrintCenteredTitle(fmt.Sprintf("Memory Test - %s Method", memoryTestMethod), width) utils.PrintCenteredTitle(fmt.Sprintf("Memory Test - %s Method", memoryTestMethod), width)
utils.PrintCenteredTitle(fmt.Sprintf("Disk Test - %s Method", diskTestMethod), width) memorytest.MemoryTest(language, memoryTestMethod)
}
if diskTestStatus {
utils.PrintCenteredTitle(fmt.Sprintf("Disk Test - %s Method", diskTestMethod), width) utils.PrintCenteredTitle(fmt.Sprintf("Disk Test - %s Method", diskTestMethod), width)
disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck) disktest.DiskTest(language, diskTestMethod, diskTestPath, diskMultiCheck)
wg.Add(1) }
if emailTestStatus {
wg1.Add(1)
go func() { go func() {
defer wg.Done() defer wg1.Done()
emailInfo = email.EmailCheck() emailInfo = email.EmailCheck()
}() }()
}
if commTestStatus {
utils.PrintCenteredTitle("The Three Families Streaming Media Unlock", width) utils.PrintCenteredTitle("The Three Families Streaming Media Unlock", width)
commediatest.ComMediaTest(language) commediatest.ComMediaTest(language)
}
if utTestStatus {
utils.PrintCenteredTitle("Cross-Border Streaming Media Unlock", width) utils.PrintCenteredTitle("Cross-Border Streaming Media Unlock", width)
unlocktest.MediaTest(language) unlocktest.MediaTest(language)
}
if securityTestStatus {
utils.PrintCenteredTitle("IP Quality Check", width) utils.PrintCenteredTitle("IP Quality Check", width)
fmt.Printf(securityInfo) fmt.Printf(securityInfo)
}
if emailTestStatus {
utils.PrintCenteredTitle("Email Port Check", width) utils.PrintCenteredTitle("Email Port Check", width)
wg.Wait() wg1.Wait()
fmt.Println(emailInfo) fmt.Println(emailInfo)
//utils.PrintCenteredTitle("Return Path Routing", width) }
if speedTestStatus {
utils.PrintCenteredTitle("Nearby Node Speed Test", width) utils.PrintCenteredTitle("Nearby Node Speed Test", width)
speedtest.ShowHead(language) speedtest.ShowHead(language)
speedtest.NearbySP() speedtest.NearbySP()
speedtest.CustomSP("net", "global", -1) speedtest.CustomSP("net", "global", -1)
}
utils.PrintCenteredTitle("", width) utils.PrintCenteredTitle("", width)
endTime := time.Now() endTime := time.Now()
duration := endTime.Sub(startTime) duration := endTime.Sub(startTime)
@@ -154,34 +386,5 @@ func main() {
fmt.Println("Unsupported language") fmt.Println("Unsupported language")
} }
}, tempOutput, output) }, tempOutput, output)
// 创建文件 utils.ProcessAndUpload(output, filePath, enabelUpload)
filePath := "goecs.txt"
file, err := os.Create(filePath)
if err != nil {
fmt.Println("Can not make file:", err)
return
}
defer file.Close()
// 将 output 写入文件
// 匹配 ANSI 转义序列
ansiRegex := regexp.MustCompile("\x1B\\[[0-9;]+[a-zA-Z]")
// 移除 ANSI 转义序列
cleanedOutput := ansiRegex.ReplaceAllString(output, "")
_, err = file.WriteString(cleanedOutput)
if err != nil {
fmt.Println("Can not write file:", err)
return
}
// 获取文件的绝对路径
absPath, err := filepath.Abs(filePath)
if err != nil {
fmt.Println("Get file absPath failed:", err)
return
}
shorturl, err := utils.UploadText(absPath)
if err != nil {
fmt.Println("Upload failed, can not generate short URL.")
fmt.Println(err.Error())
}
fmt.Println("Upload successful, short URL:", shorturl)
} }

View File

@@ -59,17 +59,16 @@ goecs_check() {
ECS_VERSION=$(curl -m 6 -sSL "https://githubapi.spiritlhl.top/repos/oneclickvirt/ecs/releases/latest" | awk -F \" '/tag_name/{gsub(/^v/,"",$4); print $4}') ECS_VERSION=$(curl -m 6 -sSL "https://githubapi.spiritlhl.top/repos/oneclickvirt/ecs/releases/latest" | awk -F \" '/tag_name/{gsub(/^v/,"",$4); print $4}')
fi fi
# 检测原始goecs命令是否存在若存在则升级不存在则安装 # 检测原始goecs命令是否存在若存在则升级不存在则安装
version_output=$(goecs -v || ./goecs -v) version_output=$(goecs -v command 2>/dev/null || ./goecs -v command 2>/dev/null)
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
extracted_version=$(echo "$version_output" | grep -oP '^v\d+(\.\d+)+') extracted_version=$(echo "${version_output//v/}")
if [ -n "$extracted_version" ]; then if [ -n "$extracted_version" ]; then
current_version=$(echo "$extracted_version" | cut -c 2-)
ecs_version=$ECS_VERSION ecs_version=$ECS_VERSION
if [[ "$(echo -e "$current_version\n$ecs_version" | sort -V | tail -n 1)" == "$current_version" ]]; then if [[ "$(echo -e "$extracted_version\n$ecs_version" | sort -V | tail -n 1)" == "$extracted_version" ]]; then
echo "goecs version ($current_version) is latest, no need to upgrade." echo "goecs version ($extracted_version) is latest, no need to upgrade."
return return
else else
echo "goecs version ($current_version) < $ecs_version, need to upgrade, 5 seconds later will start to upgrade" echo "goecs version ($extracted_version) < $ecs_version, need to upgrade, 5 seconds later will start to upgrade"
rm -rf /usr/bin/goecs rm -rf /usr/bin/goecs
rm -rf goecs rm -rf goecs
fi fi
@@ -163,7 +162,7 @@ InstallSysbench() {
arch) pacman -S --needed --noconfirm sysbench && pacman -S --needed --noconfirm libaio && ldconfig ;; arch) pacman -S --needed --noconfirm sysbench && pacman -S --needed --noconfirm libaio && ldconfig ;;
freebsd) pkg install -y sysbench ;; freebsd) pkg install -y sysbench ;;
alpinelinux) echo -e "${Msg_Warning}Sysbench Module not found, installing ..." && echo -e "${Msg_Warning}SysBench Current not support Alpine Linux, Skipping..." && Var_Skip_SysBench="1" ;; alpinelinux) echo -e "${Msg_Warning}Sysbench Module not found, installing ..." && echo -e "${Msg_Warning}SysBench Current not support Alpine Linux, Skipping..." && Var_Skip_SysBench="1" ;;
*) echo "Error: Unknown OS release: $os_release" && exit 1 ;; *) echo "Error: Unknown OS release: $os_release" ;;
esac esac
} }
@@ -230,7 +229,7 @@ prepare_compile_env() {
env_check() { env_check() {
REGEX=("debian|astra" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "arch" "freebsd" "alpine" "openbsd") REGEX=("debian|astra" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "arch" "freebsd" "alpine" "openbsd")
RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Arch" "FreeBSD" "Alpine" "OpenBSD") RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Arch" "FreeBSD" "Alpine" "OpenBSD")
PACKAGE_UPDATE=("! apt-get update && apt-get --fix-broken install -y && apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "pacman -Sy" "pkg update" "apk update" "pkg_add -u") PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "pacman -Sy" "pkg update" "apk update" "pkg_add -u")
PACKAGE_INSTALL=("apt-get -y install" "apt-get -y install" "yum -y install" "yum -y install" "yum -y install" "pacman -Sy --noconfirm --needed" "pkg install -y" "apk add") PACKAGE_INSTALL=("apt-get -y install" "apt-get -y install" "yum -y install" "yum -y install" "yum -y install" "pacman -Sy --noconfirm --needed" "pkg install -y" "apk add")
PACKAGE_REMOVE=("apt-get -y remove" "apt-get -y remove" "yum -y remove" "yum -y remove" "yum -y remove" "pacman -Rsc --noconfirm" "pkg delete" "apk del") PACKAGE_REMOVE=("apt-get -y remove" "apt-get -y remove" "yum -y remove" "yum -y remove" "yum -y remove" "pacman -Rsc --noconfirm" "pkg delete" "apk del")
PACKAGE_UNINSTALL=("apt-get -y autoremove" "apt-get -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove" "" "pkg autoremove" "apk autoremove") PACKAGE_UNINSTALL=("apt-get -y autoremove" "apt-get -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove" "" "pkg autoremove" "apk autoremove")
@@ -245,6 +244,16 @@ env_check() {
done done
cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/") cdn_urls=("https://cdn0.spiritlhl.top/" "http://cdn3.spiritlhl.net/" "http://cdn1.spiritlhl.net/" "http://cdn2.spiritlhl.net/")
check_cdn_file check_cdn_file
_green "Update system manager."
$PACKAGE_UPDATE command 2>/dev/null
if ! command -v tar >/dev/null 2>&1; then
_green "Installing tar"
$PACKAGE_INSTALL tar
fi
if ! command -v unzip >/dev/null 2>&1; then
_green "Installing unzip"
$PACKAGE_INSTALL unzip
fi
if ! command -v dd >/dev/null 2>&1; then if ! command -v dd >/dev/null 2>&1; then
_green "Installing dd" _green "Installing dd"
$PACKAGE_INSTALL dd $PACKAGE_INSTALL dd
@@ -291,16 +300,31 @@ env_check() {
echo "rm -rf /usr/bin/speedtest-go" echo "rm -rf /usr/bin/speedtest-go"
_blue "to uninstall speedtest and speedtest-go" _blue "to uninstall speedtest and speedtest-go"
fi fi
_green "The environment is ready."
}
delete_goecs() {
rm -rf /root/goecs
rm -rf /usr/bin/goecs
} }
show_help() { show_help() {
cat <<"EOF" cat <<"EOF"
Available commands: Available commands:
env Check and Install package: dd fio sysbench geekbench5 speedtest ./goecs.sh env Check and Install package:
install Install goecs command tar (Almost all unix-like systems have it.)
upgrade Upgrade goecs command unzip (Almost all unix-like systems have it.)
help Show this message dd (Almost all unix-like systems have it.)
fio (Almost all unix-like systems can be installed through the system's package manager.)
sysbench (Almost all unix-like systems can be installed through the system's package manager.)
geekbench (geekbench5)(Only support IPV4 environment, and memory greater than 1GB network detection, only support amd64 and arm64 architecture.)
speedtest (Use the officially provided binaries for more accurate test results.)
In fact, sysbench/geekbench is the only one of the above dependencies that must be installed, without which the CPU score cannot be tested.
./goecs.sh install Install goecs command
./goecs.sh upgrade Upgrade goecs command
./goecs.sh delete Uninstall goecs command
./goecs.sh help Show this message
EOF EOF
} }
@@ -315,6 +339,9 @@ case "$1" in
"install" | "upgrade") "install" | "upgrade")
goecs_check goecs_check
;; ;;
"delete")
delete_goecs
;;
*) *)
echo "No command found." echo "No command found."
echo echo

View File

@@ -9,8 +9,11 @@ import (
"github.com/oneclickvirt/security/network" "github.com/oneclickvirt/security/network"
"io" "io"
"os" "os"
"path/filepath"
"regexp"
"strings" "strings"
"sync" "sync"
"time"
"unicode/utf8" "unicode/utf8"
) )
@@ -27,13 +30,13 @@ func PrintCenteredTitle(title string, width int) {
// PrintHead 根据语言打印头部信息 // PrintHead 根据语言打印头部信息
func PrintHead(language string, width int, ecsVersion string) { func PrintHead(language string, width int, ecsVersion string) {
if language == "zh" { if language == "zh" {
PrintCenteredTitle("融合怪测试", width) PrintCenteredTitle("VPS融合怪测试", width)
fmt.Printf("版本:%s\n", ecsVersion) fmt.Printf("版本:%s\n", ecsVersion)
fmt.Println("测评频道: https://t.me/vps_reviews\n" + fmt.Println("测评频道: https://t.me/vps_reviews\n" +
"Go项目地址https://github.com/oneclickvirt/ecs\n" + "Go项目地址https://github.com/oneclickvirt/ecs\n" +
"Shell项目地址https://github.com/spiritLHLS/ecs") "Shell项目地址https://github.com/spiritLHLS/ecs")
} else { } else {
PrintCenteredTitle("Fusion Monster Test", width) PrintCenteredTitle("VPS Fusion Monster Test", width)
fmt.Printf("Version: %s\n", ecsVersion) fmt.Printf("Version: %s\n", ecsVersion)
fmt.Println("Review Channel: https://t.me/vps_reviews\n" + fmt.Println("Review Channel: https://t.me/vps_reviews\n" +
"Go Project URL: https://github.com/oneclickvirt/ecs\n" + "Go Project URL: https://github.com/oneclickvirt/ecs\n" +
@@ -42,14 +45,14 @@ func PrintHead(language string, width int, ecsVersion string) {
} }
// SecurityCheck 执行安全检查 // SecurityCheck 执行安全检查
func SecurityCheck(language, nt3CheckType string) (string, string, string) { func SecurityCheck(language, nt3CheckType string, securtyCheckStatus bool) (string, string, string) {
var wgt sync.WaitGroup var wgt sync.WaitGroup
var ipInfo, securityInfo, systemInfo string var ipInfo, securityInfo, systemInfo string
var err error var err error
wgt.Add(2) wgt.Add(2)
go func() { go func() {
defer wgt.Done() defer wgt.Done()
ipInfo, securityInfo, err = network.NetworkCheck("both", true, language) ipInfo, securityInfo, err = network.NetworkCheck("both", securtyCheckStatus, language)
if err != nil { if err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
@@ -88,7 +91,7 @@ func SecurityCheck(language, nt3CheckType string) (string, string, string) {
return basicInfo, securityInfo, nt3CheckType return basicInfo, securityInfo, nt3CheckType
} }
// CaptureOutput 捕获函数输出和错误输出并返回字符串 // CaptureOutput 捕获函数输出和错误输出,实时输出,并返回字符串
func CaptureOutput(f func()) string { func CaptureOutput(f func()) string {
// 保存旧的 stdout 和 stderr // 保存旧的 stdout 和 stderr
oldStdout := os.Stdout oldStdout := os.Stdout
@@ -139,7 +142,8 @@ func CaptureOutput(f func()) string {
<-done <-done
<-done <-done
// 返回捕获的输出字符串 // 返回捕获的输出字符串
return stdoutBuf.String() + stderrBuf.String() // stderrBuf.String()
return stdoutBuf.String()
} }
// PrintAndCapture 捕获函数输出的同时打印内容 // PrintAndCapture 捕获函数输出的同时打印内容
@@ -154,6 +158,11 @@ func UploadText(absPath string) (string, error) {
url := "https://paste.spiritlhl.net/api/upload" url := "https://paste.spiritlhl.net/api/upload"
token := network.SecurityUploadToken token := network.SecurityUploadToken
client := req.DefaultClient() client := req.DefaultClient()
client.SetTimeout(6 * time.Second)
client.R().
SetRetryCount(2).
SetRetryBackoffInterval(1*time.Second, 5*time.Second).
SetRetryFixedInterval(2 * time.Second)
file, _ := os.Open(absPath) file, _ := os.Open(absPath)
resp, err := client.R(). resp, err := client.R().
SetHeader("Authorization", token). SetHeader("Authorization", token).
@@ -173,3 +182,51 @@ func UploadText(absPath string) (string, error) {
return "", fmt.Errorf("upload failed with status code: %d", resp.StatusCode) return "", fmt.Errorf("upload failed with status code: %d", resp.StatusCode)
} }
} }
// ProcessAndUpload 创建结果文件并上传文件
func ProcessAndUpload(output string, filePath string, enableUplaod bool) {
// 检查文件是否存在
if _, err := os.Stat(filePath); err == nil {
// 文件存在,删除文件
err = os.Remove(filePath)
if err != nil {
fmt.Println("Cannot delete file:", err)
return
}
}
// 创建文件
file, err := os.Create(filePath)
if err != nil {
fmt.Println("Cannot create file:", err)
return
}
defer file.Close()
// 匹配 ANSI 转义序列
ansiRegex := regexp.MustCompile("\x1B\\[[0-9;]+[a-zA-Z]")
// 移除 ANSI 转义序列
cleanedOutput := ansiRegex.ReplaceAllString(output, "")
// 写入文件
_, err = file.WriteString(cleanedOutput)
if err != nil {
fmt.Println("Cannot write to file:", err)
return
} else {
fmt.Println("Write test result in ", filePath)
}
if enableUplaod {
// 获取文件的绝对路径
absPath, err2 := filepath.Abs(filePath)
if err2 != nil {
fmt.Println("Failed to get absolute file path:", err2)
return
}
// 上传文件并生成短链接
shorturl, err3 := UploadText(absPath)
if err3 != nil {
fmt.Println("Upload failed, cannot generate short URL.")
fmt.Println(err3.Error())
return
}
fmt.Println("Upload successful, short URL:", shorturl)
}
}

View File

@@ -24,6 +24,7 @@ REM 提示用户输入版本号
set /p version="Enter the version number (e.g., v1.0.0): " set /p version="Enter the version number (e.g., v1.0.0): "
REM 创建并推送标签 REM 创建并推送标签
:push_tag
git tag %version% git tag %version%
git push origin %version% git push origin %version%
if errorlevel 1 ( if errorlevel 1 (