agent/session/plugin/cli/command.go (187 lines of code) (raw):

// Copyright (c) 2009-present, Alibaba Cloud All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package cli import ( "fmt" "strings" "github.com/aliyun/aliyun_assist_client/agent/session/plugin/i18n" ) type Command struct { // Command Name Name string // Short is the short description shown in the 'help' output. Short *i18n.Text // Long is the long message shown in the 'help <this-command>' output. Long *i18n.Text // Syntax for usage Usage string // Sample command Sample string // Enable unknown flags EnableUnknownFlag bool // enable suggest distance, // disable -1 // 0: default distance SuggestDistance int // Hidden command Hidden bool // Run, command error will be catch Run func(ctx *Context, args []string) error // Help Help func(ctx *Context, args []string) error // auto compete AutoComplete func(ctx *Context, args []string) []string suggestDistance int parent *Command subCommands []*Command flags *FlagSet } func (c *Command) AddSubCommand(cmd *Command) { cmd.parent = c c.subCommands = append(c.subCommands, cmd) } func (c *Command) Flags() *FlagSet { if c.flags == nil { c.flags = NewFlagSet() } return c.flags } func (c *Command) Execute(ctx *Context, args []string) { // // if completion if ctx.completion != nil { args = ctx.completion.GetArgs() } err := c.executeInner(ctx, args) if err != nil { c.processError(ctx, err) } } func (c *Command) GetSubCommand(s string) *Command { for _, cmd := range c.subCommands { if cmd.Name == s { return cmd } } return nil } func (c *Command) GetSuggestions(s string) []string { sr := NewSuggester(s, c.GetSuggestDistance()) for _, cmd := range c.subCommands { sr.Apply(cmd.Name) } return sr.GetResults() } func (c *Command) GetSuggestDistance() int { if c.SuggestDistance < 0 { return 0 } else if c.SuggestDistance == 0 { return DefaultSuggestDistance } else { return c.SuggestDistance } } func (c *Command) GetUsageWithParent() string { usage := c.Usage for p := c.parent; p != nil; p = p.parent { usage = p.Name + " " + usage } return usage } func (c *Command) ExecuteComplete(ctx *Context, args []string) { if strings.HasPrefix(ctx.completion.Current, "-") { for _, f := range ctx.flags.Flags() { if f.Hidden { continue } if !strings.HasPrefix("--"+f.Name, ctx.completion.Current) { continue } Printf(ctx.Writer(), "--%s\n", f.Name) } } else { for _, sc := range c.subCommands { if sc.Hidden { continue } if !strings.HasPrefix(sc.Name, ctx.completion.Current) { continue } Printf(ctx.Writer(), "%s\n", sc.Name) } } } func (c *Command) executeInner(ctx *Context, args []string) error { // // fmt.Printf(">>> Execute Command: %s args=%v\n", c.Name, args) parser := NewParser(args, ctx) // // get next arg nextArg, _, err := parser.ReadNextArg() if err != nil { return err } // // if next arg is help, run help if nextArg == "help" { ctx.help = true return c.executeInner(ctx, parser.GetRemains()) } // // if next args is not empty, try find sub commands if nextArg != "" { // // if has sub command, run it subCommand := c.GetSubCommand(nextArg) if subCommand != nil { ctx.EnterCommand(subCommand) return subCommand.executeInner(ctx, parser.GetRemains()) } // // no sub command and command.Run == nil // raise error if c.Run == nil { // c.executeHelp(ctx, args, fmt.Errorf("unknown command: %s", nextArg)) return NewInvalidCommandError(nextArg, ctx) } } // cmd is find by args, try run cmd.Run // parse remain args remainArgs, err := parser.ReadAll() if err != nil { return fmt.Errorf("parse failed %s", err) } // // check flags err = ctx.CheckFlags() if err != nil { return err } if HelpFlag(ctx.Flags()).IsAssigned() { ctx.help = true } callArgs := make([]string, 0) if nextArg != "" { callArgs = append(callArgs, nextArg) } for _, s := range remainArgs { if s != "help" { callArgs = append(callArgs, s) } else { ctx.help = true } } if ctx.completion != nil { if c.AutoComplete != nil { ss := c.AutoComplete(ctx, callArgs) for _, s := range ss { Printf(ctx.Writer(), "%s\n", s) } } else { c.ExecuteComplete(ctx, callArgs) } return nil } if ctx.help { c.executeHelp(ctx, callArgs) return nil } else if c.Run == nil { c.executeHelp(ctx, callArgs) return nil } else { return c.Run(ctx, callArgs) } } func (c *Command) processError(ctx *Context, err error) { Errorf(ctx.Stderr(), "ERROR: %s\n", err.Error()) if e, ok := err.(SuggestibleError); ok { PrintSuggestions(ctx, i18n.GetLanguage(), e.GetSuggestions()) Exit(2) return } if e, ok := err.(ErrorWithTip); ok { Noticef(ctx.Stderr(), "\n%s\n", e.GetTip(i18n.GetLanguage())) Exit(3) return } Exit(1) } func (c *Command) executeHelp(ctx *Context, args []string) { if c.Help != nil { err := c.Help(ctx, args) if err != nil { c.processError(ctx, err) } return } c.PrintHead(ctx) c.PrintUsage(ctx) c.PrintSubCommands(ctx) c.PrintFlags(ctx) c.PrintTail(ctx) }