Skip to content

Commit 1eb4c8f

Browse files
committed
Auto merge of #5181 - alexcrichton:selectively-write-dep-info, r=matklad
Don't rewrite dep-info files if they don't change Similar to how we treat lock files, read the contents, compare, and if they're the same don't actually write the file. Closes #5172
2 parents 83a3084 + f605676 commit 1eb4c8f

File tree

3 files changed

+77
-26
lines changed

3 files changed

+77
-26
lines changed

src/cargo/ops/cargo_rustc/fingerprint.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -738,29 +738,13 @@ pub fn translate_dep_info(rustc_dep_info: &Path,
738738
cargo_dep_info: &Path,
739739
pkg_root: &Path,
740740
rustc_cwd: &Path) -> CargoResult<()> {
741-
let contents = paths::read(rustc_dep_info)?;
742-
let line = match contents.lines().next() {
743-
Some(line) => line,
744-
None => return Ok(()),
745-
};
746-
let pos = line.find(": ").ok_or_else(|| {
747-
internal(format!("dep-info not in an understood format: {}",
748-
rustc_dep_info.display()))
749-
})?;
750-
let deps = &line[pos + 2..];
741+
let target = parse_rustc_dep_info(rustc_dep_info)?;
742+
let deps = &target.get(0).ok_or_else(|| {
743+
internal("malformed dep-info format, no targets".to_string())
744+
})?.1;
751745

752746
let mut new_contents = Vec::new();
753-
let mut deps = deps.split(' ').map(|s| s.trim()).filter(|s| !s.is_empty());
754-
while let Some(s) = deps.next() {
755-
let mut file = s.to_string();
756-
while file.ends_with('\\') {
757-
file.pop();
758-
file.push(' ');
759-
file.push_str(deps.next().ok_or_else(|| {
760-
internal("malformed dep-info format, trailing \\".to_string())
761-
})?);
762-
}
763-
747+
for file in deps {
764748
let absolute = rustc_cwd.join(file);
765749
let path = absolute.strip_prefix(pkg_root).unwrap_or(&absolute);
766750
new_contents.extend(util::path2bytes(path)?);
@@ -770,3 +754,29 @@ pub fn translate_dep_info(rustc_dep_info: &Path,
770754
Ok(())
771755
}
772756

757+
pub fn parse_rustc_dep_info(rustc_dep_info: &Path)
758+
-> CargoResult<Vec<(String, Vec<String>)>>
759+
{
760+
let contents = paths::read(rustc_dep_info)?;
761+
contents.lines()
762+
.filter_map(|l| l.find(": ").map(|i| (l, i)))
763+
.map(|(line, pos)| {
764+
let target = &line[..pos];
765+
let mut deps = line[pos + 2..].split_whitespace();
766+
767+
let mut ret = Vec::new();
768+
while let Some(s) = deps.next() {
769+
let mut file = s.to_string();
770+
while file.ends_with('\\') {
771+
file.pop();
772+
file.push(' ');
773+
file.push_str(deps.next().ok_or_else(|| {
774+
internal("malformed dep-info format, trailing \\".to_string())
775+
})?);
776+
}
777+
ret.push(file);
778+
}
779+
Ok((target.to_string(), ret))
780+
})
781+
.collect()
782+
}

src/cargo/ops/cargo_rustc/output_depinfo.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::HashSet;
1+
use std::collections::{HashSet, BTreeSet};
22
use std::io::{Write, BufWriter};
33
use std::fs::File;
44
use std::path::{Path, PathBuf};
@@ -21,7 +21,7 @@ fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResul
2121
}
2222

2323
fn add_deps_for_unit<'a, 'b>(
24-
deps: &mut HashSet<PathBuf>,
24+
deps: &mut BTreeSet<PathBuf>,
2525
context: &mut Context<'a, 'b>,
2626
unit: &Unit<'a>,
2727
visited: &mut HashSet<Unit<'a>>,
@@ -67,7 +67,7 @@ fn add_deps_for_unit<'a, 'b>(
6767
}
6868

6969
pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) -> CargoResult<()> {
70-
let mut deps = HashSet::new();
70+
let mut deps = BTreeSet::new();
7171
let mut visited = HashSet::new();
7272
let success = add_deps_for_unit(&mut deps, context, unit, &mut visited).is_ok();
7373
let basedir_string;
@@ -79,15 +79,31 @@ pub fn output_depinfo<'a, 'b>(context: &mut Context<'a, 'b>, unit: &Unit<'a>) ->
7979
}
8080
None => None,
8181
};
82+
let deps = deps.iter()
83+
.map(|f| render_filename(f, basedir))
84+
.collect::<CargoResult<Vec<_>>>()?;
85+
8286
for &(_, ref link_dst, _) in context.target_filenames(unit)?.iter() {
8387
if let Some(ref link_dst) = *link_dst {
8488
let output_path = link_dst.with_extension("d");
8589
if success {
86-
let mut outfile = BufWriter::new(File::create(output_path)?);
8790
let target_fn = render_filename(link_dst, basedir)?;
91+
92+
// If nothing changed don't recreate the file which could alter
93+
// its mtime
94+
if let Ok(previous) = fingerprint::parse_rustc_dep_info(&output_path) {
95+
if previous.len() == 1 &&
96+
previous[0].0 == target_fn &&
97+
previous[0].1 == deps {
98+
continue
99+
}
100+
}
101+
102+
// Otherwise write it all out
103+
let mut outfile = BufWriter::new(File::create(output_path)?);
88104
write!(outfile, "{}:", target_fn)?;
89105
for dep in &deps {
90-
write!(outfile, " {}", render_filename(dep, basedir)?)?;
106+
write!(outfile, " {}", dep)?;
91107
}
92108
writeln!(outfile, "")?;
93109

tests/testsuite/dep_info.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use cargotest::support::{basic_bin_manifest, main_file, execs, project};
2+
use filetime::FileTime;
23
use hamcrest::{assert_that, existing_file};
34

45
#[test]
@@ -79,3 +80,27 @@ fn build_dep_info_dylib() {
7980
assert_that(p.cargo("build").arg("--example=ex"), execs().with_status(0));
8081
assert_that(&p.example_lib("ex", "dylib").with_extension("d"), existing_file());
8182
}
83+
84+
#[test]
85+
fn no_rewrite_if_no_change() {
86+
let p = project("foo")
87+
.file("Cargo.toml", r#"
88+
[package]
89+
name = "foo"
90+
version = "0.0.1"
91+
authors = []
92+
"#)
93+
.file("src/lib.rs", "")
94+
.build();
95+
96+
assert_that(p.cargo("build"), execs().with_status(0));
97+
let dep_info = p.root().join("target/debug/libfoo.d");
98+
let metadata1 = dep_info.metadata().unwrap();
99+
assert_that(p.cargo("build"), execs().with_status(0));
100+
let metadata2 = dep_info.metadata().unwrap();
101+
102+
assert_eq!(
103+
FileTime::from_last_modification_time(&metadata1),
104+
FileTime::from_last_modification_time(&metadata2),
105+
);
106+
}

0 commit comments

Comments
 (0)