github.com/GGP1/kure@v0.8.4/commands/it/it.go (about) 1 package it 2 3 import ( 4 "strings" 5 6 "github.com/GGP1/kure/auth" 7 cmdutil "github.com/GGP1/kure/commands" 8 9 "github.com/spf13/cobra" 10 bolt "go.etcd.io/bbolt" 11 ) 12 13 const example = ` 14 * No arguments 15 kure it 16 17 * Command without flags 18 kure it ls 19 20 * Command with flags 21 kure it ls -s -q 22 23 * Only the name 24 kure sample` 25 26 // NewCmd returns a new command. 27 func NewCmd(db *bolt.DB) *cobra.Command { 28 return &cobra.Command{ 29 Use: "it <command|flags|name>", 30 Short: "Execute commands through an interactive prompt", 31 Long: `Interactive prompt. 32 This command behaves depending on the arguments received, it requests the missing information. 33 34 Given Requests 35 command flags and name 36 command and flags name 37 name command and flags`, 38 Example: example, 39 DisableFlagParsing: true, 40 PreRunE: auth.Login(db), 41 RunE: runIt(db), 42 } 43 } 44 45 func runIt(db *bolt.DB) cmdutil.RunEFunc { 46 return func(cmd *cobra.Command, args []string) error { 47 root := cmd.Root() 48 // Get rid of unnecessary information and reset in case we are inside a session 49 defer root.SetUsageTemplate(root.UsageTemplate()) 50 root.SetUsageTemplate(template) 51 52 // We received nothing, request all 53 if len(args) == 0 { 54 arguments, err := requestCommands(db, root, nil) 55 if err != nil { 56 return err 57 } 58 59 return execute(root, arguments) 60 } 61 62 command, _, err := root.Find(args) 63 if err != nil || command == root { 64 // If the command does not exist or is the root, assume the user passed a name 65 arguments, err := gotName(db, root, args) 66 if err != nil { 67 return err 68 } 69 70 return execute(root, arguments) 71 } 72 73 foundFlags := false 74 for _, a := range args { 75 if strings.HasPrefix(a, "-") { 76 foundFlags = true 77 break 78 } 79 } 80 81 if foundFlags { 82 // Got command+flags, do not look for subcommands 83 if err := command.ParseFlags(args); err != nil { 84 return err 85 } 86 87 // Get rid of the command and flags to validate the name 88 argsWoFlags := strings.Join(command.Flags().Args(), " ") 89 name := strings.Replace(argsWoFlags, command.Name(), "", 1) 90 91 // The validation won't fail if the user lists records 92 err := command.ValidateArgs([]string{name}) 93 if err != nil || strings.Contains(command.Name(), "ls") { 94 // Received commands+flags, request name 95 arguments, err := requestName(db, args) 96 if err != nil { 97 return err 98 } 99 100 return execute(root, arguments) 101 } 102 103 // Received command+flags+name, nothing to request 104 return execute(root, args) 105 } 106 107 // Pass on received command(s) and look for subcommands 108 arguments, err := requestCommands(db, command, args) 109 if err != nil { 110 return err 111 } 112 113 return execute(root, arguments) 114 } 115 } 116 117 func execute(root *cobra.Command, args []string) error { 118 // Discard empty arguments as some commands will fail if we don't 119 // eg. file cat 120 filteredArgs := make([]string, 0, len(args)) 121 for _, a := range args { 122 if a != "" { 123 filteredArgs = append(filteredArgs, a) 124 } 125 } 126 127 root.SetArgs(filteredArgs) 128 return root.Execute() 129 } 130 131 func requestCommands(db *bolt.DB, root *cobra.Command, receivedCmds []string) ([]string, error) { 132 commands, err := selectCommands(root) 133 if err != nil { 134 return nil, err 135 } 136 137 flags, err := selectFlags(root, commands) 138 if err != nil { 139 return nil, err 140 } 141 142 args := append(commands, flags...) 143 // Preprend the received commands if there is any 144 // We would have [received commands] [commands] [flags] 145 if len(receivedCmds) > 0 { 146 args = append(receivedCmds, args...) 147 } 148 return requestName(db, args) 149 } 150 151 // args contains commands and flags. 152 func requestName(db *bolt.DB, args []string) ([]string, error) { 153 var ( 154 name string 155 err error 156 ) 157 158 search := strings.Join(args, " ") 159 // contains reports whether s is within search 160 contains := func(s string) bool { 161 return strings.Contains(search, s) 162 } 163 164 // Behave depending on which command the user is executing 165 switch { 166 case contains("add"), 167 contains("ls") && contains("-f"), // Filter 168 contains("rm") && contains("-d"): // Remove directory 169 name, err = inputName() 170 171 case contains("import"), contains("export"): 172 name, err = selectManager(db) 173 174 case contains("file cat"), contains("file touch"): 175 names, err := fileMultiselect(db) 176 if err != nil { 177 return nil, err 178 } 179 return append(args, names...), nil 180 181 case contains("file mv"): 182 names, err := fileMvNames(db) 183 if err != nil { 184 return nil, err 185 } 186 return append(args, names...), nil 187 188 default: 189 list := []string{"2fa", "copy", "edit", "ls", "rm"} 190 // Request the name depending on the command 191 for _, cmd := range list { 192 if contains(cmd) { 193 // Skip "config edit" as it doesn't need a name 194 if args[0] != "config" { 195 name, err = selectName(db, args) 196 break 197 } 198 } 199 } 200 } 201 if err != nil { 202 return nil, err 203 } 204 205 // Remember: the flags are inside the commands slice 206 result := append(args, name) 207 return result, nil 208 } 209 210 // gotName is executed when the user already provided the name, commands and flags are requested only. 211 func gotName(db *bolt.DB, root *cobra.Command, args []string) ([]string, error) { 212 var ( 213 name []string 214 flags []string 215 ) 216 217 for _, a := range args { 218 if strings.HasPrefix(a, "-") { 219 flags = append(flags, a) 220 continue 221 } 222 name = append(name, a) 223 } 224 225 commands, err := selectCommands(root) 226 if err != nil { 227 return nil, err 228 } 229 230 if len(flags) == 0 { 231 flags, err = selectFlags(root, commands) 232 if err != nil { 233 return nil, err 234 } 235 } 236 237 if len(name) == 0 { 238 name, err = requestName(db, commands) 239 if err != nil { 240 return nil, err 241 } 242 } 243 244 result := append(commands, flags...) 245 result = append(result, name...) 246 247 return result, nil 248 }