wapm_cli/data/lock/
lockfile.rs1use crate::data::lock::lockfile_command::LockfileCommand;
2use crate::data::lock::lockfile_module::{
3 LockfileModule, LockfileModuleV2, LockfileModuleV3, LockfileModuleV4,
4};
5use crate::data::lock::{LOCKFILE_HEADER, LOCKFILE_NAME};
6use semver::Version;
7use std::collections::BTreeMap;
8use std::fs::File;
9use std::io;
10use std::io::Write;
11use std::path::Path;
12use thiserror::Error;
13
14pub type ModuleMapV2 = BTreeMap<String, BTreeMap<Version, BTreeMap<String, LockfileModuleV2>>>;
15pub type CommandMapV2 = BTreeMap<String, LockfileCommand>;
16
17#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
20pub struct LockfileV2 {
21 pub modules: ModuleMapV2, pub commands: CommandMapV2, }
24
25pub type ModuleMapV3 = BTreeMap<String, BTreeMap<Version, BTreeMap<String, LockfileModuleV3>>>;
26pub type CommandMapV3 = BTreeMap<String, LockfileCommand>;
27
28#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
30pub struct LockfileV3 {
31 pub modules: ModuleMapV3, pub commands: CommandMapV3, }
34
35pub type ModuleMap = BTreeMap<String, BTreeMap<Version, BTreeMap<String, LockfileModuleV4>>>;
36pub type CommandMap = BTreeMap<String, LockfileCommand>;
37
38#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
40pub struct Lockfile {
41 pub modules: ModuleMap, pub commands: CommandMap, }
44
45pub type LockfileV4 = Lockfile;
46pub type ModuleMapV4 = ModuleMap;
47pub type CommandMapV4 = CommandMap;
48
49impl Lockfile {
50 pub fn save<P: AsRef<Path>>(&self, directory: P) -> anyhow::Result<()> {
52 let lockfile_string = toml::to_string(self)?;
53 let lockfile_string = format!("{}\n{}", LOCKFILE_HEADER, lockfile_string);
54 let lockfile_path = directory.as_ref().join(LOCKFILE_NAME);
55 let mut file = File::create(lockfile_path)?;
56 file.write_all(lockfile_string.as_bytes())?;
57 Ok(())
58 }
59
60 pub fn get_prehashed_cache_key_from_command(
62 &self,
63 command: &LockfileCommand,
64 ) -> Option<String> {
65 self.modules
66 .get(&command.package_name)
67 .and_then(|version_map| version_map.get(&command.package_version))
68 .and_then(|module_map| module_map.get(&command.module))
69 .and_then(|module| module.prehashed_module_key.clone())
70 }
71
72 pub fn get_command(&self, command_name: &str) -> Result<&LockfileCommand, LockfileError> {
73 self.commands
74 .get(command_name)
75 .ok_or_else(|| LockfileError::CommandNotFound(command_name.to_string()))
76 }
77
78 pub fn get_module(
79 &self,
80 package_name: &str,
81 package_version: &Version,
82 module_name: &str,
83 ) -> anyhow::Result<&LockfileModule> {
84 let version_map = self.modules.get(package_name).ok_or_else(|| {
85 LockfileError::PackageWithVersionNotFoundWhenFindingModule(
86 package_name.to_string(),
87 package_version.to_string(),
88 module_name.to_string(),
89 )
90 })?;
91 let module_map = version_map.get(package_version).ok_or_else(|| {
92 LockfileError::VersionNotFoundForPackageWhenFindingModule(
93 package_name.to_string(),
94 package_version.to_string(),
95 module_name.to_string(),
96 )
97 })?;
98 let module = module_map.get(module_name).ok_or_else(|| {
99 LockfileError::ModuleForPackageVersionNotFound(
100 package_name.to_string(),
101 package_version.to_string(),
102 module_name.to_string(),
103 )
104 })?;
105 Ok(module)
106 }
107}
108
109#[derive(Debug, Error)]
110pub enum LockfileError {
111 #[error("Command not found: {0}")]
112 CommandNotFound(String),
113 #[error("module {2} in package \"{0} {1}\" was not found")]
114 ModuleForPackageVersionNotFound(String, String, String),
115 #[error("Module \"{2}\" with package name \"{0}\" and version \"{1}\" was not found.")]
116 PackageWithVersionNotFoundWhenFindingModule(String, String, String),
117 #[error(
118 "version \"{1}\" for package \"{0}\" was not found when searching for module \"{2}\"."
119 )]
120 VersionNotFoundForPackageWhenFindingModule(String, String, String),
121 #[error("Lockfile file not found.")]
122 MissingLockfile,
123 #[error("File I/O error reading lockfile. I/O error: {0:?}")]
124 FileIoErrorReadingLockfile(io::Error),
125 #[error(
126 "Failed to parse lockfile toml. Did you modify the generated lockfile? Toml error: {0:?}"
127 )]
128 TomlParseError(toml::de::Error),
129}