fix: introduce AbsolutePathBuf as part of sandbox config

This commit is contained in:
Michael Bolin
2025-12-10 18:41:46 -08:00
parent 3fc8b2894f
commit 39c5b2acfa
26 changed files with 174 additions and 66 deletions

View File

@@ -10,7 +10,12 @@ workspace = true
[dependencies]
path-absolutize = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true, features = ["derive"] }
ts-rs = { workspace = true, features = [
"serde-json-impl",
"no-serde-warnings",
] }
[dev-dependencies]
serde_json = { workspace = true }

View File

@@ -1,4 +1,5 @@
use path_absolutize::Absolutize;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
@@ -7,6 +8,7 @@ use std::cell::RefCell;
use std::path::Display;
use std::path::Path;
use std::path::PathBuf;
use ts_rs::TS;
/// A path that is guaranteed to be absolute and normalized (though it is not
/// guaranteed to be canonicalized or exist on the filesystem).
@@ -15,27 +17,27 @@ use std::path::PathBuf;
/// using `AbsolutePathBufGuard::new(base_path)`. If no base path is set, the
/// deserialization will fail unless the path being deserialized is already
/// absolute.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, JsonSchema, TS)]
pub struct AbsolutePathBuf(PathBuf);
impl AbsolutePathBuf {
pub fn resolve_path_against_base<P, B>(path: P, base_path: B) -> std::io::Result<Self>
where
P: AsRef<Path>,
B: AsRef<Path>,
{
pub fn resolve_path_against_base<P: AsRef<Path>, B: AsRef<Path>>(
path: P,
base_path: B,
) -> std::io::Result<Self> {
let absolute_path = path.as_ref().absolutize_from(base_path.as_ref())?;
Ok(Self(absolute_path.into_owned()))
}
pub fn from_absolute_path<P>(path: P) -> std::io::Result<Self>
where
P: AsRef<Path>,
{
pub fn from_absolute_path<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
let absolute_path = path.as_ref().absolutize()?;
Ok(Self(absolute_path.into_owned()))
}
pub fn join<P: AsRef<Path>>(&self, path: P) -> std::io::Result<Self> {
Self::resolve_path_against_base(path, &self.0)
}
pub fn as_path(&self) -> &Path {
&self.0
}
@@ -48,11 +50,59 @@ impl AbsolutePathBuf {
self.0.clone()
}
pub fn to_string_lossy(&self) -> std::borrow::Cow<'_, str> {
self.0.to_string_lossy()
}
pub fn display(&self) -> Display<'_> {
self.0.display()
}
}
impl AsRef<Path> for AbsolutePathBuf {
fn as_ref(&self) -> &Path {
&self.0
}
}
impl From<AbsolutePathBuf> for PathBuf {
fn from(path: AbsolutePathBuf) -> Self {
path.into_path_buf()
}
}
impl TryFrom<&Path> for AbsolutePathBuf {
type Error = std::io::Error;
fn try_from(value: &Path) -> Result<Self, Self::Error> {
Self::from_absolute_path(value)
}
}
impl TryFrom<PathBuf> for AbsolutePathBuf {
type Error = std::io::Error;
fn try_from(value: PathBuf) -> Result<Self, Self::Error> {
Self::from_absolute_path(value)
}
}
impl TryFrom<&str> for AbsolutePathBuf {
type Error = std::io::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
Self::from_absolute_path(value)
}
}
impl TryFrom<String> for AbsolutePathBuf {
type Error = std::io::Error;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::from_absolute_path(value)
}
}
thread_local! {
static ABSOLUTE_PATH_BASE: RefCell<Option<PathBuf>> = const { RefCell::new(None) };
}
@@ -96,18 +146,6 @@ impl<'de> Deserialize<'de> for AbsolutePathBuf {
}
}
impl AsRef<Path> for AbsolutePathBuf {
fn as_ref(&self) -> &Path {
self.as_path()
}
}
impl From<AbsolutePathBuf> for PathBuf {
fn from(path: AbsolutePathBuf) -> Self {
path.into_path_buf()
}
}
#[cfg(test)]
mod tests {
use super::*;