package env import ( . "ersteller-lib" "fmt" "os" "path/filepath" "github.com/joho/godotenv" ) const ( EnvKeyDatabaseURL = "DATABASE_URL" EnvKeySessionSecret = "SESSION_SECRET" EnvKeyBaseURL = "BASE_URL" EnvKeyIsLocal = "IS_LOCAL" EnvKeyIsDev = "IS_DEV" EnvKeyGoogleClientID = "GOOGLE_CLIENT_ID" EnvKeyGoogleClientSecret = "GOOGLE_CLIENT_SECRET" EnvKeyGoogleRedirectURL = "GOOGLE_REDIRECT_URL" EnvKeyKeycloakDiscoveryURL = "KEYCLOAK_DISCOVERY_URL" EnvKeyKeycloakClientID = "KEYCLOAK_CLIENT_ID" EnvKeyKeycloakClientSecret = "KEYCLOAK_CLIENT_SECRET" ) type UrlApiKey struct { Url string ApiKey string } type Environment struct { DatabaseUrl string MistralApiKey string IsDev bool GoogleSheetsCredPath string GoogleSheetsSpreadId string GoogleSheetsSheetName string GoogleClientId string GoogleClientSecret string GoogleRedirectUrl string IsLocal bool SessionSecret string ApifyKey string Keycloak KeycloakConfig BaseUrl string } type KeycloakConfig struct { DiscoveryUrl string CLientId string ClientSecret string } func LoadEnvironment() Environment { if _, err := os.Stat(".env"); err != nil { err = GenerateEnvFile("", false) if err != nil { Error("error generating the environment file", err) } } err := godotenv.Load() if err != nil { LogError("Error loading .env file: %v", err) panic(err) } return Environment{ DatabaseUrl: os.Getenv(EnvKeyDatabaseURL), IsDev: os.Getenv(EnvKeyIsDev) == "true" || os.Getenv(EnvKeyIsLocal) == "true", GoogleClientId: os.Getenv(EnvKeyGoogleClientID), GoogleClientSecret: os.Getenv(EnvKeyGoogleClientSecret), GoogleRedirectUrl: os.Getenv(EnvKeyGoogleRedirectURL), IsLocal: os.Getenv(EnvKeyIsLocal) == "true", SessionSecret: os.Getenv(EnvKeySessionSecret), BaseUrl: os.Getenv(EnvKeyBaseURL), Keycloak: KeycloakConfig{ DiscoveryUrl: os.Getenv(EnvKeyKeycloakDiscoveryURL), CLientId: os.Getenv(EnvKeyKeycloakClientID), ClientSecret: os.Getenv(EnvKeyKeycloakClientSecret), }, } } // EnvKeys returns all environment variable names used by the application configuration. // This allows other packages (e.g., CLI tools) to discover the required keys // without duplicating or hard-coding the list elsewhere. func EnvKeys() []string { return []string{ EnvKeyDatabaseURL, EnvKeySessionSecret, EnvKeyBaseURL, EnvKeyIsLocal, EnvKeyIsDev, EnvKeyGoogleClientID, EnvKeyGoogleClientSecret, EnvKeyGoogleRedirectURL, EnvKeyKeycloakDiscoveryURL, EnvKeyKeycloakClientID, EnvKeyKeycloakClientSecret, } } // GenerateEnvFile creates a .env file template with all required environment variables // from the EnvKeys function. The file will contain comments and default values where appropriate. func GenerateEnvFile(rootPath string, overwrite bool) error { envPath := filepath.Join(rootPath, ".env") Debug("envPath:", envPath) if !overwrite { if _, err := os.Stat(envPath); err == nil { fmt.Println(".env already exists at:", envPath) fmt.Println("No changes made. Delete or move the existing .env to regenerate.") return fmt.Errorf(".env already exists at: %s", envPath) } } file, err := os.Create(envPath) if err != nil { return fmt.Errorf("failed to create .env file: %w", err) } defer file.Close() // Write header comment _, err = file.WriteString("# Environment Variables Configuration\n") if err != nil { return fmt.Errorf("failed to write to .env file: %w", err) } _, err = file.WriteString("# Generated from EnvKeys function\n\n") if err != nil { return fmt.Errorf("failed to write to .env file: %w", err) } // Get all environment keys keys := EnvKeys() // Define default values and comments for specific keys defaults := map[string]string{ EnvKeyDatabaseURL: "\"db/starter.db?_fk=1\"", EnvKeyBaseURL: "\"http://localhost:8090\"", EnvKeyIsLocal: "true", EnvKeyIsDev: "true", } comments := map[string]string{ EnvKeyDatabaseURL: "# Database connection URL", EnvKeySessionSecret: "# Secret key for session management", EnvKeyBaseURL: "# Base URL of the application", EnvKeyIsLocal: "# Set to true for local development", EnvKeyIsDev: "# Set to true for development mode", EnvKeyGoogleClientID: "# Google OAuth client ID", EnvKeyGoogleClientSecret: "# Google OAuth client secret", EnvKeyGoogleRedirectURL: "# Google OAuth redirect URL", EnvKeyKeycloakDiscoveryURL: "# Keycloak discovery URL", EnvKeyKeycloakClientID: "# Keycloak client ID", EnvKeyKeycloakClientSecret: "# Keycloak client secret", } // Write each environment variable for _, key := range keys { // Write comment if available if comment, exists := comments[key]; exists { _, err = file.WriteString(comment + "\n") if err != nil { return fmt.Errorf("failed to write to .env file: %w", err) } } // Write the environment variable with default value if available if defaultValue, exists := defaults[key]; exists { _, err = file.WriteString(fmt.Sprintf("%s=%s\n", key, defaultValue)) } else { _, err = file.WriteString(fmt.Sprintf("%s=\n", key)) } if err != nil { return fmt.Errorf("failed to write to .env file: %w", err) } } return nil }