-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: Quickly start developing curves based on cobra
Signed-off-by: Liao PengFei <[email protected]>
- Loading branch information
1 parent
9d83a9c
commit f243ad6
Showing
2 changed files
with
516 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
# Curveadm CLI Development | ||
|
||
## Cobra library | ||
|
||
Curveadm CLI is developed based on the [Cobra](https://github.com/spf13/cobra) library, a Go language library for creating CLI command line programs. | ||
|
||
### Basic use of Cobra | ||
|
||
Create a root command using Cobra (print `root command` on the command line): | ||
``` | ||
package main | ||
import ( | ||
"fmt" | ||
"os" | ||
"github.com/spf13/cobra" | ||
) | ||
var rootCmd = &cobra.Command{ | ||
Use: "hugo", | ||
Short: "Hugo is a very fast static site generator", | ||
Long: `A Fast and Flexible Static Site Generator built with | ||
love by spf13 and friends in Go. | ||
Complete documentation is available at https://gohugo.io/documentation/`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Println("root command") | ||
}, | ||
} | ||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
os.Exit(1) | ||
} | ||
} | ||
func main() { | ||
rootCmd.Execute() | ||
} | ||
``` | ||
- Use field sets the name of the command | ||
- Short field sets a short description | ||
- Long field setting detailed description | ||
- The Run field sets the function when executing the command | ||
|
||
For more details on `Command` object fields and usage, see [Cobra library--command.go](https://github.com/spf13/cobra/blob/main/command.go). | ||
|
||
### flag usage | ||
|
||
Cobra supports parsing of custom parameters: | ||
``` | ||
cmd.PersistentFlags().BoolP("help", "h", false, "Print usage") | ||
cmd.Flags().BoolVarP(&options.debug, "debug", "d", false, "Print debug information") | ||
``` | ||
PersistentFlags() is used for global flags and can be used by the current command and its subcommands. | ||
|
||
Flags() is used to define local flags, only for the current command. | ||
|
||
For more details on the `flag` function and usage, see [Cobra library--command.go](https://github.com/spf13/cobra/blob/main/command.go) and [pflag library](https:// github.com/spf13/pflag). | ||
|
||
### hook function | ||
|
||
Cobra's Command object supports custom hook functions (PreRun and PostRun fields), and the hook function is run before and after the `run` command is executed. As follows: | ||
``` | ||
cmd := &cobra.Command{ | ||
Use: "root [sub]", | ||
Short: "My root command", | ||
PersistentPreRun: func(cmd *cobra.Command, args []string) { | ||
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) | ||
}, | ||
PreRun: func(cmd *cobra.Command, args []string) { | ||
fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) | ||
}, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
fmt.Printf("Inside rootCmd Run with args: %v\n", args) | ||
}, | ||
PostRun: func(cmd *cobra.Command, args []string) { | ||
fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) | ||
}, | ||
PersistentPostRun: func(cmd *cobra.Command, args []string) { | ||
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) | ||
}, | ||
} | ||
``` | ||
The hook function will be executed in the order of (`PersistentPreRun`, `PreRun`, `Run`, `PostRun`, `PersistentPostRun`). Note: If the subcommand does not set `Persistent*Run`, it will automatically inherit the function definition of the parent command. | ||
|
||
### Subcommands | ||
cobra allows nested commands, through the `AddCommand` function of the current command object. As follows: | ||
``` | ||
rootCmd.AddCommand(versionCmd) | ||
``` | ||
The recommended hierarchical command nesting structure is as follows: | ||
``` | ||
├── cmd | ||
│ ├── root.go | ||
│ └── sub1 | ||
│ ├── sub1.go | ||
│ └── sub2 | ||
│ ├── leafA.go | ||
│ └── leafB.go | ||
└── main.go | ||
``` | ||
Add the commands defined in leafA.go and leafB.go to the sub2 command. | ||
|
||
Add the commands defined in sub2.go to the sub1 command. | ||
|
||
Add the commands defined in sub1.go to the root command. | ||
|
||
The main structure of the final command call is as follows: | ||
``` | ||
root options | ||
root sub1 options | ||
root sub1 sub2 options | ||
root sub1 sub2 leafA options | ||
root sub1 sub2 leafB options | ||
``` | ||
|
||
|
||
## curveadm cli project structure | ||
``` | ||
cli | ||
├── cli | ||
│ ├── cli.go | ||
│ └── version.go | ||
├── command | ||
│ ├── audit.go | ||
│ ├── clean.go | ||
│ ├── client | ||
│ ├── cluster | ||
│ ... | ||
└── curveadm.go | ||
``` | ||
The `cli.go` in the cli folder defines the `curveadm` object and related methods, which run through all curveadm cli command development. | ||
``` | ||
type CurveAdm struct { | ||
rootDir string | ||
dataDir string | ||
... | ||
} | ||
func NewCurveAdm() (*CurveAdm, error) { | ||
curveadm := &CurveAdm{ | ||
rootDir: rootDir, | ||
... | ||
} | ||
... | ||
return curveadm, nil | ||
} | ||
``` | ||
|
||
The command directory stores command implementations at each level. | ||
``` | ||
├── audit.go | ||
├── client | ||
│ ├── cmd.go | ||
│ ├── enter.go | ||
│ └── unmap.go | ||
├── cluster | ||
│ ├── add.go | ||
│ ├── cmd.go | ||
├── cmd.go | ||
├── deploy.go | ||
``` | ||
In curveadm cli, the root command of each layer is defined in `cmd.go`. The root command is only responsible for registering subcommands and providing help information, and does not participate in actual work operations. | ||
``` | ||
cli\command\cmd.go | ||
func addSubCommands(cmd *cobra.Command, curveadm *cli.CurveAdm) { | ||
cmd.AddCommand( | ||
client.NewClientCommand(curveadm), // curveadm client | ||
... | ||
) | ||
} | ||
func NewCurveAdmCommand(curveadm *cli.CurveAdm) *cobra.Command { | ||
... | ||
cmd := &cobra.Command{ | ||
Use: "curveadm [OPTIONS] COMMAND [ARGS...]", | ||
... | ||
} | ||
... | ||
addSubCommands(cmd, curveadm) | ||
return cmd | ||
} | ||
################################################ ############## | ||
cli\command\client\cmd.go | ||
func NewClientCommand(curveadm *cli.CurveAdm) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "client", | ||
... | ||
} | ||
cmd.AddCommand( | ||
NewMapCommand(curveadm), | ||
... | ||
) | ||
... | ||
} | ||
################################################ ############## | ||
cli\command\client\enter.go | ||
func NewEnterCommand(curveadm *cli.CurveAdm) *cobra.Command { | ||
... | ||
cmd := &cobra.Command{ | ||
Use: "enter ID", | ||
... | ||
} | ||
... | ||
} | ||
``` | ||
The final call structure of the enter command is as follows: | ||
``` | ||
curveadm client enter ID | ||
``` | ||
|
||
curveadm.go defines the execution function of the `curveadm` root command and performs related audit work. | ||
``` | ||
func Execute() { | ||
curveadm, err := cli.NewCurveAdm() | ||
... | ||
id := curveadm.PreAudit(time.Now(), os.Args[1:]) | ||
cmd := command.NewCurveAdmCommand(curveadm) | ||
err = cmd.Execute() | ||
curveadm.PostAudit(id, err) | ||
if err != nil { | ||
os.Exit(1) | ||
} | ||
} | ||
``` | ||
|
||
The entrance to the `curveadm` main program is under the [curveadm folder](https://github.com/opencurve/curveadm/tree/develop/cmd/curveadm). You can execute the operation and execution of `curveadm` in this directory. compile | ||
``` | ||
func main() { | ||
cli.Execute() | ||
} | ||
``` | ||
|
||
### curveadm general tools | ||
For command development of curveadm cli, curveadm provides general tools, such as: | ||
|
||
- cliutil.NoArgs: used to determine whether the command does not contain parameters | ||
|
||
- cliutil.ShowHelp: used to display help information when the command is run | ||
|
||
In the [curveadm/internal directory](https://github.com/opencurve/curveadm/tree/develop/internal). As follows: | ||
``` | ||
import ( | ||
cliutil "github.com/opencurve/curveadm/internal/utils" | ||
... | ||
) | ||
cmd := &cobra.Command{ | ||
Use: "client", | ||
Args: cliutil.NoArgs, | ||
RunE: cliutil.ShowHelp(curveadm.Err()), | ||
} | ||
``` | ||
`cliutil.NoArgs` specifies that the `curveadm client` command does not contain any arguments (except subcommands); the `cliutil.ShowHelp` function displays the defined help options when running the `curveadm client` command directly. | ||
|
||
For more common commands and usage, please refer to [internal folder](https://github.com/opencurve/curveadm/tree/develop/internal). |
Oops, something went wrong.