diff --git a/cmd/gf/gfcmd/gfcmd.go b/cmd/gf/gfcmd/gfcmd.go index 9869e6ae5db..4a8dd0622f7 100644 --- a/cmd/gf/gfcmd/gfcmd.go +++ b/cmd/gf/gfcmd/gfcmd.go @@ -73,7 +73,7 @@ func (c *Command) Run(ctx context.Context) { func GetCommand(ctx context.Context) (*Command, error) { root, err := gcmd.NewFromObject(cmd.GF) if err != nil { - panic(err) + return nil, err } err = root.AddObject( cmd.Up, diff --git a/os/gcmd/gcmd_command.go b/os/gcmd/gcmd_command.go index 557a7531c82..ce05820602d 100644 --- a/os/gcmd/gcmd_command.go +++ b/os/gcmd/gcmd_command.go @@ -24,14 +24,18 @@ type Command struct { Arguments []Argument // Argument array, configuring how this command act. Func Function // Custom function. FuncWithValue FuncWithValue // Custom function with output parameters that can interact with command caller. - HelpFunc Function // Custom help function + HelpFunc Function // Custom help function. 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. + internalCommandAttributes +} + +type internalCommandAttributes struct { + 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. diff --git a/os/gcmd/gcmd_command_run.go b/os/gcmd/gcmd_command_run.go index 13cde00505a..1f4c4bd063c 100644 --- a/os/gcmd/gcmd_command_run.go +++ b/os/gcmd/gcmd_command_run.go @@ -85,13 +85,15 @@ func (c *Command) RunWithSpecificArgs(ctx context.Context, args []string) (value return nil, err } parsedArgs := parser.GetArgAll() - if len(parsedArgs) == 1 { - return c.doRun(ctx, args, parser) - } // Exclude the root binary name. parsedArgs = parsedArgs[1:] + // If no args or no sub command, it runs standalone. + if len(parsedArgs) == 0 || len(c.commands) == 0 { + return c.doRun(ctx, args, parser) + } + // Find the matched command and run it. // It here `fromArgIndex` set to 1 to calculate the argument index in to `newCtx`. lastCmd, foundCmd, newCtx := c.searchCommand(ctx, parsedArgs, 1) @@ -129,6 +131,7 @@ func (c *Command) doRun(ctx context.Context, args []string, parser *Parser) (val } return nil, c.defaultHelpFunc(ctx, parser) } + // OpenTelemetry for command. var ( span trace.Span diff --git a/os/gcmd/gcmd_z_unit_issue_test.go b/os/gcmd/gcmd_z_unit_issue_test.go index fd4b5c790a0..2db62bd65ca 100644 --- a/os/gcmd/gcmd_z_unit_issue_test.go +++ b/os/gcmd/gcmd_z_unit_issue_test.go @@ -305,3 +305,26 @@ func Test_Issue3670(t *testing.T) { t.Assert(value.(*Issue3670LastOutput).Content, `{"Country":"china","Singer":"邓丽君"}`) }) } + +func Test_Issue3701(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + var ( + outputArgs []string + inputArgs = []string{"abc", "def"} + ctx = gctx.New() + cmd = gcmd.Command{ + Name: "main", + Usage: "main", + Brief: "...", + Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { + outputArgs = parser.GetArgAll() + return nil + }, + } + ) + + _, err := cmd.RunWithSpecificArgs(ctx, inputArgs) + t.AssertNil(err) + t.Assert(outputArgs, inputArgs) + }) +}