deb-bootc-compose/internal/config/config.go
2025-08-18 23:32:51 -07:00

183 lines
6.2 KiB
Go

package config
import (
"fmt"
"os"
"github.com/spf13/viper"
)
// Config represents the configuration for deb-bootc-compose
type Config struct {
Compose ComposeConfig `mapstructure:"compose"`
Build BuildConfig `mapstructure:"build"`
OSTree OSTreeConfig `mapstructure:"ostree"`
Output OutputConfig `mapstructure:"output"`
Logging LoggingConfig `mapstructure:"logging"`
Orchestrator OrchestratorConfig `mapstructure:"orchestrator"`
}
// ComposeConfig represents compose-specific configuration
type ComposeConfig struct {
Release string `mapstructure:"release"`
Variants []string `mapstructure:"variants"`
Architectures []string `mapstructure:"architectures"`
SkipPhases []string `mapstructure:"skip_phases"`
JustPhases []string `mapstructure:"just_phases"`
Parallel bool `mapstructure:"parallel"`
MaxWorkers int `mapstructure:"max_workers"`
}
// BuildConfig represents build system configuration
type BuildConfig struct {
System string `mapstructure:"system"`
Environment string `mapstructure:"environment"`
CacheDir string `mapstructure:"cache_dir"`
WorkDir string `mapstructure:"work_dir"`
Timeout int `mapstructure:"timeout"`
OrchestratorURL string `mapstructure:"orchestrator_url"`
MockConfig string `mapstructure:"mock_config"`
MaxConcurrent int `mapstructure:"max_concurrent"`
BuildDeps map[string]string `mapstructure:"build_deps"`
}
// OSTreeConfig represents OSTree configuration
type OSTreeConfig struct {
Mode string `mapstructure:"mode"`
Refs []string `mapstructure:"refs"`
Repository string `mapstructure:"repository"`
Signing bool `mapstructure:"signing"`
KeyFile string `mapstructure:"key_file"`
RepoPath string `mapstructure:"repo_path"`
TreefilePath string `mapstructure:"treefile_path"`
LogDir string `mapstructure:"log_dir"`
Version string `mapstructure:"version"`
UpdateSummary bool `mapstructure:"update_summary"`
ForceNewCommit bool `mapstructure:"force_new_commit"`
UnifiedCore bool `mapstructure:"unified_core"`
ExtraConfig map[string]interface{} `mapstructure:"extra_config"`
OSTreeRef string `mapstructure:"ostree_ref"`
WorkDir string `mapstructure:"work_dir"`
CacheDir string `mapstructure:"cache_dir"`
ContainerOutput bool `mapstructure:"container_output"`
}
// OutputConfig represents output configuration
type OutputConfig struct {
Formats []string `mapstructure:"formats"`
Registry string `mapstructure:"registry"`
Signing bool `mapstructure:"signing"`
Compression bool `mapstructure:"compression"`
}
// LoggingConfig represents logging configuration
type LoggingConfig struct {
Level string `mapstructure:"level"`
Format string `mapstructure:"format"`
File string `mapstructure:"file"`
}
// OrchestratorConfig represents deb-orchestrator integration
type OrchestratorConfig struct {
Enabled bool `mapstructure:"enabled"`
URL string `mapstructure:"url"`
AuthToken string `mapstructure:"auth_token"`
Timeout int `mapstructure:"timeout"`
}
// LoadConfig loads configuration from file and environment
func LoadConfig(configPath string) (*Config, error) {
viper.SetConfigFile(configPath)
viper.AutomaticEnv()
// Set defaults
setDefaults()
// Try to read config file
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
// Config file not found, use defaults
viper.SetConfigFile("")
}
var config Config
if err := viper.Unmarshal(&config); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
// Validate configuration
if err := validateConfig(&config); err != nil {
return nil, fmt.Errorf("invalid configuration: %w", err)
}
return &config, nil
}
// setDefaults sets default configuration values
func setDefaults() {
viper.SetDefault("compose.release", "bookworm")
viper.SetDefault("compose.parallel", true)
viper.SetDefault("compose.max_workers", 4)
viper.SetDefault("build.system", "sbuild")
viper.SetDefault("build.environment", "debootstrap")
viper.SetDefault("build.cache_dir", "/var/cache/deb-bootc-compose")
viper.SetDefault("build.work_dir", "/var/lib/deb-bootc-compose")
viper.SetDefault("build.timeout", 3600)
viper.SetDefault("ostree.mode", "bare")
viper.SetDefault("ostree.signing", false)
viper.SetDefault("output.formats", []string{"container", "disk-image"})
viper.SetDefault("output.compression", true)
viper.SetDefault("logging.level", "info")
viper.SetDefault("logging.format", "text")
viper.SetDefault("orchestrator.enabled", false)
viper.SetDefault("orchestrator.timeout", 30)
}
// validateConfig validates the configuration
func validateConfig(config *Config) error {
// Validate compose configuration
if config.Compose.Release == "" {
return fmt.Errorf("compose.release is required")
}
if len(config.Compose.Architectures) == 0 {
return fmt.Errorf("compose.architectures is required")
}
// Validate build configuration
if config.Build.System == "" {
return fmt.Errorf("build.system is required")
}
// Validate OSTree configuration
if config.OSTree.Mode == "" {
return fmt.Errorf("ostree.mode is required")
}
// Validate output configuration
if len(config.Output.Formats) == 0 {
return fmt.Errorf("output.formats is required")
}
// Validate orchestrator configuration
if config.Orchestrator.Enabled && config.Orchestrator.URL == "" {
return fmt.Errorf("orchestrator.url is required when orchestrator is enabled")
}
return nil
}
// GetEnvWithDefault gets an environment variable with a default value
func GetEnvWithDefault(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}