wowlab_engine/cli/audit/
mod.rs1mod output;
2
3use wowlab_common::output as out;
4use wowlab_engine_application::{SpecAudit, audit_manifest_repository};
5use wowlab_engine_ports::DynDataResolver;
6use wowlab_fs::{
7 directory::{self, EntryKind},
8 path::{Path, PathBuf},
9};
10use wowlab_manifest_schema::ManifestRepository;
11
12use super::CliError;
13
14pub(crate) async fn run(manifests: Option<PathBuf>, workspace_root: &Path) -> Result<(), CliError> {
15 let manifests_dir = match manifests {
16 Some(path) => path,
17 None => find_manifests_dir(workspace_root)?.ok_or_else(|| {
18 CliError::audit(
19 "could not auto-detect manifests directory. Set ENGINE_ROOT or pass --manifests <path>"
20 .to_string(),
21 )
22 })?,
23 };
24
25 let handle = super::resolver::create(workspace_root)?;
26
27 run_audit(&manifests_dir, &handle.resolver).await
28}
29
30async fn run_audit(manifests_dir: &Path, resolver: &DynDataResolver<'_>) -> Result<(), CliError> {
31 let repository = ManifestRepository::new(manifests_dir);
32 let spec_count = repository.spec_paths()?.len();
33
34 out::banner("Manifest Audit", &format!("{spec_count} specs"));
35 out::blank();
36
37 let audits = audit_manifest_repository(&repository, resolver).await?;
38
39 let (total_errors, total_warnings, specs_with_errors) = print_audits(&audits);
40
41 output::print_summary(
42 total_errors,
43 total_warnings,
44 specs_with_errors,
45 audits.len(),
46 );
47
48 if total_errors > 0 {
49 Err(CliError::audit(format!(
50 "{total_errors} audit errors found"
51 )))
52 } else {
53 Ok(())
54 }
55}
56
57fn print_audits(audits: &[SpecAudit]) -> (usize, usize, usize) {
58 let mut total_errors = 0;
59 let mut total_warnings = 0;
60 let mut specs_with_errors = 0;
61
62 for audit in audits {
63 specs_with_errors += usize::from(!audit.errors.is_empty());
64 total_errors += audit.errors.len();
65 total_warnings += audit.warnings.len();
66 output::print_spec(audit);
67 }
68
69 (total_errors, total_warnings, specs_with_errors)
70}
71
72fn find_manifests_dir(workspace_root: &Path) -> Result<Option<PathBuf>, CliError> {
73 let path = workspace_root
74 .join("crates")
75 .join("engine")
76 .join("manifests");
77 let entry = directory::inspect(&path)?;
78
79 Ok(entry
80 .is_some_and(|entry| entry.kind() == EntryKind::Directory)
81 .then_some(path))
82}