1use crate::{
2 error::{BundleError, MrBundleResult},
3 ResourceBytes,
4};
5use holochain_util::ffs;
6use std::path::{Path, PathBuf};
7
8#[derive(Clone, Debug, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[serde(rename_all = "snake_case")]
15#[allow(missing_docs)]
16pub enum Location {
17 Bundled(PathBuf),
19
20 Path(PathBuf),
22
23 Url(String),
25}
26
27impl Location {
28 pub fn normalize(&self, root_dir: Option<&PathBuf>) -> MrBundleResult<Location> {
30 if let Location::Path(path) = self {
31 if path.is_relative() {
32 if let Some(dir) = root_dir {
33 Ok(Location::Path(ffs::sync::canonicalize(dir.join(path))?))
34 } else {
35 Err(BundleError::RelativeLocalPath(path.to_owned()).into())
36 }
37 } else {
38 Ok(self.clone())
39 }
40 } else {
41 Ok(self.clone())
42 }
43 }
44}
45
46#[cfg(feature = "fuzzing")]
47impl proptest::arbitrary::Arbitrary for Location {
48 type Parameters = ();
49 type Strategy = proptest::strategy::BoxedStrategy<Self>;
50
51 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
54 use proptest::strategy::Strategy;
55
56 proptest::prelude::any::<String>()
57 .prop_map(|s| Self::Path(s.into()))
58 .boxed()
59 }
60}
61
62pub(crate) async fn resolve_local(path: &Path) -> MrBundleResult<ResourceBytes> {
63 Ok(ffs::read(path).await?.into())
64}
65
66pub(crate) async fn resolve_remote(url: &str) -> MrBundleResult<ResourceBytes> {
67 Ok(reqwest::get(url)
68 .await?
69 .bytes()
70 .await?
71 .into_iter()
72 .collect::<Vec<_>>()
73 .into())
74}
75
76#[cfg(test)]
77mod tests {
78
79 use super::*;
80 use serde::{Deserialize, Serialize};
81 use serde_yaml::value::{Tag, TaggedValue};
82
83 #[derive(Serialize, Deserialize)]
84 struct TunaSalad {
85 celery: Vec<Location>,
86
87 #[serde(flatten)]
88 mayo: Location,
89 }
90
91 #[test]
103 fn location_flattening() {
104 use serde_yaml::Value;
105
106 let tuna = TunaSalad {
107 celery: vec![Location::Bundled("b".into()), Location::Path("p".into())],
108 mayo: Location::Url("http://r.co".into()),
109 };
110 let val = serde_yaml::to_value(&tuna).unwrap();
111 println!("yaml produced:\n{}", serde_yaml::to_string(&tuna).unwrap());
112
113 assert_eq!(
114 val["celery"][0],
115 Value::Tagged(Box::new(TaggedValue {
116 tag: Tag::new("!bundled"),
117 value: Value::from("b")
118 }))
119 );
120 assert_eq!(
121 val["celery"][1],
122 Value::Tagged(Box::new(TaggedValue {
123 tag: Tag::new("!path"),
124 value: Value::from("p")
125 }))
126 );
127 assert_eq!(val["url"], Value::from("http://r.co"));
128 }
129}