wok_dev/cmd/
status.rs

1use anyhow::*;
2use std::io::Write;
3
4use crate::{config, repo};
5
6pub fn status<W: Write>(
7    wok_config: &mut config::Config,
8    umbrella: &repo::Repo,
9    stdout: &mut W,
10) -> Result<()> {
11    // Check if umbrella repo is clean
12    let umbrella_clean = is_repo_clean(&umbrella.git_repo, Some(&wok_config.repos))?;
13    let clean_status = if umbrella_clean { ", all clean" } else { "" };
14
15    writeln!(stdout, "On branch '{}'{}", &umbrella.head, clean_status)?;
16
17    // Show status for each configured subrepo
18    for config_repo in &wok_config.repos {
19        if let Some(subrepo) = umbrella.get_subrepo_by_path(&config_repo.path) {
20            let subrepo_clean = is_repo_clean(&subrepo.git_repo, None)?;
21            let subrepo_clean_status = if subrepo_clean { ", all clean" } else { "" };
22
23            writeln!(
24                stdout,
25                "- '{}' is on branch '{}'{}",
26                config_repo.path.display(),
27                &subrepo.head,
28                subrepo_clean_status
29            )?;
30        }
31    }
32
33    Ok(())
34}
35
36fn is_repo_clean(
37    git_repo: &git2::Repository,
38    config_repos: Option<&[crate::config::Repo]>,
39) -> Result<bool> {
40    // Check if there are any uncommitted changes
41    let mut status_options = git2::StatusOptions::new();
42    status_options.include_ignored(false);
43    status_options.include_untracked(true);
44
45    let statuses = git_repo.statuses(Some(&mut status_options))?;
46
47    // Check if repo is clean - ignore certain files that are expected
48    for entry in statuses.iter() {
49        let status = entry.status();
50        let path = entry.path();
51
52        // If it's just an untracked wok.toml file, we can consider the repo clean
53        if status == git2::Status::WT_NEW && path == Some("wok.toml") {
54            continue;
55        }
56
57        // If it's a newly added .gitmodules file, we can consider the repo clean
58        if status == git2::Status::INDEX_NEW && path == Some(".gitmodules") {
59            continue;
60        }
61
62        // If it's a newly added submodule directory, we can consider the repo clean
63        if status == git2::Status::INDEX_NEW
64            && let Some(path_str) = path
65            && let Some(config_repos) = config_repos
66            && config_repos
67                .iter()
68                .any(|r| r.path.to_string_lossy() == path_str)
69        {
70            continue;
71        }
72
73        // Any other status means the repo is not clean
74        return Ok(false);
75    }
76
77    Ok(true)
78}