cmd, lib
[arvados.git] / cmd / dispatch.go
1 package cmd
2
3 import (
4         "flag"
5         "fmt"
6         "os"
7         "sort"
8
9         "git.curoverse.com/arvados.git/sdk/go/config"
10 )
11
12 // A Command is a subcommand that can be invoked by Dispatch.
13 type Command interface {
14         DefaultConfigFile() string
15         ParseFlags([]string) error
16         Run() error
17 }
18
19 // Dispatch parses flags from args, chooses an entry in cmds using the
20 // next argument after the parsed flags, loads the command's
21 // configuration file if it exists, passes any additional flags to the
22 // command's ParseFlags method, and -- if all of those steps complete
23 // without errors -- runs the command.
24 func Dispatch(cmds map[string]Command, prog string, args []string) error {
25         fs := flag.NewFlagSet(prog, flag.ContinueOnError)
26         err := fs.Parse(args)
27         if err != nil {
28                 return err
29         }
30
31         subcmd := fs.Arg(0)
32         cmd, ok := cmds[subcmd]
33         if !ok {
34                 if subcmd != "" && subcmd != "help" {
35                         return fmt.Errorf("unrecognized subcommand %q", subcmd)
36                 }
37                 var subcmds []string
38                 for s := range cmds {
39                         subcmds = append(subcmds, s)
40                 }
41                 sort.Sort(sort.StringSlice(subcmds))
42                 return fmt.Errorf("available subcommands: %q", subcmds)
43         }
44
45         err = config.LoadFile(cmd, cmd.DefaultConfigFile())
46         if err != nil && !os.IsNotExist(err) {
47                 return err
48         }
49         if fs.NArg() > 1 {
50                 args = fs.Args()[1:]
51         } else {
52                 args = nil
53         }
54         err = cmd.ParseFlags(args)
55         if err != nil {
56                 return err
57         }
58         return cmd.Run()
59 }