package main import ( "bufio" "fmt" "os" "strings" "sync" ) func runBatch(batchFile string) error { file, err := os.Open(batchFile) if err != nil { return fmt.Errorf("failed to open batch file: %w", err) } defer file.Close() var configFiles []string scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } configFiles = append(configFiles, line) } if err := scanner.Err(); err != nil { return fmt.Errorf("failed to read batch file: %w", err) } if len(configFiles) == 0 { return fmt.Errorf("no config files found in batch file") } fmt.Printf("Found %d config files to process\n\n", len(configFiles)) var wg sync.WaitGroup errors := make(chan error, len(configFiles)) semaphore := make(chan struct{}, 3) // Max 3 concurrent jobs for i, configFile := range configFiles { wg.Add(1) go func(index int, cfgFile string) { defer wg.Done() semaphore <- struct{}{} defer func() { <-semaphore }() fmt.Printf("[%d/%d] Processing: %s\n", index+1, len(configFiles), cfgFile) config := &Config{} if err := loadConfigFile(cfgFile, config); err != nil { errors <- fmt.Errorf("[%s] failed to load config: %w", cfgFile, err) return } if err := run(config); err != nil { errors <- fmt.Errorf("[%s] failed to create template: %w", cfgFile, err) return } fmt.Printf("[%d/%d] ✓ Completed: %s\n\n", index+1, len(configFiles), cfgFile) }(i, configFile) } wg.Wait() close(errors) var batchErrors []error for err := range errors { batchErrors = append(batchErrors, err) } if len(batchErrors) > 0 { fmt.Fprintf(os.Stderr, "\n%d template(s) failed:\n", len(batchErrors)) for _, err := range batchErrors { fmt.Fprintf(os.Stderr, " - %v\n", err) } return fmt.Errorf("%d template(s) failed", len(batchErrors)) } return nil } // ... existing code ...