mirror of
https://github.com/openai/codex.git
synced 2026-04-29 10:53:24 +03:00
feat: introduce find_resource! macro that works with Cargo or Bazel (#8879)
To support Bazelification in https://github.com/openai/codex/pull/8875, this PR introduces a new `find_resource!` macro that we use in place of our existing logic in tests that looks for resources relative to the compile-time `CARGO_MANIFEST_DIR` env var. To make this work, we plan to add the following to all `rust_library()` and `rust_test()` Bazel rules in the project: ``` rustc_env = { "BAZEL_PACKAGE": native.package_name(), }, ``` Our new `find_resource!` macro reads this value via `option_env!("BAZEL_PACKAGE")` so that the Bazel package _of the code using `find_resource!`_ is injected into the code expanded from the macro. (If `find_resource()` were a function, then `option_env!("BAZEL_PACKAGE")` would always be `codex-rs/utils/cargo-bin`, which is not what we want.) Note we only consider the `BAZEL_PACKAGE` value when the `RUNFILES_DIR` environment variable is set at runtime, indicating that the test is being run by Bazel. In this case, we have to concatenate the runtime `RUNFILES_DIR` with the compile-time `BAZEL_PACKAGE` value to build the path to the resource. In testing this change, I discovered one funky edge case in `codex-rs/exec-server/tests/common/lib.rs` where we have to _normalize_ (but not canonicalize!) the result from `find_resource!` because the path contains a `common/..` component that does not exist on disk when the test is run under Bazel, so it must be semantically normalized using the [`path-absolutize`](https://crates.io/crates/path-absolutize) crate before it is passed to `dotslash fetch`. Because this new behavior may be non-obvious, this PR also updates `AGENTS.md` to make humans/Codex aware that this API is preferred.
This commit is contained in:
@@ -70,6 +70,43 @@ fn cargo_bin_env_keys(name: &str) -> Vec<String> {
|
||||
keys
|
||||
}
|
||||
|
||||
/// Macro that derives the path to a test resource at runtime, the value of
|
||||
/// which depends on whether Cargo or Bazel is being used to build and run a
|
||||
/// test. Note the return value may be a relative or absolute path.
|
||||
/// (Incidentally, this is a macro rather than a function because it reads
|
||||
/// compile-time environment variables that need to be captured at the call
|
||||
/// site.)
|
||||
///
|
||||
/// This is expected to be used exclusively in test code because Codex CLI is a
|
||||
/// standalone binary with no packaged resources.
|
||||
#[macro_export]
|
||||
macro_rules! find_resource {
|
||||
($resource:expr) => {{
|
||||
// When this code is built and run with Bazel:
|
||||
// - we inject `BAZEL_PACKAGE` as a compile-time environment variable
|
||||
// that points to native.package_name()
|
||||
// - at runtime, Bazel will set `RUNFILES_DIR` to the runfiles directory
|
||||
//
|
||||
// Therefore, the compile-time value of `BAZEL_PACKAGE` will always be
|
||||
// included in the compiled binary (even if it is built with Cargo), but
|
||||
// we only check it at runtime if `RUNFILES_DIR` is set.
|
||||
let resource = std::path::Path::new(&$resource);
|
||||
let manifest_dir = match std::env::var("RUNFILES_DIR") {
|
||||
Ok(bazel_runtime_files) => match option_env!("BAZEL_PACKAGE") {
|
||||
Some(bazel_package) => Ok(std::path::PathBuf::from(bazel_runtime_files)
|
||||
.join("_main")
|
||||
.join(bazel_package)),
|
||||
None => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
"BAZEL_PACKAGE not set in Bazel build",
|
||||
)),
|
||||
},
|
||||
Err(_) => Ok(std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))),
|
||||
};
|
||||
manifest_dir.map(|dir| dir.join(resource))
|
||||
}};
|
||||
}
|
||||
|
||||
fn resolve_bin_from_env(key: &str, value: OsString) -> Result<PathBuf, CargoBinError> {
|
||||
let abs = absolutize_from_buck_or_cwd(PathBuf::from(value))?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user