@@ -12,15 +12,16 @@ use std::str;
12
12
use BuildContext ;
13
13
use PythonInterpreter ;
14
14
15
- #[ derive( Deserialize ) ]
15
+ #[ derive( Deserialize , Debug , Clone ) ]
16
16
struct BuildPlanEntry {
17
17
package_name : String ,
18
+ program : String ,
18
19
}
19
20
20
21
/// The (abbreviated) format of `cargo build --build-plan`
21
22
/// For the real thing, see
22
23
/// https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/build_plan.rs
23
- #[ derive( Deserialize ) ]
24
+ #[ derive( Deserialize , Debug , Clone ) ]
24
25
struct SerializedBuildPlan {
25
26
invocations : Vec < BuildPlanEntry > ,
26
27
}
@@ -40,7 +41,7 @@ struct SerializedBuildPlan {
40
41
/// reason: "build-script-executed",
41
42
/// }
42
43
/// ```
43
- #[ derive( Serialize , Deserialize ) ]
44
+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
44
45
struct CargoBuildOutput {
45
46
cfgs : Vec < String > ,
46
47
env : Vec < String > ,
@@ -52,25 +53,26 @@ struct CargoBuildOutput {
52
53
53
54
/// This kind of message is printed by `cargo build --message-format=json
54
55
/// --quiet` for an artifact such as an .so/.dll
55
- #[ derive( Serialize , Deserialize ) ]
56
+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
56
57
struct CompilerArtifactMessage {
57
58
filenames : Vec < PathBuf > ,
58
59
target : CompilerTargetMessage ,
60
+ package_id : String ,
59
61
}
60
62
61
- #[ derive( Serialize , Deserialize ) ]
63
+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
62
64
struct CompilerTargetMessage {
63
65
crate_types : Vec < String > ,
64
66
name : String ,
65
67
}
66
68
67
- #[ derive( Serialize , Deserialize ) ]
69
+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
68
70
struct CompilerErrorMessage {
69
71
message : CompilerErrorMessageMessage ,
70
72
reason : String ,
71
73
}
72
74
73
- #[ derive( Serialize , Deserialize ) ]
75
+ #[ derive( Serialize , Deserialize , Debug , Clone ) ]
74
76
struct CompilerErrorMessageMessage {
75
77
rendered : String ,
76
78
}
@@ -86,7 +88,7 @@ fn get_build_plan(shared_args: &[&str]) -> Result<SerializedBuildPlan, Error> {
86
88
"--build-plan" ,
87
89
] ;
88
90
89
- let command_formated = [ "cargo" ]
91
+ let command_formatted = [ "cargo" ]
90
92
. iter ( )
91
93
. chain ( build_plan_args)
92
94
. chain ( shared_args)
@@ -104,15 +106,15 @@ fn get_build_plan(shared_args: &[&str]) -> Result<SerializedBuildPlan, Error> {
104
106
format_err ! (
105
107
"Failed to get a build plan from cargo: {} ({})" ,
106
108
e,
107
- command_formated
109
+ command_formatted
108
110
)
109
111
} ) ?;
110
112
111
113
if !build_plan. status . success ( ) {
112
114
bail ! (
113
115
"Failed to get a build plan from cargo with '{}': `{}`" ,
114
116
build_plan. status,
115
- command_formated
117
+ command_formatted
116
118
) ;
117
119
}
118
120
@@ -121,6 +123,39 @@ fn get_build_plan(shared_args: &[&str]) -> Result<SerializedBuildPlan, Error> {
121
123
Ok ( plan)
122
124
}
123
125
126
+ fn get_progress_plan ( shared_args : & [ & str ] ) -> Option < ( ProgressBar , Vec < String > ) > {
127
+ if atty:: is ( Stream :: Stderr ) {
128
+ match get_build_plan ( shared_args) {
129
+ Ok ( build_plan) => {
130
+ let mut packages: Vec < String > = build_plan
131
+ . invocations
132
+ . iter ( )
133
+ . filter ( |x| x. program == "rustc" ) // Only those gives artifact messages
134
+ . map ( |x| x. package_name . clone ( ) )
135
+ . collect ( ) ;
136
+
137
+ let progress_bar = ProgressBar :: new ( packages. len ( ) as u64 ) ;
138
+ progress_bar. set_style (
139
+ ProgressStyle :: default_bar ( )
140
+ . template ( "[{bar:60}] {pos:>3}/{len:3} {msg}" )
141
+ . progress_chars ( "=> " ) ,
142
+ ) ;
143
+
144
+ if let Some ( first) = packages. first ( ) {
145
+ progress_bar. set_message ( first) ;
146
+ } else {
147
+ eprintln ! ( "Warning: The build plan is empty" ) ;
148
+ }
149
+
150
+ Some ( ( progress_bar, packages) )
151
+ }
152
+ Err ( _) => None ,
153
+ }
154
+ } else {
155
+ None
156
+ }
157
+ }
158
+
124
159
/// Builds the rust crate into a native module (i.e. an .so or .dll) for a
125
160
/// specific python version
126
161
///
@@ -163,28 +198,12 @@ pub fn compile(
163
198
let mut cargo_args = vec ! [ "rustc" , "--message-format" , "json" ] ;
164
199
165
200
// Mimicks cargo's -Z compile-progress, just without the long result log
166
- let progress_plan = if atty:: is ( Stream :: Stderr ) {
167
- match get_build_plan ( & shared_args) {
168
- Ok ( build_plan) => {
169
- let progress_bar = ProgressBar :: new ( build_plan. invocations . len ( ) as u64 ) ;
170
- progress_bar. set_style (
171
- ProgressStyle :: default_bar ( )
172
- . template ( "[{bar:60}] {pos:>3}/{len:3} {msg}" )
173
- . progress_chars ( "=> " ) ,
174
- ) ;
175
-
176
- progress_bar. set_message ( & build_plan. invocations [ 0 ] . package_name ) ;
201
+ let mut progress_plan = get_progress_plan ( & shared_args) ;
177
202
178
- // We have out own progess bar, so we don't need cargo's bar
179
- cargo_args. push ( "--quiet" ) ;
180
-
181
- Some ( ( progress_bar, build_plan) )
182
- }
183
- Err ( _) => None ,
184
- }
185
- } else {
186
- None
187
- } ;
203
+ if progress_plan. is_some ( ) {
204
+ // We have out own progess bar, so we don't need cargo's bar
205
+ cargo_args. push ( "--quiet" ) ;
206
+ }
188
207
189
208
let mut rustc_args: Vec < & str > = context
190
209
. rustc_extra_args
@@ -222,24 +241,30 @@ pub fn compile(
222
241
let mut cargo_build = build_command. spawn ( ) . context ( "Failed to run cargo" ) ?;
223
242
224
243
let mut artifact_messages = Vec :: new ( ) ;
225
- let mut build_plan_pos = 0 ;
226
244
let reader = BufReader :: new ( cargo_build. stdout . take ( ) . unwrap ( ) ) ;
227
245
for line in reader. lines ( ) . map ( |line| line. unwrap ( ) ) {
228
246
if let Ok ( message) = serde_json:: from_str :: < CompilerArtifactMessage > ( & line) {
229
247
// Extract the location of the .so/.dll/etc. from cargo's json output
230
- if message. target . name == context. module_name
231
- || message. target . name == context. metadata21 . name
232
- {
233
- artifact_messages. push ( message) ;
248
+ let target_name = message. target . name . clone ( ) ;
249
+ if target_name == context. module_name || target_name == context. metadata21 . name {
250
+ artifact_messages. push ( message. clone ( ) ) ;
234
251
}
235
252
253
+ let crate_name = message. package_id . split ( " " ) . nth ( 0 ) . unwrap ( ) . to_string ( ) ;
254
+
236
255
// The progress bar isn't an exact science and stuff might get out-of-sync,
237
256
// but that isn't big problem since the bar is only to give the user an estimate
238
- if let Some ( ( ref progress_bar, ref build_plan) ) = progress_plan {
239
- progress_bar. inc ( 1 ) ;
240
- build_plan_pos += 1 ;
241
- if let Some ( package) = build_plan. invocations . get ( build_plan_pos) {
242
- progress_bar. set_message ( & package. package_name ) ;
257
+ if let Some ( ( ref progress_bar, ref mut packages) ) = progress_plan {
258
+ match packages. iter ( ) . position ( |x| x == & crate_name) {
259
+ Some ( pos) => {
260
+ packages. remove ( pos) ;
261
+ progress_bar. inc ( 1 ) ;
262
+ }
263
+ None => eprintln ! ( "WARN: {} not found in build plan" , crate_name) ,
264
+ }
265
+
266
+ if let Some ( package) = packages. first ( ) {
267
+ progress_bar. set_message ( & package) ;
243
268
}
244
269
}
245
270
}
0 commit comments