1
1
import json
2
+ import sys
3
+ import os
2
4
import subprocess
3
5
4
6
def print_code_snippet (file_path , line_num , context = 3 ):
@@ -31,52 +33,51 @@ def print_code_snippet(file_path, line_num, context=3):
31
33
print (f"Could not read file { file_path } : { e } " )
32
34
33
35
34
- def parse_rustc_json (stderr : str , file_path ):
35
- """
36
- Parses rustc's JSON output and prints only the first error with a single snippet.
37
-
38
- Args:
39
- stderr (str): JSON-formatted stderr output from rustc.
40
- file_path: Path to the Rust file.
36
+ import json
41
37
42
- Returns:
43
- None
38
+ def parse_cargo_errors (output : str , output_rust ):
39
+ """
40
+ Parses Cargo’s JSON output and prints only the first compiler error it finds.
41
+ Ignores warnings and notes entirely.
44
42
"""
45
- for line in stderr .splitlines ():
43
+ for line in output .splitlines ():
46
44
line = line .strip ()
47
45
if not line :
48
46
continue
49
47
50
48
try :
51
- diagnostic = json .loads (line )
49
+ rec = json .loads (line )
52
50
except json .JSONDecodeError :
53
51
continue
54
52
55
- if diagnostic .get ("$message_type" ) != "diagnostic" :
53
+ # Only look at compiler messages
54
+ if rec .get ("reason" ) != "compiler-message" :
56
55
continue
57
56
58
- if diagnostic .get ("level" ) != "error" :
57
+ msg = rec ["message" ]
58
+ # Skip anything that isn't an error
59
+ if msg .get ("level" ) != "error" :
59
60
continue
60
61
61
- message = diagnostic .get ("message" , "" )
62
- spans = diagnostic .get ("spans" , [])
62
+ text = msg .get ("message" , "" )
63
+ spans = msg .get ("spans" , [])
63
64
64
- # Prefer the primary span in the current file
65
+ # Print the high-level error first
66
+ print (f"\n error: { text } " )
67
+
68
+ # Then try to show its primary location
65
69
for span in spans :
66
- if span .get ("is_primary" ) and span ["file_name" ] == file_path :
67
- line_num = span ["line_start" ]
70
+ if span .get ("is_primary" ):
71
+ file = span .get ("file_name" )
72
+ line_start = span .get ("line_start" )
68
73
label = span .get ("label" , "" )
69
- print (f"error: line { line_num } : { message } " )
70
- if label :
71
- print (f"--> { label } " )
72
- print ("=" * 25 )
73
- snippet = print_code_snippet (file_path , line_num , context = 8 )
74
- print (snippet )
75
- print ("=" * 25 )
76
- return # we return because we only print the first error--in json format there can be multiple error messages(primary and non primary) for 1 error-- if you want to see them comment this line.
77
-
78
- # fallback: print the error message if no span in the current file
79
- print (f"error: { message } " )
74
+ print (f" --> { file } :{ line_start } { label } " .rstrip (), file = sys .stderr )
75
+ # and a snippet
76
+ snippet = print_code_snippet (output_rust + file , line_start , context = 5 )
77
+ print ("\n " + snippet , file = sys .stderr )
78
+ break
79
+
80
+ # Stop after the first error
80
81
return
81
82
82
83
def check_rust_test_errors (app , exception ):
@@ -86,31 +87,31 @@ def check_rust_test_errors(app, exception):
86
87
This function is connected to the Sphinx build lifecycle and is executed after the build finishes.
87
88
It invokes `rustc` in test mode on the generated Rust file and reports any compilation or test-related
88
89
errors.
89
-
90
- Args:
91
- app: The Sphinx application object. Must have an `output_rust_file` attribute containing
92
- the path to the generated Rust source file.
93
- exception: Exception raised during the build process, or None if the build completed successfully.
94
90
"""
95
- rs_path = app .output_rust_file
91
+ rs_path = app .output_rust
92
+ cargo_toml_path = os .path .join (rs_path , "Cargo.toml" )
96
93
# Run the Rust compiler in test mode with JSON error output format.
97
94
# capturing stdout and stderr as text.
98
95
result = subprocess .run (
99
- ["rustc" , "--test" , "--edition=2024" , "--error-format=json" , "--emit=metadata" , rs_path ],
100
- # --emit=metadata or else rustc will produce a binary ./generated
96
+ [
97
+ "cargo" ,
98
+ "test" ,
99
+ "--message-format=json" ,
100
+ "--manifest-path" ,
101
+ cargo_toml_path
102
+ ],
101
103
capture_output = True ,
102
- text = True
104
+ text = True ,
103
105
)
104
106
105
107
if result .returncode != 0 :
106
- print ("--- rustc Errors/Warnings ---" )
107
- parse_rustc_json (result .stderr , app .output_rust_file )
108
+ print ("\033 [31m --- Cargo test errors ---\033 [0m " )
109
+ parse_cargo_errors (result .stdout , app .output_rust ) # parse stdout JSON lines
108
110
# print("--- rustc Output ---")
109
111
# print(result.stdout)
110
-
111
112
else :
112
- print ("--- rustc Output ---" )
113
- print (result .stdout )
114
- if result .stderr :
115
- print ("\n \n --- rustc Warnings---" )
116
- print (result .stderr )
113
+ print ("\033 [1;32mAll tests succeeded \033 [0m" ) # ANSI magic
114
+ # print(result.stdout)
115
+ # if result.stderr:
116
+ # print("\n\n--- rustc Warnings ---")
117
+ # print(result.stderr)
0 commit comments