huskies: merge 1029
This commit is contained in:
@@ -88,3 +88,62 @@ pub async fn run_git_owned(args: Vec<String>, dir: PathBuf) -> Result<Output, Er
|
||||
.map_err(|e| Error::UpstreamFailure(format!("Task join error: {e}")))?
|
||||
.map_err(|e| Error::Io(format!("Failed to run git: {e}")))
|
||||
}
|
||||
|
||||
/// Summary of uncommitted changes in a git working tree.
|
||||
///
|
||||
/// Returned by [`read_dirty_files_sync`] for use in status rendering.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DirtyFiles {
|
||||
/// Number of tracked files that have uncommitted changes (staged or unstaged).
|
||||
pub modified: usize,
|
||||
/// Number of untracked files.
|
||||
pub new: usize,
|
||||
/// All dirty file paths in the order `git status` reports them (deduplicated).
|
||||
pub paths: Vec<String>,
|
||||
}
|
||||
|
||||
impl DirtyFiles {
|
||||
/// Returns `true` when the working tree has no uncommitted changes.
|
||||
pub fn is_clean(&self) -> bool {
|
||||
self.paths.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
/// Run `git status --porcelain=v1 -u` synchronously in `dir` and return dirty file info.
|
||||
///
|
||||
/// Returns a zeroed [`DirtyFiles`] if `dir` is not a git repo, git is unavailable, or the
|
||||
/// working tree is clean.
|
||||
pub fn read_dirty_files_sync(dir: &Path) -> DirtyFiles {
|
||||
let output = match std::process::Command::new("git")
|
||||
.args(["status", "--porcelain=v1", "-u"])
|
||||
.current_dir(dir)
|
||||
.output()
|
||||
{
|
||||
Ok(o) => o,
|
||||
Err(_) => return DirtyFiles::default(),
|
||||
};
|
||||
if !output.status.success() && output.stdout.is_empty() {
|
||||
return DirtyFiles::default();
|
||||
}
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let (staged, unstaged, untracked) = super::porcelain::parse_git_status_porcelain(&stdout);
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let mut paths = Vec::new();
|
||||
let mut modified_set = std::collections::HashSet::new();
|
||||
for path in staged.iter().chain(unstaged.iter()) {
|
||||
modified_set.insert(path.clone());
|
||||
if seen.insert(path.clone()) {
|
||||
paths.push(path.clone());
|
||||
}
|
||||
}
|
||||
for path in &untracked {
|
||||
if seen.insert(path.clone()) {
|
||||
paths.push(path.clone());
|
||||
}
|
||||
}
|
||||
DirtyFiles {
|
||||
modified: modified_set.len(),
|
||||
new: untracked.len(),
|
||||
paths,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub mod path_guard;
|
||||
/// Pure git porcelain output parsers.
|
||||
pub mod porcelain;
|
||||
|
||||
pub use io::DirtyFiles;
|
||||
#[allow(unused_imports)]
|
||||
pub use path_guard::is_under_root;
|
||||
pub use porcelain::parse_git_status_porcelain;
|
||||
|
||||
Reference in New Issue
Block a user