Automatically sets up command line flags based on struct fields and tags.

Commandeer

Go Report Card GoDoc Coverage

Image

Commandeer sets up command line flags based on struct fields and tags.

Do you...

  • like to develop Go apps as libraries with tiny main packages?
  • get frustrated keeping your flags up to date as your code evolves?
  • feel irked by the overlap between comments on struct fields and help strings for flags?
  • hate switching between your app's main and library packages?

You might like Commandeer. See the godoc for detailed usage, or just...

Try It!

Here's how it works, define your app like so:

package myapp

import "fmt"

type Main struct {
	Num     int    `help:"How many does it take?"`
	Vehicle string `help:"What did they get?"`
}

func NewMain() *Main { return &Main{Num: 5, Vehicle: "jeep"} }

func (m *Main) Run() error {
	if m.Num < 2 || m.Vehicle == "" {
		return fmt.Errorf("Need more gophers and/or vehicles.")
	}
	fmt.Printf("%d gophers stole my %s!\n", m.Num, m.Vehicle)
	return nil
}

and your main package:

package main

import (
	"fmt"

	"github.com/jaffee/commandeer"
	"github.com/jaffee/commandeer/examples/myapp"
)

func main() {
	err := commandeer.Run(myapp.NewMain())
	if err != nil {
		fmt.Println(err)
	}
}

Now...

$ ./myapp -h
Usage of ./myapp:
  -num int
    	How many does it take? (default 5)
  -vehicle string
    	What did they get? (default "jeep")

$ ./myapp
5 gophers stole my jeep!
$ ./myapp -num 3 -vehicle horse
3 gophers stole my horse!

Notice that Commandeer set up the default values for each flag based on the values in the struct passed to Run.

Commandeer is set up for minimal dependency pollution - it uses only stdlib dependencies and is a few hundred lines of code itself. You need only import it from a tiny main package (as in the example), and shouldn't need to reference it anywhere else.

If you aren't allergic to external dependencies, you can also try github.com/jaffee/commandeer/cobrafy which pulls in the excellent Cobra and pflag packages giving you GNU/POSIX style flags and some other nice features should you care to use them. See the godoc, or the myapp-cobrafy example.

Features

In addition to the help struct tag, you can use flag to override the computed flag name, e.g.

type Main struct {
	Num     int    `flag:"number"`
}

You can also use flag:"-" to explicitly ignore fields from being used as flags, e.g.

type Main struct {
	Num     int    `flag:"-"`
}

Nested structs are supported, by default the field names will be joined with "." to create the flag name, e.g.

type Main struct {
	Vehicle struct {
		Color string
		Weight int
	}
}

produces:

  -vehicle.color string
    	
  -vehicle.weight int

If you wish to avoid this prefix behavior (e.g. if you have an embedded struct field and you want to elevate its fields to the top level) you can use flag:"!embed", e.g.

type Main struct {
	Vehicle struct {
		Color string
		Weight int
	} `flag:"!embed"`
}

which will produce:

  -color string
    	
  -weight int

Contributing

Yes please!

For small stuff, feel free to submit a PR directly. For larger things, especially API changes, it's best to make an issue first so it can be discussed.

Similar projects

Owner
Matthew Jaffee
Astrophysics to Computer Science to software dev - now building a distributed index at Pilosa. Goal: build software which outlives me.
Matthew Jaffee
Comments
  • undefined: commandeer.ImplementsRunner

    undefined: commandeer.ImplementsRunner

    I tried to run myapp-cobrafy which gives undefined: commandeer.ImplementsRunner at line 31 in cobrafy/cobra.go

    full error

    ~/dev/golang/src/github.com/jaffee/commandeer/examples/myapp/cmd/myapp-cobrafy master
    » go run main.go
    # github.com/jaffee/commandeer/cobrafy
    ../../../../cobrafy/cobra.go:31:5: undefined: commandeer.ImplementsRunner
    
  • Fixing panic when -h is an argument

    Fixing panic when -h is an argument

    If you are using stdlib Flags, and one of your flags implements TextMarshaler and TextUnmarshaler, commander panics when the -h flag is passed as an argument.

  • "short" struct tag should support using hyphen to ignore a flag

    I tried short:"-" to suppress short flags, but commandeer 1) doesn't support that, 2) tries to use -- like a valid flag, which is anti-conventional.

  • Readme typo

    Readme typo

    Hi, very nice package :)

    Just pointing out a small typo in your readme, I believe the following part:

    $ ./myapp
    5 gophers stole my jeep!
    $ ./myapp
    3 gophers stole my horse!
    

    Should be:

    $ ./myapp
    5 gophers stole my jeep!
    $ ./myapp -num 3
    3 gophers stole my horse!
    

    With the -num 3 flag included. Am I correct?

  • Generate uppercase env var names in LoadEnv

    Generate uppercase env var names in LoadEnv

    This patch applies an uppercase filter to the generated environment variable names in LoadEnv. For example, a flag called config will be translated to env var COMMANDEER_CONFIG instead of COMMANDEER_config.

  • use type assertions instead of reflect

    use type assertions instead of reflect

    You can type-assert to interfaces, even in cases where this is "upgrading" to a more-restrictive interface which needs additional fields, as long as the underlying concrete type implements the interface.

    I wasn't 100% sure about this, but I did some test cases and it worked. (Then it failed because my copy of spf13/pflag was too old to handle IP masks, but updating it fixed that.)

  • generated shortflags are potentially unstable

    generated shortflags are potentially unstable

    When new fields are added to structs, are the same short flags generated for existing fields? Are the same short flags even generated from build to build? Can we always ensure that we iterate the struct fields in the order they're defined?

  • cobrafy confused by JSON attributes

    cobrafy confused by JSON attributes

    I haven't used base commandeer yet, but the wanted to try using cobrafy to reuse some structs we use for JSON parsing as arguments for a sub command we shell out to.

    However, it seems like the generated Cobra.Command is confused by the omitempty on the json attribute.

    See for example: https://go.dev/play/p/dTj_Fxo63sr

    package main
    
    import (
    	"fmt"
    
    	"github.com/jaffee/commandeer/cobrafy"
    )
    
    type Args struct {
    	Count      int  `json:"count,omitempty"`
    	Reticulate bool `json:"reticulate,omitempty"`
    }
    
    func main() {
    	args := Args{
    		Count:      1,
    		Reticulate: false,
    	}
    	cmd, err := cobrafy.Command(&args)
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println("Trying --count ... ")
    	cmd.SetArgs([]string{"--count"})
    	if err := cmd.Execute(); err != nil {
    		fmt.Println(err)
    	}
    
    	fmt.Println("Trying --reticulate,omitempty ... ")
    	cmd.SetArgs([]string{"--reticulate,omitempty"})
    	if err := cmd.Execute(); err != nil {
    		fmt.Println(err)
    	} else {
    		fmt.Println("Accepted")
    	}
    }
    
  • panic when using named non-struct types

    panic when using named non-struct types

    While attempting to use a wrapped version of time.Duration, I ran into a crash when using commandeer.

    https://github.com/jaffee/commandeer/blob/07c6265b86ee0e0cd87f47e8f50b027653e70b79/com.go#L274-L358

    All of these type assertions will panic if the type is named.

  • support setting custom help messages

    support setting custom help messages

    By default, running a binary set up with commandeer will print out the available flags, but I don't think there's an easy/general way to set a usage message above the flags. Maybe I'm wrong, but need to look into this regardless.

  • add map support

    add map support

    This is probably sorta insane, I just wanted to see if it could be done.

    Map members only define arguments for entries they have when the provided structure-or-map was scanned to create arguments.

A go1.18 wrapper to provide simple generics based API for defining command line flags.

gflag A go1.18 wrapper to provide simple generics based API for defining command line flags. Example package main import ( "flag" "fmt" "time" "

Dec 20, 2021
Envp - ENVP is cli wrapper that sets environment variables by profile when you execute the command line

ENVP ENVP is cli wrapper that sets environment variables by profile based config

Nov 7, 2022
A command line tool that builds and (re)starts your web application everytime you save a Go or template fileA command line tool that builds and (re)starts your web application everytime you save a Go or template file

# Fresh Fresh is a command line tool that builds and (re)starts your web application everytime you save a Go or template file. If the web framework yo

Nov 22, 2021
Automatically generate Go (golang) struct definitions from example JSON

gojson gojson generates go struct definitions from json or yaml documents. Example $ curl -s https://api.github.com/repos/chimeracoder/gojson | gojson

Jan 1, 2023
An open-source GitLab command line tool bringing GitLab's cool features to your command line
An open-source GitLab command line tool bringing GitLab's cool features to your command line

GLab is an open source GitLab CLI tool bringing GitLab to your terminal next to where you are already working with git and your code without switching

Dec 30, 2022
A command line tool to prompt for a value to be included in another command line.

readval is a command line tool which is designed for one specific purpose—to prompt for a value to be included in another command line. readval prints

Dec 22, 2021
Idiomatic Go input parsing with subcommands, positional values, and flags at any position. No required project or package layout and no external dependencies.
Idiomatic Go input parsing with subcommands, positional values, and flags at any position. No required project or package layout and no external dependencies.

Sensible and fast command-line flag parsing with excellent support for subcommands and positional values. Flags can be at any position. Flaggy has no

Jan 1, 2023
archy is an static binary to determine current kernel and machine architecture, with backwards compatible flags to uname, and offers alternative output format of Go runtime (i.e. GOOS, GOARCH).

archy archy is an simple binary to determine current kernel and machine architecture, which wraps uname and alternatively can read from Go runtime std

Mar 18, 2022
CLI tool to update ~/.aws/config with all accounts and permission sets defined in AWS SSO

aws-sso-profiles Generate or update ~/.aws/config with a profile for each SSO account you have access to, by using an existing AWS SSO session. Bootst

Nov 3, 2022
A rich tool for parsing flags and values in pure Golang

A rich tool for parsing flags and values in pure Golang. No additional library is required and you can use everywhere.

Jan 25, 2022
Drop-in replacement for Go's flag package, implementing POSIX/GNU-style --flags.

Description pflag is a drop-in replacement for Go's flag package, implementing POSIX/GNU-style --flags. pflag is compatible with the GNU extensions to

Dec 30, 2022
Generate flags by parsing structures

Flags based on structures. The sflags package uses structs, reflection and struct field tags to allow you specify command line options. It supports di

Nov 24, 2022
Prompts users to enter values for required flags in Cobra CLI applications

Cobra Flag Prompt Cobra Flag Prompt prompts users to enter values for required flags. It is an extension of Cobra, and requires that you use Cobra to

Nov 13, 2021
Go-flags wireframing demo

go-flags-demo redo - global option redo Redo global option via automatic code-gen TOC go-flags-demo - global option redo Synopsis Usage Development Hi

Jan 22, 2022
Little golang app that allows you to download a youtube video as mp3, and optionally embed ID3 tags -Cover Art, Artist ...-

yt2mp3 Little golang app that allows you to download a youtube video as mp3, and optionally embed ID3 tags -Cover Art, Artist ...- Instructions At the

Dec 25, 2021
learn go build --tags and ldflags

Learn tags and ldflags for go build go build -tags debug -ldflags "-X main.version=`autotag current`" -o normal ./normal output is: running version is

Dec 26, 2021
Watcher - A simple command line app to watch files in a directory for changes and run a command when files change!

Watcher - Develop your programs easily Watcher watches all the files present in the directory it is run from of the directory that is specified while

Mar 27, 2022
Go package to make lightweight ASCII line graph ╭┈╯ in command line apps with no other dependencies.
Go package to make lightweight ASCII line graph ╭┈╯ in command line apps with no other dependencies.

asciigraph Go package to make lightweight ASCII line graphs ╭┈╯. Installation go get github.com/guptarohit/asciigraph Usage Basic graph package main

Jan 8, 2023
Use the command to convert arbitrary formats to Go Struct (including json, toml, yaml, etc.)

go2struct-tool Use the command to convert arbitrary formats to Go Struct (including json, toml, yaml, etc.) Installation Run the following command und

Dec 16, 2021