mirror of
https://github.com/openai/codex.git
synced 2026-04-28 18:32:04 +03:00
6.0 KiB
6.0 KiB
DOs
- Bold: Route by arg0: dispatch to the right entrypoint based on
argv[0].
let exe_name = std::env::current_exe()?
.file_name().and_then(|s| s.to_str()).unwrap_or("");
if exe_name == LINUX_SANDBOX_ARG0 {
codex_linux_sandbox::run_main(); // never returns
} else if exe_name == APPLY_PATCH_ARG0 || exe_name == MISSPELLED_APPLY_PATCH_ARG0 {
codex_apply_patch::main(); // never returns
}
- Bold: Expose an
apply_patchbinary: add a bin target.
[[bin]]
name = "apply_patch"
path = "src/main.rs"
- Bold: Provide a standalone
mainfor the binary.
// apply-patch/src/main.rs
pub fn main() -> ! {
codex_apply_patch::main()
}
- Bold: Accept patch via single arg or stdin; reject extras; flush on success.
pub fn run_main() -> i32 {
let mut args = std::env::args_os();
let _argv0 = args.next();
let patch = match args.next() {
Some(arg) => match arg.into_string() {
Ok(s) => s,
Err(_) => { eprintln!("Error: apply_patch requires a UTF-8 PATCH argument."); return 1; }
},
None => {
let mut buf = String::new();
if std::io::stdin().read_to_string(&mut buf).is_err() || buf.is_empty() {
eprintln!("Usage: apply_patch 'PATCH'\n echo 'PATCH' | apply-patch");
return 2;
}
buf
}
};
if args.next().is_some() {
eprintln!("Error: apply_patch accepts exactly one argument.");
return 2;
}
let (mut out, mut err) = (std::io::stdout(), std::io::stderr());
match crate::apply_patch(&patch, &mut out, &mut err) {
Ok(()) => { let _ = out.flush(); 0 }
Err(_) => 1,
}
}
- Bold: Prepend PATH with a temp dir that provides
apply_patch(andapplypatch) before spawning threads.
fn prepend_path_entry_for_apply_patch() -> std::io::Result<TempDir> {
let temp_dir = TempDir::new()?;
let exe = std::env::current_exe()?;
#[cfg(unix)]
for name in [APPLY_PATCH_ARG0, MISSPELLED_APPLY_PATCH_ARG0] {
std::os::unix::fs::symlink(&exe, temp_dir.path().join(name))?;
}
#[cfg(windows)]
for name in [APPLY_PATCH_ARG0, MISSPELLED_APPLY_PATCH_ARG0] {
let bat = temp_dir.path().join(format!("{name}.bat"));
std::fs::write(&bat, format!("@echo off\r\n\"{}\" {} %*\r\n", exe.display(), CODEX_APPLY_PATCH_ARG1))?;
}
let sep = if cfg!(windows) { ";" } else { ":" };
let updated = match std::env::var("PATH") {
Ok(p) => format!("{}{}{}", temp_dir.path().display(), sep, p),
Err(_) => format!("{}", temp_dir.path().display()),
};
std::env::set_var("PATH", updated);
Ok(temp_dir)
}
- Bold: Retain the temp dir for process lifetime; warn if PATH injection fails.
load_dotenv();
// keep it alive; do this before starting Tokio/threads
let _path_entry = match prepend_path_entry_for_apply_patch() {
Ok(td) => Some(td),
Err(err) => { eprintln!("WARNING: proceeding, even though we could not update PATH: {err}"); None }
};
let runtime = tokio::runtime::Runtime::new()?; // safe now
- Bold: Support the alias
applypatcheverywhere you handleapply_patch.
for name in [APPLY_PATCH_ARG0, MISSPELLED_APPLY_PATCH_ARG0] {
// create symlink or .bat for both
}
- Bold: Use inline
format!placeholders to build patches and expected outputs.
let file = "cli_test.txt";
let add_patch = format!(
r#"*** Begin Patch
*** Add File: {file}
+hello
*** End Patch"#
);
- Bold: Write integration tests with
assert_cmd, covering both arg and stdin flows.
use assert_cmd::prelude::*;
use std::process::Command;
Command::cargo_bin("apply_patch")?
.arg(add_patch)
.current_dir(tmp.path())
.assert()
.success()
.stdout(format!("Success. Updated the following files:\nA {file}\n"));
let mut cmd = assert_cmd::Command::cargo_bin("apply_patch")?;
cmd.current_dir(tmp.path());
cmd.write_stdin(update_patch)
.assert()
.success()
.stdout(format!("Success. Updated the following files:\nM {file}\n"));
- Bold: Assume paths never contain NUL on UNIX/Windows; no extra checks required.
// Path NUL validation unnecessary; standard APIs suffice
let exe = std::env::current_exe()?; // safe for our purposes
DON’Ts
- Bold: Don’t exit if PATH injection fails; warn and continue.
let _path_entry = match prepend_path_entry_for_apply_patch() {
Ok(td) => Some(td),
Err(err) => { eprintln!("WARNING: proceeding, even though we could not update PATH: {err}"); None }
};
- Bold: Don’t spawn threads/runtime before modifying
PATH.
// Correct order:
load_dotenv();
let _path_entry = prepend_path_entry_for_apply_patch().ok();
let runtime = tokio::runtime::Runtime::new()?; // after PATH change
- Bold: Don’t accept multiple CLI args; exactly one or read stdin.
if args.next().is_some() {
eprintln!("Error: apply_patch accepts exactly one argument.");
return 2;
}
- Bold: Don’t drop the temp dir handle; keep it alive.
// Keep `TempDir` in scope (e.g., Option<TempDir>) until process exit
let _path_entry: Option<TempDir> = prepend_path_entry_for_apply_patch().ok();
- Bold: Don’t mix platform logic; gate with
#[cfg(unix)]/#[cfg(windows)].
#[cfg(unix)]
std::os::unix::fs::symlink(&exe, temp_dir.path().join(APPLY_PATCH_ARG0))?;
#[cfg(windows)]
std::fs::write(temp_dir.path().join("apply_patch.bat"),
format!("@echo off\r\n\"{}\" {} %*\r\n", exe.display(), CODEX_APPLY_PATCH_ARG1))?;
- Bold: Don’t rely on a separately installed
apply_patch; inject it via PATH.
// Create/link `apply_patch` into a TempDir and prepend to PATH
let _path_entry = prepend_path_entry_for_apply_patch()?;
- Bold: Don’t forget the
applypatchalias.
if exe_name == APPLY_PATCH_ARG0 || exe_name == MISSPELLED_APPLY_PATCH_ARG0 {
codex_apply_patch::main();
}
- Bold: Don’t build strings with manual concatenation; use
format!with placeholders.
let msg = format!("Success. Updated the following files:\nA {file}\n");