]> git.lizzy.rs Git - rust.git/blob - src/tools/cargotest/main.rs
Rollup merge of #104052 - TaKO8Ki:fix-103997, r=notriddle
[rust.git] / src / tools / cargotest / main.rs
1 use std::env;
2 use std::fs;
3 use std::path::{Path, PathBuf};
4 use std::process::Command;
5
6 struct Test {
7     repo: &'static str,
8     name: &'static str,
9     sha: &'static str,
10     lock: Option<&'static str>,
11     packages: &'static [&'static str],
12     features: Option<&'static [&'static str]>,
13     manifest_path: Option<&'static str>,
14     /// `filters` are passed to libtest (i.e., after a `--` in the `cargo test` invocation).
15     filters: &'static [&'static str],
16 }
17
18 const TEST_REPOS: &[Test] = &[
19     Test {
20         name: "iron",
21         repo: "https://github.com/iron/iron",
22         sha: "cf056ea5e8052c1feea6141e40ab0306715a2c33",
23         lock: None,
24         packages: &[],
25         features: None,
26         manifest_path: None,
27         filters: &[],
28     },
29     Test {
30         name: "ripgrep",
31         repo: "https://github.com/BurntSushi/ripgrep",
32         sha: "ced5b92aa93eb47e892bd2fd26ab454008721730",
33         lock: None,
34         packages: &[],
35         features: None,
36         manifest_path: None,
37         filters: &[],
38     },
39     Test {
40         name: "tokei",
41         repo: "https://github.com/XAMPPRocky/tokei",
42         sha: "fdf3f8cb279a7aeac0696c87e5d8b0cd946e4f9e",
43         lock: None,
44         packages: &[],
45         features: None,
46         manifest_path: None,
47         filters: &[],
48     },
49     Test {
50         name: "xsv",
51         repo: "https://github.com/BurntSushi/xsv",
52         sha: "3de6c04269a7d315f7e9864b9013451cd9580a08",
53         lock: None,
54         packages: &[],
55         features: None,
56         manifest_path: None,
57         // Many tests here use quickcheck and some of them can fail randomly, so only run deterministic tests.
58         filters: &[
59             "test_flatten::",
60             "test_fmt::",
61             "test_headers::",
62             "test_index::",
63             "test_join::",
64             "test_partition::",
65             "test_search::",
66             "test_select::",
67             "test_slice::",
68             "test_split::",
69             "test_stats::",
70             "test_table::",
71         ],
72     },
73     Test {
74         name: "servo",
75         repo: "https://github.com/servo/servo",
76         sha: "785a344e32db58d4e631fd3cae17fd1f29a721ab",
77         lock: None,
78         // Only test Stylo a.k.a. Quantum CSS, the parts of Servo going into Firefox.
79         // This takes much less time to build than all of Servo and supports stable Rust.
80         packages: &["selectors"],
81         features: None,
82         manifest_path: None,
83         filters: &[],
84     },
85     Test {
86         name: "diesel",
87         repo: "https://github.com/diesel-rs/diesel",
88         sha: "91493fe47175076f330ce5fc518f0196c0476f56",
89         lock: None,
90         packages: &[],
91         // Test the embedded sqlite variant of diesel
92         // This does not require any dependency to be present,
93         // sqlite will be compiled as part of the build process
94         features: Some(&["sqlite", "libsqlite3-sys/bundled"]),
95         // We are only interested in testing diesel itself
96         // not any other crate present in the diesel workspace
97         // (This is required to set the feature flags above)
98         manifest_path: Some("diesel/Cargo.toml"),
99         filters: &[],
100     },
101 ];
102
103 fn main() {
104     let args = env::args().collect::<Vec<_>>();
105     let cargo = &args[1];
106     let out_dir = Path::new(&args[2]);
107     let cargo = &Path::new(cargo);
108
109     for test in TEST_REPOS.iter().rev() {
110         if args[3..].is_empty() || args[3..].iter().any(|s| s.contains(test.name)) {
111             test_repo(cargo, out_dir, test);
112         }
113     }
114 }
115
116 fn test_repo(cargo: &Path, out_dir: &Path, test: &Test) {
117     println!("testing {}", test.repo);
118     let dir = clone_repo(test, out_dir);
119     if let Some(lockfile) = test.lock {
120         fs::write(&dir.join("Cargo.lock"), lockfile).unwrap();
121     }
122     if !run_cargo_test(cargo, &dir, test.packages, test.features, test.manifest_path, test.filters)
123     {
124         panic!("tests failed for {}", test.repo);
125     }
126 }
127
128 fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf {
129     let out_dir = out_dir.join(test.name);
130
131     if !out_dir.join(".git").is_dir() {
132         let status = Command::new("git").arg("init").arg(&out_dir).status().unwrap();
133         assert!(status.success());
134     }
135
136     // Try progressively deeper fetch depths to find the commit
137     let mut found = false;
138     for depth in &[0, 1, 10, 100, 1000, 100000] {
139         if *depth > 0 {
140             let status = Command::new("git")
141                 .arg("fetch")
142                 .arg(test.repo)
143                 .arg("master")
144                 .arg(&format!("--depth={}", depth))
145                 .current_dir(&out_dir)
146                 .status()
147                 .unwrap();
148             assert!(status.success());
149         }
150
151         let status = Command::new("git")
152             .arg("reset")
153             .arg(test.sha)
154             .arg("--hard")
155             .current_dir(&out_dir)
156             .status()
157             .unwrap();
158
159         if status.success() {
160             found = true;
161             break;
162         }
163     }
164
165     if !found {
166         panic!("unable to find commit {}", test.sha)
167     }
168     let status =
169         Command::new("git").arg("clean").arg("-fdx").current_dir(&out_dir).status().unwrap();
170     assert!(status.success());
171
172     out_dir
173 }
174
175 fn run_cargo_test(
176     cargo_path: &Path,
177     crate_path: &Path,
178     packages: &[&str],
179     features: Option<&[&str]>,
180     manifest_path: Option<&str>,
181     filters: &[&str],
182 ) -> bool {
183     let mut command = Command::new(cargo_path);
184     command.arg("test");
185
186     if let Some(path) = manifest_path {
187         command.arg(format!("--manifest-path={}", path));
188     }
189
190     if let Some(features) = features {
191         command.arg("--no-default-features");
192         for feature in features {
193             command.arg(format!("--features={}", feature));
194         }
195     }
196
197     for name in packages {
198         command.arg("-p").arg(name);
199     }
200
201     command.arg("--");
202     command.args(filters);
203
204     let status = command
205         // Disable rust-lang/cargo's cross-compile tests
206         .env("CFG_DISABLE_CROSS_TESTS", "1")
207         // Relax #![deny(warnings)] in some crates
208         .env("RUSTFLAGS", "--cap-lints warn")
209         // servo tries to use 'lld-link.exe' on windows, but we don't
210         // have lld on our PATH in CI. Override it to use 'link.exe'
211         .env("CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER", "link.exe")
212         .env("CARGO_TARGET_I686_PC_WINDOWS_MSVC_LINKER", "link.exe")
213         .current_dir(crate_path)
214         .status()
215         .unwrap();
216
217     status.success()
218 }