package config import ( "os" "path/filepath" "runtime" "strings" ) // EnvironmentProfile represents the deployment environment type EnvironmentProfile int const ( ProfileLocal EnvironmentProfile = iota ProfileContainer ProfileCI ProfileProduction ) // DetectEnvironment determines the current environment profile func DetectEnvironment() EnvironmentProfile { // CI detection if os.Getenv("CI") != "" || os.Getenv("GITHUB_ACTIONS") != "" || os.Getenv("GITLAB_CI") != "" { return ProfileCI } // Container detection if _, err := os.Stat("/.dockerenv"); err == nil { return ProfileContainer } if os.Getenv("KUBERNETES_SERVICE_HOST") != "" { return ProfileContainer } if os.Getenv("CONTAINER") != "" { return ProfileContainer } // Production detection (customizable) if os.Getenv("FETCH_ML_ENV") == "production" || os.Getenv("ENV") == "production" { return ProfileProduction } // Default to local development return ProfileLocal } // SmartDefaults provides environment-aware default values type SmartDefaults struct { Profile EnvironmentProfile } // GetSmartDefaults returns defaults for the current environment func GetSmartDefaults() *SmartDefaults { return &SmartDefaults{ Profile: DetectEnvironment(), } } // Host returns the appropriate default host func (s *SmartDefaults) Host() string { switch s.Profile { case ProfileContainer, ProfileCI: return "host.docker.internal" // Docker Desktop/Colima case ProfileProduction: return "0.0.0.0" default: // ProfileLocal return "localhost" } } // BasePath returns the appropriate default base path func (s *SmartDefaults) BasePath() string { switch s.Profile { case ProfileContainer, ProfileCI: return "/workspace/ml-experiments" case ProfileProduction: return "/var/lib/fetch_ml/experiments" default: // ProfileLocal if home, err := os.UserHomeDir(); err == nil { return filepath.Join(home, "ml-experiments") } return "./ml-experiments" } } // DataDir returns the appropriate default data directory func (s *SmartDefaults) DataDir() string { switch s.Profile { case ProfileContainer, ProfileCI: return "/workspace/data" case ProfileProduction: return "/var/lib/fetch_ml/data" default: // ProfileLocal if home, err := os.UserHomeDir(); err == nil { return filepath.Join(home, "ml-data") } return "./data" } } // RedisAddr returns the appropriate default Redis address func (s *SmartDefaults) RedisAddr() string { switch s.Profile { case ProfileContainer, ProfileCI: return "redis:6379" // Service name in containers case ProfileProduction: return "redis:6379" default: // ProfileLocal return "localhost:6379" } } // SSHKeyPath returns the appropriate default SSH key path func (s *SmartDefaults) SSHKeyPath() string { switch s.Profile { case ProfileContainer, ProfileCI: return "/workspace/.ssh/id_rsa" case ProfileProduction: return "/etc/fetch_ml/ssh/id_rsa" default: // ProfileLocal if home, err := os.UserHomeDir(); err == nil { return filepath.Join(home, ".ssh", "id_rsa") } return "~/.ssh/id_rsa" } } // KnownHostsPath returns the appropriate default known_hosts path func (s *SmartDefaults) KnownHostsPath() string { switch s.Profile { case ProfileContainer, ProfileCI: return "/workspace/.ssh/known_hosts" case ProfileProduction: return "/etc/fetch_ml/ssh/known_hosts" default: // ProfileLocal if home, err := os.UserHomeDir(); err == nil { return filepath.Join(home, ".ssh", "known_hosts") } return "~/.ssh/known_hosts" } } // LogLevel returns the appropriate default log level func (s *SmartDefaults) LogLevel() string { switch s.Profile { case ProfileCI: return "debug" // More verbose for CI debugging case ProfileProduction: return "info" default: // ProfileLocal, ProfileContainer return "info" } } // MaxWorkers returns the appropriate default worker count func (s *SmartDefaults) MaxWorkers() int { switch s.Profile { case ProfileCI: return 1 // Conservative for CI case ProfileProduction: return runtime.NumCPU() // Scale with CPU cores default: // ProfileLocal, ProfileContainer return 2 // Reasonable default for local dev } } // PollInterval returns the appropriate default poll interval in seconds func (s *SmartDefaults) PollInterval() int { switch s.Profile { case ProfileCI: return 1 // Fast polling for quick tests case ProfileProduction: return 10 // Conservative for production default: // ProfileLocal, ProfileContainer return 5 // Balanced default } } // IsInContainer returns true if running in a container environment func (s *SmartDefaults) IsInContainer() bool { return s.Profile == ProfileContainer || s.Profile == ProfileCI } // IsProduction returns true if this is a production environment func (s *SmartDefaults) IsProduction() bool { return s.Profile == ProfileProduction } // IsCI returns true if this is a CI environment func (s *SmartDefaults) IsCI() bool { return s.Profile == ProfileCI } // ExpandPath expands ~ and environment variables in paths func (s *SmartDefaults) ExpandPath(path string) string { if strings.HasPrefix(path, "~/") { if home, err := os.UserHomeDir(); err == nil { path = filepath.Join(home, path[2:]) } } // Expand environment variables path = os.ExpandEnv(path) return path } // GetEnvironmentDescription returns a human-readable description func (s *SmartDefaults) GetEnvironmentDescription() string { switch s.Profile { case ProfileLocal: return "Local Development" case ProfileContainer: return "Container Environment" case ProfileCI: return "CI/CD Environment" case ProfileProduction: return "Production Environment" default: return "Unknown Environment" } }