Simple INI is a Go library for parsing INI files using reflection. It provides a simple and flexible way to map INI file keys to Go struct fields.
This project is currently in active development and may undergo significant changes. Use at your own risk.
To install Simple INI, use go get
:
go get github.com/BenBurnett/simpleini
An example usage of Simple INI can be found in the example
folder. This example demonstrates how to define a struct with ini
tags and parse an INI file into that struct.
By default, Simple INI maps snake_case keys in the INI file to PascalCase field names in the Go struct. For example, the key app_name
in the INI file will map to the field AppName
in the Go struct.
app_name = MyApp
app_version = 1.0.0
type AppConfig struct {
AppName string
AppVersion string
}
You can override the implicit name mapping by using struct tags. For example, if you want the key ip_address
in the INI file to map to the field IP
in the Go struct, you can use the following struct tag:
ip_address = 192.168.1.1
server_name = MyServer
maximum_connections = 100
type ServerConfig struct {
IP *net.IP `ini:"ip_address"`
ServerName string
MaxConnections int `ini:"maximum_connections"`
}
You can specify default values for fields using the default
struct tag. These values will be used if the corresponding key is not present in the INI file.
app_name = MyApp
type AppConfig struct {
AppName string `default:"DefaultApp"`
AppVersion string `default:"1.0.0"`
}
Simple INI supports comments. Lines starting with ;
or #
are treated as comments and ignored.
; This is a comment
# This is also a comment
app_name = MyApp
You can specify a custom delimiter for key-value pairs in the INI file. By default, the delimiter is =
.
app_name: MyApp
app_version: 1.0.0
type AppConfig struct {
AppName string
AppVersion string
}
var config AppConfig
simpleini.SetDelimiter(":")
err := simpleini.Parse(strings.NewReader(iniData), &config)
if err != nil {
log.Fatal(err)
}
fmt.Println(config.AppName) // Output: MyApp
fmt.Println(config.AppVersion) // Output: 1.0.0
Simple INI supports sections and subsections in the INI file. Sections are defined using square brackets, and subsections can be defined using dot notation. Sections can contain alphanumeric characters, underscores, and dots, while keys can only contain alphanumeric characters and underscores.
app_name = MyApp
app_version = 1.0.0
[database]
host = localhost
port = 5432
[server]
ip_address = 192.168.1.1
[server.logging]
level = debug
[server.logging.file]
path = /var/log/myapp.log
type DatabaseConfig struct {
Host string
Port int
}
type FileLoggingConfig struct {
Path string
}
type LoggingConfig struct {
Level string
File FileLoggingConfig
}
type ServerConfig struct {
IPAddress string
Logging LoggingConfig
}
type Config struct {
AppName string
AppVersion string
Database DatabaseConfig
Server ServerConfig
}
Simple INI supports custom types that implement the encoding.TextUnmarshaler
interface. This allows you to define custom parsing logic for specific fields.
date = 2023-10-01
type CustomDate struct {
time.Time
}
func (d *CustomDate) UnmarshalText(text []byte) error {
parsedTime, err := time.Parse("2006-01-02", string(text))
if err != nil {
return err
}
d.Time = parsedTime
return nil
}
type Config struct {
Date CustomDate
}
Simple INI supports multiline values for strings. A multiline value continues when the next line starts with a space or tab.
description = This is a long description
that spans multiple lines.
type Config struct {
Description string
}
Simple INI supports parsing slices from multiline values in the INI file. A multiline value continues when the next line starts with a space or tab.
servers = server1
server2
server3
type Config struct {
Servers []string `ini:"servers"`
}
Note: A slice of custom types will call the encoding.TextUnmarshaler
for each value. A single custom type will call it with the entire multiline value and can parse it in any way.
Simple INI supports expanding environment variables in values. Environment variables are referenced using the ${VAR_NAME}
syntax.
path = ${HOME}/myapp/config
type Config struct {
Path string
}
Simple INI supports including other INI files using the !include
directive. The included file's content will be parsed as if it were part of the original file.
other_field = i was included
!include other_config.ini
app_name = MyApp
type AppConfig struct {
AppName string
OtherField string
}
This example demonstrates how to use several features of Simple INI, including implicit key name mapping, overriding implicit name mapping, default values, custom types, and environment variable expansion.
app_name = MyApp
app_version = 1.0.0
date = 2023-10-01
[database]
host = localhost
port = 5432
[server]
ip_address = 192.168.1.1
server_name = MyServer
maximum_connections = 100
[server.logging]
level = debug
[server.logging.file]
path = ${HOME}/myapp/logs/app.log
package main
import (
"fmt"
"log"
"os"
"time"
"github.com/BenBurnett/simpleini"
)
type CustomDate struct {
time.Time
}
func (d *CustomDate) UnmarshalText(text []byte) error {
parsedTime, err := time.Parse("2006-01-02", string(text))
if err != nil {
return err
}
d.Time = parsedTime
return nil
}
type DatabaseConfig struct {
Host string
Port int
}
type FileLoggingConfig struct {
Path string
}
type LoggingConfig struct {
Level string
File FileLoggingConfig
}
type ServerConfig struct {
IPAddress string `ini:"ip_address"`
ServerName string `ini:"server_name"`
MaxConnections int `ini:"maximum_connections"`
Logging LoggingConfig
}
type AppConfig struct {
AppName string
AppVersion string
Date CustomDate
Database DatabaseConfig
Server ServerConfig
}
func main() {
file, err := os.Open("config.ini")
if err != nil {
log.Fatal(err)
}
defer file.Close()
os.Setenv("HOME", "/home/user")
var config AppConfig
err = simpleini.Parse(file, &config)
if err != nil {
log.Fatal(err)
}
fmt.Println("AppName:", config.AppName) // Output: MyApp
fmt.Println("AppVersion:", config.AppVersion) // Output: 1.0.0
fmt.Println("Database Host:", config.Database.Host) // Output: localhost
fmt.Println("Database Port:", config.Database.Port) // Output: 5432
fmt.Println("Server IP Address:", config.Server.IPAddress) // Output: 192.168.1.1
fmt.Println("Server Name:", config.Server.ServerName) // Output: MyServer
fmt.Println("Max Connections:", config.Server.MaxConnections) // Output: 100
fmt.Println("Logging Level:", config.Server.Logging.Level) // Output: debug
fmt.Println("Log File Path:", config.Server.Logging.File.Path) // Output: /home/user/myapp/logs/app.log
fmt.Println("Date:", config.Date.Format("2006-01-02")) // Output: 2023-10-01
}
Simple INI returns a slice of errors if any issues are encountered during parsing. You can handle these errors in your code to provide meaningful feedback to the user.
errors := simpleini.Parse(file, &config)
if len(errors) > 0 {
for _, err := range errors {
fmt.Println("Error:", err)
}
}
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
This project is licensed under the MIT License. See the LICENSE file for details.