package cmd import ( "fmt" "log" "sort" "github.com/insertr/insertr/internal/content" "github.com/spf13/cobra" "github.com/spf13/viper" ) var ( timestamp string latest bool clean bool ) var restoreCmd = &cobra.Command{ Use: "restore [site-id]", Short: "Restore a site from backup", Long: `Restore a registered site from a timestamped backup. Examples: insertr restore demo # List available backups insertr restore demo --clean # Restore from oldest backup (cleanest) insertr restore demo --latest # Restore from newest backup insertr restore demo --timestamp 20250910-224704 # Restore from specific backup`, Args: cobra.ExactArgs(1), Run: runRestore, } func init() { restoreCmd.Flags().StringVarP(×tamp, "timestamp", "t", "", "specific backup timestamp to restore from") restoreCmd.Flags().BoolVar(&latest, "latest", false, "restore from most recent backup") restoreCmd.Flags().BoolVar(&clean, "clean", false, "restore from oldest backup (cleanest state)") // Bind flags to viper viper.BindPFlag("restore.timestamp", restoreCmd.Flags().Lookup("timestamp")) viper.BindPFlag("restore.latest", restoreCmd.Flags().Lookup("latest")) viper.BindPFlag("restore.clean", restoreCmd.Flags().Lookup("clean")) } func runRestore(cmd *cobra.Command, args []string) { siteID := args[0] // Initialize content client (we don't actually need it for restore, but SiteManager expects it) contentClient := content.NewMockClient() // Initialize site manager siteManager := content.NewSiteManager(contentClient, "./insertr-backups", false) // Load sites from configuration to register them if siteConfigs := viper.Get("server.sites"); siteConfigs != nil { if configs, ok := siteConfigs.([]interface{}); ok { var sites []*content.SiteConfig for _, configInterface := range configs { if configMap, ok := configInterface.(map[string]interface{}); ok { site := &content.SiteConfig{} if id, ok := configMap["site_id"].(string); ok { site.SiteID = id } if path, ok := configMap["path"].(string); ok { site.Path = path } if domain, ok := configMap["domain"].(string); ok { site.Domain = domain } if autoEnhance, ok := configMap["auto_enhance"].(bool); ok { site.AutoEnhance = autoEnhance } if backupOriginals, ok := configMap["backup_originals"].(bool); ok { site.BackupOriginals = backupOriginals } sites = append(sites, site) } } if err := siteManager.RegisterSites(sites); err != nil { log.Fatalf("Failed to register sites: %v", err) } } } // List available backups backups, err := siteManager.ListBackups(siteID) if err != nil { log.Fatalf("Failed to list backups: %v", err) } if len(backups) == 0 { fmt.Printf("โŒ No backups found for site '%s'\n", siteID) fmt.Printf("๐Ÿ’ก Backups are created automatically during enhancement when backup_originals is enabled\n") return } // Sort backups chronologically sort.Strings(backups) // Handle different restore modes var targetTimestamp string if timestamp != "" { // Specific timestamp provided targetTimestamp = timestamp found := false for _, backup := range backups { if backup == targetTimestamp { found = true break } } if !found { fmt.Printf("โŒ Backup timestamp '%s' not found for site '%s'\n", targetTimestamp, siteID) fmt.Printf("๐Ÿ“‹ Available backups:\n") for i, backup := range backups { if i == 0 { fmt.Printf(" %s (oldest/cleanest)\n", backup) } else if i == len(backups)-1 { fmt.Printf(" %s (newest)\n", backup) } else { fmt.Printf(" %s\n", backup) } } return } } else if clean { // Restore from oldest backup (cleanest) targetTimestamp = backups[0] fmt.Printf("๐Ÿงน Restoring from oldest backup (cleanest state): %s\n", targetTimestamp) } else if latest { // Restore from newest backup targetTimestamp = backups[len(backups)-1] fmt.Printf("๐Ÿ”„ Restoring from newest backup: %s\n", targetTimestamp) } else { // No specific option - list available backups fmt.Printf("๐Ÿ“‹ Available backups for site '%s':\n", siteID) for i, backup := range backups { if i == 0 { fmt.Printf(" %s (oldest/cleanest) โ† use --clean\n", backup) } else if i == len(backups)-1 { fmt.Printf(" %s (newest) โ† use --latest\n", backup) } else { fmt.Printf(" %s\n", backup) } } fmt.Printf("\nUsage:\n") fmt.Printf(" insertr restore %s --clean # restore from oldest backup\n", siteID) fmt.Printf(" insertr restore %s --latest # restore from newest backup\n", siteID) fmt.Printf(" insertr restore %s --timestamp %s # restore from specific backup\n", siteID, backups[0]) return } // Perform restore fmt.Printf("๐Ÿ”„ Restoring site '%s' from backup %s...\n", siteID, targetTimestamp) if err := siteManager.RestoreFromBackup(siteID, targetTimestamp); err != nil { log.Fatalf("โŒ Restore failed: %v", err) } fmt.Printf("โœ… Successfully restored site '%s' from backup %s\n", siteID, targetTimestamp) fmt.Printf("๐Ÿ’ก Site files have been restored to their state from %s\n", targetTimestamp) }