Explorar o código

feat: Replace cli to cobra (#1855)

* Replace cli

* Replace cli

* Replace cli

* Format code

* Add compare case

* Add compare case

* Add compare case

* Support go style flag

* Support go style flag

* Add test case
anqiansong %!s(int64=3) %!d(string=hai) anos
pai
achega
5383e29ce6
Modificáronse 61 ficheiros con 1856 adicións e 1588 borrados
  1. 19 15
      tools/goctl/api/apigen/gen.go
  2. 1 2
      tools/goctl/api/apigen/template.go
  3. 176 0
      tools/goctl/api/cmd.go
  4. 17 6
      tools/goctl/api/dartgen/gen.go
  5. 11 4
      tools/goctl/api/docgen/gen.go
  6. 20 13
      tools/goctl/api/format/format.go
  7. 23 9
      tools/goctl/api/gogen/gen.go
  8. 1 2
      tools/goctl/api/gogen/template.go
  9. 11 4
      tools/goctl/api/javagen/gen.go
  10. 14 5
      tools/goctl/api/ktgen/cmd.go
  11. 21 21
      tools/goctl/api/new/newservice.go
  12. 1 2
      tools/goctl/api/new/template.go
  13. 20 7
      tools/goctl/api/tsgen/gen.go
  14. 6 3
      tools/goctl/api/validate/validate.go
  15. 2 2
      tools/goctl/bug/bug.go
  16. 11 0
      tools/goctl/bug/cmd.go
  17. 101 0
      tools/goctl/cmd/root.go
  18. 23 0
      tools/goctl/compare/cmd/cmd.go
  19. 11 0
      tools/goctl/compare/compare.go
  20. 7 0
      tools/goctl/compare/make.sh
  21. 17 0
      tools/goctl/compare/testdata/kotlin.api
  22. 470 0
      tools/goctl/compare/testdata/testcase.go
  23. 120 0
      tools/goctl/compare/testdata/testdata.go
  24. 3 0
      tools/goctl/compare/testdata/unformat.api
  25. 34 0
      tools/goctl/compare/testdata/user.sql
  26. 0 77
      tools/goctl/completion/completion.go
  27. 0 12
      tools/goctl/completion/const.go
  28. 0 51
      tools/goctl/completion/script.go
  29. 32 0
      tools/goctl/docker/cmd.go
  30. 11 15
      tools/goctl/docker/docker.go
  31. 1 2
      tools/goctl/docker/template.go
  32. 3 6
      tools/goctl/env/check.go
  33. 46 0
      tools/goctl/env/cmd.go
  34. 4 5
      tools/goctl/env/env.go
  35. 5 5
      tools/goctl/env/install.go
  36. 1 1
      tools/goctl/go.mod
  37. 7 5
      tools/goctl/go.sum
  38. 2 947
      tools/goctl/goctl.go
  39. 1 1
      tools/goctl/internal/version/version.go
  40. 71 0
      tools/goctl/kube/cmd.go
  41. 22 22
      tools/goctl/kube/kube.go
  42. 23 0
      tools/goctl/migrate/cmd.go
  43. 9 11
      tools/goctl/migrate/migrate.go
  44. 91 0
      tools/goctl/model/cmd.go
  45. 1 2
      tools/goctl/model/mongo/generate/template.go
  46. 26 9
      tools/goctl/model/mongo/mongo.go
  47. 62 48
      tools/goctl/model/sql/command/command.go
  48. 2 3
      tools/goctl/model/sql/command/migrationnotes/migrationnotes.go
  49. 1 5
      tools/goctl/model/sql/command/migrationnotes/v1.3.4.go
  50. 1 2
      tools/goctl/model/sql/gen/template.go
  51. 19 8
      tools/goctl/plugin/plugin.go
  52. 46 24
      tools/goctl/rpc/cli/cli.go
  53. 29 79
      tools/goctl/rpc/cli/zrpc.go
  54. 0 125
      tools/goctl/rpc/cli/zrpc_test.go
  55. 90 0
      tools/goctl/rpc/cmd.go
  56. 1 2
      tools/goctl/rpc/generator/template.go
  57. 55 0
      tools/goctl/tpl/cmd.go
  58. 24 24
      tools/goctl/tpl/templates.go
  59. 10 0
      tools/goctl/upgrade/cmd.go
  60. 2 2
      tools/goctl/upgrade/upgrade.go
  61. 18 0
      tools/goctl/util/pathx/file.go

+ 19 - 15
tools/goctl/api/apigen/gen.go

@@ -9,7 +9,7 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
@@ -17,13 +17,20 @@ import (
 //go:embed api.tpl
 //go:embed api.tpl
 var apiTemplate string
 var apiTemplate string
 
 
-// ApiCommand create api template file
-func ApiCommand(c *cli.Context) error {
-	if c.NumFlags() == 0 {
-		cli.ShowAppHelpAndExit(c, 1)
-	}
+var (
+	// VarStringOutput describes the output.
+	VarStringOutput string
+	// VarStringHome describes the goctl home.
+	VarStringHome string
+	// VarStringRemote describes the remote git repository.
+	VarStringRemote string
+	// VarStringBranch describes the git branch.
+	VarStringBranch string
+)
 
 
-	apiFile := c.String("o")
+// CreateApiTemplate create api template file
+func CreateApiTemplate(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringOutput
 	if len(apiFile) == 0 {
 	if len(apiFile) == 0 {
 		return errors.New("missing -o")
 		return errors.New("missing -o")
 	}
 	}
@@ -34,18 +41,15 @@ func ApiCommand(c *cli.Context) error {
 	}
 	}
 	defer fp.Close()
 	defer fp.Close()
 
 
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
-	if len(remote) > 0 {
-		repo, _ := util.CloneIntoGitHome(remote, branch)
+	if len(VarStringRemote) > 0 {
+		repo, _ := util.CloneIntoGitHome(VarStringRemote, VarStringBranch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
-			home = repo
+			VarStringHome = repo
 		}
 		}
 	}
 	}
 
 
-	if len(home) > 0 {
-		pathx.RegisterGoctlHome(home)
+	if len(VarStringHome) > 0 {
+		pathx.RegisterGoctlHome(VarStringHome)
 	}
 	}
 
 
 	text, err := pathx.LoadTemplate(category, apiTemplateFile, apiTemplate)
 	text, err := pathx.LoadTemplate(category, apiTemplateFile, apiTemplate)

+ 1 - 2
tools/goctl/api/apigen/template.go

@@ -3,7 +3,6 @@ package apigen
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
@@ -27,7 +26,7 @@ func Clean() error {
 }
 }
 
 
 // GenTemplates generates api template files.
 // GenTemplates generates api template files.
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return pathx.InitTemplates(category, templates)
 	return pathx.InitTemplates(category, templates)
 }
 }
 
 

+ 176 - 0
tools/goctl/api/cmd.go

@@ -0,0 +1,176 @@
+package api
+
+import (
+	"github.com/spf13/cobra"
+	"github.com/zeromicro/go-zero/tools/goctl/api/apigen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/dartgen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/docgen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/format"
+	"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/javagen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/ktgen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/new"
+	"github.com/zeromicro/go-zero/tools/goctl/api/tsgen"
+	"github.com/zeromicro/go-zero/tools/goctl/api/validate"
+	"github.com/zeromicro/go-zero/tools/goctl/plugin"
+)
+
+var (
+	// Cmd describes a api command.
+	Cmd = &cobra.Command{
+		Use:   "api",
+		Short: "Generate api related files",
+		RunE:  apigen.CreateApiTemplate,
+	}
+
+	dartCmd = &cobra.Command{
+		Use:   "dart",
+		Short: "Generate dart files for provided api in api file",
+		RunE:  dartgen.DartCommand,
+	}
+
+	docCmd = &cobra.Command{
+		Use:   "doc",
+		Short: "Generate doc files",
+		RunE:  docgen.DocCommand,
+	}
+
+	formatCmd = &cobra.Command{
+		Use:   "format",
+		Short: "Format api files",
+		RunE:  format.GoFormatApi,
+	}
+
+	goCmd = &cobra.Command{
+		Use:   "go",
+		Short: "Generate go files for provided api in yaml file",
+		RunE:  gogen.GoCommand,
+	}
+
+	newCmd = &cobra.Command{
+		Use:     "new",
+		Short:   "Fast create api service",
+		Example: "goctl api new [options] service-name",
+		Args:    cobra.ExactValidArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return new.CreateServiceCommand(args)
+		},
+	}
+
+	validateCmd = &cobra.Command{
+		Use:   "validate",
+		Short: "Validate api file",
+		RunE:  validate.GoValidateApi,
+	}
+
+	javaCmd = &cobra.Command{
+		Use:   "java",
+		Short: "Generate java files for provided api in api file",
+		RunE:  javagen.JavaCommand,
+	}
+
+	ktCmd = &cobra.Command{
+		Use:   "kt",
+		Short: "Generate kotlin code for provided api file",
+		RunE:  ktgen.KtCommand,
+	}
+
+	pluginCmd = &cobra.Command{
+		Use:   "plugin",
+		Short: "Custom file generator",
+		RunE:  plugin.PluginCommand,
+	}
+
+	tsCmd = &cobra.Command{
+		Use:   "ts",
+		Short: "Generate ts files for provided api in api file",
+		RunE:  tsgen.TsCommand,
+	}
+)
+
+func init() {
+	Cmd.Flags().StringVar(&apigen.VarStringOutput, "o", "", "Output a sample api file")
+	Cmd.Flags().StringVar(&apigen.VarStringHome, "home", "", "The goctl home path of the"+
+		" template, --home and --remote cannot be set at the same time, if they are, --remote has "+
+		"higher priority")
+	Cmd.Flags().StringVar(&apigen.VarStringRemote, "remote", "", "The remote git repo of the"+
+		" template, --home and --remote cannot be set at the same time, if they are, --remote has higher"+
+		" priority\n\tThe git repo directory must be consistent with the"+
+		" https://github.com/zeromicro/go-zero-template directory structure")
+	Cmd.Flags().StringVar(&apigen.VarStringBranch, "branch", "master", "The branch of the "+
+		"remote repo, it does work with --remote")
+
+	dartCmd.Flags().StringVar(&dartgen.VarStringDir, "dir", "", "The target dir")
+	dartCmd.Flags().StringVar(&dartgen.VarStringAPI, "api", "", "The api file")
+	dartCmd.Flags().BoolVar(&dartgen.VarStringLegacy, "legacy", false, "Legacy generator for flutter v1")
+	dartCmd.Flags().StringVar(&dartgen.VarStringHostname, "hostname", "", "hostname of the server")
+
+	docCmd.Flags().StringVar(&docgen.VarStringDir, "dir", "", "The target dir")
+	docCmd.Flags().StringVar(&docgen.VarStringOutput, "o", "", "The output markdown directory")
+
+	formatCmd.Flags().StringVar(&format.VarStringDir, "dir", "", "The format target dir")
+	formatCmd.Flags().BoolVar(&format.VarBoolIgnore, "iu", false, "Ignore update")
+	formatCmd.Flags().BoolVar(&format.VarBoolUseStdin, "stdin", false, "Use stdin to input api"+
+		" doc content, press \"ctrl + d\" to send EOF")
+	formatCmd.Flags().BoolVar(&format.VarBoolSkipCheckDeclare, "declare", false, "Use to skip check "+
+		"api types already declare")
+
+	goCmd.Flags().StringVar(&gogen.VarStringDir, "dir", "", "The target dir")
+	goCmd.Flags().StringVar(&gogen.VarStringAPI, "api", "", "The api file")
+	goCmd.Flags().StringVar(&gogen.VarStringHome, "home", "", "The goctl home path of "+
+		"the template, --home and --remote cannot be set at the same time, if they are, --remote "+
+		"has higher priority")
+	goCmd.Flags().StringVar(&gogen.VarStringRemote, "remote", "", "The remote git repo "+
+		"of the template, --home and --remote cannot be set at the same time, if they are, --remote"+
+		" has higher priority\n\tThe git repo directory must be consistent with the "+
+		"https://github.com/zeromicro/go-zero-template directory structure")
+	goCmd.Flags().StringVar(&gogen.VarStringBranch, "branch", "master", "The branch of "+
+		"the remote repo, it does work with --remote")
+	goCmd.Flags().StringVar(&gogen.VarStringStyle, "style", "gozero", "The file naming format,"+
+		" see [https://github.com/zeromicro/go-zero/blob/master/tools/goctl/config/readme.md]")
+
+	javaCmd.Flags().StringVar(&javagen.VarStringDir, "dir", "", "The target dir")
+	javaCmd.Flags().StringVar(&javagen.VarStringAPI, "api", "", "The api file")
+
+	ktCmd.Flags().StringVar(&ktgen.VarStringDir, "dir", "", "The target dir")
+	ktCmd.Flags().StringVar(&ktgen.VarStringAPI, "api", "", "The api file")
+	ktCmd.Flags().StringVar(&ktgen.VarStringPKG, "pkg", "", "Define package name for kotlin file")
+
+	newCmd.Flags().StringVar(&new.VarStringHome, "home", "", "The goctl home path of "+
+		"the template, --home and --remote cannot be set at the same time, if they are, --remote "+
+		"has higher priority")
+	newCmd.Flags().StringVar(&new.VarStringRemote, "remote", "", "The remote git repo "+
+		"of the template, --home and --remote cannot be set at the same time, if they are, --remote"+
+		" has higher priority\n\tThe git repo directory must be consistent with the "+
+		"https://github.com/zeromicro/go-zero-template directory structure")
+	newCmd.Flags().StringVar(&new.VarStringBranch, "branch", "master", "The branch of "+
+		"the remote repo, it does work with --remote")
+	newCmd.Flags().StringVar(&new.VarStringStyle, "style", "gozero", "The file naming format,"+
+		" see [https://github.com/zeromicro/go-zero/blob/master/tools/goctl/config/readme.md]")
+
+	pluginCmd.Flags().StringVarP(&plugin.VarStringPlugin, "plugin", "p", "", "The plugin file")
+	pluginCmd.Flags().StringVar(&plugin.VarStringDir, "dir", "", "The target dir")
+	pluginCmd.Flags().StringVar(&plugin.VarStringAPI, "api", "", "The api file")
+	pluginCmd.Flags().StringVar(&plugin.VarStringStyle, "style", "",
+		"The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+
+	tsCmd.Flags().StringVar(&tsgen.VarStringDir, "dir", "", "The target dir")
+	tsCmd.Flags().StringVar(&tsgen.VarStringAPI, "api", "", "The api file")
+	tsCmd.Flags().StringVar(&tsgen.VarStringWebAPI, "webapi", "", "The web api file path")
+	tsCmd.Flags().StringVar(&tsgen.VarStringCaller, "caller", "", "The web api caller")
+	tsCmd.Flags().BoolVar(&tsgen.VarBoolUnWrap, "unwrap", false, "Unwrap the webapi caller for import")
+
+	validateCmd.Flags().StringVar(&validate.VarStringAPI, "api", "", "Validate target api file")
+
+	// Add sub-commands
+	Cmd.AddCommand(dartCmd)
+	Cmd.AddCommand(docCmd)
+	Cmd.AddCommand(formatCmd)
+	Cmd.AddCommand(goCmd)
+	Cmd.AddCommand(javaCmd)
+	Cmd.AddCommand(ktCmd)
+	Cmd.AddCommand(newCmd)
+	Cmd.AddCommand(pluginCmd)
+	Cmd.AddCommand(tsCmd)
+	Cmd.AddCommand(validateCmd)
+}

+ 17 - 6
tools/goctl/api/dartgen/gen.go

@@ -5,17 +5,28 @@ import (
 	"fmt"
 	"fmt"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 )
 )
 
 
+var (
+	// VarStringDir describes the directory.
+	VarStringDir string
+	// VarStringAPI defines the API.
+	VarStringAPI string
+	// VarStringLegacy describes whether legacy.
+	VarStringLegacy bool
+	// VarStringHostname defines the hostname.
+	VarStringHostname string
+)
+
 // DartCommand create dart network request code
 // DartCommand create dart network request code
-func DartCommand(c *cli.Context) error {
-	apiFile := c.String("api")
-	dir := c.String("dir")
-	isLegacy := c.Bool("legacy")
-	hostname := c.String("hostname")
+func DartCommand(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringAPI
+	dir := VarStringDir
+	isLegacy := VarStringLegacy
+	hostname := VarStringHostname
 	if len(apiFile) == 0 {
 	if len(apiFile) == 0 {
 		return errors.New("missing -api")
 		return errors.New("missing -api")
 	}
 	}

+ 11 - 4
tools/goctl/api/docgen/gen.go

@@ -7,19 +7,26 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
+var (
+	// VarStringDir describes a directory.
+	VarStringDir string
+	// VarStringOutput describes an output directory.
+	VarStringOutput string
+)
+
 // DocCommand generate Markdown doc file
 // DocCommand generate Markdown doc file
-func DocCommand(c *cli.Context) error {
-	dir := c.String("dir")
+func DocCommand(_ *cobra.Command, _ []string) error {
+	dir := VarStringDir
 	if len(dir) == 0 {
 	if len(dir) == 0 {
 		return errors.New("missing -dir")
 		return errors.New("missing -dir")
 	}
 	}
 
 
-	outputDir := c.String("o")
+	outputDir := VarStringOutput
 	if len(outputDir) == 0 {
 	if len(outputDir) == 0 {
 		var err error
 		var err error
 		outputDir, err = os.Getwd()
 		outputDir, err = os.Getwd()

+ 20 - 13
tools/goctl/api/format/format.go

@@ -12,7 +12,7 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/errorx"
 	"github.com/zeromicro/go-zero/core/errorx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/util"
 	"github.com/zeromicro/go-zero/tools/goctl/api/util"
@@ -26,30 +26,37 @@ const (
 	rightBrace       = "}"
 	rightBrace       = "}"
 )
 )
 
 
-// GoFormatApi format api file
-func GoFormatApi(c *cli.Context) error {
-	useStdin := c.Bool("stdin")
-	skipCheckDeclare := c.Bool("declare")
-	dir := c.String("dir")
+var (
+	// VarBoolUseStdin describes whether to use stdin or not.
+	VarBoolUseStdin bool
+	// VarBoolSkipCheckDeclare describes whether to skip.
+	VarBoolSkipCheckDeclare bool
+	// VarStringDir describes the directory.
+	VarStringDir string
+	// VarBoolIgnore describes whether to ignore.
+	VarBoolIgnore bool
+)
 
 
+// GoFormatApi format api file
+func GoFormatApi(_ *cobra.Command, _ []string) error {
 	var be errorx.BatchError
 	var be errorx.BatchError
-	if useStdin {
-		if err := apiFormatReader(os.Stdin, dir, skipCheckDeclare); err != nil {
+	if VarBoolUseStdin {
+		if err := apiFormatReader(os.Stdin, VarStringDir, VarBoolSkipCheckDeclare); err != nil {
 			be.Add(err)
 			be.Add(err)
 		}
 		}
 	} else {
 	} else {
-		if len(dir) == 0 {
+		if len(VarStringDir) == 0 {
 			return errors.New("missing -dir")
 			return errors.New("missing -dir")
 		}
 		}
 
 
-		_, err := os.Lstat(dir)
+		_, err := os.Lstat(VarStringDir)
 		if err != nil {
 		if err != nil {
-			return errors.New(dir + ": No such file or directory")
+			return errors.New(VarStringDir + ": No such file or directory")
 		}
 		}
 
 
-		err = filepath.Walk(dir, func(path string, fi os.FileInfo, errBack error) (err error) {
+		err = filepath.Walk(VarStringDir, func(path string, fi os.FileInfo, errBack error) (err error) {
 			if strings.HasSuffix(path, ".api") {
 			if strings.HasSuffix(path, ".api") {
-				if err := ApiFormatByPath(path, skipCheckDeclare); err != nil {
+				if err := ApiFormatByPath(path, VarBoolSkipCheckDeclare); err != nil {
 					be.Add(util.WrapErr(err, fi.Name()))
 					be.Add(util.WrapErr(err, fi.Name()))
 				}
 				}
 			}
 			}

+ 23 - 9
tools/goctl/api/gogen/gen.go

@@ -12,7 +12,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/logx"
 	apiformat "github.com/zeromicro/go-zero/tools/goctl/api/format"
 	apiformat "github.com/zeromicro/go-zero/tools/goctl/api/format"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
@@ -24,16 +24,30 @@ import (
 
 
 const tmpFile = "%s-%d"
 const tmpFile = "%s-%d"
 
 
-var tmpDir = path.Join(os.TempDir(), "goctl")
+var (
+	tmpDir = path.Join(os.TempDir(), "goctl")
+	// VarStringDir describes the directory.
+	VarStringDir string
+	// VarStringAPI describes the API.
+	VarStringAPI string
+	// VarStringHome describes the go home.
+	VarStringHome string
+	// VarStringRemote describes the remote git repository.
+	VarStringRemote string
+	// VarStringBranch describes the branch.
+	VarStringBranch string
+	// VarStringStyle describes the style of output files.
+	VarStringStyle string
+)
 
 
 // GoCommand gen go project files from command line
 // GoCommand gen go project files from command line
-func GoCommand(c *cli.Context) error {
-	apiFile := c.String("api")
-	dir := c.String("dir")
-	namingStyle := c.String("style")
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
+func GoCommand(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringAPI
+	dir := VarStringDir
+	namingStyle := VarStringStyle
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {

+ 1 - 2
tools/goctl/api/gogen/template.go

@@ -3,7 +3,6 @@ package gogen
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
@@ -45,7 +44,7 @@ func Clean() error {
 }
 }
 
 
 // GenTemplates generates api template files.
 // GenTemplates generates api template files.
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return pathx.InitTemplates(category, templates)
 	return pathx.InitTemplates(category, templates)
 }
 }
 
 

+ 11 - 4
tools/goctl/api/javagen/gen.go

@@ -6,16 +6,23 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
+var (
+	// VarStringDir describes a directory.
+	VarStringDir string
+	// VarStringAPI describes an API.
+	VarStringAPI string
+)
+
 // JavaCommand generates java code command entrance.
 // JavaCommand generates java code command entrance.
-func JavaCommand(c *cli.Context) error {
-	apiFile := c.String("api")
-	dir := c.String("dir")
+func JavaCommand(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringAPI
+	dir := VarStringDir
 	if len(apiFile) == 0 {
 	if len(apiFile) == 0 {
 		return errors.New("missing -api")
 		return errors.New("missing -api")
 	}
 	}

+ 14 - 5
tools/goctl/api/ktgen/cmd.go

@@ -3,21 +3,30 @@ package ktgen
 import (
 import (
 	"errors"
 	"errors"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 )
 )
 
 
+var (
+	// VarStringDir describes a directory.
+	VarStringDir string
+	// VarStringAPI describes an API.
+	VarStringAPI string
+	// VarStringPKG describes a package.
+	VarStringPKG string
+)
+
 // KtCommand generates kotlin code command entrance
 // KtCommand generates kotlin code command entrance
-func KtCommand(c *cli.Context) error {
-	apiFile := c.String("api")
+func KtCommand(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringAPI
 	if apiFile == "" {
 	if apiFile == "" {
 		return errors.New("missing -api")
 		return errors.New("missing -api")
 	}
 	}
-	dir := c.String("dir")
+	dir := VarStringDir
 	if dir == "" {
 	if dir == "" {
 		return errors.New("missing -dir")
 		return errors.New("missing -dir")
 	}
 	}
-	pkg := c.String("pkg")
+	pkg := VarStringPKG
 	if pkg == "" {
 	if pkg == "" {
 		return errors.New("missing -pkg")
 		return errors.New("missing -pkg")
 	}
 	}

+ 21 - 21
tools/goctl/api/new/newservice.go

@@ -8,7 +8,6 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
 	"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
 	conf "github.com/zeromicro/go-zero/tools/goctl/config"
 	conf "github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
@@ -18,18 +17,22 @@ import (
 //go:embed api.tpl
 //go:embed api.tpl
 var apiTemplate string
 var apiTemplate string
 
 
-// CreateServiceCommand fast create service
-func CreateServiceCommand(c *cli.Context) error {
-	if c.NArg() == 0 {
-		cli.ShowCommandHelpAndExit(c, "new", 1)
-	}
-
-	args := c.Args()
-	dirName := args.First()
+var (
+	// VarStringHome describes the goctl home.
+	VarStringHome string
+	// VarStringRemote describes the remote git repository.
+	VarStringRemote string
+	// VarStringBranch describes the git branch.
+	VarStringBranch string
+	// VarStringStyle describes the style of output files.
+	VarStringStyle string
+)
 
 
-	dirStyle := c.String("style")
-	if len(dirStyle) == 0 {
-		dirStyle = conf.DefaultFormat
+// CreateServiceCommand fast create service
+func CreateServiceCommand(args []string) error {
+	dirName := args[0]
+	if len(VarStringStyle) == 0 {
+		VarStringStyle = conf.DefaultFormat
 	}
 	}
 	if strings.Contains(dirName, "-") {
 	if strings.Contains(dirName, "-") {
 		return errors.New("api new command service name not support strikethrough, because this will used by function name")
 		return errors.New("api new command service name not support strikethrough, because this will used by function name")
@@ -55,18 +58,15 @@ func CreateServiceCommand(c *cli.Context) error {
 
 
 	defer fp.Close()
 	defer fp.Close()
 
 
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
-	if len(remote) > 0 {
-		repo, _ := util.CloneIntoGitHome(remote, branch)
+	if len(VarStringRemote) > 0 {
+		repo, _ := util.CloneIntoGitHome(VarStringRemote, VarStringBranch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
-			home = repo
+			VarStringHome = repo
 		}
 		}
 	}
 	}
 
 
-	if len(home) > 0 {
-		pathx.RegisterGoctlHome(home)
+	if len(VarStringHome) > 0 {
+		pathx.RegisterGoctlHome(VarStringHome)
 	}
 	}
 
 
 	text, err := pathx.LoadTemplate(category, apiTemplateFile, apiTemplate)
 	text, err := pathx.LoadTemplate(category, apiTemplateFile, apiTemplate)
@@ -82,6 +82,6 @@ func CreateServiceCommand(c *cli.Context) error {
 		return err
 		return err
 	}
 	}
 
 
-	err = gogen.DoGenProject(apiFilePath, abs, dirStyle)
+	err = gogen.DoGenProject(apiFilePath, abs, VarStringStyle)
 	return err
 	return err
 }
 }

+ 1 - 2
tools/goctl/api/new/template.go

@@ -3,7 +3,6 @@ package new
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
@@ -27,7 +26,7 @@ func Clean() error {
 }
 }
 
 
 // GenTemplates generates api template files.
 // GenTemplates generates api template files.
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return pathx.InitTemplates(category, templates)
 	return pathx.InitTemplates(category, templates)
 }
 }
 
 

+ 20 - 7
tools/goctl/api/tsgen/gen.go

@@ -5,19 +5,32 @@ import (
 	"fmt"
 	"fmt"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
+var (
+	// VarStringDir describes a directory.
+	VarStringDir string
+	// VarStringAPI describes an API file.
+	VarStringAPI string
+	// VarStringWebAPI describes a web API file.
+	VarStringWebAPI string
+	// VarStringCaller describes a caller.
+	VarStringCaller string
+	// VarBoolUnWrap describes whether wrap or not.
+	VarBoolUnWrap bool
+)
+
 // TsCommand provides the entry to generate typescript codes
 // TsCommand provides the entry to generate typescript codes
-func TsCommand(c *cli.Context) error {
-	apiFile := c.String("api")
-	dir := c.String("dir")
-	webAPI := c.String("webapi")
-	caller := c.String("caller")
-	unwrapAPI := c.Bool("unwrap")
+func TsCommand(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringAPI
+	dir := VarStringDir
+	webAPI := VarStringWebAPI
+	caller := VarStringCaller
+	unwrapAPI := VarBoolUnWrap
 	if len(apiFile) == 0 {
 	if len(apiFile) == 0 {
 		return errors.New("missing -api")
 		return errors.New("missing -api")
 	}
 	}

+ 6 - 3
tools/goctl/api/validate/validate.go

@@ -5,13 +5,16 @@ import (
 	"fmt"
 	"fmt"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 )
 )
 
 
+// VarStringAPI describes an API.
+var VarStringAPI string
+
 // GoValidateApi verifies whether the api has a syntax error
 // GoValidateApi verifies whether the api has a syntax error
-func GoValidateApi(c *cli.Context) error {
-	apiFile := c.String("api")
+func GoValidateApi(_ *cobra.Command, _ []string) error {
+	apiFile := VarStringAPI
 
 
 	if len(apiFile) == 0 {
 	if len(apiFile) == 0 {
 		return errors.New("missing -api")
 		return errors.New("missing -api")

+ 2 - 2
tools/goctl/bug/bug.go

@@ -6,7 +6,7 @@ import (
 	"os/exec"
 	"os/exec"
 	"runtime"
 	"runtime"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/internal/version"
 	"github.com/zeromicro/go-zero/tools/goctl/internal/version"
 )
 )
 
 
@@ -29,7 +29,7 @@ var openCmd = map[string]string{
 	darwin:  darwinOpen,
 	darwin:  darwinOpen,
 }
 }
 
 
-func Action(_ *cli.Context) error {
+func runE(_ *cobra.Command, _ []string) error {
 	env := getEnv()
 	env := getEnv()
 	content := fmt.Sprintf(issueTemplate, version.BuildVersion, env.string())
 	content := fmt.Sprintf(issueTemplate, version.BuildVersion, env.string())
 	content = url.QueryEscape(content)
 	content = url.QueryEscape(content)

+ 11 - 0
tools/goctl/bug/cmd.go

@@ -0,0 +1,11 @@
+package bug
+
+import "github.com/spf13/cobra"
+
+// Cmd describes a bug command.
+var Cmd = &cobra.Command{
+	Use:   "bug",
+	Short: "Report a bug",
+	Args:  cobra.NoArgs,
+	RunE:  runE,
+}

+ 101 - 0
tools/goctl/cmd/root.go

@@ -0,0 +1,101 @@
+package cmd
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"strings"
+
+	"github.com/logrusorgru/aurora"
+	"github.com/spf13/cobra"
+	"github.com/zeromicro/go-zero/tools/goctl/api"
+	"github.com/zeromicro/go-zero/tools/goctl/bug"
+	"github.com/zeromicro/go-zero/tools/goctl/docker"
+	"github.com/zeromicro/go-zero/tools/goctl/env"
+	"github.com/zeromicro/go-zero/tools/goctl/internal/version"
+	"github.com/zeromicro/go-zero/tools/goctl/kube"
+	"github.com/zeromicro/go-zero/tools/goctl/migrate"
+	"github.com/zeromicro/go-zero/tools/goctl/model"
+	"github.com/zeromicro/go-zero/tools/goctl/rpc"
+	"github.com/zeromicro/go-zero/tools/goctl/tpl"
+	"github.com/zeromicro/go-zero/tools/goctl/upgrade"
+)
+
+const (
+	codeFailure = 1
+	dash        = "-"
+	doubleDash  = "--"
+	assign      = "="
+)
+
+var rootCmd = &cobra.Command{
+	Use:   "goctl",
+	Short: "A cli tool to generate go-zero code",
+	Long:  "A cli tool to generate api, zrpc, model code",
+}
+
+// Execute executes the given command
+func Execute() {
+	os.Args = supportGoStdFlag(os.Args)
+	if err := rootCmd.Execute(); err != nil {
+		fmt.Println(aurora.Red(err.Error()))
+		os.Exit(codeFailure)
+	}
+}
+
+func supportGoStdFlag(args []string) []string {
+	copyArgs := append([]string(nil), args...)
+	parentCmd, _, err := rootCmd.Traverse(args[:1])
+	if err != nil { // ignore it to let cobra handle the error.
+		return copyArgs
+	}
+
+	for idx, arg := range copyArgs[0:] {
+		parentCmd, _, err = parentCmd.Traverse([]string{arg})
+		if err != nil { // ignore it to let cobra handle the error.
+			break
+		}
+		if !strings.HasPrefix(arg, dash) {
+			continue
+		}
+
+		flagExpr := strings.TrimPrefix(arg, doubleDash)
+		flagExpr = strings.TrimPrefix(flagExpr, dash)
+		flagName, flagValue := flagExpr, ""
+		assignIndex := strings.Index(flagExpr, assign)
+		if assignIndex > 0 {
+			flagName = flagExpr[:assignIndex]
+			flagValue = flagExpr[assignIndex:]
+		}
+
+		f := parentCmd.Flag(flagName)
+		if f == nil {
+			continue
+		}
+		if f.Shorthand == flagName {
+			continue
+		}
+
+		goStyleFlag := doubleDash + f.Name
+		if assignIndex > 0 {
+			goStyleFlag += flagValue
+		}
+
+		copyArgs[idx] = goStyleFlag
+	}
+	return copyArgs
+}
+
+func init() {
+	rootCmd.Version = fmt.Sprintf("%s %s/%s", version.BuildVersion, runtime.GOOS, runtime.GOARCH)
+	rootCmd.AddCommand(api.Cmd)
+	rootCmd.AddCommand(bug.Cmd)
+	rootCmd.AddCommand(docker.Cmd)
+	rootCmd.AddCommand(kube.Cmd)
+	rootCmd.AddCommand(env.Cmd)
+	rootCmd.AddCommand(model.Cmd)
+	rootCmd.AddCommand(migrate.Cmd)
+	rootCmd.AddCommand(rpc.Cmd)
+	rootCmd.AddCommand(tpl.Cmd)
+	rootCmd.AddCommand(upgrade.Cmd)
+}

+ 23 - 0
tools/goctl/compare/cmd/cmd.go

@@ -0,0 +1,23 @@
+package cmd
+
+import (
+	"github.com/spf13/cobra"
+	"github.com/zeromicro/go-zero/tools/goctl/compare/testdata"
+	"github.com/zeromicro/go-zero/tools/goctl/util/console"
+)
+
+var rootCmd = &cobra.Command{
+	Use:   "compare",
+	Short: "Compare the goctl commands generated results between urfave and cobra",
+	Args:  cobra.ExactValidArgs(1),
+	Run: func(cmd *cobra.Command, args []string) {
+		dir := args[0]
+		testdata.MustRun(dir)
+	},
+}
+
+func Execute() {
+	if err := rootCmd.Execute(); err != nil {
+		console.Error("%+v", err)
+	}
+}

+ 11 - 0
tools/goctl/compare/compare.go

@@ -0,0 +1,11 @@
+package main
+
+import "github.com/zeromicro/go-zero/tools/goctl/compare/cmd"
+
+// EXPRIMENTAL: compare goctl generated code results between old and new, it will be removed in the feature.
+// TODO: BEFORE RUNNING: export DSN=$datasource, the database must be gozero, and there has no limit for tables.
+// TODO: AFTER RUNNING: diff --recursive old_fs new_fs
+
+func main() {
+	cmd.Execute()
+}

+ 7 - 0
tools/goctl/compare/make.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+wd=`dirname $0`
+GOBIN="$GOPATH/bin"
+EXE=goctl-compare
+go build -o $EXE $wd
+mv $EXE $GOBIN

+ 17 - 0
tools/goctl/compare/testdata/kotlin.api

@@ -0,0 +1,17 @@
+syntax = "v1"
+
+info(
+    title: "type title here"
+    desc: "type desc here"
+    author: "type author here"
+    email: "type email here"
+    version: "type version here"
+)
+
+type req{}
+type reply{}
+
+service kotlin-api{
+    @handler ping
+    post /ping
+}

+ 470 - 0
tools/goctl/compare/testdata/testcase.go

@@ -0,0 +1,470 @@
+package testdata
+
+import _ "embed"
+
+var (
+	//go:embed unformat.api
+	unformatApi string
+	//go:embed kotlin.api
+	kotlinApi string
+	//go:embed user.sql
+	userSql string
+
+	list = Files{
+		{
+			IsDir: true,
+			Path:  "version",
+			Cmd:   "goctl --version",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/local",
+			Cmd:   "goctl api --o sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/local/assign",
+			Cmd:   "goctl api --o=sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/local/assign/shorthand",
+			Cmd:   "goctl api -o=sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/remote",
+			Cmd:   "goctl api --o sample.api --remote https://github.com/zeromicro/go-zero-template --branch main",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/remote/shorthand",
+			Cmd:   "goctl api -o sample.api -remote https://github.com/zeromicro/go-zero-template -branch main",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/remote/assign",
+			Cmd:   "goctl api --o=sample.api --remote https://github.com/zeromicro/go-zero-template --branch=main",
+		},
+		{
+			IsDir: true,
+			Path:  "api/sample_file/remote/assign/shorthand",
+			Cmd:   "goctl api -o=sample.api -remote https://github.com/zeromicro/go-zero-template -branch=main",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/true",
+			Cmd:   "goctl api --o sample.api && goctl api dart --api sample.api --dir . --hostname 127.0.0.1 --legacy true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/true/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api dart -api sample.api -dir . -hostname 127.0.0.1 -legacy true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/true/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api dart --api=sample.api --dir=. --hostname=127.0.0.1 --legacy=true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/true/assign/shorthand",
+			Cmd:   "goctl api -o=sample.api && goctl api dart -api=sample.api -dir=. -hostname=127.0.0.1 -legacy=true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/false",
+			Cmd:   "goctl api --o sample.api && goctl api dart --api sample.api --dir . --hostname 127.0.0.1 --legacy true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/false/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api dart -api sample.api -dir . -hostname 127.0.0.1 -legacy true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/false/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api dart --api=sample.api --dir=. --hostname=127.0.0.1 --legacy=true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/dart/legacy/false/assign/shorthand",
+			Cmd:   "goctl api -o=sample.api && goctl api dart -api=sample.api -dir=. -hostname=127.0.0.1 -legacy=true",
+		},
+		{
+			IsDir: true,
+			Path:  "api/doc",
+			Cmd:   "goctl api --o sample.api && goctl api doc --dir . --o .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/doc/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api doc -dir . -o .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/doc/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api doc --dir=. --o=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/doc/assign/shorthand",
+			Cmd:   "goctl api -o=sample.api && goctl api doc -dir=. -o=.",
+		},
+		{
+			Path:    "api/format/unformat.api",
+			Content: unformatApi,
+			Cmd:     "goctl api format --dir . --iu",
+		},
+		{
+			Path:    "api/format/shorthand/unformat.api",
+			Content: unformatApi,
+			Cmd:     "goctl api format -dir . -iu",
+		},
+		{
+			Path:    "api/format/assign/unformat.api",
+			Content: unformatApi,
+			Cmd:     "goctl api format --dir=. --iu",
+		},
+		{
+			Path:    "api/format/assign/shorthand/unformat.api",
+			Content: unformatApi,
+			Cmd:     "goctl api format -dir=. -iu",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/default",
+			Cmd:   "goctl api --o sample.api && goctl api go --api sample.api --dir .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/default/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api go -api sample.api -dir .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/assign/default",
+			Cmd:   "goctl api --o=sample.api && goctl api go --api=sample.api --dir=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/assign/default/shorthand",
+			Cmd:   "goctl api -o=sample.api && goctl api go -api=sample.api -dir=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/goZero",
+			Cmd:   "goctl api --o sample.api && goctl api go --api sample.api --dir . --style goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/goZero/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api go -api sample.api -dir . -style goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/goZero/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api go --api=sample.api --dir=. --style=goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/go/style/goZero/assign/shorthand",
+			Cmd:   "goctl api -o=sample.api && goctl api go -api=sample.api -dir=. -style=goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/java",
+			Cmd:   "goctl api --o sample.api && goctl api java --api sample.api --dir .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/java/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api java -api sample.api -dir .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/java/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api java --api=sample.api --dir=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/java/shorthand/assign",
+			Cmd:   "goctl api -o=sample.api && goctl api java -api=sample.api -dir=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/new/style/default",
+			Cmd:   "goctl api new greet",
+		},
+		{
+			IsDir: true,
+			Path:  "api/new/style/goZero",
+			Cmd:   "goctl api new greet --style goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/new/style/goZero/assign",
+			Cmd:   "goctl api new greet --style=goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/new/style/goZero/shorthand",
+			Cmd:   "goctl api new greet -style goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/new/style/goZero/shorthand/assign",
+			Cmd:   "goctl api new greet -style=goZero",
+		},
+		{
+			IsDir: true,
+			Path:  "api/ts",
+			Cmd:   "goctl api --o sample.api && goctl api ts --api sample.api --dir . --unwrap --webapi .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/ts/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api ts -api sample.api -dir . -unwrap -webapi .",
+		},
+		{
+			IsDir: true,
+			Path:  "api/ts/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api ts --api=sample.api --dir=. --unwrap --webapi=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/ts/shorthand/assign",
+			Cmd:   "goctl api -o=sample.api && goctl api ts -api=sample.api -dir=. -unwrap -webapi=.",
+		},
+		{
+			IsDir: true,
+			Path:  "api/validate",
+			Cmd:   "goctl api --o sample.api && goctl api validate --api sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "api/validate/shorthand",
+			Cmd:   "goctl api -o sample.api && goctl api validate -api sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "api/validate/assign",
+			Cmd:   "goctl api --o=sample.api && goctl api validate --api=sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "api/validate/shorthand/assign",
+			Cmd:   "goctl api -o=sample.api && goctl api validate -api=sample.api",
+		},
+		{
+			IsDir: true,
+			Path:  "env/show",
+			Cmd:   "goctl env > env.txt",
+		},
+		{
+			IsDir: true,
+			Path:  "env/check",
+			Cmd:   "goctl env check -f -v",
+		},
+		{
+			IsDir: true,
+			Path:  "env/install",
+			Cmd:   "goctl env install -v",
+		},
+		{
+			IsDir: true,
+			Path:  "kube",
+			Cmd:   "goctl kube deploy --image alpine --name foo --namespace foo --o foo.yaml --port 8888",
+		},
+		{
+			IsDir: true,
+			Path:  "kube/shorthand",
+			Cmd:   "goctl kube deploy -image alpine -name foo -namespace foo -o foo.yaml -port 8888",
+		},
+		{
+			IsDir: true,
+			Path:  "kube/assign",
+			Cmd:   "goctl kube deploy --image=alpine --name=foo --namespace=foo --o=foo.yaml --port=8888",
+		},
+		{
+			IsDir: true,
+			Path:  "kube/shorthand/assign",
+			Cmd:   "goctl kube deploy -image=alpine -name=foo -namespace=foo -o=foo.yaml -port=8888",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/cache",
+			Cmd:   "goctl model mongo --dir . --type user --style goZero -c",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/cache/shorthand",
+			Cmd:   "goctl model mongo -dir . -type user -style goZero -c",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/cache/assign",
+			Cmd:   "goctl model mongo --dir=. --type=user --style=goZero -c",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/cache/shorthand/assign",
+			Cmd:   "goctl model mongo -dir=. -type=user -style=goZero -c",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/nocache",
+			Cmd:   "goctl model mongo --dir . --type user",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/nocache/shorthand",
+			Cmd:   "goctl model mongo -dir . -type user",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/nocache/assign",
+			Cmd:   "goctl model mongo --dir=. --type=user",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mongo/nocache/shorthand/assign",
+			Cmd:   "goctl model mongo -dir=. -type=user",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/user.sql",
+			Cmd:     "goctl model mysql ddl --database user --dir cache --src user.sql -c",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/shorthand/user.sql",
+			Cmd:     "goctl model mysql ddl -database user -dir cache -src user.sql -c",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/assign/user.sql",
+			Cmd:     "goctl model mysql ddl --database=user --dir=cache --src=user.sql -c",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/shorthand/assign/user.sql",
+			Cmd:     "goctl model mysql ddl -database=user -dir=cache -src=user.sql -c",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/user.sql",
+			Cmd:     "goctl model mysql ddl --database user --dir nocache --src user.sql",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/shorthand/user.sql",
+			Cmd:     "goctl model mysql ddl -database user -dir nocache -src user.sql",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/assign/user.sql",
+			Cmd:     "goctl model mysql ddl --database=user --dir=nocache --src=user.sql",
+		},
+		{
+			Content: userSql,
+			Path:    "model/mysql/ddl/shorthand/assign/user.sql",
+			Cmd:     "goctl model mysql ddl -database=user -dir=nocache -src=user.sql",
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource",
+			Cmd:   `goctl model mysql datasource --url $DSN --dir cache --table "*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand",
+			Cmd:   `goctl model mysql datasource -url $DSN -dir cache -table "*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand2",
+			Cmd:   `goctl model mysql datasource -url $DSN -dir cache -t "*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/assign",
+			Cmd:   `goctl model mysql datasource --url=$DSN --dir=cache --table="*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand/assign",
+			Cmd:   `goctl model mysql datasource -url=$DSN -dir=cache -table="*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand2/assign",
+			Cmd:   `goctl model mysql datasource -url=$DSN -dir=cache -t="*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource",
+			Cmd:   `goctl model mysql datasource --url $DSN --dir nocache --table "*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand",
+			Cmd:   `goctl model mysql datasource -url $DSN -dir nocache -table "*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand2",
+			Cmd:   `goctl model mysql datasource -url $DSN -dir nocache -t "*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/assign",
+			Cmd:   `goctl model mysql datasource --url=$DSN --dir=nocache --table="*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand/assign",
+			Cmd:   `goctl model mysql datasource -url=$DSN -dir=nocache -table="*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "model/mysql/datasource/shorthand2/assign",
+			Cmd:   `goctl model mysql datasource -url=$DSN -dir=nocache -t="*" -c`,
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/new",
+			Cmd:   "goctl rpc new greet",
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/template",
+			Cmd:   "goctl rpc template --o greet.proto",
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/template/shorthand",
+			Cmd:   "goctl rpc template -o greet.proto",
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/template/assign",
+			Cmd:   "goctl rpc template --o=greet.proto",
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/template/shorthand/assign",
+			Cmd:   "goctl rpc template -o=greet.proto",
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/protoc",
+			Cmd:   "goctl rpc template --o greet.proto && goctl rpc protoc greet.proto --go_out . --go-grpc_out . --zrpc_out .",
+		},
+		{
+			IsDir: true,
+			Path:  "rpc/protoc/assign",
+			Cmd:   "goctl rpc template --o=greet.proto && goctl rpc protoc greet.proto --go_out=. --go-grpc_out=. --zrpc_out=.",
+		},
+	}
+)

+ 120 - 0
tools/goctl/compare/testdata/testdata.go

@@ -0,0 +1,120 @@
+package testdata
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+
+	"github.com/logrusorgru/aurora"
+	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
+)
+
+type (
+	File struct {
+		IsDir        bool
+		Path         string
+		AbsolutePath string
+		Content      string
+		Cmd          string
+	}
+
+	Files []File
+)
+
+func (f File) execute(goctl string) error {
+	printDir := f.Path
+	dir := f.AbsolutePath
+	if !f.IsDir {
+		printDir = filepath.Dir(printDir)
+		dir = filepath.Dir(dir)
+	}
+	printCommand := strings.ReplaceAll(fmt.Sprintf("cd %s && %s", printDir, f.Cmd), "goctl", filepath.Base(goctl))
+	command := strings.ReplaceAll(fmt.Sprintf("cd %s && %s", dir, f.Cmd), "goctl", goctl)
+	fmt.Println(aurora.BrightGreen(printCommand))
+	cmd := exec.Command("sh", "-c", command)
+	cmd.Env = os.Environ()
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	return cmd.Run()
+}
+
+func (fs Files) execute(goctl string) error {
+	for _, f := range fs {
+		err := f.execute(goctl)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func mustGetTestData(baseDir string) (Files, Files) {
+	if len(baseDir) == 0 {
+		dir, err := os.Getwd()
+		if err != nil {
+			log.Fatalln(err)
+		}
+		baseDir = dir
+	}
+	baseDir, err := filepath.Abs(baseDir)
+	if err != nil {
+		return nil, nil
+	}
+	createFile := func(baseDir string, data File) (File, error) {
+		fp := filepath.Join(baseDir, data.Path)
+		dir := filepath.Dir(fp)
+		if data.IsDir {
+			dir = fp
+		}
+		if err := pathx.MkdirIfNotExist(dir); err != nil {
+			return data, err
+		}
+		data.AbsolutePath = fp
+		if data.IsDir {
+			return data, nil
+		}
+
+		return data, ioutil.WriteFile(fp, []byte(data.Content), os.ModePerm)
+	}
+	oldDir := filepath.Join(baseDir, "old_fs")
+	newDir := filepath.Join(baseDir, "new_fs")
+	os.RemoveAll(oldDir)
+	os.RemoveAll(newDir)
+	var oldFiles, newFiles []File
+	for _, data := range list {
+		od, err := createFile(oldDir, data)
+		if err != nil {
+			log.Fatalln(err)
+		}
+		oldFiles = append(oldFiles, od)
+		nd, err := createFile(newDir, data)
+		if err != nil {
+			log.Fatalln(err)
+		}
+		newFiles = append(newFiles, nd)
+	}
+	return oldFiles, newFiles
+}
+
+func MustRun(baseDir string) {
+	oldFiles, newFiles := mustGetTestData(baseDir)
+	goctlOld, err := exec.LookPath("goctl.old")
+	must(err)
+	goctlNew, err := exec.LookPath("goctl")
+	must(err)
+	fmt.Println(aurora.BrightBlue("========================goctl.old======================="))
+	must(oldFiles.execute(goctlOld))
+	fmt.Println()
+	fmt.Println(aurora.BrightBlue("========================goctl.new======================="))
+	must(newFiles.execute(goctlNew))
+}
+
+func must(err error) {
+	if err != nil {
+		log.Fatalln(err)
+	}
+}

+ 3 - 0
tools/goctl/compare/testdata/unformat.api

@@ -0,0 +1,3 @@
+syntax = "v1"
+
+type Foo struct{}

+ 34 - 0
tools/goctl/compare/testdata/user.sql

@@ -0,0 +1,34 @@
+-- 用户表 --
+CREATE TABLE `user`
+(
+    `id`          bigint(10) NOT NULL AUTO_INCREMENT,
+    `user`        varchar(50)                             NOT NULL DEFAULT '' COMMENT '用户',
+    `name`        varchar(255) COLLATE utf8mb4_general_ci NULL COMMENT '用户\t名称',
+    `password`    varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户\n密码',
+    `mobile`      varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '手机号',
+    `gender`      char(5) COLLATE utf8mb4_general_ci      NOT NULL COMMENT '男|女|未公\r开',
+    `nickname`    varchar(255) COLLATE utf8mb4_general_ci          DEFAULT '' COMMENT '用户昵称',
+    `type`    tinyint(1) COLLATE utf8mb4_general_ci          DEFAULT 0 COMMENT '用户类型',
+    `create_time` timestamp NULL,
+    `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `name_index` (`name`),
+    UNIQUE KEY `name_index2` (`name`),
+    UNIQUE KEY `user_index` (`user`),
+    UNIQUE KEY `type_index` (`type`),
+    UNIQUE KEY `mobile_index` (`mobile`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+
+CREATE TABLE `student`
+(
+    `type`    bigint                           NOT NULL,
+    `class` varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
+    `name`  varchar(255) COLLATE utf8mb4_bin NOT NULL DEFAULT '',
+    `age`   tinyint                                   DEFAULT NULL,
+    `score` float(10, 0
+) DEFAULT NULL,
+  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `update_time` timestamp NULL DEFAULT NULL,
+  PRIMARY KEY (`type`) USING BTREE,
+  UNIQUE KEY `class_name_index` (`class`,`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

+ 0 - 77
tools/goctl/completion/completion.go

@@ -1,77 +0,0 @@
-package completion
-
-import (
-	"bytes"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"runtime"
-
-	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
-	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
-	"github.com/zeromicro/go-zero/tools/goctl/vars"
-)
-
-func Completion(c *cli.Context) error {
-	goos := runtime.GOOS
-	if goos == vars.OsWindows {
-		return fmt.Errorf("%q: only support unix-like OS", goos)
-	}
-
-	name := c.String("name")
-	if len(name) == 0 {
-		name = defaultCompletionFilename
-	}
-	if filepath.IsAbs(name) {
-		return fmt.Errorf("unsupport absolute path: %q", name)
-	}
-
-	home, err := pathx.GetAutoCompleteHome()
-	if err != nil {
-		return err
-	}
-
-	buffer := bytes.NewBuffer(nil)
-	zshF := filepath.Join(home, "zsh", defaultCompletionFilename)
-	err = pathx.MkdirIfNotExist(filepath.Dir(zshF))
-	if err != nil {
-		return err
-	}
-
-	bashF := filepath.Join(home, "bash", defaultCompletionFilename)
-	err = pathx.MkdirIfNotExist(filepath.Dir(bashF))
-	if err != nil {
-		return err
-	}
-
-	flag := magic
-	err = ioutil.WriteFile(zshF, zsh, os.ModePerm)
-	if err == nil {
-		flag |= flagZsh
-	}
-
-	err = ioutil.WriteFile(bashF, bash, os.ModePerm)
-	if err == nil {
-		flag |= flagBash
-	}
-
-	buffer.WriteString(aurora.BrightGreen("generation auto completion success!\n").String())
-	buffer.WriteString(aurora.BrightGreen("executes the following script to setting shell:\n").String())
-	switch flag {
-	case magic | flagZsh:
-		buffer.WriteString(aurora.BrightCyan(fmt.Sprintf("echo PROG=goctl source %s >> ~/.zshrc && source ~/.zshrc", zshF)).String())
-	case magic | flagBash:
-		buffer.WriteString(aurora.BrightCyan(fmt.Sprintf("echo PROG=goctl source %s >> ~/.bashrc && source ~/.bashrc", bashF)).String())
-	case magic | flagZsh | flagBash:
-		buffer.WriteString(aurora.BrightCyan(fmt.Sprintf(`echo PROG=goctl source %s >> ~/.zshrc && source ~/.zshrc
-or
-echo PROG=goctl source %s >> ~/.bashrc && source ~/.bashrc`, zshF, bashF)).String())
-	default:
-		return nil
-	}
-
-	fmt.Println(buffer.String())
-	return nil
-}

+ 0 - 12
tools/goctl/completion/const.go

@@ -1,12 +0,0 @@
-package completion
-
-const (
-	BashCompletionFlag        = `generate-goctl-completion`
-	defaultCompletionFilename = "goctl_autocomplete"
-)
-
-const (
-	magic = 1 << iota
-	flagZsh
-	flagBash
-)

+ 0 - 51
tools/goctl/completion/script.go

@@ -1,51 +0,0 @@
-package completion
-
-import "fmt"
-
-var zsh = []byte(fmt.Sprintf(`#compdef $PROG
-
-_cli_zsh_autocomplete() {
-
-  local -a opts
-  local cur
-  cur=${words[-1]}
-  if [[ "$cur" == "-"* ]]; then
-    opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --%s)}")
-  else
-    opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --%s)}")
-  fi
-
-  if [[ "${opts[1]}" != "" ]]; then
-    _describe 'values' opts
-  else
-    _files
-  fi
-
-  return
-}
-
-compdef _cli_zsh_autocomplete $PROG
-`, BashCompletionFlag, BashCompletionFlag))
-
-var bash = []byte(fmt.Sprintf(`#! /bin/bash
-
-: ${PROG:=$(basename ${BASH_SOURCE})}
-
-_cli_bash_autocomplete() {
-  if [[ "${COMP_WORDS[0]}" != "source" ]]; then
-    local cur opts base
-    COMPREPLY=()
-    cur="${COMP_WORDS[COMP_CWORD]}"
-    if [[ "$cur" == "-"* ]]; then
-      opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --%s )
-    else
-      opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --%s )
-    fi
-    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
-    return 0
-  fi
-}
-
-complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
-unset PROG
-`, BashCompletionFlag, BashCompletionFlag))

+ 32 - 0
tools/goctl/docker/cmd.go

@@ -0,0 +1,32 @@
+package docker
+
+import "github.com/spf13/cobra"
+
+var (
+	varStringGo      string
+	varStringBase    string
+	varIntPort       int
+	varStringHome    string
+	varStringRemote  string
+	varStringBranch  string
+	varStringVersion string
+	varStringTZ      string
+
+	// Cmd describes a docker command.
+	Cmd = &cobra.Command{
+		Use:   "docker",
+		Short: "Generate Dockerfile",
+		RunE:  dockerCommand,
+	}
+)
+
+func init() {
+	Cmd.Flags().StringVar(&varStringGo, "go", "", "The file that contains main function")
+	Cmd.Flags().StringVar(&varStringBase, "base", "scratch", "The base image to build the docker image, default scratch")
+	Cmd.Flags().IntVar(&varIntPort, "port", 0, "The port to expose, default none")
+	Cmd.Flags().StringVar(&varStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	Cmd.Flags().StringVar(&varStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	Cmd.Flags().StringVar(&varStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+	Cmd.Flags().StringVar(&varStringVersion, "version", "", "The goctl builder golang image version")
+	Cmd.Flags().StringVar(&varStringTZ, "tz", "Asia/Shanghai", "The timezone of the container")
+}

+ 11 - 15
tools/goctl/docker/docker.go

@@ -10,7 +10,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
@@ -37,24 +37,20 @@ type Docker struct {
 	Timezone    string
 	Timezone    string
 }
 }
 
 
-// DockerCommand provides the entry for goctl docker
-func DockerCommand(c *cli.Context) (err error) {
+// dockerCommand provides the entry for goctl docker
+func dockerCommand(_ *cobra.Command, _ []string) (err error) {
 	defer func() {
 	defer func() {
 		if err == nil {
 		if err == nil {
 			fmt.Println(aurora.Green("Done."))
 			fmt.Println(aurora.Green("Done."))
 		}
 		}
 	}()
 	}()
 
 
-	if c.NumFlags() == 0 {
-		cli.ShowCommandHelpAndExit(c, "docker", 1)
-	}
-
-	goFile := c.String("go")
-	home := c.String("home")
-	version := c.String("version")
-	remote := c.String("remote")
-	branch := c.String("branch")
-	timezone := c.String("tz")
+	goFile := varStringGo
+	home := varStringHome
+	version := varStringVersion
+	remote := varStringRemote
+	branch := varStringBranch
+	timezone := varStringTZ
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
@@ -78,8 +74,8 @@ func DockerCommand(c *cli.Context) (err error) {
 		return fmt.Errorf("file %q not found", goFile)
 		return fmt.Errorf("file %q not found", goFile)
 	}
 	}
 
 
-	base := c.String("base")
-	port := c.Int("port")
+	base := varStringBase
+	port := varIntPort
 	if _, err := os.Stat(etcDir); os.IsNotExist(err) {
 	if _, err := os.Stat(etcDir); os.IsNotExist(err) {
 		return generateDockerfile(goFile, base, port, version, timezone)
 		return generateDockerfile(goFile, base, port, version, timezone)
 	}
 	}

+ 1 - 2
tools/goctl/docker/template.go

@@ -3,7 +3,6 @@ package docker
 import (
 import (
 	_ "embed"
 	_ "embed"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
@@ -21,7 +20,7 @@ func Clean() error {
 }
 }
 
 
 // GenTemplates creates docker template files
 // GenTemplates creates docker template files
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return initTemplate()
 	return initTemplate()
 }
 }
 
 

+ 3 - 6
tools/goctl/env/check.go

@@ -5,7 +5,7 @@ import (
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/env"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/env"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/protoc"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/protoc"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/protocgengo"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/protocgengo"
@@ -37,11 +37,8 @@ var bins = []bin{
 	},
 	},
 }
 }
 
 
-func Check(ctx *cli.Context) error {
-	install := ctx.Bool("install")
-	force := ctx.Bool("force")
-	verbose := ctx.Bool("verbose")
-	return Prepare(install, force, verbose)
+func check(_ *cobra.Command, _ []string) error {
+	return Prepare(boolVarInstall, boolVarForce, boolVarVerbose)
 }
 }
 
 
 func Prepare(install, force, verbose bool) error {
 func Prepare(install, force, verbose bool) error {

+ 46 - 0
tools/goctl/env/cmd.go

@@ -0,0 +1,46 @@
+package env
+
+import "github.com/spf13/cobra"
+
+var (
+	sliceVarWriteValue []string
+	boolVarForce       bool
+	boolVarVerbose     bool
+	boolVarInstall     bool
+
+	// Cmd describes a env command.
+	Cmd = &cobra.Command{
+		Use:   "env",
+		Short: "Check or edit goctl environment",
+		RunE:  write,
+	}
+	installCmd = &cobra.Command{
+		Use:   "install",
+		Short: "Goctl env installation",
+		RunE:  install,
+	}
+	checkCmd = &cobra.Command{
+		Use:   "check",
+		Short: "Detect goctl env and dependency tools",
+		RunE:  check,
+	}
+)
+
+func init() {
+	// The root command flags
+	Cmd.Flags().StringSliceVarP(&sliceVarWriteValue,
+		"write", "w", nil, "Edit goctl environment")
+	Cmd.PersistentFlags().BoolVarP(&boolVarForce,
+		"force", "f", false,
+		"Silent installation of non-existent dependencies")
+	Cmd.PersistentFlags().BoolVarP(&boolVarVerbose,
+		"verbose", "v", false, "Enable log output")
+
+	// The sub-command flags
+	checkCmd.Flags().BoolVarP(&boolVarInstall, "install", "i",
+		false, "Install dependencies if not found")
+
+	// Add sub-command
+	Cmd.AddCommand(installCmd)
+	Cmd.AddCommand(checkCmd)
+}

+ 4 - 5
tools/goctl/env/env.go

@@ -3,14 +3,13 @@ package env
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/env"
 	"github.com/zeromicro/go-zero/tools/goctl/pkg/env"
 )
 )
 
 
-func Action(c *cli.Context) error {
-	write := c.StringSlice("write")
-	if len(write) > 0 {
-		return env.WriteEnv(write)
+func write(_ *cobra.Command, _ []string) error {
+	if len(sliceVarWriteValue) > 0 {
+		return env.WriteEnv(sliceVarWriteValue)
 	}
 	}
 	fmt.Println(env.Print())
 	fmt.Println(env.Print())
 	return nil
 	return nil

+ 5 - 5
tools/goctl/env/install.go

@@ -1,9 +1,9 @@
 package env
 package env
 
 
-import "github.com/urfave/cli"
+import (
+	"github.com/spf13/cobra"
+)
 
 
-func Install(c *cli.Context) error {
-	force := c.Bool("force")
-	verbose := c.Bool("verbose")
-	return Prepare(true, force, verbose)
+func install(_ *cobra.Command, _ []string) error {
+	return Prepare(true, boolVarForce, boolVarVerbose)
 }
 }

+ 1 - 1
tools/goctl/go.mod

@@ -9,8 +9,8 @@ require (
 	github.com/go-sql-driver/mysql v1.6.0
 	github.com/go-sql-driver/mysql v1.6.0
 	github.com/iancoleman/strcase v0.2.0
 	github.com/iancoleman/strcase v0.2.0
 	github.com/logrusorgru/aurora v2.0.3+incompatible
 	github.com/logrusorgru/aurora v2.0.3+incompatible
+	github.com/spf13/cobra v1.4.0
 	github.com/stretchr/testify v1.7.0
 	github.com/stretchr/testify v1.7.0
-	github.com/urfave/cli v1.22.5
 	github.com/zeromicro/antlr v0.0.1
 	github.com/zeromicro/antlr v0.0.1
 	github.com/zeromicro/ddl-parser v1.0.3
 	github.com/zeromicro/ddl-parser v1.0.3
 	github.com/zeromicro/go-zero v1.3.2
 	github.com/zeromicro/go-zero v1.3.2

+ 7 - 5
tools/goctl/go.sum

@@ -85,8 +85,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -238,6 +238,8 @@ github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHL
 github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
 github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
 github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
 github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
 github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
 github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
 github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
 github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
@@ -344,9 +346,8 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqn
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -355,7 +356,10 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
+github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -367,8 +371,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
-github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=

+ 2 - 947
tools/goctl/goctl.go

@@ -1,958 +1,13 @@
 package main
 package main
 
 
 import (
 import (
-	"fmt"
-	"os"
-	"runtime"
-
-	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/core/load"
 	"github.com/zeromicro/go-zero/core/load"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/logx"
-	"github.com/zeromicro/go-zero/tools/goctl/api/apigen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/dartgen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/docgen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/format"
-	"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/javagen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/ktgen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/new"
-	"github.com/zeromicro/go-zero/tools/goctl/api/tsgen"
-	"github.com/zeromicro/go-zero/tools/goctl/api/validate"
-	"github.com/zeromicro/go-zero/tools/goctl/bug"
-	"github.com/zeromicro/go-zero/tools/goctl/completion"
-	"github.com/zeromicro/go-zero/tools/goctl/docker"
-	"github.com/zeromicro/go-zero/tools/goctl/env"
-	"github.com/zeromicro/go-zero/tools/goctl/internal/version"
-	"github.com/zeromicro/go-zero/tools/goctl/kube"
-	"github.com/zeromicro/go-zero/tools/goctl/migrate"
-	"github.com/zeromicro/go-zero/tools/goctl/model/mongo"
-	model "github.com/zeromicro/go-zero/tools/goctl/model/sql/command"
-	"github.com/zeromicro/go-zero/tools/goctl/plugin"
-	rpc "github.com/zeromicro/go-zero/tools/goctl/rpc/cli"
-	"github.com/zeromicro/go-zero/tools/goctl/tpl"
-	"github.com/zeromicro/go-zero/tools/goctl/upgrade"
+	"github.com/zeromicro/go-zero/tools/goctl/cmd"
 )
 )
 
 
-const codeFailure = 1
-
-var commands = []cli.Command{
-	{
-		Name:   "bug",
-		Usage:  "report a bug",
-		Action: bug.Action,
-	},
-	{
-		Name:   "upgrade",
-		Usage:  "upgrade goctl to latest version",
-		Action: upgrade.Upgrade,
-	},
-	{
-		Name:  "env",
-		Usage: "check or edit goctl environment",
-		Flags: []cli.Flag{
-			cli.StringSliceFlag{
-				Name:  "write, w",
-				Usage: "edit goctl environment",
-			},
-		},
-		Subcommands: []cli.Command{
-			{
-				Name:   "install",
-				Usage:  "goctl env installation",
-				Action: env.Install,
-				Flags: []cli.Flag{
-					cli.BoolFlag{
-						Name:  "force,f",
-						Usage: "silent installation of non-existent dependencies",
-					},
-					cli.BoolFlag{
-						Name:  "verbose, v",
-						Usage: "enable log output",
-					},
-				},
-			},
-			{
-				Name:  "check",
-				Usage: "detect goctl env and dependency tools",
-				Flags: []cli.Flag{
-					cli.BoolFlag{
-						Name:  "install, i",
-						Usage: "install dependencies if not found",
-					},
-					cli.BoolFlag{
-						Name:  "force, f",
-						Usage: "silent installation of non-existent dependencies",
-					},
-					cli.BoolFlag{
-						Name:  "verbose, v",
-						Usage: "enable log output",
-					},
-				},
-				Action: env.Check,
-			},
-		},
-		Action: env.Action,
-	},
-	{
-		Name:        "migrate",
-		Usage:       "migrate from tal-tech to zeromicro",
-		Description: "migrate is a transition command to help users migrate their projects from tal-tech to zeromicro version",
-		Action:      migrate.Migrate,
-		Flags: []cli.Flag{
-			cli.BoolFlag{
-				Name:  "verbose, v",
-				Usage: "verbose enables extra logging",
-			},
-			cli.StringFlag{
-				Name:  "version",
-				Usage: "the target release version of github.com/zeromicro/go-zero to migrate",
-			},
-		},
-	},
-	{
-		Name:  "api",
-		Usage: "generate api related files",
-		Flags: []cli.Flag{
-			cli.StringFlag{
-				Name:  "o",
-				Usage: "output a sample api file",
-			},
-			cli.StringFlag{
-				Name: "home",
-				Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-					"if they are, --remote has higher priority",
-			},
-			cli.StringFlag{
-				Name: "remote",
-				Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-					"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-					"https://github.com/zeromicro/go-zero-template directory structure",
-			},
-			cli.StringFlag{
-				Name:  "branch",
-				Usage: "the branch of the remote repo, it does work with --remote",
-			},
-		},
-		Action: apigen.ApiCommand,
-		Subcommands: []cli.Command{
-			{
-				Name:      "new",
-				Usage:     "fast create api service",
-				UsageText: "example: goctl api new [options] service-name",
-				Action:    new.CreateServiceCommand,
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name: "home",
-						Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-					cli.StringFlag{
-						Name:  "style",
-						Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/blob/master/tools/goctl/config/readme.md]",
-					},
-				},
-			},
-			{
-				Name:  "format",
-				Usage: "format api files",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the format target dir",
-					},
-					cli.BoolFlag{
-						Name:  "iu",
-						Usage: "ignore update",
-					},
-					cli.BoolFlag{
-						Name:  "stdin",
-						Usage: "use stdin to input api doc content, press \"ctrl + d\" to send EOF",
-					},
-					cli.BoolFlag{
-						Name:  "declare",
-						Usage: "use to skip check api types already declare",
-					},
-				},
-				Action: format.GoFormatApi,
-			},
-			{
-				Name:  "validate",
-				Usage: "validate api file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "validate target api file",
-					},
-				},
-				Action: validate.GoValidateApi,
-			},
-			{
-				Name:  "doc",
-				Usage: "generate doc files",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target dir",
-					},
-					cli.StringFlag{
-						Name:     "o",
-						Required: false,
-						Usage:    "the output markdown directory",
-					},
-				},
-				Action: docgen.DocCommand,
-			},
-			{
-				Name:  "go",
-				Usage: "generate go files for provided api in api file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target dir",
-					},
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "the api file",
-					},
-					cli.StringFlag{
-						Name:  "style",
-						Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-					},
-					cli.StringFlag{
-						Name: "home",
-						Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-				},
-				Action: gogen.GoCommand,
-			},
-			{
-				Name:  "java",
-				Usage: "generate java files for provided api in api file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target dir",
-					},
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "the api file",
-					},
-				},
-				Action: javagen.JavaCommand,
-			},
-			{
-				Name:  "ts",
-				Usage: "generate ts files for provided api in api file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target dir",
-					},
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "the api file",
-					},
-					cli.StringFlag{
-						Name:  "webapi",
-						Usage: "the web api file path",
-					},
-					cli.StringFlag{
-						Name:  "caller",
-						Usage: "the web api caller",
-					},
-					cli.BoolFlag{
-						Name:  "unwrap",
-						Usage: "unwrap the webapi caller for import",
-					},
-				},
-				Action: tsgen.TsCommand,
-			},
-			{
-				Name:  "dart",
-				Usage: "generate dart files for provided api in api file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target dir",
-					},
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "the api file",
-					},
-					cli.BoolFlag{
-						Name:  "legacy",
-						Usage: "legacy generator for flutter v1",
-					},
-					cli.StringFlag{
-						Name:  "hostname",
-						Usage: "hostname of the server",
-					},
-				},
-				Action: dartgen.DartCommand,
-			},
-			{
-				Name:  "kt",
-				Usage: "generate kotlin code for provided api file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target directory",
-					},
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "the api file",
-					},
-					cli.StringFlag{
-						Name:  "pkg",
-						Usage: "define package name for kotlin file",
-					},
-				},
-				Action: ktgen.KtCommand,
-			},
-			{
-				Name:  "plugin",
-				Usage: "custom file generator",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "plugin, p",
-						Usage: "the plugin file",
-					},
-					cli.StringFlag{
-						Name:  "dir",
-						Usage: "the target directory",
-					},
-					cli.StringFlag{
-						Name:  "api",
-						Usage: "the api file",
-					},
-					cli.StringFlag{
-						Name:  "style",
-						Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-					},
-				},
-				Action: plugin.PluginCommand,
-			},
-		},
-	},
-	{
-		Name:  "docker",
-		Usage: "generate Dockerfile",
-		Flags: []cli.Flag{
-			cli.StringFlag{
-				Name:  "go",
-				Usage: "the file that contains main function",
-			},
-			cli.StringFlag{
-				Name:  "base",
-				Usage: "the base image to build the docker image, default scratch",
-				Value: "scratch",
-			},
-			cli.IntFlag{
-				Name:  "port",
-				Usage: "the port to expose, default none",
-				Value: 0,
-			},
-			cli.StringFlag{
-				Name: "home",
-				Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-					"if they are, --remote has higher priority",
-			},
-			cli.StringFlag{
-				Name: "remote",
-				Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-					"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-					"https://github.com/zeromicro/go-zero-template directory structure",
-			},
-			cli.StringFlag{
-				Name:  "branch",
-				Usage: "the branch of the remote repo, it does work with --remote",
-			},
-			cli.StringFlag{
-				Name:  "version",
-				Usage: "the goctl builder golang image version",
-			},
-			cli.StringFlag{
-				Name:  "tz",
-				Usage: "the timezone of the container",
-				Value: "Asia/Shanghai",
-			},
-		},
-		Action: docker.DockerCommand,
-	},
-	{
-		Name:  "kube",
-		Usage: "generate kubernetes files",
-		Subcommands: []cli.Command{
-			{
-				Name:  "deploy",
-				Usage: "generate deployment yaml file",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:     "name",
-						Usage:    "the name of deployment",
-						Required: true,
-					},
-					cli.StringFlag{
-						Name:     "namespace",
-						Usage:    "the namespace of deployment",
-						Required: true,
-					},
-					cli.StringFlag{
-						Name:     "image",
-						Usage:    "the docker image of deployment",
-						Required: true,
-					},
-					cli.StringFlag{
-						Name:  "secret",
-						Usage: "the secret to image pull from registry",
-					},
-					cli.IntFlag{
-						Name:  "requestCpu",
-						Usage: "the request cpu to deploy",
-						Value: 500,
-					},
-					cli.IntFlag{
-						Name:  "requestMem",
-						Usage: "the request memory to deploy",
-						Value: 512,
-					},
-					cli.IntFlag{
-						Name:  "limitCpu",
-						Usage: "the limit cpu to deploy",
-						Value: 1000,
-					},
-					cli.IntFlag{
-						Name:  "limitMem",
-						Usage: "the limit memory to deploy",
-						Value: 1024,
-					},
-					cli.StringFlag{
-						Name:     "o",
-						Usage:    "the output yaml file",
-						Required: true,
-					},
-					cli.IntFlag{
-						Name:  "replicas",
-						Usage: "the number of replicas to deploy",
-						Value: 3,
-					},
-					cli.IntFlag{
-						Name:  "revisions",
-						Usage: "the number of revision history to limit",
-						Value: 5,
-					},
-					cli.IntFlag{
-						Name:     "port",
-						Usage:    "the port of the deployment to listen on pod",
-						Required: true,
-					},
-					cli.IntFlag{
-						Name:  "nodePort",
-						Usage: "the nodePort of the deployment to expose",
-						Value: 0,
-					},
-					cli.IntFlag{
-						Name:  "minReplicas",
-						Usage: "the min replicas to deploy",
-						Value: 3,
-					},
-					cli.IntFlag{
-						Name:  "maxReplicas",
-						Usage: "the max replicas of deploy",
-						Value: 10,
-					},
-					cli.StringFlag{
-						Name: "home",
-						Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-					cli.StringFlag{
-						Name:  "serviceAccount",
-						Usage: "the ServiceAccount for the deployment",
-					},
-				},
-				Action: kube.DeploymentCommand,
-			},
-		},
-	},
-	{
-		Name:  "rpc",
-		Usage: "generate rpc code",
-		Flags: []cli.Flag{
-			cli.StringFlag{
-				Name:  "o",
-				Usage: "output a sample proto file",
-			},
-			cli.StringFlag{
-				Name: "home",
-				Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-					"if they are, --remote has higher priority",
-			},
-			cli.StringFlag{
-				Name: "remote",
-				Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-					"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-					"https://github.com/zeromicro/go-zero-template directory structure",
-			},
-			cli.StringFlag{
-				Name:  "branch",
-				Usage: "the branch of the remote repo, it does work with --remote",
-			},
-		},
-		Action: rpc.RPCTemplate,
-		Subcommands: []cli.Command{
-			{
-				Name:      "new",
-				Usage:     `generate rpc demo service`,
-				UsageText: "example: goctl rpc new [options] service-name",
-				Flags: []cli.Flag{
-					cli.StringSliceFlag{
-						Name:   "go_opt",
-						Hidden: true,
-					},
-					cli.StringSliceFlag{
-						Name:   "go-grpc_opt",
-						Hidden: true,
-					},
-					cli.StringFlag{
-						Name:  "style",
-						Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-					},
-					cli.BoolFlag{
-						Name:  "idea",
-						Usage: "whether the command execution environment is from idea plugin. [optional]",
-					},
-					cli.StringFlag{
-						Name: "home",
-						Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-					cli.BoolFlag{
-						Name:  "verbose, v",
-						Usage: "enable log output",
-					},
-				},
-				Action: rpc.RPCNew,
-			},
-			{
-				Name:  "template",
-				Usage: `generate proto template`,
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "out, o",
-						Usage: "the target path of proto (deprecated)",
-					},
-					cli.StringFlag{
-						Name: "home",
-						Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time," +
-							" if they are, --remote has higher priority",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-				},
-				Action: rpc.RPCTemplate,
-			},
-			{
-				Name:        "protoc",
-				Usage:       "generate grpc code",
-				UsageText:   `example: goctl rpc protoc xx.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.`,
-				Description: "for details, see https://go-zero.dev/cn/goctl-rpc.html",
-				Action:      rpc.ZRPC,
-				Flags: []cli.Flag{
-					cli.StringSliceFlag{
-						Name:   "go_out",
-						Hidden: true,
-					},
-					cli.StringSliceFlag{
-						Name:   "go-grpc_out",
-						Hidden: true,
-					},
-					cli.StringSliceFlag{
-						Name:   "go_opt",
-						Hidden: true,
-					},
-					cli.StringSliceFlag{
-						Name:   "go-grpc_opt",
-						Hidden: true,
-					},
-					cli.StringSliceFlag{
-						Name:   "plugin",
-						Hidden: true,
-					},
-					cli.StringSliceFlag{
-						Name:   "proto_path,I",
-						Hidden: true,
-					},
-					cli.StringFlag{
-						Name:  "zrpc_out",
-						Usage: "the zrpc output directory",
-					},
-					cli.StringFlag{
-						Name:  "style",
-						Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-					},
-					cli.StringFlag{
-						Name:  "home",
-						Usage: "the goctl home path of the template",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-					cli.BoolFlag{
-						Name:  "verbose, v",
-						Usage: "enable log output",
-					},
-				},
-			},
-		},
-	},
-	{
-		Name:  "model",
-		Usage: "generate model code",
-		Subcommands: []cli.Command{
-			{
-				Name:  "mysql",
-				Usage: `generate mysql model`,
-				Subcommands: []cli.Command{
-					{
-						Name:  "ddl",
-						Usage: `generate mysql model from ddl`,
-						Flags: []cli.Flag{
-							cli.StringFlag{
-								Name:  "src, s",
-								Usage: "the path or path globbing patterns of the ddl",
-							},
-							cli.StringFlag{
-								Name:  "dir, d",
-								Usage: "the target dir",
-							},
-							cli.StringFlag{
-								Name:  "style",
-								Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-							},
-							cli.BoolFlag{
-								Name:  "cache, c",
-								Usage: "generate code with cache [optional]",
-							},
-							cli.BoolFlag{
-								Name:  "idea",
-								Usage: "for idea plugin [optional]",
-							},
-							cli.StringFlag{
-								Name:  "database, db",
-								Usage: "the name of database [optional]",
-							},
-							cli.StringFlag{
-								Name: "home",
-								Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-									"if they are, --remote has higher priority",
-							},
-							cli.StringFlag{
-								Name: "remote",
-								Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-									"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-									"https://github.com/zeromicro/go-zero-template directory structure",
-							},
-							cli.StringFlag{
-								Name:  "branch",
-								Usage: "the branch of the remote repo, it does work with --remote",
-							},
-						},
-						Action: model.MysqlDDL,
-					},
-					{
-						Name:  "datasource",
-						Usage: `generate model from datasource`,
-						Flags: []cli.Flag{
-							cli.StringFlag{
-								Name:  "url",
-								Usage: `the data source of database,like "root:password@tcp(127.0.0.1:3306)/database"`,
-							},
-							cli.StringSliceFlag{
-								Name:  "table, t",
-								Usage: `the table or table globbing patterns in the database`,
-							},
-							cli.BoolFlag{
-								Name:  "cache, c",
-								Usage: "generate code with cache [optional]",
-							},
-							cli.StringFlag{
-								Name:  "dir, d",
-								Usage: "the target dir",
-							},
-							cli.StringFlag{
-								Name:  "style",
-								Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-							},
-							cli.BoolFlag{
-								Name:  "idea",
-								Usage: "for idea plugin [optional]",
-							},
-							cli.StringFlag{
-								Name: "home",
-								Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-									"if they are, --remote has higher priority",
-							},
-							cli.StringFlag{
-								Name: "remote",
-								Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-									"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-									"https://github.com/zeromicro/go-zero-template directory structure",
-							},
-							cli.StringFlag{
-								Name:  "branch",
-								Usage: "the branch of the remote repo, it does work with --remote",
-							},
-						},
-						Action: model.MySqlDataSource,
-					},
-				},
-			},
-			{
-				Name:  "pg",
-				Usage: `generate postgresql model`,
-				Subcommands: []cli.Command{
-					{
-						Name:  "datasource",
-						Usage: `generate model from datasource`,
-						Flags: []cli.Flag{
-							cli.StringFlag{
-								Name:  "url",
-								Usage: `the data source of database,like "postgres://root:password@127.0.0.1:5432/database?sslmode=disable"`,
-							},
-							cli.StringFlag{
-								Name:  "table, t",
-								Usage: `the table or table globbing patterns in the database`,
-							},
-							cli.StringFlag{
-								Name:  "schema, s",
-								Usage: `the table schema, default is [public]`,
-							},
-							cli.BoolFlag{
-								Name:  "cache, c",
-								Usage: "generate code with cache [optional]",
-							},
-							cli.StringFlag{
-								Name:  "dir, d",
-								Usage: "the target dir",
-							},
-							cli.StringFlag{
-								Name:  "style",
-								Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-							},
-							cli.BoolFlag{
-								Name:  "idea",
-								Usage: "for idea plugin [optional]",
-							},
-							cli.StringFlag{
-								Name: "home",
-								Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
-									"if they are, --remote has higher priority",
-							},
-							cli.StringFlag{
-								Name: "remote",
-								Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-									"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-									"https://github.com/zeromicro/go-zero-template directory structure",
-							},
-							cli.StringFlag{
-								Name:  "branch",
-								Usage: "the branch of the remote repo, it does work with --remote",
-							},
-						},
-						Action: model.PostgreSqlDataSource,
-					},
-				},
-			},
-			{
-				Name:  "mongo",
-				Usage: `generate mongo model`,
-				Flags: []cli.Flag{
-					cli.StringSliceFlag{
-						Name:  "type, t",
-						Usage: "specified model type name",
-					},
-					cli.BoolFlag{
-						Name:  "cache, c",
-						Usage: "generate code with cache [optional]",
-					},
-					cli.StringFlag{
-						Name:  "dir, d",
-						Usage: "the target dir",
-					},
-					cli.StringFlag{
-						Name:  "style",
-						Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
-					},
-					cli.StringFlag{
-						Name: "home",
-						Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time," +
-							" if they are, --remote has higher priority",
-					},
-					cli.StringFlag{
-						Name: "remote",
-						Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
-							"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
-							"https://github.com/zeromicro/go-zero-template directory structure",
-					},
-					cli.StringFlag{
-						Name:  "branch",
-						Usage: "the branch of the remote repo, it does work with --remote",
-					},
-				},
-				Action: mongo.Action,
-			},
-		},
-	},
-	{
-		Name:  "template",
-		Usage: "template operation",
-		Subcommands: []cli.Command{
-			{
-				Name:  "init",
-				Usage: "initialize the all templates(force update)",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "home",
-						Usage: "the goctl home path of the template",
-					},
-				},
-				Action: tpl.GenTemplates,
-			},
-			{
-				Name:  "clean",
-				Usage: "clean the all cache templates",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "home",
-						Usage: "the goctl home path of the template",
-					},
-				},
-				Action: tpl.CleanTemplates,
-			},
-			{
-				Name:  "update",
-				Usage: "update template of the target category to the latest",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "category,c",
-						Usage: "the category of template, enum [api,rpc,model,docker,kube]",
-					},
-					cli.StringFlag{
-						Name:  "home",
-						Usage: "the goctl home path of the template",
-					},
-				},
-				Action: tpl.UpdateTemplates,
-			},
-			{
-				Name:  "revert",
-				Usage: "revert the target template to the latest",
-				Flags: []cli.Flag{
-					cli.StringFlag{
-						Name:  "category,c",
-						Usage: "the category of template, enum [api,rpc,model,docker,kube]",
-					},
-					cli.StringFlag{
-						Name:  "name,n",
-						Usage: "the target file name of template",
-					},
-					cli.StringFlag{
-						Name:  "home",
-						Usage: "the goctl home path of the template",
-					},
-				},
-				Action: tpl.RevertTemplates,
-			},
-		},
-	},
-	{
-		Name:   "completion",
-		Usage:  "generation completion script, it only works for unix-like OS",
-		Action: completion.Completion,
-		Flags: []cli.Flag{
-			cli.StringFlag{
-				Name:  "name, n",
-				Usage: "the filename of auto complete script, default is [goctl_autocomplete]",
-			},
-		},
-	},
-}
-
 func main() {
 func main() {
 	logx.Disable()
 	logx.Disable()
 	load.Disable()
 	load.Disable()
-
-	cli.BashCompletionFlag = cli.BoolFlag{
-		Name:   completion.BashCompletionFlag,
-		Hidden: true,
-	}
-	app := cli.NewApp()
-	app.EnableBashCompletion = true
-	app.Usage = "a cli tool to generate code"
-	app.Version = fmt.Sprintf("%s %s/%s", version.BuildVersion, runtime.GOOS, runtime.GOARCH)
-	app.Commands = commands
-
-	// cli already print error messages.
-	if err := app.Run(os.Args); err != nil {
-		fmt.Println(aurora.Red(err.Error()))
-		os.Exit(codeFailure)
-	}
+	cmd.Execute()
 }
 }

+ 1 - 1
tools/goctl/internal/version/version.go

@@ -6,7 +6,7 @@ import (
 )
 )
 
 
 // BuildVersion is the version of goctl.
 // BuildVersion is the version of goctl.
-const BuildVersion = "1.3.5"
+const BuildVersion = "1.3.6-beta"
 
 
 var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
 var tag = map[string]int{"pre-alpha": 0, "alpha": 1, "pre-bata": 2, "beta": 3, "released": 4, "": 5}
 
 

+ 71 - 0
tools/goctl/kube/cmd.go

@@ -0,0 +1,71 @@
+package kube
+
+import "github.com/spf13/cobra"
+
+var (
+	varStringName           string
+	varStringNamespace      string
+	varStringImage          string
+	varStringSecret         string
+	varIntRequestCpu        int
+	varIntRequestMem        int
+	varIntLimitCpu          int
+	varIntLimitMem          int
+	varStringO              string
+	varIntReplicas          int
+	varIntRevisions         int
+	varIntPort              int
+	varIntNodePort          int
+	varIntMinReplicas       int
+	varIntMaxReplicas       int
+	varStringHome           string
+	varStringRemote         string
+	varStringBranch         string
+	varStringServiceAccount string
+
+	// Cmd describes a kube command.
+	Cmd = &cobra.Command{
+		Use:   "kube",
+		Short: "Generate kubernetes files",
+	}
+
+	deployCmd = &cobra.Command{
+		Use:   "deploy",
+		Short: "Generate deployment yaml file",
+		RunE:  deploymentCommand,
+	}
+)
+
+func init() {
+	deployCmd.Flags().StringVar(&varStringName, "name", "", "The name of deployment (required)")
+	deployCmd.Flags().StringVar(&varStringNamespace, "namespace", "", "The namespace of deployment (required)")
+	deployCmd.Flags().StringVar(&varStringImage, "image", "", "The docker image of deployment (required)")
+	deployCmd.Flags().StringVar(&varStringSecret, "secret", "", "The secret to image pull from registry")
+	deployCmd.Flags().IntVar(&varIntRequestCpu, "requestCpu", 500, "The request cpu to deploy")
+	deployCmd.Flags().IntVar(&varIntRequestMem, "requestMem", 512, "The request memory to deploy")
+	deployCmd.Flags().IntVar(&varIntLimitCpu, "limitCpu", 1000, "The limit cpu to deploy")
+	deployCmd.Flags().IntVar(&varIntLimitMem, "limitMem", 1024, "The limit memory to deploy")
+	deployCmd.Flags().StringVar(&varStringO, "o", "", "The output yaml file (required)")
+	deployCmd.Flags().IntVar(&varIntReplicas, "replicas", 3, "The number of replicas to deploy")
+	deployCmd.Flags().IntVar(&varIntRevisions, "revisions", 5, "The number of revision history to limit")
+	deployCmd.Flags().IntVar(&varIntPort, "port", 0, "The port of the deployment to listen on pod (required)")
+	deployCmd.Flags().IntVar(&varIntNodePort, "nodePort", 0, "The nodePort of the deployment to expose")
+	deployCmd.Flags().IntVar(&varIntMinReplicas, "minReplicas", 3, "The min replicas to deploy")
+	deployCmd.Flags().IntVar(&varIntMaxReplicas, "maxReplicas", 10, "The max replicas to deploy")
+
+	deployCmd.Flags().StringVar(&varStringHome, "home", "", "The goctl home path of the template, "+
+		"--home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	deployCmd.Flags().StringVar(&varStringRemote, "remote", "", "The remote git repo of the template, "+
+		"--home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo "+
+		"directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	deployCmd.Flags().StringVar(&varStringBranch, "branch", "", "The branch of the remote repo, it "+
+		"does work with --remote")
+	deployCmd.Flags().StringVar(&varStringServiceAccount, "serviceAccount", "", "The ServiceAccount "+
+		"for the deployment")
+	deployCmd.MarkFlagRequired("name")
+	deployCmd.MarkFlagRequired("namespace")
+	deployCmd.MarkFlagRequired("o")
+	deployCmd.MarkFlagRequired("port")
+
+	Cmd.AddCommand(deployCmd)
+}

+ 22 - 22
tools/goctl/kube/kube.go

@@ -7,7 +7,7 @@ import (
 	"text/template"
 	"text/template"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
@@ -48,11 +48,11 @@ type Deployment struct {
 }
 }
 
 
 // DeploymentCommand is used to generate the kubernetes deployment yaml files.
 // DeploymentCommand is used to generate the kubernetes deployment yaml files.
-func DeploymentCommand(c *cli.Context) error {
-	nodePort := c.Int("nodePort")
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
+func deploymentCommand(_ *cobra.Command, _ []string) error {
+	nodePort := varIntNodePort
+	home := varStringHome
+	remote := varStringRemote
+	branch := varStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
@@ -74,7 +74,7 @@ func DeploymentCommand(c *cli.Context) error {
 		return err
 		return err
 	}
 	}
 
 
-	out, err := pathx.CreateIfNotExist(c.String("o"))
+	out, err := pathx.CreateIfNotExist(varStringO)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -82,22 +82,22 @@ func DeploymentCommand(c *cli.Context) error {
 
 
 	t := template.Must(template.New("deploymentTemplate").Parse(text))
 	t := template.Must(template.New("deploymentTemplate").Parse(text))
 	err = t.Execute(out, Deployment{
 	err = t.Execute(out, Deployment{
-		Name:           c.String("name"),
-		Namespace:      c.String("namespace"),
-		Image:          c.String("image"),
-		Secret:         c.String("secret"),
-		Replicas:       c.Int("replicas"),
-		Revisions:      c.Int("revisions"),
-		Port:           c.Int("port"),
+		Name:           varStringName,
+		Namespace:      varStringNamespace,
+		Image:          varStringImage,
+		Secret:         varStringSecret,
+		Replicas:       varIntReplicas,
+		Revisions:      varIntRevisions,
+		Port:           varIntPort,
 		NodePort:       nodePort,
 		NodePort:       nodePort,
 		UseNodePort:    nodePort > 0,
 		UseNodePort:    nodePort > 0,
-		RequestCpu:     c.Int("requestCpu"),
-		RequestMem:     c.Int("requestMem"),
-		LimitCpu:       c.Int("limitCpu"),
-		LimitMem:       c.Int("limitMem"),
-		MinReplicas:    c.Int("minReplicas"),
-		MaxReplicas:    c.Int("maxReplicas"),
-		ServiceAccount: c.String("serviceAccount"),
+		RequestCpu:     varIntRequestCpu,
+		RequestMem:     varIntRequestMem,
+		LimitCpu:       varIntLimitCpu,
+		LimitMem:       varIntLimitMem,
+		MinReplicas:    varIntMinReplicas,
+		MaxReplicas:    varIntMaxReplicas,
+		ServiceAccount: varStringServiceAccount,
 	})
 	})
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -118,7 +118,7 @@ func Clean() error {
 }
 }
 
 
 // GenTemplates generates the deployment template files.
 // GenTemplates generates the deployment template files.
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return pathx.InitTemplates(category, map[string]string{
 	return pathx.InitTemplates(category, map[string]string{
 		deployTemplateFile: deploymentTemplate,
 		deployTemplateFile: deploymentTemplate,
 		jobTemplateFile:    jobTemplate,
 		jobTemplateFile:    jobTemplate,

+ 23 - 0
tools/goctl/migrate/cmd.go

@@ -0,0 +1,23 @@
+package migrate
+
+import "github.com/spf13/cobra"
+
+var (
+	boolVarVerbose   bool
+	stringVarVersion string
+	// Cmd describes a migrate command.
+	Cmd = &cobra.Command{
+		Use:   "migrate",
+		Short: "Migrate from tal-tech to zeromicro",
+		Long: "Migrate is a transition command to help users migrate their " +
+			"projects from tal-tech to zeromicro version",
+		RunE: migrate,
+	}
+)
+
+func init() {
+	Cmd.Flags().BoolVarP(&boolVarVerbose, "verbose", "v",
+		false, "Verbose enables extra logging")
+	Cmd.Flags().StringVar(&stringVarVersion, "version", defaultMigrateVersion,
+		"The target release version of github.com/zeromicro/go-zero to migrate")
+}

+ 9 - 11
tools/goctl/migrate/migrate.go

@@ -16,13 +16,13 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/util/console"
 	"github.com/zeromicro/go-zero/tools/goctl/util/console"
 	"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
 	"github.com/zeromicro/go-zero/tools/goctl/vars"
 	"github.com/zeromicro/go-zero/tools/goctl/vars"
 )
 )
 
 
-const zeromicroVersion = "v1.3.0"
+const defaultMigrateVersion = "v1.3.0"
 
 
 const (
 const (
 	confirmUnknown = iota
 	confirmUnknown = iota
@@ -35,28 +35,26 @@ var (
 	builderxConfirm = confirmUnknown
 	builderxConfirm = confirmUnknown
 )
 )
 
 
-func Migrate(c *cli.Context) error {
-	verbose := c.Bool("verbose")
-	version := c.String("version")
-	if len(version) == 0 {
-		version = zeromicroVersion
+func migrate(_ *cobra.Command, _ []string) error {
+	if len(stringVarVersion) == 0 {
+		stringVarVersion = defaultMigrateVersion
 	}
 	}
-	err := editMod(version, verbose)
+	err := editMod(stringVarVersion, boolVarVerbose)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	err = rewriteImport(verbose)
+	err = rewriteImport(boolVarVerbose)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	err = tidy(verbose)
+	err = tidy(boolVarVerbose)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	if verbose {
+	if boolVarVerbose {
 		console.Success("[OK] refactor finish, execute %q on project root to check status.",
 		console.Success("[OK] refactor finish, execute %q on project root to check status.",
 			"go test -race ./...")
 			"go test -race ./...")
 	}
 	}

+ 91 - 0
tools/goctl/model/cmd.go

@@ -0,0 +1,91 @@
+package model
+
+import (
+	"github.com/spf13/cobra"
+	"github.com/zeromicro/go-zero/tools/goctl/model/mongo"
+	"github.com/zeromicro/go-zero/tools/goctl/model/sql/command"
+)
+
+var (
+	// Cmd describes a model command.
+	Cmd = &cobra.Command{
+		Use:   "model",
+		Short: "Generate model code",
+	}
+
+	mysqlCmd = &cobra.Command{
+		Use:   "mysql",
+		Short: "Generate mysql model",
+	}
+
+	ddlCmd = &cobra.Command{
+		Use:   "ddl",
+		Short: "Generate mysql model from ddl",
+		RunE:  command.MysqlDDL,
+	}
+
+	datasourceCmd = &cobra.Command{
+		Use:   "datasource",
+		Short: "Generate model from datasource",
+		RunE:  command.MySqlDataSource,
+	}
+
+	pgCmd = &cobra.Command{
+		Use:   "pg",
+		Short: "Generate postgresql model",
+		RunE:  command.PostgreSqlDataSource,
+	}
+
+	mongoCmd = &cobra.Command{
+		Use:   "mongo",
+		Short: "Generate mongo model",
+		RunE:  mongo.Action,
+	}
+)
+
+func init() {
+	ddlCmd.Flags().StringVarP(&command.VarStringSrc, "src", "s", "", "The path or path globbing patterns of the ddl")
+	ddlCmd.Flags().StringVarP(&command.VarStringDir, "dir", "d", "", "The target dir")
+	ddlCmd.Flags().StringVar(&command.VarStringStyle, "style", "", "The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+	ddlCmd.Flags().BoolVarP(&command.VarBoolCache, "cache", "c", false, "Generate code with cache [optional]")
+	ddlCmd.Flags().BoolVar(&command.VarBoolIdea, "idea", false, "For idea plugin [optional]")
+	ddlCmd.Flags().StringVar(&command.VarStringDatabase, "database", "", "The name of database [optional]")
+	ddlCmd.Flags().StringVar(&command.VarStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	ddlCmd.Flags().StringVar(&command.VarStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	ddlCmd.Flags().StringVar(&command.VarStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+
+	datasourceCmd.Flags().StringVar(&command.VarStringURL, "url", "", `The data source of database,like "root:password@tcp(127.0.0.1:3306)/database"`)
+	datasourceCmd.Flags().StringSliceVarP(&command.VarStringSliceTable, "table", "t", nil, "The table or table globbing patterns in the database")
+	datasourceCmd.Flags().BoolVarP(&command.VarBoolCache, "cache", "c", false, "Generate code with cache [optional]")
+	datasourceCmd.Flags().StringVarP(&command.VarStringDir, "dir", "d", "", "The target dir")
+	datasourceCmd.Flags().StringVar(&command.VarStringStyle, "style", "", "The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+	datasourceCmd.Flags().BoolVar(&command.VarBoolIdea, "idea", false, "For idea plugin [optional]")
+	datasourceCmd.Flags().StringVar(&command.VarStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	datasourceCmd.Flags().StringVar(&command.VarStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	datasourceCmd.Flags().StringVar(&command.VarStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+
+	pgCmd.Flags().StringVar(&command.VarStringURL, "url", "", `The data source of database,like "root:password@tcp(127.0.0.1:3306)/database"`)
+	pgCmd.Flags().StringVarP(&command.VarStringTable, "table", "t", "", "The table or table globbing patterns in the database")
+	pgCmd.Flags().StringVarP(&command.VarStringSchema, "schema", "s", "public", "The table schema")
+	pgCmd.Flags().BoolVarP(&command.VarBoolCache, "cache", "c", false, "Generate code with cache [optional]")
+	pgCmd.Flags().StringVarP(&command.VarStringDir, "dir", "d", "", "The target dir")
+	pgCmd.Flags().StringVar(&command.VarStringStyle, "style", "", "The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+	pgCmd.Flags().BoolVar(&command.VarBoolIdea, "idea", false, "For idea plugin [optional]")
+	pgCmd.Flags().StringVar(&command.VarStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	pgCmd.Flags().StringVar(&command.VarStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	pgCmd.Flags().StringVar(&command.VarStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+
+	mongoCmd.Flags().StringSliceVarP(&mongo.VarStringSliceType, "type", "t", nil, "Specified model type name")
+	mongoCmd.Flags().BoolVarP(&mongo.VarBoolCache, "cache", "c", false, "Generate code with cache [optional]")
+	mongoCmd.Flags().StringVarP(&mongo.VarStringDir, "dir", "d", "", "The target dir")
+	mongoCmd.Flags().StringVar(&mongo.VarStringStyle, "style", "", "The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+	mongoCmd.Flags().StringVar(&mongo.VarStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	mongoCmd.Flags().StringVar(&mongo.VarStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	mongoCmd.Flags().StringVar(&mongo.VarStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+
+	mysqlCmd.AddCommand(datasourceCmd)
+	mysqlCmd.AddCommand(ddlCmd)
+	mysqlCmd.AddCommand(pgCmd)
+	Cmd.AddCommand(mysqlCmd)
+	Cmd.AddCommand(mongoCmd)
+}

+ 1 - 2
tools/goctl/model/mongo/generate/template.go

@@ -3,7 +3,6 @@ package generate
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/model/mongo/template"
 	"github.com/zeromicro/go-zero/tools/goctl/model/mongo/template"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
@@ -30,7 +29,7 @@ func Clean() error {
 }
 }
 
 
 // Templates initializes the mongo templates.
 // Templates initializes the mongo templates.
-func Templates(_ *cli.Context) error {
+func Templates() error {
 	return pathx.InitTemplates(category, templates)
 	return pathx.InitTemplates(category, templates)
 }
 }
 
 

+ 26 - 9
tools/goctl/model/mongo/mongo.go

@@ -5,22 +5,39 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/model/mongo/generate"
 	"github.com/zeromicro/go-zero/tools/goctl/model/mongo/generate"
 	file "github.com/zeromicro/go-zero/tools/goctl/util"
 	file "github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
+var (
+	// VarStringSliceType describes a golang data structure name for mongo.
+	VarStringSliceType []string
+	// VarStringDir describes an output directory.
+	VarStringDir string
+	// VarBoolCache describes whether cache is enabled.
+	VarBoolCache bool
+	// VarStringStyle describes the style.
+	VarStringStyle string
+	// VarStringHome describes the goctl home.
+	VarStringHome string
+	// VarStringRemote describes the remote git repository.
+	VarStringRemote string
+	// VarStringBranch describes the git branch.
+	VarStringBranch string
+)
+
 // Action provides the entry for goctl mongo code generation.
 // Action provides the entry for goctl mongo code generation.
-func Action(ctx *cli.Context) error {
-	tp := ctx.StringSlice("type")
-	c := ctx.Bool("cache")
-	o := strings.TrimSpace(ctx.String("dir"))
-	s := ctx.String("style")
-	home := ctx.String("home")
-	remote := ctx.String("remote")
-	branch := ctx.String("branch")
+func Action(_ *cobra.Command, _ []string) error {
+	tp := VarStringSliceType
+	c := VarBoolCache
+	o := strings.TrimSpace(VarStringDir)
+	s := VarStringStyle
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {

+ 62 - 48
tools/goctl/model/sql/command/command.go

@@ -6,7 +6,7 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/go-sql-driver/mysql"
 	"github.com/go-sql-driver/mysql"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/logx"
 	"github.com/zeromicro/go-zero/core/stores/postgres"
 	"github.com/zeromicro/go-zero/core/stores/postgres"
 	"github.com/zeromicro/go-zero/core/stores/sqlx"
 	"github.com/zeromicro/go-zero/core/stores/sqlx"
@@ -20,35 +20,49 @@ import (
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
-const (
-	flagSrc      = "src"
-	flagDir      = "dir"
-	flagCache    = "cache"
-	flagIdea     = "idea"
-	flagURL      = "url"
-	flagTable    = "table"
-	flagStyle    = "style"
-	flagDatabase = "database"
-	flagSchema   = "schema"
-	flagHome     = "home"
-	flagRemote   = "remote"
-	flagBranch   = "branch"
+var (
+	// VarStringSrc describes the source file of sql.
+	VarStringSrc string
+	// VarStringDir describes the output directory of sql.
+	VarStringDir string
+	// VarBoolCache describes whether the cache is enabled.
+	VarBoolCache bool
+	// VarBoolIdea describes whether is idea or not.
+	VarBoolIdea bool
+	// VarStringURL describes the dsn of the sql.
+	VarStringURL string
+	// VarStringSliceTable describes tables.
+	VarStringSliceTable []string
+	// VarStringTable describes a table of sql.
+	VarStringTable string
+	// VarStringStyle describes the style.
+	VarStringStyle string
+	// VarStringDatabase describes the database.
+	VarStringDatabase string
+	// VarStringSchema describes the schema of postgresql.
+	VarStringSchema string
+	// VarStringHome describes the goctl home.
+	VarStringHome string
+	// VarStringRemote describes the remote git repository.
+	VarStringRemote string
+	// VarStringBranch describes the git branch of the repository.
+	VarStringBranch string
 )
 )
 
 
 var errNotMatched = errors.New("sql not matched")
 var errNotMatched = errors.New("sql not matched")
 
 
 // MysqlDDL generates model code from ddl
 // MysqlDDL generates model code from ddl
-func MysqlDDL(ctx *cli.Context) error {
-	migrationnotes.BeforeCommands(ctx)
-	src := ctx.String(flagSrc)
-	dir := ctx.String(flagDir)
-	cache := ctx.Bool(flagCache)
-	idea := ctx.Bool(flagIdea)
-	style := ctx.String(flagStyle)
-	database := ctx.String(flagDatabase)
-	home := ctx.String(flagHome)
-	remote := ctx.String(flagRemote)
-	branch := ctx.String(flagBranch)
+func MysqlDDL(_ *cobra.Command, _ []string) error {
+	migrationnotes.BeforeCommands(VarStringDir, VarStringStyle)
+	src := VarStringSrc
+	dir := VarStringDir
+	cache := VarBoolCache
+	idea := VarBoolIdea
+	style := VarStringStyle
+	database := VarStringDatabase
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
@@ -67,16 +81,16 @@ func MysqlDDL(ctx *cli.Context) error {
 }
 }
 
 
 // MySqlDataSource generates model code from datasource
 // MySqlDataSource generates model code from datasource
-func MySqlDataSource(ctx *cli.Context) error {
-	migrationnotes.BeforeCommands(ctx)
-	url := strings.TrimSpace(ctx.String(flagURL))
-	dir := strings.TrimSpace(ctx.String(flagDir))
-	cache := ctx.Bool(flagCache)
-	idea := ctx.Bool(flagIdea)
-	style := ctx.String(flagStyle)
-	home := ctx.String(flagHome)
-	remote := ctx.String(flagRemote)
-	branch := ctx.String(flagBranch)
+func MySqlDataSource(_ *cobra.Command, _ []string) error {
+	migrationnotes.BeforeCommands(VarStringDir, VarStringStyle)
+	url := strings.TrimSpace(VarStringURL)
+	dir := strings.TrimSpace(VarStringDir)
+	cache := VarBoolCache
+	idea := VarBoolIdea
+	style := VarStringStyle
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
@@ -87,7 +101,7 @@ func MySqlDataSource(ctx *cli.Context) error {
 		pathx.RegisterGoctlHome(home)
 		pathx.RegisterGoctlHome(home)
 	}
 	}
 
 
-	tableValue := ctx.StringSlice(flagTable)
+	tableValue := VarStringSliceTable
 	patterns := parseTableList(tableValue)
 	patterns := parseTableList(tableValue)
 	cfg, err := config.NewConfig(style)
 	cfg, err := config.NewConfig(style)
 	if err != nil {
 	if err != nil {
@@ -135,17 +149,17 @@ func parseTableList(tableValue []string) pattern {
 }
 }
 
 
 // PostgreSqlDataSource generates model code from datasource
 // PostgreSqlDataSource generates model code from datasource
-func PostgreSqlDataSource(ctx *cli.Context) error {
-	migrationnotes.BeforeCommands(ctx)
-	url := strings.TrimSpace(ctx.String(flagURL))
-	dir := strings.TrimSpace(ctx.String(flagDir))
-	cache := ctx.Bool(flagCache)
-	idea := ctx.Bool(flagIdea)
-	style := ctx.String(flagStyle)
-	schema := ctx.String(flagSchema)
-	home := ctx.String(flagHome)
-	remote := ctx.String(flagRemote)
-	branch := ctx.String(flagBranch)
+func PostgreSqlDataSource(_ *cobra.Command, _ []string) error {
+	migrationnotes.BeforeCommands(VarStringDir, VarStringStyle)
+	url := strings.TrimSpace(VarStringURL)
+	dir := strings.TrimSpace(VarStringDir)
+	cache := VarBoolCache
+	idea := VarBoolIdea
+	style := VarStringStyle
+	schema := VarStringSchema
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		repo, _ := file.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
@@ -160,7 +174,7 @@ func PostgreSqlDataSource(ctx *cli.Context) error {
 		schema = "public"
 		schema = "public"
 	}
 	}
 
 
-	pattern := strings.TrimSpace(ctx.String(flagTable))
+	pattern := strings.TrimSpace(VarStringTable)
 	cfg, err := config.NewConfig(style)
 	cfg, err := config.NewConfig(style)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 2 - 3
tools/goctl/model/sql/command/migrationnotes/migrationnotes.go

@@ -1,14 +1,13 @@
 package migrationnotes
 package migrationnotes
 
 
 import (
 import (
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/config"
 	"github.com/zeromicro/go-zero/tools/goctl/util/format"
 	"github.com/zeromicro/go-zero/tools/goctl/util/format"
 )
 )
 
 
 // BeforeCommands run before comamnd run to show some migration notes
 // BeforeCommands run before comamnd run to show some migration notes
-func BeforeCommands(ctx *cli.Context) error {
-	if err := migrateBefore1_3_4(ctx); err != nil {
+func BeforeCommands(dir, style string) error {
+	if err := migrateBefore1_3_4(dir, style); err != nil {
 		return err
 		return err
 	}
 	}
 	return nil
 	return nil

+ 1 - 5
tools/goctl/model/sql/command/migrationnotes/v1.3.4.go

@@ -4,13 +4,9 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"strings"
 	"strings"
-
-	"github.com/urfave/cli"
 )
 )
 
 
-func migrateBefore1_3_4(ctx *cli.Context) error {
-	dir := ctx.String("dir")
-	style := ctx.String("style")
+func migrateBefore1_3_4(dir, style string) error {
 	ok, err := needShow1_3_4(dir, style)
 	ok, err := needShow1_3_4(dir, style)
 	if err != nil {
 	if err != nil {
 		return err
 		return err

+ 1 - 2
tools/goctl/model/sql/gen/template.go

@@ -3,7 +3,6 @@ package gen
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/model/sql/template"
 	"github.com/zeromicro/go-zero/tools/goctl/model/sql/template"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
@@ -70,7 +69,7 @@ func Clean() error {
 }
 }
 
 
 // GenTemplates creates template files if not exists
 // GenTemplates creates template files if not exists
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return pathx.InitTemplates(category, templates)
 	return pathx.InitTemplates(category, templates)
 }
 }
 
 

+ 19 - 8
tools/goctl/plugin/plugin.go

@@ -13,7 +13,7 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/parser"
 	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
 	"github.com/zeromicro/go-zero/tools/goctl/api/spec"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
@@ -30,19 +30,30 @@ type Plugin struct {
 	Dir         string
 	Dir         string
 }
 }
 
 
+var (
+	// VarStringPlugin describes a plugin.
+	VarStringPlugin string
+	// VarStringDir describes a directory.
+	VarStringDir string
+	// VarStringAPI describes an API file.
+	VarStringAPI string
+	// VarStringStyle describes a style.
+	VarStringStyle string
+)
+
 // PluginCommand is the entry of goctl api plugin
 // PluginCommand is the entry of goctl api plugin
-func PluginCommand(c *cli.Context) error {
+func PluginCommand(_ *cobra.Command, _ []string) error {
 	ex, err := os.Executable()
 	ex, err := os.Executable()
 	if err != nil {
 	if err != nil {
 		panic(err)
 		panic(err)
 	}
 	}
 
 
-	plugin := c.String("plugin")
+	plugin := VarStringPlugin
 	if len(plugin) == 0 {
 	if len(plugin) == 0 {
 		return errors.New("missing plugin")
 		return errors.New("missing plugin")
 	}
 	}
 
 
-	transferData, err := prepareArgs(c)
+	transferData, err := prepareArgs()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
@@ -69,8 +80,8 @@ func PluginCommand(c *cli.Context) error {
 	return nil
 	return nil
 }
 }
 
 
-func prepareArgs(c *cli.Context) ([]byte, error) {
-	apiPath := c.String("api")
+func prepareArgs() ([]byte, error) {
+	apiPath := VarStringAPI
 
 
 	var transferData Plugin
 	var transferData Plugin
 	if len(apiPath) > 0 && pathx.FileExists(apiPath) {
 	if len(apiPath) > 0 && pathx.FileExists(apiPath) {
@@ -88,13 +99,13 @@ func prepareArgs(c *cli.Context) ([]byte, error) {
 	}
 	}
 
 
 	transferData.ApiFilePath = absApiFilePath
 	transferData.ApiFilePath = absApiFilePath
-	dirAbs, err := filepath.Abs(c.String("dir"))
+	dirAbs, err := filepath.Abs(VarStringDir)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
 	transferData.Dir = dirAbs
 	transferData.Dir = dirAbs
-	transferData.Style = c.String("style")
+	transferData.Style = VarStringStyle
 	data, err := json.Marshal(transferData)
 	data, err := json.Marshal(transferData)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err

+ 46 - 24
tools/goctl/rpc/cli/cli.go

@@ -6,30 +6,57 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/generator"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/generator"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/console"
 	"github.com/zeromicro/go-zero/tools/goctl/util/console"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
+var (
+	// VarStringOutput describes the output.
+	VarStringOutput string
+	// VarStringHome describes the goctl home.
+	VarStringHome string
+	// VarStringRemote describes the remote git repository.
+	VarStringRemote string
+	// VarStringBranch describes the git branch.
+	VarStringBranch string
+	// VarStringSliceGoOut describes the go output.
+	VarStringSliceGoOut []string
+	// VarStringSliceGoGRPCOut describes the grpc output.
+	VarStringSliceGoGRPCOut []string
+	// VarStringSlicePlugin describes the protoc plugin.
+	VarStringSlicePlugin []string
+	// VarStringSliceProtoPath describes the proto path.
+	VarStringSliceProtoPath []string
+	// VarStringSliceGoOpt describes the go options.
+	VarStringSliceGoOpt []string
+	// VarStringSliceGoGRPCOpt describes the grpc options.
+	VarStringSliceGoGRPCOpt []string
+	// VarStringStyle describes the style of output files.
+	VarStringStyle string
+	// VarStringZRPCOut describes the zRPC output.
+	VarStringZRPCOut string
+	// VarBoolIdea describes whether idea or not
+	VarBoolIdea bool
+	// VarBoolVerbose describes whether verbose.
+	VarBoolVerbose bool
+)
+
 // RPCNew is to generate rpc greet service, this greet service can speed
 // RPCNew is to generate rpc greet service, this greet service can speed
 // up your understanding of the zrpc service structure
 // up your understanding of the zrpc service structure
-func RPCNew(c *cli.Context) error {
-	if c.NArg() == 0 {
-		cli.ShowCommandHelpAndExit(c, "new", 1)
-	}
-
-	rpcname := c.Args().First()
+func RPCNew(_ *cobra.Command, args []string) error {
+	rpcname := args[0]
 	ext := filepath.Ext(rpcname)
 	ext := filepath.Ext(rpcname)
 	if len(ext) > 0 {
 	if len(ext) > 0 {
 		return fmt.Errorf("unexpected ext: %s", ext)
 		return fmt.Errorf("unexpected ext: %s", ext)
 	}
 	}
-	style := c.String("style")
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
-	verbose := c.Bool("verbose")
+	style := VarStringStyle
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
+	verbose := VarBoolVerbose
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {
@@ -60,12 +87,12 @@ func RPCNew(c *cli.Context) error {
 	ctx.Output = filepath.Dir(src)
 	ctx.Output = filepath.Dir(src)
 	ctx.ProtocCmd = fmt.Sprintf("protoc -I=%s %s --go_out=%s --go-grpc_out=%s", filepath.Dir(src), filepath.Base(src), filepath.Dir(src), filepath.Dir(src))
 	ctx.ProtocCmd = fmt.Sprintf("protoc -I=%s %s --go_out=%s --go-grpc_out=%s", filepath.Dir(src), filepath.Base(src), filepath.Dir(src), filepath.Dir(src))
 
 
-	grpcOptList := c.StringSlice("go-grpc_opt")
+	grpcOptList := VarStringSliceGoGRPCOpt
 	if len(grpcOptList) > 0 {
 	if len(grpcOptList) > 0 {
 		ctx.ProtocCmd += " --go-grpc_opt=" + strings.Join(grpcOptList, ",")
 		ctx.ProtocCmd += " --go-grpc_opt=" + strings.Join(grpcOptList, ",")
 	}
 	}
 
 
-	goOptList := c.StringSlice("go_opt")
+	goOptList := VarStringSliceGoOpt
 	if len(goOptList) > 0 {
 	if len(goOptList) > 0 {
 		ctx.ProtocCmd += " --go_opt=" + strings.Join(goOptList, ",")
 		ctx.ProtocCmd += " --go_opt=" + strings.Join(goOptList, ",")
 	}
 	}
@@ -75,17 +102,12 @@ func RPCNew(c *cli.Context) error {
 }
 }
 
 
 // RPCTemplate is the entry for generate rpc template
 // RPCTemplate is the entry for generate rpc template
-func RPCTemplate(c *cli.Context) error {
+func RPCTemplate(_ *cobra.Command, _ []string) error {
 	console.Warning("deprecated: goctl rpc template -o is deprecated and will be removed in the future, use goctl rpc -o instead")
 	console.Warning("deprecated: goctl rpc template -o is deprecated and will be removed in the future, use goctl rpc -o instead")
-
-	if c.NumFlags() == 0 {
-		cli.ShowCommandHelpAndExit(c, "template", 1)
-	}
-
-	protoFile := c.String("o")
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
+	protoFile := VarStringOutput
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
 	if len(remote) > 0 {
 	if len(remote) > 0 {
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		repo, _ := util.CloneIntoGitHome(remote, branch)
 		if len(repo) > 0 {
 		if len(repo) > 0 {

+ 29 - 79
tools/goctl/rpc/cli/zrpc.go

@@ -6,7 +6,7 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/generator"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/generator"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
@@ -16,37 +16,26 @@ var (
 	errInvalidGrpcOutput = errors.New("ZRPC: missing --go-grpc_out")
 	errInvalidGrpcOutput = errors.New("ZRPC: missing --go-grpc_out")
 	errInvalidGoOutput   = errors.New("ZRPC: missing --go_out")
 	errInvalidGoOutput   = errors.New("ZRPC: missing --go_out")
 	errInvalidZrpcOutput = errors.New("ZRPC: missing zrpc output, please use --zrpc_out to specify the output")
 	errInvalidZrpcOutput = errors.New("ZRPC: missing zrpc output, please use --zrpc_out to specify the output")
-	errInvalidInput      = errors.New("ZRPC: missing source")
-	errMultiInput        = errors.New("ZRPC: only one source is expected")
 )
 )
 
 
 // ZRPC generates grpc code directly by protoc and generates
 // ZRPC generates grpc code directly by protoc and generates
 // zrpc code by goctl.
 // zrpc code by goctl.
-func ZRPC(c *cli.Context) error {
-	if c.NumFlags() == 0 {
-		cli.ShowCommandHelpAndExit(c, "protoc", 1)
-	}
-
-	args := c.Parent().Args()
-	protocArgs := removeGoctlFlag(args)
+func ZRPC(cmd *cobra.Command, args []string) error {
+	protocArgs := wrapProtocCmd("protoc", args)
 	pwd, err := os.Getwd()
 	pwd, err := os.Getwd()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	source, err := getSourceProto(c.Args(), pwd)
-	if err != nil {
-		return err
-	}
-
-	grpcOutList := c.StringSlice("go-grpc_out")
-	goOutList := c.StringSlice("go_out")
-	zrpcOut := c.String("zrpc_out")
-	style := c.String("style")
-	home := c.String("home")
-	remote := c.String("remote")
-	branch := c.String("branch")
-	verbose := c.Bool("verbose")
+	source := args[0]
+	grpcOutList := VarStringSliceGoGRPCOut
+	goOutList := VarStringSliceGoOut
+	zrpcOut := VarStringZRPCOut
+	style := VarStringStyle
+	home := VarStringHome
+	remote := VarStringRemote
+	branch := VarStringBranch
+	verbose := VarBoolVerbose
 	if len(grpcOutList) == 0 {
 	if len(grpcOutList) == 0 {
 		return errInvalidGrpcOutput
 		return errInvalidGrpcOutput
 	}
 	}
@@ -116,64 +105,25 @@ func ZRPC(c *cli.Context) error {
 	return g.Generate(&ctx)
 	return g.Generate(&ctx)
 }
 }
 
 
-func removeGoctlFlag(args []string) []string {
-	var ret []string
-	var step int
-	for step < len(args) {
-		arg := args[step]
-		switch {
-		case arg == "--style", arg == "--home",
-			arg == "--zrpc_out", arg == "--verbose",
-			arg == "-v", arg == "--remote",
-			arg == "--branch":
-			step += 2
-			continue
-		case strings.HasPrefix(arg, "--style="),
-			strings.HasPrefix(arg, "--home="),
-			strings.HasPrefix(arg, "--verbose="),
-			strings.HasPrefix(arg, "-v="),
-			strings.HasPrefix(arg, "--remote="),
-			strings.HasPrefix(arg, "--branch="),
-			strings.HasPrefix(arg, "--zrpc_out="):
-			step += 1
-			continue
-		}
-		step += 1
-		ret = append(ret, arg)
+func wrapProtocCmd(name string, args []string) []string {
+	ret := append([]string{name}, args...)
+	for _, protoPath := range VarStringSliceProtoPath {
+		ret = append(ret, "--proto_path", protoPath)
 	}
 	}
-
-	return ret
-}
-
-func getSourceProto(args []string, pwd string) (string, error) {
-	var source []string
-	for _, p := range args {
-		if strings.HasSuffix(p, ".proto") {
-			source = append(source, p)
-		}
+	for _, goOpt := range VarStringSliceGoOpt {
+		ret = append(ret, "--go_opt", goOpt)
 	}
 	}
-
-	switch len(source) {
-	case 0:
-		return "", errInvalidInput
-	case 1:
-		isAbs := filepath.IsAbs(source[0])
-		if isAbs {
-			return source[0], nil
-		}
-
-		abs := filepath.Join(pwd, source[0])
-		return abs, nil
-	default:
-		return "", errMultiInput
+	for _, goGRPCOpt := range VarStringSliceGoGRPCOpt {
+		ret = append(ret, "--go-grpc_opt", goGRPCOpt)
 	}
 	}
-}
-
-func removePluginFlag(goOut string) string {
-	goOut = strings.ReplaceAll(goOut, "plugins=", "")
-	index := strings.LastIndex(goOut, ":")
-	if index < 0 {
-		return goOut
+	for _, goOut := range VarStringSliceGoOut {
+		ret = append(ret, "--go_out", goOut)
+	}
+	for _, goGRPCOut := range VarStringSliceGoGRPCOut {
+		ret = append(ret, "--go-grpc_out", goGRPCOut)
 	}
 	}
-	return goOut[index+1:]
+	for _, plugin := range VarStringSlicePlugin {
+		ret = append(ret, "--plugin="+plugin)
+	}
+	return ret
 }
 }

+ 0 - 125
tools/goctl/rpc/cli/zrpc_test.go

@@ -1,125 +0,0 @@
-package cli
-
-import (
-	"os"
-	"path/filepath"
-	"strings"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-	"github.com/zeromicro/go-zero/tools/goctl/util/console"
-)
-
-type test struct {
-	source      []string
-	expected    string
-	expectedErr error
-}
-
-func Test_GetSourceProto(t *testing.T) {
-	pwd, err := os.Getwd()
-	if err != nil {
-		console.Error(err.Error())
-		return
-	}
-
-	testData := []test{
-		{
-			source:   []string{"a.proto"},
-			expected: filepath.Join(pwd, "a.proto"),
-		},
-		{
-			source:   []string{"/foo/bar/a.proto"},
-			expected: "/foo/bar/a.proto",
-		},
-		{
-			source:      []string{"a.proto", "b.proto"},
-			expectedErr: errMultiInput,
-		},
-		{
-			source:      []string{"", "--go_out=."},
-			expectedErr: errInvalidInput,
-		},
-	}
-
-	for _, d := range testData {
-		ret, err := getSourceProto(d.source, pwd)
-		if d.expectedErr != nil {
-			assert.Equal(t, d.expectedErr, err)
-			continue
-		}
-
-		assert.Equal(t, d.expected, ret)
-	}
-}
-
-func Test_RemoveGoctlFlag(t *testing.T) {
-	testData := []test{
-		{
-			source:   strings.Fields("protoc foo.proto --go_out=. --go_opt=bar --zrpc_out=. --style go-zero --home=foo"),
-			expected: "protoc foo.proto --go_out=. --go_opt=bar",
-		},
-		{
-			source:   strings.Fields("foo bar foo.proto"),
-			expected: "foo bar foo.proto",
-		},
-		{
-			source:   strings.Fields("protoc foo.proto --go_out . --style=go_zero --home ."),
-			expected: "protoc foo.proto --go_out .",
-		},
-		{
-			source:   strings.Fields(`protoc foo.proto --go_out . --style="go_zero" --home="."`),
-			expected: "protoc foo.proto --go_out .",
-		},
-		{
-			source:   strings.Fields(`protoc foo.proto --go_opt=. --zrpc_out . --style=goZero  --home=bar`),
-			expected: "protoc foo.proto --go_opt=.",
-		},
-		{
-			source:   strings.Fields(`protoc foo.proto --go_opt=. --zrpc_out="bar" --style=goZero  --home=bar`),
-			expected: "protoc foo.proto --go_opt=.",
-		},
-		{
-			source:   strings.Fields(`protoc --go_opt=. --go-grpc_out=. --zrpc_out=. foo.proto`),
-			expected: "protoc --go_opt=. --go-grpc_out=. foo.proto",
-		},
-		{
-			source:   strings.Fields(`protoc --go_opt=. --go-grpc_out=. --zrpc_out=. --remote=foo --branch=bar foo.proto`),
-			expected: "protoc --go_opt=. --go-grpc_out=. foo.proto",
-		},
-		{
-			source:   strings.Fields(`protoc --go_opt=. --go-grpc_out=. --zrpc_out=. --remote foo --branch bar foo.proto`),
-			expected: "protoc --go_opt=. --go-grpc_out=. foo.proto",
-		},
-	}
-	for _, e := range testData {
-		cmd := strings.Join(removeGoctlFlag(e.source), " ")
-		assert.Equal(t, e.expected, cmd)
-	}
-}
-
-func Test_RemovePluginFlag(t *testing.T) {
-	testData := []test{
-		{
-			source:   strings.Fields("plugins=grpc:."),
-			expected: ".",
-		},
-		{
-			source:   strings.Fields("plugins=g1,g2:."),
-			expected: ".",
-		},
-		{
-			source:   strings.Fields("g1,g2:."),
-			expected: ".",
-		},
-		{
-			source:   strings.Fields("plugins=g1,g2:foo"),
-			expected: "foo",
-		},
-	}
-
-	for _, e := range testData {
-		data := removePluginFlag(e.source[0])
-		assert.Equal(t, e.expected, data)
-	}
-}

+ 90 - 0
tools/goctl/rpc/cmd.go

@@ -0,0 +1,90 @@
+package rpc
+
+import (
+	"github.com/spf13/cobra"
+	"github.com/zeromicro/go-zero/tools/goctl/rpc/cli"
+)
+
+var (
+	// Cmd describes a rpc command.
+	Cmd = &cobra.Command{
+		Use:   "rpc",
+		Short: "Generate rpc code",
+		RunE:  cli.RPCTemplate,
+	}
+
+	newCmd = &cobra.Command{
+		Use:   "new",
+		Short: "Generate rpc demo service",
+		Args:  cobra.ExactValidArgs(1),
+		RunE:  cli.RPCNew,
+	}
+
+	templateCmd = &cobra.Command{
+		Use:   "template",
+		Short: "Generate proto template",
+		RunE:  cli.RPCTemplate,
+	}
+
+	protocCmd = &cobra.Command{
+		Use:     "protoc",
+		Short:   "Generate grpc code",
+		Example: "goctl rpc protoc xx.proto --go_out=./pb --go-grpc_out=./pb --zrpc_out=.",
+		Args:    cobra.ExactValidArgs(1),
+		RunE:    cli.ZRPC,
+	}
+)
+
+func init() {
+	Cmd.Flags().StringVar(&cli.VarStringOutput, "o", "", "Output a sample proto file")
+	Cmd.Flags().StringVar(&cli.VarStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	Cmd.Flags().StringVar(&cli.VarStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	Cmd.Flags().StringVar(&cli.VarStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+
+	newCmd.Flags().StringSliceVar(&cli.VarStringSliceGoOpt, "go_opt", nil, "")
+	newCmd.Flags().StringSliceVar(&cli.VarStringSliceGoGRPCOpt, "go-grpc_opt", nil, "")
+	newCmd.Flags().StringVar(&cli.VarStringStyle, "style", "gozero", "The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+	newCmd.Flags().BoolVar(&cli.VarBoolIdea, "idea", false, "Whether the command execution environment is from idea plugin.")
+	newCmd.Flags().StringVar(&cli.VarStringHome, "home", "", "The goctl home path of the template, "+
+		"--home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	newCmd.Flags().StringVar(&cli.VarStringRemote, "remote", "", "The remote git repo of the template, "+
+		"--home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo "+
+		"directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	newCmd.Flags().StringVar(&cli.VarStringBranch, "branch", "", "The branch of the remote repo, it "+
+		"does work with --remote")
+	newCmd.Flags().BoolVarP(&cli.VarBoolVerbose, "verbose", "v", false, "Enable log output")
+	newCmd.Flags().MarkHidden("go_opt")
+	newCmd.Flags().MarkHidden("go-grpc_opt")
+
+	protocCmd.Flags().StringSliceVar(&cli.VarStringSliceGoOut, "go_out", nil, "")
+	protocCmd.Flags().StringSliceVar(&cli.VarStringSliceGoGRPCOut, "go-grpc_out", nil, "")
+	protocCmd.Flags().StringSliceVar(&cli.VarStringSliceGoOpt, "go_opt", nil, "")
+	protocCmd.Flags().StringSliceVar(&cli.VarStringSliceGoGRPCOpt, "go-grpc_opt", nil, "")
+	protocCmd.Flags().StringSliceVar(&cli.VarStringSlicePlugin, "plugin", nil, "")
+	protocCmd.Flags().StringSliceVarP(&cli.VarStringSliceProtoPath, "proto_path", "I", nil, "")
+	protocCmd.Flags().StringVar(&cli.VarStringZRPCOut, "zrpc_out", "", "The zrpc output directory")
+	protocCmd.Flags().StringVar(&cli.VarStringStyle, "style", "gozero", "The file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]")
+	protocCmd.Flags().StringVar(&cli.VarStringHome, "home", "", "The goctl home path of the template, "+
+		"--home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	protocCmd.Flags().StringVar(&cli.VarStringRemote, "remote", "", "The remote git repo of the template, "+
+		"--home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo "+
+		"directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	protocCmd.Flags().StringVar(&cli.VarStringBranch, "branch", "", "The branch of the remote repo, it "+
+		"does work with --remote")
+	protocCmd.Flags().BoolVarP(&cli.VarBoolVerbose, "verbose", "v", false, "Enable log output")
+	protocCmd.Flags().MarkHidden("go_out")
+	protocCmd.Flags().MarkHidden("go-grpc_out")
+	protocCmd.Flags().MarkHidden("go_opt")
+	protocCmd.Flags().MarkHidden("go-grpc_opt")
+	protocCmd.Flags().MarkHidden("plugin")
+	protocCmd.Flags().MarkHidden("proto_path")
+
+	templateCmd.Flags().StringVar(&cli.VarStringOutput, "o", "", "Output a sample proto file")
+	templateCmd.Flags().StringVar(&cli.VarStringHome, "home", "", "The goctl home path of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority")
+	templateCmd.Flags().StringVar(&cli.VarStringRemote, "remote", "", "The remote git repo of the template, --home and --remote cannot be set at the same time, if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the https://github.com/zeromicro/go-zero-template directory structure")
+	templateCmd.Flags().StringVar(&cli.VarStringBranch, "branch", "", "The branch of the remote repo, it does work with --remote")
+
+	Cmd.AddCommand(newCmd)
+	Cmd.AddCommand(protocCmd)
+	Cmd.AddCommand(templateCmd)
+}

+ 1 - 2
tools/goctl/rpc/generator/template.go

@@ -3,7 +3,6 @@ package generator
 import (
 import (
 	"fmt"
 	"fmt"
 
 
-	"github.com/urfave/cli"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 	"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
 )
 )
 
 
@@ -40,7 +39,7 @@ var templates = map[string]string{
 
 
 // GenTemplates is the entry for command goctl template,
 // GenTemplates is the entry for command goctl template,
 // it will create the specified category
 // it will create the specified category
-func GenTemplates(_ *cli.Context) error {
+func GenTemplates() error {
 	return pathx.InitTemplates(category, templates)
 	return pathx.InitTemplates(category, templates)
 }
 }
 
 

+ 55 - 0
tools/goctl/tpl/cmd.go

@@ -0,0 +1,55 @@
+package tpl
+
+import (
+	"github.com/spf13/cobra"
+)
+
+var (
+	varStringHome     string
+	varStringCategory string
+	varStringName     string
+	// Cmd describes a template command.
+	Cmd = &cobra.Command{
+		Use:   "template",
+		Short: "Template operation",
+	}
+
+	initCmd = &cobra.Command{
+		Use:   "init",
+		Short: "Initialize the all templates(force update)",
+		RunE:  genTemplates,
+	}
+
+	cleanCmd = &cobra.Command{
+		Use:   "clean",
+		Short: "Clean the all cache templates",
+		RunE:  cleanTemplates,
+	}
+
+	updateCmd = &cobra.Command{
+		Use:   "update",
+		Short: "Update template of the target category to the latest",
+		RunE:  updateTemplates,
+	}
+
+	revertCmd = &cobra.Command{
+		Use:   "revert",
+		Short: "Revert the target template to the latest",
+		RunE:  revertTemplates,
+	}
+)
+
+func init() {
+	initCmd.Flags().StringVar(&varStringHome, "home", "", "The goctl home path of the template")
+	cleanCmd.Flags().StringVar(&varStringHome, "home", "", "The goctl home path of the template")
+	updateCmd.Flags().StringVar(&varStringHome, "home", "", "The goctl home path of the template")
+	updateCmd.Flags().StringVarP(&varStringCategory, "category", "c", "", "The category of template, enum [api,rpc,model,docker,kube]")
+	revertCmd.Flags().StringVar(&varStringHome, "home", "", "The goctl home path of the template")
+	revertCmd.Flags().StringVarP(&varStringCategory, "category", "c", "", "The category of template, enum [api,rpc,model,docker,kube]")
+	revertCmd.Flags().StringVarP(&varStringName, "name", "n", "", "The target file name of template")
+
+	Cmd.AddCommand(cleanCmd)
+	Cmd.AddCommand(initCmd)
+	Cmd.AddCommand(revertCmd)
+	Cmd.AddCommand(updateCmd)
+}

+ 24 - 24
tools/goctl/tpl/templates.go

@@ -5,7 +5,7 @@ import (
 	"path/filepath"
 	"path/filepath"
 
 
 	"github.com/logrusorgru/aurora"
 	"github.com/logrusorgru/aurora"
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/core/errorx"
 	"github.com/zeromicro/go-zero/core/errorx"
 	"github.com/zeromicro/go-zero/tools/goctl/api/apigen"
 	"github.com/zeromicro/go-zero/tools/goctl/api/apigen"
 	"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
 	"github.com/zeromicro/go-zero/tools/goctl/api/gogen"
@@ -20,37 +20,37 @@ import (
 
 
 const templateParentPath = "/"
 const templateParentPath = "/"
 
 
-// GenTemplates writes the latest template text into file which is not exists
-func GenTemplates(ctx *cli.Context) error {
-	path := ctx.String("home")
+// genTemplates writes the latest template text into file which is not exists
+func genTemplates(_ *cobra.Command, _ []string) error {
+	path := varStringHome
 	if len(path) != 0 {
 	if len(path) != 0 {
 		pathx.RegisterGoctlHome(path)
 		pathx.RegisterGoctlHome(path)
 	}
 	}
 
 
 	if err := errorx.Chain(
 	if err := errorx.Chain(
 		func() error {
 		func() error {
-			return gogen.GenTemplates(ctx)
+			return gogen.GenTemplates()
 		},
 		},
 		func() error {
 		func() error {
-			return modelgen.GenTemplates(ctx)
+			return modelgen.GenTemplates()
 		},
 		},
 		func() error {
 		func() error {
-			return rpcgen.GenTemplates(ctx)
+			return rpcgen.GenTemplates()
 		},
 		},
 		func() error {
 		func() error {
-			return docker.GenTemplates(ctx)
+			return docker.GenTemplates()
 		},
 		},
 		func() error {
 		func() error {
-			return kube.GenTemplates(ctx)
+			return kube.GenTemplates()
 		},
 		},
 		func() error {
 		func() error {
-			return mongogen.Templates(ctx)
+			return mongogen.Templates()
 		},
 		},
 		func() error {
 		func() error {
-			return apigen.GenTemplates(ctx)
+			return apigen.GenTemplates()
 		},
 		},
 		func() error {
 		func() error {
-			return apinew.GenTemplates(ctx)
+			return apinew.GenTemplates()
 		},
 		},
 	); err != nil {
 	); err != nil {
 		return err
 		return err
@@ -72,9 +72,9 @@ func GenTemplates(ctx *cli.Context) error {
 	return nil
 	return nil
 }
 }
 
 
-// CleanTemplates deletes all templates
-func CleanTemplates(ctx *cli.Context) error {
-	path := ctx.String("home")
+// cleanTemplates deletes all templates
+func cleanTemplates(_ *cobra.Command, _ []string) error {
+	path := varStringHome
 	if len(path) != 0 {
 	if len(path) != 0 {
 		pathx.RegisterGoctlHome(path)
 		pathx.RegisterGoctlHome(path)
 	}
 	}
@@ -113,11 +113,11 @@ func CleanTemplates(ctx *cli.Context) error {
 	return nil
 	return nil
 }
 }
 
 
-// UpdateTemplates writes the latest template text into file,
+// updateTemplates writes the latest template text into file,
 // it will delete the older templates if there are exists
 // it will delete the older templates if there are exists
-func UpdateTemplates(ctx *cli.Context) (err error) {
-	path := ctx.String("home")
-	category := ctx.String("category")
+func updateTemplates(_ *cobra.Command, _ []string) (err error) {
+	path := varStringHome
+	category := varStringCategory
 	if len(path) != 0 {
 	if len(path) != 0 {
 		pathx.RegisterGoctlHome(path)
 		pathx.RegisterGoctlHome(path)
 	}
 	}
@@ -150,11 +150,11 @@ func UpdateTemplates(ctx *cli.Context) (err error) {
 	}
 	}
 }
 }
 
 
-// RevertTemplates will overwrite the old template content with the new template
-func RevertTemplates(ctx *cli.Context) (err error) {
-	path := ctx.String("home")
-	category := ctx.String("category")
-	filename := ctx.String("name")
+// revertTemplates will overwrite the old template content with the new template
+func revertTemplates(_ *cobra.Command, _ []string) (err error) {
+	path := varStringHome
+	category := varStringCategory
+	filename := varStringName
 	if len(path) != 0 {
 	if len(path) != 0 {
 		pathx.RegisterGoctlHome(path)
 		pathx.RegisterGoctlHome(path)
 	}
 	}

+ 10 - 0
tools/goctl/upgrade/cmd.go

@@ -0,0 +1,10 @@
+package upgrade
+
+import "github.com/spf13/cobra"
+
+// Cmd describes a upgrade command.
+var Cmd = &cobra.Command{
+	Use:   "upgrade",
+	Short: "Upgrade goctl to latest version",
+	RunE:  upgrade,
+}

+ 2 - 2
tools/goctl/upgrade/upgrade.go

@@ -4,13 +4,13 @@ import (
 	"fmt"
 	"fmt"
 	"runtime"
 	"runtime"
 
 
-	"github.com/urfave/cli"
+	"github.com/spf13/cobra"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
 	"github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
 )
 )
 
 
 // Upgrade gets the latest goctl by
 // Upgrade gets the latest goctl by
 // go install github.com/zeromicro/go-zero/tools/goctl@latest
 // go install github.com/zeromicro/go-zero/tools/goctl@latest
-func Upgrade(_ *cli.Context) error {
+func upgrade(_ *cobra.Command, _ []string) error {
 	cmd := `GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest`
 	cmd := `GO111MODULE=on GOPROXY=https://goproxy.cn/,direct go install github.com/zeromicro/go-zero/tools/goctl@latest`
 	if runtime.GOOS == "windows" {
 	if runtime.GOOS == "windows" {
 		cmd = `set GOPROXY=https://goproxy.cn,direct && go install github.com/zeromicro/go-zero/tools/goctl@latest`
 		cmd = `set GOPROXY=https://goproxy.cn,direct && go install github.com/zeromicro/go-zero/tools/goctl@latest`

+ 18 - 0
tools/goctl/util/pathx/file.go

@@ -2,6 +2,8 @@ package pathx
 
 
 import (
 import (
 	"bufio"
 	"bufio"
+	"crypto/md5"
+	"encoding/hex"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
@@ -283,3 +285,19 @@ func Copy(src, dest string) error {
 	_, err = io.Copy(w, f)
 	_, err = io.Copy(w, f)
 	return err
 	return err
 }
 }
+
+func Hash(file string) (string, error) {
+	f, err := os.Open(file)
+	if err != nil {
+		return "", err
+	}
+	defer func() {
+		_ = f.Close()
+	}()
+	hash := md5.New()
+	_, err = io.Copy(hash, f)
+	if err != nil {
+		return "", err
+	}
+	return hex.EncodeToString(hash.Sum(nil)), nil
+}