1pub(crate) mod package_wizard;
4pub(crate) mod prompts;
5pub(crate) mod render;
6pub(crate) mod timestamp;
7pub(crate) mod unpack;
8
9use std::path::{Path, PathBuf};
10
11use anyhow::{Context as _, Result, bail};
12use itertools::Itertools;
13use wasmer_wasix::runners::MappedDirectory;
14
15fn retrieve_alias_pathbuf(host_dir: &str, guest_dir: &str) -> Result<MappedDirectory> {
16 let host_dir_path = PathBuf::from(&host_dir).canonicalize()?;
17 if let Ok(pb_metadata) = host_dir_path.metadata() {
18 if !pb_metadata.is_dir() {
19 bail!("\"{}\" exists, but it is not a directory", &host_dir);
20 }
21 } else {
22 bail!("Directory \"{}\" does not exist", &host_dir);
23 }
24 Ok(MappedDirectory {
25 host: host_dir_path,
26 guest: guest_dir.to_string(),
27 })
28}
29
30pub fn parse_volume(entry: &str) -> Result<MappedDirectory> {
32 let components = entry.split(":").collect_vec();
33 match components.as_slice() {
34 [entry] => retrieve_alias_pathbuf(entry, entry),
35 [host_dir, guest_dir] => retrieve_alias_pathbuf(host_dir, guest_dir),
36 _ => bail!(
37 "Directory mappings must consist of a single path, or two paths separate by a `:`. Found {}",
38 &entry
39 ),
40 }
41}
42
43pub fn parse_mapdir(entry: &str) -> Result<MappedDirectory> {
45 let components = entry.split(":").collect_vec();
46 match components.as_slice() {
47 [entry] => retrieve_alias_pathbuf(entry, entry),
48 [guest_dir, host_dir] => retrieve_alias_pathbuf(host_dir, guest_dir),
50 _ => bail!(
51 "Directory mappings must consist of a single path, or two paths separate by a `:`. Found {}",
52 &entry
53 ),
54 }
55}
56
57pub fn parse_envvar(entry: &str) -> Result<(String, String)> {
59 let entry = entry.trim();
60
61 match entry.find('=') {
62 None => bail!(
63 "Environment variable must be of the form `<name>=<value>`; found `{}`",
64 &entry
65 ),
66
67 Some(0) => bail!(
68 "Environment variable is not well formed, the `name` is missing in `<name>=<value>`; got `{}`",
69 &entry
70 ),
71
72 Some(position) if position == entry.len() - 1 => bail!(
73 "Environment variable is not well formed, the `value` is missing in `<name>=<value>`; got `{}`",
74 &entry
75 ),
76
77 Some(position) => Ok((entry[..position].into(), entry[position + 1..].into())),
78 }
79}
80
81pub(crate) const DEFAULT_PACKAGE_MANIFEST_FILE: &str = "wasmer.toml";
82
83pub fn load_package_manifest(
87 path: &Path,
88) -> Result<Option<(PathBuf, wasmer_config::package::Manifest)>, anyhow::Error> {
89 let file_path = if path.is_file() {
90 path.to_owned()
91 } else {
92 path.join(DEFAULT_PACKAGE_MANIFEST_FILE)
93 };
94
95 let contents = match std::fs::read_to_string(&file_path) {
96 Ok(c) => c,
97 Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
98 Err(err) => {
99 return Err(err).with_context(|| {
100 format!(
101 "Could not read package manifest at '{}'",
102 file_path.display()
103 )
104 });
105 }
106 };
107
108 let manifest = wasmer_config::package::Manifest::parse(&contents).with_context(|| {
109 format!(
110 "Could not parse package config at: '{}' - full config: {}",
111 file_path.display(),
112 contents
113 )
114 })?;
115
116 Ok(Some((file_path, manifest)))
117}
118
119pub(crate) fn merge_yaml_values(a: &serde_yaml::Value, b: &serde_yaml::Value) -> serde_yaml::Value {
123 use serde_yaml::Value as V;
124 match (a, b) {
125 (V::Mapping(a), V::Mapping(b)) => {
126 let mut m = a.clone();
127 for (k, v) in b.iter() {
128 let newval = if let Some(old) = a.get(k) {
129 merge_yaml_values(old, v)
130 } else {
131 v.clone()
132 };
133 m.insert(k.clone(), newval);
134 }
135 V::Mapping(m)
136 }
137 _ => b.clone(),
138 }
139}
140
141#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_merge_yaml_values() {
159 use serde_yaml::Value;
160 let v1 = r#"
161a: a
162b:
163 b1: b1
164c: c
165 "#;
166 let v2 = r#"
167a: a1
168b:
169 b2: b2
170 "#;
171 let v3 = r#"
172a: a1
173b:
174 b1: b1
175 b2: b2
176c: c
177 "#;
178
179 let a: Value = serde_yaml::from_str(v1).unwrap();
180 let b: Value = serde_yaml::from_str(v2).unwrap();
181 let c: Value = serde_yaml::from_str(v3).unwrap();
182 let merged = merge_yaml_values(&a, &b);
183 assert_eq!(merged, c);
184 }
185
186 #[test]
187 fn test_parse_envvar() {
188 assert_eq!(
189 parse_envvar("A").unwrap_err().to_string(),
190 "Environment variable must be of the form `<name>=<value>`; found `A`"
191 );
192 assert_eq!(
193 parse_envvar("=A").unwrap_err().to_string(),
194 "Environment variable is not well formed, the `name` is missing in `<name>=<value>`; got `=A`"
195 );
196 assert_eq!(
197 parse_envvar("A=").unwrap_err().to_string(),
198 "Environment variable is not well formed, the `value` is missing in `<name>=<value>`; got `A=`"
199 );
200 assert_eq!(parse_envvar("A=B").unwrap(), ("A".into(), "B".into()));
201 assert_eq!(parse_envvar(" A=B\t").unwrap(), ("A".into(), "B".into()));
202 assert_eq!(
203 parse_envvar("A=B=C=D").unwrap(),
204 ("A".into(), "B=C=D".into())
205 );
206 }
207}