mirror of
https://github.com/openai/codex.git
synced 2026-11-01 19:33:35 +00:00
feat: introduce codex-utils-cargo-bin as an alternative to assert_cmd::Command
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "codex-utils-cargo-bin"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
assert_cmd = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
@@ -0,0 +1,126 @@
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CargoBinError {
|
||||
#[error("failed to read current exe")]
|
||||
CurrentExe {
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("failed to read current directory")]
|
||||
CurrentDir {
|
||||
#[source]
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("CARGO_BIN_EXE env var {key} resolved to {path:?}, but it does not exist")]
|
||||
ResolvedPathDoesNotExist { key: String, path: PathBuf },
|
||||
#[error("could not locate binary {name:?}; tried env vars {env_keys:?}; {fallback}")]
|
||||
NotFound {
|
||||
name: String,
|
||||
env_keys: Vec<String>,
|
||||
fallback: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// Returns an absolute path to a binary target built for the current test run.
|
||||
///
|
||||
/// In `cargo test`, `CARGO_BIN_EXE_*` env vars are absolute, but Buck2 may set
|
||||
/// them to project-relative paths (e.g. `buck-out/...`). Those paths break if a
|
||||
/// test later changes its working directory. This helper makes the path
|
||||
/// absolute up-front so callers can safely `chdir` afterwards.
|
||||
pub fn cargo_bin(name: &str) -> Result<PathBuf, CargoBinError> {
|
||||
let env_keys = cargo_bin_env_keys(name);
|
||||
for key in &env_keys {
|
||||
if let Some(value) = std::env::var_os(key) {
|
||||
return resolve_bin_from_env(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
match assert_cmd::Command::cargo_bin(name) {
|
||||
Ok(cmd) => {
|
||||
let abs = absolutize_from_buck_or_cwd(PathBuf::from(cmd.get_program()))?;
|
||||
if abs.exists() {
|
||||
Ok(abs)
|
||||
} else {
|
||||
Err(CargoBinError::ResolvedPathDoesNotExist {
|
||||
key: "assert_cmd::Command::cargo_bin".to_owned(),
|
||||
path: abs,
|
||||
})
|
||||
}
|
||||
}
|
||||
Err(err) => Err(CargoBinError::NotFound {
|
||||
name: name.to_owned(),
|
||||
env_keys,
|
||||
fallback: format!("assert_cmd fallback failed: {err}"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn cargo_bin_env_keys(name: &str) -> Vec<String> {
|
||||
let mut keys = Vec::with_capacity(2);
|
||||
keys.push(format!("CARGO_BIN_EXE_{name}"));
|
||||
|
||||
// Cargo replaces dashes in target names when exporting env vars.
|
||||
let underscore_name = name.replace('-', "_");
|
||||
if underscore_name != name {
|
||||
keys.push(format!("CARGO_BIN_EXE_{underscore_name}"));
|
||||
}
|
||||
|
||||
keys
|
||||
}
|
||||
|
||||
fn resolve_bin_from_env(key: &str, value: OsString) -> Result<PathBuf, CargoBinError> {
|
||||
let abs = absolutize_from_buck_or_cwd(PathBuf::from(value))?;
|
||||
|
||||
if abs.exists() {
|
||||
Ok(abs)
|
||||
} else {
|
||||
Err(CargoBinError::ResolvedPathDoesNotExist {
|
||||
key: key.to_owned(),
|
||||
path: abs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn absolutize_from_buck_or_cwd(path: PathBuf) -> Result<PathBuf, CargoBinError> {
|
||||
if path.is_absolute() {
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
if let Some(root) = buck_project_root().map_err(|source| CargoBinError::CurrentExe { source })?
|
||||
{
|
||||
return Ok(root.join(path));
|
||||
}
|
||||
|
||||
Ok(std::env::current_dir()
|
||||
.map_err(|source| CargoBinError::CurrentDir { source })?
|
||||
.join(path))
|
||||
}
|
||||
|
||||
/// Best-effort attempt to find the Buck project root for the currently running
|
||||
/// process.
|
||||
///
|
||||
/// Prefer this over `env!("CARGO_MANIFEST_DIR")` when running under Buck2: our
|
||||
/// Buck generator sets `CARGO_MANIFEST_DIR="."` for compilation, which makes
|
||||
/// `env!("CARGO_MANIFEST_DIR")` unusable for locating workspace files.
|
||||
pub fn buck_project_root() -> Result<Option<PathBuf>, std::io::Error> {
|
||||
if let Some(root) = std::env::var_os("BUCK_PROJECT_ROOT") {
|
||||
let root = PathBuf::from(root);
|
||||
if root.is_absolute() {
|
||||
return Ok(Some(root));
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to deriving the project root from the location of the test
|
||||
// runner executable:
|
||||
// <project>/buck-out/v2/gen/.../__tests__/test-binary
|
||||
let exe = std::env::current_exe()?;
|
||||
for ancestor in exe.ancestors() {
|
||||
if ancestor.file_name().is_some_and(|name| name == "buck-out") {
|
||||
return Ok(ancestor.parent().map(PathBuf::from));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Reference in New Issue
Block a user