use std::path::Path;
use std::process::Command;
pub const REPO_LOCAL_GIT_VARS: &[&str] = &[
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
"GIT_CONFIG",
"GIT_CONFIG_PARAMETERS",
"GIT_CONFIG_COUNT",
"GIT_OBJECT_DIRECTORY",
"GIT_DIR",
"GIT_WORK_TREE",
"GIT_IMPLICIT_WORK_TREE",
"GIT_GRAFT_FILE",
"GIT_INDEX_FILE",
"GIT_NO_REPLACE_OBJECTS",
"GIT_REPLACE_REF_BASE",
"GIT_PREFIX",
"GIT_SHALLOW_FILE",
"GIT_COMMON_DIR",
];
pub const ALSO_REDIRECTING_GIT_VARS: &[&str] =
&["GIT_NAMESPACE", "GIT_DISCOVERY_ACROSS_FILESYSTEM"];
pub fn git_command(repo: &Path) -> Command {
hermetic_command("git", repo)
}
pub fn hermetic_command(program: &str, dir: &Path) -> Command {
let mut cmd = Command::new(program);
cmd.current_dir(dir);
for var in REPO_LOCAL_GIT_VARS.iter().chain(ALSO_REDIRECTING_GIT_VARS) {
cmd.env_remove(var);
}
cmd
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn git_command_marks_every_redirecting_var_for_removal() {
let cmd = git_command(Path::new("/tmp"));
let removed: Vec<&str> = cmd
.get_envs()
.filter(|(_, value)| value.is_none())
.filter_map(|(key, _)| key.to_str())
.collect();
for var in REPO_LOCAL_GIT_VARS.iter().chain(ALSO_REDIRECTING_GIT_VARS) {
assert!(
removed.contains(var),
"{var} is not cleared by git_command — a fixture inheriting it \
would operate on that repository instead of its tempdir"
);
}
}
#[test]
fn git_command_preserves_git_exec_path() {
let cmd = git_command(Path::new("/tmp"));
assert!(
!cmd.get_envs()
.any(|(key, value)| key == "GIT_EXEC_PATH" && value.is_none()),
"GIT_EXEC_PATH must not be cleared"
);
}
#[test]
fn local_env_vars_match_git() {
let output = Command::new("git")
.args(["rev-parse", "--local-env-vars"])
.output()
.expect("run `git rev-parse --local-env-vars`");
assert!(
output.status.success(),
"`git rev-parse --local-env-vars` failed"
);
let mut from_git: Vec<String> = String::from_utf8_lossy(&output.stdout)
.lines()
.map(str::trim)
.filter(|line| !line.is_empty())
.map(str::to_string)
.collect();
let mut ours: Vec<String> = REPO_LOCAL_GIT_VARS
.iter()
.map(|v| (*v).to_string())
.collect();
from_git.sort();
ours.sort();
assert_eq!(
ours, from_git,
"REPO_LOCAL_GIT_VARS has drifted from `git rev-parse --local-env-vars`"
);
}
}