use crate::auto_push_single_flight::{PushAttempt, PushGit, SingleFlightError, git_command, run_query};
use crate::bounded_push::{STOP_GRACE, push_patience, run_bounded_push, strip_one_line_break};
use crate::lfs_push_precheck::lfs_refusal;
use crate::lfs_object_plan::narrow_plan;
use crate::lfs_upload::run_upload_bounded;
use crate::git_system_config::with_real_git;
use crate::repo_read_layout::read_layout_after_success;
use crate::lfs_pre_push::plan_failed_message;
use crate::lfs_upload_plan::{GitQuery, PlanError, Settings, UploadPlan, plan_upload, read_settings};
use std::ffi::OsString;
const REFUSED_EXIT_CODE: i64 = 1;
struct PushQuery<'a> {
git: &'a PushGit,
}
impl GitQuery for PushQuery<'_> {
fn ask(&mut self, query_arguments: &[&str]) -> Result<String, String> {
let owned: Vec<OsString> = query_arguments.iter().map(OsString::from).collect();
let output = match run_query(self.git, owned.as_slice()) {
Ok(done) => done,
Err(error) => return Err(error.to_string()),
};
let text: String = String::from_utf8_lossy(output.stdout.as_slice()).trim().to_owned();
return match output.code {
Some(0) => Ok(text),
Some(1) if text.is_empty() => Ok(text),
code => Err(format!("exited with {code:?}: {}", String::from_utf8_lossy(output.stderr.as_slice()).trim())),
};
}
}
pub fn run_push(git: &PushGit, arguments: &[OsString]) -> Result<PushAttempt, SingleFlightError> {
let region: &[OsString] = arguments.get(1..).unwrap_or_default();
if git.lfs {
if let Some(refusal) = lfs_refusal(&[], region, git.environment.as_slice()) {
return Ok(PushAttempt {
exit_code: REFUSED_EXIT_CODE,
output: strip_one_line_break(refusal.as_str()).to_owned(),
});
}
let mut query: PushQuery<'_> = PushQuery { git };
let read: Result<Settings, PlanError> = read_settings(&mut query);
let planned: Result<Option<UploadPlan>, PlanError> = match read {
Ok(settings) => plan_upload(&[], region, git.environment.as_slice(), git.cwd.as_path(), settings.as_slice(), &mut query),
Err(error) => Err(error),
};
match planned {
Ok(Some(plan)) => {
let layout = read_layout_after_success(git.cwd.as_path(), with_real_git(git.environment.as_slice(), git.real_git.as_path()).as_slice());
if let Some(narrowed) = narrow_plan(plan, layout.as_ref())
&& let Some(failed) = run_upload_bounded(git, &narrowed)? {
return Ok(failed);
}
}
Ok(None) => {}
Err(error) => {
return Ok(PushAttempt {
exit_code: REFUSED_EXIT_CODE,
output: strip_one_line_break(plan_failed_message(error.0.as_str()).as_str()).to_owned(),
});
}
}
}
let command = git_command(git, arguments);
return run_bounded_push(command, push_patience(git.environment.as_slice()), STOP_GRACE, git.environment.as_slice());
}