wapm_cli/data/lock/
migrate.rs1use crate::data::lock::lockfile::{LockfileV2, LockfileV3, LockfileV4};
7use crate::data::lock::lockfile_command::LockfileCommand;
8use crate::data::lock::lockfile_module::{LockfileModuleV2, LockfileModuleV3, LockfileModuleV4};
9use crate::data::manifest::PACKAGES_DIR_NAME;
10use crate::dataflow::lockfile_packages::LockfileError;
11use crate::dataflow::normalize_global_namespace_package_name;
12
13use lazy_static::lazy_static;
14use regex::Regex;
15use std::collections::*;
16use std::path::{Path, PathBuf};
17
18pub enum LockfileVersion {
20 V1(LockfileV2),
21 V2(LockfileV2),
22 V3(LockfileV3),
23 V4(LockfileV4),
24}
25
26lazy_static! {
27 static ref VER_NUM_RE: Regex = Regex::new(r"^# Lockfile v(\d+)$").unwrap();
28}
29
30impl LockfileVersion {
31 pub fn from_lockfile_string(raw_string: &str) -> Result<Self, LockfileError> {
32 let first_line = raw_string
33 .lines()
34 .next()
35 .ok_or(LockfileError::InvalidOrMissingVersion)?;
36 let lockfile_version = (*VER_NUM_RE)
37 .captures_iter(first_line)
38 .map(|captures| captures[1].parse::<usize>())
39 .next()
40 .ok_or(LockfileError::InvalidOrMissingVersion)?
41 .map_err(|_| LockfileError::InvalidOrMissingVersion)?;
42
43 match lockfile_version {
44 1 => {
45 let lockfile_v1 = toml::from_str::<LockfileV2>(raw_string)
46 .map_err(|e| LockfileError::LockfileTomlParseError(e.to_string()))?;
47 Ok(LockfileVersion::V1(lockfile_v1))
48 }
49 2 => {
50 let lockfile_v2 = toml::from_str::<LockfileV2>(raw_string)
51 .map_err(|e| LockfileError::LockfileTomlParseError(e.to_string()))?;
52 Ok(LockfileVersion::V2(lockfile_v2))
53 }
54 3 => {
55 let lockfile_v3 = toml::from_str::<LockfileV3>(raw_string)
56 .map_err(|e| LockfileError::LockfileTomlParseError(e.to_string()))?;
57 Ok(LockfileVersion::V3(lockfile_v3))
58 }
59 4 => {
60 let lockfile_v4 = toml::from_str::<LockfileV4>(raw_string)
61 .map_err(|e| LockfileError::LockfileTomlParseError(e.to_string()))?;
62 Ok(LockfileVersion::V4(lockfile_v4))
63 }
64 0 => Err(LockfileError::InvalidOrMissingVersion),
65 _ => Err(LockfileError::VersionTooHigh),
66 }
67 }
68}
69
70pub fn fix_up_v1_package_names(lockfile: &mut LockfileV2) {
71 for command in lockfile.commands.iter_mut() {
72 let (_, command): (&String, &mut LockfileCommand) = command;
73 let package_name =
74 normalize_global_namespace_package_name(command.package_name.as_str().into());
75 command.package_name = package_name.to_string();
76 }
77 lockfile.modules = lockfile
78 .modules
79 .clone()
80 .into_iter()
81 .map(|(package_name, mut versions)| {
82 let correct_name =
83 normalize_global_namespace_package_name(package_name.as_str().into()).to_string();
84
85 for (_version, modules) in versions.iter_mut() {
86 for (_module_name, module) in modules.iter_mut() {
87 let module: &mut LockfileModuleV2 = module;
88 module.package_name = correct_name.clone();
89 }
90 }
91 (correct_name, versions)
92 })
93 .collect();
94}
95
96pub fn convert_lockfilev2_to_v3(lockfile: LockfileV2) -> LockfileV3 {
97 let mut modules: BTreeMap<String, _> = Default::default();
98 for (k1, version_map) in lockfile.modules.into_iter() {
99 let mut ver_map: BTreeMap<semver::Version, BTreeMap<_, _>> = Default::default();
100 for (k2, module_map) in version_map.into_iter() {
101 let mut name_map: BTreeMap<String, LockfileModuleV3> = Default::default();
102 for (k3, module_data) in module_map.into_iter() {
103 let module = LockfileModuleV3 {
104 name: module_data.name,
105 package_version: module_data.package_version,
106 package_name: module_data.package_name,
107 source: module_data.source,
108 resolved: module_data.resolved,
109 abi: module_data.abi,
110 entry: module_data.entry.clone(),
111 root: {
112 let mut entry = PathBuf::from(module_data.entry);
113 entry.pop();
115 entry.to_string_lossy().to_string()
116 },
117 prehashed_module_key: None,
118 };
119 name_map.insert(k3, module);
120 }
121 ver_map.insert(k2, name_map);
122 }
123 modules.insert(k1, ver_map);
124 }
125 LockfileV3 {
126 modules,
127 commands: lockfile.commands,
128 }
129}
130
131pub fn convert_lockfilev3_to_v4(lockfile: LockfileV3, directory: &Path) -> LockfileV4 {
132 let dir_prefix = directory.join(PACKAGES_DIR_NAME);
133
134 let mut modules: BTreeMap<String, _> = Default::default();
135 for (k1, version_map) in lockfile.modules.into_iter() {
136 let mut ver_map: BTreeMap<semver::Version, BTreeMap<_, _>> = Default::default();
137 for (k2, module_map) in version_map.into_iter() {
138 let mut name_map: BTreeMap<String, LockfileModuleV4> = Default::default();
139 for (k3, module_data) in module_map.into_iter() {
140 let package_path = format!(
141 "{}@{}",
142 &module_data.package_name, &module_data.package_version
143 );
144 let module = LockfileModuleV4 {
145 name: module_data.name,
146 package_version: module_data.package_version,
147 package_name: module_data.package_name,
148 resolved: module_data.resolved,
149 resolved_source: module_data.source,
150 abi: module_data.abi,
151 source: {
152 let full_prefix = dir_prefix.join(&package_path);
153 let path = directory.join(&module_data.entry);
156 path.strip_prefix(&full_prefix)
157 .expect("Corrupt data in Lockfile, please delete it and try again")
158 .to_string_lossy()
159 .to_string()
160 },
161 package_path,
162 prehashed_module_key: module_data.prehashed_module_key,
163 };
164 name_map.insert(k3, module);
165 }
166 ver_map.insert(k2, name_map);
167 }
168 modules.insert(k1, ver_map);
169 }
170 LockfileV4 {
171 modules,
172 commands: lockfile.commands,
173 }
174}
175
176#[cfg(test)]
177mod test {
178 use super::*;
179 use crate::data::lock::lockfile::{LockfileV2, LockfileV3, LockfileV4};
180 use std::path::Path;
181
182 #[test]
183 fn test_fix_up_v1_lockfile() {
184 let v1_lockfile_toml = toml! {
185 [modules.sqlite."0.1.1".sqlite]
186 name = "sqlite"
187 package_version = "0.1.1"
188 package_name = "sqlite"
189 source = "registry+sqlite"
190 resolved = "https://registry-cdn.wapm.dev/packages/_/sqlite/sqlite-0.1.1.tar.gz"
191 abi = "emscripten"
192 entry = "wapm_packages\\_\\sqlite@0.1.1\\sqlite.wasm"
193 [commands.sqlite]
194 name = "sqlite"
195 package_name = "sqlite"
196 package_version = "0.1.1"
197 module = "sqlite"
198 is_top_level_dependency = true
199 };
200
201 let mut lockfile: LockfileV2 = toml::from_str(&v1_lockfile_toml.to_string()).unwrap();
202
203 let v2_lockfile_toml = toml! {
204 [modules."_/sqlite"."0.1.1".sqlite]
205 name = "sqlite"
206 package_version = "0.1.1"
207 package_name = "_/sqlite"
208 source = "registry+sqlite"
209 resolved = "https://registry-cdn.wapm.dev/packages/_/sqlite/sqlite-0.1.1.tar.gz"
210 abi = "emscripten"
211 entry = "wapm_packages\\_\\sqlite@0.1.1\\sqlite.wasm"
212 [commands.sqlite]
213 name = "sqlite"
214 package_name = "_/sqlite"
215 package_version = "0.1.1"
216 module = "sqlite"
217 is_top_level_dependency = true
218 };
219
220 let expected_v2_lockfile: LockfileV2 =
221 toml::from_str(&v2_lockfile_toml.to_string()).unwrap();
222
223 fix_up_v1_package_names(&mut lockfile);
224
225 assert_eq!(expected_v2_lockfile, lockfile);
226 }
227
228 #[test]
229 fn upgrade_to_v3() {
230 let v1_lockfile_toml = toml! {
231 [modules.sqlite."0.1.1".sqlite]
232 name = "sqlite"
233 package_version = "0.1.1"
234 package_name = "sqlite"
235 source = "registry+sqlite"
236 resolved = "https://registry-cdn.wapm.dev/packages/_/sqlite/sqlite-0.1.1.tar.gz"
237 abi = "emscripten"
238 entry = "wapm_packages/_/sqlite@0.1.1/sqlite.wasm"
239 [commands.sqlite]
240 name = "sqlite"
241 package_name = "sqlite"
242 package_version = "0.1.1"
243 module = "sqlite"
244 is_top_level_dependency = true
245 };
246
247 let mut lockfile_v1: LockfileV2 = toml::from_str(&v1_lockfile_toml.to_string()).unwrap();
248
249 let v3_lockfile_toml = toml! {
250 [modules."_/sqlite"."0.1.1".sqlite]
251 name = "sqlite"
252 package_version = "0.1.1"
253 package_name = "_/sqlite"
254 source = "registry+sqlite"
255 resolved = "https://registry-cdn.wapm.dev/packages/_/sqlite/sqlite-0.1.1.tar.gz"
256 abi = "emscripten"
257 entry = "wapm_packages/_/sqlite@0.1.1/sqlite.wasm"
258 root = "wapm_packages/_/sqlite@0.1.1"
259 [commands.sqlite]
260 name = "sqlite"
261 package_name = "_/sqlite"
262 package_version = "0.1.1"
263 module = "sqlite"
264 is_top_level_dependency = true
265 };
266
267 let expected_v3_lockfile: LockfileV3 =
268 toml::from_str(&v3_lockfile_toml.to_string()).unwrap();
269
270 fix_up_v1_package_names(&mut lockfile_v1);
271 let converted_lockfile_v3 = convert_lockfilev2_to_v3(lockfile_v1);
272
273 assert_eq!(expected_v3_lockfile, converted_lockfile_v3);
274 }
275
276 #[test]
277 fn upgrade_to_v4() {
278 let directory = Path::new("/home/shiba/project");
279
280 let v3_lockfile_toml = toml! {
281 [modules."_/sqlite"."0.1.1".sqlite]
282 name = "sqlite"
283 package_version = "0.1.1"
284 package_name = "_/sqlite"
285 source = "registry+sqlite"
286 resolved = "https://registry-cdn.wapm.dev/packages/_/sqlite/sqlite-0.1.1.tar.gz"
287 abi = "emscripten"
288 entry = "/home/shiba/project/wapm_packages/_/sqlite@0.1.1/sqlite.wasm"
289 root = "/home/shiba/project/wapm_packages/_/sqlite@0.1.1"
290 [commands.sqlite]
291 name = "sqlite"
292 package_name = "_/sqlite"
293 package_version = "0.1.1"
294 module = "sqlite"
295 is_top_level_dependency = true
296 };
297
298 let v3_lockfile: LockfileV3 = toml::from_str(&v3_lockfile_toml.to_string()).unwrap();
299
300 let v4_lockfile_toml = toml! {
301 [modules."_/sqlite"."0.1.1".sqlite]
302 name = "sqlite"
303 package_version = "0.1.1"
304 package_name = "_/sqlite"
305 package_path = "_/sqlite@0.1.1"
306 resolved = "https://registry-cdn.wapm.dev/packages/_/sqlite/sqlite-0.1.1.tar.gz"
307 resolved_source = "registry+sqlite"
308 abi = "emscripten"
309 source = "sqlite.wasm"
310 [commands.sqlite]
311 name = "sqlite"
312 package_name = "_/sqlite"
313 package_version = "0.1.1"
314 module = "sqlite"
315 is_top_level_dependency = true
316 };
317
318 let v4_lockfile: LockfileV4 = toml::from_str(&v4_lockfile_toml.to_string()).unwrap();
319
320 let v4_lockfile_converted = convert_lockfilev3_to_v4(v3_lockfile, directory);
321
322 assert_eq!(v4_lockfile, v4_lockfile_converted);
323 }
324}