|
1 | 1 | use std::fs::{self, File, OpenOptions};
|
2 | 2 | use std::io::prelude::*;
|
3 | 3 | use std::net::TcpListener;
|
| 4 | +use std::path::PathBuf; |
4 | 5 | use std::thread;
|
| 6 | +use std::time::SystemTime; |
5 | 7 |
|
6 | 8 | use crate::support::paths::CargoPathExt;
|
7 | 9 | use crate::support::registry::Package;
|
@@ -1178,6 +1180,176 @@ fn changing_rustflags_is_cached() {
|
1178 | 1180 | .run();
|
1179 | 1181 | }
|
1180 | 1182 |
|
| 1183 | +fn simple_deps_cleaner(mut dir: PathBuf, timestamp: filetime::FileTime) { |
| 1184 | + // Cargo is experimenting with letting outside projects develop some |
| 1185 | + // limited forms of GC for target_dir. This is one of the forms. |
| 1186 | + // Specifically, Cargo is updating the mtime of files in |
| 1187 | + // target/profile/deps each time it uses the file. |
| 1188 | + // So a cleaner can remove files older then a time stamp without |
| 1189 | + // effecting any builds that happened since that time stamp. |
| 1190 | + let mut cleand = false; |
| 1191 | + dir.push("deps"); |
| 1192 | + for dep in fs::read_dir(&dir).unwrap() { |
| 1193 | + let dep = dep.unwrap(); |
| 1194 | + if filetime::FileTime::from_last_modification_time(&dep.metadata().unwrap()) <= timestamp { |
| 1195 | + fs::remove_file(dep.path()).unwrap(); |
| 1196 | + println!("remove: {:?}", dep.path()); |
| 1197 | + cleand = true; |
| 1198 | + } |
| 1199 | + } |
| 1200 | + assert!( |
| 1201 | + cleand, |
| 1202 | + "called simple_deps_cleaner, but there was nothing to remove" |
| 1203 | + ); |
| 1204 | +} |
| 1205 | + |
| 1206 | +#[test] |
| 1207 | +fn simple_deps_cleaner_dose_not_rebuild() { |
| 1208 | + let p = project() |
| 1209 | + .file( |
| 1210 | + "Cargo.toml", |
| 1211 | + r#" |
| 1212 | + [package] |
| 1213 | + name = "foo" |
| 1214 | + version = "0.0.1" |
| 1215 | +
|
| 1216 | + [dependencies] |
| 1217 | + bar = { path = "bar" } |
| 1218 | + "#, |
| 1219 | + ) |
| 1220 | + .file("src/lib.rs", "") |
| 1221 | + .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| 1222 | + .file("bar/src/lib.rs", "") |
| 1223 | + .build(); |
| 1224 | + |
| 1225 | + p.cargo("build").run(); |
| 1226 | + p.cargo("build") |
| 1227 | + .env("RUSTFLAGS", "-C target-cpu=native") |
| 1228 | + .with_stderr( |
| 1229 | + "\ |
| 1230 | +[COMPILING] bar v0.0.1 ([..]) |
| 1231 | +[COMPILING] foo v0.0.1 ([..]) |
| 1232 | +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]", |
| 1233 | + ) |
| 1234 | + .run(); |
| 1235 | + if is_coarse_mtime() { |
| 1236 | + sleep_ms(1000); |
| 1237 | + } |
| 1238 | + let timestamp = filetime::FileTime::from_system_time(SystemTime::now()); |
| 1239 | + if is_coarse_mtime() { |
| 1240 | + sleep_ms(1000); |
| 1241 | + } |
| 1242 | + // This dose not make new files, but it dose update the mtime. |
| 1243 | + p.cargo("build") |
| 1244 | + .env("RUSTFLAGS", "-C target-cpu=native") |
| 1245 | + .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]") |
| 1246 | + .run(); |
| 1247 | + simple_deps_cleaner(p.target_debug_dir(), timestamp); |
| 1248 | + // This should not recompile! |
| 1249 | + p.cargo("build") |
| 1250 | + .env("RUSTFLAGS", "-C target-cpu=native") |
| 1251 | + .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]") |
| 1252 | + .run(); |
| 1253 | + // But this should be cleaned and so need a rebuild |
| 1254 | + p.cargo("build") |
| 1255 | + .with_stderr( |
| 1256 | + "\ |
| 1257 | +[COMPILING] bar v0.0.1 ([..]) |
| 1258 | +[COMPILING] foo v0.0.1 ([..]) |
| 1259 | +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]", |
| 1260 | + ) |
| 1261 | + .run(); |
| 1262 | +} |
| 1263 | + |
| 1264 | +fn fingerprint_cleaner(mut dir: PathBuf, timestamp: filetime::FileTime) { |
| 1265 | + // Cargo is experimenting with letting outside projects develop some |
| 1266 | + // limited forms of GC for target_dir. This is one of the forms. |
| 1267 | + // Specifically, Cargo is updating the mtime of a file in |
| 1268 | + // target/profile/.fingerprint each time it uses the fingerprint. |
| 1269 | + // So a cleaner can remove files associated with a fingerprint |
| 1270 | + // if all the files in the fingerprint's folder are older then a time stamp without |
| 1271 | + // effecting any builds that happened since that time stamp. |
| 1272 | + let mut cleand = false; |
| 1273 | + dir.push(".fingerprint"); |
| 1274 | + for fing in fs::read_dir(&dir).unwrap() { |
| 1275 | + let fing = fing.unwrap(); |
| 1276 | + |
| 1277 | + if fs::read_dir(fing.path()).unwrap().all(|f| { |
| 1278 | + filetime::FileTime::from_last_modification_time(&f.unwrap().metadata().unwrap()) |
| 1279 | + <= timestamp |
| 1280 | + }) { |
| 1281 | + fs::remove_dir_all(fing.path()).unwrap(); |
| 1282 | + println!("remove: {:?}", fing.path()); |
| 1283 | + // a real cleaner would remove the big files in deps and build as well |
| 1284 | + // but fingerprint is sufficient for our tests |
| 1285 | + cleand = true; |
| 1286 | + } else { |
| 1287 | + } |
| 1288 | + } |
| 1289 | + assert!( |
| 1290 | + cleand, |
| 1291 | + "called fingerprint_cleaner, but there was nothing to remove" |
| 1292 | + ); |
| 1293 | +} |
| 1294 | + |
| 1295 | +#[test] |
| 1296 | +fn fingerprint_cleaner_dose_not_rebuild() { |
| 1297 | + let p = project() |
| 1298 | + .file( |
| 1299 | + "Cargo.toml", |
| 1300 | + r#" |
| 1301 | + [package] |
| 1302 | + name = "foo" |
| 1303 | + version = "0.0.1" |
| 1304 | +
|
| 1305 | + [dependencies] |
| 1306 | + bar = { path = "bar" } |
| 1307 | + "#, |
| 1308 | + ) |
| 1309 | + .file("src/lib.rs", "") |
| 1310 | + .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) |
| 1311 | + .file("bar/src/lib.rs", "") |
| 1312 | + .build(); |
| 1313 | + |
| 1314 | + p.cargo("build").run(); |
| 1315 | + p.cargo("build") |
| 1316 | + .env("RUSTFLAGS", "-C target-cpu=native") |
| 1317 | + .with_stderr( |
| 1318 | + "\ |
| 1319 | +[COMPILING] bar v0.0.1 ([..]) |
| 1320 | +[COMPILING] foo v0.0.1 ([..]) |
| 1321 | +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]", |
| 1322 | + ) |
| 1323 | + .run(); |
| 1324 | + if is_coarse_mtime() { |
| 1325 | + sleep_ms(1000); |
| 1326 | + } |
| 1327 | + let timestamp = filetime::FileTime::from_system_time(SystemTime::now()); |
| 1328 | + if is_coarse_mtime() { |
| 1329 | + sleep_ms(1000); |
| 1330 | + } |
| 1331 | + // This dose not make new files, but it dose update the mtime. |
| 1332 | + p.cargo("build") |
| 1333 | + .env("RUSTFLAGS", "-C target-cpu=native") |
| 1334 | + .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]") |
| 1335 | + .run(); |
| 1336 | + fingerprint_cleaner(p.target_debug_dir(), timestamp); |
| 1337 | + // This should not recompile! |
| 1338 | + p.cargo("build") |
| 1339 | + .env("RUSTFLAGS", "-C target-cpu=native") |
| 1340 | + .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]") |
| 1341 | + .run(); |
| 1342 | + // But this should be cleaned and so need a rebuild |
| 1343 | + p.cargo("build") |
| 1344 | + .with_stderr( |
| 1345 | + "\ |
| 1346 | +[COMPILING] bar v0.0.1 ([..]) |
| 1347 | +[COMPILING] foo v0.0.1 ([..]) |
| 1348 | +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]", |
| 1349 | + ) |
| 1350 | + .run(); |
| 1351 | +} |
| 1352 | + |
1181 | 1353 | #[test]
|
1182 | 1354 | fn reuse_panic_build_dep_test() {
|
1183 | 1355 | let p = project()
|
|
0 commit comments