args.go (4078B)
1 // Copyright 2013-2023 The Cobra Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cobra 16 17 import ( 18 "fmt" 19 "strings" 20 ) 21 22 type PositionalArgs func(cmd *Command, args []string) error 23 24 // legacyArgs validation has the following behaviour: 25 // - root commands with no subcommands can take arbitrary arguments 26 // - root commands with subcommands will do subcommand validity checking 27 // - subcommands will always accept arbitrary arguments 28 func legacyArgs(cmd *Command, args []string) error { 29 // no subcommand, always take args 30 if !cmd.HasSubCommands() { 31 return nil 32 } 33 34 // root command with subcommands, do subcommand checking. 35 if !cmd.HasParent() && len(args) > 0 { 36 return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0])) 37 } 38 return nil 39 } 40 41 // NoArgs returns an error if any args are included. 42 func NoArgs(cmd *Command, args []string) error { 43 if len(args) > 0 { 44 return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath()) 45 } 46 return nil 47 } 48 49 // OnlyValidArgs returns an error if there are any positional args that are not in 50 // the `ValidArgs` field of `Command` 51 func OnlyValidArgs(cmd *Command, args []string) error { 52 if len(cmd.ValidArgs) > 0 { 53 // Remove any description that may be included in ValidArgs. 54 // A description is following a tab character. 55 var validArgs []string 56 for _, v := range cmd.ValidArgs { 57 validArgs = append(validArgs, strings.Split(v, "\t")[0]) 58 } 59 for _, v := range args { 60 if !stringInSlice(v, validArgs) { 61 return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0])) 62 } 63 } 64 } 65 return nil 66 } 67 68 // ArbitraryArgs never returns an error. 69 func ArbitraryArgs(cmd *Command, args []string) error { 70 return nil 71 } 72 73 // MinimumNArgs returns an error if there is not at least N args. 74 func MinimumNArgs(n int) PositionalArgs { 75 return func(cmd *Command, args []string) error { 76 if len(args) < n { 77 return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args)) 78 } 79 return nil 80 } 81 } 82 83 // MaximumNArgs returns an error if there are more than N args. 84 func MaximumNArgs(n int) PositionalArgs { 85 return func(cmd *Command, args []string) error { 86 if len(args) > n { 87 return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args)) 88 } 89 return nil 90 } 91 } 92 93 // ExactArgs returns an error if there are not exactly n args. 94 func ExactArgs(n int) PositionalArgs { 95 return func(cmd *Command, args []string) error { 96 if len(args) != n { 97 return fmt.Errorf("accepts %d arg(s), received %d", n, len(args)) 98 } 99 return nil 100 } 101 } 102 103 // RangeArgs returns an error if the number of args is not within the expected range. 104 func RangeArgs(min int, max int) PositionalArgs { 105 return func(cmd *Command, args []string) error { 106 if len(args) < min || len(args) > max { 107 return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args)) 108 } 109 return nil 110 } 111 } 112 113 // MatchAll allows combining several PositionalArgs to work in concert. 114 func MatchAll(pargs ...PositionalArgs) PositionalArgs { 115 return func(cmd *Command, args []string) error { 116 for _, parg := range pargs { 117 if err := parg(cmd, args); err != nil { 118 return err 119 } 120 } 121 return nil 122 } 123 } 124 125 // ExactValidArgs returns an error if there are not exactly N positional args OR 126 // there are any positional args that are not in the `ValidArgs` field of `Command` 127 // 128 // Deprecated: use MatchAll(ExactArgs(n), OnlyValidArgs) instead 129 func ExactValidArgs(n int) PositionalArgs { 130 return MatchAll(ExactArgs(n), OnlyValidArgs) 131 }