Generate flags by parsing structures

Flags based on structures. GoDoc Build Status codecov Go Report Card

The sflags package uses structs, reflection and struct field tags to allow you specify command line options. It supports different types and features.

An example:

type HTTPConfig struct {
	Host    string        `desc:"HTTP host"`
	Port    int           `flag:"port p" desc:"some port"`
	SSL     bool          `env:"HTTP_SSL_VALUE"`
	Timeout time.Duration `flag:",deprecated,hidden"`
}

type Config struct {
	HTTP  HTTPConfig
	Stats StatsConfig
}

And you can use your favorite flag or cli library!

Supported flags and cli libraries:

Features:

  • Set environment name
  • Set usage
  • Long and short forms
  • Skip field
  • Required
  • Placeholders (by name)
  • Deprecated and hidden options
  • Multiple ENV names
  • Interface for user types.
  • Validation (using govalidator package)
  • Anonymous nested structure support (anonymous structures flatten by default)

Supported types in structures:

  • int, int8, int16, int32, int64
  • uint, uint8, uint16, uint32, uint64
  • float32, float64
  • slices for all previous numeric types (e.g. []int, []float64)
  • bool
  • []bool
  • string
  • []string
  • nested structures
  • net.TCPAddr
  • net.IP
  • time.Duration
  • regexp.Regexp
  • map for all previous types (e.g. map[int64]bool, map[string]float64)

Custom types:

  • HexBytes

  • count

  • ipmask

  • enum values

  • enum list values

  • file

  • file list

  • url

  • url list

  • units (bytes 1kb = 1024b, speed, etc)

Supported features matrix:

Name Hidden Deprecated Short Env
flag - - - -
pflag [x] [x] [x] -
kingpin [x] [ ] [x] [x]
urfave [x] - [x] [x]
cobra [x] [x] [x] -
viper [ ] [ ] [ ] [ ]

[x] - feature is supported and implemented

- - feature can't be implemented for this cli library

Simple example for flag library:

package main

import (
	"flag"
	"log"
	"time"

	"github.com/octago/sflags/gen/gflag"
)

type httpConfig struct {
	Host    string `desc:"HTTP host"`
	Port    int
	SSL     bool
	Timeout time.Duration
}

type config struct {
	HTTP httpConfig
}

func main() {
	cfg := &config{
		HTTP: httpConfig{
			Host:    "127.0.0.1",
			Port:    6000,
			SSL:     false,
			Timeout: 15 * time.Second,
		},
	}
	err := gflag.ParseToDef(cfg)
	if err != nil {
		log.Fatalf("err: %v", err)
	}
	flag.Parse()
}

That code generates next output:

go run ./main.go --help
Usage of _obj/exe/main:
  -http-host value
    	HTTP host (default 127.0.0.1)
  -http-port value
    	 (default 6000)
  -http-ssl

  -http-timeout value
    	 (default 15s)
exit status 2

Look at the other examples for different flag libraries.

Options for flag tag

The flag default key string is the struct field name but can be specified in the struct field's tag value. The "flag" key in the struct field's tag value is the key name, followed by an optional comma and options. Examples:

// Field is ignored by this package.
Field int `flag:"-"`

// Field appears in flags as "myName".
Field int `flag:"myName"`

// If this field is from nested struct, prefix from parent struct will be ingored.
Field int `flag:"~myName"`

// You can set short name for flags by providing it's value after a space
// Prefixes will not be applied for short names.
Field int `flag:"myName a"`

// this field will be removed from generated help text.
Field int `flag:",hidden"`

// this field will be marked as deprecated in generated help text
Field int `flag:",deprecated"`

Options for desc tag

If you specify description in description tag (desc by default) it will be used in USAGE section.

Addr string `desc:"HTTP address"`

this description produces something like:

  -addr value
    	HTTP host (default 127.0.0.1)

Options for env tag

Options for Parse function:

// DescTag sets custom description tag. It is "desc" by default.
func DescTag(val string)

// FlagTag sets custom flag tag. It is "flag" be default.
func FlagTag(val string)

// Prefix sets prefix that will be applied for all flags (if they are not marked as ~).
func Prefix(val string)

// EnvPrefix sets prefix that will be applied for all environment variables (if they are not marked as ~).
func EnvPrefix(val string)

// FlagDivider sets custom divider for flags. It is dash by default. e.g. "flag-name".
func FlagDivider(val string)

// EnvDivider sets custom divider for environment variables.
// It is underscore by default. e.g. "ENV_NAME".
func EnvDivider(val string)

// Validator sets validator function for flags.
// Check existed validators in sflags/validator package.
func Validator(val ValidateFunc)

// Set to false if you don't want anonymous structure fields to be flatten.
func Flatten(val bool)

Known issues

  • kingpin doesn't pass value for boolean arguments. Counter can't get initial value from arguments.

Similar projects

Comments
  • tag a new release?

    tag a new release?

    There have been a number of new features and bug fixes since the last tagged release, v0.2.0: https://github.com/octago/sflags/compare/v0.2.0..master

    Can we tag a new release to simply updates for projects using go mod?

  • Add map typed flags

    Add map typed flags

    Issue #7 This PR add availability of map typed flags usage. Map keys can be string or kind of integer, and values can be any types available as flags by this library.

    Example:

    package main
    
    import (
    	"fmt"
    	"log"
    	"github.com/davecgh/go-spew/spew"
    	"github.com/octago/sflags/gen/gflag"
    	"flag"
    )
    
    type config struct {
    	Field1 map[string]int64
    	Field2 map[int64]int32
    	Field3 map[int8]bool
    	Field4 map[string]string
    }
    
    func main() {
    	var cfg config
    
    	err := gflag.ParseToDef(&cfg)
    	if err != nil {
    		log.Fatalf("err: %v", err)
    	}
    
    	flag.Parse()
    
    	fmt.Printf("cfg: %s\n", spew.Sdump(cfg))
    
    	/*
    	INPUT:
    	./flag -field1=test:123 -field2=8:2 -field2=3:5 -field3=5:true -field4=m:v
    	*/
    
    	/*
    	OUTPUT:
    	cfg: (main.config) {
    	Field1: (map[string]int64) (len=1) {
    		(string) (len=4) "test": (int64) 123
    		},
    	Field2: (map[int64]int32) (len=2) {
    		(int64) 8: (int32) 2,
    		(int64) 3: (int32) 5
    		},
    	Field3: (map[int8]bool) (len=1) {
    		(int8) 5: (bool) true
    		},
    	Field4: (map[string]string) (len=1) {
    		(string) (len=1) "m": (string) (len=1) "v"
    		}
    	}
    	*/
    }
    

    TODO:

    • [x] Add tests for generated maps types
    • [x] Extend docs
  • Simplify Counter implementation

    Simplify Counter implementation

    • use a pointer receiver only where necessary
    • use strconv.Itoa instead of fmt.Sprintf
    • fix call to strconv.ParseInt: the last argument must be 0 for int instead of 64 (for proper compatibility with 32 bits platform)
  • Multiple build issues

    Multiple build issues

    I'm trying to build fdbe18cab49348fa0bbc857387bafd65a814aecb before starting to contribute, but:

    1. make fails

    $ make
    Go generate
    Formatting
    Run vet
    Run lint
    Run metalinter
    parser_test.go:28:3:warning: field name6 is unused (U1000) (megacheck)
    make: *** [check] Error 1
    

    I'm using the latest gometalinter and I have ensured that the linters are up-to-date (gometalinter -i -u)

    2. go test fails

    --- FAIL: TestValidator (0.00s)
            Error Trace:    parser_test.go:414
    	Error:      	Invalid operation: (sflags.ValidateFunc)(nil) == (sflags.ValidateFunc)(nil) (cannot take func type as argument)
    	Test:       	TestValidator
    FAIL
    exit status 1
    FAIL	github.com/octago/sflags	0.025s
    

    I'm using the latest version of the assert package: go get -u github.com/stretchr/testify/assert

  • Fix go module package name and Makefile error

    Fix go module package name and Makefile error

    Fix module name in go.mod. Without this change it is impossible to use this library in a project with GO111MODULE=on

    Also fix error in Makefile. make does not track working directory between commands.

  • New project heavily piggy-backing on your repository

    New project heavily piggy-backing on your repository

    Hello ! I'm posting a little message to "advertise" a project I've been working for a long time now, which is a merging of your own work and the concepts of https://github.com/jessevdk/go-flags, which brings a new array of possiblities and functionality to generated CLI tools. Since your project was an immense help, because it helped me shifting my approach when working on go-flags, and that most of your code is still used in this new library, I wanted to make a heads-up here ! Link to the repo: https://github.com/reeflective/flags

    Hope you will find it useful !

  • Suggestion: there should be separate dividers for hierarchies and multi-word options within the same hierarchy

    Suggestion: there should be separate dividers for hierarchies and multi-word options within the same hierarchy

    For example

    type Multi struct {
    	Word Word
    }
    
    type Word struct {
    	String string
    }
    
    type Config struct {
    	Multi     *Multi
    	MultiWord *Word
    }
    

    This sort of config results in both of those options being turned into the flag multi-word-string . This causes some issues when sflags is used in combination with config file parsing libraries because it's impossible to automatically determine if multi-word-string is multi.word.string or multi-word.string.

  • Fix go.mod path

    Fix go.mod path

    The go.mod path is incorrect which causes this error when running go mod tidy:

    	github.com/octago/sflags/gen/gcli: github.com/octago/[email protected]: parsing go.mod:
    	module declares its path as: github.com/sflags
    	        but was required as: github.com/octago/sflags
    
  • Fix go module name

    Fix go module name

    It looks like there was a typo in the go module name introduced in #19:

    $ go get -u github.com/octago/sflags
    go: github.com/octago/sflags upgrade => v0.3.0                                          
    go get: github.com/octago/[email protected]: parsing go.mod:                                                                                                                        
            module declares its path as: github.com/sflags                                                                                                                          
                    but was required as: github.com/octago/sflags     
    

    Note that we'll need to tag a new version after merging this PR.

  • ast flagset parser to generate sflags structs

    ast flagset parser to generate sflags structs

    Hi,

    Hope you are all well !

    I am using amalgomate, a go tool for combining multiple different main packages into a single program or library, and I would like to export flags from repacked packages and wrap them with your package, so I can get more details info while printing the help of the repacked package. (Feature actually missing in the current amalgomate version)

    Is there a tool allowing to convert a flagset from a package by parsing the ast in order to insert a sflags structs and import your package ?

    It could be done here: https://github.com/palantir/amalgomate/blob/master/amalgomate/astfuncs.go#L121-L133

    Thanks for any insights.

    Cheers, Rosco

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
Automatically sets up command line flags based on struct fields and tags.
Automatically sets up command line flags based on struct fields and tags.

Commandeer Commandeer sets up command line flags based on struct fields and tags. Do you... like to develop Go apps as libraries with tiny main packag

Dec 1, 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
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
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
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
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
Query, update and convert data structures from the command line. Comparable to jq/yq but supports JSON, TOML, YAML, XML and CSV with zero runtime dependencies.
Query, update and convert data structures from the command line. Comparable to jq/yq but supports JSON, TOML, YAML, XML and CSV with zero runtime dependencies.

dasel Dasel (short for data-selector) allows you to query and modify data structures using selector strings. Comparable to jq / yq, but supports JSON,

Jan 2, 2023
Flag is a simple but powerful command line option parsing library for Go support infinite level subcommand

Flag Flag is a simple but powerful commandline flag parsing library for Go. Documentation Documentation can be found at Godoc Supported features bool

Sep 26, 2022
Struct-based argument parsing in Go
Struct-based argument parsing in Go

go-arg Struct-based argument parsing for Go Declare command line arguments for your program by defining a struct. var args struct { Foo string Bar b

Jan 8, 2023
Go library for Parsing Ansible inventory files

aini Go library for Parsing Ansible inventory files. We are trying to follow the logic of Ansible parser as close as possible. Documentation on ansibl

Jan 5, 2023
elf binary parsing utility written in Go.

What is it ? go-readelf is a small elf binary parser currently capable of printing relocation entries, elf header, sections and Symbols. It utilizes G

Nov 9, 2022
Package varflag implements command-line flag parsing into vars.Variables for easy type handling with additional flag types.

varflag Package flag implements command-line flag parsing into vars.Variables for easy type handling with additional flag types. varflag Flags String

Aug 2, 2022
Rdelf2json - CLI application for parsing ELF and converting to json

rdelf2json CLI application for parsing ELF and converting to json Install go ins

Jan 22, 2022
🚀 Platform providing a powerful and fast public script parsing API dedicated to the Skript community.

SkriptMC-Parser is currently a prototype in the early stages of development of a system that allows the Skript community to test their scripts via a public API for potential errors or warnings. This is a quick and easy way to check your scripts without having to set up a Spigot server on your environment.

Mar 3, 2022
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
Generate High Level Cloud Architecture diagrams using YAML syntax.
Generate High Level Cloud Architecture diagrams using YAML syntax.

A commandline tool that generate High Level microservice & serverless Architecture diagrams using a declarative syntax defined in a YAML file.

Dec 24, 2022
A CLI Tool to easily generate your Terraform configuration

Tf Tf is a command line tool to easily generate your Terraform configuration with an interactive prompt. Inspiration Boredom in Covid-19 Installation

Sep 30, 2022
Generate Changelogs from Commits (CLI)

Commitlog Changelog generator using Commit History To see an example of this in action, you can check the actions file for this repo. Yes it uses itse

Sep 30, 2022