use crate::service_fault::reach;
use crate::service_built_checks::{BuiltCommit, adds_only_present_objects, read_commit};
use crate::service_land_follow::classify;
use crate::service_protocol::{CommitRequest, FailureCode, is_zero_object};
use crate::transaction_git::{GitContext, GitOutput};
use std::path::{Path, PathBuf};
use crate::service_land_git_steps_and_import_stream::{commits_from_marks, import_stream, run};
pub(crate) fn objects_of_batch(
git: &GitContext,
journal: &Path,
seq: u64,
first: &CommitRequest,
scratch: &str,
old: &str,
batch: &[&CommitRequest],
amended_parents: &[String],
plain_history: bool,
import_fsync: Option<&str>,
) -> Result<(Vec<String>, String), FailureCode> {
let repository: &Path = first.repository.as_path();
let unborn: bool = is_zero_object(first.base.as_str());
return if let Some(built) = first.commit.as_deref() {
let read: Option<BuiltCommit> = if plain_history { read_commit(first.common_dir.as_path(), built) } else { None };
let (named_itself, parents): (bool, Vec<String>) = match &read {
Some(commit) => (true, commit.parents.clone()),
None => {
let listing: GitOutput = run(git, repository, &["rev-list", "--parents", "--max-count=1", built], None)?;
let text: String = String::from_utf8_lossy(listing.stdout.as_slice()).into_owned();
let mut words = text.split_whitespace();
let named: bool = listing.succeeded() && words.next() == Some(built);
(named, words.map(str::to_string).collect())
}
};
let acceptable: bool = if first.amend {
parents == amended_parents
} else if unborn {
parents.is_empty()
} else {
parents.first() == Some(&first.base)
};
if !named_itself || !acceptable {
return Err(FailureCode::Rejected);
}
reach("before-connectivity");
let proven: bool = match read.as_ref() {
Some(commit) => !unborn && adds_only_present_objects(first.common_dir.as_path(), commit, old),
None => false,
};
if !proven {
let connected: Vec<&str> = if unborn { vec!["rev-list", "--objects", built] } else { vec!["rev-list", "--objects", built, "--not", old] };
if !run(git, repository, connected.as_slice(), None)?.succeeded() {
return Err(FailureCode::Unavailable);
}
}
Ok((vec![built.to_string()], built.to_string()))
} else {
let marks: PathBuf = journal.join(format!("marks-{seq}"));
let marks_argument: String = format!("--export-marks={}", marks.display());
let fsync_setting: String = match import_fsync {
Some(value) => format!("core.fsync={value}"),
None => String::new(),
};
let mut import_arguments: Vec<&str> = Vec::new();
if import_fsync.is_some() {
import_arguments.extend(["-c", fsync_setting.as_str()]);
}
import_arguments.extend(["fast-import", "--done", marks_argument.as_str()]);
let imported: GitOutput = run(git, repository, import_arguments.as_slice(), Some(import_stream(scratch, old, batch, amended_parents)))?;
if !imported.succeeded() {
return Err(classify(&imported));
}
crate::inner_git_words::record_words(&["fast-import", "--done"], &imported);
let marks_text: String = match std::fs::read_to_string(&marks) {
Ok(read_marks) => read_marks,
Err(_unreadable) => return Err(FailureCode::Unavailable),
};
let _marks_removed = std::fs::remove_file(&marks);
let made: Vec<String> = commits_from_marks(marks_text.as_str(), batch.len()).ok_or(FailureCode::Unavailable)?;
let last: String = made.last().cloned().ok_or(FailureCode::Unavailable)?;
Ok((made, last))
};
}