瀏覽代碼

删除命令行参数解析相关代码

移除了与命令行参数解析相关的所有文件和代码,包括定义、导出方法及内部实现。同时更新了主函数以使用新的配置方式,并引入了 Cobra 库来处理版本、许可证和报告命令。
SongZihuan 1 周之前
父節點
當前提交
f141c32652

+ 5 - 1
CHANGELOG.md

@@ -7,7 +7,7 @@
 
 **注意:本文档内容若与[GitHub Wiki](https://github.com/SongZihuan/BackendServerTemplate/wiki/%E5%8F%98%E6%9B%B4%E6%97%A5%E5%BF%97)冲突,则以后者为准**
 
-## [未发布]
+## [0.6.0] - 2025-04-21
 
 ### 新增
 
@@ -18,6 +18,10 @@
 - 修复`strconvutils.ReadTimeDuration`中把`uint`转换程`int`可能带来的风险问题,并新增`ReadTimeDurationPositive`函数。
 - 完善`README.md`文档关于版本号的描述。
 
+### 重构
+
+- 优化了命令行匹配系统,使其能够支持更复杂的命令行(子命令、标志、参数)。
+
 ## [0.5.0] - 2025-04-19
 
 ### 新增

+ 0 - 1
NAME

@@ -1 +0,0 @@
-Backend-Server-Template

+ 3 - 0
REPORT

@@ -1,5 +1,8 @@
 How to report of BackendServerTemplate
 
+Security: When submitting feedback, please be sure to read the Security Docs.
+Security Docs: https://github.com/SongZihuan/BackendServerTemplate/blob/master/SECURITY.md
+
 Author: 宋子桓(Song Zihuan)
 Author Github: https://github.com/SongZihuan
 Author Website: https://song-zh.com

+ 6 - 1
go.mod

@@ -10,4 +10,9 @@ require (
 	gopkg.in/yaml.v3 v3.0.1
 )
 
-require golang.org/x/sys v0.31.0 // indirect
+require (
+	github.com/inconshreveable/mousetrap v1.1.0 // indirect
+	github.com/spf13/cobra v1.9.1 // indirect
+	github.com/spf13/pflag v1.0.6 // indirect
+	golang.org/x/sys v0.31.0 // indirect
+)

+ 8 - 0
go.sum

@@ -1,7 +1,15 @@
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
 github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=

+ 14 - 2
resource.go

@@ -46,9 +46,9 @@ func init() {
 
 	// 其他操作
 	initName()
+	initLicense()
 	initBuildDate()
 	initVersion()
-	initServiceConfig()
 }
 
 func initCleanFile() {
@@ -87,7 +87,19 @@ func initName() {
 		panic("name was empty")
 	}
 
-	Name = _args0Name
+	_args0NamePosix := strings.TrimSuffix(_args0Name, ".exe")
+
+	if _args0NamePosix == "" {
+		panic("name was empty")
+	}
+
+	Name = _args0NamePosix
+}
+
+func initLicense() {
+	License = strings.Split(License, "--- 下述为中文翻译,仅供参考,以上述英文协议原文为准。 ---")[0]
+	License = strings.TrimRight(License, "\n")
+	License = strings.TrimSpace(License)
 }
 
 func initBuildDate() {

+ 1 - 94
service.go

@@ -6,100 +6,7 @@ package resource
 
 import (
 	_ "embed"
-	"gopkg.in/yaml.v3"
-	"os"
-	"regexp"
 )
 
-const (
-	FromNo      = "no"
-	FromInstall = "install"
-	FromConfig  = "config"
-)
-
-const (
-	Args1Install    = "install"
-	Args1Uninstall1 = "remove"
-	Args1Uninstall2 = "uninstall"
-	Args1Start      = "start"
-	Args1Stop       = "stop"
-	Args1Restart    = "restart"
-)
-
-type ServiceConfigType struct {
-	Name         string            `yaml:"name"`
-	DisplayName  string            `yaml:"display-name"`
-	Describe     string            `yaml:"describe"`
-	ArgumentFrom string            `yaml:"argument-from"`
-	ArgumentList []string          `yaml:"argument-list"`
-	EnvFrom      string            `yaml:"env-from"`
-	EnvGetList   []string          `yaml:"env-get-list"`
-	EnvSetList   map[string]string `yaml:"env-set-list"`
-}
-
 //go:embed SERVICE.yaml
-var serviceConfig []byte
-var ServiceConfig ServiceConfigType
-
-var nameRegex = regexp.MustCompilePOSIX(`^[a-zA-Z0-9]+$`)
-
-func initServiceConfig() {
-	err := yaml.Unmarshal(serviceConfig, &ServiceConfig)
-	if err != nil {
-		panic(err)
-	}
-
-	if ServiceConfig.Name == "" || !nameRegex.MatchString(ServiceConfig.Name) {
-		panic("service name is invalid")
-	}
-
-	if ServiceConfig.DisplayName == "" {
-		ServiceConfig.DisplayName = ServiceConfig.Name
-	}
-
-	ServiceConfig.Describe = utilsClenFileData(ServiceConfig.Describe)
-
-	switch ServiceConfig.ArgumentFrom {
-	case FromInstall:
-		if len(os.Args) > 2 && os.Args[1] == Args1Install {
-			ServiceConfig.ArgumentFrom = FromConfig
-			ServiceConfig.ArgumentList = os.Args[2:]
-		} else {
-			ServiceConfig.ArgumentFrom = FromNo
-			ServiceConfig.ArgumentList = nil
-		}
-	case FromConfig:
-		if len(ServiceConfig.ArgumentList) == 0 {
-			ServiceConfig.ArgumentFrom = FromNo
-			ServiceConfig.ArgumentList = nil
-		}
-	default:
-		ServiceConfig.ArgumentFrom = FromNo
-		ServiceConfig.ArgumentList = nil
-	}
-
-	switch ServiceConfig.EnvFrom {
-	case FromInstall:
-		if len(ServiceConfig.EnvGetList) == 0 {
-			ServiceConfig.EnvFrom = FromNo
-			ServiceConfig.EnvGetList = nil
-			ServiceConfig.EnvSetList = nil
-			break
-		}
-
-		ServiceConfig.EnvSetList = make(map[string]string, len(ServiceConfig.EnvGetList))
-		for _, e := range ServiceConfig.EnvGetList {
-			ServiceConfig.EnvSetList[e] = os.Getenv(e)
-		}
-	case FromConfig:
-		ServiceConfig.EnvGetList = nil
-		if len(ServiceConfig.EnvSetList) == 0 {
-			ServiceConfig.EnvFrom = FromNo
-			ServiceConfig.EnvSetList = nil
-		}
-	default:
-		ServiceConfig.EnvFrom = FromNo
-		ServiceConfig.EnvGetList = nil
-		ServiceConfig.EnvSetList = nil
-	}
-}
+var ServiceConfigYamlData []byte

+ 0 - 63
service_test.go

@@ -1,63 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package resource
-
-import (
-	"fmt"
-	"strings"
-	"testing"
-)
-
-func TestServiceConfig(t *testing.T) {
-	if ServiceConfig.Name == "" {
-		t.Errorf("Service name is empty")
-	}
-
-	if ServiceConfig.DisplayName == "" {
-		t.Errorf("Service display name is empty")
-	}
-
-	if strings.Contains(ServiceConfig.Describe, "\n") {
-		t.Errorf("Service describe has LF")
-	}
-
-	if strings.Contains(ServiceConfig.Describe, "\r") {
-		t.Errorf("Service describe has CR")
-	}
-
-	if len(ServiceConfig.Describe) > 1 && ServiceConfig.Describe[0] == ' ' {
-		t.Errorf("Service describe start with space")
-	}
-
-	if len(ServiceConfig.Describe) > 2 && ServiceConfig.Describe[len(ServiceConfig.Describe)-1] == ' ' {
-		t.Errorf("Service describe end with space")
-	}
-
-	switch ServiceConfig.ArgumentFrom {
-	case FromConfig:
-		if len(ServiceConfig.ArgumentList) == 0 {
-			t.Errorf("Error argument-from: argument-list is empty, but argument-from config")
-		}
-	case FromNo:
-		if len(ServiceConfig.ArgumentList) > 0 {
-			t.Errorf("Error argument-from: argument-list is not empty, but argument-from no")
-		}
-	default:
-		t.Errorf(fmt.Sprintf("Error argument-from: %s", ServiceConfig.ArgumentFrom))
-	}
-
-	switch ServiceConfig.EnvFrom {
-	case FromConfig:
-		if len(ServiceConfig.EnvSetList) == 0 {
-			t.Errorf("Error env-from: env-set-list is empty, but env-from config")
-		}
-	case FromNo:
-		if len(ServiceConfig.EnvSetList) > 0 {
-			t.Errorf("Error env-from: env-set-list is not empty, but env-from no")
-		}
-	default:
-		t.Errorf(fmt.Sprintf("Error argument-from: %s", ServiceConfig.EnvFrom))
-	}
-}

+ 138 - 2
src/cmd/catv1/main.go

@@ -5,11 +5,147 @@
 package main
 
 import (
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/root"
 	_ "github.com/SongZihuan/BackendServerTemplate/src/global"
 	catv1 "github.com/SongZihuan/BackendServerTemplate/src/mainfunc/cat/v1"
-	"os"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
+	"github.com/spf13/cobra"
+)
+
+const (
+	args1Install    = "install"
+	args1Uninstall1 = "uninstall"
+	args1Uninstall2 = "remove"
+	args1Start      = "start"
+	args1Stop       = "stop"
+	args1Restart    = "restart"
 )
 
 func main() {
-	os.Exit(int(catv1.MainV1()))
+	cmd := root.GetRootCMD("System service registration tool",
+		"Register this software as a system service, mainly used in Windows.",
+		catv1.MainV1)
+
+	cmd.Flags().StringVarP(&catv1.InputConfigFilePath, "config", "c", catv1.InputConfigFilePath, "the file path of the configuration file")
+	cmd.Flags().StringVarP(&catv1.InputConfigFilePath, "output-config", "o", catv1.InputConfigFilePath, "the file path of the output configuration file")
+
+	install := &cobra.Command{
+		Use:           args1Install,
+		Short:         "Install/Register the service",
+		Long:          "",
+		SilenceUsage:  false,
+		SilenceErrors: false,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = true
+			cmd.SilenceErrors = true
+			return catv1.MainV1Install(cmd, args)
+		},
+		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+	}
+
+	uninstall := &cobra.Command{
+		Use:           args1Uninstall1,
+		Short:         "Uninstall/Remove the service",
+		Long:          "",
+		Aliases:       []string{args1Uninstall2},
+		SilenceUsage:  false,
+		SilenceErrors: false,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = true
+			cmd.SilenceErrors = true
+			return catv1.MainV1UnInstall(cmd, args)
+		},
+		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+	}
+
+	start := &cobra.Command{
+		Use:           args1Start,
+		Short:         "Start the service",
+		Long:          "",
+		SilenceUsage:  false,
+		SilenceErrors: false,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = true
+			cmd.SilenceErrors = true
+			return catv1.MainV1Start(cmd, args)
+		},
+		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+	}
+
+	stop := &cobra.Command{
+		Use:           args1Stop,
+		Short:         "Stop the service",
+		Long:          "",
+		SilenceUsage:  false,
+		SilenceErrors: false,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = true
+			cmd.SilenceErrors = true
+			return catv1.MainV1Stop(cmd, args)
+		},
+		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+	}
+
+	restart := &cobra.Command{
+		Use:           args1Restart,
+		Short:         "Restart the service",
+		Long:          "",
+		SilenceUsage:  false,
+		SilenceErrors: false,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = true
+			cmd.SilenceErrors = true
+			return catv1.MainV1Restart(cmd, args)
+		},
+		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+	}
+
+	cmd.AddCommand(install, uninstall, start, stop, restart)
+
+	exitutils.Exit(cmd.Execute())
 }

+ 33 - 0
src/cmd/globalmain/main.go

@@ -0,0 +1,33 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package globalmain
+
+import (
+	"github.com/SongZihuan/BackendServerTemplate/src/logger"
+	"github.com/SongZihuan/BackendServerTemplate/src/logger/loglevel"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/consoleutils"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
+)
+
+func PreRun() (exitCode error) {
+	var err error
+
+	err = consoleutils.SetConsoleCPSafe(consoleutils.CodePageUTF8)
+	if err != nil {
+		return exitutils.InitFailedErrorForWin32ConsoleModule(err.Error())
+	}
+
+	err = logger.InitBaseLogger(loglevel.LevelDebug, true, nil, nil, nil, nil)
+	if err != nil {
+		return exitutils.InitFailedErrorForLoggerModule(err.Error())
+	}
+
+	return nil
+}
+
+func PostRun() {
+	defer logger.CloseLogger()
+	defer logger.Recover()
+}

+ 10 - 2
src/cmd/lionv1/main.go

@@ -5,11 +5,19 @@
 package main
 
 import (
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/root"
 	_ "github.com/SongZihuan/BackendServerTemplate/src/global"
 	lionv1 "github.com/SongZihuan/BackendServerTemplate/src/mainfunc/lion/v1"
-	"os"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
 )
 
 func main() {
-	os.Exit(int(lionv1.MainV1()))
+	cmd := root.GetRootCMD("Multi-tasking background system",
+		"A multi-task background system controlled by a controller to run multiple tasks concurrently",
+		lionv1.MainV1)
+
+	cmd.Flags().StringVarP(&lionv1.InputConfigFilePath, "config", "c", lionv1.InputConfigFilePath, "the file path of the configuration file")
+	cmd.Flags().StringVarP(&lionv1.InputConfigFilePath, "output-config", "o", lionv1.InputConfigFilePath, "the file path of the output configuration file")
+
+	exitutils.Exit(cmd.Execute())
 }

+ 10 - 2
src/cmd/tigerv1/main.go

@@ -5,11 +5,19 @@
 package main
 
 import (
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/root"
 	_ "github.com/SongZihuan/BackendServerTemplate/src/global"
 	tigerv1 "github.com/SongZihuan/BackendServerTemplate/src/mainfunc/tiger/v1"
-	"os"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
 )
 
 func main() {
-	os.Exit(int(tigerv1.MainV1()))
+	cmd := root.GetRootCMD("Single-tasking background system",
+		"A single-task background system that runs a single task directly without using a controller",
+		tigerv1.MainV1)
+
+	cmd.Flags().StringVarP(&tigerv1.InputConfigFilePath, "config", "c", tigerv1.InputConfigFilePath, "the file path of the configuration file")
+	cmd.Flags().StringVarP(&tigerv1.InputConfigFilePath, "output-config", "o", tigerv1.InputConfigFilePath, "the file path of the output configuration file")
+
+	exitutils.Exit(cmd.Execute())
 }

+ 28 - 0
src/cmdparser/license/license.go

@@ -0,0 +1,28 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package license
+
+import (
+	"fmt"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/formatutils"
+	"github.com/spf13/cobra"
+	"io"
+	"os"
+)
+
+var CMD = &cobra.Command{
+	Use:   "license",
+	Short: "Print the license of this project",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		_, _ = printLicense(os.Stdout)
+		return nil
+	},
+}
+
+func printLicense(writer io.Writer) (int, error) {
+	license := formatutils.FormatTextToWidth(global.License, formatutils.NormalConsoleWidth)
+	return fmt.Fprint(writer, license)
+}

+ 28 - 0
src/cmdparser/report/cmd.go

@@ -0,0 +1,28 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package report
+
+import (
+	"fmt"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/formatutils"
+	"github.com/spf13/cobra"
+	"io"
+	"os"
+)
+
+var CMD = &cobra.Command{
+	Use:   "report",
+	Short: "Print how to submit feedback",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		_, _ = printReport(os.Stdout)
+		return nil
+	},
+}
+
+func printReport(writer io.Writer) (int, error) {
+	report := formatutils.FormatTextToWidth(global.Report, formatutils.NormalConsoleWidth)
+	return fmt.Fprint(writer, report)
+}

+ 62 - 0
src/cmdparser/root/root.go

@@ -0,0 +1,62 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package root
+
+import (
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/license"
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/report"
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/version"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/cleanstringutils"
+	"github.com/spf13/cobra"
+)
+
+var name string = global.Name
+var nameChanged bool
+
+func GetRootCMD(shortDescribe string, longDescribe string, action func(cmd *cobra.Command, args []string) error) *cobra.Command {
+	cmd := &cobra.Command{
+		Use:           global.Name,
+		Short:         shortDescribe,
+		Long:          longDescribe,
+		SilenceUsage:  false,
+		SilenceErrors: false,
+		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+
+			if name = cleanstringutils.GetStringOneLine(name); cmd.Flags().Changed("name") && name != "" {
+				global.Name = name
+				nameChanged = true
+			} else {
+				nameChanged = false
+			}
+			return nil
+		},
+		RunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = true
+			cmd.SilenceErrors = true
+			return action(cmd, args)
+		},
+		PersistentPostRunE: func(cmd *cobra.Command, args []string) error {
+			cmd.SilenceUsage = false
+			cmd.SilenceErrors = false
+			return nil
+		},
+	}
+
+	cmd.AddCommand(version.CMD, license.CMD, report.CMD)
+	cmd.PersistentFlags().StringVarP(&name, "name", "n", global.Name, "the program display name")
+
+	return cmd
+}
+
+func Name() string {
+	return name
+}
+
+func NameChanged() bool {
+	return nameChanged
+}

+ 56 - 0
src/cmdparser/version/cmd.go

@@ -0,0 +1,56 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package version
+
+import (
+	"fmt"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/formatutils"
+	"github.com/spf13/cobra"
+	"io"
+	"os"
+	"runtime"
+	"strings"
+	"time"
+)
+
+var short bool
+
+var CMD = &cobra.Command{
+	Use:   "version",
+	Short: "Print the version and build info of this program",
+	RunE: func(cmd *cobra.Command, args []string) error {
+		if short {
+			_, _ = printShortVersion(os.Stdout)
+		} else {
+			_, _ = printVersion(os.Stdout)
+		}
+		return nil
+	},
+}
+
+func init() {
+	CMD.Flags().BoolVarP(&short, "short", "s", false, "only show the version info")
+}
+
+func printVersion(writer io.Writer) (int, error) {
+	res := new(strings.Builder)
+	res.WriteString(fmt.Sprintf("Version: %s\n", global.Version))
+	res.WriteString(fmt.Sprintf("Build Date (UTC): %s\n", global.BuildTime.In(time.UTC).Format(time.DateTime)))
+	if time.Local != nil && time.Local.String() != time.UTC.String() {
+		zone, _ := time.Now().Local().Zone()
+		res.WriteString(fmt.Sprintf("Build Date (%s): %s\n", zone, global.BuildTime.In(time.Local).Format(time.DateTime)))
+	}
+	res.WriteString(fmt.Sprintf("Compiler: %s\n", runtime.Version()))
+	res.WriteString(fmt.Sprintf("OS: %s\n", runtime.GOOS))
+	res.WriteString(fmt.Sprintf("Arch: %s\n", runtime.GOARCH))
+
+	version := formatutils.FormatTextToWidth(res.String(), formatutils.NormalConsoleWidth)
+	return fmt.Fprint(writer, version)
+}
+
+func printShortVersion(writer io.Writer) (int, error) {
+	return fmt.Fprint(writer, global.SemanticVersioning) // 不需要(ln)换行
+}

+ 0 - 133
src/commandlineargs/define_data_type.go

@@ -1,133 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package commandlineargs
-
-import (
-	"flag"
-	"fmt"
-	"github.com/SongZihuan/BackendServerTemplate/src/global"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/osutils"
-)
-
-type commandLineArgsDataType struct {
-	flagReady  bool
-	flagSet    bool
-	flagParser bool
-
-	NameData  string
-	NameName  string
-	NameUsage string
-
-	HelpData  bool
-	HelpName  string
-	HelpUsage string
-
-	OutputVersionData      bool
-	OutputVersionName      string
-	OutputVersionShortName string
-	OutputVersionUsage     string
-
-	VersionData  bool
-	VersionName  string
-	VersionUsage string
-
-	LicenseData  bool
-	LicenseName  string
-	LicenseUsage string
-
-	ReportData  bool
-	ReportName  string
-	ReportUsage string
-
-	ConfigFileData  string
-	ConfigFileName  string
-	ConfigFileUsage string
-
-	ConfigOutputFileData  string
-	ConfigOutputFileName  string
-	ConfigOutputFileUsage string
-
-	Usage string
-}
-
-func initData() {
-	commandLineArgsData = commandLineArgsDataType{
-		flagReady:  false,
-		flagSet:    false,
-		flagParser: false,
-
-		NameData:  "", // 默认值为空,具体Name为什么则由config决定
-		NameName:  "name",
-		NameUsage: fmt.Sprintf("Set the name of the running program, the default is %s.", global.Name),
-
-		HelpData:  false,
-		HelpName:  "help",
-		HelpUsage: fmt.Sprintf("Show usage of %s. If this option is set, the backend service will not run.", osutils.GetArgs0Name()),
-
-		VersionData:  false,
-		VersionName:  "version",
-		VersionUsage: fmt.Sprintf("Show version of %s. If this option is set, the backend service will not run.", osutils.GetArgs0Name()),
-
-		OutputVersionData:      false,
-		OutputVersionName:      "output-version",
-		OutputVersionShortName: "",
-		OutputVersionUsage:     fmt.Sprintf("Show version of %s. If this option is set, the backend service will not run.", osutils.GetArgs0Name()),
-
-		LicenseData:  false,
-		LicenseName:  "license",
-		LicenseUsage: fmt.Sprintf("Show license of %s. If this option is set, the backend service will not run.", osutils.GetArgs0Name()),
-
-		ReportData:  false,
-		ReportName:  "report",
-		ReportUsage: fmt.Sprintf("Show how to report questions/errors of %s. If this option is set, the backend service will not run.", osutils.GetArgs0Name()),
-
-		ConfigFileData:  "config.yaml",
-		ConfigFileName:  "config",
-		ConfigFileUsage: fmt.Sprintf("%s", "The location of the running configuration file of the backend service. The option is a string, the default value is config.yaml in the running directory."),
-
-		ConfigOutputFileData:  "",
-		ConfigOutputFileName:  "output-config",
-		ConfigOutputFileUsage: fmt.Sprintf("%s", "Reverse output configuration file (can be used for corresponding inspection work), the default value is empty (no output)."),
-
-		Usage: "",
-	}
-
-	commandLineArgsData.ready()
-}
-
-func (d *commandLineArgsDataType) setFlag() {
-	if d.isFlagSet() {
-		return
-	}
-
-	flag.StringVar(&d.NameData, d.NameName, d.NameData, d.NameUsage)
-	flag.StringVar(&d.NameData, d.NameName[0:1], d.NameData, d.NameUsage)
-
-	flag.BoolVar(&d.HelpData, d.HelpName, d.HelpData, d.HelpUsage)
-	flag.BoolVar(&d.HelpData, d.HelpName[0:1], d.HelpData, d.HelpUsage)
-
-	flag.BoolVar(&d.VersionData, d.VersionName, d.VersionData, d.VersionUsage)
-	flag.BoolVar(&d.VersionData, d.VersionName[0:1], d.VersionData, d.VersionUsage)
-
-	flag.BoolVar(&d.OutputVersionData, d.OutputVersionName, d.OutputVersionData, d.OutputVersionUsage)
-
-	flag.BoolVar(&d.LicenseData, d.LicenseName, d.LicenseData, d.LicenseUsage)
-	flag.BoolVar(&d.LicenseData, d.LicenseName[0:1], d.LicenseData, d.LicenseUsage)
-
-	flag.BoolVar(&d.ReportData, d.ReportName, d.ReportData, d.ReportUsage)
-	flag.BoolVar(&d.ReportData, d.ReportName[0:1], d.ReportData, d.ReportUsage)
-
-	flag.StringVar(&d.ConfigFileData, d.ConfigFileName, d.ConfigFileData, d.ConfigFileUsage)
-	flag.StringVar(&d.ConfigFileData, d.ConfigFileName[0:1], d.ConfigFileData, d.ConfigFileUsage)
-
-	flag.StringVar(&d.ConfigOutputFileData, d.ConfigOutputFileName, d.ConfigOutputFileData, d.ConfigOutputFileUsage)
-	flag.StringVar(&d.ConfigOutputFileData, d.ConfigOutputFileName[0:1], d.ConfigOutputFileData, d.ConfigOutputFileUsage)
-
-	flag.Usage = func() {
-		_, _ = d.PrintUsage()
-	}
-
-	d.flagSet = true
-}

+ 0 - 111
src/commandlineargs/export.go

@@ -1,111 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package commandlineargs
-
-import (
-	"fmt"
-	"io"
-	"os"
-)
-
-var StopRun = fmt.Errorf("stop run and exit with success")
-
-var isReady = false
-
-func InitCommandLineArgsParser(output io.Writer) (err error) {
-	if IsReady() {
-		return nil
-	}
-
-	defer func() {
-		if e := recover(); e != nil {
-			err = fmt.Errorf("%v", e)
-		}
-	}()
-
-	isReady = false
-
-	initData()
-
-	SetOutput(output)
-
-	isReady = true
-
-	err = helpInfoRun()
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func helpInfoRun() error {
-	var stopFlag = false
-
-	if commandLineArgsData.OutputVersion() {
-		_, _ = commandLineArgsData.PrintOutputVersion()
-		stopFlag = true
-		return StopRun
-	}
-
-	if commandLineArgsData.Version() {
-		_, _ = commandLineArgsData.PrintVersion()
-		stopFlag = true
-	}
-
-	if commandLineArgsData.License() {
-		if stopFlag {
-			_, _ = commandLineArgsData.PrintLF()
-		}
-		_, _ = commandLineArgsData.PrintLicense()
-		stopFlag = true
-	}
-
-	if commandLineArgsData.Report() {
-		if stopFlag {
-			_, _ = commandLineArgsData.PrintLF()
-		}
-		_, _ = commandLineArgsData.PrintReport()
-		stopFlag = true
-	}
-
-	if commandLineArgsData.Help() {
-		if stopFlag {
-			_, _ = commandLineArgsData.PrintLF()
-		}
-		_, _ = commandLineArgsData.PrintUsage()
-		stopFlag = true
-	}
-
-	if stopFlag {
-		return StopRun
-	}
-
-	return nil
-}
-
-func IsReady() bool {
-	return commandLineArgsData.isReady() && isReady
-}
-
-func Name() string {
-	return commandLineArgsData.Name()
-}
-
-func ConfigFile() string {
-	return commandLineArgsData.ConfigFile()
-}
-
-func OutputConfigFile() string {
-	return commandLineArgsData.OutputConfig()
-}
-
-func SetOutput(writer io.Writer) {
-	if writer == nil {
-		writer = os.Stdout
-	}
-
-	commandLineArgsData.SetOutput(writer)
-}

+ 0 - 49
src/commandlineargs/export_data.go

@@ -1,49 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package commandlineargs
-
-import "github.com/SongZihuan/BackendServerTemplate/src/logger"
-
-var commandLineArgsData commandLineArgsDataType
-
-func (d *commandLineArgsDataType) Name() string {
-	if !d.isReady() {
-		logger.Panic("flag not ready")
-	}
-
-	return d.NameData
-}
-
-func (d *commandLineArgsDataType) Help() bool {
-	if !d.isReady() {
-		logger.Panic("flag not ready")
-	}
-
-	return d.HelpData
-}
-
-func (d *commandLineArgsDataType) Version() bool {
-	return getData(d, d.VersionData)
-}
-
-func (d *commandLineArgsDataType) OutputVersion() bool {
-	return getData(d, d.OutputVersionData)
-}
-
-func (d *commandLineArgsDataType) License() bool {
-	return getData(d, d.LicenseData)
-}
-
-func (d *commandLineArgsDataType) Report() bool {
-	return getData(d, d.ReportData)
-}
-
-func (d *commandLineArgsDataType) ConfigFile() string {
-	return getData(d, d.ConfigFileData)
-}
-
-func (d *commandLineArgsDataType) OutputConfig() string {
-	return getData(d, d.ConfigOutputFileData)
-}

+ 0 - 19
src/commandlineargs/export_method.go

@@ -1,19 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package commandlineargs
-
-import (
-	"flag"
-	"io"
-	"os"
-)
-
-func (d *commandLineArgsDataType) SetOutput(writer io.Writer) {
-	if writer == nil {
-		writer = os.Stdout
-	}
-
-	flag.CommandLine.SetOutput(writer)
-}

+ 0 - 81
src/commandlineargs/export_printer.go

@@ -1,81 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package commandlineargs
-
-import (
-	"flag"
-	"fmt"
-	"github.com/SongZihuan/BackendServerTemplate/src/global"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/formatutils"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/osutils"
-	"io"
-	"runtime"
-	"strings"
-	"time"
-)
-
-func (d *commandLineArgsDataType) FprintUsage(writer io.Writer) (int, error) {
-	return fmt.Fprintf(writer, "%s\n", d.Usage)
-}
-
-func (d *commandLineArgsDataType) PrintUsage() (int, error) {
-	return d.FprintUsage(flag.CommandLine.Output())
-}
-
-func (d *commandLineArgsDataType) FprintVersion(writer io.Writer) (int, error) {
-	res := new(strings.Builder)
-	res.WriteString(fmt.Sprintf("Version of %s: %s\n", osutils.GetArgs0Name(), global.Version))
-	res.WriteString(fmt.Sprintf("Build Date (UTC): %s\n", global.BuildTime.In(time.UTC).Format(time.DateTime)))
-	if time.Local != nil && time.Local.String() != time.UTC.String() {
-		zone, _ := time.Now().Local().Zone()
-		res.WriteString(fmt.Sprintf("Build Date (%s): %s\n", zone, global.BuildTime.In(time.Local).Format(time.DateTime)))
-	}
-	res.WriteString(fmt.Sprintf("Compiler: %s\n", runtime.Version()))
-	res.WriteString(fmt.Sprintf("OS: %s\n", runtime.GOOS))
-	res.WriteString(fmt.Sprintf("Arch: %s\n", runtime.GOARCH))
-
-	version := formatutils.FormatTextToWidth(res.String(), formatutils.NormalConsoleWidth)
-	return fmt.Fprintf(writer, "%s\n", version)
-}
-
-func (d *commandLineArgsDataType) PrintVersion() (int, error) {
-	return d.FprintVersion(flag.CommandLine.Output())
-}
-
-func (d *commandLineArgsDataType) FprintOutputVersion(writer io.Writer) (int, error) {
-	return fmt.Fprintf(writer, "%s", global.SemanticVersioning)
-}
-
-func (d *commandLineArgsDataType) PrintOutputVersion() (int, error) {
-	return d.FprintOutputVersion(flag.CommandLine.Output())
-}
-
-func (d *commandLineArgsDataType) FprintLicense(writer io.Writer) (int, error) {
-	title := formatutils.FormatTextToWidth(fmt.Sprintf("License of %s:", osutils.GetArgs0Name()), formatutils.NormalConsoleWidth)
-	license := formatutils.FormatTextToWidth(global.License, formatutils.NormalConsoleWidth)
-	return fmt.Fprintf(writer, "%s\n%s\n", title, license)
-}
-
-func (d *commandLineArgsDataType) PrintLicense() (int, error) {
-	return d.FprintLicense(flag.CommandLine.Output())
-}
-
-func (d *commandLineArgsDataType) FprintReport(writer io.Writer) (int, error) {
-	// 不需要title
-	report := formatutils.FormatTextToWidth(global.Report, formatutils.NormalConsoleWidth)
-	return fmt.Fprintf(writer, "%s\n", report)
-}
-
-func (d *commandLineArgsDataType) PrintReport() (int, error) {
-	return d.FprintReport(flag.CommandLine.Output())
-}
-
-func (d *commandLineArgsDataType) FprintLF(writer io.Writer) (int, error) {
-	return fmt.Fprintf(writer, "\n")
-}
-
-func (d *commandLineArgsDataType) PrintLF() (int, error) {
-	return d.FprintLF(flag.CommandLine.Output())
-}

+ 0 - 206
src/commandlineargs/internal_data_type_method.go

@@ -1,206 +0,0 @@
-// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package commandlineargs
-
-import (
-	"flag"
-	"fmt"
-	"github.com/SongZihuan/BackendServerTemplate/src/logger"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/formatutils"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/osutils"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/reflectutils"
-	"reflect"
-	"strings"
-)
-
-const OptionIdent = "  "
-const OptionPrefix = "--"
-const OptionShortPrefix = "-"
-const UsagePrefixWidth = 10
-
-func (d *commandLineArgsDataType) ready() {
-	if d.isReady() {
-		return
-	}
-
-	d.setFlag()
-	d.writeUsage()
-	d.parser()
-	d.flagReady = true
-}
-
-func (d *commandLineArgsDataType) writeUsage() {
-	if len(d.Usage) != 0 {
-		return
-	}
-
-	var result strings.Builder
-	result.WriteString(formatutils.FormatTextToWidth(fmt.Sprintf("Usage of %s:", osutils.GetArgs0Name()), formatutils.NormalConsoleWidth))
-	result.WriteString("\n")
-
-	val := reflect.ValueOf(*d)
-	typ := val.Type()
-
-	for i := 0; i < val.NumField(); i++ {
-		field := typ.Field(i)
-
-		if !strings.HasSuffix(field.Name, "Data") {
-			continue
-		}
-
-		option := field.Name[:len(field.Name)-4]
-		optionName := ""
-		optionShortName := ""
-		optionUsage := ""
-
-		if reflectutils.HasFieldByReflect(typ, option+"Name") {
-			var ok bool
-			optionName, ok = val.FieldByName(option + "Name").Interface().(string)
-			if !ok {
-				logger.Panic("can not get option name")
-			}
-		}
-
-		if reflectutils.HasFieldByReflect(typ, option+"ShortName") {
-			var ok bool
-			optionShortName, ok = val.FieldByName(option + "ShortName").Interface().(string)
-			if !ok {
-				logger.Panic("can not get option short name")
-			}
-		} else if len(optionName) > 1 {
-			optionShortName = optionName[:1]
-		}
-
-		if reflectutils.HasFieldByReflect(typ, option+"Usage") {
-			var ok bool
-			optionUsage, ok = val.FieldByName(option + "Usage").Interface().(string)
-			if !ok {
-				logger.Panic("can not get option usage")
-			}
-		}
-
-		var title string
-		var title1 string
-		var title2 string
-		if field.Type.Kind() == reflect.Bool {
-			var optionData bool
-			if reflectutils.HasFieldByReflect(typ, option+"Data") {
-				var ok bool
-				optionData, ok = val.FieldByName(option + "Data").Interface().(bool)
-				if !ok {
-					logger.Panic("can not get option data")
-				}
-			}
-
-			if optionData == true {
-				logger.Panic("bool option can not be true")
-			}
-
-			if optionName != "" {
-				title1 = fmt.Sprintf("%s%s%s", OptionIdent, OptionPrefix, formatutils.FormatTextToWidth(optionName, formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			}
-
-			if optionShortName != "" {
-				title2 = fmt.Sprintf("%s%s%s", OptionIdent, OptionShortPrefix, formatutils.FormatTextToWidth(optionShortName, formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			}
-		} else if field.Type.Kind() == reflect.String {
-			var optionData string
-			if reflectutils.HasFieldByReflect(typ, option+"Data") {
-				var ok bool
-				optionData, ok = val.FieldByName(option + "Data").Interface().(string)
-				if !ok {
-					logger.Panic("can not get option data")
-				}
-			}
-
-			if optionName != "" && optionData != "" {
-				title1 = fmt.Sprintf("%s%s%s", OptionIdent, OptionPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s string, default: '%s'", optionName, optionData), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			} else if optionName != "" && optionData == "" {
-				title1 = fmt.Sprintf("%s%s%s", OptionIdent, OptionPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s string", optionName), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			}
-
-			if optionShortName != "" && optionData != "" {
-				title2 = fmt.Sprintf("%s%s%s", OptionIdent, OptionShortPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s string, default: '%s'", optionShortName, optionData), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			} else if optionShortName != "" && optionData == "" {
-				title2 = fmt.Sprintf("%s%s%s", OptionIdent, OptionShortPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s string", optionShortName), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			}
-		} else if field.Type.Kind() == reflect.Uint || field.Type.Kind() == reflect.Int {
-			var optionData uint
-			if reflectutils.HasFieldByReflect(typ, option+"Data") {
-				var ok bool
-				optionData, ok = val.FieldByName(option + "Data").Interface().(uint)
-				if !ok {
-					logger.Panic("can not get option data")
-				}
-			}
-
-			if optionName != "" && optionData != 0 {
-				title1 = fmt.Sprintf("%s%s%s", OptionIdent, OptionPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s number, default: %d", optionName, optionData), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			} else if optionName != "" && optionData == 0 {
-				title1 = fmt.Sprintf("%s%s%s", OptionIdent, OptionPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s number", optionName), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			}
-
-			if optionShortName != "" && optionData != 0 {
-				title2 = fmt.Sprintf("%s%s%s", OptionIdent, OptionShortPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s number, default: %d", optionShortName, optionData), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			} else if optionShortName != "" && optionData == 0 {
-				title2 = fmt.Sprintf("%s%s%s", OptionIdent, OptionShortPrefix, formatutils.FormatTextToWidth(fmt.Sprintf("%s number", optionShortName), formatutils.NormalConsoleWidth-len(OptionIdent)-len(OptionPrefix)))
-			}
-		} else {
-			logger.Panic(fmt.Sprintf("the flag type (%s) is not support", field.Type.Name()))
-		}
-
-		if title1 == "" && title2 == "" {
-			continue
-		} else if title1 != "" && title2 == "" {
-			title = title1
-		} else if title1 == "" {
-			title = title2
-		} else {
-			title = fmt.Sprintf("%s\n%s", title1, title2)
-		}
-
-		result.WriteString(title)
-		result.WriteString("\n")
-
-		usage := formatutils.FormatTextToWidthAndPrefix(optionUsage, UsagePrefixWidth, formatutils.NormalConsoleWidth)
-		result.WriteString(usage)
-		result.WriteString("\n\n")
-	}
-
-	d.Usage = strings.TrimRight(result.String(), "\n")
-}
-
-func (d *commandLineArgsDataType) parser() {
-	if d.flagParser {
-		return
-	}
-
-	if !d.isFlagSet() {
-		logger.Panic("flag not set")
-	}
-
-	flag.Parse()
-	d.flagParser = true
-}
-
-func (d *commandLineArgsDataType) isReady() bool {
-	return d.isFlagSet() && d.isFlagParser() && d.flagReady
-}
-
-func (d *commandLineArgsDataType) isFlagSet() bool {
-	return d.flagSet
-}
-
-func (d *commandLineArgsDataType) isFlagParser() bool {
-	return d.flagParser
-}
-
-func getData[T any](d *commandLineArgsDataType, data T) T { // 泛型函数无法作为 “方法” 只能作为函数
-	if !d.isReady() {
-		logger.Panic("flag not ready")
-	}
-
-	return data
-}

+ 5 - 7
src/config/global_config.go

@@ -5,10 +5,11 @@
 package config
 
 import (
-	"github.com/SongZihuan/BackendServerTemplate/src/commandlineargs"
+	"github.com/SongZihuan/BackendServerTemplate/src/cmdparser/root"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configerror"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configparser"
 	"github.com/SongZihuan/BackendServerTemplate/src/global"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/cleanstringutils"
 	"strings"
 	"time"
 )
@@ -65,14 +66,11 @@ func (d *GlobalConfig) check(c *configInfo) configerror.Error {
 }
 
 func (d *GlobalConfig) process(c *configInfo) (cfgErr configerror.Error) {
-	if commandlineargs.Name() != "" {
-		global.Name = commandlineargs.Name()
-	} else if d.Name != "" {
-		global.Name = d.Name
+	name := cleanstringutils.GetStringOneLine(d.Name)
+	if (!root.NameChanged() || global.Name == "") && name != "" {
+		global.Name = name
 	}
 
-	d.Name = global.Name
-
 	var location *time.Location
 	if strings.ToLower(d.Timezone) == "utc" {
 		location = time.UTC

+ 1 - 10
src/global/service.go

@@ -6,13 +6,4 @@ package global
 
 import resource "github.com/SongZihuan/BackendServerTemplate"
 
-var ServiceConfig = resource.ServiceConfig
-
-const (
-	Args1Install    = resource.Args1Install
-	Args1Uninstall1 = resource.Args1Uninstall1
-	Args1Uninstall2 = resource.Args1Uninstall2
-	Args1Start      = resource.Args1Start
-	Args1Stop       = resource.Args1Stop
-	Args1Restart    = resource.Args1Restart
-)
+var ServiceConfigYamlData = resource.ServiceConfigYamlData

+ 1 - 1
src/global/variabl.go

@@ -20,7 +20,7 @@ var (
 	GitTag             = resource.GitTag
 	GitTagCommitHash   = resource.GitTagCommitHash
 
-	// Name 继承自resource(程序init完成后即可调用)
+	// Name 继承自resource
 	// 注意:命令行参数或配置文件加载时可能会被更改
 	Name = resource.Name
 )

+ 126 - 0
src/mainfunc/cat/v1/config.go

@@ -0,0 +1,126 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package v1
+
+import (
+	"fmt"
+	"github.com/SongZihuan/BackendServerTemplate/src/global"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/cleanstringutils"
+	"github.com/SongZihuan/BackendServerTemplate/src/utils/sliceutils"
+	"gopkg.in/yaml.v3"
+	"os"
+	"regexp"
+)
+
+const (
+	FromNo      = "no"
+	FromInstall = "install"
+	FromConfig  = "config"
+)
+
+type ServiceConfigType struct {
+	Name         string            `yaml:"name,omitempty"`
+	DisplayName  string            `yaml:"display-name,omitempty"`
+	Describe     string            `yaml:"describe,omitempty"`
+	ArgumentFrom string            `yaml:"argument-from,omitempty"`
+	ArgumentList []string          `yaml:"argument-list,omitempty"`
+	EnvFrom      string            `yaml:"env-from,omitempty"`
+	EnvGetList   []string          `yaml:"env-get-list,omitempty"`
+	EnvSetList   map[string]string `yaml:"env-set-list,omitempty"`
+}
+
+var serviceConfigYamlData = global.ServiceConfigYamlData
+var serviceConfig ServiceConfigType
+
+var nameRegex = regexp.MustCompilePOSIX(`^[a-zA-Z0-9]+$`)
+
+func initInstallServiceConfig(args []string) error {
+	err := yaml.Unmarshal(serviceConfigYamlData, &serviceConfig)
+	if err != nil {
+		return err
+	}
+
+	if serviceConfig.Name == "" || !nameRegex.MatchString(serviceConfig.Name) {
+		return fmt.Errorf("service name is invalid")
+	}
+
+	if serviceConfig.DisplayName == "" {
+		serviceConfig.DisplayName = serviceConfig.Name
+	}
+
+	serviceConfig.Describe = cleanstringutils.GetStringOneLine(serviceConfig.Describe)
+
+	switch serviceConfig.ArgumentFrom {
+	case FromInstall:
+		if len(args) > 0 {
+			serviceConfig.ArgumentFrom = FromConfig
+			serviceConfig.ArgumentList = sliceutils.CopySlice(args)
+		} else {
+			serviceConfig.ArgumentFrom = FromNo
+			serviceConfig.ArgumentList = nil
+		}
+	case FromConfig:
+		if len(serviceConfig.ArgumentList) == 0 {
+			serviceConfig.ArgumentFrom = FromNo
+			serviceConfig.ArgumentList = nil
+		}
+	default:
+		serviceConfig.ArgumentFrom = FromNo
+		serviceConfig.ArgumentList = nil
+	}
+
+	switch serviceConfig.EnvFrom {
+	case FromInstall:
+		if len(serviceConfig.EnvGetList) == 0 {
+			serviceConfig.EnvFrom = FromNo
+			serviceConfig.EnvGetList = nil
+			serviceConfig.EnvSetList = nil
+			break
+		}
+
+		serviceConfig.EnvSetList = make(map[string]string, len(serviceConfig.EnvGetList))
+		for _, e := range serviceConfig.EnvGetList {
+			serviceConfig.EnvSetList[e] = os.Getenv(e)
+		}
+	case FromConfig:
+		serviceConfig.EnvGetList = nil
+		if len(serviceConfig.EnvSetList) == 0 {
+			serviceConfig.EnvFrom = FromNo
+			serviceConfig.EnvSetList = nil
+		}
+	default:
+		serviceConfig.EnvFrom = FromNo
+		serviceConfig.EnvGetList = nil
+		serviceConfig.EnvSetList = nil
+	}
+
+	return nil
+}
+
+func initServiceConfig() error {
+	err := yaml.Unmarshal(serviceConfigYamlData, &serviceConfig)
+	if err != nil {
+		return err
+	}
+
+	if serviceConfig.Name == "" || !nameRegex.MatchString(serviceConfig.Name) {
+		return fmt.Errorf("service name is invalid")
+	}
+
+	if serviceConfig.DisplayName == "" {
+		serviceConfig.DisplayName = serviceConfig.Name
+	}
+
+	serviceConfig.Describe = cleanstringutils.GetStringOneLine(serviceConfig.Describe)
+
+	serviceConfig.ArgumentFrom = FromNo
+	serviceConfig.ArgumentList = nil
+
+	serviceConfig.EnvFrom = FromNo
+	serviceConfig.EnvGetList = nil
+	serviceConfig.EnvSetList = nil
+
+	return nil
+}

+ 94 - 0
src/mainfunc/cat/v1/config_test.go

@@ -0,0 +1,94 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package v1
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func testNormalServiceConfig(t *testing.T) {
+	if serviceConfig.Name == "" {
+		t.Errorf("Service name is empty")
+	}
+
+	if serviceConfig.DisplayName == "" {
+		t.Errorf("Service display name is empty")
+	}
+
+	if strings.Contains(serviceConfig.Describe, "\n") {
+		t.Errorf("Service describe has LF")
+	}
+
+	if strings.Contains(serviceConfig.Describe, "\r") {
+		t.Errorf("Service describe has CR")
+	}
+
+	if len(serviceConfig.Describe) > 1 && serviceConfig.Describe[0] == ' ' {
+		t.Errorf("Service describe start with space")
+	}
+
+	if len(serviceConfig.Describe) > 2 && serviceConfig.Describe[len(serviceConfig.Describe)-1] == ' ' {
+		t.Errorf("Service describe end with space")
+	}
+}
+
+func TestNormalServiceConfig(t *testing.T) {
+	err := initServiceConfig()
+
+	if err != nil {
+		t.Fatalf("Init service error: %s", err.Error())
+	}
+
+	testNormalServiceConfig(t)
+
+	if serviceConfig.ArgumentFrom != FromNo {
+		t.Errorf("ArgumentFrom should be no")
+	} else if len(serviceConfig.ArgumentList) != 0 {
+		t.Errorf("ArgumentList should be empty")
+	}
+
+	if serviceConfig.EnvFrom != FromNo {
+		t.Errorf("EnvFrom should be no")
+	} else if len(serviceConfig.EnvSetList) != 0 {
+		t.Errorf("EnvSetList should be empty")
+	}
+}
+
+func TestInstallServiceConfig(t *testing.T) {
+	err := initServiceConfig()
+	if err != nil {
+		t.Fatalf("Init service error: %s", err.Error())
+	}
+
+	testNormalServiceConfig(t)
+
+	switch serviceConfig.ArgumentFrom {
+	case FromConfig:
+		if len(serviceConfig.ArgumentList) == 0 {
+			t.Errorf("Error argument-from: argument-list is empty, but argument-from config")
+		}
+	case FromNo:
+		if len(serviceConfig.ArgumentList) > 0 {
+			t.Errorf("Error argument-from: argument-list is not empty, but argument-from no")
+		}
+	default:
+		t.Errorf(fmt.Sprintf("Error argument-from: %s", serviceConfig.ArgumentFrom))
+	}
+
+	switch serviceConfig.EnvFrom {
+	case FromConfig:
+		if len(serviceConfig.EnvSetList) == 0 {
+			t.Errorf("Error env-from: env-set-list is empty, but env-from config")
+		}
+	case FromNo:
+		if len(serviceConfig.EnvSetList) > 0 {
+			t.Errorf("Error env-from: env-set-list is not empty, but env-from no")
+		}
+	default:
+		t.Errorf(fmt.Sprintf("Error argument-from: %s", serviceConfig.EnvFrom))
+	}
+}

+ 203 - 68
src/mainfunc/cat/v1/main.go

@@ -5,38 +5,33 @@
 package v1
 
 import (
-	"github.com/SongZihuan/BackendServerTemplate/src/global"
-	"github.com/SongZihuan/BackendServerTemplate/src/logger"
-	"github.com/SongZihuan/BackendServerTemplate/src/logger/loglevel"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/consoleutils"
+	"github.com/SongZihuan/BackendServerTemplate/src/cmd/globalmain"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
 	"github.com/kardianos/service"
-	"os"
-	"strings"
+	"github.com/spf13/cobra"
 )
 
-func MainV1() (exitCode exitutils.ExitCode) {
+func MainV1(cmd *cobra.Command, args []string) (exitCode error) {
 	var err error
 
-	err = consoleutils.SetConsoleCPSafe(consoleutils.CodePageUTF8)
+	err = globalmain.PreRun()
 	if err != nil {
-		return exitutils.InitFailedErrorForWin32ConsoleModule(err.Error())
+		return err
 	}
+	defer globalmain.PostRun()
 
-	err = logger.InitBaseLogger(loglevel.LevelDebug, true, nil, nil, nil, nil)
+	err = initServiceConfig()
 	if err != nil {
-		return exitutils.InitFailedErrorForLoggerModule(err.Error())
+		return exitutils.InitFailedError("service config", err.Error())
 	}
-	defer logger.CloseLogger()
-	defer logger.Recover()
 
 	// 定义服务配置
 	svcConfig := &service.Config{
-		Name:        global.ServiceConfig.Name,
-		DisplayName: global.ServiceConfig.DisplayName,
-		Description: global.ServiceConfig.Describe,
-		Arguments:   global.ServiceConfig.ArgumentList,
-		EnvVars:     global.ServiceConfig.EnvSetList,
+		Name:        serviceConfig.Name,
+		DisplayName: serviceConfig.DisplayName,
+		Description: serviceConfig.Describe,
+		Arguments:   serviceConfig.ArgumentList,
+		EnvVars:     serviceConfig.EnvSetList,
 	}
 
 	prg := NewProgram()
@@ -45,56 +40,196 @@ func MainV1() (exitCode exitutils.ExitCode) {
 		return exitutils.InitFailedError("Service New", err.Error())
 	}
 
-	// 解析命令行参数
-	if len(os.Args) > 1 {
-		cmd := os.Args[1]
-		switch strings.ToLower(cmd) {
-		case global.Args1Install:
-			// 安装服务
-			err = s.Install()
-			if err != nil {
-				return exitutils.InitFailedError("Service Install", err.Error())
-			}
-
-			return exitutils.SuccessExitSimple("Service Install Success")
-		case global.Args1Uninstall1, global.Args1Uninstall2:
-			// 卸载服务
-			err = s.Uninstall()
-			if err != nil {
-				return exitutils.InitFailedError("Service Remove", err.Error())
-			}
-
-			return exitutils.SuccessExitSimple("Service Remove Success")
-		case global.Args1Start:
-			// 启动服务
-			err = s.Start()
-			if err != nil {
-				return exitutils.InitFailedError("Service Start", err.Error())
-			}
-
-			return exitutils.SuccessExitSimple("Service Start Success")
-		case global.Args1Stop:
-			// 停止服务
-			err = s.Stop()
-			if err != nil {
-				return exitutils.InitFailedError("Service Stop", err.Error())
-			}
-
-			return exitutils.SuccessExitSimple("Service Stop Success")
-		case global.Args1Restart:
-			// 重启服务
-			err = s.Restart()
-			if err != nil {
-				return exitutils.InitFailedError("Service Restart", err.Error())
-			}
-
-			return exitutils.SuccessExitSimple("Service Restart Success")
-		default:
-			// 正常运行服务
-			// pass
-		}
-	}
-
 	_ = s.Run()
 	return prg.ExitCode()
 }
+
+func MainV1Install(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
+
+	err = globalmain.PreRun()
+	if err != nil {
+		return err
+	}
+	defer globalmain.PostRun()
+
+	err = initInstallServiceConfig(args)
+	if err != nil {
+		return exitutils.InitFailedError("service config", err.Error())
+	}
+
+	// 定义服务配置
+	svcConfig := &service.Config{
+		Name:        serviceConfig.Name,
+		DisplayName: serviceConfig.DisplayName,
+		Description: serviceConfig.Describe,
+		Arguments:   serviceConfig.ArgumentList,
+		EnvVars:     serviceConfig.EnvSetList,
+	}
+
+	prg := NewProgram()
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		return exitutils.InitFailedError("Service New", err.Error())
+	}
+
+	// 安装服务
+	err = s.Install()
+	if err != nil {
+		return exitutils.InitFailedError("Service Install", err.Error())
+	}
+
+	return exitutils.SuccessExitSimple("Service Install Success")
+}
+
+func MainV1UnInstall(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
+
+	err = globalmain.PreRun()
+	if err != nil {
+		return err
+	}
+	defer globalmain.PostRun()
+
+	err = initServiceConfig()
+	if err != nil {
+		return exitutils.InitFailedError("service config", err.Error())
+	}
+
+	// 定义服务配置
+	svcConfig := &service.Config{
+		Name:        serviceConfig.Name,
+		DisplayName: serviceConfig.DisplayName,
+		Description: serviceConfig.Describe,
+		Arguments:   serviceConfig.ArgumentList,
+		EnvVars:     serviceConfig.EnvSetList,
+	}
+
+	prg := NewProgram()
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		return exitutils.InitFailedError("Service New", err.Error())
+	}
+
+	// 卸载服务
+	err = s.Uninstall()
+	if err != nil {
+		return exitutils.InitFailedError("Service Remove", err.Error())
+	}
+
+	return exitutils.SuccessExitSimple("Service Remove Success")
+}
+
+func MainV1Start(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
+
+	err = globalmain.PreRun()
+	if err != nil {
+		return err
+	}
+	defer globalmain.PostRun()
+
+	err = initServiceConfig()
+	if err != nil {
+		return exitutils.InitFailedError("service config", err.Error())
+	}
+
+	// 定义服务配置
+	svcConfig := &service.Config{
+		Name:        serviceConfig.Name,
+		DisplayName: serviceConfig.DisplayName,
+		Description: serviceConfig.Describe,
+		Arguments:   serviceConfig.ArgumentList,
+		EnvVars:     serviceConfig.EnvSetList,
+	}
+
+	prg := NewProgram()
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		return exitutils.InitFailedError("Service New", err.Error())
+	}
+
+	// 启动服务
+	err = s.Start()
+	if err != nil {
+		return exitutils.InitFailedError("Service Start", err.Error())
+	}
+
+	return exitutils.SuccessExitSimple("Service Start Success")
+}
+
+func MainV1Stop(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
+
+	err = globalmain.PreRun()
+	if err != nil {
+		return err
+	}
+	defer globalmain.PostRun()
+
+	err = initServiceConfig()
+	if err != nil {
+		return exitutils.InitFailedError("service config", err.Error())
+	}
+
+	// 定义服务配置
+	svcConfig := &service.Config{
+		Name:        serviceConfig.Name,
+		DisplayName: serviceConfig.DisplayName,
+		Description: serviceConfig.Describe,
+		Arguments:   serviceConfig.ArgumentList,
+		EnvVars:     serviceConfig.EnvSetList,
+	}
+
+	prg := NewProgram()
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		return exitutils.InitFailedError("Service New", err.Error())
+	}
+
+	// 停止服务
+	err = s.Stop()
+	if err != nil {
+		return exitutils.InitFailedError("Service Stop", err.Error())
+	}
+
+	return exitutils.SuccessExitSimple("Service Stop Success")
+}
+
+func MainV1Restart(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
+
+	err = globalmain.PreRun()
+	if err != nil {
+		return err
+	}
+	defer globalmain.PostRun()
+
+	err = initServiceConfig()
+	if err != nil {
+		return exitutils.InitFailedError("service config", err.Error())
+	}
+
+	// 定义服务配置
+	svcConfig := &service.Config{
+		Name:        serviceConfig.Name,
+		DisplayName: serviceConfig.DisplayName,
+		Description: serviceConfig.Describe,
+		Arguments:   serviceConfig.ArgumentList,
+		EnvVars:     serviceConfig.EnvSetList,
+	}
+
+	prg := NewProgram()
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		return exitutils.InitFailedError("Service New", err.Error())
+	}
+
+	// 重启服务
+	err = s.Restart()
+	if err != nil {
+		return exitutils.InitFailedError("Service Restart", err.Error())
+	}
+
+	return exitutils.SuccessExitSimple("Service Restart Success")
+}

+ 6 - 13
src/mainfunc/cat/v1/service.go

@@ -6,7 +6,6 @@ package v1
 
 import (
 	"errors"
-	"github.com/SongZihuan/BackendServerTemplate/src/commandlineargs"
 	"github.com/SongZihuan/BackendServerTemplate/src/config"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configparser"
 	"github.com/SongZihuan/BackendServerTemplate/src/consolewatcher"
@@ -21,6 +20,9 @@ import (
 	"os"
 )
 
+var InputConfigFilePath string = "config.yaml"
+var OutputConfigFilePath string = ""
+
 type Program struct {
 	sigchan             chan os.Signal
 	consolechan         chan consoleutils.Event
@@ -35,20 +37,11 @@ func NewProgram() *Program {
 }
 
 func (p *Program) Start(s service.Service) error {
-	err := commandlineargs.InitCommandLineArgsParser(nil)
-	if err != nil {
-		if errors.Is(err, commandlineargs.StopRun) {
-			p.exitCode = exitutils.SuccessExitQuite()
-			return err
-		}
-
-		p.exitCode = exitutils.InitFailedError("Command Line Args Parser", err.Error())
-		return err
-	}
+	var err error
 
 	err = config.InitConfig(&config.ConfigOption{
-		ConfigFilePath: commandlineargs.ConfigFile(),
-		OutputFilePath: commandlineargs.OutputConfigFile(),
+		ConfigFilePath: InputConfigFilePath,
+		OutputFilePath: OutputConfigFilePath,
 		Provider:       configparser.NewYamlProvider(),
 	})
 	if err != nil {

+ 11 - 24
src/mainfunc/lion/v1/main.go

@@ -6,48 +6,35 @@ package v1
 
 import (
 	"errors"
-	"github.com/SongZihuan/BackendServerTemplate/src/commandlineargs"
+	"github.com/SongZihuan/BackendServerTemplate/src/cmd/globalmain"
 	"github.com/SongZihuan/BackendServerTemplate/src/config"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configparser"
 	"github.com/SongZihuan/BackendServerTemplate/src/consolewatcher"
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
-	"github.com/SongZihuan/BackendServerTemplate/src/logger/loglevel"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/controller"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/example1"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/example2"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/signalwatcher"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/consoleutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
+	"github.com/spf13/cobra"
 )
 
-func MainV1() (exitCode exitutils.ExitCode) {
-	var err error
+var InputConfigFilePath string = "config.yaml"
+var OutputConfigFilePath string = ""
 
-	err = consoleutils.SetConsoleCPSafe(consoleutils.CodePageUTF8)
-	if err != nil {
-		return exitutils.InitFailedErrorForWin32ConsoleModule(err.Error())
-	}
-
-	err = logger.InitBaseLogger(loglevel.LevelDebug, true, nil, nil, nil, nil)
-	if err != nil {
-		return exitutils.InitFailedErrorForLoggerModule(err.Error())
-	}
-	defer logger.CloseLogger()
-	defer logger.Recover()
+func MainV1(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
 
-	err = commandlineargs.InitCommandLineArgsParser(nil)
+	err = globalmain.PreRun()
 	if err != nil {
-		if errors.Is(err, commandlineargs.StopRun) {
-			return exitutils.SuccessExitQuite()
-		}
-
-		return exitutils.InitFailedError("Command Line Args Parser", err.Error())
+		return err
 	}
+	defer globalmain.PostRun()
 
 	err = config.InitConfig(&config.ConfigOption{
-		ConfigFilePath: commandlineargs.ConfigFile(),
-		OutputFilePath: commandlineargs.OutputConfigFile(),
+		ConfigFilePath: InputConfigFilePath,
+		OutputFilePath: OutputConfigFilePath,
 		Provider:       configparser.NewYamlProvider(),
 	})
 	if err != nil {

+ 11 - 24
src/mainfunc/tiger/v1/main.go

@@ -6,46 +6,33 @@ package v1
 
 import (
 	"errors"
-	"github.com/SongZihuan/BackendServerTemplate/src/commandlineargs"
+	"github.com/SongZihuan/BackendServerTemplate/src/cmd/globalmain"
 	"github.com/SongZihuan/BackendServerTemplate/src/config"
 	"github.com/SongZihuan/BackendServerTemplate/src/config/configparser"
 	"github.com/SongZihuan/BackendServerTemplate/src/consolewatcher"
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
-	"github.com/SongZihuan/BackendServerTemplate/src/logger/loglevel"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/example1"
 	"github.com/SongZihuan/BackendServerTemplate/src/server/servercontext"
 	"github.com/SongZihuan/BackendServerTemplate/src/signalwatcher"
-	"github.com/SongZihuan/BackendServerTemplate/src/utils/consoleutils"
 	"github.com/SongZihuan/BackendServerTemplate/src/utils/exitutils"
+	"github.com/spf13/cobra"
 )
 
-func MainV1() (exitCode exitutils.ExitCode) {
-	var err error
+var InputConfigFilePath string = "config.yaml"
+var OutputConfigFilePath string = ""
 
-	err = consoleutils.SetConsoleCPSafe(consoleutils.CodePageUTF8)
-	if err != nil {
-		return exitutils.InitFailedErrorForWin32ConsoleModule(err.Error())
-	}
-
-	err = logger.InitBaseLogger(loglevel.LevelDebug, true, nil, nil, nil, nil)
-	if err != nil {
-		return exitutils.InitFailedErrorForLoggerModule(err.Error())
-	}
-	defer logger.CloseLogger()
-	defer logger.Recover()
+func MainV1(cmd *cobra.Command, args []string) (exitCode error) {
+	var err error
 
-	err = commandlineargs.InitCommandLineArgsParser(nil)
+	err = globalmain.PreRun()
 	if err != nil {
-		if errors.Is(err, commandlineargs.StopRun) {
-			return exitutils.SuccessExitQuite()
-		}
-
-		return exitutils.InitFailedError("Command Line Args Parser", err.Error())
+		return err
 	}
+	defer globalmain.PostRun()
 
 	err = config.InitConfig(&config.ConfigOption{
-		ConfigFilePath: commandlineargs.ConfigFile(),
-		OutputFilePath: commandlineargs.OutputConfigFile(),
+		ConfigFilePath: InputConfigFilePath,
+		OutputFilePath: OutputConfigFilePath,
 		Provider:       configparser.NewYamlProvider(),
 	})
 	if err != nil {

+ 14 - 0
src/utils/cleanstringutils/oneline.go

@@ -0,0 +1,14 @@
+// Copyright 2025 BackendServerTemplate Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package cleanstringutils
+
+import "strings"
+
+func GetStringOneLine(data string) (res string) {
+	res = strings.Replace(data, "\r", "", -1)
+	res = strings.Split(res, "\n")[0]
+	res = strings.TrimSpace(res)
+	return res
+}

+ 33 - 8
src/utils/exitutils/exit.go

@@ -5,14 +5,19 @@
 package exitutils
 
 import (
+	"errors"
 	"fmt"
 	"github.com/SongZihuan/BackendServerTemplate/src/logger"
 	"log"
+	"os"
 )
 
 const (
 	exitCodeMin                 = 0
 	exitCodeMax                 = 255
+	exitCodeDefaultSuccess      = 0
+	exitCodeDefaultError        = 1
+	exitWithUnknownError        = 253
 	exitCodeErrorLogMustBeReady = 254
 )
 
@@ -45,7 +50,7 @@ func InitFailedErrorForWin32ConsoleModule(reason string, exitCode ...int) ExitCo
 		reason = "no reason"
 	}
 
-	ec := getExitCode(1, exitCode...)
+	ec := getExitCode(exitCodeDefaultError, exitCode...)
 
 	log.Printf("The module `Win32 Console` init failed (reason: `%s`) .", reason)
 	log.Printf("Now we should exit with code %d.", ec)
@@ -58,7 +63,7 @@ func InitFailedErrorForLoggerModule(reason string, exitCode ...int) ExitCode {
 		reason = "no reason"
 	}
 
-	ec := getExitCode(1, exitCode...)
+	ec := getExitCode(exitCodeDefaultError, exitCode...)
 
 	log.Printf("The module `Logger` init failed (reason: `%s`) .", reason)
 	log.Printf("Now we should exit with code %d.", ec)
@@ -75,7 +80,7 @@ func InitFailedError(module string, reason string, exitCode ...int) ExitCode {
 		reason = "no reason"
 	}
 
-	ec := getExitCode(1, exitCode...)
+	ec := getExitCode(exitCodeDefaultError, exitCode...)
 
 	logger.Errorf("The module `%s` init failed (reason: `%s`) .", module, reason)
 	logger.Errorf("Now we should exit with code %d.", ec)
@@ -87,7 +92,7 @@ func RunErrorQuite(exitCode ...int) ExitCode {
 	if !logger.IsReady() {
 		return exitCodeErrorLogMustBeReady
 	}
-	return getExitCode(1, exitCode...)
+	return getExitCode(exitCodeDefaultError, exitCode...)
 }
 
 func RunError(reason string, exitCode ...int) ExitCode {
@@ -99,7 +104,7 @@ func RunError(reason string, exitCode ...int) ExitCode {
 		reason = "no reason"
 	}
 
-	ec := getExitCode(1, exitCode...)
+	ec := getExitCode(exitCodeDefaultError, exitCode...)
 
 	logger.Errorf("Run error (reason: `%s`) .", reason)
 	logger.Errorf("Now we should exit with code %d.", ec)
@@ -116,7 +121,7 @@ func SuccessExit(reason string, exitCode ...int) ExitCode {
 		reason = "no reason"
 	}
 
-	ec := getExitCode(0, exitCode...)
+	ec := getExitCode(exitCodeDefaultSuccess, exitCode...)
 
 	logger.Warnf("Now we should exit with code %d (reason: %s) .", ec, reason)
 
@@ -127,7 +132,7 @@ func SuccessExitSimple(reason string, exitCode ...int) ExitCode {
 	if reason != "" {
 		fmt.Println(reason)
 	}
-	return getExitCode(0, exitCode...)
+	return getExitCode(exitCodeDefaultSuccess, exitCode...)
 }
 
 func SuccessExitQuite(exitCode ...int) ExitCode {
@@ -135,7 +140,27 @@ func SuccessExitQuite(exitCode ...int) ExitCode {
 		return exitCodeErrorLogMustBeReady
 	}
 
-	ec := getExitCode(0, exitCode...)
+	ec := getExitCode(exitCodeDefaultSuccess, exitCode...)
 
 	return ec
 }
+
+func Exit(err error) {
+	var ec ExitCode
+	if err == nil {
+		os.Exit(exitCodeDefaultSuccess)
+	} else if errors.As(err, &ec) {
+		ExitByCode(ec)
+	} else {
+		if logger.IsReady() {
+			logger.Warnf("Now we should exit with code %d (reason: %s) .", ec, err.Error())
+		} else {
+			log.Printf("Now we should exit with code %d (reason: %s) .", ec, err.Error())
+		}
+		os.Exit(exitCodeDefaultError)
+	}
+}
+
+func ExitByCode(ec ExitCode) {
+	os.Exit(int(ec))
+}

+ 10 - 2
src/utils/osutils/export.go

@@ -7,10 +7,12 @@ package osutils
 import (
 	"os"
 	"path/filepath"
+	"strings"
 )
 
 var _args0 = ""
 var _args0Name = ""
+var _args0NamePosix = ""
 
 func init() {
 	var err error
@@ -24,13 +26,19 @@ func init() {
 	}
 
 	if _args0 == "" {
-		panic("args 0 was empty")
+		panic("_args0 was empty")
 	}
 
 	_args0Name = filepath.Base(_args0)
 
 	if _args0Name == "" {
-		panic("args 0 was empty")
+		panic("_args0Name was empty")
+	}
+
+	_args0NamePosix = strings.TrimSuffix(_args0Name, ".exe")
+
+	if _args0NamePosix == "" {
+		panic("_args0NamePosix was empty")
 	}
 }