package cmd import ( "fmt" "os" "path/filepath" "time" "git.membo.co.uk/dtomlinson/gitlocal/internal/config" "git.membo.co.uk/dtomlinson/gitlocal/internal/git" "git.membo.co.uk/dtomlinson/gitlocal/internal/scanner" "github.com/spf13/cobra" ) var ( recursive bool dryRun bool ) var convertCmd = &cobra.Command{ Use: "convert [path]", Short: "Convert .git to .gitlocal", Long: `Convert renames .git to .gitlocal in the specified directory. If no path is provided, uses the current directory. Use --recursive to scan and convert all nested git repositories.`, Args: cobra.MaximumNArgs(1), RunE: runConvert, } func init() { convertCmd.Flags().BoolVarP(&recursive, "recursive", "r", false, "Recursively convert all nested repos") convertCmd.Flags().BoolVar(&dryRun, "dry-run", false, "Show what would be converted without making changes") } func runConvert(cmd *cobra.Command, args []string) error { // Determine target path targetPath := "." if len(args) > 0 { targetPath = args[0] } // Get absolute path absPath, err := filepath.Abs(targetPath) if err != nil { return fmt.Errorf("failed to get absolute path: %w", err) } // Load config cfg, err := config.Load() if err != nil { return fmt.Errorf("failed to load config: %w", err) } if recursive { return convertRecursive(absPath, cfg) } return convertSingle(absPath, cfg) } func convertSingle(path string, cfg *config.Config) error { // Check if already converted if git.IsGitLocalRepo(path) { // Check if already in config if existingRepo := cfg.FindRepo(path); existingRepo != nil { fmt.Printf("⊘ Already converted and tracked: %s\n", path) return nil } // Add to config gitLocalPath := filepath.Join(path, git.GitLocalDir) remoteURL := git.GetRemoteURL(gitLocalPath) branch := git.GetCurrentBranch(gitLocalPath) cfg.AddRepo(config.Repo{ Path: path, ConvertedAt: time.Now(), OriginalRemote: remoteURL, OriginalBranch: branch, }) if err := cfg.Save(); err != nil { return fmt.Errorf("failed to save config: %w", err) } fmt.Printf("✓ Registered already-converted repo: %s\n", path) if remoteURL != "" { fmt.Printf(" Remote: %s\n", remoteURL) } if branch != "" { fmt.Printf(" Branch: %s\n", branch) } return nil } if !git.IsGitRepo(path) { return fmt.Errorf("no .git directory found at %s", path) } if dryRun { fmt.Printf("[DRY RUN] Would convert: %s\n", path) return nil } // Get git info before converting gitPath := filepath.Join(path, git.GitDir) remoteURL := git.GetRemoteURL(gitPath) branch := git.GetCurrentBranch(gitPath) // Convert if err := git.Convert(path); err != nil { return err } // Update config cfg.AddRepo(config.Repo{ Path: path, ConvertedAt: time.Now(), OriginalRemote: remoteURL, OriginalBranch: branch, }) if err := cfg.Save(); err != nil { return fmt.Errorf("failed to save config: %w", err) } fmt.Printf("✓ Converted: %s\n", path) if remoteURL != "" { fmt.Printf(" Remote: %s\n", remoteURL) } if branch != "" { fmt.Printf(" Branch: %s\n", branch) } return nil } func convertRecursive(rootPath string, cfg *config.Config) error { repos, err := scanner.FindNestedGitRepos(rootPath) if err != nil { return fmt.Errorf("failed to scan for nested repos: %w", err) } if len(repos) == 0 { fmt.Println("No nested git repositories found") return nil } fmt.Printf("Found %d nested git repositories\n\n", len(repos)) converted := 0 registered := 0 for _, repoPath := range repos { if git.IsGitLocalRepo(repoPath) { // Check if already in config if existingRepo := cfg.FindRepo(repoPath); existingRepo != nil { fmt.Printf("⊘ Skipped (already converted and tracked): %s\n", repoPath) continue } // Register already-converted repo gitLocalPath := filepath.Join(repoPath, git.GitLocalDir) remoteURL := git.GetRemoteURL(gitLocalPath) branch := git.GetCurrentBranch(gitLocalPath) cfg.AddRepo(config.Repo{ Path: repoPath, ConvertedAt: time.Now(), OriginalRemote: remoteURL, OriginalBranch: branch, }) fmt.Printf("✓ Registered already-converted: %s\n", repoPath) registered++ continue } if dryRun { fmt.Printf("[DRY RUN] Would convert: %s\n", repoPath) continue } // Get git info before converting gitPath := filepath.Join(repoPath, git.GitDir) remoteURL := git.GetRemoteURL(gitPath) branch := git.GetCurrentBranch(gitPath) // Convert if err := git.Convert(repoPath); err != nil { fmt.Fprintf(os.Stderr, "✗ Failed to convert %s: %v\n", repoPath, err) continue } // Update config cfg.AddRepo(config.Repo{ Path: repoPath, ConvertedAt: time.Now(), OriginalRemote: remoteURL, OriginalBranch: branch, }) fmt.Printf("✓ Converted: %s\n", repoPath) converted++ } if !dryRun && (converted > 0 || registered > 0) { if err := cfg.Save(); err != nil { return fmt.Errorf("failed to save config: %w", err) } fmt.Printf("\nSuccessfully converted %d repositories", converted) if registered > 0 { fmt.Printf(", registered %d already-converted", registered) } fmt.Println() } return nil }