package environment import ( "context" "fmt" "os" "path/filepath" ) // Environment manages Wild Cloud environment variables and paths type Environment struct { wcRoot string wcHome string } // New creates a new Environment instance func New() *Environment { env := &Environment{} // Initialize from environment variables set by root command if wcRoot := os.Getenv("WC_ROOT"); wcRoot != "" { env.wcRoot = wcRoot } if wcHome := os.Getenv("WC_HOME"); wcHome != "" { env.wcHome = wcHome } // If WC_HOME is not set, try to detect it if env.wcHome == "" { if detected, err := env.DetectWCHome(); err == nil && detected != "" { env.wcHome = detected // Set environment variable for child processes _ = os.Setenv("WC_HOME", detected) } } return env } // WCRoot returns the Wild Cloud installation directory func (e *Environment) WCRoot() string { return e.wcRoot } // WCHome returns the Wild Cloud project directory func (e *Environment) WCHome() string { return e.wcHome } // SetWCRoot sets the Wild Cloud installation directory func (e *Environment) SetWCRoot(path string) { e.wcRoot = path } // SetWCHome sets the Wild Cloud project directory func (e *Environment) SetWCHome(path string) { e.wcHome = path } // DetectWCHome attempts to find the Wild Cloud project directory by looking for .wildcloud marker func (e *Environment) DetectWCHome() (string, error) { // Start from current working directory dir, err := os.Getwd() if err != nil { return "", fmt.Errorf("getting current directory: %w", err) } // Walk up the directory tree looking for .wildcloud marker for { markerPath := filepath.Join(dir, ".wildcloud") if info, err := os.Stat(markerPath); err == nil && info.IsDir() { return dir, nil } parent := filepath.Dir(dir) if parent == dir { // Reached root directory break } dir = parent } return "", nil } // Validate checks that the environment is properly configured func (e *Environment) Validate(ctx context.Context) error { // Validate WC_ROOT if set if e.wcRoot != "" { if err := e.validateWCRoot(); err != nil { return fmt.Errorf("invalid WC_ROOT: %w", err) } } // Validate WC_HOME if set if e.wcHome != "" { if err := e.validateWCHome(); err != nil { return fmt.Errorf("invalid WC_HOME: %w", err) } } return nil } // validateWCRoot checks that WC_ROOT is a valid Wild Cloud installation func (e *Environment) validateWCRoot() error { if e.wcRoot == "" { return nil } // Check if directory exists info, err := os.Stat(e.wcRoot) if err != nil { return fmt.Errorf("directory does not exist: %w", err) } if !info.IsDir() { return fmt.Errorf("path is not a directory: %s", e.wcRoot) } // Check for bin directory (contains wild-* scripts) binDir := filepath.Join(e.wcRoot, "bin") if info, err := os.Stat(binDir); err != nil || !info.IsDir() { return fmt.Errorf("bin directory not found, this may not be a Wild Cloud installation") } // Note: We skip the PATH check for CLI usage as it's not required // The original bash scripts expect WC_ROOT/bin to be in PATH, but the CLI can work without it return nil } // validateWCHome checks that WC_HOME is a valid Wild Cloud project func (e *Environment) validateWCHome() error { if e.wcHome == "" { return nil } // Check if directory exists info, err := os.Stat(e.wcHome) if err != nil { return fmt.Errorf("directory does not exist: %w", err) } if !info.IsDir() { return fmt.Errorf("path is not a directory: %s", e.wcHome) } // Check for .wildcloud marker directory markerDir := filepath.Join(e.wcHome, ".wildcloud") if info, err := os.Stat(markerDir); err != nil || !info.IsDir() { return fmt.Errorf("not a Wild Cloud project directory (missing .wildcloud marker)") } return nil } // ConfigPath returns the path to the config.yaml file func (e *Environment) ConfigPath() string { if e.wcHome == "" { return "" } return filepath.Join(e.wcHome, "config.yaml") } // SecretsPath returns the path to the secrets.yaml file func (e *Environment) SecretsPath() string { if e.wcHome == "" { return "" } return filepath.Join(e.wcHome, "secrets.yaml") } // AppsDir returns the path to the apps directory func (e *Environment) AppsDir() string { if e.wcHome == "" { return "" } return filepath.Join(e.wcHome, "apps") } // WildCloudDir returns the path to the .wildcloud directory func (e *Environment) WildCloudDir() string { if e.wcHome == "" { return "" } return filepath.Join(e.wcHome, ".wildcloud") } // CacheDir returns the path to the cache directory func (e *Environment) CacheDir() string { if e.wcHome == "" { return "" } return filepath.Join(e.wcHome, ".wildcloud", "cache") } // IsConfigured returns true if both WC_ROOT and WC_HOME are set and valid func (e *Environment) IsConfigured() bool { return e.wcRoot != "" && e.wcHome != "" } // RequiresProject returns an error if WC_HOME is not configured func (e *Environment) RequiresProject() error { if e.wcHome == "" { return fmt.Errorf("this command requires a Wild Cloud project directory. Run 'wild setup scaffold' to create one, or run from within an existing project") } return nil } // RequiresInstallation returns an error if WC_ROOT is not configured func (e *Environment) RequiresInstallation() error { if e.wcRoot == "" { return fmt.Errorf("WC_ROOT is not set. Please set the WC_ROOT environment variable to your Wild Cloud installation directory") } return nil }