mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
use a version-specific suffix for command runner binary in .sandbox-bin (#19180)
we copy `codex-command-runner.exe` into `CODEX_HOME/.sandbox-bin/` so that it can be executed by the sandbox user. We also detect if that version is stale and copy a new one in if so. This can fail when you are running multiple versions of the app - the file in `.sandbox-bin` can look stale because it comes from another app build. This change allows us to have multiple versions in there for different CLI versions, and it fallsback to a `size+mtime` hash in the filename for dev builds that don't report a real CLI version.
This commit is contained in:
committed by
GitHub
Unverified
parent
0d6a90cd6b
commit
d169bb541e
@@ -8,11 +8,13 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::OnceLock;
|
||||
use std::time::UNIX_EPOCH;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
use crate::logging::log_note;
|
||||
use crate::sandbox_bin_dir;
|
||||
|
||||
const DEV_BUILD_VERSION_SENTINEL: &str = "0.0.0";
|
||||
const RESOURCES_DIRNAME: &str = "codex-resources";
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
@@ -134,7 +136,7 @@ pub(crate) fn copy_helper_if_needed(
|
||||
}
|
||||
|
||||
let source = sibling_source_path(kind)?;
|
||||
let destination = helper_bin_dir(codex_home).join(kind.file_name());
|
||||
let destination = helper_destination_for_source(kind, codex_home, &source)?;
|
||||
log_note(
|
||||
&format!(
|
||||
"helper copy: validating {} source={} destination={}",
|
||||
@@ -197,6 +199,56 @@ fn source_path_for_exe(exe: &Path, file_name: &str) -> Option<PathBuf> {
|
||||
resource_candidate.exists().then_some(resource_candidate)
|
||||
}
|
||||
|
||||
fn helper_destination_for_source(
|
||||
kind: HelperExecutable,
|
||||
codex_home: &Path,
|
||||
source: &Path,
|
||||
) -> Result<PathBuf> {
|
||||
let suffix = helper_version_suffix(source)?;
|
||||
let file_name = materialized_file_name(kind, &suffix);
|
||||
Ok(helper_bin_dir(codex_home).join(file_name))
|
||||
}
|
||||
|
||||
fn materialized_file_name(kind: HelperExecutable, suffix: &str) -> String {
|
||||
let source_name = kind.file_name();
|
||||
let path = Path::new(source_name);
|
||||
let stem = path
|
||||
.file_stem()
|
||||
.and_then(|stem| stem.to_str())
|
||||
.unwrap_or(source_name);
|
||||
let extension = path
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.map(|ext| format!(".{ext}"))
|
||||
.unwrap_or_default();
|
||||
format!("{stem}-{suffix}{extension}")
|
||||
}
|
||||
|
||||
fn helper_version_suffix(source: &Path) -> Result<String> {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
if version == DEV_BUILD_VERSION_SENTINEL {
|
||||
dev_build_suffix(source)
|
||||
} else {
|
||||
Ok(version.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn dev_build_suffix(source: &Path) -> Result<String> {
|
||||
let metadata = fs::metadata(source)
|
||||
.with_context(|| format!("read helper source metadata {}", source.display()))?;
|
||||
let modified = metadata
|
||||
.modified()
|
||||
.with_context(|| format!("read helper source mtime {}", source.display()))?;
|
||||
let duration = modified
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.with_context(|| format!("convert helper source mtime {}", source.display()))?;
|
||||
Ok(format!(
|
||||
"{}-{:x}",
|
||||
metadata.len(),
|
||||
duration.as_secs(),
|
||||
))
|
||||
}
|
||||
|
||||
fn copy_from_source_if_needed(source: &Path, destination: &Path) -> Result<CopyOutcome> {
|
||||
if destination_is_fresh(source, destination)? {
|
||||
return Ok(CopyOutcome::Reused);
|
||||
@@ -298,8 +350,13 @@ fn destination_is_fresh(source: &Path, destination: &Path) -> Result<bool> {
|
||||
mod tests {
|
||||
use super::copy_from_source_if_needed;
|
||||
use super::CopyOutcome;
|
||||
use super::dev_build_suffix;
|
||||
use super::destination_is_fresh;
|
||||
use super::helper_bin_dir;
|
||||
use super::helper_version_suffix;
|
||||
use super::materialized_file_name;
|
||||
use super::HelperExecutable;
|
||||
use super::DEV_BUILD_VERSION_SENTINEL;
|
||||
use super::RESOURCES_DIRNAME;
|
||||
use super::source_path_for_exe;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -370,8 +427,10 @@ mod tests {
|
||||
let source_dir = tmp.path().join("sibling-source");
|
||||
fs::create_dir_all(&source_dir).expect("create source dir");
|
||||
let runner_source = source_dir.join("codex-command-runner.exe");
|
||||
let runner_destination = helper_bin_dir(&codex_home).join("codex-command-runner.exe");
|
||||
fs::write(&runner_source, b"runner").expect("runner");
|
||||
let runner_suffix = helper_version_suffix(&runner_source).expect("runner suffix");
|
||||
let runner_destination = helper_bin_dir(&codex_home)
|
||||
.join(materialized_file_name(HelperExecutable::CommandRunner, &runner_suffix));
|
||||
|
||||
let runner_outcome =
|
||||
copy_from_source_if_needed(&runner_source, &runner_destination).expect("runner copy");
|
||||
@@ -418,4 +477,25 @@ mod tests {
|
||||
|
||||
assert_eq!(resolved, sibling_helper);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn helper_version_suffix_uses_cli_version_or_dev_build_metadata() {
|
||||
let tmp = TempDir::new().expect("tempdir");
|
||||
let source = tmp.path().join("source.exe");
|
||||
fs::write(&source, b"runner-v1").expect("write source");
|
||||
let suffix = helper_version_suffix(&source).expect("suffix");
|
||||
|
||||
if env!("CARGO_PKG_VERSION") == DEV_BUILD_VERSION_SENTINEL {
|
||||
assert_eq!(suffix, dev_build_suffix(&source).expect("dev build suffix"));
|
||||
} else {
|
||||
assert_eq!(suffix, env!("CARGO_PKG_VERSION"));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn materialized_file_name_adds_suffix_before_extension() {
|
||||
let file_name = materialized_file_name(HelperExecutable::CommandRunner, "test-suffix");
|
||||
|
||||
assert_eq!(file_name, "codex-command-runner-test-suffix.exe");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user