use std::path::Path;
use anyhow::{Result, bail};
use clap::Args;
use super::resolve::resolve_loop;
use crate::git::Git;
#[derive(Debug, Args)]
pub struct MergeArgs {
pub target: String,
}
#[derive(Debug, Args)]
pub struct RebaseArgs {
pub target: String,
}
#[derive(Debug, Args)]
pub struct PullArgs {
#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
pub args: Vec<String>,
}
#[derive(Debug, Args)]
pub struct CherryPickArgs {
#[arg(trailing_var_arg = true, allow_hyphen_values = true, required = true)]
pub args: Vec<String>,
}
#[derive(Debug, Args)]
pub struct RevertArgs {
#[arg(trailing_var_arg = true, allow_hyphen_values = true, required = true)]
pub args: Vec<String>,
}
pub fn merge(args: MergeArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
launch(&["merge", "--no-edit", &args.target], verbose, dir, light)
}
pub fn rebase(args: RebaseArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
launch(&["rebase", &args.target], verbose, dir, light)
}
pub fn pull(args: PullArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
let mut cmd = vec!["pull"];
cmd.extend(args.args.iter().map(String::as_str));
launch(&cmd, verbose, dir, light)
}
pub fn cherry_pick(args: CherryPickArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
let mut cmd = vec!["cherry-pick"];
cmd.extend(args.args.iter().map(String::as_str));
launch(&cmd, verbose, dir, light)
}
pub fn revert(args: RevertArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
let mut cmd = vec!["revert", "--no-edit"];
cmd.extend(args.args.iter().map(String::as_str));
launch(&cmd, verbose, dir, light)
}
fn launch(initial: &[&str], verbose: bool, dir: &Path, light: bool) -> Result<()> {
let git = Git::discover(dir, verbose)?;
println!("[git-pincer] $ git {}", initial.join(" "));
let status = git.run_inherit(initial)?;
if status.success() {
return Ok(());
}
if git.conflicted_files()?.is_empty() {
bail!(
"git {} execution failed, please check the Git output messages",
initial.join(" ")
);
}
resolve_loop(&git, light)
}
#[derive(Debug)]
pub enum LaunchOutcome {
Success(std::process::Output),
Conflicts(std::process::Output),
Failed(String),
}
pub fn launch_captured(git: &Git, initial: &[&str]) -> Result<LaunchOutcome> {
let out = git.run(initial)?;
if out.status.success() {
return Ok(LaunchOutcome::Success(out));
}
if git.conflicted_files()?.is_empty() {
let stderr = String::from_utf8_lossy(&out.stderr).trim().to_owned();
let stdout = String::from_utf8_lossy(&out.stdout).trim().to_owned();
let reason = if stderr.is_empty() { stdout } else { stderr };
return Ok(LaunchOutcome::Failed(reason));
}
Ok(LaunchOutcome::Conflicts(out))
}