SkillAgentSearch skills...

Mow.cli

A versatile library for building CLI applications in Go

Install / Use

/learn @jawher/Mow.cli
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

mow.cli

CI GoDoc Coverage Status

Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the user.

Getting Started

The following examples demonstrate basic usage the package.

Simple Application

In this simple application, we mimic the argument parsing of the standard UNIX cp command. Our application requires the user to specify one or more source files followed by a destination. An optional recursive flag may be provided.

package main

import (
	"fmt"
	"os"

	"github.com/jawher/mow.cli"
)

func main() {
	// create an app
	app := cli.App("cp", "Copy files around")

	// Here's what differentiates mow.cli from other CLI libraries:
	// This line is not just for help message generation.
	// It also validates the call to reject calls with less than 2 arguments
	// and split the arguments between SRC or DST
	app.Spec = "[-r] SRC... DST"

	var (
		// declare the -r flag as a boolean flag
		recursive = app.BoolOpt("r recursive", false, "Copy files recursively")
		// declare the SRC argument as a multi-string argument
		src = app.StringsArg("SRC", nil, "Source files to copy")
		// declare the DST argument as a single string (string slice) arguments
		dst = app.StringArg("DST", "", "Destination where to copy files to")
	)

	// Specify the action to execute when the app is invoked correctly
	app.Action = func() {
		fmt.Printf("Copying %v to %s [recursively: %v]\n", *src, *dst, *recursive)
	}

	// Invoke the app passing in os.Args
	app.Run(os.Args)
}

Pointers to existing variables

This variant of the cp command uses the Ptr variants, where you can pass pointers to existing variables instead of declaring new ones for the options/arguments:

package main

import (
	"fmt"
	"os"

	cli "github.com/jawher/mow.cli"
)

type Config struct {
	Recursive bool
	Src       []string
	Dst       string
}

func main() {
	var (
		app = cli.App("cp", "Copy files around")
		cfg Config
	)
	// Here's what differentiates mow.cli from other CLI libraries:
	// This line is not just for help message generation.
	// It also validates the call to reject calls with less than 2 arguments
	// and split the arguments between SRC or DST
	app.Spec = "[-r] SRC... DST"

	// declare the -r flag as a boolean flag
	app.BoolOptPtr(&cfg.Recursive, "r recursive", false, "Copy files recursively")
	// declare the SRC argument as a multi-string argument
	app.StringsArgPtr(&cfg.Src, "SRC", nil, "Source files to copy")
	// declare the DST argument as a single string (string slice) arguments
	app.StringArgPtr(&cfg.Dst, "DST", "", "Destination where to copy files to")

	// Specify the action to execute when the app is invoked correctly
	app.Action = func() {
		fmt.Printf("Copying using config: %+v\n", cfg)
	}
	// Invoke the app passing in os.Args
	app.Run(os.Args)
}

Multi-Command Application

In the next example, we create a multi-command application in the same style as familiar commands such as git and docker. We build a fictional utility called uman to manage users in a system. It provides two commands that can be invoked: list and get. The list command takes an optional flag to specify all users including disabled ones. The get command requires one argument, the user ID, and takes an optional flag to specify a detailed listing.

package main

import (
	"fmt"
	"os"

	"github.com/jawher/mow.cli"
)

func main() {
	app := cli.App("uman", "User Manager")

	app.Spec = "[-v]"

	var (
		verbose = app.BoolOpt("v verbose", false, "Verbose debug mode")
	)

	app.Before = func() {
		if *verbose {
			// Here we can enable debug output in our logger for example
			fmt.Println("Verbose mode enabled")
		}
	}

	// Declare our first command, which is invocable with "uman list"
	app.Command("list", "list the users", func(cmd *cli.Cmd) {
		// These are the command-specific options and args, nicely scoped
		// inside a func so they don't pollute the namespace
		var (
			all = cmd.BoolOpt("all", false, "List all users, including disabled")
		)

		// Run this function when the command is invoked
		cmd.Action = func() {
			// Inside the action, and only inside, we can safely access the
			// values of the options and arguments
			fmt.Printf("user list (including disabled ones: %v)\n", *all)
		}
	})

	// Declare our second command, which is invocable with "uman get"
	app.Command("get", "get a user details", func(cmd *cli.Cmd) {
		var (
			detailed = cmd.BoolOpt("detailed", false, "Display detailed info")
			id       = cmd.StringArg("ID", "", "The user id to display")
		)

		cmd.Action = func() {
			fmt.Printf("user %q details (detailed mode: %v)\n", *id, *detailed)
		}
	})

	// With the app configured, execute it, passing in the os.Args array
	app.Run(os.Args)
}

A Larger Multi-Command Example

This example shows an alternate way of organizing our code when dealing with a larger number of commands and subcommands. This layout emphasizes the command structure and defers the details of each command to subsequent functions. Like the prior examples, options and arguments are still scoped to their respective functions and don't pollute the global namespace.

package main

import (
	"fmt"
	"os"

	"github.com/jawher/mow.cli"
)

// Global options available to any of the commands
var filename *string

func main() {
	app := cli.App("vault", "Password Keeper")

	// Define our top-level global options
	filename = app.StringOpt("f file", os.Getenv("HOME")+"/.safe", "Path to safe")

	// Define our command structure for usage like this:
	app.Command("list", "list accounts", cmdList)
	app.Command("creds", "display account credentials", cmdCreds)
	app.Command("config", "manage accounts", func(config *cli.Cmd) {
		config.Command("list", "list accounts", cmdList)
		config.Command("add", "add an account", cmdAdd)
		config.Command("remove", "remove an account(s)", cmdRemove)
	})

	app.Run(os.Args)
}

// Sample use: vault list OR vault config list
func cmdList(cmd *cli.Cmd) {
	cmd.Action = func() {
		fmt.Printf("list the contents of the safe here")
	}
}

// Sample use: vault creds reddit.com
func cmdCreds(cmd *cli.Cmd) {
	cmd.Spec = "ACCOUNT"
	account := cmd.StringArg("ACCOUNT", "", "Name of account")
	cmd.Action = func() {
		fmt.Printf("display account info for %s\n", *account)
	}
}

// Sample use: vault config add reddit.com -u username -p password
func cmdAdd(cmd *cli.Cmd) {
	cmd.Spec = "ACCOUNT [ -u=<username> ] [ -p=<password> ]"
	var (
		account  = cmd.StringArg("ACCOUNT", "", "Account name")
		username = cmd.StringOpt("u username", "admin", "Account username")
		password = cmd.StringOpt("p password", "admin", "Account password")
	)
	cmd.Action = func() {
		fmt.Printf("Adding account %s:%s@%s", *username, *password, *account)
	}
}

// Sample use: vault config remove reddit.com twitter.com
func cmdRemove(cmd *cli.Cmd) {
	cmd.Spec = "ACCOUNT..."
	var (
		accounts = cmd.StringsArg("ACCOUNT", nil, "Account names to remove")
	)
	cmd.Action = func() {
		fmt.Printf("Deleting accounts: %v", *accounts)
	}
}

Comparison to Other Tools

There are several tools in the Go ecosystem to facilitate the creation of command line tools. The following is a comparison to the built-in flag package as well as the popular urfave/cli (formerly known as codegangsta/cli):

| | mow.cli | urfave/cli | flag | |---------------------------------------------------------------------|---------|------------|------| | Contextual help | ✓ | ✓ | | | Commands | ✓ | ✓ | | | Option folding -xyz | ✓ | | | | Option value folding -fValue | ✓ | | | | Option exclusion --start ❘ --stop | ✓ | | | | Option dependency [-a -b] or [-a [-b]] | ✓ | | | | Arguments validation SRC DST | ✓ | | | | Argument optionality SRC [DST] | ✓ | | | | Argument repetition SRC... DST | ✓ | | | | Option/argument dependency SRC [-f DST] | ✓ | | | | Any combination of the above [-d ❘ --rm] IMAGE [COMMAND [ARG...]] | ✓ | | |

Unlike the simple packages above, docopt is another library that supports rich set of flag and argument validation. It does, however, fall short for many use cases including:

| | mow.cli | docopt | |----------------------------|---------|--------| | Contextual help | ✓ | | | Backtracking SRC... DST | ✓ | | | Backtracking [SRC] DST | ✓ | | | Branching (SRC ❘ -f DST) | ✓ | |

Installation

To install this package, run the following:

go get github.com/jawher/mow.cli

Package Documentation

<!-- Do NOT edit past here. This is replaced by the contents of the package documentation -->

Package cli provides a framework to build command line applications in Go with most of the burden of arguments parsing and validation placed on the framework instead of the user.

Basics

To create a new application, initialize an app with cli.App. Specify a name and a brief description for

Related Skills

View on GitHub
GitHub Stars883
CategoryDevelopment
Updated1mo ago
Forks56

Languages

Go

Security Score

100/100

Audited on Feb 24, 2026

No findings