use crate::auto_push_single_flight::{PushGit, SingleFlightError};
use crate::action::{Action, ENGINE_FAILURE_EXIT_CODE};
use crate::diagnostic_log::debug;
use crate::entry::plan_invocation;
use crate::push_stacking::{STACKED_PUSH_MARKER, run_stacked_push};
use crate::real_git::process_resolution_inputs;
use crate::worktree_copy_forward::{ForwardedRun, run_forwarded_git};
use std::ffi::OsString;
use std::io::Write;
const TAG: &str = "cli-git";
fn marked_environment(environment: &[(OsString, OsString)]) -> Vec<(OsString, OsString)> {
let mut marked: Vec<(OsString, OsString)> = environment
.iter()
.filter(|(name, _)| {
return name.as_os_str() != STACKED_PUSH_MARKER;
})
.cloned()
.collect();
marked.push((OsString::from(STACKED_PUSH_MARKER), OsString::from("1")));
return marked;
}
fn run_planned(action: Action) -> i32 {
let marker = (OsString::from(STACKED_PUSH_MARKER), OsString::from("1"));
let write_stderr = |text: &str| {
let _written = std::io::stderr().write_all(text.as_bytes());
};
let ran = |run: ForwardedRun| -> i32 {
return match run {
ForwardedRun::Ran(code) => code,
ForwardedRun::Failed { stderr, code } => {
write_stderr(stderr.as_str());
code
}
};
};
match action {
Action::Forward { real_git, arguments, mut overlay, stderr } => {
write_stderr(stderr.as_str());
overlay.push(marker);
return ran(run_forwarded_git(real_git.as_path(), arguments.as_slice(), overlay.as_slice(), None));
}
Action::ForwardSettled { real_git, arguments, mut overlay, copy, stderr } => {
write_stderr(stderr.as_str());
overlay.push(marker);
return ran(run_forwarded_git(real_git.as_path(), arguments.as_slice(), overlay.as_slice(), Some(&*copy)));
}
Action::ForwardPush { mut forward, stderr } => {
write_stderr(stderr.as_str());
forward.overlay.push(marker);
return run_stacked_push(&forward);
}
Action::Exit { code, stdout, stderr } => {
let _written = std::io::stdout().write_all(stdout.as_bytes());
write_stderr(stderr.as_str());
return code;
}
other => {
debug(TAG, format!("a merge push planned an action it cannot run: {other:?}").as_str());
write_stderr("cli-git: the merge push could not be planned; nothing was pushed.\n");
return ENGINE_FAILURE_EXIT_CODE;
}
}
}
pub fn gated_merge_push(
git: &PushGit,
global_prefix: &[OsString],
tokens: &[OsString],
destination: &[String],
) -> Result<i32, SingleFlightError> {
let mut arguments: Vec<OsString> = global_prefix.to_vec();
arguments.push(OsString::from("push"));
arguments.extend(tokens.iter().cloned());
arguments.extend(destination.iter().map(OsString::from));
let environment: Vec<(OsString, OsString)> = marked_environment(git.environment.as_slice());
let inputs = process_resolution_inputs(environment.as_slice()).map_err(SingleFlightError::Io)?;
let action: Action = plan_invocation(arguments.as_slice(), environment.as_slice(), &inputs);
return Ok(run_planned(action));
}