use super::git_metadata::MetadataOutput;
#[cfg(unix)]
use super::repo_read_config_scan::ScopeEnvironment;
#[cfg(unix)]
use super::repo_read_query::{Answer, Query, answer_with};
use super::transaction_git::{GitContext, GitOutput, GitRequest};
use std::ffi::OsString;
#[cfg(unix)]
use std::path::Path;
pub const SWITCH_VARIABLE: &str = "CLI_GIT_IN_PROCESS_READS";
pub fn enabled(variables: &[(OsString, OsString)]) -> bool {
let added_off: bool = variables.iter().any(|(name, value)| { return name == SWITCH_VARIABLE && value == "off"; });
return !added_off && std::env::var_os(SWITCH_VARIABLE).is_none_or(|value| { return value != "off"; });
}
#[cfg(test)]
pub fn switch_off() -> [(OsString, OsString); 1] {
return [(OsString::from(SWITCH_VARIABLE), OsString::from("off"))];
}
#[cfg(unix)]
fn attempt(
arguments: &[OsString],
directory: Option<&Path>,
base: Vec<(OsString, OsString)>,
variables: &[(OsString, OsString)],
input: Option<&[u8]>,
) -> Option<Answer> {
if !enabled(variables) {
return None;
}
let mut effective: Vec<(OsString, OsString)> = base.clone();
effective.extend(variables.iter().cloned());
let scope: ScopeEnvironment = ScopeEnvironment::from_variables(effective.as_slice());
return answer_with(&Query { arguments, directory, variables, input }, base, &scope);
}
#[cfg(unix)]
pub fn try_metadata(arguments: &[OsString], overlay: &[(OsString, OsString)]) -> Option<MetadataOutput> {
let found: Answer = attempt(arguments, None, std::env::vars_os().collect(), overlay, None)?;
return Some(MetadataOutput { success: found.code == 0, code: Some(found.code), stdout: found.stdout, stderr: found.stderr });
}
#[cfg(not(unix))]
pub fn try_metadata(_arguments: &[OsString], _overlay: &[(OsString, OsString)]) -> Option<MetadataOutput> {
return None;
}
#[cfg(unix)]
pub fn try_complete(arguments: &[OsString], directory: &Path, environment: &[(OsString, OsString)]) -> Option<(Option<i32>, Vec<u8>, Vec<u8>)> {
let found: Answer = attempt(arguments, Some(directory), Vec::new(), environment, None)?;
return Some((Some(found.code), found.stdout, found.stderr));
}
#[cfg(not(unix))]
pub fn try_complete(_arguments: &[OsString], _directory: &std::path::Path, _environment: &[(OsString, OsString)]) -> Option<(Option<i32>, Vec<u8>, Vec<u8>)> {
return None;
}
#[cfg(unix)]
pub fn try_request(context: &GitContext, request: &GitRequest) -> Option<GitOutput> {
let mut arguments: Vec<OsString> = Vec::new();
if !request.without_prefix {
arguments.extend(context.global_prefix.iter().cloned());
}
arguments.extend(request.arguments.iter().cloned());
let mut variables: Vec<(OsString, OsString)> = context.overlay.clone();
variables.extend(request.environment.iter().cloned());
if let Some(index) = &request.index {
variables.push((OsString::from("GIT_INDEX_FILE"), index.clone().into_os_string()));
}
if let Some(objects) = &request.object_directory {
variables.push((OsString::from("GIT_OBJECT_DIRECTORY"), objects.clone().into_os_string()));
}
let base: Vec<(OsString, OsString)> = std::env::vars_os()
.filter(|(name, _)| { return !request.unset.contains(name); })
.collect();
let found: Answer = attempt(arguments.as_slice(), Some(request.cwd.as_path()), base, variables.as_slice(), request.input.as_deref())?;
return Some(GitOutput { code: Some(found.code), stdout: found.stdout, stderr: found.stderr });
}
#[cfg(not(unix))]
pub fn try_request(_context: &GitContext, _request: &GitRequest) -> Option<GitOutput> {
return None;
}
#[cfg(test)]
#[path = "repo_read_hook_tests.rs"]
mod tests;
#[cfg(test)]
#[path = "repo_read_batch_tests.rs"]
mod batch_tests;