~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/govmomi/govc/cli/command.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright (c) 2014 VMware, Inc. All Rights Reserved.
 
3
 
 
4
Licensed under the Apache License, Version 2.0 (the "License");
 
5
you may not use this file except in compliance with the License.
 
6
You may obtain a copy of the License at
 
7
 
 
8
    http://www.apache.org/licenses/LICENSE-2.0
 
9
 
 
10
Unless required by applicable law or agreed to in writing, software
 
11
distributed under the License is distributed on an "AS IS" BASIS,
 
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
See the License for the specific language governing permissions and
 
14
limitations under the License.
 
15
*/
 
16
 
 
17
package cli
 
18
 
 
19
import (
 
20
        "flag"
 
21
        "fmt"
 
22
        "io/ioutil"
 
23
        "os"
 
24
        "reflect"
 
25
        "sort"
 
26
        "text/tabwriter"
 
27
)
 
28
 
 
29
type HasFlags interface {
 
30
        // Register may be called more than once and should be idempotent.
 
31
        Register(f *flag.FlagSet)
 
32
 
 
33
        // Process may be called more than once and should be idempotent.
 
34
        Process() error
 
35
}
 
36
 
 
37
type Command interface {
 
38
        HasFlags
 
39
 
 
40
        Run(f *flag.FlagSet) error
 
41
}
 
42
 
 
43
var hasFlagsType = reflect.TypeOf((*HasFlags)(nil)).Elem()
 
44
 
 
45
func RegisterCommand(h HasFlags, f *flag.FlagSet) {
 
46
        visited := make(map[interface{}]struct{})
 
47
        Walk(h, hasFlagsType, func(v interface{}) error {
 
48
                if _, ok := visited[v]; ok {
 
49
                        return nil
 
50
                }
 
51
                visited[v] = struct{}{}
 
52
                v.(HasFlags).Register(f)
 
53
                return nil
 
54
        })
 
55
}
 
56
 
 
57
func ProcessCommand(h HasFlags) error {
 
58
        visited := make(map[interface{}]struct{})
 
59
        err := Walk(h, hasFlagsType, func(v interface{}) error {
 
60
                if _, ok := visited[v]; ok {
 
61
                        return nil
 
62
                }
 
63
                visited[v] = struct{}{}
 
64
                err := v.(HasFlags).Process()
 
65
                return err
 
66
        })
 
67
        return err
 
68
}
 
69
 
 
70
func generalHelp() {
 
71
        fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
 
72
 
 
73
        cmds := []string{}
 
74
        for name := range commands {
 
75
                cmds = append(cmds, name)
 
76
        }
 
77
 
 
78
        sort.Strings(cmds)
 
79
 
 
80
        for _, name := range cmds {
 
81
                fmt.Fprintf(os.Stderr, "  %s\n", name)
 
82
        }
 
83
}
 
84
 
 
85
func commandHelp(name string, cmd Command, f *flag.FlagSet) {
 
86
        type HasUsage interface {
 
87
                Usage() string
 
88
        }
 
89
 
 
90
        fmt.Fprintf(os.Stderr, "Usage: %s %s [OPTIONS]", os.Args[0], name)
 
91
        if u, ok := cmd.(HasUsage); ok {
 
92
                fmt.Fprintf(os.Stderr, " %s", u.Usage())
 
93
        }
 
94
        fmt.Fprintf(os.Stderr, "\n")
 
95
 
 
96
        type HasDescription interface {
 
97
                Description() string
 
98
        }
 
99
 
 
100
        if u, ok := cmd.(HasDescription); ok {
 
101
                fmt.Fprintf(os.Stderr, "%s\n", u.Description())
 
102
        }
 
103
 
 
104
        n := 0
 
105
        f.VisitAll(func(_ *flag.Flag) {
 
106
                n += 1
 
107
        })
 
108
 
 
109
        if n > 0 {
 
110
                fmt.Fprintf(os.Stderr, "\nOptions:\n")
 
111
                tw := tabwriter.NewWriter(os.Stderr, 2, 0, 2, ' ', 0)
 
112
                f.VisitAll(func(f *flag.Flag) {
 
113
                        fmt.Fprintf(tw, "\t-%s=%s\t%s\n", f.Name, f.DefValue, f.Usage)
 
114
                })
 
115
                tw.Flush()
 
116
        }
 
117
}
 
118
 
 
119
func Run(args []string) int {
 
120
        if len(args) == 0 {
 
121
                generalHelp()
 
122
                return 1
 
123
        }
 
124
 
 
125
        // Look up real command name in aliases table.
 
126
        name, ok := aliases[args[0]]
 
127
        if !ok {
 
128
                name = args[0]
 
129
        }
 
130
 
 
131
        cmd, ok := commands[name]
 
132
        if !ok {
 
133
                generalHelp()
 
134
                return 1
 
135
        }
 
136
 
 
137
        f := flag.NewFlagSet("", flag.ContinueOnError)
 
138
        f.SetOutput(ioutil.Discard)
 
139
 
 
140
        RegisterCommand(cmd, f)
 
141
 
 
142
        if err := f.Parse(args[1:]); err != nil {
 
143
                if err == flag.ErrHelp {
 
144
                        commandHelp(args[0], cmd, f)
 
145
                } else {
 
146
                        fmt.Fprintf(os.Stderr, "Error: %s\n", err)
 
147
                }
 
148
                return 1
 
149
        }
 
150
 
 
151
        if err := ProcessCommand(cmd); err != nil {
 
152
                if err == flag.ErrHelp {
 
153
                        commandHelp(args[0], cmd, f)
 
154
                } else {
 
155
                        fmt.Fprintf(os.Stderr, "Error: %s\n", err)
 
156
                }
 
157
                return 1
 
158
        }
 
159
 
 
160
        if err := cmd.Run(f); err != nil {
 
161
                if err == flag.ErrHelp {
 
162
                        commandHelp(args[0], cmd, f)
 
163
                } else {
 
164
                        fmt.Fprintf(os.Stderr, "Error: %s\n", err)
 
165
                }
 
166
                return 1
 
167
        }
 
168
 
 
169
        return 0
 
170
}