use std::path::PathBuf;
use crate::addr::RemoteEndpoint;
use crate::filesystem::Filesystem;
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct ResourceLocation {
#[serde(alias = "target")]
pub filesystem: Filesystem,
#[serde(with = "strop_core::path_serde")]
pub path: PathBuf,
}
impl ResourceLocation {
pub fn local(path: PathBuf) -> Self {
Self {
filesystem: Filesystem::Local,
path,
}
}
pub fn remote(endpoint: RemoteEndpoint, path: PathBuf) -> Self {
Self {
filesystem: Filesystem::Remote(endpoint),
path,
}
}
pub fn label(&self) -> String {
match &self.filesystem {
Filesystem::Local => self.path.display().to_string(),
other => format!("{}{}", other.label(), self.path.display()),
}
}
pub fn local_path(&self) -> Option<&std::path::Path> {
match &self.filesystem {
Filesystem::Local => Some(&self.path),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn decodes_the_legacy_docpath_shape() {
let legacy = serde_json::json!({
"target": "Local",
"path": "/workspace/a.rs",
});
let location: ResourceLocation = serde_json::from_value(legacy).unwrap();
assert_eq!(location.filesystem, Filesystem::Local);
assert_eq!(location.path, PathBuf::from("/workspace/a.rs"));
let endpoint = RemoteEndpoint::parse("ssh://user@example.com:2222").unwrap();
let legacy = serde_json::json!({
"target": { "Remote": endpoint },
"path": "/var/log/app.log",
});
let location: ResourceLocation = serde_json::from_value(legacy).unwrap();
assert_eq!(location.filesystem, Filesystem::Remote(endpoint));
}
#[test]
fn remote_resources_never_expose_a_local_path() {
let endpoint = RemoteEndpoint::parse("ssh://example.com").unwrap();
let location = ResourceLocation::remote(endpoint, PathBuf::from("/etc/hostname"));
assert_eq!(location.local_path(), None);
assert!(location.label().starts_with("ssh://example.com"));
}
}