1use crate::fs;
2use crate::fs::write_options::WriteOptions;
3use crate::PackageJson;
4use anyhow::{format_err, Result};
5use std::env;
6use std::path::{Path, PathBuf};
7
8pub const PACKAGE_JSON_FILENAME: &str = "package.json";
9
10#[derive(Debug)]
12pub struct PackageJsonManager {
13 file_path: Option<PathBuf>,
14 json: PackageJson,
15 write_options: Option<WriteOptions>,
16}
17
18impl Default for PackageJsonManager {
19 fn default() -> Self {
20 Self {
21 file_path: None,
22 json: Default::default(),
23 write_options: Some(WriteOptions::default()),
24 }
25 }
26}
27
28impl PackageJsonManager {
29 pub fn new() -> Self {
31 Default::default()
32 }
33
34 pub fn with_file_path<FilePath>(path: FilePath) -> Self
40 where
41 FilePath: AsRef<Path>,
42 {
43 Self {
44 file_path: Some(path.as_ref().to_path_buf()),
45 ..Default::default()
46 }
47 }
48
49 pub fn with_write_options(options: WriteOptions) -> Self {
59 Self {
60 write_options: Some(options),
61 ..Default::default()
62 }
63 }
64
65 pub fn locate_closest(&mut self) -> Result<PathBuf> {
67 env::current_dir().map(|cwd| self.locate_closest_from(cwd))?
68 }
69
70 pub fn locate_closest_from<P: AsRef<Path>>(&mut self, from: P) -> Result<PathBuf> {
72 fs::find_closest_file(PACKAGE_JSON_FILENAME, from).map(|file_path| {
73 self.file_path = Some(file_path);
74 self.file_path.as_ref().unwrap().to_owned()
75 })
76 }
77
78 pub fn set_file_path<FilePath: AsRef<Path>>(&mut self, file_path: FilePath) {
80 self.file_path = Some(file_path.as_ref().to_path_buf());
81 }
82
83 pub fn get_file_path(&mut self) -> Option<&Path> {
85 self.file_path.as_deref()
86 }
87
88 pub fn take_file_path(&mut self) -> Option<PathBuf> {
90 self.file_path.take()
91 }
92
93 fn read(&mut self) -> Result<()> {
95 self
96 .file_path
97 .as_ref()
98 .map(|file_path| {
99 fs::read_json(file_path).map(|json| {
100 self.json = json;
101 })
102 })
103 .unwrap_or_else(|| {
104 Err(format_err!(
105 "Couldn't find an available {} file.",
106 PACKAGE_JSON_FILENAME
107 ))
108 })
109 }
110
111 pub fn read_ref(&mut self) -> Result<&PackageJson> {
123 self.read().map(|_| &self.json)
124 }
125
126 pub fn read_mut(&mut self) -> Result<&mut PackageJson> {
137 self.read().map(|_| &mut self.json)
138 }
139
140 pub fn write(&mut self) -> Result<()> {
153 self
154 .file_path
155 .as_ref()
156 .map(|file_path| {
157 fs::write_json(
158 file_path,
159 &self.json,
160 self
161 .write_options
162 .as_ref()
163 .expect("self.write_options should not be None"),
164 )
165 })
166 .unwrap_or_else(|| {
167 Err(format_err!(
168 "Couldn't find an available {} file.",
169 PACKAGE_JSON_FILENAME
170 ))
171 })
172 }
173
174 pub fn write_to(&mut self, file_path: &Path) -> Result<()> {
190 fs::write_json(
191 file_path,
192 &self.json,
193 self
194 .write_options
195 .as_ref()
196 .expect("self.write_options should not be None"),
197 )
198 }
199}
200
201impl AsRef<PackageJson> for PackageJsonManager {
202 fn as_ref(&self) -> &PackageJson {
204 &self.json
205 }
206}
207
208impl AsMut<PackageJson> for PackageJsonManager {
209 fn as_mut(&mut self) -> &mut PackageJson {
211 &mut self.json
212 }
213}
214
215#[test]
216fn test_new() {
217 use std::path::PathBuf;
218
219 let mut manager = PackageJsonManager::new();
220 assert_eq!(manager.file_path, None);
221
222 let file_path = PathBuf::from("/path/to/package.json");
223 manager.set_file_path(&file_path);
224 assert_eq!(manager.file_path, Some(file_path.to_owned()));
225 assert_eq!(manager.get_file_path(), Some(file_path.as_ref()));
226 assert_eq!(manager.take_file_path(), Some(file_path.to_owned()));
227 assert_eq!(manager.file_path, None);
228}
229
230#[test]
231fn test_readable() {
232 use crate::PACKAGE_JSON_FILENAME;
233 use std::env::current_dir;
234 use std::fs::{create_dir_all, File};
235 use std::io::Write;
236 use tempfile::tempdir_in;
237
238 let mut manager = PackageJsonManager::new();
239 assert!(manager.read_ref().is_err(), "found an available file.");
240 assert!(
241 manager.get_file_path().is_none(),
242 "found an available file."
243 );
244 assert!(
245 manager.locate_closest().is_err(),
246 "found an available file."
247 );
248
249 let dir = tempdir_in(current_dir().unwrap()).expect("create temp_dir failed!");
250 let file_path = dir.path().join(format!("a/b/c/{}", PACKAGE_JSON_FILENAME));
251 let file_dir = file_path.parent().unwrap();
252 let deeper_file_dir = file_dir.join("d/e/f");
253 create_dir_all(file_dir).expect("create a/b/c dir failed!");
254 create_dir_all(deeper_file_dir.as_path()).expect("create d/e/f dir field!");
255
256 let mut valid_file = File::create(&file_path).expect("create file failed!");
257 let valid_json = r#"{
258"name": "test",
259"version": "0.0.1"
260}"#;
261
262 valid_file
263 .write_all(valid_json.as_bytes())
264 .expect("write json failed");
265
266 for (dir, expect) in [
267 (dir.path(), None),
268 (file_dir, Some(file_path.to_owned())),
269 (deeper_file_dir.as_path(), Some(file_path.to_owned())),
270 ] {
271 assert_eq!(manager.locate_closest_from(dir).ok(), expect);
272 if expect.is_some() {
273 assert!(manager.read_ref().is_ok(), "read file failed.");
274 assert_eq!(manager.get_file_path().map(|p| p.to_path_buf()), expect);
275
276 if let Ok(json) = manager.read_ref() {
277 assert_eq!(json.name, "test");
278 assert_eq!(json.version, "0.0.1");
279 }
280
281 let handler = manager.as_ref();
282 assert_eq!(handler.name, "test");
283 assert_eq!(handler.version, "0.0.1");
284 assert!(!handler.private);
285 } else {
286 assert!(manager.read_ref().is_err(), "read field successful.")
287 }
288 }
289}
290
291#[test]
292fn test_writable() {
293 use crate::PACKAGE_JSON_FILENAME;
294 use std::env::current_dir;
295 use std::fs::{create_dir_all, File};
296 use std::io::Write;
297 use tempfile::tempdir_in;
298
299 let mut manager = PackageJsonManager::new();
300 assert!(manager.write().is_err(), "found an available file.");
301
302 let dir = tempdir_in(current_dir().unwrap()).expect("create temp_dir failed!");
303 let file_path = dir.path().join(format!("a/b/c/{}", PACKAGE_JSON_FILENAME));
304 let file_dir = file_path.parent().unwrap();
305 create_dir_all(file_dir).expect("create a/b/c dir failed!");
306
307 let mut valid_file = File::create(&file_path).expect("create file failed!");
308 let valid_json = r#"{
309"name": "test",
310"version": "0.0.1"
311}"#;
312
313 valid_file
314 .write_all(valid_json.as_bytes())
315 .expect("write json failed");
316
317 manager.set_file_path(&file_path);
318
319 {
321 let file_writer = manager.read_mut();
322 assert!(
323 file_writer.is_ok(),
324 "{}",
325 format!("create file writer failed: {:?}", file_writer)
326 );
327 if let Ok(json) = file_writer {
328 json.name = "test2".to_string();
329 json.version = "0.0.2".to_string();
330 assert!(manager.write().is_ok());
331 }
332 let file_reader = manager.as_ref();
333 assert_eq!(file_reader.name, "test2");
334 assert_eq!(file_reader.version, "0.0.2");
335 }
336
337 {
339 let mutable_handler = manager.as_mut();
340 mutable_handler.name = "test3".to_string();
341 mutable_handler.version = "0.0.3".to_string();
342 let file_reader = manager.as_ref();
343 assert_eq!(file_reader.name, "test3");
344 assert_eq!(file_reader.version, "0.0.3");
345 }
346}