package main import ( "context" "fmt" "os" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/wild-cloud/wild-cli/cmd/wild/app" "github.com/wild-cloud/wild-cli/cmd/wild/cluster" "github.com/wild-cloud/wild-cli/cmd/wild/config" "github.com/wild-cloud/wild-cli/cmd/wild/secret" "github.com/wild-cloud/wild-cli/cmd/wild/setup" "github.com/wild-cloud/wild-cli/cmd/wild/util" "github.com/wild-cloud/wild-cli/internal/environment" "github.com/wild-cloud/wild-cli/internal/output" ) var ( // Global flags cfgDir string verbose bool dryRun bool noColor bool wcRoot string wcHome string ) func newRootCommand() *cobra.Command { cmd := &cobra.Command{ Use: "wild", Short: "Wild Cloud - Personal cloud infrastructure management", Long: `Wild Cloud CLI provides comprehensive management of your personal cloud infrastructure built on Talos Linux and Kubernetes. This tool replaces the collection of wild-* bash scripts with a single, unified CLI that provides better error handling, progress tracking, and cross-platform support.`, Version: "0.1.0-dev", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return initializeConfig(cmd.Context()) }, SilenceUsage: true, SilenceErrors: true, } // Add persistent flags pflags := cmd.PersistentFlags() pflags.StringVar(&cfgDir, "config-dir", "", "config directory (default: current directory)") pflags.BoolVarP(&verbose, "verbose", "v", false, "enable verbose logging") pflags.BoolVar(&dryRun, "dry-run", false, "show what would be done without making changes") pflags.BoolVar(&noColor, "no-color", false, "disable colored output") pflags.StringVar(&wcRoot, "wc-root", "", "Wild Cloud installation directory") pflags.StringVar(&wcHome, "wc-home", "", "Wild Cloud project directory") // Bind flags to viper _ = viper.BindPFlag("verbose", pflags.Lookup("verbose")) _ = viper.BindPFlag("dry-run", pflags.Lookup("dry-run")) _ = viper.BindPFlag("no-color", pflags.Lookup("no-color")) // Add subcommands cmd.AddCommand( setup.NewSetupCommand(), app.NewAppCommand(), cluster.NewClusterCommand(), config.NewConfigCommand(), secret.NewSecretCommand(), util.NewBackupCommand(), util.NewDashboardCommand(), util.NewTemplateCommand(), util.NewStatusCommand(), util.NewVersionCommand(), ) return cmd } func initializeConfig(ctx context.Context) error { // Set up output formatting based on flags if noColor { output.DisableColor() } if verbose { output.SetVerbose(true) } // Initialize environment env := environment.New() // Set WC_ROOT if wcRoot != "" { env.SetWCRoot(wcRoot) } else if envRoot := os.Getenv("WC_ROOT"); envRoot != "" { env.SetWCRoot(envRoot) } // Detect or set WC_HOME if wcHome != "" { env.SetWCHome(wcHome) } else if cfgDir != "" { env.SetWCHome(cfgDir) } else { // Try to auto-detect WC_HOME by looking for .wildcloud marker detected, err := env.DetectWCHome() if err != nil { return fmt.Errorf("failed to detect Wild Cloud project directory: %w", err) } if detected == "" { // Only require WC_HOME for commands that need it // Some commands like "wild setup scaffold" don't need an existing project return nil } env.SetWCHome(detected) } // Validate environment if err := env.Validate(ctx); err != nil { return fmt.Errorf("environment validation failed: %w", err) } // Set up viper configuration if env.WCHome() != "" { viper.AddConfigPath(env.WCHome()) viper.SetConfigName("config") viper.SetConfigType("yaml") // Try to read config file (not required) if err := viper.ReadInConfig(); err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); !ok { return fmt.Errorf("error reading config file: %w", err) } } } // Set environment variables for child processes and internal use if env.WCRoot() != "" { _ = os.Setenv("WC_ROOT", env.WCRoot()) } if env.WCHome() != "" { _ = os.Setenv("WC_HOME", env.WCHome()) } return nil }