11
11
#![ cfg_attr( feature = "deny-warnings" , deny( warnings) ) ]
12
12
#![ warn( rust_2018_idioms, unused_lifetimes) ]
13
13
14
- use std:: env;
15
14
use std:: ffi:: OsStr ;
15
+ use std:: path:: PathBuf ;
16
16
use std:: process:: Command ;
17
+ use std:: { env, fs} ;
17
18
18
19
#[ cfg( not( windows) ) ]
19
20
const CARGO_CLIPPY : & str = "cargo-clippy" ;
@@ -23,6 +24,11 @@ const CARGO_CLIPPY: &str = "cargo-clippy.exe";
23
24
#[ cfg_attr( feature = "integration" , test) ]
24
25
fn integration_test ( ) {
25
26
let repo_name = env:: var ( "INTEGRATION" ) . expect ( "`INTEGRATION` var not set" ) ;
27
+
28
+ if repo_name == "rust-lang/rust" {
29
+ return ;
30
+ }
31
+
26
32
let repo_url = format ! ( "https://github.com/{repo_name}" ) ;
27
33
let crate_name = repo_name
28
34
. split ( '/' )
@@ -123,3 +129,166 @@ fn integration_test() {
123
129
None => panic ! ( "Process terminated by signal" ) ,
124
130
}
125
131
}
132
+
133
+ #[ allow( clippy:: too_many_lines) ]
134
+ #[ cfg_attr( feature = "integration" , test) ]
135
+ fn integration_test_rustc ( ) {
136
+ let repo_name = env:: var ( "INTEGRATION" ) . expect ( "`INTEGRATION` var not set" ) ;
137
+
138
+ // try to avoid running this test locally
139
+ if !( repo_name == "rust-lang/rust" && env:: var ( "GITHUB_ACTIONS" ) == Ok ( String :: from ( "true" ) ) ) {
140
+ return ;
141
+ }
142
+
143
+ println ! ( "getting rustc version" ) ;
144
+ // clippy is pinned to a specific nightly version
145
+ // check out the commit of that nightly to ensure compatibility
146
+ let rustc_output = Command :: new ( "rustc" )
147
+ . arg ( "--version" )
148
+ . arg ( "--verbose" )
149
+ . output ( )
150
+ . expect ( "failed to run rustc --version" ) ;
151
+
152
+ let rustc_output_string = String :: from_utf8_lossy ( & rustc_output. stdout ) ;
153
+ let commit_line = rustc_output_string
154
+ . lines ( )
155
+ . find ( |line| line. starts_with ( "commit-hash: " ) )
156
+ . expect ( "did not find 'commit-hash: ' in --version output" ) ;
157
+
158
+ let commit = commit_line
159
+ . strip_prefix ( "commit-hash: " )
160
+ . expect ( "failed parsing commit line" ) ;
161
+
162
+ let repo_url = format ! ( "https://github.com/{repo_name}" ) ;
163
+ let crate_name = repo_name
164
+ . split ( '/' )
165
+ . nth ( 1 )
166
+ . expect ( "repo name should have format `<org>/<name>`" ) ;
167
+
168
+ let mut repo_dir = tempfile:: tempdir ( ) . expect ( "couldn't create temp dir" ) . into_path ( ) ;
169
+ repo_dir. push ( crate_name) ;
170
+
171
+ println ! ( "cloning git repo" ) ;
172
+ let st_git_cl = Command :: new ( "git" )
173
+ . args ( [
174
+ OsStr :: new ( "clone" ) ,
175
+ // we can't use depth=x because we don't know how far away the master branc tip is from our nightly commit
176
+ // that we need.
177
+ // however, we can still gain a lot by using --filter=tree:0 which is still ~10x faster than a full clone
178
+
179
+ // https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
180
+ OsStr :: new ( "--filter=tree:0" ) ,
181
+ OsStr :: new ( & repo_url) ,
182
+ OsStr :: new ( & repo_dir) ,
183
+ ] )
184
+ . status ( )
185
+ . expect ( "unable to run git clone" ) ;
186
+ assert ! ( st_git_cl. success( ) ) ;
187
+
188
+ // check out the commit in the rustc repo to ensure clippy is compatible with std/core and the
189
+ // compiler internals
190
+
191
+ println ! ( "checking out commit '{commit}' in rustc repo" ) ;
192
+ let st_git_checkout = Command :: new ( "git" )
193
+ . current_dir ( & repo_dir)
194
+ . arg ( "checkout" )
195
+ . arg ( commit)
196
+ . status ( )
197
+ . expect ( "git failed to check out commit '{commit}' in rustc repo" ) ;
198
+ assert ! ( st_git_checkout. success( ) ) ;
199
+
200
+ let root_dir = std:: path:: PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) ;
201
+ let target_dir = std:: path:: Path :: new ( & root_dir) . join ( "target" ) ;
202
+ // the clippy binary is in there
203
+ let clippy_exec_dir = target_dir. join ( env ! ( "PROFILE" ) ) ;
204
+
205
+ // we want that `x.py clippy` picks up our self-built clippy for testing!
206
+ // copy the clippy we built earlier into the toolchain directory of the nightly
207
+ // that clippy is pinned, so that x.py can pick it up and use it
208
+
209
+ // copy our own clippy binary into the rustc toolchain dir so that x.py finds them:
210
+ // get the sysroot path from nightly and put our binaries into ${sysroot}/bin/
211
+ let sysroot_output = Command :: new ( "rustc" )
212
+ . arg ( "--print" )
213
+ . arg ( "sysroot" )
214
+ . output ( )
215
+ . expect ( "rustc failed to print sysroot" ) ;
216
+ // trim away the "\n" at the end because we don't want this in our Path :D
217
+ let untrimmed = String :: from_utf8_lossy ( & sysroot_output. stdout ) . to_string ( ) ;
218
+ let sysroot_trimmed = untrimmed. trim ( ) ;
219
+ let mut sysroot = sysroot_trimmed. to_string ( ) ;
220
+ sysroot. push ( '/' ) ;
221
+ let sysroot_path = PathBuf :: from ( sysroot) ;
222
+
223
+ assert ! (
224
+ sysroot_path. exists( ) ,
225
+ "{}" ,
226
+ format!( "sysroot path '{}' not found!" , sysroot_path. display( ) )
227
+ ) ;
228
+
229
+ let sysroot_bin_dir = sysroot_path. join ( "bin" ) ;
230
+ eprintln ! ( "clippy binaries will be put int {}" , sysroot_bin_dir. display( ) ) ;
231
+
232
+ // copy files from target dir into our $sysroot/bin
233
+ std:: fs:: read_dir ( clippy_exec_dir)
234
+ . expect ( "failed to read clippys target/ dir that we downloaded from previous ci step" )
235
+ . map ( |entry| entry. expect ( "DirEntry not ok" ) )
236
+ . map ( |entry| entry. path ( ) )
237
+ . filter ( |path| path. is_file ( ) )
238
+ . for_each ( |clippy_binary| {
239
+ let new_base: PathBuf = sysroot_bin_dir. join ( "willbeoverwritten" ) ; // file_name() will overwrite this
240
+ // set the path from /foo/dir/willbeoverwritten to /foo/dir/cargo-clippy
241
+ let bin_file_name: & std:: ffi:: OsStr = clippy_binary. file_name ( ) . unwrap ( ) ;
242
+ let new_path: PathBuf = new_base. with_file_name ( bin_file_name) ;
243
+
244
+ fs:: copy ( dbg ! ( clippy_binary) , dbg ! ( new_path) )
245
+ . expect ( "could not copy file from '{clippy_binary}' to '{new_path}'" ) ;
246
+ } ) ;
247
+
248
+ // some notes: x.py will set --cap-lints warn by default
249
+ let output = Command :: new ( "python" )
250
+ . arg ( "./x.py" )
251
+ . current_dir ( & repo_dir)
252
+ . env ( "RUST_BACKTRACE" , "full" )
253
+ . args ( [ "clippy" , "-Wclippy::pedantic" , "-Wclippy::cargo" ] )
254
+ . output ( )
255
+ . expect ( "unable to run x.py clippy" ) ;
256
+
257
+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
258
+
259
+ eprintln ! ( "{stderr}" ) ;
260
+
261
+ if let Some ( backtrace_start) = stderr. find ( "error: internal compiler error" ) {
262
+ static BACKTRACE_END_MSG : & str = "end of query stack" ;
263
+ let backtrace_end = stderr[ backtrace_start..]
264
+ . find ( BACKTRACE_END_MSG )
265
+ . expect ( "end of backtrace not found" ) ;
266
+
267
+ panic ! (
268
+ "internal compiler error\n Backtrace:\n \n {}" ,
269
+ & stderr[ backtrace_start..backtrace_start + backtrace_end + BACKTRACE_END_MSG . len( ) ]
270
+ ) ;
271
+ } else if stderr. contains ( "query stack during panic" ) {
272
+ panic ! ( "query stack during panic in the output" ) ;
273
+ } else if stderr. contains ( "E0463" ) {
274
+ // Encountering E0463 (can't find crate for `x`) did _not_ cause the build to fail in the
275
+ // past. Even though it should have. That's why we explicitly panic here.
276
+ // See PR #3552 and issue #3523 for more background.
277
+ panic ! ( "error: E0463" ) ;
278
+ } else if stderr. contains ( "E0514" ) {
279
+ panic ! ( "incompatible crate versions" ) ;
280
+ } else if stderr. contains ( "failed to run `rustc` to learn about target-specific information" ) {
281
+ panic ! ( "couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`" ) ;
282
+ } else {
283
+ assert ! (
284
+ !stderr. contains( "toolchain" ) || !stderr. contains( "is not installed" ) ,
285
+ "missing required toolchain"
286
+ ) ;
287
+ }
288
+
289
+ match output. status . code ( ) {
290
+ Some ( 0 ) => println ! ( "Compilation successful" ) ,
291
+ Some ( code) => eprintln ! ( "Compilation failed. Exit code: {code}" ) ,
292
+ None => panic ! ( "Process terminated by signal" ) ,
293
+ }
294
+ }
0 commit comments