Files
2026-07-27 00:00:27 +08:00

198 lines
4.0 KiB
Go

//go:build ignore
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
type Platform struct {
OS string
Arch string
Name string
Ext string
}
var platforms = []Platform{
{"windows", "amd64", "Windows x86-64", ".exe"},
{"linux", "amd64", "Linux x86-64", ""},
{"linux", "arm64", "Linux ARM64", ""},
{"linux", "arm", "Linux ARMv7l", ""},
}
const (
Version = "2.0.0"
BuildTime = "2026-07-26"
Binary = "frps-console"
)
func main() {
if len(os.Args) > 1 {
target := os.Args[1]
switch target {
case "all":
buildAll()
return
case "clean":
clean()
return
case "list":
listPlatforms()
return
}
for _, p := range platforms {
if target == p.OS+"/"+p.Arch {
build(p, false)
return
}
}
fmt.Println("❌ 不支持的平台:", target)
fmt.Println(" 可用: windows/amd64, linux/amd64, linux/arm64, linux/arm")
fmt.Println(" 或: all, list, clean")
return
}
interactiveMenu()
}
func listPlatforms() {
fmt.Println("可用平台:")
for i, p := range platforms {
fmt.Printf(" %d. %s (%s/%s)\n", i+1, p.Name, p.OS, p.Arch)
}
}
func interactiveMenu() {
fmt.Println("========================================")
fmt.Println(" frps-console 多平台构建工具 v" + Version)
fmt.Println("========================================")
fmt.Println()
for i, p := range platforms {
fmt.Printf(" %d. %s (%s/%s)\n", i+1, p.Name, p.OS, p.Arch)
}
fmt.Println(" a. 全部构建")
fmt.Println(" c. 清理构建产物")
fmt.Println(" q. 退出")
fmt.Println()
reader := bufio.NewReader(os.Stdin)
fmt.Print("请选择: ")
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(strings.ToLower(input))
switch input {
case "q":
fmt.Println("已退出")
return
case "c":
clean()
return
case "a":
buildAll()
return
default:
var idx int
if n, err := fmt.Sscanf(input, "%d", &idx); n == 1 && err == nil && idx >= 1 && idx <= len(platforms) {
build(platforms[idx-1], false)
return
}
fmt.Println("❌ 无效选择")
interactiveMenu()
}
}
func buildAll() {
for _, p := range platforms {
build(p, true)
}
fmt.Println("\n✅ 全部构建完成!产物位于 build/ 目录")
}
func build(p Platform, silent bool) {
if !silent {
fmt.Printf("🔨 构建 %s (%s/%s)...\n", p.Name, p.OS, p.Arch)
}
outDir := "./build"
if err := os.MkdirAll(outDir, 0755); err != nil {
fmt.Printf("❌ 创建目录失败: %v\n", err)
return
}
outName := Binary + "-" + p.OS + "-" + p.Arch
if p.Arch == "arm" {
outName += "v7"
}
outName += p.Ext
outPath := filepath.Join(outDir, outName)
cmd := exec.Command("go", "build",
"-ldflags=-s -w -X main.version="+Version,
"-o", outPath,
".",
)
cmd.Env = append(os.Environ(),
"GOOS="+p.OS,
"GOARCH="+p.Arch,
"CGO_ENABLED=0",
)
if p.Arch == "arm" {
cmd.Env = append(cmd.Env, "GOARM=7")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
fmt.Printf("❌ 构建失败: %v\n", err)
return
}
if !silent {
fmt.Printf("✅ 构建完成: %s\n", outPath)
if info, err := os.Stat(outPath); err == nil {
size := float64(info.Size()) / 1024 / 1024
fmt.Printf(" 📦 %.2f MB\n", size)
}
}
if !silent {
packageBinary(outPath, p)
}
}
func packageBinary(binPath string, p Platform) {
base := strings.TrimSuffix(filepath.Base(binPath), p.Ext)
dir := filepath.Dir(binPath)
if p.Ext == ".exe" {
zipName := filepath.Join(dir, base+".zip")
cmd := exec.Command("zip", "-j", zipName, binPath)
if err := cmd.Run(); err == nil {
fmt.Printf(" 📦 已打包: %s\n", zipName)
}
} else {
tarName := filepath.Join(dir, base+".tar.gz")
cmd := exec.Command("tar", "-czf", tarName, "-C", dir, filepath.Base(binPath))
if err := cmd.Run(); err == nil {
fmt.Printf(" 📦 已打包: %s\n", tarName)
}
}
}
func clean() {
fmt.Println("🧹 清理构建产物...")
if err := os.RemoveAll("./build"); err != nil {
fmt.Printf("❌ 清理失败: %v\n", err)
return
}
fmt.Println("✅ 清理完成")
}