config

package module
v0.0.0-...-7faca0a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 15, 2026 License: EUPL-1.2 Imports: 12 Imported by: 0

README

Config Module

Go CI codecov

This repository is a config module for the Core Framework. It includes a Go backend, an Angular custom element, and a full release cycle configuration.

Getting Started

  1. Clone the repository:

    git clone https://github.com/Snider/config.git
    
  2. Install the dependencies:

    cd config
    go mod tidy
    cd ui
    npm install
    
  3. Run the development server:

    go run ./cmd/demo-cli serve
    

    This will start the Go backend and serve the Angular custom element.

Building the Custom Element

To build the Angular custom element, run the following command:

cd ui
npm run build

This will create a single JavaScript file in the dist directory that you can use in any HTML page.

Usage

The config service provides a generic way to load and save configuration files in various formats. This is useful for other packages that need to persist their own configuration without being tied to a specific format.

Supported Formats
  • JSON (.json)
  • YAML (.yml, .yaml)
  • INI (.ini)
  • XML (.xml)
Saving Configuration

To save a set of key-value pairs, you can use the SaveKeyValues method. The format is determined by the file extension of the key you provide.

package main

import (
	"log"

	"github.com/Snider/config/pkg/config"
)

func main() {
	// Get a new config service instance
	configSvc, err := config.New()
	if err != nil {
		log.Fatalf("Failed to create config service: %v", err)
	}

	// Example data to save
	data := map[string]interface{}{
		"setting1": "value1",
		"enabled":  true,
		"retries":  3,
	}

	// Save as a JSON file
	if err := configSvc.SaveKeyValues("my-app-settings.json", data); err != nil {
		log.Fatalf("Failed to save JSON config: %v", err)
	}

	// Save as a YAML file
	if err := configSvc.SaveKeyValues("my-app-settings.yaml", data); err != nil {
		log.Fatalf("Failed to save YAML config: %v", err)
	}

	// For INI, keys are typically in `section.key` format
	iniData := map[string]interface{}{
		"general.setting1": "value1",
		"general.enabled":  true,
		"network.retries":  3,
	}
	if err := configSvc.SaveKeyValues("my-app-settings.ini", iniData); err != nil {
		log.Fatalf("Failed to save INI config: %v", err)
	}

	// Save as an XML file
	if err := configSvc.SaveKeyValues("my-app-settings.xml", data); err != nil {
		log.Fatalf("Failed to save XML config: %v", err)
	}
}
Loading Configuration

To load a configuration file, use the LoadKeyValues method. It will automatically parse the file based on its extension and return a map[string]interface{}.

package main

import (
	"fmt"
	"log"

	"github.com/Snider/config/pkg/config"
)

func main() {
	// Get a new config service instance
	configSvc, err := config.New()
	if err != nil {
		log.Fatalf("Failed to create config service: %v", err)
	}

	// Load a JSON file
	jsonData, err := configSvc.LoadKeyValues("my-app-settings.json")
	if err != nil {
		log.Fatalf("Failed to load JSON config: %v", err)
	}
	fmt.Printf("Loaded from JSON: %v\n", jsonData)
	// Note: Numbers from JSON are unmarshaled as float64

	// Load a YAML file
	yamlData, err := configSvc.LoadKeyValues("my-app-settings.yaml")
	if err != nil {
		log.Fatalf("Failed to load YAML config: %v", err)
	}
	fmt.Printf("Loaded from YAML: %v\n", yamlData)
	// Note: Numbers from YAML without decimals are unmarshaled as int

	// Load an INI file
	iniData, err := configSvc.LoadKeyValues("my-app-settings.ini")
	if err != nil {
		log.Fatalf("Failed to load INI config: %v", err)
	}
	fmt.Printf("Loaded from INI: %v\n", iniData)
	// Note: All values from INI are loaded as strings

	// Load an XML file
	xmlData, err := configSvc.LoadKeyValues("my-app-settings.xml")
	if err != nil {
		log.Fatalf("Failed to load XML config: %v", err)
	}
	fmt.Printf("Loaded from XML: %v\n", xmlData)
	// Note: All values from XML are loaded as strings
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the EUPL-1.2 License - see the LICENSE file for details.

Documentation

Overview

Package config provides a configuration management service that handles loading, saving, and accessing application settings. It supports both a main JSON configuration file and auxiliary data stored in various formats like YAML, INI, and XML. The service is designed to be extensible and can be used with static or dynamic dependency injection.

The Service struct is the core of the package, providing methods to interact with the configuration. It manages file paths, default values, and the serialization/deserialization of data.

Basic usage involves creating a new Service instance and then using its methods to get, set, and manage configuration data.

Example:

// Create a new config service.
cfg, err := config.New()
if err != nil {
	log.Fatalf("failed to create config service: %v", err)
}

// Set a new value.
err = cfg.Set("language", "fr")
if err != nil {
	log.Fatalf("failed to set config value: %v", err)
}

// Retrieve a value.
var lang string
err = cfg.Get("language", &lang)
if err != nil {
	log.Fatalf("failed to get config value: %v", err)
}
fmt.Printf("Language: %s\n", lang)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(c *core.Core) (any, error)

Register creates a new instance of the configuration service and registers it with the application's core. This constructor is intended for dynamic dependency injection, where services are managed by a central core component. It performs the same initialization as New, but also integrates the service with the provided core instance.

Types

type ConfigFormat

type ConfigFormat interface {
	// Load reads data from the specified path and returns it as a map.
	Load(path string) (map[string]interface{}, error)
	// Save writes the provided data map to the specified path.
	Save(path string, data map[string]interface{}) error
}

ConfigFormat defines an interface for loading and saving configuration data in various formats. Each format implementation is responsible for serializing and deserializing data between a file and a map of key-value pairs.

func GetConfigFormat

func GetConfigFormat(path string) (ConfigFormat, error)

GetConfigFormat returns a ConfigFormat implementation based on the file extension of the provided path. This allows the config service to dynamically handle different file formats.

Example:

format, err := GetConfigFormat("settings.json")
if err != nil {
	log.Fatal(err)
}
// format is now a JSONFormat

type INIFormat

type INIFormat struct{}

INIFormat implements the ConfigFormat interface for INI files. It handles the structured format of INI files, including sections and keys.

func (*INIFormat) Load

func (f *INIFormat) Load(path string) (map[string]interface{}, error)

Load reads an INI file and converts its sections and keys into a single map. Keys in the map are formed by concatenating the section name and key name with a dot (e.g., "section.key").

func (*INIFormat) Save

func (f *INIFormat) Save(path string, data map[string]interface{}) error

Save writes a map of key-value pairs to an INI file. Keys in the map are split by a dot to determine the section and key for the INI file.

type JSONFormat

type JSONFormat struct{}

JSONFormat implements the ConfigFormat interface for JSON files. It provides methods to read from and write to files in JSON format.

func (*JSONFormat) Load

func (f *JSONFormat) Load(path string) (map[string]interface{}, error)

Load reads a JSON file from the given path and decodes it into a map. The keys of the map are strings, and the values are of type interface{}.

func (*JSONFormat) Save

func (f *JSONFormat) Save(path string, data map[string]interface{}) error

Save encodes the provided map into JSON format and writes it to the given path. The output is indented for readability.

type Options

type Options struct{}

Options holds configuration for the config service. This struct is provided for future extensibility and currently has no fields.

type Service

type Service struct {
	*core.ServiceRuntime[Options] `json:"-"`

	// Persistent fields, saved to config.json.
	ConfigPath   string   `json:"configPath,omitempty"`
	UserHomeDir  string   `json:"userHomeDir,omitempty"`
	RootDir      string   `json:"rootDir,omitempty"`
	CacheDir     string   `json:"cacheDir,omitempty"`
	ConfigDir    string   `json:"configDir,omitempty"`
	DataDir      string   `json:"dataDir,omitempty"`
	WorkspaceDir string   `json:"workspaceDir,omitempty"`
	DefaultRoute string   `json:"default_route"`
	Features     []string `json:"features"`
	Language     string   `json:"language"`
}

Service provides access to the application's configuration. It handles loading, saving, and providing access to configuration values, abstracting away the details of file I/O and data serialization. The Service is designed to be a central point for all configuration-related operations within the application.

The fields of the Service struct are automatically saved to and loaded from a JSON configuration file. The `json:"-"` tag on ServiceRuntime prevents it from being serialized.

func New

func New() (*Service, error)

New creates a new instance of the configuration service. This constructor is intended for static dependency injection, where the service is created and managed manually. It initializes the service with default paths and values, and loads any existing configuration from disk.

Example:

cfg, err := config.New()
if err != nil {
	log.Fatalf("Failed to initialize config: %v", err)
}
// Use cfg to access configuration settings.

func (*Service) DisableFeature

func (s *Service) DisableFeature(feature string) error

DisableFeature disables a feature by removing it from the features list. If the feature is not enabled, this is a no-op.

Example:

err := cfg.DisableFeature("dark_mode")
if err != nil {
	log.Printf("Failed to disable feature: %v", err)
}

func (*Service) EnableFeature

func (s *Service) EnableFeature(feature string) error

EnableFeature enables a feature by adding it to the features list. If the feature is already enabled, this is a no-op.

Example:

err := cfg.EnableFeature("dark_mode")
if err != nil {
	log.Printf("Failed to enable feature: %v", err)
}

func (*Service) Get

func (s *Service) Get(key string, out any) error

Get retrieves a configuration value by its key. The key corresponds to the JSON tag of a field in the Service struct. The retrieved value is stored in the `out` parameter, which must be a non-nil pointer to a variable of the correct type.

Example:

var currentLanguage string
err := cfg.Get("language", &currentLanguage)
if err != nil {
	log.Printf("Could not retrieve language setting: %v", err)
}
fmt.Println("Current language is:", currentLanguage)

func (*Service) HandleIPCEvents

func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error

HandleIPCEvents processes IPC messages for the config service.

func (*Service) IsFeatureEnabled

func (s *Service) IsFeatureEnabled(feature string) bool

IsFeatureEnabled checks if a feature is enabled.

Example:

if cfg.IsFeatureEnabled("dark_mode") {
	// Apply dark mode styles
}

func (*Service) LoadKeyValues

func (s *Service) LoadKeyValues(key string) (map[string]interface{}, error)

LoadKeyValues loads a map of key-value pairs from a file in the config directory. The file format is determined by the extension of the `key` parameter. This allows for easy retrieval of data stored in various formats.

Example:

dbConfig, err := cfg.LoadKeyValues("database.yml")
if err != nil {
	log.Printf("Error loading database config: %v", err)
}
port, ok := dbConfig["port"].(int)
// ...

func (*Service) LoadStruct

func (s *Service) LoadStruct(key string, data interface{}) error

LoadStruct loads an arbitrary struct from a JSON file in the config directory. The `key` parameter specifies the filename (without the .json extension). The loaded data is unmarshaled into the `data` parameter, which must be a non-nil pointer to a struct.

Example:

var prefs UserPreferences
err := cfg.LoadStruct("user_prefs", &prefs)
if err != nil {
	log.Printf("Error loading user preferences: %v", err)
}
fmt.Printf("User theme is: %s", prefs.Theme)

func (*Service) Save

func (s *Service) Save() error

Save writes the current configuration to a JSON file. The location of the file is determined by the ConfigPath field of the Service struct. This method is typically called automatically by Set, but can be used to explicitly save changes.

Example:

err := cfg.Save()
if err != nil {
	log.Printf("Error saving configuration: %v", err)
}

func (*Service) SaveKeyValues

func (s *Service) SaveKeyValues(key string, data map[string]interface{}) error

SaveKeyValues saves a map of key-value pairs to a file in the config directory. The file format is determined by the extension of the `key` parameter. This method is a convenient way to store structured data in a format of choice.

Example:

data := map[string]interface{}{"host": "localhost", "port": 8080}
err := cfg.SaveKeyValues("database.yml", data)
if err != nil {
	log.Printf("Error saving database config: %v", err)
}

func (*Service) SaveStruct

func (s *Service) SaveStruct(key string, data interface{}) error

SaveStruct saves an arbitrary struct to a JSON file in the config directory. This is useful for storing complex data that is not part of the main configuration. The `key` parameter is used as the filename (with a .json extension).

Example:

type UserPreferences struct {
	Theme string `json:"theme"`
	Notifications bool `json:"notifications"`
}
prefs := UserPreferences{Theme: "dark", Notifications: true}
err := cfg.SaveStruct("user_prefs", prefs)
if err != nil {
	log.Printf("Error saving user preferences: %v", err)
}

func (*Service) Set

func (s *Service) Set(key string, v any) error

Set updates a configuration value and saves the change to the configuration file. The key corresponds to the JSON tag of a field in the Service struct. The provided value `v` must be of a type that is assignable to the field.

Example:

err := cfg.Set("default_route", "/home")
if err != nil {
	log.Printf("Failed to set default route: %v", err)
}

type XMLFormat

type XMLFormat struct{}

XMLFormat implements the ConfigFormat interface for XML files. It uses a simple structure with a root "config" element containing a series of "entry" elements, each with a "key" and "value".

func (*XMLFormat) Load

func (f *XMLFormat) Load(path string) (map[string]interface{}, error)

Load reads an XML file and parses it into a map. It expects the XML to have a specific structure as defined by the xmlEntry struct.

func (*XMLFormat) Save

func (f *XMLFormat) Save(path string, data map[string]interface{}) error

Save writes a map of key-value pairs to an XML file. The data is structured with a root "config" element and child "entry" elements.

type YAMLFormat

type YAMLFormat struct{}

YAMLFormat implements the ConfigFormat interface for YAML files. It provides methods to read from and write to files in YAML format.

func (*YAMLFormat) Load

func (f *YAMLFormat) Load(path string) (map[string]interface{}, error)

Load reads a YAML file from the given path and decodes it into a map.

func (*YAMLFormat) Save

func (f *YAMLFormat) Save(path string, data map[string]interface{}) error

Save encodes the provided map into YAML format and writes it to the given path.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL