1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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?)
}
pub(crate) async fn resolve_remote(url: &str) -> MrBundleResult<ResourceBytes> {
Ok(reqwest::get(url)
.await?
.bytes()
.await?
.into_iter()
.collect())
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[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]["bundled"], Value::from("b"));
assert_eq!(val["celery"][1]["path"], Value::from("p"));
assert_eq!(val["url"], Value::from("http://r.co"));
}
}