wapm_cli/data/
wax_index.rs1use crate::config;
5use crate::constants::RFC3339_FORMAT_STRING;
6use semver::Version;
7use std::convert::From;
8use std::env;
9use std::fs;
10use std::io::{self, Read, Write};
11use std::path::{Path, PathBuf};
12use thiserror::Error;
13
14use std::collections::HashMap;
15
16#[derive(Debug, Deserialize, Serialize)]
17pub struct WaxIndex {
18 base_dir: PathBuf,
19 index: HashMap<String, WaxEntry>,
20}
21
22#[derive(Debug, Deserialize, Serialize)]
23struct WaxEntry {
24 package_name: String,
26 last_updated: String,
28}
29
30impl WaxEntry {
31 fn new(name: String, version: Version, time: String) -> Self {
32 WaxEntry {
33 package_name: format!("{}@{}", name, version),
34 last_updated: time,
35 }
36 }
37}
38
39impl WaxIndex {
40 pub fn open() -> Result<Self, WaxIndexError> {
42 trace!("Loading WaxIndex!");
43 let wax_path = config::Config::get_wax_file_path()?;
44 let wax_index = if wax_path.exists() {
45 let mut f = fs::OpenOptions::new().read(true).open(wax_path)?;
46
47 let index_str = {
48 let mut s = String::new();
49 f.read_to_string(&mut s)?;
50 s
51 };
52
53 if index_str.is_empty() {
54 WaxIndex {
55 index: Default::default(),
56 base_dir: env::temp_dir().join("wax"),
57 }
58 } else {
59 serde_json::from_str(&index_str)?
60 }
61 } else {
62 WaxIndex {
63 index: Default::default(),
64 base_dir: env::temp_dir().join("wax"),
65 }
66 };
67
68 fs::create_dir_all(&wax_index.base_dir)?;
70 trace!("WaxIndex created!");
71
72 Ok(wax_index)
73 }
74
75 pub fn save(&self) -> Result<(), WaxIndexError> {
77 trace!("Saving WaxIndex!");
78 let wax_path = config::Config::get_wax_file_path()?;
79 let mut f = fs::OpenOptions::new()
80 .write(true)
81 .create(true)
82 .truncate(true)
83 .open(wax_path)?;
84
85 let json_str = serde_json::to_string(self)?;
86
87 f.write_all(json_str.as_bytes())?;
88 trace!("WaxIndex saved!");
89 Ok(())
90 }
91
92 pub fn search_for_entry(
95 &mut self,
96 entry: String,
97 ) -> Result<(String, Version, time::Timespec), WaxIndexError> {
98 if let Some(WaxEntry {
99 package_name,
100 last_updated,
101 }) = self.index.get(&entry)
102 {
103 let location = self.base_path().join(package_name);
104 if location.exists() {
106 trace!("Wax entry found and it still exists!");
107 let mut splitter = package_name.split('@');
108 let package_name = splitter
109 .next()
110 .ok_or_else(|| WaxIndexError::EntryCorrupt {
111 entry: entry.clone(),
112 })?
113 .to_string();
114 let version = splitter
115 .next()
116 .and_then(|v| Version::parse(v).ok())
117 .ok_or_else(|| WaxIndexError::EntryCorrupt {
118 entry: entry.clone(),
119 })?;
120 let last_seen =
121 time::strptime(last_updated, RFC3339_FORMAT_STRING).map_err(|e| {
122 WaxIndexError::EntryCorrupt {
123 entry: e.to_string(),
124 }
125 })?;
126 return Ok((package_name, version, last_seen.to_timespec()));
127 }
128 trace!("Wax entry found but it no longer exists, removing from registry!");
129 self.index.remove(&entry);
130 }
131 Err(WaxIndexError::EntryNotFound {
132 entry: entry.clone(),
133 })
134 }
135
136 pub fn insert_entry(&mut self, entry: String, version: Version, package_name: String) -> bool {
140 let now = time::now_utc();
141 let now_str = time::strftime(RFC3339_FORMAT_STRING, &now).expect("Format current time!");
142 self.index
143 .insert(entry, WaxEntry::new(package_name, version, now_str))
144 .is_some()
145 }
146
147 pub fn base_path(&self) -> &Path {
149 &self.base_dir
150 }
151}
152
153#[derive(Debug, Error)]
154pub enum WaxIndexError {
155 #[error("Error finding Wax Index: {0}")]
156 ConfigError(config::GlobalConfigError),
157 #[error("Failed to operate on Wax index file: `{0}`")]
158 IoError(io::Error),
159 #[error("Failed to parse WaxIndex from JSON or convert WaxIndex to JSON: `{0}`")]
160 SerdeError(serde_json::error::Error),
161 #[error("Entry `{entry}` not found")]
162 EntryNotFound { entry: String },
163 #[error("Entry `{entry}` found but was corrupt")]
164 EntryCorrupt { entry: String },
165}
166
167impl From<config::GlobalConfigError> for WaxIndexError {
168 fn from(other: config::GlobalConfigError) -> Self {
169 WaxIndexError::ConfigError(other)
170 }
171}
172
173impl From<io::Error> for WaxIndexError {
174 fn from(other: io::Error) -> Self {
175 WaxIndexError::IoError(other)
176 }
177}
178
179impl From<serde_json::error::Error> for WaxIndexError {
180 fn from(other: serde_json::error::Error) -> Self {
181 WaxIndexError::SerdeError(other)
182 }
183}