git_pincer/commands/
run.rs1use std::path::Path;
4
5use anyhow::{Result, bail};
6use clap::Args;
7
8use super::resolve::resolve_loop;
9use crate::git::Git;
10
11#[derive(Debug, Args)]
13pub struct MergeArgs {
14 pub target: String,
16}
17
18#[derive(Debug, Args)]
20pub struct RebaseArgs {
21 pub target: String,
23}
24
25#[derive(Debug, Args)]
27pub struct PullArgs {
28 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
30 pub args: Vec<String>,
31}
32
33#[derive(Debug, Args)]
35pub struct CherryPickArgs {
36 #[arg(trailing_var_arg = true, allow_hyphen_values = true, required = true)]
38 pub args: Vec<String>,
39}
40
41#[derive(Debug, Args)]
43pub struct RevertArgs {
44 #[arg(trailing_var_arg = true, allow_hyphen_values = true, required = true)]
46 pub args: Vec<String>,
47}
48
49pub fn merge(args: MergeArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
51 launch(&["merge", "--no-edit", &args.target], verbose, dir, light)
52}
53
54pub fn rebase(args: RebaseArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
56 launch(&["rebase", &args.target], verbose, dir, light)
57}
58
59pub fn pull(args: PullArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
61 let mut cmd = vec!["pull"];
62 cmd.extend(args.args.iter().map(String::as_str));
63 launch(&cmd, verbose, dir, light)
64}
65
66pub fn cherry_pick(args: CherryPickArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
68 let mut cmd = vec!["cherry-pick"];
69 cmd.extend(args.args.iter().map(String::as_str));
70 launch(&cmd, verbose, dir, light)
71}
72
73pub fn revert(args: RevertArgs, verbose: bool, dir: &Path, light: bool) -> Result<()> {
75 let mut cmd = vec!["revert", "--no-edit"];
76 cmd.extend(args.args.iter().map(String::as_str));
77 launch(&cmd, verbose, dir, light)
78}
79
80fn launch(initial: &[&str], verbose: bool, dir: &Path, light: bool) -> Result<()> {
82 let git = Git::discover(dir, verbose)?;
83 println!("[git-pincer] $ git {}", initial.join(" "));
84 let status = git.run_inherit(initial)?;
85 if status.success() {
86 return Ok(());
88 }
89 if git.conflicted_files()?.is_empty() {
90 bail!(
91 "git {} execution failed, please check the Git output messages",
92 initial.join(" ")
93 );
94 }
95 resolve_loop(&git, light)
96}
97
98#[derive(Debug)]
100pub enum LaunchOutcome {
101 Success(std::process::Output),
103 Conflicts(std::process::Output),
105 Failed(String),
107}
108
109pub fn launch_captured(git: &Git, initial: &[&str]) -> Result<LaunchOutcome> {
115 let out = git.run(initial)?;
116 if out.status.success() {
117 return Ok(LaunchOutcome::Success(out));
118 }
119 if git.conflicted_files()?.is_empty() {
120 let stderr = String::from_utf8_lossy(&out.stderr).trim().to_owned();
121 let stdout = String::from_utf8_lossy(&out.stdout).trim().to_owned();
122 let reason = if stderr.is_empty() { stdout } else { stderr };
123 return Ok(LaunchOutcome::Failed(reason));
124 }
125 Ok(LaunchOutcome::Conflicts(out))
126}