settings
A small, concurrency-safe Go package to load simple key/value configuration files and keep them updated automatically.
Package: settings
Quick overview
- What it does: Parses simple text files containing key/value pairs and stores them in a thread-safe in-memory map. It can watch the file (via a background goroutine) and refresh values when the file on disk changes.
- File format: Each non-empty, non-comment line must contain a key and a value separated by a delimiter (
:or=). Lines beginning with//or#are treated as comments and ignored.
Key features
- Automatic updates: A background maintenance goroutine periodically calls
Update()to reload the file when it changes. - Thread-safe: All exported methods on
Settingsuse mutexes or atomic flags where appropriate. - Simple scanner: The
scannerreads lines, supports comments and a small set of delimiters, and returns clear errors for malformed lines.
Installation
This package is part of the current module. To run tests or use it, ensure your module is initialized (see go.mod) and import it using the module path where it's hosted, e.g.:
import "your/module/path/settings"
Replace your/module/path with your module path.
Public API
func NewSettings(filename string, logUpdates bool) *Settings— create aSettingsinstance usingcontext.Background(); starts the background maintenance goroutine.func NewSettingsWithContext(ctx context.Context, filename string, logUpdates bool) *Settings— same as above but accepts acontext.Contextto control lifecycle (cancellation stops the maintenance goroutine).func (s *Settings) GetFilename() string— returns the current filename.func (s *Settings) SetFilename(filename string) (updated bool)— atomically change the filename and attempt an immediate update; returns true if filename changed.func (s *Settings) SetKeyValue(key, value string) (updated bool)— set a key/value pair in the in-memory map (returns whether it changed).func (s *Settings) ContainsKey(key string) bool— returns whether a key exists.func (s *Settings) GetKeyValue(key string) string— returns the value for a key (empty string if not present).func (s *Settings) Update() error— force a synchronous update from the current filename; returns an error on IO problems.
Constants / package variables
MaintenanceRoutinePace(time.Duration) — pacing for the background maintenance goroutine (defaulttime.Second).WarnIfFileNotFound(bool) — when true, log messages for missing files even if they areos.ErrNotExist.
Scanner details
KeyValueDelimiterChars— allowed delimiter bytes (default':'and'=').ErrNoValidDelimiter— returned when a non-comment non-empty line doesn't contain a valid delimiter.LineIsComment(line string) bool— returns true for lines starting with//or#.
File format example
Valid settings file contents:
// comments allowed
# another comment
host: localhost
port = 8080
mode: production
Notes on behavior
- When created,
NewSettings*immediately attempts an initial load. If the file doesn't exist or another IO error occurs, an error is logged but aSettingsinstance is still returned. - The background maintenance goroutine invokes
Update()everyMaintenanceRoutinePace. UseNewSettingsWithContextand pass a cancellable context to stop the goroutine when you no longer need theSettingsinstance. SetFilenamewill attempt to read the new file immediately. If reading fails an error may be logged depending onWarnIfFileNotFound.LogUpdatesis anatomic.Boolon theSettingsstruct; set totrueif you want the package to log add/update operations for keys.
Examples
Create and use Settings:
ctx := context.Background()
settings := settings.NewSettingsWithContext(ctx, "config.settings", false)
// read a value
if settings.ContainsKey("host") {
host := settings.GetKeyValue("host")
fmt.Println("host =", host)
}
// change the file being used
settings.SetFilename("other.settings")
// programmatically set a value
settings.SetKeyValue("local_only", "true")
// force a synchronous reload
if err := settings.Update(); err != nil {
log.Printf("update error: %v", err)
}
Running tests
From the repository root run:
go test ./...
This package includes unit tests for both the scanner and the Settings behaviors (see scanner_test.go and settings_test.go).
Contributing / License
This repository is licensed under the MIT License. See the LICENSE file in the project root for the full text.
Summary: Copyright (c) 2025 William Dillon — permission is granted to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to the
conditions in the LICENSE. The software is provided "AS IS", without warranty of any kind.
Questions
If you want any additional examples, a different README layout, or embedded documentation for each exported symbol, tell me which format you prefer and I will update the file.