@@ -2,13 +2,15 @@ use std::env;
22use std:: fs;
33use std:: path:: { Path , PathBuf } ;
44use std:: process:: ExitCode ;
5+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
56
67use rsscript:: {
7- analyze_source, explain_diagnostic_code, format_diagnostic_explanation,
8- format_diagnostics_human, format_diagnostics_json, format_review_human, format_review_json,
9- format_review_map_human, format_review_map_json, lower_source_to_rust,
10- lower_source_to_rust_package, parse_source_map_json, remap_rustc_diagnostic_json_lines,
11- review_map_sources, review_sources,
8+ Diagnostic , analyze_source, check_generated_rust_package, explain_diagnostic_code,
9+ format_diagnostic_explanation, format_diagnostics_human, format_diagnostics_json,
10+ format_review_human, format_review_json, format_review_map_human, format_review_map_json,
11+ lower_source_to_rust, lower_source_to_rust_package, parse_source_map_json,
12+ remap_rustc_diagnostic_json_lines, review_map_sources, review_sources,
13+ write_generated_rust_package,
1214} ;
1315
1416fn main ( ) -> ExitCode {
@@ -24,6 +26,7 @@ fn main() -> ExitCode {
2426 "review" => run_review ( & args[ 2 ..] ) ,
2527 "lower" => run_lower ( & args[ 2 ..] ) ,
2628 "remap-rustc" => run_remap_rustc ( & args[ 2 ..] ) ,
29+ "verify-rust" => run_verify_rust ( & args[ 2 ..] ) ,
2730 _ => {
2831 print_usage ( ) ;
2932 ExitCode :: from ( 2 )
@@ -175,33 +178,8 @@ fn run_lower_rust_package(path: &str, source: &str, out_dir: &str) -> ExitCode {
175178 } ;
176179
177180 let out_dir = Path :: new ( out_dir) ;
178- let src_dir = out_dir. join ( "src" ) ;
179- if let Err ( error) = fs:: create_dir_all ( & src_dir) {
180- eprintln ! ( "failed to create {}: {error}" , src_dir. display( ) ) ;
181- return ExitCode :: from ( 2 ) ;
182- }
183- if let Err ( error) = fs:: write ( out_dir. join ( "Cargo.toml" ) , package. cargo_toml ) {
184- eprintln ! (
185- "failed to write {}: {error}" ,
186- out_dir. join( "Cargo.toml" ) . display( )
187- ) ;
188- return ExitCode :: from ( 2 ) ;
189- }
190- if let Err ( error) = fs:: write ( src_dir. join ( "lib.rs" ) , package. lib_rs ) {
191- eprintln ! (
192- "failed to write {}: {error}" ,
193- src_dir. join( "lib.rs" ) . display( )
194- ) ;
195- return ExitCode :: from ( 2 ) ;
196- }
197- if let Err ( error) = fs:: write (
198- out_dir. join ( "rsscript-source-map.json" ) ,
199- package. source_map_json ,
200- ) {
201- eprintln ! (
202- "failed to write {}: {error}" ,
203- out_dir. join( "rsscript-source-map.json" ) . display( )
204- ) ;
181+ if let Err ( error) = write_generated_rust_package ( out_dir, & package) {
182+ eprintln ! ( "{error}" ) ;
205183 return ExitCode :: from ( 2 ) ;
206184 }
207185
@@ -213,6 +191,83 @@ fn run_lower_rust_package(path: &str, source: &str, out_dir: &str) -> ExitCode {
213191 ExitCode :: SUCCESS
214192}
215193
194+ fn run_verify_rust ( args : & [ String ] ) -> ExitCode {
195+ let ( json, path) = parse_path_args ( args) ;
196+ let Some ( path) = path else {
197+ print_usage ( ) ;
198+ return ExitCode :: from ( 2 ) ;
199+ } ;
200+ let source = match fs:: read_to_string ( path) {
201+ Ok ( source) => source,
202+ Err ( error) => {
203+ eprintln ! ( "failed to read {path}: {error}" ) ;
204+ return ExitCode :: from ( 2 ) ;
205+ }
206+ } ;
207+ let runtime_path = match default_runtime_path ( ) {
208+ Ok ( path) => path,
209+ Err ( error) => {
210+ eprintln ! ( "{error}" ) ;
211+ return ExitCode :: from ( 2 ) ;
212+ }
213+ } ;
214+ let package_name = generated_package_name ( path) ;
215+ let package = match lower_source_to_rust_package (
216+ path,
217+ & source,
218+ & package_name,
219+ & runtime_path. display ( ) . to_string ( ) ,
220+ ) {
221+ Ok ( package) => package,
222+ Err ( diagnostics) => {
223+ print_diagnostics ( json, & diagnostics) ;
224+ return ExitCode :: from ( 1 ) ;
225+ }
226+ } ;
227+ let temp_dir = verify_temp_dir ( & package. package_name ) ;
228+ if let Err ( error) = write_generated_rust_package ( & temp_dir, & package) {
229+ eprintln ! ( "{error}" ) ;
230+ cleanup_temp_dir ( & temp_dir) ;
231+ return ExitCode :: from ( 2 ) ;
232+ }
233+ let result = match check_generated_rust_package ( & temp_dir) {
234+ Ok ( result) => result,
235+ Err ( error) => {
236+ eprintln ! ( "{error}" ) ;
237+ cleanup_temp_dir ( & temp_dir) ;
238+ return ExitCode :: from ( 2 ) ;
239+ }
240+ } ;
241+ cleanup_temp_dir ( & temp_dir) ;
242+
243+ if result. diagnostics . is_empty ( ) {
244+ if result. success {
245+ if !json {
246+ println ! ( "{path}: rust backend ok" ) ;
247+ } else {
248+ println ! ( "[]" ) ;
249+ }
250+ return ExitCode :: SUCCESS ;
251+ }
252+ if !result. stderr . trim ( ) . is_empty ( ) {
253+ eprintln ! ( "{}" , result. stderr. trim( ) ) ;
254+ }
255+ eprintln ! ( "rust backend check failed without mappable diagnostics" ) ;
256+ return ExitCode :: from ( 1 ) ;
257+ }
258+
259+ print_diagnostics ( json, & result. diagnostics ) ;
260+ if result
261+ . diagnostics
262+ . iter ( )
263+ . any ( |diagnostic| diagnostic. severity . is_error ( ) )
264+ {
265+ ExitCode :: from ( 1 )
266+ } else {
267+ ExitCode :: SUCCESS
268+ }
269+ }
270+
216271fn run_remap_rustc ( args : & [ String ] ) -> ExitCode {
217272 let ( json, paths) = parse_multi_path_args ( args) ;
218273 let [ source_map_path, rustc_json_path] = paths. as_slice ( ) else {
@@ -270,6 +325,14 @@ fn run_remap_rustc(args: &[String]) -> ExitCode {
270325 }
271326}
272327
328+ fn print_diagnostics ( json : bool , diagnostics : & [ Diagnostic ] ) {
329+ if json {
330+ println ! ( "{}" , format_diagnostics_json( diagnostics) ) ;
331+ } else {
332+ print ! ( "{}" , format_diagnostics_human( diagnostics) ) ;
333+ }
334+ }
335+
273336fn parse_explain_args ( args : & [ String ] ) -> Option < & str > {
274337 let [ flag, code] = args else {
275338 return None ;
@@ -360,6 +423,21 @@ fn generated_package_name(path: &str) -> String {
360423 . to_string ( )
361424}
362425
426+ fn verify_temp_dir ( package_name : & str ) -> PathBuf {
427+ let now = SystemTime :: now ( )
428+ . duration_since ( UNIX_EPOCH )
429+ . map ( |duration| duration. as_nanos ( ) )
430+ . unwrap_or ( 0 ) ;
431+ env:: temp_dir ( ) . join ( format ! (
432+ "rsscript-verify-{package_name}-{}-{now}" ,
433+ std:: process:: id( )
434+ ) )
435+ }
436+
437+ fn cleanup_temp_dir ( path : & Path ) {
438+ let _ = fs:: remove_dir_all ( path) ;
439+ }
440+
363441enum ReviewCommand < ' a > {
364442 Diff {
365443 json : bool ,
@@ -528,6 +606,7 @@ fn print_usage() {
528606 eprintln ! ( " rsscript lower --rust <file.rss>" ) ;
529607 eprintln ! ( " rsscript lower --rust <file.rss> --out-dir <directory>" ) ;
530608 eprintln ! ( " rsscript remap-rustc [--json] <rsscript-source-map.json> <rustc-json-lines>" ) ;
609+ eprintln ! ( " rsscript verify-rust [--json] <file.rss>" ) ;
531610 eprintln ! ( " rsscript review [--json] --diff <old.rss> <new.rss>" ) ;
532611 eprintln ! ( " rsscript review [--json] --map <file-or-directory>" ) ;
533612}
0 commit comments