Coder Social home page Coder Social logo

admiral's Introduction

Admiral

Flags & Commands

Command line arguments parser for humans.

TL;DR

type Conf struct {
	Version bool `type:"flag" name:"version" alias:"v" description:"Show version"`

	Network  string `type:"flag" name:"network" alias:"n" description:"Network in CIDR format" required:"true"`
	Confpath string `type:"flag" name:"conf" alias:"c" description:"Path to config file" default:"/etc/app.conf"`
	ServeFolder string `type:"arg" name:"servefolder" description:"Folder containing files to serve"`

	Start Start `type:"command" name:"start" description:"Start the app in detached mode"`
	Stop  Stop  `type:"command" name:"stop" description:"Stop the app"`
}

type Start struct {
	Network  string `type:"flag" name:"network" alias:"n" description:"Network in CIDR format" required:"true"`
	Logfile  string `type:"flag" name:"logfile" alias:"l" description:"Logfile path" default:"/var/log/app.log"`
	Confpath string `type:"flag" name:"conf" alias:"c" description:"Path to config file" default:"/etc/app.conf"`
	ServeFolder string `type:"arg" name:"servefolder" description:"Folder containing files to serve"`
}

type Stop struct{}

func main() {
	cli := admiral.New("myapp", "My app")
	conf := Conf{}
	cli.Configure(&conf)
	cli.Flag("version").Handle(func(value interface{}) {
		fmt.Println("Version 1.0.0")
		os.Exit(0)
	})

	_, err := cli.Parse(os.Args)
	if err != nil {
		fmt.Printf("Error: %s\n", err)
		os.Exit(1)
	}

	fmt.Printf("%+v\n", conf)
}

Core concepts

Command

Entity representing commands or subcommand of application

Admiral

Root command represnting the binary

Arg

Positinal argument of a command

Flag

Flag (argument with '--' or '-' prefix) of a command

Usage

First thing to do is to initialize admiral instance:

cli := admiral.New("myApp", "My App")

Here first argument is an entryopoint name and second is application description. Both are used in help message.

Configuring using struct

You can use structs to configure the parser:

type Conf struct {
	Host   string      `type:"flag" name:"host" alias:"h" description:"Host to listen on" required:"true"`
	Port   int         `type:"flag" name:"port" alias:"p" description:"Port to listen on" default:"8080"`
	ServeFolder string `type:"arg" name:"servefolder" description:"Folder containing files to serve" required:"true" pos:"0"`
	Listen ListenSubcommand `type:"command" name:"listen" description:"Listen specified host and port"`
}

Each entity is defined using tags. The tags are:

  • type - defines entity type: flag, arg, command.

  • name - entity name.

    For flags acts like a long name when using in cli. For type:"flag" name:"example" flag is available as --example.

    For commands define callable name of the command. For type:"command" name:"example" command is used like app example.

    For arguments name appear in help message.

  • alias - Flag alias.

  • description - Entity description. Appear in help message.

  • required - Is flag or argument required or not for this command.

  • default - Default value for flag.

  • pos - Positional argument's position starting from 0. If used for one argument, should be used for all. Flag data type is recognized automatically based on property type. Argument property must have string type.

After defining structure make variable of it:

conf := &Conf{}

Then call Configure method:

cli.Configure(conf)

Then call Parse method:

rest, err := cli.Parse(os.Args)

rest variable contains all cli argument that were not parsed for some reason. Use conf variable to access parsed data.

Configuring subcommands

To configure subcommand you can use structs with same structure as root struct.

type Conf struct {
	Listen Listen `type:"command" name:"listen" description:"Listen specified host and port"`
}

type Listen struct {
	Host   string     `type:"flag" name:"host" alias:"h" description:"Host to listen on" required:"true"`
	Port   int        `type:"flag" name:"port" alias:"p" description:"Port to listen on" default:"8080"`
	ServeFolder string `type:"arg" name:"servefolder" description:"Folder containing files to serve" required:"true" pos:"0"`
}

Configuring using methods

It's also possible to configure using methods instead of using structs:

cli := admiral.New("myApp", "My App")
cli.AddFlag("host", "h", "Host to listen on").SetType("string").SetRequired(true)
cli.AddFlag("port", "p", "Port to listen on").SetType("int").SetDefault("8080")
cli.AddArg("servefolder", "Folder containing files to serve").SetRequired(true)

cli.AddCommand("listen")

cli.Command("listen").
	AddFlag("host", "h", "Host to listen on").
	SetDataType("string").
	SetRequired(true)

cli.Command("listen").
	AddFlag("port", "p", "Port to listen on").
	SetType("int").
	SetDefault("8080")

cli.Command("listen").
	AddArg("servefolder", "Folder containing files to serve").
	SetRequired(true)

After parsing arguments:

rest, err := cli.Parse(os.Args)

You can access result by using .Is and .Value properties. .Is stands for entity presence in arguments. .Value contains actual value.

if !cli.Command("listen").Is {
	host := cli.Flag("host").Value
	port := cli.Flag("port").Value
	folder := cli.Arg("servefolder").Value
} else {
	host := cli.Command("listen").Flag("host").Value
	port := cli.Command("listen").Flag("port").Value
	folder := cli.Command("listen").Arg("servefolder").Value
}

Adding handlers

You can add handle callback to each entity:

cli.Flag("version").Handle(func (_ interface{}) {
	fmt.Println("1.0.0")
	os.Exit(0)
})

cli.Command("listen").Handle(func (opts interface{}) {
	ctx := opts.(*Listen)
	host := ctx.Host
	port := ctx.Port
})

The callback argument contains entity value after parsing. For positional arguments, callback argument has string type. For flags and commands it's interface{}. You need to downcast it manually.

admiral's People

Contributors

trueaniki avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.