LEFT | RIGHT |
1 package cmd | 1 package cmd |
2 | 2 |
3 import ( | 3 import ( |
4 "fmt" | 4 "fmt" |
5 "launchpad.net/gnuflag" | 5 "launchpad.net/gnuflag" |
6 "launchpad.net/juju/go/log" | |
7 "os" | |
8 "strings" | |
9 ) | 6 ) |
10 | 7 |
11 // Info holds everything necessary to describe a Command's intent and usage. | 8 // Info holds everything necessary to describe a Command's intent and usage. |
12 type Info struct { | 9 type Info struct { |
13 // Name is the Command's name. | 10 // Name is the Command's name. |
14 Name string | 11 Name string |
15 | 12 |
16 // Args describes the command's expected arguments. | 13 // Args describes the command's expected arguments. |
17 Args string | 14 Args string |
18 | 15 |
19 // Purpose is a short explanation of the Command's purpose. | 16 // Purpose is a short explanation of the Command's purpose. |
20 Purpose string | 17 Purpose string |
21 | 18 |
22 // Doc is the long documentation for the Command. | 19 // Doc is the long documentation for the Command. |
23 Doc string | 20 Doc string |
24 | |
25 // Intersperse controls whether the Command will accept interspersed | |
26 // options and positional args. | |
27 Intersperse bool | |
28 } | 21 } |
29 | 22 |
30 // Usage combines Name and Args to describe the Command's intended usage. | 23 // Usage combines Name and Args to describe the Command's intended usage. |
31 func (i *Info) Usage() string { | 24 func (i *Info) Usage() string { |
| 25 if i.Args == "" { |
| 26 return i.Name |
| 27 } |
32 return fmt.Sprintf("%s %s", i.Name, i.Args) | 28 return fmt.Sprintf("%s %s", i.Name, i.Args) |
33 } | 29 } |
34 | 30 |
35 // Command is implemented by types that interpret any command-line arguments | 31 // Command is implemented by types that interpret command-line arguments. |
36 // passed to the "juju" command. | |
37 type Command interface { | 32 type Command interface { |
38 » // Info returns information about the command. | 33 » // Info returns information about the Command. |
39 Info() *Info | 34 Info() *Info |
40 | 35 |
41 » // InitFlagSet prepares a FlagSet such that Parsing that FlagSet will | 36 » // Init initializes the Command before running. The command may add opti
ons |
42 » // initialize the Command's options. | 37 » // to f before processing args. |
43 » InitFlagSet(f *gnuflag.FlagSet) | 38 » Init(f *gnuflag.FlagSet, args []string) error |
44 | 39 |
45 » // ParsePositional is called by Parse to allow the Command to handle | 40 » // Run will execute the Command as directed by the options and positiona
l |
46 » // positional command-line arguments. | 41 » // arguments passed to Init. |
47 » ParsePositional(args []string) error | 42 » Run(ctx *Context) error |
48 | |
49 » // Run will execute the command according to the options and positional | |
50 » // arguments interpreted by a call to Parse. | |
51 » Run() error | |
52 } | |
53 | |
54 // NewFlagSet returns a FlagSet initialized for use with c. | |
55 func NewFlagSet(c Command) *gnuflag.FlagSet { | |
56 » f := gnuflag.NewFlagSet(c.Info().Name, gnuflag.ExitOnError) | |
57 » f.Usage = func() { PrintUsage(c) } | |
58 » c.InitFlagSet(f) | |
59 » return f | |
60 } | |
61 | |
62 // PrintUsage prints usage information for c to stderr. | |
63 func PrintUsage(c Command) { | |
64 » i := c.Info() | |
65 » fmt.Fprintf(os.Stderr, "usage: %s\n", i.Usage()) | |
66 » fmt.Fprintf(os.Stderr, "purpose: %s\n", i.Purpose) | |
67 » fmt.Fprintf(os.Stderr, "\noptions:\n") | |
68 » NewFlagSet(c).PrintDefaults() | |
69 » if i.Doc != "" { | |
70 » » fmt.Fprintf(os.Stderr, "\n%s\n", strings.TrimSpace(i.Doc)) | |
71 » } | |
72 } | |
73 | |
74 // Parse parses args on c. This must be called before c is Run. | |
75 func Parse(c Command, args []string) error { | |
76 » f := NewFlagSet(c) | |
77 » if err := f.Parse(c.Info().Intersperse, args); err != nil { | |
78 » » return err | |
79 » } | |
80 » return c.ParsePositional(f.Args()) | |
81 } | 43 } |
82 | 44 |
83 // CheckEmpty is a utility function that returns an error if args is not empty. | 45 // CheckEmpty is a utility function that returns an error if args is not empty. |
84 func CheckEmpty(args []string) error { | 46 func CheckEmpty(args []string) error { |
85 if len(args) != 0 { | 47 if len(args) != 0 { |
86 return fmt.Errorf("unrecognised args: %s", args) | 48 return fmt.Errorf("unrecognised args: %s", args) |
87 } | 49 } |
88 return nil | 50 return nil |
89 } | 51 } |
90 | |
91 // Main will Parse and Run a Command, and exit appropriately. | |
92 func Main(c Command, args []string) { | |
93 if err := Parse(c, args[1:]); err != nil { | |
94 fmt.Fprintf(os.Stderr, "%v\n", err) | |
95 PrintUsage(c) | |
96 os.Exit(2) | |
97 } | |
98 if err := c.Run(); err != nil { | |
99 log.Debugf("%s command failed: %s\n", c.Info().Name, err) | |
100 fmt.Fprintf(os.Stderr, "%v\n", err) | |
101 os.Exit(1) | |
102 } | |
103 os.Exit(0) | |
104 } | |
LEFT | RIGHT |