This commit is contained in:
2025-06-20 17:13:51 +08:00
parent 1b55403cd6
commit fd0345a034
472 changed files with 52560 additions and 77 deletions

View File

@@ -0,0 +1,14 @@
package cmd
import (
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Main = gcmd.Command{
Name: "cool-tools",
Usage: "cool-tools [command] [args...]",
Brief: "cool-tools is a collection of tools for cool people.",
Description: `cool-tools is a collection of tools for cool people.`,
}
)

View File

@@ -0,0 +1,328 @@
package cmd
import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
"runtime"
"strings"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
)
var (
Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "internal/packed/build_pack_data.go",
}
)
type cBuild struct {
g.Meta `name:"build" brief:"{cBuildBrief}" dc:"{cBuildDc}" eg:"{cBuildEg}" ad:"{cBuildAd}"`
nodeNameInConfigFile string // nodeNameInConfigFile is the node name for compiler configurations in configuration file.
packedGoFileName string // packedGoFileName specifies the file name for packing common folders into one single go file.
}
const (
cBuildBrief = `cross-building go project for lots of platforms`
cBuildEg = `
cool-tools build main.go
cool-tools build main.go --pack public,template
cool-tools build main.go --cgo
cool-tools build main.go -m none
cool-tools build main.go -n my-app -a all -s all
cool-tools build main.go -n my-app -a amd64,386 -s linux -p .
cool-tools build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin
`
cBuildDc = `
The "build" command is most commonly used command, which is designed as a powerful wrapper for
"go build" command for convenience cross-compiling usage.
It provides much more features for building binary:
1. Cross-Compiling for many platforms and architectures.
2. Configuration file support for compiling.
3. Build-In Variables.
`
cBuildAd = `
PLATFORMS
darwin amd64,arm64
freebsd 386,amd64,arm
linux 386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le
netbsd 386,amd64,arm
openbsd 386,amd64,arm
windows 386,amd64
`
// https://golang.google.cn/doc/install/source
cBuildPlatforms = `
darwin amd64
darwin arm64
ios amd64
ios arm64
freebsd 386
freebsd amd64
freebsd arm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux mips
linux mipsle
linux mips64
linux mips64le
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
windows 386
windows amd64
android arm
dragonfly amd64
plan9 386
plan9 amd64
solaris amd64
`
)
func init() {
gtag.Sets(g.MapStrStr{
`cBuildBrief`: cBuildBrief,
`cBuildDc`: cBuildDc,
`cBuildEg`: cBuildEg,
`cBuildAd`: cBuildAd,
})
Main.AddObject(Build)
}
type cBuildInput struct {
g.Meta `name:"build" config:"gfcli.build"`
File string `name:"FILE" arg:"true" brief:"building file path"`
Name string `short:"n" name:"name" brief:"output binary name"`
Version string `short:"v" name:"version" brief:"output binary version"`
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
Path string `short:"p" name:"path" brief:"output binary directory path, default is './temp'" d:"./temp"`
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
VarMap g.Map `short:"r" name:"varMap" brief:"custom built embedded variable into binary"`
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
}
type cBuildOutput struct{}
func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {
mlog.SetHeaderPrint(true)
mlog.Debugf(`build input: %+v`, in)
// Necessary check.
if gproc.SearchBinary("go") == "" {
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
}
var (
parser = gcmd.ParserFromCtx(ctx)
file = parser.GetArg(2).String()
)
if len(file) < 1 {
// Check and use the main.go file.
if gfile.Exists("main.go") {
file = "main.go"
} else {
mlog.Fatal("build file path cannot be empty")
}
}
if in.Name == "" {
in.Name = gfile.Name(file)
}
if len(in.Name) < 1 || in.Name == "*" {
mlog.Fatal("name cannot be empty")
}
if in.Mod != "" && in.Mod != "none" {
mlog.Debugf(`mod is %s`, in.Mod)
if in.Extra == "" {
in.Extra = fmt.Sprintf(`-mod=%s`, in.Mod)
} else {
in.Extra = fmt.Sprintf(`-mod=%s %s`, in.Mod, in.Extra)
}
}
if in.Extra != "" {
in.Extra += " "
}
var (
customSystems = gstr.SplitAndTrim(in.System, ",")
customArches = gstr.SplitAndTrim(in.Arch, ",")
)
if len(in.Version) > 0 {
in.Path += "/" + in.Version
}
// System and arch checks.
var (
spaceRegex = regexp.MustCompile(`\s+`)
platformMap = make(map[string]map[string]bool)
)
for _, line := range strings.Split(strings.TrimSpace(cBuildPlatforms), "\n") {
line = gstr.Trim(line)
line = spaceRegex.ReplaceAllString(line, " ")
var (
array = strings.Split(line, " ")
system = strings.TrimSpace(array[0])
arch = strings.TrimSpace(array[1])
)
if platformMap[system] == nil {
platformMap[system] = make(map[string]bool)
}
platformMap[system][arch] = true
}
// Auto packing.
if in.PackSrc != "" {
if in.PackDst == "" {
mlog.Fatal(`parameter "packDst" should not be empty when "packSrc" is used`)
}
if gfile.Exists(in.PackDst) && !gfile.IsFile(in.PackDst) {
mlog.Fatalf(`parameter "packDst" path "%s" should be type of file not directory`, in.PackDst)
}
if !gfile.Exists(in.PackDst) {
// Remove the go file that is automatically packed resource.
defer func() {
_ = gfile.Remove(in.PackDst)
mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)
}()
}
// remove black space in separator.
in.PackSrc, _ = gregex.ReplaceString(`,\s+`, `,`, in.PackSrc)
packCmd := fmt.Sprintf(`gf pack %s %s --keepPath=true`, in.PackSrc, in.PackDst)
mlog.Print(packCmd)
gproc.MustShellRun(ctx, packCmd)
}
// Injected information by building flags.
ldFlags := fmt.Sprintf(
`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`,
c.getBuildInVarStr(ctx, in),
)
// start building
mlog.Print("start building...")
if in.Cgo {
genv.MustSet("CGO_ENABLED", "1")
} else {
genv.MustSet("CGO_ENABLED", "0")
}
var (
cmd = ""
ext = ""
)
for system, item := range platformMap {
cmd = ""
ext = ""
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
continue
}
for arch := range item {
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
continue
}
if len(customSystems) == 0 && len(customArches) == 0 {
if runtime.GOOS == "windows" {
ext = ".exe"
}
// Single binary building, output the binary to current working folder.
output := ""
if len(in.Output) > 0 {
output = "-o " + in.Output + ext
} else {
output = "-o " + in.Name + ext
}
cmd = fmt.Sprintf(`go build %s -ldflags "%s" %s %s`, output, ldFlags, in.Extra, file)
} else {
// Cross-building, output the compiled binary to specified path.
if system == "windows" {
ext = ".exe"
}
genv.MustSet("GOOS", system)
genv.MustSet("GOARCH", arch)
cmd = fmt.Sprintf(
`go build -o %s/%s/%s%s -ldflags "%s" %s%s`,
in.Path, system+"_"+arch, in.Name, ext, ldFlags, in.Extra, file,
)
}
mlog.Debug(cmd)
// It's not necessary printing the complete command string.
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
mlog.Print(cmdShow)
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
mlog.Printf(
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
system, arch, gstr.Trim(result),
`you may use command option "--debug" to enable debug info and check the details`,
)
if in.ExitWhenError {
os.Exit(1)
}
} else {
mlog.Debug(gstr.Trim(result))
}
// single binary building.
if len(customSystems) == 0 && len(customArches) == 0 {
goto buildDone
}
}
}
buildDone:
mlog.Print("done!")
return
}
// getBuildInVarMapJson retrieves and returns the custom build-in variables in configuration
// file as json.
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
buildInVarMap := in.VarMap
if buildInVarMap == nil {
buildInVarMap = make(g.Map)
}
buildInVarMap["builtGit"] = c.getGitCommit(ctx)
buildInVarMap["builtTime"] = gtime.Now().String()
b, err := json.Marshal(buildInVarMap)
if err != nil {
mlog.Fatal(err)
}
return gbase64.EncodeToString(b)
}
// getGitCommit retrieves and returns the latest git commit hash string if present.
func (c cBuild) getGitCommit(ctx context.Context) string {
if gproc.SearchBinary("git") == "" {
return ""
}
var (
cmd = `git log -1 --format="%cd %H" --date=format:"%Y-%m-%d %H:%M:%S"`
s, _ = gproc.ShellExec(ctx, cmd)
)
mlog.Debug(cmd)
if s != "" {
if !gstr.Contains(s, "fatal") {
return gstr.Trim(s)
}
}
return ""
}

View File

@@ -0,0 +1,99 @@
package cmd
import (
"context"
"strings"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/allyes"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
"github.com/gogf/gf/v2/util/gtag"
)
var (
Pack = cPack{}
)
type cPack struct {
g.Meta `name:"pack" usage:"{cPackUsage}" brief:"{cPackBrief}" eg:"{cPackEg}"`
}
const (
cPackUsage = `cool-tools pack SRC DST`
cPackBrief = `packing any file/directory to a resource file, or a go file`
cPackEg = `
cool-tools pack public data.bin
cool-tools pack public,template data.bin
cool-tools pack public,template packed/data.go
cool-tools pack public,template,config packed/data.go
cool-tools pack public,template,config packed/data.go -n=packed -p=/var/www/my-app
cool-tools pack /var/www/public packed/data.go -n=packed
`
cPackSrcBrief = `source path for packing, which can be multiple source paths.`
cPackDstBrief = `
destination file path for packed file. if extension of the filename is ".go" and "-n" option is given,
it enables packing SRC to go file, or else it packs SRC into a binary file.
`
cPackNameBrief = `package name for output go file, it's set as its directory name if no name passed`
cPackPrefixBrief = `prefix for each file packed into the resource file`
cPackKeepPathBrief = `keep the source path from system to resource file, usually for relative path`
)
func init() {
gtag.Sets(g.MapStrStr{
`cPackUsage`: cPackUsage,
`cPackBrief`: cPackBrief,
`cPackEg`: cPackEg,
`cPackSrcBrief`: cPackSrcBrief,
`cPackDstBrief`: cPackDstBrief,
`cPackNameBrief`: cPackNameBrief,
`cPackPrefixBrief`: cPackPrefixBrief,
`cPackKeepPathBrief`: cPackKeepPathBrief,
})
Main.AddObject(Pack)
}
type cPackInput struct {
g.Meta `name:"pack"`
Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`
Prefix string `name:"prefix" short:"p" brief:"{cPackPrefixBrief}"`
KeepPath bool `name:"keepPath" short:"k" brief:"{cPackKeepPathBrief}" orphan:"true"`
}
type cPackOutput struct{}
func (c cPack) Index(ctx context.Context, in cPackInput) (out *cPackOutput, err error) {
if gfile.Exists(in.Dst) && gfile.IsDir(in.Dst) {
mlog.Fatalf("DST path '%s' cannot be a directory", in.Dst)
}
if !gfile.IsEmpty(in.Dst) && !allyes.Check() {
s := gcmd.Scanf("path '%s' is not empty, files might be overwrote, continue? [y/n]: ", in.Dst)
if strings.EqualFold(s, "n") {
return
}
}
if in.Name == "" && gfile.ExtName(in.Dst) == "go" {
in.Name = gfile.Basename(gfile.Dir(in.Dst))
}
var option = gres.Option{
Prefix: in.Prefix,
KeepPath: in.KeepPath,
}
if in.Name != "" {
if err = gres.PackToGoFileWithOption(in.Src, in.Dst, in.Name, option); err != nil {
mlog.Fatalf("pack failed: %v", err)
}
} else {
if err = gres.PackToFileWithOption(in.Src, in.Dst, option); err != nil {
mlog.Fatalf("pack failed: %v", err)
}
}
mlog.Print("done!")
return
}

View File

@@ -0,0 +1,170 @@
package cmd
// 同步自 gf v2.2.2 https://github.com/gogf/gf/blob/60d828397149ed281111a7530074ce20f997224a/cmd/gf/internal/cmd/cmd_build.go
import (
"context"
"fmt"
"runtime"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gfsnotify"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/util/gtag"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
)
var (
Run = cRun{}
)
type cRun struct {
g.Meta `name:"run" usage:"{cRunUsage}" brief:"{cRunBrief}" eg:"{cRunEg}" dc:"{cRunDc}"`
}
type cRunApp struct {
File string // Go run file name.
Path string // Directory storing built binary.
Options string // Extra "go run" options.
Args string // Custom arguments.
}
const (
cRunUsage = `cool-tools run FILE [OPTION]`
cRunBrief = `running go codes with hot-compiled-like feature`
cRunEg = `
cool-tools run main.go
cool-tools run main.go --args "server -p 8080"
cool-tools run main.go -mod=vendor
`
cRunDc = `
The "run" command is used for running go codes with hot-compiled-like feature,
which compiles and runs the go codes asynchronously when codes change.
`
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "manifest/output" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
)
var (
process *gproc.Process
)
func init() {
gtag.Sets(g.MapStrStr{
`cRunUsage`: cRunUsage,
`cRunBrief`: cRunBrief,
`cRunEg`: cRunEg,
`cRunDc`: cRunDc,
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
})
// 注册命令
Main.AddObject(Run)
}
type (
cRunInput struct {
g.Meta `name:"run"`
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
}
cRunOutput struct{}
)
func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err error) {
// Necessary check.
if gproc.SearchBinary("go") == "" {
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
}
app := &cRunApp{
File: in.File,
Path: in.Path,
Options: in.Extra,
Args: in.Args,
}
dirty := gtype.NewBool()
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
if gfile.ExtName(event.Path) != "go" {
return
}
// Variable `dirty` is used for running the changes only one in one second.
if !dirty.Cas(false, true) {
return
}
// With some delay in case of multiple code changes in very short interval.
gtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {
defer dirty.Set(false)
mlog.Printf(`go file changes: %s`, event.String())
app.Run(ctx)
})
})
if err != nil {
mlog.Fatal(err)
}
go app.Run(ctx)
select {}
}
func (app *cRunApp) Run(ctx context.Context) {
// Rebuild and run the codes.
renamePath := ""
mlog.Printf("build: %s", app.File)
outputPath := gfile.Join(app.Path, gfile.Name(app.File))
if runtime.GOOS == "windows" {
outputPath += ".exe"
if gfile.Exists(outputPath) {
renamePath = outputPath + "~"
if err := gfile.Rename(outputPath, renamePath); err != nil {
mlog.Print(err)
}
}
}
// In case of `pipe: too many open files` error.
// Build the app.
buildCommand := fmt.Sprintf(
`go build -o %s %s %s`,
outputPath,
app.Options,
app.File,
)
mlog.Print(buildCommand)
result, err := gproc.ShellExec(ctx, buildCommand)
if err != nil {
mlog.Printf("build error: \n%s%s", result, err.Error())
return
}
// Kill the old process if build successfully.
if process != nil {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
//return
}
}
// Run the binary file.
runCommand := fmt.Sprintf(`%s %s`, outputPath, app.Args)
mlog.Print(runCommand)
if runtime.GOOS == "windows" {
// Special handling for windows platform.
// DO NOT USE "cmd /c" command.
process = gproc.NewProcess(runCommand, nil)
} else {
process = gproc.NewProcessCmd(runCommand, nil)
}
if pid, err := process.Start(ctx); err != nil {
mlog.Printf("build running error: %s", err.Error())
} else {
mlog.Printf("build running pid: %d", pid)
}
}

View File

@@ -0,0 +1,80 @@
package cmd
import (
"context"
"net"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/util/gconv"
)
var (
Docs = gcmd.Command{
Name: "docs",
Usage: "cool-tools docs",
Brief: "查看帮助文档",
Description: "查看帮助文档",
Func: func(ctx context.Context, parser *gcmd.Parser) error {
s := g.Server("docs")
// 获取本机未占用的端口
port, err := getfreeport()
if err != nil {
mlog.Fatal(err)
return err
}
// 获取本机ip
// ip, err := getlocalip()
// if err != nil {
// mlog.Fatal(err)
// return err
// }
s.SetServerRoot("docs")
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.RedirectTo("/cool-admin-go/")
})
// 设置端口
s.SetPort(gconv.Int(port))
mlog.Printf("CoolAdminGo docs server is running at %s", "http://"+"127.0.0.1"+":"+gconv.String(port)+"/cool-admin-go/")
s.Run()
return nil
},
}
)
func init() {
Main.AddCommand(&Docs)
}
// getfreeport 获取本机未占用的端口
func getfreeport() (int, error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return 0, err
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return 0, err
}
defer l.Close()
return l.Addr().(*net.TCPAddr).Port, nil
}
// getlocalip 获取本机ip
// func getlocalip() (string, error) {
// addrs, err := net.InterfaceAddrs()
// if err != nil {
// return "", err
// }
// for _, address := range addrs {
// // 检查ip地址判断是否回环地址
// if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
// if ipnet.IP.To4() != nil {
// return ipnet.IP.String(), nil
// }
// }
// }
// return "", nil
// }

View File

@@ -0,0 +1,27 @@
package cmd
import (
"context"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gres"
)
var (
Dump = &gcmd.Command{
Name: "dump",
Usage: "cool-tools dump",
Brief: "查看打包的资源文件",
Description: "查看打包的资源文件",
Arguments: []gcmd.Argument{},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
gres.Dump()
return nil
},
}
)
// init
func init() {
Main.AddCommand(Dump)
}

View File

@@ -0,0 +1,18 @@
package cmd
import (
"github.com/gogf/gf/v2/frame/g"
)
var (
Gen = cGen{}
)
type cGen struct {
g.Meta `name:"gen" brief:"生成代码" description:"生成代码, 例如: cool-tools gen model"`
cGenModel
}
func init() {
Main.AddObject(Gen)
}

View File

@@ -0,0 +1,46 @@
package cmd
import (
"github.com/cool-team-official/cool-admin-go/cool"
"github.com/gogf/gf/v2/frame/g"
"gorm.io/gen"
)
type cGenModel struct {
g.Meta `name:"model" brief:"生成模型代码" description:"生成模型代码, 例如: cool-tools gen model"`
}
var (
GenModel = cGenModel{}
)
type cGenModelInput struct {
g.Meta `name:"model" brief:"生成模型代码" description:"生成模型代码, 例如: cool-tools gen model"`
Database string `v:"required#请输入数据库名称" arg:"true" name:"database" brief:"数据库名称" description:"数据库名称"`
}
type cGenModelOutput struct{}
func (c *cGenModel) Index(ctx g.Ctx, in cGenModelInput) (out cGenModelOutput, err error) {
g.Log().Print(ctx, in.Database)
// 获取数据库
db, err := cool.InitDB(in.Database)
if err != nil {
panic(err.Error())
}
generator := gen.NewGenerator(gen.Config{
OutPath: "temp/gen/model",
OutFile: "",
ModelPkgPath: "",
WithUnitTest: false,
FieldNullable: true,
FieldCoverable: true,
FieldSignable: true,
FieldWithIndexTag: true,
FieldWithTypeTag: true,
Mode: 0,
})
generator.UseDB(db)
generator.GenerateAllTable()
generator.Execute()
return
}

View File

@@ -0,0 +1,68 @@
package cmd
import (
"context"
"strings"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gres"
)
var (
Init = gcmd.Command{
Name: "init",
Usage: "cool-tools init [dst]",
Brief: "创建一个新的cool-admin-go项目",
Arguments: []gcmd.Argument{
{
Name: "dst",
// Short: "m",
Brief: "the destination path",
IsArg: true,
},
},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
dst := parser.GetArg(2).String()
if dst == "" {
dst = "."
}
// 如果目标路径不存在,则创建目标路径
if gfile.IsEmpty(dst) {
if err = gfile.Mkdir(dst); err != nil {
return
}
} else {
if !gfile.IsDir(dst) {
g.Log().Panicf(ctx, "%s is not a directory", dst)
} else {
s := gcmd.Scanf(`the folder "%s" is not empty, files might be overwrote, continue? [y/n]: `, dst)
if strings.EqualFold(s, "n") {
return
}
}
}
err = gres.Export("cool-admin-go-simple", dst, gres.ExportOption{
RemovePrefix: "cool-admin-go-simple",
})
if err != nil {
return
}
err = gfile.ReplaceDir("cool-admin-go-simple", gfile.Basename(gfile.RealPath(dst)), dst, "*", true)
if err != nil {
return
}
g.Log().Infof(ctx, "init success")
return nil
},
}
)
// init 初始化模块
func init() {
Main.AddCommand(&Init)
}

View File

@@ -0,0 +1,25 @@
package cmd
import (
"context"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/service"
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Install = gcmd.Command{
Name: "install",
Usage: "cool-tools install",
Brief: "Install cool-tools to the system.",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
err = service.Install.Run(ctx)
return
},
}
)
// init
func init() {
Main.AddCommand(&Install)
}

View File

@@ -0,0 +1,61 @@
package cmd
import (
"context"
"github.com/cool-team-official/cool-admin-go/cool-tools/internal/service"
"github.com/gogf/gf/v2/os/gcmd"
)
var (
Module = &gcmd.Command{
Name: "module",
Usage: "cool-tools module moduleName",
Brief: "在modules目录下创建模块",
Description: "在modules目录下创建模块, 并且创建相应的目录结构,注意: 如果模块已经存在, 则会覆盖原有的模块,本命令需在项目根目录下执行.",
Arguments: []gcmd.Argument{
{
Name: "moduleName",
IsArg: true,
Orphan: false,
},
},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
moduleName := parser.GetArg(2).String()
if moduleName == "" {
println("moduleName is empty")
return nil
}
err = service.CreatModule(ctx, moduleName)
return
},
}
M = &gcmd.Command{
Name: "m",
Usage: "cool-tools module moduleName",
Brief: "在modules目录下创建模块,为module的简写模式",
Description: "在modules目录下创建模块, 并且创建相应的目录结构,注意: 如果模块已经存在, 则会覆盖原有的模块,本命令需在项目根目录下执行.",
Arguments: []gcmd.Argument{
{
Name: "moduleName",
IsArg: true,
Orphan: false,
},
},
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
moduleName := parser.GetArg(2).String()
if moduleName == "" {
println("moduleName is empty")
return nil
}
err = service.CreatModule(ctx, moduleName)
return
},
}
)
func init() {
Main.AddCommand(Module)
Main.AddCommand(M)
}

View File

@@ -0,0 +1,61 @@
package cmd
import (
"context"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
)
var (
SnippetsMaker = gcmd.Command{
Name: "snippetsmaker",
Usage: "snippetsmaker",
Brief: "代码片段生成器",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
g.Log().Debug(ctx, "snippetsmaker,生成工具^.^")
files := garray.New(true)
files.Append("modules/demo/model/demo_sample.go")
files.Append("modules/demo/service/demo_sample.go")
files.Append("modules/demo/controller/admin/demo_sample.go")
// 遍历files
for _, file := range files.Slice() {
sArray := garray.NewStrArray()
gfile.ReadLines(file.(string), func(line string) error {
// g.Log().Debug(ctx, line)
// println(line)
// search := `Sample`
// replace := `${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}`
// replaceArray := []string{"Sample", "${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}", "sample", "${TM_FILENAME_BASE/(.*)/${1:/downcase}/}", "demo", "${2:模块名称}", "app", "${TM_DIRECTORY/^.+[\\/\\\\]+(.*)$/$1/}"}
replaceArray := []string{"DemoSample", "${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/}", "demo_sample", "${TM_FILENAME_BASE/(.*)/${1:/downcase}/}"}
result := gstr.ReplaceByArray(line, replaceArray)
sArray.Append(gstr.AddSlashes(result))
return nil
})
// g.Dump(sArray)
println(file.(string))
println("--------------------------------------code start------------------------------------------")
println(`"body":[`)
sArray.Iterator(
func(index int, value string) bool {
println("\"" + value + "\",")
return true
},
)
println("]")
println("--------------------------------------code end------------------------------------------")
}
return nil
},
}
)
func init() {
Main.AddCommand(&SnippetsMaker)
}

View File

@@ -0,0 +1,53 @@
package cmd
import (
"context"
"github.com/gogf/gf/v2/os/gbuild"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/util/gutil"
)
type sVersion struct {
Name string //程序名称
Homepage string //程序主页
Version string //程序版本
GoFrame string //goframe version
Golang string //golang version
Git string //git commit id
Time string //build datetime
InstallPath string //安装路径
}
var (
Version = gcmd.Command{
Name: "version",
Usage: "cool-tools version",
Brief: "查看版本信息",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
info := gbuild.Info()
binVersion := "v1.5.10"
// 生成sVersion结构体
res := sVersion{
Name: "cool-tools",
Homepage: "https://cool-js.com",
Version: binVersion,
GoFrame: info.GoFrame,
Golang: info.Golang,
Git: info.Git,
Time: info.Time,
InstallPath: gfile.SelfDir(),
}
// mlog.Printf(`CLI Installed At: %s`, gfile.SelfPath())
gutil.Dump(res)
return nil
},
}
)
// init 初始化模块
func init() {
Main.AddCommand(&Version)
}