use crate::{
error::{BundleError, MrBundleResult},
ResourceBytes,
};
use holochain_util::ffs;
use std::path::{Path, PathBuf};
#[derive(Clone, Debug, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[allow(missing_docs)]
pub enum Location {
Bundled(PathBuf),
Path(PathBuf),
Url(String),
}
impl Location {
pub fn normalize(&self, root_dir: Option<&PathBuf>) -> MrBundleResult<Location> {
if let Location::Path(path) = self {
if path.is_relative() {
if let Some(dir) = root_dir {
Ok(Location::Path(ffs::sync::canonicalize(dir.join(path))?))
} else {
Err(BundleError::RelativeLocalPath(path.to_owned()).into())
}
} else {
Ok(self.clone())
}
} else {
Ok(self.clone())
}
}
}
pub(crate) async fn resolve_local(path: &Path) -> MrBundleResult<ResourceBytes> {
Ok(ffs::read(path).await?.into())
}
pub(crate) async fn resolve_remote(url: &str) -> MrBundleResult<ResourceBytes> {
Ok(reqwest::get(url)
.await?
.bytes()
.await?
.into_iter()
.collect::<Vec<_>>()
.into())
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
use serde_yaml::value::{Tag, TaggedValue};
#[derive(Serialize, Deserialize)]
struct TunaSalad {
celery: Vec<Location>,
#[serde(flatten)]
mayo: Location,
}
#[test]
fn location_flattening() {
use serde_yaml::Value;
let tuna = TunaSalad {
celery: vec![Location::Bundled("b".into()), Location::Path("p".into())],
mayo: Location::Url("http://r.co".into()),
};
let val = serde_yaml::to_value(&tuna).unwrap();
println!("yaml produced:\n{}", serde_yaml::to_string(&tuna).unwrap());
assert_eq!(
val["celery"][0],
Value::Tagged(Box::new(TaggedValue {
tag: Tag::new("!bundled"),
value: Value::from("b")
}))
);
assert_eq!(
val["celery"][1],
Value::Tagged(Box::new(TaggedValue {
tag: Tag::new("!path"),
value: Value::from("p")
}))
);
assert_eq!(val["url"], Value::from("http://r.co"));
}
}