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

Flag

GoDoc

Flag is a simple but powerful commandline flag parsing library for Go.

Documentation

Documentation can be found at Godoc

Supported features

  • bool
    • -f, -f=false, -f=true, there is no -f true and -f false to avoid conflicting with positional flag and non-flag values
  • string,number
    • -f a.go -n 100
  • slice:
    • -f a.go -f b.go -f c.go
  • hint flag as value
    • -- to hint next argument is value: rm -- -a.go, rm -- -a.go -b.go will throws error for -b.go is invalid flag
    • --* to hint latter all arguments are value: rm -- -a.go -b.go -c.go
  • useful tricks:
    • -f a.go, -f=a.go, --file=a.go
    • -zcf=a.go, -zcf a.go
    • -I/usr/include: only works for -[a-zA-Z][^a-zA-Z].+
  • catch non-flag arguments:
    • rm -rf a.go b.go c.go, catchs [a.go, b.go, c.go]
  • positional flag:
    • cp -f src.go dst.go, catchs SOURCE=a.go DESTINATION=dst.go
    • This is implemented as a special case of non-flag arguments, positional flags will be applied first, and remain values
  • value apply/checking
    • default value
    • environment value
    • value list for user selecting
  • multiple flag names for one flag
  • subcommand.

Definition via structure field tag

  • names: flag/command names, comma-speparated, default uses camelCase of field name(with a - prefix for flag)

    • - to skip this field
    • @ to indicate that this is a positional flag
    • support multiple name and formats: eg: `-f, --file, -file'
  • arglist: argument list for command or argument name for flag

    • for positional flag, this will also be used as it's display name if defined, otherwise field name is used.
    • command example: eg: [OPTION]... SOURCE DESTINATION, or [FLAG]... FILE [ARG}...
    • flag example: eg: 'FILE', 'DESTINATION'
  • version: version message for command

  • usage: short description

  • desc: long description

  • env: environment name for flag, if user doesn't passed this flag, environment value will be used

  • default: default value for flag, if user doesn't passed this flag and environment value not defined, it will be used

  • args: used to catching non-flag arguments, it's type must be []string

  • special cases

    • Enable, there must be a Enable field inside command to indicate whether user are using this command.
    • Args: this field will be used to store non-flag arguments if args tag is not defined
    • Metadata: structure could implement this interface to override settings defined by tags
      type Metadata interface {
          // the key is comma-separated flag name to find command/flag,
          // each component represents a level, "" represents root command
          Metadata() map[string]Flag
      }

Example

Flags

package flag

import "fmt"

type Tar struct {
	GZ          bool     `names:"-z, --gz" usage:"gzip format"`
	BZ          bool     `names:"-j, --bz" usage:"bzip2 format"`
	XZ          bool     `names:"-J, --xz" usage:"xz format"`
	Create      bool     `names:"-c" usage:"create tar file"`
	Extract     bool     `names:"-x" usage:"extract tar file"`
	File        string   `names:"-f" usage:"output file for create or input file for extract"`
	Directory   string   `names:"-C" usage:"extract directory"`
	SourceFiles []string `args:"true"`
}

func (t *Tar) Metadata() map[string]Flag {
	const (
		usage   = "tar is a tool for manipulate tape archives."
		version = `
			version: v1.0.0
			commit: 10adf10dc10
			date:   2017-01-01 10:00:01
		`
		desc = `
		tar creates and manipulates streaming archive files.  This implementation can extract
		from tar, pax, cpio, zip, jar, ar, and ISO 9660 cdrom images and can create tar, pax,
		cpio, ar, and shar archives.
		`
	)
	return map[string]Flag{
		"": {
			Usage:   usage,
			Version: version,
			Desc:    desc,
		},
		"--gz": {
			Desc: "use gzip format",
		},
	}
}

func ExampleFlagSet_ParseStruct() {
	var tar Tar

	NewFlagSet(Flag{}).ParseStruct(&tar, "tar", "-zcf", "a.tgz", "a.go", "b.go")
	fmt.Println(tar.GZ)
	fmt.Println(tar.Create)
	fmt.Println(tar.File)
	fmt.Println(tar.SourceFiles)

	// Output:
	// true
	// true
	// a.tgz
	// [a.go b.go]
}

Help message

tar is a tool for manipulate tape archives.

Usage:
      flag.test [FLAG]...

Version:
      version: v1.0.0
      commit: 10adf10dc10
      date:   2017-01-01 10:00:01

Description:
      tar creates and manipulates streaming archive files.  This implementation can extract
      from tar, pax, cpio, zip, jar, ar, and ISO 9660 cdrom images and can create tar, pax,
      cpio, ar, and shar archives.

Flags:
      -z, --gz     gzip format (bool)
            use gzip format
      -j, --bz     bzip2 format (bool)
      -J, --xz     xz format (bool)
      -c           create tar file (bool)
      -x           extract tar file (bool)
      -f           output file for create or input file for extract (string)
      -C           extract directory (string)

FlagSet

type GoCmd struct {
	Build struct {
		Enable  bool
		Already bool   `names:"-a" important:"1" desc:"force rebuilding of packages that are already up-to-date."`
		Race    bool   `important:"1" desc:"enable data race detection.\nSupported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64."`
		Output  string `names:"-o" arglist:"output" important:"1" desc:"only allowed when compiling a single package"`

		LdFlags  string   `names:"-ldflags" arglist:"'flag list'" desc:"arguments to pass on each go tool link invocation."`
		Packages []string `args:"true"`
	} `usage:"compile packages and dependencies"`
	Clean struct {
		Enable bool
	} `usage:"remove object files"`
	Doc struct {
		Enable bool
	} `usage:"show documentation for package or symbol"`
	Env struct {
		Enable bool
	} `usage:"print Go environment information"`
	Bug struct {
		Enable bool
	} `usage:"start a bug report"`
	Fix struct {
		Enable bool
	} `usage:"run go tool fix on packages"`
	Fmt struct {
		Enable bool
	} `usage:"run gofmt on package sources"`
}

func (*GoCmd) Metadata() map[string]Flag {
	return map[string]Flag{
		"": {
			Usage:   "Go is a tool for managing Go source code.",
			Arglist: "command [argument]",
		},
		"build": {
			Arglist: "[-o output] [-i] [build flags] [packages]",
			Desc: `
		Build compiles the packages named by the import paths,
		along with their dependencies, but it does not install the results.
		...
		The build flags are shared by the build, clean, get, install, list, run,
		and test commands:
			`,
		},
	}
}

func TestSubset(t *testing.T) {
	var g GoCmd

	set := NewFlagSet(Flag{})
	set.StructFlags(&g)
	set.Help(false)
	fmt.Println()
	build, _ := set.FindSubset("build")
	build.Help(false)
}

##Help Message

Go is a tool for managing Go source code.

Usage:
      flag.test command [argument]

Sets:
      build        compile packages and dependencies
      clean        remove object files
      doc          show documentation for package or symbol
      env          print Go environment information
      bug          start a bug report
      fix          run go tool fix on packages
      fmt          run gofmt on package sources
compile packages and dependencies

Usage:
      build [-o output] [-i] [build flags] [packages]

Description:
      Build compiles the packages named by the import paths,
      along with their dependencies, but it does not install the results.
      ...
      The build flags are shared by the build, clean, get, install, list, run,
      and test commands:

Flags:
      -a                  
            force rebuilding of packages that are already up-to-date.
      -race               
            enable data race detection.
            Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
      -o output           
            only allowed when compiling a single package

      -ldflags 'flag list'
            arguments to pass on each go tool link invocation.

LICENSE

MIT.

Comments
  • Add positional tag

    Add positional tag

    Is a good idea add a tag for setting postitional arguments. For example:

    type Args struct {
    	Version string `names:"-v" usage:"Version"`
    	Pos     string `names:"positional" positional:"true" usage"positional flag"`
    }
    

    Result would be:

    Usage:
        cmd [FLAG] [positional]...
    
    Flags:
          -v               Version
          -h, --help   show help
    
    Positional flags:
        positional    positional flag
    
  • How to end greedy-consume arguments?

    How to end greedy-consume arguments?

    Given:

    type flags struct {
       Something []string `names:"-s" usage:"pass in something(s)"`
       Rest      []string `args:"true"`
    }
    

    how does the user end the greedy consumption of -s and provide non-flag arguments? E.g., a common pattern in flag parsing libraries requires multi-value argument flags to be specified once for each argument:

    cmd -s A -s B -s C XYZ
    

    would produce len(a.Something) == 3 and a.Rest == []string{"XYZ"}. If multi-value arguments are greedy, len(a.Something) == 4 and a.Rest == []string{}.

    How does a user pass in arguments to Rest with greedy consumption?

  • Does this support implied flags, like tar?

    Does this support implied flags, like tar?

    '-' to ensure next argument must be a flag

    That seems to imply that implied flags will work here the same as they do with tar:

    tar -xvf test.tar.gz
    tar xvf test.tar.gz
    

    Is that true?

  • 4 level deep struct breaks again on the latest commit.

    4 level deep struct breaks again on the latest commit.

    Works here: https://github.com/cosiner/flag/commit/d92f27aedc79cc2b1cfc52a23b07d9ab408775dc

    Stop working here: https://github.com/cosiner/flag/commit/e5854e42cd87a32f1a8a21b006033b66dde8ca60

    Example config struct:

    type Arguments struct {
        Config string `names:"-c" default:"." desc:"Path to config directory"`
    
        Index struct {
            Enable bool
    
            Full struct {
                Enable bool
    
                List struct {
                    Enable   bool
                    Unsynced bool `names:"--unsynced" default:"false" desc:"Display only unsynced metric indices"`
                }
    
                Syncto struct {
                    Enable bool
    
                    Storage struct {
                        Enable   bool
                        Unsynced bool `names:"--unsynced" default:"false" desc:"Sync only unsynced metric indices"`
                    }
                }
            }
    
            Short struct {
                Enable bool
    
                List struct {
                    Enable   bool
                    Unsynced bool `names:"--unsynced" default:"false" desc:"Display only unsynced metric indices"`
                }
    
                Syncto struct {
                    Enable bool
    
                    Storage struct {
                        Enable   bool
                        Unsynced bool `names:"--unsynced" default:"false" desc:"Sync only unsynced metric indices"`
                    }
                }
            }
        }
    }
    

    Error:

    go run main.go index short syncto storage
    StandaloneValue: standalone value without flag: [main index short syncto] storage
    
  • How deep can I nest the structs?

    How deep can I nest the structs?

    It looks like the 3rd nested structs aren't visible. Example:

    type Arguments struct {
    	Index struct {
    		Enable bool
    
    		Full struct {
    			Enable bool
    
    			// This is not visible
    			List struct {
    				Enable bool
    			}
    
    			// This is not visible as well
    			Syncto struct {
    				Enable bool
    
    				Cassandra struct {
    					Enable bool
    					All    bool `names:"--all" default:"true" desc:"Just sync everything from Redis to Cassandra"`
    				}
    			}
    		}
    	}
    }
    

    This is the error I got:

    go run -race main.go index full list
    StandaloneValue: standalone value without flag: [main index full] list
    
  • Changes the behavior of multi-value arguments

    Changes the behavior of multi-value arguments

    This change causes flag to follow common POSIX behavior of requiring flags to be specified once for each argument, rather than having mvalue flags greedily consume all arguments that follow. This means that:

    type F struct {
       A []string `name:"-a"`
       B []string `args:"true"`
    }
    

    called with:

    k := F{}
    flags.NewFlagSet(Flag{}).ParseStruct(&k, "cmd", "-a", "B", "C", "D")
    

    results in:

    F{ A: []string{"B"}, B: []string{"C", "D"} }
    

    rather than

    F{ A: string{"B", "C", "D"}, B: []string{} }
    

    To pass multiple values for -a, call -a multiple times. This follows standard POSIX convention as seen in standard tools such as gcc, find, and other GNU tools.

  • Unable to have negative value

    Unable to have negative value

    This should work: go run main.go logs --from "-1d" /var/log/messages

    But it doesn't. Here's the error log:

    StandaloneFlag: standalone flag without values: [main logs].--from
    
  • Make examples executable directly

    Make examples executable directly

    Hi!

    Thanks for writing and sharing this useful args parsing library!

    As I'm still learning Go, it took me some time to make the provided examples work. I propose the apply in README.md the changes I had to make in order to make them work on my end, hoping that it would also help other potential users of your module.

    Best regards,

    Adrien

Fully featured Go (golang) command line option parser with built-in auto-completion support.

go-getoptions Go option parser inspired on the flexibility of Perl’s GetOpt::Long. Table of Contents Quick overview Examples Simple script Program wit

Dec 14, 2022
Golang library with POSIX-compliant command-line UI (CLI) and Hierarchical-configuration. Better substitute for stdlib flag.
Golang library with POSIX-compliant command-line UI (CLI) and Hierarchical-configuration. Better substitute for stdlib flag.

cmdr cmdr is a POSIX-compliant, command-line UI (CLI) library in Golang. It is a getopt-like parser of command-line options, be compatible with the ge

Oct 28, 2022
A wrapper of aliyun-cli subcommand alidns, run aliyun-cli in Declarative mode.

aliyun-dns A wrapper of aliyun-cli subcommand alidns, run aliyun-cli in Declarative mode. Installation Install aliyun-cli. Usage $ aliyun-dns -h A wra

Dec 21, 2021
CONTRIBUTIONS ONLY: A Go (golang) command line and flag parser

CONTRIBUTIONS ONLY What does this mean? I do not have time to fix issues myself. The only way fixes or new features will be added is by people submitt

Dec 29, 2022
go command line option parser

go-flags: a go library for parsing command line arguments This library provides similar functionality to the builtin flag library of go, but provides

Jan 4, 2023
Go binding configuration and command flag made easy✨✨
Go binding configuration and command flag made easy✨✨

✨ Binding configuration and command flag made easy! ✨ You can use multiple keys tag to simplify the look like this (supported feature**): // single ta

Sep 18, 2022
InfiniMaze : an infinite, persistent, procedurally generated, explorable maze

InfiniMaze : an infinite, persistent, procedurally generated, explorable maze

Dec 9, 2021
🚀 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
A very simple library for interactively selecting an option on a terminal
A very simple library for interactively selecting an option on a terminal

go-choice A very simple library for interactively selecting an option on a terminal Usage package main import ( "fmt" "github.com/TwiN/go-ch

Dec 30, 2021
The standard library flag package with its missing features

cmd Package cmd is a minimalistic library that enables easy sub commands with the standard flag library. This library extends the standard library fla

Oct 4, 2022
A lightweight but powerful OCR tool.
A lightweight but powerful OCR tool.

这个项目是什么? LOCR(Lightweight OCR)是一款轻量级的文字识别工具, 结合第三方截图工具, 可以快速的对图片文字进行识别。 为什么有这个项目 在日常学习的工作中, 难免会遇到一些文字的复制粘贴任务。但由于一些限制,我们无法复制想要的文字,只能一个字一个字的敲出来。而随着近几年OC

Nov 1, 2022
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 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
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
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
Argparse for golang. Just because `flag` sucks

Golang argparse Let's be honest -- Go's standard command line arguments parser flag terribly sucks. It cannot come anywhere close to the Python's argp

Dec 28, 2022
A collection of CLI argument types for the Go `flag` package.

flagvar A collection of CLI argument types for the flag package. import "github.com/sgreben/flagvar" Or just copy & paste what you need. It's public d

Sep 26, 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
Option container for golang

Option Option provides an Option container which can be used to force some addit

Dec 21, 2021