Browse Source

Merge pull request #842 from 0xJacky/feat/cli

feat: new command system
Jacky 4 months ago
parent
commit
d2e7dd500d
13 changed files with 192 additions and 53 deletions
  1. 12 6
      .github/workflows/build.yml
  2. 1 0
      .gitignore
  3. 4 2
      api/cluster/node.go
  4. 5 9
      api/system/upgrade.go
  5. 0 2
      app/app.go
  6. 1 3
      app/app_unembed.go
  7. 81 0
      cmd/version/generate.go
  8. 5 4
      go.mod
  9. 2 4
      go.sum
  10. 50 0
      internal/cmd/main.go
  11. 0 18
      internal/upgrader/info.go
  12. 26 0
      internal/version/version.go
  13. 5 5
      main.go

+ 12 - 6
.github/workflows/build.yml

@@ -142,6 +142,18 @@ jobs:
         with:
           go-version: ^1.23.0
 
+      - name: Download app artifacts
+        uses: actions/download-artifact@v4
+        with:
+          name: app-dist
+          path: app/dist
+
+      - name: Generate files
+        env:
+          GOOS: linux
+          GOARCH: amd64
+        run: go generate
+
       - name: Setup compiler environment
         id: info
         run: |
@@ -182,12 +194,6 @@ jobs:
           echo "CXX=${{ env.ARCH_NAME }}-clang++" >> $GITHUB_ENV
           echo "LD_FLAGS=-w" >> $GITHUB_ENV
 
-      - name: Download app artifacts
-        uses: actions/download-artifact@v4
-        with:
-          name: app-dist
-          path: app/dist
-
       - name: Build
         run: |
           mkdir -p dist

+ 1 - 0
.gitignore

@@ -14,6 +14,7 @@ app/.env
 app/.status_hash
 .idea/deployment.xml
 .idea/webServers.xml
+*.gen.go
 .devcontainer/go-path
 .devcontainer/data
 .devcontainer/casdoor.pem

+ 4 - 2
api/cluster/node.go

@@ -1,14 +1,16 @@
 package cluster
 
 import (
+	"net/http"
+
 	"github.com/0xJacky/Nginx-UI/api"
 	analytic2 "github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/upgrader"
+	"github.com/0xJacky/Nginx-UI/internal/version"
 	"github.com/dustin/go-humanize"
 	"github.com/gin-gonic/gin"
 	"github.com/shirou/gopsutil/v4/cpu"
 	"github.com/shirou/gopsutil/v4/disk"
-	"net/http"
 )
 
 func GetCurrentNode(c *gin.Context) {
@@ -26,7 +28,7 @@ func GetCurrentNode(c *gin.Context) {
 	}
 	cpuInfo, _ := cpu.Info()
 	memory, _ := analytic2.GetMemoryStat()
-	ver, _ := upgrader.GetCurrentVersion()
+	ver := version.GetVersionInfo()
 	diskUsage, _ := disk.Usage(".")
 
 	nodeInfo := analytic2.NodeInfo{

+ 5 - 9
api/system/upgrade.go

@@ -1,14 +1,16 @@
 package system
 
 import (
+	"net/http"
+	"os"
+
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/upgrader"
+	"github.com/0xJacky/Nginx-UI/internal/version"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/gorilla/websocket"
 	"github.com/uozi-tech/cosy/logger"
-	"net/http"
-	"os"
 )
 
 func GetRelease(c *gin.Context) {
@@ -32,13 +34,7 @@ func GetRelease(c *gin.Context) {
 }
 
 func GetCurrentVersion(c *gin.Context) {
-	curVer, err := upgrader.GetCurrentVersion()
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, curVer)
+	c.JSON(http.StatusOK, version.GetVersionInfo())
 }
 
 const (

+ 0 - 2
app/app.go

@@ -8,5 +8,3 @@ import (
 
 //go:embed i18n.json dist/* dist/*/* src/language/* src/language/*/*
 var DistFS embed.FS
-
-var VersionPath = "dist/version.json"

+ 1 - 3
app/app_unembed.go

@@ -4,7 +4,5 @@ package app
 
 import "embed"
 
-//go:embed i18n.json src/language/* src/language/*/* src/version.json
+//go:embed i18n.json src/language/* src/language/*/*
 var DistFS embed.FS
-
-var VersionPath = "src/version.json"

+ 81 - 0
cmd/version/generate.go

@@ -0,0 +1,81 @@
+package main
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io"
+	"io/fs"
+	"log"
+	"os"
+	"path"
+	"runtime"
+)
+
+type VersionInfo struct {
+	Version    string `json:"version"`
+	BuildId    int    `json:"build_id"`
+	TotalBuild int    `json:"total_build"`
+}
+
+func main() {
+	_, file, _, ok := runtime.Caller(0)
+	if !ok {
+		log.Print("Unable to get the current file")
+		return
+	}
+	basePath := path.Join(path.Dir(file), "../../")
+
+	versionFile, err := os.Open(path.Join(basePath, "app/dist/version.json"))
+	if err != nil {
+		if errors.Is(err, fs.ErrNotExist) {
+			log.Print("\"dist/version.json\" not found, load from src instead")
+			versionFile, err = os.Open(path.Join(basePath, "app/src/version.json"))
+		}
+
+		if err != nil {
+			log.Fatal(err)
+			return
+		}
+	}
+
+	defer func(versionFile fs.File) {
+		err := versionFile.Close()
+		if err != nil {
+			log.Fatal(err)
+		}
+	}(versionFile)
+
+	// Read the version.json file
+	data, err := io.ReadAll(versionFile)
+	if err != nil {
+		log.Fatalf("Failed to read version.json: %v", err)
+	}
+
+	// Parse the JSON data
+	var versionInfo VersionInfo
+	err = json.Unmarshal(data, &versionInfo)
+	if err != nil {
+		log.Fatalf("Failed to parse JSON: %v", err)
+	}
+
+	// Generate the version.gen.go file content
+	genContent := fmt.Sprintf(`// Code generated by cmd/version/generate.go; DO NOT EDIT.
+
+package version
+
+func init() {
+	Version = "%s"
+	BuildId = %d
+	TotalBuild = %d
+}
+`, versionInfo.Version, versionInfo.BuildId, versionInfo.TotalBuild)
+
+	genPath := path.Join(basePath, "internal/version/version.gen.go")
+	err = os.WriteFile(genPath, []byte(genContent), 0644)
+	if err != nil {
+		log.Fatalf("Failed to write version.gen.go: %v", err)
+	}
+
+	fmt.Println("version.gen.go has been generated successfully.")
+}

+ 5 - 4
go.mod

@@ -11,7 +11,6 @@ require (
 	github.com/dgraph-io/ristretto/v2 v2.1.0
 	github.com/dustin/go-humanize v1.0.1
 	github.com/elliotchance/orderedmap/v3 v3.1.0
-	github.com/fatih/color v1.18.0
 	github.com/gin-contrib/static v1.1.3
 	github.com/gin-gonic/gin v1.10.0
 	github.com/go-acme/lego/v4 v4.21.0
@@ -31,13 +30,13 @@ require (
 	github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
 	github.com/samber/lo v1.49.1
 	github.com/sashabaranov/go-openai v1.36.1
-	github.com/shirou/gopsutil/v4 v4.25.1
+	github.com/shirou/gopsutil/v4 v4.24.12
 	github.com/spf13/cast v1.7.1
 	github.com/stretchr/testify v1.10.0
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20250120210832-12a9c7ae0c8a
 	github.com/uozi-tech/cosy v1.14.3
-	github.com/uozi-tech/cosy-driver-sqlite v0.2.1
-	go.uber.org/zap v1.27.0
+	github.com/uozi-tech/cosy-driver-sqlite v0.2.0
+	github.com/urfave/cli/v3 v3.0.0-beta1
 	golang.org/x/crypto v0.32.0
 	golang.org/x/net v0.34.0
 	gopkg.in/ini.v1 v1.67.0
@@ -107,6 +106,7 @@ require (
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
 	github.com/ebitengine/purego v0.8.2 // indirect
 	github.com/exoscale/egoscale/v3 v3.1.9 // indirect
+	github.com/fatih/color v1.18.0 // indirect
 	github.com/fatih/structs v1.1.0 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/fsnotify/fsnotify v1.8.0 // indirect
@@ -253,6 +253,7 @@ require (
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/ratelimit v0.3.1 // indirect
+	go.uber.org/zap v1.27.0 // indirect
 	golang.org/x/arch v0.13.0 // indirect
 	golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
 	golang.org/x/mod v0.22.0 // indirect

+ 2 - 4
go.sum

@@ -1658,8 +1658,6 @@ github.com/selectel/go-selvpcclient/v3 v3.2.1 h1:ny6WIAMiHzKxOgOEnwcWE79wIQij1AH
 github.com/selectel/go-selvpcclient/v3 v3.2.1/go.mod h1:3EfSf8aEWyhspOGbvZ6mvnFg7JN5uckxNyBFPGWsXNQ=
 github.com/shirou/gopsutil/v4 v4.24.12 h1:qvePBOk20e0IKA1QXrIIU+jmk+zEiYVVx06WjBRlZo4=
 github.com/shirou/gopsutil/v4 v4.24.12/go.mod h1:DCtMPAad2XceTeIAbGyVfycbYQNBGk2P8cvDi7/VN9o=
-github.com/shirou/gopsutil/v4 v4.25.1 h1:QSWkTc+fu9LTAWfkZwZ6j8MSUk4A2LV7rbH0ZqmLjXs=
-github.com/shirou/gopsutil/v4 v4.25.1/go.mod h1:RoUCUpndaJFtT+2zsZzzmhvbfGoDCJ7nFXKJf8GqJbI=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
@@ -1783,9 +1781,9 @@ github.com/uozi-tech/cosy-driver-postgres v0.2.1 h1:OICakGuT+omva6QOJCxTJ5Lfr7CG
 github.com/uozi-tech/cosy-driver-postgres v0.2.1/go.mod h1:eAy1A89yHbAEfjkhNAifaJQk172NqrNoRyRtFcZc9Go=
 github.com/uozi-tech/cosy-driver-sqlite v0.2.0 h1:eTpIMyGoFUK4JcaiKfJHD5AyiM6vtCwN98c7Bz5n25o=
 github.com/uozi-tech/cosy-driver-sqlite v0.2.0/go.mod h1:87a6mzn5IuEtIR4z7U4Ey8eKLGfNEOSkv7kPQlbNQgM=
-github.com/uozi-tech/cosy-driver-sqlite v0.2.1 h1:W+Z4pY25PSJCeReqroG7LIBeffsqotbpHzgqSMqZDIM=
-github.com/uozi-tech/cosy-driver-sqlite v0.2.1/go.mod h1:2ya7Z5P3HzFi1ktfL8gvwaAGx0DDV0bmWxNSNpaLlwo=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
+github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
+github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
 github.com/volcengine/volc-sdk-golang v1.0.194 h1:3o0INQzdtYJWvdGrtX02booCqPL5TsWSq2W1Ur7Bzlo=

+ 50 - 0
internal/cmd/main.go

@@ -0,0 +1,50 @@
+package cmd
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"os"
+
+	"github.com/0xJacky/Nginx-UI/internal/version"
+	"github.com/urfave/cli/v3"
+)
+
+func NewAppCmd() *cli.Command {
+	serve := false
+
+	cmd := &cli.Command{
+		Name:  "nginx-ui",
+		Usage: "Yet another Nginx Web UI",
+		Commands: []*cli.Command{
+			{
+				Name:  "serve",
+				Usage: "Start the Nginx-UI server",
+				Action: func(ctx context.Context, command *cli.Command) error {
+					serve = true
+					return nil
+				},
+			},
+		},
+		Flags: []cli.Flag{
+			&cli.StringFlag{
+				Name:  "config",
+				Value: "app.ini",
+				Usage: "configuration file path",
+			},
+		},
+		DefaultCommand: "serve",
+		Version:        version.Version,
+	}
+
+	cli.VersionPrinter = func(cmd *cli.Command) {
+		fmt.Printf("%s (%d)\n", cmd.Root().Version, version.BuildId)
+	}
+
+	if err := cmd.Run(context.Background(), os.Args); err != nil {
+		log.Fatal(err)
+	} else if !serve {
+		os.Exit(0)
+	}
+	return cmd
+}

+ 0 - 18
internal/upgrader/info.go

@@ -1,12 +1,10 @@
 package upgrader
 
 import (
-	"encoding/json"
 	"os"
 	"path/filepath"
 	"runtime"
 
-	"github.com/0xJacky/Nginx-UI/app"
 	"github.com/pkg/errors"
 )
 
@@ -42,19 +40,3 @@ func GetRuntimeInfo() (r RuntimeInfo, err error) {
 
 	return
 }
-
-func GetCurrentVersion() (c CurVersion, err error) {
-	verJson, err := app.DistFS.ReadFile(app.VersionPath)
-	if err != nil {
-		err = errors.Wrap(err, "service.GetCurrentVersion ReadFile err")
-		return
-	}
-
-	err = json.Unmarshal(verJson, &c)
-	if err != nil {
-		err = errors.Wrap(err, "service.GetCurrentVersion json.Unmarshal err")
-		return
-	}
-
-	return
-}

+ 26 - 0
internal/version/version.go

@@ -0,0 +1,26 @@
+package version
+
+var (
+	Version    = ""
+	BuildId    = 0
+	TotalBuild = 0
+)
+
+type Info struct {
+	Version    string `json:"version"`
+	BuildId    int    `json:"build_id"`
+	TotalBuild int    `json:"total_build"`
+}
+
+var versionInfo *Info
+
+func GetVersionInfo() *Info {
+	if versionInfo == nil {
+		versionInfo = &Info{
+			Version:    Version,
+			BuildId:    BuildId,
+			TotalBuild: TotalBuild,
+		}
+	}
+	return versionInfo
+}

+ 5 - 5
main.go

@@ -2,11 +2,11 @@ package main
 
 import (
 	"errors"
-	"flag"
 	"fmt"
 	"net/http"
 	"time"
 
+	"github.com/0xJacky/Nginx-UI/internal/cmd"
 	"github.com/0xJacky/Nginx-UI/internal/kernel"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/router"
@@ -20,6 +20,8 @@ import (
 	cSettings "github.com/uozi-tech/cosy/settings"
 )
 
+//go:generate go run cmd/version/generate.go
+
 func Program(confPath string) func(state overseer.State) {
 	return func(state overseer.State) {
 		defer logger.Sync()
@@ -59,12 +61,10 @@ func Program(confPath string) func(state overseer.State) {
 }
 
 func main() {
-	var confPath string
-	flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file")
-	flag.Parse()
+	appCmd := cmd.NewAppCmd()
 
+	confPath := appCmd.String("config")
 	settings.Init(confPath)
-
 	overseer.Run(overseer.Config{
 		Program:          Program(confPath),
 		Address:          fmt.Sprintf("%s:%d", cSettings.ServerSettings.Host, cSettings.ServerSettings.Port),