Coder Social home page Coder Social logo

flagutil's Introduction

flagutil

GoDoc Travis

A library to populate flag.FlagSet from various sources.

Features

  • Uses standard flag package
  • Structured configuration
  • Reads values from multiple sources
  • Ability to write your own parser

Why

Defining your program parameters and reading their values should be as simple as possible. There is no reason to use some library or even monstrous framework instead of standard flag package.

There is Configuration in Go article, which describes in detail the reasons of creating this library.

Usage

package main

import (
	"flag"

	"github.com/gobwas/flagutil"
	"github.com/gobwas/flagutil/parse/pargs"
	"github.com/gobwas/flagutil/parse/file/json"
)

func main() {
	flags := flag.NewFlagSet("my-app", flag.ExitOnError)
	
	// Define top level parameters.
	var port int
	flag.IntVar(&port,
		"port", "port",
		"port to bind to",
	)

	// Now define parameters for some third-party library.
	var endpoint string
	flagutil.Subset(flags, "database", func(sub *flag.FlagSet) {
		sub.StringVar(&endpoint,
			"endpoint", "localhost",
			"database endpoint to connect to"
		)
	})
	
	// This flag will be required by the file.Parser below.
	flags.String(
		"config", "/etc/app/config.json", 
		"path to configuration file",
	)

	flagutil.Parse(flags,
		// First, use posix options syntax instead of `flag` – just to
		// illustrate that it is possible.
		flagutil.WithParser(&pargs.Parser{
			Args: os.Args[1:],
		}),	

		// Then lookup for "config" flag value and try to parse its value as a
		// json configuration file.
		flagutil.WithParser(
			&file.Parser{
				Lookup: file.LookupFlag(flags, "config"),
				Syntax: new(json.Syntax),
			},
			// Don't allow to setup "config" flag from file.
			flagutil.WithIgnoreByName("config"),
		),
	)

	// Work with received values.
}

The configuration file may look as follows:

{
  "port": 4050,
  
  "database": {
    "endpoint": "localhost:5432",
  }
}

And, if you want to override, say, database endpoint, you can execute your program as follows:

$ app --config config.json --database.endpoint 4055

Available parsers

Note that it is very easy to implement your own Parser.

At the moment these parsers are already implemented:

  • Flag syntax arguments parser
  • Posix program arguments syntax parser
  • Environment variables parser
  • File parsers:
    • json
    • yaml
    • toml

Conventions and limitations

Any structure from parsed configuration is converted into a pairs of a flat key and a value. Keys are flattened recursively until there is no such flag defined within flag.FlagSet.

Keys flattening happens just as two keys concatenation with . as a > delimiter.

There are three scenarios when the flag was found:

  1. If value is a mapping or an object, then its key-value pairs are concatenated with : as a delimiter and are passed to the flag.Value.Set() in appropriate number of calls.

  2. If value is an array, then its items are passed to the flag.Value.Set() in appropriate number of calls.

  3. In other way, flag.Value.Set() will be called once with value as is.

Note that for any type of values the flag.Value.String() method is never used to access the "real" value – only for defaults when printing help message. To provide "real" value implementations must satisfy flag.Getter interface.

Suppose you have this json configuration:

{
  "foo": {
    "bar": "1",
    "baz": "2"
  }
}

If you define foo.bar flag, you will receive "1" in a single call to its flag.Value.Set() method. No surprise here. But if you define foo flag, then its flag.Value.Set() will be called twice with "bar:1" and "baz:2".

The same thing happens with slices:

{
  "foo": [
    "bar",
    "baz"
  ]
}

Your foo's flag.Value.Set() will be called twice with "bar" and "baz".

This still allows you to use command line arguments to override or declare parameter complex values:

$ app --slice 1 --slice 2 --slice 3 --map foo:bar --map bar:baz

Misc

Creation of this library was greatly inspired by peterburgon/ff – and I wouldn't write flagutil if I didn't met some design disagreement with it.

flagutil's People

Contributors

gobwas 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.