Documentation
¶
Overview ¶
Package config provides configuration management for UniRTM.
Index ¶
- Variables
- func FormatFile(path string, fmtCheck bool) (bool, error)
- func FormatTOML(content string) (string, error)
- func GetGlobalConfigPath() string
- func LoadRawTOML(path string) (map[string]interface{}, error)
- func ParseDurationToSeconds(s string) (int, error)
- func ReadFileOrEmpty(path string) (string, error)
- func SaveRawTOML(path string, m map[string]interface{}) error
- func UnsetEnvVar(content, key string) (string, bool)
- func UpsertEnvVar(content, key, value string) string
- func UpsertToolVersion(content, tool, version string) string
- type Config
- type ConfigManager
- type DurationOrInt
- type EnvironmentConfig
- type Settings
- type Task
- type ToolConfig
- type ToolMap
- type TrustManager
- type TrustStatus
Examples ¶
Constants ¶
This section is empty.
Variables ¶
Functions ¶
func FormatFile ¶
FormatFile formats the configuration file at the given path with canonical ordering. It returns true if the file content was modified, and an error if one occurred. If fmtCheck is true, it does not write changes back to the disk.
func FormatTOML ¶
FormatTOML formats TOML content strings with canonical key ordering.
func GetGlobalConfigPath ¶
func GetGlobalConfigPath() string
GetGlobalConfigPath returns the path to the global unirtm.toml configuration file. (Copied from env package to avoid circular dependency if needed, or just use full path)
func LoadRawTOML ¶
LoadRawTOML reads a TOML file into a generic map. Returns an empty map when the file does not yet exist.
func ParseDurationToSeconds ¶
ParseDurationToSeconds parses a human-readable duration string (e.g., "7d", "24h", "30m", "60s") into a number of seconds. It is exported so that service-layer code can parse minimum_release_age values without duplicating the logic.
func ReadFileOrEmpty ¶
ReadFileOrEmpty reads a file content or returns an empty string if the file doesn't exist.
func SaveRawTOML ¶
SaveRawTOML writes a generic map to a TOML file and formats it.
func UnsetEnvVar ¶
UnsetEnvVar removes an environment variable entry from the TOML env section.
func UpsertEnvVar ¶
UpsertEnvVar adds or updates an environment variable entry in the TOML env section.
func UpsertToolVersion ¶
UpsertToolVersion adds or updates a tool version entry in the TOML [tools] section.
Types ¶
type Config ¶
type Config struct {
Tools ToolMap `toml:"-" yaml:"-" mapstructure:"-"`
ToolsRaw map[string]interface{} `toml:"tools" yaml:"tools" mapstructure:"tools"`
Env map[string]interface{} `toml:"env" yaml:"env" mapstructure:"env"`
Settings Settings `toml:"settings" yaml:"settings" mapstructure:"settings"`
Tasks map[string]Task `toml:"tasks" yaml:"tasks" mapstructure:"tasks"`
Environments map[string]EnvironmentConfig `toml:"environments,omitempty" yaml:"environments,omitempty" mapstructure:"environments,omitempty"`
Aliases map[string]map[string]string `toml:"aliases,omitempty" yaml:"aliases,omitempty" mapstructure:"aliases,omitempty"`
}
Example ¶
ExampleConfig demonstrates basic usage of the Config structure.
package main
import (
"fmt"
"github.com/snowdreamtech/unirtm/internal/config"
)
func main() {
cfg := config.Config{
Tools: map[string]config.ToolConfig{
"node": {
Version: "20.0.0",
Backend: "github",
},
"python": {
Version: "3.11.0",
},
},
Env: map[string]interface{}{
"NODE_ENV": "development",
},
Settings: config.Settings{
CacheDir: "/tmp/unirtm/cache",
DataDir: "/tmp/unirtm/data",
CacheTTL: 3600,
},
Tasks: map[string]config.Task{
"build": {
Description: "Build the project",
Run: "go build -o bin/app",
},
"test": {
Description: "Run tests",
Run: "go test ./...",
Depends: []string{"build"},
},
},
}
if err := cfg.Validate(); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("Configuration is valid")
}
Output: Configuration is valid
func LoadFromDir ¶
LoadFromDir loads the UniRTM project configuration from the specified directory.
func LoadFull ¶
LoadFull loads the UniRTM configuration by merging current directory configs, parent directory configs, and the global configuration (hierarchy). This provides full alignment with mise's hierarchical config loading.
func LoadGlobal ¶
LoadGlobal loads only the global UniRTM configuration.
func LoadHierarchy ¶
LoadHierarchy loads the UniRTM configuration by merging configs starting from the given directory, parent directories up to root, and the global configuration.
func (*Config) ApplyEnvironment ¶
func (c *Config) ApplyEnvironment()
ApplyEnvironment sets the environment variables defined in the configuration to the current process environment.
func (*Config) Merge ¶
Merge merges another configuration into this one. The current configuration takes precedence over the other one (deep merge).
func (*Config) ResolveAlias ¶
ResolveAlias returns the aliased version for a tool if it exists. Otherwise, it returns the original version request.
func (*Config) ResolveEnvironment ¶
ResolveEnvironment resolves environment variables defined in the configuration. It returns a map of rendered environment variables, a list of scripts to source, a list of redacted keys, and an error if any required variables are missing. It supports pongo2 (Jinja2-like) templates.
func (*Config) Validate ¶
Example (Error) ¶
ExampleConfig_Validate_error demonstrates validation error handling.
package main
import (
"fmt"
"github.com/snowdreamtech/unirtm/internal/config"
)
func main() {
cfg := config.Config{
Tools: map[string]config.ToolConfig{
"node": {
Version: "", // Invalid: empty version
},
},
Settings: config.Settings{
CacheTTL: -100, // Invalid: negative value
},
}
if err := cfg.Validate(); err != nil {
fmt.Println("Validation failed as expected")
}
}
Output: Validation failed as expected
type ConfigManager ¶
type ConfigManager interface {
// Load loads configuration from the specified path.
// Returns an error if the file cannot be read or parsed.
Load(ctx context.Context, path string) (*Config, error)
// LoadHierarchy loads configuration from all hierarchy levels.
// Hierarchy: system → global → project → local
// Returns the merged configuration with local overriding project overriding global overriding system.
LoadHierarchy(ctx context.Context) (*Config, error)
// LoadWithEnvironment loads configuration from all hierarchy levels and applies
// environment-specific overrides for the specified environment.
// Returns the merged configuration with environment overrides applied.
LoadWithEnvironment(ctx context.Context, environment string) (*Config, error)
// Validate validates the configuration.
// Returns an error if validation fails, with all validation errors reported.
Validate(ctx context.Context, config *Config) error
// Merge merges multiple configurations with precedence rules.
// Later configurations in the slice override earlier ones.
// Returns the merged configuration or an error if merging fails.
Merge(configs ...*Config) (*Config, error)
// ApplyEnvironment applies environment-specific overrides to a configuration.
// Returns a new configuration with the environment overrides applied.
ApplyEnvironment(config *Config, environment string) (*Config, error)
}
ConfigManager defines the interface for configuration management operations.
It provides methods for loading, validating, and merging configuration files from multiple sources with hierarchical precedence rules.
func NewConfigManager ¶
func NewConfigManager() ConfigManager
NewConfigManager creates a new ConfigManager instance.
It parses TOML and YAML configuration files and supports hierarchical configuration loading with proper precedence rules.
type DurationOrInt ¶
type DurationOrInt int
DurationOrInt represents a duration in seconds, which can be parsed from either an integer number of seconds or a duration string (e.g. "30s", "1h", "20m").
func (*DurationOrInt) UnmarshalJSON ¶
func (d *DurationOrInt) UnmarshalJSON(data []byte) error
func (*DurationOrInt) UnmarshalText ¶
func (d *DurationOrInt) UnmarshalText(text []byte) error
func (*DurationOrInt) UnmarshalYAML ¶
func (d *DurationOrInt) UnmarshalYAML(value *yaml.Node) error
type EnvironmentConfig ¶
type EnvironmentConfig struct {
Tools ToolMap `toml:"-" yaml:"-" mapstructure:"-"`
ToolsRaw map[string]interface{} `toml:"tools,omitempty" yaml:"tools,omitempty" mapstructure:"tools,omitempty"`
Env map[string]interface{} `toml:"env,omitempty" yaml:"env,omitempty" mapstructure:"env,omitempty"`
Settings Settings `toml:"settings,omitempty" yaml:"settings,omitempty" mapstructure:"settings,omitempty"`
Tasks map[string]Task `toml:"tasks,omitempty" yaml:"tasks,omitempty" mapstructure:"tasks,omitempty"`
}
func (*EnvironmentConfig) PostLoad ¶
func (ec *EnvironmentConfig) PostLoad()
func (*EnvironmentConfig) Validate ¶
func (ec *EnvironmentConfig) Validate() error
type Settings ¶
type Settings struct {
CacheDir string `toml:"cache_dir" yaml:"cache_dir" mapstructure:"cache_dir"`
DataDir string `toml:"data_dir" yaml:"data_dir" mapstructure:"data_dir"`
CacheTTL DurationOrInt `toml:"cache_ttl" yaml:"cache_ttl" mapstructure:"cache_ttl"`
Lockfile bool `toml:"lockfile,omitempty" yaml:"lockfile,omitempty" mapstructure:"lockfile,omitempty"`
Locked bool `toml:"locked,omitempty" yaml:"locked,omitempty" mapstructure:"locked,omitempty"`
GitHubProxy string `toml:"github_proxy,omitempty" yaml:"github_proxy,omitempty" mapstructure:"github_proxy,omitempty"`
HttpProxy string `toml:"http_proxy,omitempty" yaml:"http_proxy,omitempty" mapstructure:"http_proxy,omitempty"`
HttpsProxy string `toml:"https_proxy,omitempty" yaml:"https_proxy,omitempty" mapstructure:"https_proxy,omitempty"`
GitHubToken string `toml:"github_token,omitempty" yaml:"github_token,omitempty" mapstructure:"github_token,omitempty"`
HTTPTimeout DurationOrInt `toml:"http_timeout,omitempty" yaml:"http_timeout,omitempty" mapstructure:"http_timeout,omitempty"`
TaskTimeout DurationOrInt `toml:"task_timeout,omitempty" yaml:"task_timeout,omitempty" mapstructure:"task_timeout,omitempty"`
TaskOutput string `toml:"task_output,omitempty" yaml:"task_output,omitempty" mapstructure:"task_output,omitempty"`
Experimental bool `toml:"experimental,omitempty" yaml:"experimental,omitempty" mapstructure:"experimental,omitempty"`
AutoInstall *bool `toml:"auto_install,omitempty" yaml:"auto_install,omitempty" mapstructure:"auto_install,omitempty"`
Color string `toml:"color,omitempty" yaml:"color,omitempty" mapstructure:"color,omitempty"`
Editor string `toml:"editor,omitempty" yaml:"editor,omitempty" mapstructure:"editor,omitempty"`
Shell string `toml:"shell,omitempty" yaml:"shell,omitempty" mapstructure:"shell,omitempty"`
AlwaysKeepDownload bool `toml:"always_keep_download,omitempty" yaml:"always_keep_download,omitempty" mapstructure:"always_keep_download,omitempty"`
CeilingPaths []string `toml:"ceiling_paths,omitempty" yaml:"ceiling_paths,omitempty" mapstructure:"ceiling_paths,omitempty"`
TrustedConfigPaths []string `toml:"trusted_config_paths,omitempty" yaml:"trusted_config_paths,omitempty" mapstructure:"trusted_config_paths,omitempty"`
GPGVerify string `toml:"gpg_verify" yaml:"gpg_verify" mapstructure:"gpg_verify"`
GPGKeys []string `toml:"gpg_keys" yaml:"gpg_keys" mapstructure:"gpg_keys"`
VerifyMetadata *bool `toml:"verify_metadata,omitempty" yaml:"verify_metadata,omitempty" mapstructure:"verify_metadata,omitempty"`
NoProxy []string `toml:"no_proxy,omitempty" yaml:"no_proxy,omitempty" mapstructure:"no_proxy,omitempty"`
Jobs int `toml:"jobs,omitempty" yaml:"jobs,omitempty" mapstructure:"jobs,omitempty"`
Tools map[string]map[string]interface{} `toml:"tools,omitempty" yaml:"tools,omitempty" mapstructure:"tools,omitempty"`
MinimumReleaseAge string `toml:"minimum_release_age,omitempty" yaml:"minimum_release_age,omitempty" mapstructure:"minimum_release_age,omitempty"`
}
Example ¶
ExampleSettings demonstrates settings configuration.
package main
import (
"fmt"
"github.com/snowdreamtech/unirtm/internal/config"
)
func main() {
settings := config.Settings{
CacheDir: "/var/cache/unirtm",
DataDir: "/var/lib/unirtm",
CacheTTL: 86400, // 24 hours
}
if err := settings.Validate(); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("Settings are valid")
}
Output: Settings are valid
func (*Settings) LoadFromEnv ¶
func (s *Settings) LoadFromEnv()
func (*Settings) SetDefaults ¶
func (s *Settings) SetDefaults()
SetDefaults applies sensible defaults for settings that were not provided either via config file or environment variables.
type Task ¶
type Task struct {
Description string `toml:"description" yaml:"description" mapstructure:"description"`
Run string `toml:"run" yaml:"run" mapstructure:"run"`
Env map[string]interface{} `toml:"env,omitempty" yaml:"env,omitempty" mapstructure:"env,omitempty"`
Depends []string `toml:"depends,omitempty" yaml:"depends,omitempty" mapstructure:"depends,omitempty"`
Timeout int `toml:"timeout,omitempty" yaml:"timeout,omitempty" mapstructure:"timeout,omitempty"`
Output string `toml:"output,omitempty" yaml:"output,omitempty" mapstructure:"output,omitempty"`
}
Example ¶
ExampleTask demonstrates task configuration with dependencies.
package main
import (
"fmt"
"github.com/snowdreamtech/unirtm/internal/config"
)
func main() {
task := config.Task{
Description: "Deploy to production",
Run: "./deploy.sh production",
Env: map[string]interface{}{
"ENVIRONMENT": "production",
},
Depends: []string{"test", "build"},
}
if err := task.Validate(); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("Task configuration is valid")
}
Output: Task configuration is valid
type ToolConfig ¶
type ToolConfig struct {
Version string `toml:"version" yaml:"version" mapstructure:"version"`
Backend string `toml:"backend,omitempty" yaml:"backend,omitempty" mapstructure:"backend,omitempty"`
Provider string `toml:"provider,omitempty" yaml:"provider,omitempty" mapstructure:"provider,omitempty"`
PreInstall string `toml:"pre_install,omitempty" yaml:"pre_install,omitempty" mapstructure:"pre_install,omitempty"`
PostInstall string `toml:"post_install,omitempty" yaml:"post_install,omitempty" mapstructure:"post_install,omitempty"`
GPGKeys []string `toml:"gpg_keys,omitempty" yaml:"gpg_keys,omitempty" mapstructure:"gpg_keys,omitempty"`
MinimumReleaseAge string `toml:"minimum_release_age,omitempty" yaml:"minimum_release_age,omitempty" mapstructure:"minimum_release_age,omitempty"`
}
Example ¶
ExampleToolConfig demonstrates tool configuration with version specification.
package main
import (
"fmt"
"github.com/snowdreamtech/unirtm/internal/config"
)
func main() {
tool := config.ToolConfig{
Version: "1.20.0",
Backend: "github",
Provider: "go",
}
if err := tool.Validate(); err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("Tool configuration is valid")
}
Output: Tool configuration is valid
func (*ToolConfig) Validate ¶
func (tc *ToolConfig) Validate() error
type TrustManager ¶
type TrustManager interface {
// TrustStatus returns the current trust state of the configuration file.
TrustStatus(path string) TrustStatus
// Trust adds the specified configuration file to the trusted list with its current hash.
Trust(path string) error
// Untrust removes the specified configuration file from the trusted list.
Untrust(path string) error
// List returns all currently trusted configuration files.
List() (map[string]string, error)
}
TrustManager handles the trust mechanism for local and project configurations. To prevent executing malicious scripts from automatically loaded configuration files in untrusted repositories, we maintain a list of trusted config absolute paths and their content hashes.
func NewTrustManager ¶
func NewTrustManager() TrustManager
NewTrustManager creates a new TrustManager that persists trusted paths to ~/.config/unirtm/trusted_configs.
type TrustStatus ¶
type TrustStatus int
TrustStatus represents the current trust state of a configuration file
const ( // TrustStatusUntrusted means the file has never been trusted TrustStatusUntrusted TrustStatus = iota // TrustStatusTrusted means the file is trusted and its hash matches TrustStatusTrusted // TrustStatusModified means the file was trusted previously but its contents have changed TrustStatusModified )