git-cleaner 0.1.0

Bulk cleanup of git worktrees and merged branches across multiple repositories
use std::path::{Path, PathBuf};

use crate::error::{Error, Result};

/// A discovered git repository (main worktree, not a linked worktree)
#[derive(Debug)]
pub struct RepoEntry {
    pub path: PathBuf,
    pub name: String,
}

/// Scan a directory for git repositories.
/// Returns only "main" repositories (directories with `.git/` as a directory),
/// not linked worktrees (which have `.git` as a file).
pub fn scan_repos(base: &Path) -> Result<Vec<RepoEntry>> {
    if !base.is_dir() {
        return Err(Error::TargetNotFound(base.to_path_buf()));
    }

    let mut repos = Vec::new();

    let entries = std::fs::read_dir(base)?;
    for entry in entries {
        let entry = entry?;
        let path = entry.path();

        if !path.is_dir() {
            continue;
        }

        let dot_git = path.join(".git");

        // .git as a directory = main repo
        // .git as a file = linked worktree (skip, will be found via parent repo)
        if dot_git.is_dir() {
            let name = path
                .file_name()
                .map(|n| n.to_string_lossy().to_string())
                .unwrap_or_default();

            repos.push(RepoEntry { path, name });
        }
    }

    repos.sort_by(|a, b| a.name.cmp(&b.name));
    Ok(repos)
}