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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Build script for compile-time validation
//!
//! Part of the Andon Signal Validation Framework - Layer 1: Compile-Time Validation
//!
//! This build script validates CLI commands and test configurations at compile time.
//!
//! ## Poka-Yoke: Verb Module Registration Validation
//!
//! Prevents the silent linkme registration failure by verifying at compile time
//! that all verb modules in `crates/ggen-cli/src/cmds/` are properly imported
//! in `mod.rs` with the force-link pattern (`use module as _;`).
//!
//! This catches the bug where a new command module is added but forgotten to be
//! force-linked, causing linkme's distributed slice to silently exclude it.
fn main() {
// Poka-Yoke: Validate verb module registration
validate_verb_module_registration();
// Validate clnrm test configurations
validate_clnrm_configs();
// Rerun if cmds directory changes
println!("cargo:rerun-if-changed=crates/ggen-cli/src/cmds/");
}
/// Poka-Yoke: Validate all verb modules are properly registered in mod.rs
///
/// This prevents the silent linkme failure where #[verb] macros are defined
/// but the module is optimized away by the linker because it's not referenced.
///
/// ## What This Checks
///
/// 1. Scans `crates/ggen-cli/src/cmds/*.rs` for files containing `#[verb(`
/// 2. Verifies each such file is imported in `mod.rs` with `use MODULE as _;`
/// 3. Emits cargo:warning if any verb module is missing the force-link pattern
///
/// ## Why This Matters
///
/// Without `use module as _;`, Rust's dead code elimination removes the linkme
/// static items generated by #[verb], causing commands to silently disappear.
fn validate_verb_module_registration() {
use std::fs;
use std::path::Path;
let cmds_dir = Path::new("crates/ggen-cli/src/cmds");
if !cmds_dir.exists() {
// Not in workspace root or cmds dir doesn't exist
return;
}
let mod_rs_path = cmds_dir.join("mod.rs");
let mod_rs_content = match fs::read_to_string(&mod_rs_path) {
Ok(content) => content,
Err(_) => return, // Can't read mod.rs, skip validation
};
// Find all .rs files in cmds/ that contain #[verb(
let mut verb_modules: Vec<String> = Vec::new();
let mut missing_registrations: Vec<String> = Vec::new();
if let Ok(entries) = fs::read_dir(cmds_dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().is_some_and(|e| e == "rs") {
let file_name = path.file_stem().unwrap().to_string_lossy().to_string();
// Skip mod.rs and helpers.rs (not verb modules)
if file_name == "mod" || file_name == "helpers" {
continue;
}
// Check if this file contains a #[verb( attribute
if let Ok(content) = fs::read_to_string(&path) {
if content.contains("#[verb(") {
verb_modules.push(file_name.clone());
// Check if mod.rs has the force-link pattern for this module
// Pattern: `use MODULE as _;` or `use MODULE as _`
let force_link_pattern = format!("use {} as _", file_name);
if !mod_rs_content.contains(&force_link_pattern) {
missing_registrations.push(file_name);
}
}
}
}
}
}
// Emit warnings for missing registrations (Andon YELLOW signal)
for module in &missing_registrations {
println!(
"cargo:warning=POKA-YOKE: Verb module '{}' contains #[verb] but is NOT force-linked in cmds/mod.rs!",
module
);
println!(
"cargo:warning=POKA-YOKE: Add `#[allow(unused_imports)] use {} as _;` to cmds/mod.rs",
module
);
println!(
"cargo:warning=POKA-YOKE: Without this, the command will be silently removed by the linker!"
);
}
// If any missing registrations, emit a summary warning
if !missing_registrations.is_empty() {
println!(
"cargo:warning=POKA-YOKE SUMMARY: {} verb module(s) missing force-link pattern: {:?}",
missing_registrations.len(),
missing_registrations
);
println!("cargo:warning=POKA-YOKE: This will cause commands to silently fail at runtime!");
}
// Emit positive confirmation if all modules are properly registered
if !verb_modules.is_empty() && missing_registrations.is_empty() {
// Use note for success (less visible than warning)
eprintln!(
"note: POKA-YOKE: All {} verb module(s) properly force-linked: {:?}",
verb_modules.len(),
verb_modules
);
}
}
/// Validate all clnrm test configuration files
fn validate_clnrm_configs() {
use std::fs;
use std::path::Path;
let test_dir = Path::new("tests/clnrm");
if !test_dir.exists() {
// Test directory doesn't exist - this is OK for some build contexts
return;
}
// Check for main CLI commands test file
let cli_commands = test_dir.join("cli_commands.clnrm.toml");
if cli_commands.exists() {
// Basic validation - file exists and is readable
if let Err(e) = fs::metadata(&cli_commands) {
println!("cargo:warning=clnrm test file validation failed: {}", e);
}
}
}