Skip to content
145 changes: 77 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,85 +1,94 @@
# conf
Package conf provides support for using environmental variables and command
line arguments for configuration.

Simple, self-documenting, struct-driven configuration with flag generation and zero dependencies.
It is compatible with the GNU extensions to the POSIX recommendations
for command-line options. See
http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html

## Overview
`conf` provides a simple method to drive structured configuration from types and fields, with automatic flag and usage generation.
There are no hard bindings for this package. This package takes a struct
value and parses it for both the environment and flags. It supports several tags
to customize the flag options.

## Usage
```go
package main
default - Provides the default value for the help
env - Allows for overriding the default variable name.
flag - Allows for overriding the default flag name.
short - Denotes a shorthand option for the flag.
noprint - Denotes to not include the field in any display string.
required - Denotes a value must be provided.
help - Provides a description for the help.

import (
"log"
"time"
The field name and any parent struct name will be used for the long form of
the command name unless the name is overridden.

"github.com/flowchartsman/conf"
)
As an example, this config struct:
```
type ip struct {
Name string `conf:"default:localhost,env:IP_NAME_VAR"`
IP string `conf:"default:127.0.0.0"`
}
type Embed struct {
Name string `conf:"default:bill"`
Duration time.Duration `conf:"default:1s,flag:e-dur,short:d"`
}
type config struct {
AnInt int `conf:"default:9"`
AString string `conf:"default:B,short:s"`
Bool bool
Skip string `conf:"-"`
IP ip
Embed
}
```
Would produce the following usage output:
```
Usage: conf.test [options] [arguments]

type myConfig struct {
Sub subConfig
TimeToWait time.Duration `conf:"help:how long to wait,short:c,required"`
Password string `conf:"help:the database password to use,noprint"`
DNSServer *string `conf:"help:the address of the dns server to use,default:127.0.0.1"`
Debug bool `conf:"help:enable debug mode"`
DBServers []string `conf:"help:a list of mirror 'host's to contact"`
}
OPTIONS
--an-int/$CRUD_AN_INT <int> (default: 9)
--a-string/-s/$CRUD_A_STRING <string> (default: B)
--bool/$CRUD_BOOL <bool>
--ip-name/$CRUD_IP_NAME_VAR <string> (default: localhost)
--ip-ip/$CRUD_IP_IP <string> (default: 127.0.0.0)
--name/$CRUD_NAME <string> (default: bill)
--e-dur/-d/$CRUD_DURATION <duration> (default: 1s)
--help/-h
display this help message
```

type subConfig struct {
Value int `conf:"help: I am a subvalue"`
}
The API is a single call to `Parse`
```
// Parse(args []string, namespace string, cfgStruct interface{}, sources ...Sourcer) error

func main() {
log.SetFlags(0)
var c myConfig
err := conf.Parse(&c,
conf.WithConfigFile("/etc/test.conf"),
conf.WithConfigFileFlag("conf"))
if err != nil {
log.Fatal(err)
if err := conf.Parse(os.Args, "CRUD", &cfg); err != nil {
log.Fatalf("main : Parsing Config : %v", err)
}
log.Println(conf.String(&c))
}
```

```
$ ./conftest -h
Usage: ./conftest [options] [arguments]
Additionally, if the config struct has a field of the slice type `conf.Args`
then it will be populated with any remaining arguments from the command line
after flags have been processed.

OPTIONS
--db-servers <host>,[host...] DB_SERVERS
a list of mirror hosts to contact
--debug enable debug mode DEBUG
--dns-server <string> DNS_SERVER
the address of the dns server to use
(default: 127.0.0.1)
--password <string> PASSWORD
the database password to use
(noprint)
--sub-value <int> SUB_VALUE
I am a subvalue
--time-to-wait, -c <duration> TIME_TO_WAIT
how long to wait
(required)
--conf filename
the filename to load configuration from
(default: /etc/test.conf)
--help, -h display this help message
For example a program with a config struct like this:

```
var cfg struct {
Port int
Args conf.Args
}
```

FILES
/etc/test.conf
The system-wide configuration file (overridden by --conf)
If that program is executed from the command line like this:

$ ./conftest
required field TimeToWait is missing value
$ ./conftest --time-to-wait 5s --sub-value 1 --password I4mInvisbl3! --db-servers 127.0.0.1,127.0.0.2 --dns-server 1.1.1.1
SUB_VALUE=1 TIME_TO_WAIT=5s DNS_SERVER=1.1.1.1 DEBUG=false DB_SERVERS=[127.0.0.1 127.0.0.2] <nil>
```
$ my-program --port=9000 serve http
```

## note
This library is still in **alpha**. It needs docs, full coverage testing, and poking to find edgecases.
Then the `cfg.Args` field will contain the string values `["serve", "http"]`.
The `Args` type has a method `Num` for convenient access to these arguments
such as this:

## shoulders
This library takes inspiration (and some code) from some great work by some great engineers. These are credited in the license, but more detail soon.
- [kelseyhightower/envconfig](https://github.com/kelseyhightower/envconfig)
- [peterbourgon/ff](https://github.com/peterbourgon/ff)
```
arg0 := cfg.Args.Num(0) // "serve"
arg1 := cfg.Args.Num(1) // "http"
arg2 := cfg.Args.Num(2) // "" empty string: not enough arguments
```
Loading