mirror of
https://github.com/wonli/aqi.git
synced 2025-09-26 20:51:23 +08:00
aqi-cli
This commit is contained in:
9
cmd/aqi/main.go
Normal file
9
cmd/aqi/main.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wonli/aqi/internal/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.Execute()
|
||||||
|
}
|
4
go.mod
4
go.mod
@@ -13,11 +13,13 @@ require (
|
|||||||
github.com/hibiken/asynq v0.24.1
|
github.com/hibiken/asynq v0.24.1
|
||||||
github.com/redis/go-redis/v9 v9.0.3
|
github.com/redis/go-redis/v9 v9.0.3
|
||||||
github.com/shirou/gopsutil/v3 v3.24.4
|
github.com/shirou/gopsutil/v3 v3.24.4
|
||||||
|
github.com/spf13/cobra v1.9.1
|
||||||
github.com/spf13/viper v1.19.0
|
github.com/spf13/viper v1.19.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/tidwall/gjson v1.17.3
|
github.com/tidwall/gjson v1.17.3
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
||||||
|
golang.org/x/time v0.5.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
gorm.io/datatypes v1.2.5
|
gorm.io/datatypes v1.2.5
|
||||||
@@ -48,6 +50,7 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
@@ -87,7 +90,6 @@ require (
|
|||||||
golang.org/x/net v0.32.0 // indirect
|
golang.org/x/net v0.32.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/text v0.21.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
golang.org/x/time v0.5.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
7
go.sum
7
go.sum
@@ -32,6 +32,7 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
|
|||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
@@ -103,6 +104,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
|||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hibiken/asynq v0.24.1 h1:+5iIEAyA9K/lcSPvx3qoPtsKJeKI5u9aOIvUmSsazEw=
|
github.com/hibiken/asynq v0.24.1 h1:+5iIEAyA9K/lcSPvx3qoPtsKJeKI5u9aOIvUmSsazEw=
|
||||||
github.com/hibiken/asynq v0.24.1/go.mod h1:u5qVeSbrnfT+vtG5Mq8ZPzQu/BmCKMHvTGb91uy9Tts=
|
github.com/hibiken/asynq v0.24.1/go.mod h1:u5qVeSbrnfT+vtG5Mq8ZPzQu/BmCKMHvTGb91uy9Tts=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
|
||||||
@@ -177,6 +180,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
|||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk=
|
||||||
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
@@ -194,6 +198,8 @@ github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNo
|
|||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
||||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
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 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||||
@@ -283,6 +289,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
14
internal/cli/cli.go
Normal file
14
internal/cli/cli.go
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: "aqi",
|
||||||
|
Short: "AQI Project Generator",
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
cobra.CheckErr(rootCmd.Execute())
|
||||||
|
}
|
114
internal/cli/cli_new.go
Normal file
114
internal/cli/cli_new.go
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var packageNameFlag string
|
||||||
|
|
||||||
|
var newCmd = &cobra.Command{
|
||||||
|
Use: "new [project-name]",
|
||||||
|
Short: "Create new project skeleton",
|
||||||
|
Args: cobra.MinimumNArgs(1),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
projectName := args[0]
|
||||||
|
|
||||||
|
packageName := projectName
|
||||||
|
if packageNameFlag != "" {
|
||||||
|
packageName = packageNameFlag
|
||||||
|
}
|
||||||
|
|
||||||
|
createDir(projectName)
|
||||||
|
createProject(projectName, packageName)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
newCmd.Flags().StringVarP(&packageNameFlag, "package", "p", "", "Specify package name (optional, defaults to project name)")
|
||||||
|
rootCmd.AddCommand(newCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDir(projectName string) {
|
||||||
|
// 检查目录是否存在
|
||||||
|
dirs := []struct {
|
||||||
|
dirName string
|
||||||
|
}{
|
||||||
|
{"cmd"},
|
||||||
|
{"internal/app"},
|
||||||
|
{"internal/dbc"},
|
||||||
|
{"internal/entity"},
|
||||||
|
{"internal/middlewares"},
|
||||||
|
{"internal/router"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range dirs {
|
||||||
|
dirPath := filepath.Join(projectName, d.dirName)
|
||||||
|
if err := os.MkdirAll(dirPath, 0755); err != nil {
|
||||||
|
fmt.Printf("Error creating directory: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createProject(name, packageName string) {
|
||||||
|
// 复制模板文件
|
||||||
|
templates := []struct {
|
||||||
|
templatePath string
|
||||||
|
outputPath string
|
||||||
|
}{
|
||||||
|
{"templates/default/main.go.tmpl", "main.go"},
|
||||||
|
{"templates/default/go.mod.tmpl", "go.mod"},
|
||||||
|
{"templates/default/makefile.tmpl", "Makefile"},
|
||||||
|
{"templates/default/cmd/api.go.tmpl", "cmd/api.go"},
|
||||||
|
{"templates/default/cmd/dal.go.tmpl", "cmd/dal.go"},
|
||||||
|
{"templates/default/cmd/boot.go.tmpl", "cmd/boot.go"},
|
||||||
|
{"templates/default/dbc/dbc.go.tmpl", "internal/dbc/dbc.go"},
|
||||||
|
{"templates/default/middlewares/app.go.tmpl", "internal/middlewares/app.go"},
|
||||||
|
{"templates/default/middlewares/recovery.go.tmpl", "internal/middlewares/recovery.go"},
|
||||||
|
{"templates/default/middlewares/cors.go.tmpl", "internal/middlewares/cors.go"},
|
||||||
|
{"templates/default/router/action.go.tmpl", "internal/router/action.go"},
|
||||||
|
{"templates/default/router/api.go.tmpl", "internal/router/api.go"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range templates {
|
||||||
|
// 从嵌入的文件系统读取模板
|
||||||
|
tmplContent, err := templateFS.ReadFile(t.templatePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error reading template: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析模板
|
||||||
|
tmpl, err := template.New(t.outputPath).Parse(string(tmplContent))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error parsing template: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
outputFile, err := os.Create(filepath.Join(name, t.outputPath))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error creating file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
data := struct {
|
||||||
|
PackageName string
|
||||||
|
}{
|
||||||
|
PackageName: packageName,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tmpl.Execute(outputFile, data); err != nil {
|
||||||
|
fmt.Printf("Error executing template: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = outputFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Successfully created project: %s\n", name)
|
||||||
|
}
|
18
internal/cli/cli_version.go
Normal file
18
internal/cli/cli_version.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var verCmd = &cobra.Command{
|
||||||
|
Use: "version",
|
||||||
|
Short: "Version of this CLI",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
fmt.Println("Version: 1.0")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(verCmd)
|
||||||
|
}
|
8
internal/cli/templates.go
Normal file
8
internal/cli/templates.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed templates/default/*.tmpl templates/default/**/*.tmpl
|
||||||
|
var templateFS embed.FS
|
35
internal/cli/templates/default/cmd/api.go.tmpl
Normal file
35
internal/cli/templates/default/cmd/api.go.tmpl
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/wonli/aqi"
|
||||||
|
|
||||||
|
"{{.PackageName}}/internal/dbc"
|
||||||
|
"{{.PackageName}}/internal/router"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
var api = &cobra.Command{
|
||||||
|
Use: "api",
|
||||||
|
Short: "启动API",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
app := aqi.Init(
|
||||||
|
aqi.ConfigFile(configFile),
|
||||||
|
aqi.HttpServer("Api", "apiPort"),
|
||||||
|
)
|
||||||
|
|
||||||
|
dbc.InitDBC()
|
||||||
|
|
||||||
|
g := gin.Default()
|
||||||
|
|
||||||
|
go router.Api(g)
|
||||||
|
go router.Actions(app)
|
||||||
|
|
||||||
|
app.WithHttpServer(g)
|
||||||
|
app.Start()
|
||||||
|
},
|
||||||
|
}
|
37
internal/cli/templates/default/cmd/boot.go.tmpl
Normal file
37
internal/cli/templates/default/cmd/boot.go.tmpl
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
_ "time/tzdata"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var timezone string
|
||||||
|
var configFile string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&timezone, "tz", "t", "default", "指定时区")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "config.yaml", "指定配置文件路径,默认当前路径下config.yaml")
|
||||||
|
cobra.OnInitialize(func() {
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var runApp = filepath.Base(strings.TrimLeft(os.Args[0], "./"))
|
||||||
|
var rootCmd = &cobra.Command{
|
||||||
|
Use: runApp,
|
||||||
|
Version: "{{.PackageName}}",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
_ = cmd.Help()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute() {
|
||||||
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
84
internal/cli/templates/default/cmd/dal.go.tmpl
Normal file
84
internal/cli/templates/default/cmd/dal.go.tmpl
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"github.com/wonli/aqi"
|
||||||
|
"golang.org/x/text/cases"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
"gorm.io/gen"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"{{.PackageName}}/internal/dbc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(dalCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dalCmd = &cobra.Command{
|
||||||
|
Use: "dal",
|
||||||
|
Short: "生成数据库表对应的model和dal",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
aqi.Init(
|
||||||
|
aqi.ConfigFile(configFile),
|
||||||
|
)
|
||||||
|
|
||||||
|
dbc.InitDBC()
|
||||||
|
|
||||||
|
g := gen.NewGenerator(gen.Config{
|
||||||
|
OutPath: "./internal/entity/dal",
|
||||||
|
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface,
|
||||||
|
FieldSignable: true, // 无符号整数类型字段
|
||||||
|
FieldNullable: true, // 数据库中的字段可为空,则生成struct字段为指针类型
|
||||||
|
FieldCoverable: true, // 如果数据库中字段有默认值,则生成指针类型的字段,以避免零值(zero-value)问题
|
||||||
|
FieldWithIndexTag: true, // 为结构体生成gorm index tag
|
||||||
|
FieldWithTypeTag: true, // 为结构体生成gorm type tag
|
||||||
|
})
|
||||||
|
|
||||||
|
g.WithDataTypeMap(map[string]func(columnType gorm.ColumnType) string{
|
||||||
|
"json": func(columnType gorm.ColumnType) string {
|
||||||
|
return "datatypes.JSON"
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
prefixToRemove := viper.GetString("mysql.logic.prefix")
|
||||||
|
g.WithTableNameStrategy(func(tableName string) string {
|
||||||
|
// 去掉指定的前缀
|
||||||
|
if strings.HasPrefix(tableName, prefixToRemove) {
|
||||||
|
return strings.TrimPrefix(tableName, prefixToRemove)
|
||||||
|
}
|
||||||
|
return tableName
|
||||||
|
})
|
||||||
|
|
||||||
|
g.WithJSONTagNameStrategy(func(columnName string) string {
|
||||||
|
parts := strings.Split(columnName, "_")
|
||||||
|
titleTransformer := cases.Title(language.English)
|
||||||
|
|
||||||
|
for i := range parts {
|
||||||
|
parts[i] = titleTransformer.String(parts[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将首字母转换为小写
|
||||||
|
if len(parts) > 0 {
|
||||||
|
parts[0] = strings.ToLower(parts[0][:1]) + parts[0][1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(parts, "")
|
||||||
|
})
|
||||||
|
|
||||||
|
logic := dbc.LogicDB.Use()
|
||||||
|
g.UseDB(logic)
|
||||||
|
g.ApplyInterface(func(Filter) {}, g.GenerateAllTable()...)
|
||||||
|
|
||||||
|
g.Execute()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Filter interface {
|
||||||
|
// FilterWithColumn
|
||||||
|
// SELECT * FROM @@table WHERE @@column=@value
|
||||||
|
FilterWithColumn(column string, value string) ([]*gen.T, error)
|
||||||
|
}
|
13
internal/cli/templates/default/dbc/dbc.go.tmpl
Normal file
13
internal/cli/templates/default/dbc/dbc.go.tmpl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package dbc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wonli/aqi/store"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Redis *store.RedisStore
|
||||||
|
var LogicDB *store.MySQLStore
|
||||||
|
|
||||||
|
func InitDBC() {
|
||||||
|
LogicDB = store.DB("mysql.logic")
|
||||||
|
Redis = store.Redis("redis.store")
|
||||||
|
}
|
14
internal/cli/templates/default/go.mod.tmpl
Normal file
14
internal/cli/templates/default/go.mod.tmpl
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module {{.PackageName}}
|
||||||
|
|
||||||
|
go 1.24
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-gonic/gin v1.10.1
|
||||||
|
github.com/spf13/cobra v1.9.1
|
||||||
|
github.com/spf13/viper v1.20.1
|
||||||
|
github.com/wonli/aqi v1.3.1
|
||||||
|
golang.org/x/text v0.25.0
|
||||||
|
gorm.io/gen v0.3.27
|
||||||
|
gorm.io/gorm v1.30.0
|
||||||
|
gorm.io/plugin/dbresolver v1.6.0
|
||||||
|
)
|
7
internal/cli/templates/default/main.go.tmpl
Normal file
7
internal/cli/templates/default/main.go.tmpl
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "{{.PackageName}}/cmd"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Execute()
|
||||||
|
}
|
51
internal/cli/templates/default/makefile.tmpl
Normal file
51
internal/cli/templates/default/makefile.tmpl
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
APP_NAME = {{.PackageName}}
|
||||||
|
APP_PATH = .
|
||||||
|
|
||||||
|
# 编译路径
|
||||||
|
BUILD_PATH := ./dist
|
||||||
|
|
||||||
|
# 编译时间
|
||||||
|
BUILD_DATE = $(shell date +'%F %T')
|
||||||
|
|
||||||
|
ifeq ($(shell test -d .git && echo yes),yes)
|
||||||
|
# git已初始化,可以安全执行git命令
|
||||||
|
GIT_BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
GIT_COMMIT = $(shell git rev-list --count HEAD)
|
||||||
|
GIT_REVISION = $(shell git rev-parse --short HEAD)
|
||||||
|
GIT_COMMITAT = $(shell git --no-pager log -1 --format="%at")
|
||||||
|
else
|
||||||
|
# git未初始化,相关变量设为默认值
|
||||||
|
GIT_BRANCH = -
|
||||||
|
GIT_COMMIT = -
|
||||||
|
GIT_REVISION = -
|
||||||
|
GIT_COMMITAT = -
|
||||||
|
endif
|
||||||
|
|
||||||
|
# support包名称
|
||||||
|
FLAGS_PKG = github.com/wonli/aqi
|
||||||
|
LDFLAGS = "-X '$(FLAGS_PKG).BuildDate=$(BUILD_DATE)' \
|
||||||
|
-X '$(FLAGS_PKG).Branch=$(GIT_BRANCH)' \
|
||||||
|
-X '$(FLAGS_PKG).CommitVersion=$(GIT_COMMIT)' \
|
||||||
|
-X '$(FLAGS_PKG).Revision=$(GIT_REVISION)' \
|
||||||
|
-extldflags '-static -s -w'"
|
||||||
|
|
||||||
|
# 编译参数
|
||||||
|
GO_FLAGS = -ldflags $(LDFLAGS) -trimpath -tags netgo
|
||||||
|
|
||||||
|
# Go编译命令 1-GOOS 2-GOARCH 3-FILE EXT
|
||||||
|
define go/build
|
||||||
|
go mod tidy
|
||||||
|
GOOS=$(1) GOARCH=$(2) CGO_ENABLED=0 go build $(GO_FLAGS) -o $(BUILD_PATH)/$(APP_NAME)-$(1)-$(2)-latest$(3) ${APP_PATH}
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Generate binaries
|
||||||
|
.PHONY: build darwin linux windows
|
||||||
|
|
||||||
|
darwin:
|
||||||
|
$(call go/build,darwin,arm64)
|
||||||
|
|
||||||
|
linux:
|
||||||
|
$(call go/build,linux,amd64)
|
||||||
|
|
||||||
|
windows:
|
||||||
|
$(call go/build,windows,amd64,.exe)
|
42
internal/cli/templates/default/middlewares/app.go.tmpl
Normal file
42
internal/cli/templates/default/middlewares/app.go.tmpl
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wonli/aqi/ws"
|
||||||
|
)
|
||||||
|
|
||||||
|
func App() ws.HandlerFunc {
|
||||||
|
return func(a *ws.Context) {
|
||||||
|
if a.Client.AppId == "" || a.Client.Platform == "" {
|
||||||
|
appId := a.Client.HttpRequest.URL.Query().Get("appId")
|
||||||
|
platform := a.Client.HttpRequest.URL.Query().Get("platform")
|
||||||
|
|
||||||
|
//获取storeId
|
||||||
|
if platform == "" {
|
||||||
|
a.SendCode(10003, "不支持的平台")
|
||||||
|
a.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Client.AppId = appId
|
||||||
|
a.Client.Platform = platform
|
||||||
|
}
|
||||||
|
|
||||||
|
// app登录
|
||||||
|
if a.Client.AppId == "app" && a.Client.ClientId == "" {
|
||||||
|
clientId := a.Client.HttpRequest.URL.Query().Get("clientId")
|
||||||
|
if clientId == "" {
|
||||||
|
a.SendCode(10013, "client不能为空")
|
||||||
|
a.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Client.ClientId = clientId
|
||||||
|
err := a.Client.Hub.UserLogin(clientId, a.Client.AppId, a.Client)
|
||||||
|
if err != nil {
|
||||||
|
a.SendCode(10013, "登录失败")
|
||||||
|
a.Abort()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
internal/cli/templates/default/middlewares/cors.go.tmpl
Normal file
21
internal/cli/templates/default/middlewares/cors.go.tmpl
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
func GinCORS() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
// 设置响应头中的Access-Control-Allow-Origin为"*",允许所有域名的跨域请求。
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||||
|
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
|
||||||
|
c.Writer.Header().Set("Access-Control-Allow-Credentials", "false")
|
||||||
|
|
||||||
|
// 如果请求方法是OPTIONS,直接返回200,不继续后续的处理逻辑。
|
||||||
|
if c.Request.Method == "OPTIONS" {
|
||||||
|
c.AbortWithStatus(200)
|
||||||
|
} else {
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
internal/cli/templates/default/middlewares/recovery.go.tmpl
Normal file
24
internal/cli/templates/default/middlewares/recovery.go.tmpl
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wonli/aqi/logger"
|
||||||
|
"github.com/wonli/aqi/ws"
|
||||||
|
"runtime/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Recovery() ws.HandlerFunc {
|
||||||
|
return func(a *ws.Context) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
// 获取 panic 发生的堆栈跟踪
|
||||||
|
stack := debug.Stack()
|
||||||
|
logger.SugarLog.Errorf("Panic happened: %s \n %s\n", err, stack)
|
||||||
|
|
||||||
|
a.SendCode(30, "服务维护中")
|
||||||
|
a.Abort()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
a.Next()
|
||||||
|
}
|
||||||
|
}
|
15
internal/cli/templates/default/router/action.go.tmpl
Normal file
15
internal/cli/templates/default/router/action.go.tmpl
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/wonli/aqi"
|
||||||
|
"github.com/wonli/aqi/ws"
|
||||||
|
|
||||||
|
"{{.PackageName}}/internal/middlewares"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Actions(e *aqi.AppConfig) {
|
||||||
|
app := ws.NewRouter().Use(middlewares.Recovery(), middlewares.App())
|
||||||
|
app.Add("hi", func(a *ws.Context) {
|
||||||
|
a.Send(a.Params)
|
||||||
|
})
|
||||||
|
}
|
22
internal/cli/templates/default/router/api.go.tmpl
Normal file
22
internal/cli/templates/default/router/api.go.tmpl
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/wonli/aqi/ws"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"{{.PackageName}}/internal/middlewares"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Api(g *gin.Engine) {
|
||||||
|
g.Use(middlewares.GinCORS())
|
||||||
|
g.GET("/ok", func(c *gin.Context) {
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"t": time.Now().Unix(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
g.GET("/ws", func(c *gin.Context) {
|
||||||
|
ws.HttpHandler(c.Writer, c.Request)
|
||||||
|
})
|
||||||
|
}
|
Reference in New Issue
Block a user