diff --git a/.example/os/gcmd/manager/main.go b/.example/os/gcmd/manager/main.go deleted file mode 100644 index e7ed739e0..000000000 --- a/.example/os/gcmd/manager/main.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "github.com/gogf/gf/frame/g" - "github.com/gogf/gf/os/gcmd" -) - -func main() { - var err error - c := &gcmd.Command{ - Name: "gf", - Description: `GoFrame Command Line Interface, which is your helpmate for building GoFrame application with convenience.`, - Additional: ` -Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '...' in the tail of their comments.`, - } - // env - commandEnv := gcmd.Command{ - Name: "env", - Brief: "show current Golang environment variables", - Description: "show current Golang environment variables", - Func: func(parser *gcmd.Parser) { - - }, - } - if err = c.AddCommand(commandEnv); err != nil { - g.Log().Fatal(err) - } - // get - commandGet := gcmd.Command{ - Name: "get", - Brief: "install or update GF to system in default...", - Description: "show current Golang environment variables", - - Examples: ` -gf get github.com/gogf/gf -gf get github.com/gogf/gf@latest -gf get github.com/gogf/gf@master -gf get golang.org/x/sys -`, - Func: func(parser *gcmd.Parser) { - - }, - } - if err = c.AddCommand(commandGet); err != nil { - g.Log().Fatal(err) - } - // build - //-n, --name output binary name - //-v, --version output binary version - //-a, --arch output binary architecture, multiple arch separated with ',' - //-s, --system output binary system, multiple os separated with ',' - //-o, --output output binary path, used when building single binary file - //-p, --path output binary directory path, default is './bin' - //-e, --extra extra custom "go build" options - //-m, --mod like "-mod" option of "go build", use "-m none" to disable go module - //-c, --cgo enable or disable cgo feature, it's disabled in default - - commandBuild := gcmd.Command{ - Name: "build", - Usage: "gf build FILE [OPTION]", - Brief: "cross-building go project for lots of platforms...", - Description: ` -The "build" command is most commonly used command, which is designed as a powerful wrapper for -"go build" command for convenience cross-compiling usage. -It provides much more features for building binary: -1. Cross-Compiling for many platforms and architectures. -2. Configuration file support for compiling. -3. Build-In Variables. -`, - Examples: ` -gf build main.go -gf build main.go --swagger -gf build main.go --pack public,template -gf build main.go --cgo -gf build main.go -m none -gf build main.go -n my-app -a all -s all -gf build main.go -n my-app -a amd64,386 -s linux -p . -gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin -`, - Func: func(parser *gcmd.Parser) { - - }, - } - if err = c.AddCommand(commandBuild); err != nil { - g.Log().Fatal(err) - } - c.Run() -} diff --git a/os/gcmd/gcmd.go b/os/gcmd/gcmd.go index 1fe7f07c8..8278521a0 100644 --- a/os/gcmd/gcmd.go +++ b/os/gcmd/gcmd.go @@ -19,11 +19,7 @@ import ( const ( helpOptionName = "help" helpOptionNameShort = "h" - maxLineChars = 100 -) - -var ( - defaultCommandFuncMap = make(map[string]func()) + maxLineChars = 120 ) // Init does custom initialization. diff --git a/os/gcmd/gcmd_command.go b/os/gcmd/gcmd_command.go index a2af75d6a..e09e58687 100644 --- a/os/gcmd/gcmd_command.go +++ b/os/gcmd/gcmd_command.go @@ -8,122 +8,51 @@ package gcmd import ( - "bytes" - "fmt" - "os" + "context" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/internal/command" "github.com/gogf/gf/v2/text/gstr" ) +// Command holds the info about an argument that can handle custom logic. type Command struct { - parent *Command - commands []Command - options []Option - level int - Name string - Usage string - Short string - Brief string - Description string - Func func(parser *Parser) - HelpFunc func(parser *Parser) - Examples string - Additional string + Name string // Command name(case-sensitive). + Usage string // A brief line description about its usage, eg: gf build main.go [OPTION] + Brief string // A brief info that describes what this command will do. + Description string // A detailed description. + Options []Option // Option array, configuring how this command act. + Func Function // Custom function. + HelpFunc Function // Custom help function + Examples string // Usage examples. + Additional string // Additional custom info about this command. + parent *Command // Parent command for internal usage. + commands []Command // Sub commands of this command. } +// Function is a custom command callback function that is bound to a certain argument. +type Function func(ctx context.Context, parser *Parser) (err error) + +// Option is the command value that is specified by a name or shor name. +// An Option can have or have no value bound to it. type Option struct { - Name string - Short string - Brief string - Description string - NeedValue bool + Name string // Option name. + Short string // Option short. + Brief string // Brief info about this Option, which is used in help info. + NeedValue bool // Whether this Option having or having no value bound to it. } -func (c *Command) Print() { - prefix := gstr.Repeat(" ", 4) - buffer := bytes.NewBuffer(nil) - // Usage. - if c.Usage != "" || c.Name != "" { - buffer.WriteString("USAGE\n") - buffer.WriteString(prefix) - if c.Usage != "" { - buffer.WriteString(c.Usage) - } else { - var ( - p = c - name = c.Name - ) - for p.parent != nil { - name = p.parent.Name + " " + name - p = p.parent - } - buffer.WriteString(fmt.Sprintf(`%s ARGUMENT [OPTION]`, name)) - } - buffer.WriteString("\n\n") - } - // Command. - if len(c.commands) > 0 { - buffer.WriteString("COMMAND\n") - maxSpaceLength := 0 - for _, cmd := range c.commands { - nameStr := cmd.Name + "/" + cmd.Short - if len(nameStr) > maxSpaceLength { - maxSpaceLength = len(nameStr) - } - } - for _, cmd := range c.commands { - nameStr := cmd.Name - if cmd.Short != "" { - nameStr += "/" + cmd.Short - } - var ( - spaceLength = maxSpaceLength - len(nameStr) - lineStr = fmt.Sprintf( - "%s%s%s %s\n", - prefix, nameStr, gstr.Repeat(" ", spaceLength), cmd.Brief, - ) - ) - lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n") - buffer.WriteString(lineStr) - } - buffer.WriteString("\n") +var ( + // defaultHelpOption is the default help option that will be automatically added to each command. + defaultHelpOption = Option{ + Name: `help`, + Short: `h`, + Brief: `more information about this command`, + NeedValue: false, } +) - // Examples. - if c.Examples != "" { - buffer.WriteString("EXAMPLES\n") - lineStr := gstr.WordWrap(gstr.Trim(c.Examples), maxLineChars, "\n") - for _, line := range gstr.SplitAndTrim(lineStr, "\n") { - buffer.WriteString(prefix) - buffer.WriteString(line) - buffer.WriteString("\n") - } - buffer.WriteString("\n") - } - // Description. - if c.Description != "" { - buffer.WriteString("DESCRIPTION\n") - lineStr := gstr.WordWrap(gstr.Trim(c.Description), maxLineChars, "\n") - for _, line := range gstr.SplitAndTrim(lineStr, "\n") { - buffer.WriteString(prefix) - buffer.WriteString(line) - buffer.WriteString("\n") - } - } - buffer.WriteString("\n") - // Additional. - if c.Additional != "" { - lineStr := gstr.WordWrap(gstr.Trim(c.Additional), maxLineChars, "\n") - buffer.WriteString(lineStr) - } - buffer.WriteString("\n") - fmt.Println(buffer.String()) -} - -func (c *Command) AddCommand(command ...Command) error { - for _, cmd := range command { +func (c *Command) Add(commands ...Command) error { + for _, cmd := range commands { cmd.Name = gstr.Trim(cmd.Name) if cmd.Name == "" { return gerror.New("command name should not be empty") @@ -132,72 +61,7 @@ func (c *Command) AddCommand(command ...Command) error { return gerror.New("command function should not be empty") } cmd.parent = c - cmd.level = c.level + 1 c.commands = append(c.commands, cmd) } return nil } - -func (c *Command) AddOption(option ...Option) error { - for _, opt := range option { - opt.Name = gstr.Trim(opt.Name) - if opt.Name == "" { - return gerror.New("option name should not be empty") - } - } - c.options = append(c.options, option...) - return nil -} - -func (c *Command) Run() { - // Find the matched command and run it. - argument := GetArg(c.level + 1) - if !argument.IsEmpty() { - if len(c.commands) > 0 { - for _, cmd := range c.commands { - if gstr.Equal(cmd.Name, argument.String()) { - cmd.Run() - return - } - } - } - } - // Run current command function. - var ( - err error - parser *Parser - ) - if len(c.options) > 0 { - optionParsingMap := make(map[string]bool, 0) - // Add custom options to parser. - for _, option := range c.options { - optionParsingKey := option.Name - if option.Short != "" { - optionParsingKey += "," + option.Short - } - optionParsingMap[optionParsingKey] = option.NeedValue - } - // Add help option to parser. - optionParsingMap[helpOptionName+","+helpOptionNameShort] = false - parser, err = Parse(optionParsingMap) - } else { - parsedArgs, parsedOptions := command.ParseUsingDefaultAlgorithm(os.Args...) - parser = &Parser{ - strict: false, - parsedArgs: parsedArgs, - parsedOptions: parsedOptions, - } - } - if err != nil { - fmt.Println("Error:", err) - } - if parser.ContainsOpt(helpOptionName) || parser.ContainsOpt(helpOptionNameShort) { - if c.HelpFunc != nil { - c.HelpFunc(parser) - } else { - c.Print() - } - return - } - c.Func(parser) -} diff --git a/os/gcmd/gcmd_command_help.go b/os/gcmd/gcmd_command_help.go new file mode 100644 index 000000000..6dc6ac6c9 --- /dev/null +++ b/os/gcmd/gcmd_command_help.go @@ -0,0 +1,130 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. +// + +package gcmd + +import ( + "bytes" + "context" + "fmt" + + "github.com/gogf/gf/v2/text/gstr" +) + +func (c *Command) Print() { + prefix := gstr.Repeat(" ", 4) + buffer := bytes.NewBuffer(nil) + // Usage. + if c.Usage != "" || c.Name != "" { + buffer.WriteString("USAGE\n") + buffer.WriteString(prefix) + if c.Usage != "" { + buffer.WriteString(c.Usage) + } else { + var ( + p = c + name = c.Name + ) + for p.parent != nil { + name = p.parent.Name + " " + name + p = p.parent + } + buffer.WriteString(fmt.Sprintf(`%s ARGUMENT [OPTION]`, name)) + } + buffer.WriteString("\n\n") + } + // Command. + if len(c.commands) > 0 { + buffer.WriteString("COMMAND\n") + var ( + maxSpaceLength = 0 + ) + for _, cmd := range c.commands { + if len(cmd.Name) > maxSpaceLength { + maxSpaceLength = len(cmd.Name) + } + } + for _, cmd := range c.commands { + // Add "..." to brief for those commands that also have sub-commands. + if len(cmd.commands) > 0 { + cmd.Brief = gstr.TrimRight(cmd.Brief, ".") + "..." + } + var ( + spaceLength = maxSpaceLength - len(cmd.Name) + lineStr = fmt.Sprintf("%s%s%s%s\n", prefix, cmd.Name, gstr.Repeat(" ", spaceLength+4), cmd.Brief) + wordwrapPrefix = gstr.Repeat(" ", len(prefix+cmd.Name)+spaceLength+4) + ) + lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+wordwrapPrefix) + buffer.WriteString(lineStr) + } + buffer.WriteString("\n") + } + + // Option. + if len(c.Options) > 0 { + buffer.WriteString("OPTION\n") + var ( + nameStr string + maxSpaceLength = 0 + ) + for _, option := range c.Options { + if option.Short != "" { + nameStr = fmt.Sprintf("-%s,\t--%s", option.Short, option.Name) + } else { + nameStr = fmt.Sprintf("-/--%s", option.Name) + } + if len(nameStr) > maxSpaceLength { + maxSpaceLength = len(nameStr) + } + } + for _, option := range c.Options { + if option.Short != "" { + nameStr = fmt.Sprintf("-%s,\t--%s", option.Short, option.Name) + } else { + nameStr = fmt.Sprintf("-/--%s", option.Name) + } + var ( + spaceLength = maxSpaceLength - len(nameStr) + lineStr = fmt.Sprintf("%s%s%s%s\n", prefix, nameStr, gstr.Repeat(" ", spaceLength+4), option.Brief) + wordwrapPrefix = gstr.Repeat(" ", len(prefix+nameStr)+spaceLength+4) + ) + lineStr = gstr.WordWrap(lineStr, maxLineChars, "\n"+wordwrapPrefix) + buffer.WriteString(lineStr) + } + buffer.WriteString("\n") + } + + // Example. + if c.Examples != "" { + buffer.WriteString("EXAMPLE\n") + buffer.WriteString(prefix) + buffer.WriteString(gstr.WordWrap(gstr.Trim(c.Examples), maxLineChars, "\n"+prefix)) + buffer.WriteString("\n") + } + + // Description. + if c.Description != "" { + buffer.WriteString("DESCRIPTION\n") + buffer.WriteString(prefix) + buffer.WriteString(gstr.WordWrap(gstr.Trim(c.Description), maxLineChars, "\n"+prefix)) + buffer.WriteString("\n") + } + buffer.WriteString("\n") + + // Additional. + if c.Additional != "" { + lineStr := gstr.WordWrap(gstr.Trim(c.Additional), maxLineChars, "\n") + buffer.WriteString(lineStr) + } + buffer.WriteString("\n") + fmt.Println(buffer.String()) +} + +func (c *Command) defaultHelpFunc(ctx context.Context, parser *Parser) error { + c.Print() + return nil +} diff --git a/os/gcmd/gcmd_command_run.go b/os/gcmd/gcmd_command_run.go new file mode 100644 index 000000000..507f22aa1 --- /dev/null +++ b/os/gcmd/gcmd_command_run.go @@ -0,0 +1,99 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. +// + +package gcmd + +import ( + "context" + "fmt" + + "github.com/gogf/gf/v2/text/gstr" +) + +func (c *Command) Run(ctx context.Context) error { + // Parse command arguments and options using default algorithm. + parser, err := Parse(nil) + if err != nil { + return err + } + args := parser.GetArgAll() + if len(args) == 1 { + if c.HelpFunc != nil { + return c.HelpFunc(ctx, parser) + } + return c.defaultHelpFunc(ctx, parser) + } + + // Exclude the root binary name. + args = args[1:] + + // Find the matched command and run it. + if subCommand := c.searchCommand(args); subCommand != nil { + return subCommand.doRun(ctx, parser) + } + + // Print error and help command if no command found. + fmt.Printf("Error: command not found for \"%s\"\n\n", gstr.Join(args, " ")) + c.Print() + + return nil +} + +func (c *Command) doRun(ctx context.Context, parser *Parser) (err error) { + // Add built-in help option, just for info only. + c.Options = append(c.Options, defaultHelpOption) + // Check built-in help command. + if parser.ContainsOpt(helpOptionName) || parser.ContainsOpt(helpOptionNameShort) { + if c.HelpFunc != nil { + return c.HelpFunc(ctx, parser) + } + return c.defaultHelpFunc(ctx, parser) + } + // Reparse the arguments for current command configuration. + parser, err = c.reParse(ctx, parser) + if err != nil { + return err + } + // Registered command function calling. + return c.Func(ctx, parser) +} + +func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error) { + // It seems just has built-in help option, it so does nothing. + if len(c.Options) == 1 { + return parser, nil + } + var ( + optionKey string + supportedOptions = make(map[string]bool) + ) + for _, option := range c.Options { + if option.Short != "" { + optionKey = fmt.Sprintf(`%s.%s`, option.Name, option.Short) + } else { + optionKey = option.Name + } + supportedOptions[optionKey] = option.NeedValue + } + return Parse(supportedOptions) +} + +func (c *Command) searchCommand(args []string) *Command { + if len(args) == 0 { + return nil + } + for _, cmd := range c.commands { + if cmd.Name == args[0] { + leftArgs := args[1:] + if len(leftArgs) == 0 { + return &cmd + } + return cmd.searchCommand(leftArgs) + } + } + return nil +} diff --git a/os/gcmd/gcmd_handler.go b/os/gcmd/gcmd_handler.go deleted file mode 100644 index b371059c8..000000000 --- a/os/gcmd/gcmd_handler.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. -// - -package gcmd - -import ( - "github.com/gogf/gf/v2/errors/gcode" - "github.com/gogf/gf/v2/errors/gerror" -) - -// BindHandle registers callback function `f` with `cmd`. -func BindHandle(cmd string, f func()) error { - if _, ok := defaultCommandFuncMap[cmd]; ok { - return gerror.NewCode(gcode.CodeInvalidOperation, "duplicated handle for command:"+cmd) - } else { - defaultCommandFuncMap[cmd] = f - } - return nil -} - -// BindHandleMap registers callback function with map `m`. -func BindHandleMap(m map[string]func()) error { - var err error - for k, v := range m { - if err = BindHandle(k, v); err != nil { - return err - } - } - return err -} - -// RunHandle executes the callback function registered by `cmd`. -func RunHandle(cmd string) error { - if handle, ok := defaultCommandFuncMap[cmd]; ok { - handle() - } else { - return gerror.NewCode(gcode.CodeMissingConfiguration, "no handle found for command:"+cmd) - } - return nil -} - -// AutoRun automatically recognizes and executes the callback function -// by value of index 0 (the first console parameter). -func AutoRun() error { - if cmd := GetArg(1); !cmd.IsEmpty() { - if handle, ok := defaultCommandFuncMap[cmd.String()]; ok { - handle() - } else { - return gerror.NewCode(gcode.CodeMissingConfiguration, "no handle found for command:"+cmd.String()) - } - } else { - return gerror.NewCode(gcode.CodeMissingParameter, "no command found") - } - return nil -} diff --git a/os/gcmd/gcmd_parser.go b/os/gcmd/gcmd_parser.go index 9306be1b9..746381c9a 100644 --- a/os/gcmd/gcmd_parser.go +++ b/os/gcmd/gcmd_parser.go @@ -14,6 +14,7 @@ import ( "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" + "github.com/gogf/gf/v2/internal/command" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/text/gregex" "github.com/gogf/gf/v2/text/gstr" @@ -25,7 +26,7 @@ type Parser struct { parsedArgs []string // As name described. parsedOptions map[string]string // As name described. passedOptions map[string]bool // User passed supported options. - supportedOptions map[string]bool // Option [option name : need argument]. + supportedOptions map[string]bool // Option [OptionName:WhetherNeedArgument]. commandFuncMap map[string]func() // Command function map for function handler. } @@ -36,6 +37,13 @@ type Parser struct { // // The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed. func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) { + if supportedOptions == nil { + command.Init(os.Args...) + return &Parser{ + parsedArgs: GetArgAll(), + parsedOptions: GetOptAll(), + }, nil + } return ParseWithArgs(os.Args, supportedOptions, strict...) } @@ -46,6 +54,13 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) { // // The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed. func ParseWithArgs(args []string, supportedOptions map[string]bool, strict ...bool) (*Parser, error) { + if supportedOptions == nil { + command.Init(args...) + return &Parser{ + parsedArgs: GetArgAll(), + parsedOptions: GetOptAll(), + }, nil + } strictParsing := false if len(strict) > 0 { strictParsing = strict[0] @@ -86,7 +101,7 @@ func ParseWithArgs(args []string, supportedOptions map[string]bool, strict ...bo } } else { // Multiple options? - if array := parser.parseMultiOption(option); len(array) > 0 { + if array = parser.parseMultiOption(option); len(array) > 0 { for _, v := range array { parser.setOptionValue(v, "") } diff --git a/os/gcmd/gcmd_z_unit_test.go b/os/gcmd/gcmd_z_unit_test.go index dc570e3c2..02b2f6673 100644 --- a/os/gcmd/gcmd_z_unit_test.go +++ b/os/gcmd/gcmd_z_unit_test.go @@ -9,10 +9,13 @@ package gcmd_test import ( + "context" + "fmt" "testing" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gcmd" + "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/genv" "github.com/gogf/gf/v2/test/gtest" ) @@ -67,3 +70,151 @@ func Test_GetWithEnv(t *testing.T) { t.Assert(gcmd.GetOptWithEnv("test"), 2) }) } + +func Test_Command(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + ctx = gctx.New() + err error + ) + commandRoot := &gcmd.Command{ + Name: "gf", + } + // env + commandEnv := gcmd.Command{ + Name: "env", + Func: func(ctx context.Context, parser *gcmd.Parser) error { + fmt.Println("env") + return nil + }, + } + // test + commandTest := gcmd.Command{ + Name: "test", + Brief: "test brief", + Description: "test description current Golang environment variables", + Examples: ` +gf get github.com/gogf/gf +gf get github.com/gogf/gf@latest +gf get github.com/gogf/gf@master +gf get golang.org/x/sys +`, + Options: []gcmd.Option{ + { + Name: "my-option", + Short: "o", + Brief: "It's my custom option", + NeedValue: false, + }, + { + Name: "another", + Short: "a", + Brief: "It's my another custom option", + NeedValue: false, + }, + }, + Func: func(ctx context.Context, parser *gcmd.Parser) error { + fmt.Println("test") + return nil + }, + } + err = commandRoot.Add( + commandEnv, + commandTest, + ) + if err != nil { + g.Log().Fatal(ctx, err) + } + + if err = commandRoot.Run(ctx); err != nil { + g.Log().Fatal(ctx, err) + } + }) +} + +func Test_Command_Print(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + ctx = gctx.New() + err error + ) + c := &gcmd.Command{ + Name: "gf", + Description: `GoFrame Command Line Interface, which is your helpmate for building GoFrame application with convenience.`, + Additional: ` +Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '...' in the tail of their comments.`, + } + // env + commandEnv := gcmd.Command{ + Name: "env", + Brief: "show current Golang environment variables, long brief.long brief.long brief.long brief.long brief.long brief.long brief.long brief.", + Description: "show current Golang environment variables", + Func: func(ctx context.Context, parser *gcmd.Parser) error { + return nil + }, + } + if err = c.Add(commandEnv); err != nil { + g.Log().Fatal(ctx, err) + } + // get + commandGet := gcmd.Command{ + Name: "get", + Brief: "install or update GF to system in default...", + Description: "show current Golang environment variables", + + Examples: ` +gf get github.com/gogf/gf +gf get github.com/gogf/gf@latest +gf get github.com/gogf/gf@master +gf get golang.org/x/sys +`, + Func: func(ctx context.Context, parser *gcmd.Parser) error { + return nil + }, + } + if err = c.Add(commandGet); err != nil { + g.Log().Fatal(ctx, err) + } + // build + //-n, --name output binary name + //-v, --version output binary version + //-a, --arch output binary architecture, multiple arch separated with ',' + //-s, --system output binary system, multiple os separated with ',' + //-o, --output output binary path, used when building single binary file + //-p, --path output binary directory path, default is './bin' + //-e, --extra extra custom "go build" options + //-m, --mod like "-mod" option of "go build", use "-m none" to disable go module + //-c, --cgo enable or disable cgo feature, it's disabled in default + + commandBuild := gcmd.Command{ + Name: "build", + Usage: "gf build FILE [OPTION]", + Brief: "cross-building go project for lots of platforms...", + Description: ` +The "build" command is most commonly used command, which is designed as a powerful wrapper for +"go build" command for convenience cross-compiling usage. +It provides much more features for building binary: +1. Cross-Compiling for many platforms and architectures. +2. Configuration file support for compiling. +3. Build-In Variables. +`, + Examples: ` +gf build main.go +gf build main.go --swagger +gf build main.go --pack public,template +gf build main.go --cgo +gf build main.go -m none +gf build main.go -n my-app -a all -s all +gf build main.go -n my-app -a amd64,386 -s linux -p . +gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin +`, + Func: func(ctx context.Context, parser *gcmd.Parser) error { + return nil + }, + } + if err = c.Add(commandBuild); err != nil { + g.Log().Fatal(ctx, err) + } + c.Run(ctx) + }) +}