1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use anyhow::Result;
use console::style;
use glob::glob;
use rayon::prelude::*;
use std::{
fs::File,
path::Path,
sync::{Arc, Mutex},
};
use crate::common::*;
use crate::utils::*;
use crate::validate::*;
pub struct ValidateArgs {
pub assets_dir: String,
pub strict: bool,
}
pub fn process_validate(args: ValidateArgs) -> Result<()> {
println!(
"{} {}Loading assets",
style("[1/1]").bold().dim(),
ASSETS_EMOJI
);
let assets_dir = Path::new(&args.assets_dir);
if !assets_dir.exists() || assets_dir.read_dir()?.next().is_none() {
info!("Assets directory is missing or empty.");
return Err(ValidateError::MissingOrEmptyAssetsDirectory.into());
}
let path = assets_dir.join("*.json");
let pattern = path.to_str().ok_or(ValidateError::InvalidAssetsDirectory)?;
let (paths, errors): (Vec<_>, Vec<_>) = glob(pattern)?.into_iter().partition(Result::is_ok);
let pb = spinner_with_style();
pb.enable_steady_tick(120);
pb.set_message(format!("Validating {} metadata file(s)...", paths.len()));
let paths: Vec<_> = paths.into_iter().map(Result::unwrap).collect();
let path_errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
let file_open_errors = Arc::new(Mutex::new(Vec::new()));
let deserialize_errors = Arc::new(Mutex::new(Vec::new()));
let validate_errors = Arc::new(Mutex::new(Vec::new()));
paths.par_iter().for_each(|path| {
let file_open_errors = file_open_errors.clone();
let f = match File::open(path) {
Ok(f) => f,
Err(error) => {
error!("{}: {}", path.display(), error);
file_open_errors
.lock()
.unwrap()
.push(FileOpenError { path, error });
return;
}
};
let metadata = match serde_json::from_reader::<File, Metadata>(f) {
Ok(metadata) => metadata,
Err(error) => {
error!("{}: {}", path.display(), error);
deserialize_errors
.lock()
.unwrap()
.push(DeserializeError { path, error });
return;
}
};
if args.strict {
match metadata.validate_strict() {
Ok(()) => {}
Err(e) => {
error!("{}: {}", path.display(), e);
validate_errors.lock().unwrap().push(e);
}
}
} else {
match metadata.validate() {
Ok(()) => {}
Err(e) => {
error!("{}: {}", path.display(), e);
validate_errors.lock().unwrap().push(e);
}
}
}
});
pb.finish();
if !path_errors.is_empty() {
error!("Path errors: {:?}", path_errors);
return Err(ReadFilesError::PathErrors.into());
}
if !file_open_errors.lock().unwrap().is_empty() {
error!("File open errors: {:?}", file_open_errors);
return Err(ReadFilesError::FileOpenErrors.into());
}
if !deserialize_errors.lock().unwrap().is_empty() {
error!("Deserialize errors: {:?}", deserialize_errors);
return Err(ReadFilesError::DeserializeErrors.into());
}
if !validate_errors.lock().unwrap().is_empty() {
error!("Validate errors: {:?}", validate_errors);
return Err(ReadFilesError::ValidateErrors.into());
}
let message = "Validation complete, your metadata file(s) look good.";
info!("{message}");
println!("\n{message}");
Ok(())
}