#[cfg(not(coverage))]
use pulpo_common::session::SessionStatus;
#[cfg(not(coverage))]
use tracing::debug;
use crate::store::Store;
#[cfg(not(coverage))]
#[allow(clippy::too_many_lines)]
pub(super) async fn update_git_info(store: &Store) {
let sessions = match store.list_sessions().await {
Ok(s) => s,
Err(e) => {
coverage_warn!("Watchdog: failed to list sessions for git info: {e}");
return;
}
};
let live: Vec<_> = sessions
.into_iter()
.filter(|s| s.status == SessionStatus::Active || s.status == SessionStatus::Idle)
.collect();
for session in live {
let effective_dir = session
.worktree_path
.as_deref()
.unwrap_or(&session.workdir)
.to_owned();
let session_id = session.id.to_string();
let old_branch = session.git_branch.clone();
let old_commit = session.git_commit.clone();
let old_files_changed = session.git_files_changed;
let old_insertions = session.git_insertions;
let old_deletions = session.git_deletions;
let old_ahead = session.git_ahead;
let result = tokio::task::spawn_blocking(move || {
let branch = std::process::Command::new("git")
.args(["rev-parse", "--abbrev-ref", "HEAD"])
.current_dir(&effective_dir)
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned());
let commit = std::process::Command::new("git")
.args(["rev-parse", "--short", "HEAD"])
.current_dir(&effective_dir)
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned());
let diff_stat = std::process::Command::new("git")
.args(["diff", "--shortstat", "HEAD"])
.current_dir(&effective_dir)
.output()
.ok()
.filter(|o| o.status.success())
.map(|o| {
let out = String::from_utf8_lossy(&o.stdout).to_string();
super::output_patterns::parse_git_shortstat(&out)
});
let ahead = std::process::Command::new("git")
.args(["rev-list", "--count", "@{upstream}..HEAD"])
.current_dir(&effective_dir)
.output()
.ok()
.filter(|o| o.status.success())
.and_then(|o| {
String::from_utf8_lossy(&o.stdout)
.trim()
.parse::<u32>()
.ok()
});
(branch, commit, diff_stat, ahead)
})
.await;
match result {
Ok((branch, commit, diff_stat, ahead)) => {
if (branch != old_branch || commit != old_commit)
&& let Err(e) = store
.update_session_git_info(&session_id, branch.as_deref(), commit.as_deref())
.await
{
coverage_warn!("Watchdog: failed to update git info for {session_id}: {e}");
}
if let Some((files, ins, del)) = diff_stat
&& (files != old_files_changed || ins != old_insertions || del != old_deletions)
&& let Err(e) = store
.update_session_git_diff(&session_id, files, ins, del)
.await
{
coverage_warn!("Watchdog: failed to update git diff for {session_id}: {e}");
}
if ahead != old_ahead
&& let Err(e) = store.update_session_git_ahead(&session_id, ahead).await
{
coverage_warn!("Watchdog: failed to update git ahead for {session_id}: {e}");
}
}
Err(e) => {
debug!("Watchdog: git info task failed for {session_id}: {e}");
}
}
}
}
#[cfg(coverage)]
pub(super) async fn update_git_info(_store: &Store) {}