mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
dffc4bf75d
Codex forces `core.fsmonitor=false` on internal Git commands so a repository cannot select an executable fsmonitor helper. This also disables Git's built-in daemon for `status`, `diff`, and `ls-files`, turning those worktree reads into full scans in large repositories. Read the raw effective `core.fsmonitor` value and preserve it only when Git interprets it as true and advertises built-in daemon support through `git version --build-options`. Query uncommon boolean spellings back through Git using the exact effective value. Unset, false, helper paths, malformed values, probe failures, and unsupported Git builds continue to force `core.fsmonitor=false`. Centralize this policy in `git-utils` while keeping process execution in the existing local and workspace-command adapters. Probe once per worktree workflow and reuse the result for its Git commands, including the TUI `/diff` path. Metadata-only commands and repository discovery remain disabled without probing. Each probe and requested Git process keeps its own existing timeout, and the decision is not cached because layered and conditional Git configuration can change while Codex runs. --------- Co-authored-by: Chris Bookholt <bookholt@openai.com>
140 lines
3.7 KiB
Rust
140 lines
3.7 KiB
Rust
use std::collections::VecDeque;
|
|
use std::future::Future;
|
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
use super::FsmonitorOverride;
|
|
use super::FsmonitorProbeRunner;
|
|
use super::detect_fsmonitor_override;
|
|
|
|
struct ProbeResponse {
|
|
args: Vec<&'static str>,
|
|
output: Option<Vec<u8>>,
|
|
}
|
|
|
|
struct FakeRunner {
|
|
responses: VecDeque<ProbeResponse>,
|
|
}
|
|
|
|
impl FsmonitorProbeRunner for FakeRunner {
|
|
fn run_probe(&mut self, args: &[&str]) -> impl Future<Output = Option<Vec<u8>>> + Send {
|
|
let response = self.responses.pop_front().expect("missing probe response");
|
|
assert_eq!(args, response.args);
|
|
std::future::ready(response.output)
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn detects_supported_builtin_fsmonitor_values() {
|
|
let cases = [
|
|
(
|
|
"missing config",
|
|
vec![response(config_args(), /*output*/ None)],
|
|
FsmonitorOverride::Disabled,
|
|
),
|
|
(
|
|
"helper path",
|
|
vec![
|
|
response(config_args(), Some(b"/tmp/fsmonitor-helper\0")),
|
|
response(
|
|
typed_config_args("/tmp/fsmonitor-helper"),
|
|
/*output*/ None,
|
|
),
|
|
],
|
|
FsmonitorOverride::Disabled,
|
|
),
|
|
(
|
|
"false spelling",
|
|
vec![response(config_args(), Some(b"OFF\0"))],
|
|
FsmonitorOverride::Disabled,
|
|
),
|
|
(
|
|
"unsupported Git",
|
|
vec![
|
|
response(config_args(), Some(b"yes\0")),
|
|
response(capability_args(), Some(b"")),
|
|
],
|
|
FsmonitorOverride::Disabled,
|
|
),
|
|
(
|
|
"common true spelling",
|
|
vec![
|
|
response(config_args(), Some(b"On\0")),
|
|
response(capability_args(), Some(fsmonitor_capability())),
|
|
],
|
|
FsmonitorOverride::BuiltIn,
|
|
),
|
|
(
|
|
"numeric true",
|
|
vec![
|
|
response(config_args(), Some(b"2k\0")),
|
|
response(typed_config_args("2k"), Some(b"true\0")),
|
|
response(capability_args(), Some(fsmonitor_capability())),
|
|
],
|
|
FsmonitorOverride::BuiltIn,
|
|
),
|
|
(
|
|
"valueless true",
|
|
vec![
|
|
response(config_args(), Some(b"\0")),
|
|
response(typed_config_args(""), Some(b"true\0")),
|
|
response(capability_args(), Some(fsmonitor_capability())),
|
|
],
|
|
FsmonitorOverride::BuiltIn,
|
|
),
|
|
(
|
|
"explicit empty false",
|
|
vec![
|
|
response(config_args(), Some(b"\0")),
|
|
response(typed_config_args(""), Some(b"false\0")),
|
|
],
|
|
FsmonitorOverride::Disabled,
|
|
),
|
|
];
|
|
|
|
for (name, responses, expected) in cases {
|
|
let mut runner = FakeRunner {
|
|
responses: responses.into(),
|
|
};
|
|
|
|
let actual = detect_fsmonitor_override(&mut runner).await;
|
|
|
|
assert_eq!(
|
|
(actual, runner.responses.len()),
|
|
(expected, 0),
|
|
"case: {name}"
|
|
);
|
|
}
|
|
}
|
|
|
|
fn response(args: Vec<&'static str>, output: Option<&[u8]>) -> ProbeResponse {
|
|
ProbeResponse {
|
|
args,
|
|
output: output.map(<[u8]>::to_vec),
|
|
}
|
|
}
|
|
|
|
fn config_args() -> Vec<&'static str> {
|
|
vec!["config", "--null", "--get", "core.fsmonitor"]
|
|
}
|
|
|
|
fn typed_config_args(value: &'static str) -> Vec<&'static str> {
|
|
vec![
|
|
"config",
|
|
"--null",
|
|
"--type=bool",
|
|
"--fixed-value",
|
|
"--get",
|
|
"core.fsmonitor",
|
|
value,
|
|
]
|
|
}
|
|
|
|
fn capability_args() -> Vec<&'static str> {
|
|
vec!["version", "--build-options"]
|
|
}
|
|
|
|
fn fsmonitor_capability() -> &'static [u8] {
|
|
b"feature: fsmonitor--daemon\n"
|
|
}
|