submodule-kit 0.2.2

A CLI toolkit for managing git submodules
Documentation
use crate::strings;
use crate::submodule::{SubmoduleInfo, parse_gitmodules_str, short};
use std::fs;
use std::path::Path;

pub fn run() -> Result<bool, String> {
    let content = fs::read_to_string(strings::GITMODULES_FILE)
        .map_err(|e| strings::err_read_gitmodules(&e))?;
    let submodules = parse_gitmodules_str(&content)?;
    check(&submodules, Path::new("."))
}

pub(crate) fn check(submodules: &[SubmoduleInfo], base_path: &Path) -> Result<bool, String> {
    let col_width = submodules.iter().map(|s| s.path.len()).max().unwrap_or(0);
    let mut all_ok = true;

    for sub in submodules {
        let sub_path = base_path.join(&sub.path);
        if !sub_path.join(".git").exists() {
            println!(
                "{:<col_width$}  {}",
                sub.path,
                strings::STATUS_NOT_POPULATED_SKIPPED
            );
            continue;
        }

        let sub_repo = git2::Repository::open(&sub_path)
            .map_err(|e| strings::err_open_submodule(&sub.path, &e))?;

        let head = sub_repo
            .head()
            .map_err(|e| strings::err_read_head(&sub.path, &e))?;

        if head.is_branch() {
            let current_branch = head.shorthand().unwrap_or(strings::LABEL_UNKNOWN);
            match &sub.branch {
                Some(expected) if current_branch != expected => {
                    println!(
                        "{:<col_width$}  {}  {}={}  {}={}",
                        sub.path,
                        strings::STATUS_WRONG_BRANCH,
                        strings::LABEL_CURRENT,
                        current_branch,
                        strings::LABEL_EXPECTED,
                        expected
                    );
                    all_ok = false;
                }
                _ => {
                    println!(
                        "{:<col_width$}  {}  {}",
                        sub.path,
                        strings::STATUS_ON_BRANCH,
                        current_branch
                    );
                }
            }
        } else {
            let sha = head
                .peel_to_commit()
                .map(|c| {
                    let full = c.id().to_string();
                    short(&full).to_string()
                })
                .unwrap_or_else(|_| strings::LABEL_UNKNOWN.to_string());
            println!(
                "{:<col_width$}  {}  {}",
                sub.path,
                strings::STATUS_DETACHED_HEAD,
                sha
            );
            all_ok = false;
        }
    }

    Ok(all_ok)
}

#[cfg(test)]
#[path = "on_branch_tests.rs"]
mod tests;