use crate::git::GitError;
use crate::util::log_cmd;
use std::path::Path;
use std::process::Command;
pub enum CherryPickResult {
Applied,
CommitNotFound,
Conflict(String),
Error(String),
}
pub fn commit_exists(repo_path: &Path, commit_sha: &str) -> bool {
let mut cmd = Command::new("git");
cmd.args(["cat-file", "-t", "--", commit_sha])
.current_dir(repo_path);
log_cmd(&cmd);
cmd.output()
.map(|o| o.status.success() && String::from_utf8_lossy(&o.stdout).trim() == "commit")
.unwrap_or(false)
}
pub fn cherry_pick(repo_path: &Path, commit_sha: &str) -> CherryPickResult {
if !commit_exists(repo_path, commit_sha) {
return CherryPickResult::CommitNotFound;
}
let mut cmd = Command::new("git");
cmd.args(["cherry-pick", "--", commit_sha])
.current_dir(repo_path);
log_cmd(&cmd);
let output = match cmd.output() {
Ok(o) => o,
Err(e) => return CherryPickResult::Error(format!("failed to run git cherry-pick: {}", e)),
};
if output.status.success() {
return CherryPickResult::Applied;
}
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
if stderr.contains("CONFLICT") || stderr.contains("conflict") {
CherryPickResult::Conflict(stderr)
} else {
CherryPickResult::Error(stderr)
}
}
pub fn cherry_pick_abort(repo_path: &Path) -> Result<(), GitError> {
let mut cmd = Command::new("git");
cmd.args(["cherry-pick", "--abort"]).current_dir(repo_path);
log_cmd(&cmd);
let output = cmd
.output()
.map_err(|e| GitError::OperationFailed(format!("failed to abort cherry-pick: {}", e)))?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
Err(GitError::OperationFailed(format!(
"cherry-pick --abort failed: {}",
stderr.trim()
)))
}
}
pub fn cherry_pick_continue(repo_path: &Path) -> Result<(), GitError> {
let mut cmd = Command::new("git");
cmd.args(["cherry-pick", "--continue"])
.current_dir(repo_path);
log_cmd(&cmd);
let output = cmd
.output()
.map_err(|e| GitError::OperationFailed(format!("failed to continue cherry-pick: {}", e)))?;
if output.status.success() {
Ok(())
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
Err(GitError::OperationFailed(format!(
"cherry-pick --continue failed: {}",
stderr.trim()
)))
}
}
pub fn cherry_pick_in_progress(repo_path: &Path) -> bool {
repo_path.join(".git").join("CHERRY_PICK_HEAD").exists()
}