mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
gcmd manager feature
This commit is contained in:
@ -35,24 +35,24 @@ 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 // 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.
|
||||
Name string // Option name.
|
||||
Short string // Option short.
|
||||
Brief string // Brief info about this Option, which is used in help info.
|
||||
Orphan bool // Whether this Option having or having no value bound to it.
|
||||
}
|
||||
|
||||
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,
|
||||
Name: `help`,
|
||||
Short: `h`,
|
||||
Brief: `more information about this command`,
|
||||
Orphan: true,
|
||||
}
|
||||
)
|
||||
|
||||
// Add adds one or more sub-commands to current command.
|
||||
func (c *Command) Add(commands ...Command) error {
|
||||
// AddCommand adds one or more sub-commands to current command.
|
||||
func (c *Command) AddCommand(commands ...Command) error {
|
||||
for _, cmd := range commands {
|
||||
cmd.Name = gstr.Trim(cmd.Name)
|
||||
if cmd.Name == "" {
|
||||
|
||||
119
os/gcmd/gcmd_command_object.go
Normal file
119
os/gcmd/gcmd_command_object.go
Normal file
@ -0,0 +1,119 @@
|
||||
// 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 (
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/utils"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
)
|
||||
|
||||
const (
|
||||
tagNameName = `name`
|
||||
tagNameUsage = `usage`
|
||||
tagNameBrief = `brief`
|
||||
tagNameShort = `short`
|
||||
tagNameOrphan = `orphan`
|
||||
tagNameDescription = `description`
|
||||
tagNameDc = `dc`
|
||||
tagNameAddition = `additional`
|
||||
tagNameAd = `ad`
|
||||
)
|
||||
|
||||
func (c *Command) AddObject(objects ...interface{}) (err error) {
|
||||
for _, object := range objects {
|
||||
if err = c.doAddObject(object); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Command) doAddObject(object interface{}) error {
|
||||
originValueAndKind := utils.OriginValueAndKind(object)
|
||||
if originValueAndKind.OriginKind != reflect.Struct {
|
||||
return gerror.Newf(
|
||||
`input object should be type of struct, but got "%s"`,
|
||||
originValueAndKind.InputValue.Type().String(),
|
||||
)
|
||||
}
|
||||
for i := 0; i < originValueAndKind.InputValue.NumMethod(); i++ {
|
||||
method := originValueAndKind.InputValue.Method(i)
|
||||
}
|
||||
for _, field := range fields {
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newCommandFromMethod(object, method reflect.Value) (cmd *Command, err error) {
|
||||
var (
|
||||
reflectType = method.Type()
|
||||
)
|
||||
if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
|
||||
if reflectType.PkgPath() != "" {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid handler: %s.%s.%s defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
|
||||
reflectType.PkgPath(), object.Type().Name(), reflectType.Name(), reflectType.String(),
|
||||
)
|
||||
} else {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid handler: defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
|
||||
reflectType.String(),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if reflectType.In(0).String() != "context.Context" {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid handler: defined as "%s", but the first input parameter should be type of "context.Context"`,
|
||||
reflectType.String(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if reflectType.Out(1).String() != "error" {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid handler: defined as "%s", but the last output parameter should be type of "error"`,
|
||||
reflectType.String(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// The input struct should be named as `xxxInput`.
|
||||
if !gstr.HasSuffix(reflectType.In(1).String(), `Input`) {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid struct naming for input: defined as "%s", but it should be named with "Input" suffix like "xxxInput"`,
|
||||
reflectType.In(1).String(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// The output struct should be named as `xxxOutput`.
|
||||
if !gstr.HasSuffix(reflectType.Out(0).String(), `Output`) {
|
||||
err = gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`invalid struct naming for output: defined as "%s", but it should be named with "Output" suffix like "xxxOutput"`,
|
||||
reflectType.Out(0).String(),
|
||||
)
|
||||
return
|
||||
}
|
||||
var (
|
||||
metaMap = gmeta.Data()
|
||||
)
|
||||
}
|
||||
@ -84,7 +84,7 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
|
||||
} else {
|
||||
optionKey = option.Name
|
||||
}
|
||||
supportedOptions[optionKey] = option.NeedValue
|
||||
supportedOptions[optionKey] = !option.Orphan
|
||||
}
|
||||
return Parse(supportedOptions)
|
||||
}
|
||||
|
||||
113
os/gcmd/gcmd_z_unit_feature_object_test.go
Normal file
113
os/gcmd/gcmd_z_unit_feature_object_test.go
Normal file
@ -0,0 +1,113 @@
|
||||
// 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.
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
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/test/gtest"
|
||||
)
|
||||
|
||||
type TestCmdObject struct{}
|
||||
|
||||
type TestCmdObjectInput struct {
|
||||
g.Meta `name:"gf" usage:"gf env/test" brief:"gf env command" dc:"description" ad:"ad"`
|
||||
}
|
||||
type TestCmdObjectOutput struct{}
|
||||
|
||||
type TestCmdObjectEnvInput struct {
|
||||
g.Meta `name:"env" usage:"gf env/test" brief:"gf env command" dc:"description" ad:"ad"`
|
||||
Name string `v:"required" name:"name" short:"n" orphan:"false" brief:"name for command"`
|
||||
}
|
||||
type TestCmdObjectEnvOutput struct{}
|
||||
|
||||
type TestCmdObjectTestInput struct {
|
||||
g.Meta `name:"test" usage:"gf env/test" brief:"gf test command" dc:"description" ad:"ad"`
|
||||
Name string `v:"required" name:"name" short:"n" orphan:"false" brief:"name for command"`
|
||||
}
|
||||
type TestCmdObjectTestOutput struct{}
|
||||
|
||||
func (TestCmdObject) Root(ctx context.Context, in TestCmdObjectInput) (out *TestCmdObjectOutput, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (TestCmdObject) Env(ctx context.Context, in TestCmdObjectEnvInput) (out *TestCmdObjectEnvOutput, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (TestCmdObject) Test(ctx context.Context, in TestCmdObjectTestInput) (out *TestCmdObjectTestOutput, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func Test_Command_AddObject(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",
|
||||
Orphan: false,
|
||||
},
|
||||
{
|
||||
Name: "another",
|
||||
Short: "a",
|
||||
Brief: "It's my another custom option",
|
||||
Orphan: false,
|
||||
},
|
||||
},
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) error {
|
||||
fmt.Println("test")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
err = commandRoot.AddCommand(
|
||||
commandEnv,
|
||||
commandTest,
|
||||
)
|
||||
if err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
|
||||
if err = commandRoot.Run(ctx); err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -101,16 +101,16 @@ gf get golang.org/x/sys
|
||||
`,
|
||||
Options: []gcmd.Option{
|
||||
{
|
||||
Name: "my-option",
|
||||
Short: "o",
|
||||
Brief: "It's my custom option",
|
||||
NeedValue: false,
|
||||
Name: "my-option",
|
||||
Short: "o",
|
||||
Brief: "It's my custom option",
|
||||
Orphan: true,
|
||||
},
|
||||
{
|
||||
Name: "another",
|
||||
Short: "a",
|
||||
Brief: "It's my another custom option",
|
||||
NeedValue: false,
|
||||
Name: "another",
|
||||
Short: "a",
|
||||
Brief: "It's my another custom option",
|
||||
Orphan: true,
|
||||
},
|
||||
},
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) error {
|
||||
@ -118,7 +118,7 @@ gf get golang.org/x/sys
|
||||
return nil
|
||||
},
|
||||
}
|
||||
err = commandRoot.Add(
|
||||
err = commandRoot.AddCommand(
|
||||
commandEnv,
|
||||
commandTest,
|
||||
)
|
||||
@ -153,7 +153,7 @@ Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err = c.Add(commandEnv); err != nil {
|
||||
if err = c.AddCommand(commandEnv); err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
// get
|
||||
@ -172,7 +172,7 @@ gf get golang.org/x/sys
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err = c.Add(commandGet); err != nil {
|
||||
if err = c.AddCommand(commandGet); err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
// build
|
||||
@ -212,7 +212,7 @@ gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./dock
|
||||
return nil
|
||||
},
|
||||
}
|
||||
if err = c.Add(commandBuild); err != nil {
|
||||
if err = c.AddCommand(commandBuild); err != nil {
|
||||
g.Log().Fatal(ctx, err)
|
||||
}
|
||||
c.Run(ctx)
|
||||
|
||||
Reference in New Issue
Block a user