diff --git a/os/gcmd/gcmd_command.go b/os/gcmd/gcmd_command.go index a7d018786..347b8e66d 100644 --- a/os/gcmd/gcmd_command.go +++ b/os/gcmd/gcmd_command.go @@ -28,6 +28,7 @@ type Command struct { Examples string // Usage examples. Additional string // Additional info about this command, which will be appended to the end of help info. Strict bool // Strict parsing options, which means it returns error if invalid option given. + CaseSensitive bool // CaseSensitive parsing options, which means it parses input options in case-sensitive way. Config string // Config node name, which also retrieves the values from config component along with command line. parent *Command // Parent command for internal usage. commands []*Command // Sub commands of this command. diff --git a/os/gcmd/gcmd_command_run.go b/os/gcmd/gcmd_command_run.go index 845900fa8..c267665dc 100644 --- a/os/gcmd/gcmd_command_run.go +++ b/os/gcmd/gcmd_command_run.go @@ -146,7 +146,10 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error) } supportedOptions[optionKey] = !arg.Orphan } - parser, err := Parse(supportedOptions, c.Strict) + parser, err := Parse(supportedOptions, ParserOption{ + CaseSensitive: c.CaseSensitive, + Strict: c.Strict, + }) if err != nil { return nil, err } diff --git a/os/gcmd/gcmd_parser.go b/os/gcmd/gcmd_parser.go index abbb6f251..9ad006b2b 100644 --- a/os/gcmd/gcmd_parser.go +++ b/os/gcmd/gcmd_parser.go @@ -21,9 +21,15 @@ import ( "github.com/gogf/gf/v2/text/gstr" ) +// ParserOption manages the parsing options. +type ParserOption struct { + CaseSensitive bool // Marks options parsing in case-sensitive way. + Strict bool // Whether stops parsing and returns error if invalid option passed. +} + // Parser for arguments. type Parser struct { - strict bool // Whether stops parsing and returns error if invalid option passed. + option ParserOption // Parse option. parsedArgs []string // As name described. parsedOptions map[string]string // As name described. passedOptions map[string]bool // User passed supported options, like: map[string]bool{"name,n":true} @@ -47,7 +53,7 @@ func ParserFromCtx(ctx context.Context) *Parser { // the value item of `supportedOptions` indicates whether corresponding option name needs argument or not. // // 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) { +func Parse(supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) { if supportedOptions == nil { command.Init(os.Args...) return &Parser{ @@ -55,7 +61,7 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) { parsedOptions: GetOptAll(), }, nil } - return ParseArgs(os.Args, supportedOptions, strict...) + return ParseArgs(os.Args, supportedOptions, option...) } // ParseArgs creates and returns a new Parser with given arguments and supported options. @@ -64,7 +70,7 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) { // the value item of `supportedOptions` indicates whether corresponding option name needs argument or not. // // The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed. -func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool) (*Parser, error) { +func ParseArgs(args []string, supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) { if supportedOptions == nil { command.Init(args...) return &Parser{ @@ -72,12 +78,12 @@ func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool) parsedOptions: GetOptAll(), }, nil } - strictParsing := false - if len(strict) > 0 { - strictParsing = strict[0] + var parserOption ParserOption + if len(option) > 0 { + parserOption = option[0] } parser := &Parser{ - strict: strictParsing, + option: parserOption, parsedArgs: make([]string, 0), parsedOptions: make(map[string]string), passedOptions: supportedOptions, @@ -118,7 +124,7 @@ func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool) } i++ continue - } else if parser.strict { + } else if parser.option.Strict { return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid option '%s'`, args[i]) } } @@ -159,8 +165,18 @@ func (p *Parser) parseOption(argument string) string { } func (p *Parser) isOptionValid(name string) bool { - _, ok := p.supportedOptions[name] - return ok + // Case-Sensitive. + if p.option.CaseSensitive { + _, ok := p.supportedOptions[name] + return ok + } + // Case-InSensitive. + for optionName, _ := range p.supportedOptions { + if gstr.Equal(optionName, name) { + return true + } + } + return false } func (p *Parser) isOptionNeedArgument(name string) bool { diff --git a/os/gcmd/gcmd_z_unit_feature_object3_test.go b/os/gcmd/gcmd_z_unit_feature_object3_test.go new file mode 100644 index 000000000..e388f6fd0 --- /dev/null +++ b/os/gcmd/gcmd_z_unit_feature_object3_test.go @@ -0,0 +1,50 @@ +// 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_test + +import ( + "context" + "os" + "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 TestParamsCase struct { + g.Meta `name:"root" root:"root"` +} + +type TestParamsCaseRootInput struct { + g.Meta `name:"root"` + Name string +} +type TestParamsCaseRootOutput struct { + Content string +} + +func (c *TestParamsCase) Root(ctx context.Context, in TestParamsCaseRootInput) (out *TestParamsCaseRootOutput, err error) { + out = &TestParamsCaseRootOutput{ + Content: in.Name, + } + return +} + +func Test_Command_ParamsCase(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ctx = gctx.New() + cmd, err := gcmd.NewFromObject(TestParamsCase{}) + t.AssertNil(err) + + os.Args = []string{"root", "-name=john"} + value, err := cmd.RunWithValueError(ctx) + t.AssertNil(err) + t.Assert(value, `{"Content":"john"}`) + }) +}