Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
565 lines
13 KiB
Go
565 lines
13 KiB
Go
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// CommandType 定义命令类型
|
|
type CommandType int
|
|
|
|
const (
|
|
SERVER CommandType = iota
|
|
CONFIG
|
|
TEST
|
|
VERSION
|
|
HELP
|
|
UNKNOWN
|
|
)
|
|
|
|
// Command 表示CLI命令的结构
|
|
// 该结构体包含命令的所有参数和配置
|
|
type Command struct {
|
|
// 基本命令信息
|
|
Type CommandType `json:"type"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Aliases []string `json:"aliases"`
|
|
Usage string `json:"usage"`
|
|
|
|
// 位置参数
|
|
Args []string `json:"args"`
|
|
ArgsCount int `json:"args_count"`
|
|
|
|
// 标志参数
|
|
Flags map[string]string `json:"flags"`
|
|
Booleans map[string]bool `json:"booleans"`
|
|
Integers map[string]int64 `json:"integers"`
|
|
Floats map[string]float64 `json:"floats"`
|
|
|
|
// 选项参数
|
|
Options map[string][]string `json:"options"`
|
|
|
|
// 环境变量
|
|
EnvVars map[string]string `json:"env_vars"`
|
|
|
|
// 配置文件
|
|
ConfigFile string `json:"config_file"`
|
|
Config interface{} `json:"config"`
|
|
|
|
// 执行信息
|
|
Executed bool `json:"executed"`
|
|
ExecutedAt time.Time `json:"executed_at"`
|
|
Duration time.Duration `json:"duration"`
|
|
ExitCode int `json:"exit_code"`
|
|
Output string `json:"output"`
|
|
Error error `json:"error"`
|
|
|
|
// 上下文信息
|
|
WorkingDir string `json:"working_dir"`
|
|
UserID string `json:"user_id,omitempty"`
|
|
SessionID string `json:"session_id,omitempty"`
|
|
|
|
// 调试信息
|
|
Debug bool `json:"debug"`
|
|
Verbose bool `json:"verbose"`
|
|
Quiet bool `json:"quiet"`
|
|
DryRun bool `json:"dry_run"`
|
|
|
|
// 自定义数据
|
|
Custom map[string]interface{} `json:"custom,omitempty"`
|
|
}
|
|
|
|
// NewCommand 创建新的命令实例
|
|
// 返回包含基本信息的Command结构体
|
|
func NewCommand(cmdType CommandType, name, description string) *Command {
|
|
return &Command{
|
|
Type: cmdType,
|
|
Name: name,
|
|
Description: description,
|
|
Args: make([]string, 0),
|
|
Flags: make(map[string]string),
|
|
Booleans: make(map[string]bool),
|
|
Integers: make(map[string]int64),
|
|
Floats: make(map[string]float64),
|
|
Options: make(map[string][]string),
|
|
EnvVars: make(map[string]string),
|
|
WorkingDir: getCurrentWorkingDir(),
|
|
Custom: make(map[string]interface{}),
|
|
}
|
|
}
|
|
|
|
// NewServerCommand 创建服务器命令
|
|
// 返回配置好的服务器命令实例
|
|
func NewServerCommand() *Command {
|
|
cmd := NewCommand(SERVER, "server", "Start the subconverter server")
|
|
cmd.Usage = "server [flags]"
|
|
cmd.Aliases = []string{"serve", "start"}
|
|
|
|
// 默认标志
|
|
cmd.Booleans["debug"] = false
|
|
cmd.Booleans["verbose"] = false
|
|
cmd.Integers["port"] = 25500
|
|
cmd.Flags["host"] = "0.0.0.0"
|
|
cmd.Flags["config"] = ""
|
|
|
|
return cmd
|
|
}
|
|
|
|
// NewConfigCommand 创建配置命令
|
|
// 返回配置好的配置命令实例
|
|
func NewConfigCommand() *Command {
|
|
cmd := NewCommand(CONFIG, "config", "Manage configuration")
|
|
cmd.Usage = "config <subcommand> [flags]"
|
|
cmd.Aliases = []string{"conf", "cfg"}
|
|
|
|
return cmd
|
|
}
|
|
|
|
// NewTestCommand 创建测试命令
|
|
// 返回配置好的测试命令实例
|
|
func NewTestCommand() *Command {
|
|
cmd := NewCommand(TEST, "test", "Run tests")
|
|
cmd.Usage = "test <subcommand> [flags]"
|
|
cmd.Aliases = []string{"t"}
|
|
|
|
cmd.Booleans["verbose"] = false
|
|
cmd.Booleans["cover"] = false
|
|
cmd.Flags["run"] = ""
|
|
cmd.Flags["output"] = ""
|
|
|
|
return cmd
|
|
}
|
|
|
|
// NewVersionCommand 创建版本命令
|
|
// 返回配置好的版本命令实例
|
|
func NewVersionCommand() *Command {
|
|
cmd := NewCommand(VERSION, "version", "Show version information")
|
|
cmd.Usage = "version [flags]"
|
|
cmd.Aliases = []string{"v", "ver"}
|
|
|
|
cmd.Booleans["verbose"] = false
|
|
cmd.Booleans["short"] = false
|
|
|
|
return cmd
|
|
}
|
|
|
|
// NewHelpCommand 创建帮助命令
|
|
// 返回配置好的帮助命令实例
|
|
func NewHelpCommand() *Command {
|
|
cmd := NewCommand(HELP, "help", "Show help information")
|
|
cmd.Usage = "help [command]"
|
|
cmd.Aliases = []string{"h", "?"}
|
|
|
|
return cmd
|
|
}
|
|
|
|
// AddArg 添加位置参数
|
|
func (c *Command) AddArg(arg string) {
|
|
c.Args = append(c.Args, arg)
|
|
c.ArgsCount = len(c.Args)
|
|
}
|
|
|
|
// AddArgs 添加多个位置参数
|
|
func (c *Command) AddArgs(args ...string) {
|
|
c.Args = append(c.Args, args...)
|
|
c.ArgsCount = len(c.Args)
|
|
}
|
|
|
|
// SetFlag 设置字符串标志
|
|
func (c *Command) SetFlag(key, value string) {
|
|
c.Flags[key] = value
|
|
}
|
|
|
|
// SetBoolean 设置布尔标志
|
|
func (c *Command) SetBoolean(key string, value bool) {
|
|
c.Booleans[key] = value
|
|
}
|
|
|
|
// SetInteger 设置整数标志
|
|
func (c *Command) SetInteger(key string, value int64) {
|
|
c.Integers[key] = value
|
|
}
|
|
|
|
// SetFloat 设置浮点数标志
|
|
func (c *Command) SetFloat(key string, value float64) {
|
|
c.Floats[key] = value
|
|
}
|
|
|
|
// AddOption 添加选项参数
|
|
func (c *Command) AddOption(key string, values ...string) {
|
|
if c.Options == nil {
|
|
c.Options = make(map[string][]string)
|
|
}
|
|
c.Options[key] = append(c.Options[key], values...)
|
|
}
|
|
|
|
// SetEnvVar 设置环境变量
|
|
func (c *Command) SetEnvVar(key, value string) {
|
|
if c.EnvVars == nil {
|
|
c.EnvVars = make(map[string]string)
|
|
}
|
|
c.EnvVars[key] = value
|
|
}
|
|
|
|
// GetArg 获取位置参数
|
|
func (c *Command) GetArg(index int) (string, bool) {
|
|
if index < 0 || index >= len(c.Args) {
|
|
return "", false
|
|
}
|
|
return c.Args[index], true
|
|
}
|
|
|
|
// GetFlag 获取字符串标志
|
|
func (c *Command) GetFlag(key string) (string, bool) {
|
|
value, exists := c.Flags[key]
|
|
return value, exists
|
|
}
|
|
|
|
// GetBoolean 获取布尔标志
|
|
func (c *Command) GetBoolean(key string) (bool, bool) {
|
|
value, exists := c.Booleans[key]
|
|
return value, exists
|
|
}
|
|
|
|
// GetInteger 获取整数标志
|
|
func (c *Command) GetInteger(key string) (int64, bool) {
|
|
value, exists := c.Integers[key]
|
|
return value, exists
|
|
}
|
|
|
|
// GetFloat 获取浮点数标志
|
|
func (c *Command) GetFloat(key string) (float64, bool) {
|
|
value, exists := c.Floats[key]
|
|
return value, exists
|
|
}
|
|
|
|
// GetOptions 获取选项参数
|
|
func (c *Command) GetOptions(key string) ([]string, bool) {
|
|
value, exists := c.Options[key]
|
|
return value, exists
|
|
}
|
|
|
|
// GetEnvVar 获取环境变量
|
|
func (c *Command) GetEnvVar(key string) (string, bool) {
|
|
value, exists := c.EnvVars[key]
|
|
return value, exists
|
|
}
|
|
|
|
// HasFlag 检查是否有指定标志
|
|
func (c *Command) HasFlag(key string) bool {
|
|
_, exists := c.Flags[key]
|
|
return exists
|
|
}
|
|
|
|
// HasBoolean 检查是否有指定布尔标志
|
|
func (c *Command) HasBoolean(key string) bool {
|
|
_, exists := c.Booleans[key]
|
|
return exists
|
|
}
|
|
|
|
// HasOption 检查是否有指定选项
|
|
func (c *Command) HasOption(key string) bool {
|
|
_, exists := c.Options[key]
|
|
return exists
|
|
}
|
|
|
|
// ArgCount 返回位置参数数量
|
|
func (c *Command) ArgCount() int {
|
|
return len(c.Args)
|
|
}
|
|
|
|
// IsExecuted 检查命令是否已执行
|
|
func (c *Command) IsExecuted() bool {
|
|
return c.Executed
|
|
}
|
|
|
|
// IsSuccessful 检查命令是否成功执行
|
|
func (c *Command) IsSuccessful() bool {
|
|
return c.Executed && c.ExitCode == 0
|
|
}
|
|
|
|
// SetConfig 设置配置信息
|
|
func (c *Command) SetConfig(config interface{}) {
|
|
c.Config = config
|
|
}
|
|
|
|
// SetConfigFile 设置配置文件路径
|
|
func (c *Command) SetConfigFile(path string) {
|
|
c.ConfigFile = path
|
|
}
|
|
|
|
// SetOutput 设置输出信息
|
|
func (c *Command) SetOutput(output string) {
|
|
c.Output = output
|
|
}
|
|
|
|
// SetError 设置错误信息
|
|
func (c *Command) SetError(err error) {
|
|
c.Error = err
|
|
c.ExitCode = 1
|
|
}
|
|
|
|
// MarkExecuted 标记命令为已执行
|
|
func (c *Command) MarkExecuted() {
|
|
c.Executed = true
|
|
c.ExecutedAt = time.Now()
|
|
}
|
|
|
|
// MarkSuccessful 标记命令为成功执行
|
|
func (c *Command) MarkSuccessful() {
|
|
c.MarkExecuted()
|
|
c.ExitCode = 0
|
|
}
|
|
|
|
// MarkFailed 标记命令为执行失败
|
|
func (c *Command) MarkFailed(exitCode int) {
|
|
c.MarkExecuted()
|
|
c.ExitCode = exitCode
|
|
}
|
|
|
|
// SetDuration 设置执行持续时间
|
|
func (c *Command) SetDuration(duration time.Duration) {
|
|
c.Duration = duration
|
|
}
|
|
|
|
// AddCustom 添加自定义数据
|
|
func (c *Command) AddCustom(key string, value interface{}) {
|
|
if c.Custom == nil {
|
|
c.Custom = make(map[string]interface{})
|
|
}
|
|
c.Custom[key] = value
|
|
}
|
|
|
|
// GetCustom 获取自定义数据
|
|
func (c *Command) GetCustom(key string) (interface{}, bool) {
|
|
value, exists := c.Custom[key]
|
|
return value, exists
|
|
}
|
|
|
|
// Validate 验证命令的有效性
|
|
func (c *Command) Validate() error {
|
|
if c.Name == "" {
|
|
return fmt.Errorf("command name cannot be empty")
|
|
}
|
|
|
|
if c.Type < SERVER || c.Type > UNKNOWN {
|
|
return fmt.Errorf("invalid command type: %d", c.Type)
|
|
}
|
|
|
|
// 验证必需的参数
|
|
switch c.Type {
|
|
case SERVER:
|
|
if port, exists := c.Integers["port"]; exists && (port < 1 || port > 65535) {
|
|
return fmt.Errorf("invalid port number: %d", port)
|
|
}
|
|
case CONFIG:
|
|
if len(c.Args) == 0 {
|
|
return fmt.Errorf("config command requires a subcommand")
|
|
}
|
|
case TEST:
|
|
if len(c.Args) == 0 {
|
|
return fmt.Errorf("test command requires a subcommand")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetUsage 返回使用说明
|
|
func (c *Command) GetUsage() string {
|
|
if c.Usage != "" {
|
|
return c.Usage
|
|
}
|
|
return c.Name
|
|
}
|
|
|
|
// GetFullUsage 返回完整的使用说明
|
|
func (c *Command) GetFullUsage() string {
|
|
var builder strings.Builder
|
|
|
|
builder.WriteString(fmt.Sprintf("Usage: %s", c.GetUsage()))
|
|
|
|
if c.Description != "" {
|
|
builder.WriteString(fmt.Sprintf("\n\n%s", c.Description))
|
|
}
|
|
|
|
if len(c.Aliases) > 0 {
|
|
builder.WriteString(fmt.Sprintf("\n\nAliases: %s", strings.Join(c.Aliases, ", ")))
|
|
}
|
|
|
|
// 添加位置参数说明
|
|
if len(c.Args) > 0 {
|
|
builder.WriteString("\n\nArguments:")
|
|
for i, arg := range c.Args {
|
|
builder.WriteString(fmt.Sprintf("\n %d: %s", i+1, arg))
|
|
}
|
|
}
|
|
|
|
// 添加标志说明
|
|
if len(c.Flags) > 0 || len(c.Booleans) > 0 || len(c.Integers) > 0 || len(c.Floats) > 0 {
|
|
builder.WriteString("\n\nFlags:")
|
|
|
|
for key, value := range c.Flags {
|
|
builder.WriteString(fmt.Sprintf("\n --%s=%s", key, value))
|
|
}
|
|
|
|
for key, value := range c.Booleans {
|
|
builder.WriteString(fmt.Sprintf("\n --%s (default: %t)", key, value))
|
|
}
|
|
|
|
for key, value := range c.Integers {
|
|
builder.WriteString(fmt.Sprintf("\n --%s=%d", key, value))
|
|
}
|
|
|
|
for key, value := range c.Floats {
|
|
builder.WriteString(fmt.Sprintf("\n --%s=%f", key, value))
|
|
}
|
|
}
|
|
|
|
return builder.String()
|
|
}
|
|
|
|
// Clone 创建命令的副本
|
|
func (c *Command) Clone() *Command {
|
|
clone := &Command{
|
|
Type: c.Type,
|
|
Name: c.Name,
|
|
Description: c.Description,
|
|
Usage: c.Usage,
|
|
ArgsCount: c.ArgsCount,
|
|
ConfigFile: c.ConfigFile,
|
|
Config: c.Config,
|
|
Executed: c.Executed,
|
|
ExecutedAt: c.ExecutedAt,
|
|
Duration: c.Duration,
|
|
ExitCode: c.ExitCode,
|
|
Output: c.Output,
|
|
Error: c.Error,
|
|
WorkingDir: c.WorkingDir,
|
|
UserID: c.UserID,
|
|
SessionID: c.SessionID,
|
|
Debug: c.Debug,
|
|
Verbose: c.Verbose,
|
|
Quiet: c.Quiet,
|
|
DryRun: c.DryRun,
|
|
}
|
|
|
|
// 深拷贝切片
|
|
if len(c.Aliases) > 0 {
|
|
clone.Aliases = make([]string, len(c.Aliases))
|
|
copy(clone.Aliases, c.Aliases)
|
|
}
|
|
|
|
if len(c.Args) > 0 {
|
|
clone.Args = make([]string, len(c.Args))
|
|
copy(clone.Args, c.Args)
|
|
}
|
|
|
|
// 深拷贝映射
|
|
if len(c.Flags) > 0 {
|
|
clone.Flags = make(map[string]string)
|
|
for k, v := range c.Flags {
|
|
clone.Flags[k] = v
|
|
}
|
|
}
|
|
|
|
if len(c.Booleans) > 0 {
|
|
clone.Booleans = make(map[string]bool)
|
|
for k, v := range c.Booleans {
|
|
clone.Booleans[k] = v
|
|
}
|
|
}
|
|
|
|
if len(c.Integers) > 0 {
|
|
clone.Integers = make(map[string]int64)
|
|
for k, v := range c.Integers {
|
|
clone.Integers[k] = v
|
|
}
|
|
}
|
|
|
|
if len(c.Floats) > 0 {
|
|
clone.Floats = make(map[string]float64)
|
|
for k, v := range c.Floats {
|
|
clone.Floats[k] = v
|
|
}
|
|
}
|
|
|
|
if len(c.Options) > 0 {
|
|
clone.Options = make(map[string][]string)
|
|
for k, v := range c.Options {
|
|
clone.Options[k] = make([]string, len(v))
|
|
copy(clone.Options[k], v)
|
|
}
|
|
}
|
|
|
|
if len(c.EnvVars) > 0 {
|
|
clone.EnvVars = make(map[string]string)
|
|
for k, v := range c.EnvVars {
|
|
clone.EnvVars[k] = v
|
|
}
|
|
}
|
|
|
|
if len(c.Custom) > 0 {
|
|
clone.Custom = make(map[string]interface{})
|
|
for k, v := range c.Custom {
|
|
clone.Custom[k] = v
|
|
}
|
|
}
|
|
|
|
return clone
|
|
}
|
|
|
|
// String 返回命令的字符串表示
|
|
func (c *Command) String() string {
|
|
if c.Executed {
|
|
return fmt.Sprintf("%s (executed in %v, exit code: %d)", c.Name, c.Duration, c.ExitCode)
|
|
}
|
|
return fmt.Sprintf("%s (not executed)", c.Name)
|
|
}
|
|
|
|
// GetCurrentWorkingDir 获取当前工作目录
|
|
func getCurrentWorkingDir() string {
|
|
if dir, err := os.Getwd(); err == nil {
|
|
return dir
|
|
}
|
|
return "."
|
|
}
|
|
|
|
// CommandTypeToString 将命令类型转换为字符串
|
|
func CommandTypeToString(cmdType CommandType) string {
|
|
switch cmdType {
|
|
case SERVER:
|
|
return "server"
|
|
case CONFIG:
|
|
return "config"
|
|
case TEST:
|
|
return "test"
|
|
case VERSION:
|
|
return "version"
|
|
case HELP:
|
|
return "help"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
// StringToCommandType 将字符串转换为命令类型
|
|
func StringToCommandType(s string) CommandType {
|
|
switch strings.ToLower(s) {
|
|
case "server", "serve", "start":
|
|
return SERVER
|
|
case "config", "conf", "cfg":
|
|
return CONFIG
|
|
case "test", "t":
|
|
return TEST
|
|
case "version", "v", "ver":
|
|
return VERSION
|
|
case "help", "h", "?":
|
|
return HELP
|
|
default:
|
|
return UNKNOWN
|
|
}
|
|
} |