From 6c0cb34745aa37492239084a1ac4b45630084a09 Mon Sep 17 00:00:00 2001 From: spf13 Date: Wed, 18 Nov 2015 22:56:25 -0500 Subject: [PATCH] Restructure README.md --- README.md | 251 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 212 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index d0f875e1..ea0bb458 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Many of the most widely used Go projects are built using Cobra including: ![cobra](https://cloud.githubusercontent.com/assets/173412/10911369/84832a8e-8212-11e5-9f82-cc96660a4794.gif) -## Overview +# Overview Cobra is a library providing a simple interface to create powerful modern CLI interfaces similar to git & go tools. @@ -52,21 +52,35 @@ constructors or initialization methods. Applications built with Cobra commands are designed to be as user-friendly as possible. Flags can be placed before or after the command (as long as a confusing space isn’t provided). Both short and long flags can be used. A -command need not even be fully typed. The shortest unambiguous string will -suffice. Help is automatically generated and available for the application or -for a specific command using either the help command or the `--help` flag. +command need not even be fully typed. Help is automatically generated and +available for the application or for a specific command using either the help +command or the `--help` flag. -## Concepts +# Concepts -Cobra is built on a structure of commands & flags. +Cobra is built on a structure of commands, arguments & flags. -**Commands** represent actions and **Flags** are modifiers for those actions. +**Commands** represent actions, **Args** are things and **Flags** are modifiers for those actions. + +The best applications will read like sentences when used. Users will know how +to use the application because they will natively understand how to use it. + +The pattern to follow is +`APPNAME VERB NOUN --ADJECTIVE.` + or +`APPNAME COMMAND ARG --FLAG` + +A few good real world examples may better illustrate this point. In the following example, 'server' is a command, and 'port' is a flag: - > hugo server --port=1313 + > hugo serve --port=1313 -### Commands +In this command we are telling Git to clone the url bare. + + > git clone URL --bare + +## Commands Command is the central point of the application. Each interaction that the application supports will be contained in a Command. A command can @@ -85,7 +99,7 @@ type Command struct { } ``` -### Flags +## Flags A Flag is a way to modify the behavior of a command. Cobra supports fully POSIX-compliant flags as well as the Go [flag package](https://golang.org/pkg/flag/). @@ -106,7 +120,7 @@ The tree defines the structure of the application. Once each command is defined with its corresponding flags, then the tree is assigned to the commander which is finally executed. -### Installing +# Installing Using Cobra is easy. First, use `go get` to install the latest version of the library: @@ -118,14 +132,118 @@ Next, include Cobra in your application: import "github.com/spf13/cobra" ``` +# Getting Started + +While you are welcome to provide your own organization, typically a Cobra based +application will follow the following organizational structure. + +``` + ▾ appName/ + ▾ cmd/ + add.go + your.go + commands.go + here.go + main.go +``` + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import "{pathToYourApp}/cmd" + +func main() { + RootCmd.Execute() +} +``` + +## Using the Cobra Generator + +Cobra provides it's own program that will create your application and add any +commands you want. It's the easiest way to incorporate Cobra into your application. + +### cobra init + +The `cobra init [yourApp]` command will create your initial application code +for you. It is a very powerful application that will populate your program with +the right structure so you can immediately enjoy all the benefits of Cobra. It +will also automatically apply the license you specify to your application. + +Cobra init is pretty smart. You can provide it a full path, or simply a path +similar to what is expected in the import. + +``` +cobra init github.com/spf13/newAppName +``` + +### cobra add + +Once an application is initialized Cobra can create additional commands for you. +Let's say you created an app and you wanted the following commands for it: + +* app serve +* app config +* app config create + +In your project directory (where your main.go file is) you would run the following: + +``` +cobra add serve +cobra add config +cobra add create -p 'configCmd' +``` + +Once you have run these four commands you would have an app structure that would look like: + +``` + ▾ app/ + ▾ cmd/ + serve.go + config.go + create.go + main.go +``` + +at this point you can run `go run main.go` and it would run your app. `go run +main.go serve`, `go run main.go config`, `go run main.go config create` along +with `go run main.go help serve`, etc would all work. + +Obviously you haven't added your own code to these yet, the commands are ready +for you to give them their tasks. Have fun. + +### Configuring the cobra generator + +The cobra generator will be easier to use if you provide a simple configuration +file which will help you eliminate providing a bunch of repeated information in +flags over and over. + +an example ~/.cobra.yaml file: + +```yaml +author: Steve Francia +license: MIT +``` + +## Manually implementing Cobra + +To manually implement cobra you need to create a bare main.go file and a RootCmd file. +You will optionally provide additional commands as you see fit. + ### Create the root command The root command represents your binary itself. + +#### Manually create rootCmd + Cobra doesn't require any special constructors. Simply create your commands. +Ideally you place this in app/cmd/root.go: + ```go -var HugoCmd = &cobra.Command{ +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 @@ -137,11 +255,63 @@ var HugoCmd = &cobra.Command{ } ``` -### Create additional commands +You will additionally define flags and handle configuration in your init() function. -Additional commands can be defined. +for example cmd/root.go: ```go +func init() { + cobra.OnInitialize(initConfig) + RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") + RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") + RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") + RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") + RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") + viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) + viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) + viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) + viper.SetDefault("author", "NAME HERE ") + viper.SetDefault("license", "apache") +} +``` + +### Create your main.go + +With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command. + +In a Cobra app, typically the main.go file is very bare. It serves, one purpose, to initialize Cobra. + +```go +package main + +import "{pathToYourApp}/cmd" + +func main() { + RootCmd.Execute() +} +``` + + +### Create additional commands + +Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory. + +If you wanted to create a version command you would create cmd/version.go and +populate it with the following: + +```go +package cmd + +import ( + "github.com/spf13/cobra" +) + +func init() { + RootCmd.AddCommand(versionCmd) +} + var versionCmd = &cobra.Command{ Use: "version", Short: "Print the version number of Hugo", @@ -152,13 +322,34 @@ var versionCmd = &cobra.Command{ } ``` -### Attach command to its parent -In this example we are attaching it to the root, but commands can be attached at any level. +### Attach command to its parent + + +If you notice in the above example we attach the command to it's parent. In +this case the parent is the rootCmd. In this example we are attaching it to the +root, but commands can be attached at any level. ```go -HugoCmd.AddCommand(versionCmd) +RootCmd.AddCommand(versionCmd) ``` +### Remove a command from its parent + +Removing a command is not a common action in simple programs, but it allows 3rd +parties to customize an existing command tree. + +In this example, we remove the existing `VersionCmd` command of an existing +root command, and we replace it with our own version: + +```go +mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd) +mainlib.RootCmd.AddCommand(versionCmd) +``` + +## Working with Flags + +Flags provide modifiers to control how the action command operates. + ### Assign flags to a command Since the flags are defined and used in different locations, we need to @@ -172,42 +363,24 @@ var Source string There are two different approaches to assign a flag. -#### Persistent Flags +### Persistent Flags A flag can be 'persistent' meaning that this flag will be available to the command it's assigned to as well as every command under that command. For global flags, assign a flag as a persistent flag on the root. ```go -HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +RootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") ``` -#### Local Flags +### Local Flags A flag can also be assigned locally which will only apply to that specific command. ```go -HugoCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +RootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") ``` -### Remove a command from its parent - -Removing a command is not a common action in simple programs, but it allows 3rd parties to customize an existing command tree. - -In this example, we remove the existing `VersionCmd` command of an existing root command, and we replace it with our own version: - -```go -mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd) -mainlib.RootCmd.AddCommand(versionCmd) -``` - -### Once all commands and flags are defined, Execute the commands - -Execute should be run on the root for clarity, though it can be called on any command. - -```go -HugoCmd.Execute() -``` ## Example