Skip to content

Commit 7bfcdb5

Browse files
author
William Kennedy
committed
Added cobra example for cli tooling.
1 parent 3bbefe6 commit 7bfcdb5

File tree

7 files changed

+245
-1
lines changed

7 files changed

+245
-1
lines changed

courses/hardcorego/tooling/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ This is a class for any intermediate-level developer who has some experience wit
1212
[Memory Trace](../../../topics/memory_trace/README.md) |
1313
[Scheduler Trace](../../../topics/sched_trace/README.md) |
1414
[Stack Traces](../../../topics/stack_trace/README.md)
15+
16+
#### Command Line Interfaces
17+
[Cobra](../../../topics/cli/cobra/README.md)
1518
___
1619
All material is licensed under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0).

topics/cli/TODO

-1
This file was deleted.

topics/cli/cobra/README.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## Cobra
2+
3+
Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. Cobra is also an application that will generate your application scaffolding to rapidly develop a Cobra-based application.
4+
5+
## Notes
6+
7+
* Easy subcommand-based CLIs: app server, app fetch, etc.
8+
* Fully POSIX-compliant flags (including short & long versions)
9+
* Nested subcommands
10+
* Global, local and cascading flags
11+
* Easy generation of applications & commands with cobra create appname & cobra add cmdname
12+
* Intelligent suggestions (app srver... did you mean app server?)
13+
* Automatic help generation for commands and flags
14+
* Automatic detailed help for app help [command]
15+
* Automatic help flag recognition of -h, --help, etc.
16+
* Automatically generated bash autocomplete for your application
17+
* Automatically generated man pages for your application
18+
* Command aliases so you can change things without breaking them
19+
* The flexibilty to define your own help, usage, etc.
20+
* Optional tight integration with viper for 12-factor apps
21+
22+
## Links
23+
24+
https://github.com/spf13/cobra
25+
26+
http://spf13.com/post/announcing-cobra/
27+
28+
## Code Review
29+
30+
[main](main.go)
31+
32+
[commands](cmduser/commands.go)
33+
34+
[create command](cmduser/create.go)
35+
36+
## Exercises
37+
38+
### Exercise 1
39+
40+
Add a new user command called get to retrieve a user record by email. For now reuse the User type and create a value and return some fake data. Then display the user value in the terminal. The purpose of the exercise it to wire up a new command. Use the create command as your template.
41+
42+
[Answer](exercises/exercise1/exercise1.go)
43+
___
44+
All material is licensed under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/LICENSE-2.0).

topics/cli/cobra/cmduser/commands.go

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cmduser
2+
3+
import "github.com/spf13/cobra"
4+
5+
// userCmd represents the parent for all user cli commands.
6+
var userCmd = &cobra.Command{
7+
Use: "user",
8+
Short: "user provides a shelf CLI for managing user records.",
9+
}
10+
11+
// GetCommands returns the user commands.
12+
func GetCommands() *cobra.Command {
13+
// TODO: Add all the commands here.
14+
addCreate()
15+
16+
return userCmd
17+
}

topics/cli/cobra/cmduser/create.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package cmduser
2+
3+
import (
4+
"errors"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var createLong = `Use create to add a new user to the system. The user email
10+
must be unique for every user.
11+
12+
Example:
13+
./shelf user create -n "Bill Kennedy" -e "[email protected]" -p "yefc*7fdf92"
14+
`
15+
16+
// create contains the state for this command.
17+
var create struct {
18+
name string
19+
pass string
20+
email string
21+
}
22+
23+
// addCreate handles the creation of users.
24+
func addCreate() {
25+
cmd := &cobra.Command{
26+
Use: "create",
27+
Short: "Add a new user to the system.",
28+
Long: createLong,
29+
Run: runCreate,
30+
}
31+
32+
cmd.Flags().StringVarP(&create.name, "name", "n", "", "Full name for the user.")
33+
cmd.Flags().StringVarP(&create.email, "email", "e", "", "Email for the user.")
34+
cmd.Flags().StringVarP(&create.pass, "pass", "p", "", "Password for the user.")
35+
36+
userCmd.AddCommand(cmd)
37+
}
38+
39+
// runCreate is the code that implements the create command.
40+
func runCreate(cmd *cobra.Command, args []string) {
41+
cmd.Printf("Creating User : Name[%s] Email[%s] Pass[%s]\n", create.name, create.email, create.pass)
42+
43+
if create.name == "" && create.email == "" && create.pass == "" {
44+
cmd.Help()
45+
return
46+
}
47+
48+
u := User{
49+
Status: 1,
50+
Name: "Bill",
51+
52+
Password: "my passoword",
53+
}
54+
55+
if err := createUser(&u); err != nil {
56+
cmd.Println("Creating User : ", err)
57+
return
58+
}
59+
60+
cmd.Println("Creating User : Created")
61+
}
62+
63+
//==============================================================================
64+
65+
// User represents a sample user model.
66+
type User struct {
67+
Status int
68+
Name string
69+
Email string
70+
Password string
71+
}
72+
73+
// createUser is a sample function to simulate a user creation.
74+
func createUser(u *User) error {
75+
if u.Status == 0 {
76+
return errors.New("Invalid user value")
77+
}
78+
79+
return nil
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package cmduser
2+
3+
import (
4+
"encoding/json"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var getLong = `Use get to retrieve a user from the system.
10+
11+
Example:
12+
./shelf user get -e "[email protected]"
13+
`
14+
15+
// get contains the state for this command.
16+
var get struct {
17+
email string
18+
}
19+
20+
// addCreate handles the creation of users.
21+
func addCreate() {
22+
cmd := &cobra.Command{
23+
Use: "get",
24+
Short: "Get retrieve a user from the system.",
25+
Long: getLong,
26+
Run: runGet,
27+
}
28+
29+
cmd.Flags().StringVarP(&get.email, "email", "e", "", "Email for the user.")
30+
31+
// THIS WILL BE AVAILABLE WHEN IN THE SAME PACKAGE.
32+
//userCmd.AddCommand(cmd)
33+
}
34+
35+
// runGet is the code that implements the create command.
36+
func runGet(cmd *cobra.Command, args []string) {
37+
cmd.Printf("Getting User : Email[%s]\n", get.email)
38+
39+
if get.email == "" {
40+
cmd.Help()
41+
return
42+
}
43+
44+
u, err := getUser(get.email)
45+
if err != nil {
46+
cmd.Println("Getting User : ", err)
47+
return
48+
}
49+
50+
data, err := json.MarshalIndent(&u, "", " ")
51+
if err != nil {
52+
cmd.Println("Getting User : ", err)
53+
return
54+
}
55+
56+
cmd.Printf("\n%s\n\n", string(data))
57+
}
58+
59+
//==============================================================================
60+
61+
// User represents a sample user model.
62+
// NEED THIS FOR THE EXERCISE TO BUILD.
63+
type User struct {
64+
Status int
65+
Name string
66+
Email string
67+
Password string
68+
}
69+
70+
// createUser is a sample function to simulate a user creation.
71+
func getUser(email string) (*User, error) {
72+
u := User{
73+
Status: 1,
74+
Name: "Bill",
75+
76+
Password: "my passoword",
77+
}
78+
79+
return &u, nil
80+
}

topics/cli/cobra/main.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// This program provides a sample building cli tooling.
2+
package main
3+
4+
import (
5+
"github.com/ardanlabs/gotraining/topics/cli/cobra/cmduser"
6+
7+
"github.com/spf13/cobra"
8+
)
9+
10+
var shelf = &cobra.Command{
11+
Use: "binary",
12+
Short: "binary provides what...",
13+
}
14+
15+
func main() {
16+
// TODO: Add more commands here.
17+
shelf.AddCommand(cmduser.GetCommands())
18+
19+
// Execute the program and process the flags.
20+
shelf.Execute()
21+
}

0 commit comments

Comments
 (0)