batuta/stack/publish_status/
git.rs1use anyhow::{anyhow, Result};
7use std::path::Path;
8
9use super::cache::get_git_head;
10use super::types::{GitStatus, PublishAction};
11
12pub fn get_git_status(repo_path: &Path) -> Result<GitStatus> {
18 let output = std::process::Command::new("git")
19 .args(["status", "--porcelain"])
20 .current_dir(repo_path)
21 .output()?;
22
23 if !output.status.success() {
24 return Err(anyhow!("git status failed"));
25 }
26
27 let stdout = String::from_utf8_lossy(&output.stdout);
28 let mut status = GitStatus::default();
29
30 for line in stdout.lines() {
31 if line.len() < 2 {
32 continue;
33 }
34 let index = line.chars().next().unwrap_or(' ');
35 let worktree = line.chars().nth(1).unwrap_or(' ');
36
37 match (index, worktree) {
38 ('?', '?') => status.untracked += 1,
39 (i, _) if i != ' ' && i != '?' => status.staged += 1,
40 (_, w) if w != ' ' && w != '?' => status.modified += 1,
41 _ => {}
42 }
43 }
44
45 status.is_clean = status.total_changes() == 0;
46 status.head_sha = get_git_head(repo_path).unwrap_or_default();
47
48 Ok(status)
49}
50
51pub fn get_local_version(repo_path: &Path) -> Result<String> {
57 let cargo_toml = repo_path.join("Cargo.toml");
58 let content = std::fs::read_to_string(&cargo_toml)?;
59
60 for line in content.lines() {
61 if line.starts_with("version") {
62 if let Some(version) = line.split('"').nth(1) {
63 return Ok(version.to_string());
64 }
65 }
66 }
67
68 Err(anyhow!("No version found in Cargo.toml"))
69}
70
71pub fn determine_action(
73 local: Option<&str>,
74 crates_io: Option<&str>,
75 git_status: &GitStatus,
76) -> PublishAction {
77 match (local, crates_io) {
78 (None, _) => PublishAction::Error,
79 (Some(_), None) => {
80 if git_status.is_clean {
81 PublishAction::NotPublished
82 } else {
83 PublishAction::NeedsCommit
84 }
85 }
86 (Some(local), Some(remote)) => {
87 if !git_status.is_clean {
88 PublishAction::NeedsCommit
89 } else if local == remote {
90 PublishAction::UpToDate
91 } else {
92 match (semver::Version::parse(local), semver::Version::parse(remote)) {
94 (Ok(l), Ok(r)) if l > r => PublishAction::NeedsPublish,
95 (Ok(l), Ok(r)) if l < r => PublishAction::LocalBehind,
96 _ => PublishAction::UpToDate,
97 }
98 }
99 }
100 }
101}