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