106 lines
3.6 KiB
Rust
106 lines
3.6 KiB
Rust
//! Copyright (c) 2022-2026 GitDataAi All rights reserved.
|
|
|
|
use crate::bare::GitBare;
|
|
use crate::error::GitResult;
|
|
use crate::pb::*;
|
|
|
|
impl GitBare {
|
|
/// Count commits in a revision range or path.
|
|
pub fn count_commits(&self, request: CountCommitsRequest) -> GitResult<CountCommitsResponse> {
|
|
let revision = if request.revision.is_empty() {
|
|
"HEAD"
|
|
} else {
|
|
&request.revision
|
|
};
|
|
crate::sanitize::validate_revision(revision)?;
|
|
|
|
let mut args = vec![
|
|
"--git-dir".to_string(),
|
|
self.bare_dir.to_string_lossy().into_owned(),
|
|
"rev-list".to_string(),
|
|
"--count".to_string(),
|
|
];
|
|
|
|
if !request.since.is_empty() {
|
|
args.push(format!("--since={}", request.since));
|
|
}
|
|
if !request.until.is_empty() {
|
|
args.push(format!("--until={}", request.until));
|
|
}
|
|
|
|
args.push(revision.to_string());
|
|
|
|
if !request.path.is_empty() {
|
|
crate::sanitize::validate_file_path(&request.path)?;
|
|
args.push("--".to_string());
|
|
args.push(request.path.clone());
|
|
}
|
|
|
|
let output = std::process::Command::new("git")
|
|
.args(&args)
|
|
.stdout(std::process::Stdio::piped())
|
|
.stderr(std::process::Stdio::piped())
|
|
.output()
|
|
.map_err(|e| crate::error::GitError::CommandFailed {
|
|
status_code: None,
|
|
stderr: e.to_string(),
|
|
})?;
|
|
if !output.status.success() {
|
|
return Err(crate::error::GitError::CommandFailed {
|
|
status_code: output.status.code(),
|
|
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
|
|
});
|
|
}
|
|
|
|
let count = String::from_utf8_lossy(&output.stdout)
|
|
.trim()
|
|
.parse::<u64>()
|
|
.unwrap_or(0);
|
|
|
|
Ok(CountCommitsResponse { count })
|
|
}
|
|
|
|
/// Count diverging commits between two branches (left vs right).
|
|
pub fn count_diverging_commits(
|
|
&self,
|
|
request: CountDivergingCommitsRequest,
|
|
) -> GitResult<CountDivergingCommitsResponse> {
|
|
crate::sanitize::validate_revision(&request.left)?;
|
|
crate::sanitize::validate_revision(&request.right)?;
|
|
|
|
let output = std::process::Command::new("git")
|
|
.args([
|
|
"--git-dir",
|
|
&self.bare_dir.to_string_lossy(),
|
|
"rev-list",
|
|
"--count",
|
|
"--left-right",
|
|
&format!("{}...{}", request.left, request.right),
|
|
])
|
|
.stdout(std::process::Stdio::piped())
|
|
.stderr(std::process::Stdio::piped())
|
|
.output()
|
|
.map_err(|e| crate::error::GitError::CommandFailed {
|
|
status_code: None,
|
|
stderr: e.to_string(),
|
|
})?;
|
|
if !output.status.success() {
|
|
return Err(crate::error::GitError::CommandFailed {
|
|
status_code: output.status.code(),
|
|
stderr: String::from_utf8_lossy(&output.stderr).trim().to_string(),
|
|
});
|
|
}
|
|
|
|
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
|
// Format: "<left_count>\t<right_count>"
|
|
let parts: Vec<&str> = stdout.split('\t').collect();
|
|
let left_count = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
|
|
let right_count = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0);
|
|
|
|
Ok(CountDivergingCommitsResponse {
|
|
left_count,
|
|
right_count,
|
|
})
|
|
}
|
|
}
|