git_gardener/git/
status.rs1use git2::{Repository, Status};
2use std::path::Path;
3use crate::error::{GitGardenerError, Result};
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum WorktreeStatus {
8 Clean,
9 Dirty,
10 Ahead,
11 Behind,
12 Diverged,
13}
14
15#[derive(Debug, Clone)]
17pub struct GitStatus {
18 pub working_tree_status: WorktreeStatus,
19 pub has_staged_changes: bool,
20 pub has_unstaged_changes: bool,
21 pub last_commit_time: Option<i64>,
22 pub ahead_count: u32,
23 pub behind_count: u32,
24}
25
26impl GitStatus {
27 pub fn from_path(path: &Path) -> Result<Self> {
28 let repo = Repository::open(path).map_err(|e| {
29 GitGardenerError::Custom(format!("Failed to open repository: {}", e))
30 })?;
31
32 Self::from_repository(&repo)
33 }
34
35 pub fn from_repository(repo: &Repository) -> Result<Self> {
36 let statuses = repo.statuses(None).map_err(|e| {
38 GitGardenerError::Custom(format!("Failed to get repository status: {}", e))
39 })?;
40
41 let mut has_staged_changes = false;
42 let mut has_unstaged_changes = false;
43
44 for status_entry in statuses.iter() {
45 let flags = status_entry.status();
46
47 if flags.intersects(
48 Status::INDEX_NEW | Status::INDEX_MODIFIED | Status::INDEX_DELETED | Status::INDEX_RENAMED | Status::INDEX_TYPECHANGE
49 ) {
50 has_staged_changes = true;
51 }
52
53 if flags.intersects(
54 Status::WT_MODIFIED | Status::WT_DELETED | Status::WT_TYPECHANGE | Status::WT_RENAMED | Status::WT_NEW
55 ) {
56 has_unstaged_changes = true;
57 }
58 }
59
60 let working_tree_status = if has_staged_changes || has_unstaged_changes {
62 WorktreeStatus::Dirty
63 } else {
64 WorktreeStatus::Clean
65 };
66
67 let last_commit_time = Self::get_last_commit_time(repo);
69
70 let ahead_count = 0;
72 let behind_count = 0;
73
74 Ok(GitStatus {
75 working_tree_status,
76 has_staged_changes,
77 has_unstaged_changes,
78 last_commit_time,
79 ahead_count,
80 behind_count,
81 })
82 }
83
84 fn get_last_commit_time(repo: &Repository) -> Option<i64> {
85 repo.head().ok()
87 .and_then(|reference| reference.target())
88 .and_then(|oid| repo.find_commit(oid).ok())
89 .map(|commit| commit.time().seconds())
90 }
91}