Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/snaipe/boa
Better configuration management in Go
https://github.com/snaipe/boa
config configuration configuration-management go golang json5 no-dependencies toml
Last synced: 3 months ago
JSON representation
Better configuration management in Go
- Host: GitHub
- URL: https://github.com/snaipe/boa
- Owner: Snaipe
- License: mit
- Created: 2022-01-17T13:51:04.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2023-07-25T11:13:21.000Z (over 1 year ago)
- Last Synced: 2024-06-21T01:19:24.742Z (7 months ago)
- Topics: config, configuration, configuration-management, go, golang, json5, no-dependencies, toml
- Language: Go
- Homepage: https://snai.pe/boa
- Size: 188 KB
- Stars: 2
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
A friendlier viper.
[![Builds](https://img.shields.io/github/workflow/status/Snaipe/boa/Test)](https://github.com/Snaipe/boa/actions/workflows/test.yml)
[![GoDoc](https://godoc.org/snai.pe/boa?status.svg)](https://godoc.org/snai.pe/boa)
[![GitHub](https://img.shields.io/github/license/Snaipe/boa?color=brightgreen)](LICENSE)
[![Dependencies](https://img.shields.io/badge/dependencies-none!-brightgreen)](go.mod)```
go get snai.pe/boa
```## Introduction
Boa aims to be a **simple, human-focused, no-dependency** configuration management library.
It supports **JSON5** and **TOML**.
Configurations are expressed as Go types, using struct field tags to map configuration files
to type-safe data types.For instance, the following TOML configuration file:
```toml
[person]
first-name = "John"
last-name = "Doe"
dob = 1953-02-25T00:00:42-08:00
```Can be loaded into this Go type:
```go
type Config struct {
Person struct {
FirstName string
LastName string
Birth time.Time `name:"dob"`
} `naming:"kebab-case"`
}
```## Why boa?
At the time of writing, none of the other configuration parsers are actually designed
for configuration. Most of the standard parsers under the `encoding` package are
designed for robots. Non-standard parsers either do not follow the same semantics
as the standard packages, or suffer the same flaws as standard parsers. Comments
and formatting are usually not parsed nor preserved. Encoders interact poorly
with other encoders, usually necessitating multiple struct tags per configuration
language, or do not provide a good interface for accessing and discovering
configuration values.Boa aims to be an overall better configuration management library. It has _no_
dependencies outside of the standard Go library, and provides a unified way to load,
manipulate, and save configurations.The following languages are supported:
* JSON5
* TOMLIn addition, all configuration parsers have the following properties:
* Error messages contain the filename when available as well as the line and column
number where the error occured.
* Parsers support the same set of base struct tags for consistency and conciseness.
* Comments and whitespace are preserved by the parsers in the configuration AST,
which makes it possible to edit configuration while still preserving the style
of the original file.## Supported tags
| Tag | Description
|-------------------|-------------
| `name:""` | Set key name.
| `help:""` | Set documentation; appears as comment in the config.
| `naming:""` | Set naming convention for key and subkeys.
| `env:""` | Populate field with specified environment variable.
| `inline` | Inline field. All sub-fields will be treated as if they were in the containing struct itself. Does the same as embedding the field.
| `-` | Ignore field.## Supported types
Any type that implements [`encoding.TextMarshaler`][encoding.TextMarshaler] can be saved as a string.
Any type that implements [`encoding.TextUnmarshaler`][encoding.TextUnmarshaler] can be loaded from a string.In addition, the following standard library types are marshaled and unmarshaled as the appropriate type:
| Type | Treated as |
|----------------------|------------|
| `[]byte` | String |
| `*big.Int` | Number |
| `*big.Float` | Number |
| `*big.Rat` | Number |
| `time.Time` | String |
| `*url.URL` | String |
| `*regexp.Regexp` | String |Some packages also define or support some specialized types for specific configuration objects:
| Type | Treated as | Packages (under `snai.pe/boa/encoding`)
|----------------------|------------|-----------------------------------------
| `time.Time` | DateTime | `toml`
| `toml.LocalDateTime` | DateTime | `toml`
| `toml.LocalDate` | DateTime | `toml`
| `toml.LocalTime` | DateTime | `toml`## Examples
### Loading configuration
```golang
package mainimport (
"fmt"
"log""snai.pe/boa"
)func main() {
var config struct {
Answer int `help:"This is an important field that needs to be 42"`
Primes []int `help:"Some prime numbers"`
Contacts map[string]string `help:"Some people in my contact list"`
}// Will load any matching "appname.toml" config file from the system config path,
// then the user config path. The TOML decoder is inferred from the .toml extension.
//
// For instance, on Linux, this will load in order:
// - /etc/.toml
// - /etc/xdg/.toml
// - ~/.config/.toml
//
if err := boa.Load("appname", &config); err != nil {
log.Fatalln(err)
}}
```### Loading configuration, with defaults
Configuration defaults are not, by design, set via struct tags or other field-specific mechanisms.
Instead, write a default configuration file in your package, and embed it. Multiple configs
defaults can be embedded into the same embed.FS declaration -- see the documentation of
the [embed](https://pkg.go.dev/embed) package.```golang
package mainimport (
"embed"
"fmt"
"log""snai.pe/boa"
)//go:embed appname.toml
var defaults embed.FSfunc main() {
// Register defaults
boa.SetDefaults(defaults)var config struct {
Answer int `help:"This is an important field that needs to be 42"`
Primes []int `help:"Some prime numbers"`
Contacts map[string]string `help:"Some people in my contact list"`
}if err := boa.Load("appname", &config); err != nil {
log.Fatalln(err)
}}
```Good configuration defaults should be consistent and self-explanatory. Consider making
the default for fields their respective type's zero value.### Environment variables
Configuration fields can be explicitly bound to environment variables via the `env` struct tag:
```golang
type Config struct {
Shell string `env:"SHELL"`
Path []string `env:"PATH"`
}
```Environment values are generally parsed according to the strconv Parse functions, or using
UnmarshalText if the field's type implements encoding.TextUnmarshaler.Slices and arrays are parsed as a path-list-separated list of strings. The delimiter
is os.PathListSeparator: with the above example, on Unix derivatives, `PATH=a:b:c` would
get unmarshaled as [a, b, c], while on Windows the value would need to be `PATH=a;b;c`.Fields with no `env` tag are not populated from the environment, unless the AutomaticEnv
option is provided:```golang
type Config struct {
ImplicitVariable string
}boa.SetOptions(
boa.AutomaticEnv("PREFIX"),
)
```In this example, `PREFIX_IMPLICIT_VARIABLE=value` would set `Config.ImplicitVariable`.
## Credits
Logo made by [Irina Mir](https://twitter.com/irmirx)
[encoding.TextMarshaler]: https://pkg.go.dev/encoding#TextMarshaler
[encoding.TextUnmarshaler]: https://pkg.go.dev/encoding#TextUnmarshaler