Skip to content

Commit a571d23

Browse files
committed
update
0 parents  commit a571d23

File tree

4 files changed

+310
-0
lines changed

4 files changed

+310
-0
lines changed

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# cmd
2+
a very simple command lib
3+
4+
### main
5+
```go
6+
package main
7+
8+
import (
9+
"flag"
10+
11+
"github.com/webpkg/cmd"
12+
)
13+
14+
var (
15+
_webForce = false
16+
)
17+
18+
func main() {
19+
20+
cmd.SetFlags(func(f *flag.FlagSet) {
21+
f.BoolVar(&_webForce, "force", false, "")
22+
})
23+
24+
cmd.AddCommands(cmdVersion)
25+
cmd.Execute()
26+
}
27+
28+
```
29+
30+
### cmdVersion
31+
```go
32+
package main
33+
34+
import (
35+
"fmt"
36+
37+
"github.com/webpkg/cmd"
38+
)
39+
40+
var (
41+
_version = "v0.0.1"
42+
_osarch string // set by ldflags
43+
44+
cmdVersion = &cmd.Command{
45+
Run: runVersion,
46+
UsageLine: "version",
47+
Short: "display version",
48+
Long: "display version and build info.\n",
49+
}
50+
)
51+
52+
func runVersion(cmd *cmd.Command, args []string) {
53+
fmt.Println(_version, _osarch)
54+
}
55+
56+
```

cmd.go

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
package cmd
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"fmt"
7+
"io"
8+
"log"
9+
"os"
10+
"sort"
11+
"strings"
12+
"sync"
13+
"text/template"
14+
"unicode"
15+
"unicode/utf8"
16+
)
17+
18+
var (
19+
_usageTemplate = `[webgo] is a web service base on web.go
20+
Usage:
21+
[webgo] command [arguments]
22+
23+
The commands are:
24+
{{range .}}{{if .Runnable}}
25+
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
26+
27+
Use "[webgo] help [command]" for more information about a command.
28+
`
29+
30+
_commands = Commands{}
31+
_exitMu sync.Mutex
32+
_exitStatus = 0
33+
_setFlags func(f *flag.FlagSet)
34+
)
35+
36+
// SetUsageTemplate set value to usageTemplate
37+
func SetUsageTemplate(usageTemplate string) {
38+
_usageTemplate = usageTemplate
39+
}
40+
41+
// SetFlags set flags to all commands
42+
func SetFlags(f func(f *flag.FlagSet)) {
43+
_setFlags = f
44+
}
45+
46+
// AddCommands Add Command.
47+
func AddCommands(cmds ...*Command) {
48+
_commands = append(_commands, cmds...)
49+
}
50+
51+
// getCommand get Command by name.
52+
func getCommand(name string) (*Command, error) {
53+
if len(_commands) == 0 {
54+
return nil, fmt.Errorf("no commands")
55+
}
56+
57+
cmd := _commands.Search(name)
58+
59+
if cmd == nil {
60+
return nil, fmt.Errorf("unknown sub command %q", name)
61+
}
62+
63+
return cmd, nil
64+
}
65+
66+
// Execute func
67+
func Execute() {
68+
flag.Usage = usage
69+
flag.Parse() // catch -h argument
70+
log.SetFlags(0)
71+
72+
args := flag.Args()
73+
74+
if len(args) < 1 {
75+
usage()
76+
}
77+
78+
if args[0] == "help" {
79+
help(args[1:])
80+
return
81+
}
82+
83+
name := args[0]
84+
cmd, err := getCommand(name)
85+
86+
if err != nil {
87+
fatalf("cmd(%s): %v \n", name, err)
88+
}
89+
90+
addFlags(&cmd.Flag)
91+
cmd.Flag.Usage = func() { cmd.Usage() }
92+
cmd.Flag.Parse(args[1:])
93+
94+
if err := cmd.Run(cmd, cmd.Flag.Args()); err != nil {
95+
logf("cmd(%s): %v\n", name, err)
96+
}
97+
98+
exit()
99+
}
100+
101+
// Command struct
102+
type Command struct {
103+
Run func(cmd *Command, args []string) error
104+
Flag flag.FlagSet
105+
UsageLine string
106+
Short string
107+
Long string
108+
}
109+
110+
// Name string
111+
func (c *Command) Name() string {
112+
name := c.UsageLine
113+
i := strings.IndexRune(name, ' ')
114+
if i >= 0 {
115+
name = name[:i]
116+
}
117+
return name
118+
}
119+
120+
// Usage u
121+
func (c *Command) Usage() {
122+
help([]string{c.Name()})
123+
os.Exit(2)
124+
}
125+
126+
// Runnable bool
127+
func (c *Command) Runnable() bool {
128+
return c.Run != nil
129+
}
130+
131+
type Commands []*Command
132+
133+
// Search use binary search to find and return the smallest index *Command
134+
func (c *Commands) Search(name string) *Command {
135+
136+
i := sort.Search(len(*c), func(i int) bool { return (*c)[i].Name() >= name })
137+
138+
if i < len(*c) && (*c)[i].Name() == name {
139+
return (*c)[i]
140+
}
141+
142+
return nil
143+
}
144+
145+
func usage() {
146+
printUsage(os.Stderr)
147+
os.Exit(2)
148+
}
149+
150+
func printUsage(w io.Writer) {
151+
bw := bufio.NewWriter(w)
152+
runTemplate(bw, _usageTemplate, _commands)
153+
bw.Flush()
154+
}
155+
156+
type errWriter struct {
157+
w io.Writer
158+
err error
159+
}
160+
161+
func (w *errWriter) Write(b []byte) (int, error) {
162+
n, err := w.w.Write(b)
163+
if err != nil {
164+
w.err = err
165+
}
166+
return n, err
167+
}
168+
169+
func capitalize(s string) string {
170+
if s == "" {
171+
return s
172+
}
173+
r, n := utf8.DecodeRuneInString(s)
174+
return string(unicode.ToTitle(r)) + s[n:]
175+
}
176+
177+
func runTemplate(w io.Writer, text string, data interface{}) {
178+
t := template.New("top")
179+
t.Funcs(template.FuncMap{
180+
"trim": strings.TrimSpace,
181+
"capitalize": capitalize,
182+
})
183+
template.Must(t.Parse(text))
184+
ew := &errWriter{w: w}
185+
err := t.Execute(ew, data)
186+
if ew.err != nil {
187+
if strings.Contains(ew.err.Error(), "pipe") {
188+
os.Exit(1)
189+
}
190+
fatalf("writing output: %v", ew.err)
191+
}
192+
if err != nil {
193+
panic(err)
194+
}
195+
}
196+
197+
func help(args []string) {
198+
if len(args) == 0 {
199+
printUsage(os.Stdout)
200+
return
201+
}
202+
if len(args) != 1 {
203+
fatalf("usage: help command\n\nToo many arguments given.\n")
204+
}
205+
206+
name := args[0]
207+
208+
cmd, err := getCommand(name)
209+
210+
if err != nil {
211+
fatalf("help(%s): %v \n", name, err)
212+
}
213+
214+
if cmd.Runnable() {
215+
fmt.Fprintf(os.Stdout, "usage: %s\n", cmd.UsageLine)
216+
}
217+
218+
runTemplate(os.Stdout, cmd.Long, nil)
219+
}
220+
221+
func addFlags(f *flag.FlagSet) {
222+
if _setFlags != nil {
223+
_setFlags(f)
224+
}
225+
}
226+
227+
func logf(format string, v ...interface{}) {
228+
log.Printf(format, v...)
229+
}
230+
231+
func errorf(format string, args ...interface{}) {
232+
logf(format, args...)
233+
setExitStatus(1)
234+
}
235+
236+
func fatalf(format string, args ...interface{}) {
237+
errorf(format, args...)
238+
exit()
239+
}
240+
241+
func setExitStatus(n int) {
242+
_exitMu.Lock()
243+
if _exitStatus < n {
244+
_exitStatus = n
245+
}
246+
_exitMu.Unlock()
247+
}
248+
249+
func exit() {
250+
os.Exit(_exitStatus)
251+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/Wiiiiill/go-cmd
2+
3+
go 1.13

go.sum

Whitespace-only changes.

0 commit comments

Comments
 (0)