Support execution-host context when resolving cloud config (#38086)

## What changed

- Add a scoped `AbsolutePathBufGuard::with_home_directory` override so `~`
  paths can resolve against an explicitly supplied home directory while
  preserving the existing base-directory behavior. Nested overrides restore
  the previous home directory.
- Expose `compose_requirements_for_hostname` so callers can evaluate
  `remote_sandbox_config` for a supplied execution-host hostname.
- Cover cloud bundle conversion with execution-host path expansion and
  hostname-specific sandbox requirements.

GitOrigin-RevId: 6fd486992b45ff92e22bb4073b888252b544f285
This commit is contained in:
sayan-oai
2026-08-11 23:31:26 +00:00
committed by copyberry
parent 52d9218424
commit f4936d7aba
5 changed files with 166 additions and 3 deletions
+67 -1
View File
@@ -26,8 +26,10 @@ pub struct AbsolutePathBuf(PathBuf);
impl AbsolutePathBuf {
fn maybe_expand_home_directory(path: &Path) -> PathBuf {
if let Some(path_str) = path.to_str()
&& let Some(home) = home_dir()
&& let Some(rest) = path_str.strip_prefix('~')
&& let Some(home) = ABSOLUTE_PATH_HOME
.with(|cell| cell.borrow().clone())
.or_else(home_dir)
{
if rest.is_empty() {
return home;
@@ -326,6 +328,7 @@ impl TryFrom<String> for AbsolutePathBuf {
thread_local! {
static ABSOLUTE_PATH_BASE: RefCell<Option<PathBuf>> = const { RefCell::new(None) };
static ABSOLUTE_PATH_HOME: RefCell<Option<PathBuf>> = const { RefCell::new(None) };
}
/// Ensure this guard is held while deserializing `AbsolutePathBuf` values to
@@ -341,6 +344,15 @@ impl AbsolutePathBufGuard {
});
Self
}
/// Resolves home-relative paths against `home_directory` during `operation`.
/// The operation must complete synchronously on the current thread.
pub fn with_home_directory<T>(home_directory: &Path, operation: impl FnOnce() -> T) -> T {
let previous_home =
ABSOLUTE_PATH_HOME.with(|cell| cell.replace(Some(home_directory.to_path_buf())));
let _guard = HomeDirectoryGuard(previous_home);
operation()
}
}
impl Drop for AbsolutePathBufGuard {
@@ -351,6 +363,16 @@ impl Drop for AbsolutePathBufGuard {
}
}
struct HomeDirectoryGuard(Option<PathBuf>);
impl Drop for HomeDirectoryGuard {
fn drop(&mut self) {
ABSOLUTE_PATH_HOME.with(|cell| {
*cell.borrow_mut() = self.0.take();
});
}
}
impl<'de> Deserialize<'de> for AbsolutePathBuf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@@ -595,6 +617,50 @@ mod tests {
assert_eq!(abs_path_buf.as_path(), home.join("code").as_path());
}
#[test]
fn explicit_home_directory_is_used_with_existing_path_guards() {
let home_dir = tempdir().expect("explicit home directory");
let base_dir = tempdir().expect("base directory");
let (home_path, relative_path) =
AbsolutePathBufGuard::with_home_directory(home_dir.path(), || {
let _guard = AbsolutePathBufGuard::new(base_dir.path());
let home_path = serde_json::from_str::<AbsolutePathBuf>("\"~/code\"")
.expect("deserialize home-relative path");
let relative_path = serde_json::from_str::<AbsolutePathBuf>("\"project/file\"")
.expect("deserialize relative path");
(home_path, relative_path)
});
assert_eq!(home_path.as_path(), home_dir.path().join("code"));
assert_eq!(
relative_path.as_path(),
base_dir.path().join("project/file")
);
assert!(serde_json::from_str::<AbsolutePathBuf>("\"project/file\"").is_err());
}
#[test]
fn nested_explicit_home_directories_restore_the_previous_home() {
let outer_home = tempdir().expect("outer home directory");
let inner_home = tempdir().expect("inner home directory");
let (inner_path, restored_path) =
AbsolutePathBufGuard::with_home_directory(outer_home.path(), || {
let inner_path =
AbsolutePathBufGuard::with_home_directory(inner_home.path(), || {
AbsolutePathBuf::from_absolute_path("~/project")
.expect("resolve path with inner home")
});
let restored_path = AbsolutePathBuf::from_absolute_path("~/project")
.expect("resolve path with restored home");
(inner_path, restored_path)
});
assert_eq!(inner_path.as_path(), inner_home.path().join("project"));
assert_eq!(restored_path.as_path(), outer_home.path().join("project"));
}
#[test]
fn home_directory_double_slash_is_expanded_in_deserialization() {
let Some(home) = home_dir() else {