Skip to content

Commit 2dd67fc

Browse files
committed
Hash the sysroot contents
1 parent c5d3a55 commit 2dd67fc

File tree

3 files changed

+83
-7
lines changed

3 files changed

+83
-7
lines changed

Cargo.lock

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ description = "Build a rustc sysroot with custom flags"
1212
tempfile = "3"
1313
rustc_version = "0.4"
1414
anyhow = "1.0"
15+
walkdir = "2.4"

src/lib.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@
77
use std::collections::hash_map::DefaultHasher;
88
use std::env;
99
use std::ffi::{OsStr, OsString};
10-
use std::fs;
10+
use std::fs::{self, File};
1111
use std::hash::{Hash, Hasher};
12+
use std::io::{BufRead, BufReader};
1213
use std::ops::Not;
1314
use std::path::{Path, PathBuf};
1415
use std::process::Command;
1516

1617
use anyhow::{bail, Context, Result};
1718
use tempfile::TempDir;
19+
use walkdir::WalkDir;
1820

1921
/// Returns where the given rustc stores its sysroot source code.
2022
pub fn rustc_sysroot_src(mut rustc: Command) -> Result<PathBuf> {
@@ -84,6 +86,30 @@ fn make_writeable(p: &Path) -> Result<()> {
8486
Ok(())
8587
}
8688

89+
/// Hash the contents of every file in a directory, recursively.
90+
pub fn hash_recursive(path: &Path, hasher: &mut DefaultHasher) -> Result<()> {
91+
for entry in WalkDir::new(path).follow_links(true).into_iter() {
92+
let entry = entry?;
93+
// WalkDir yields the directories as well, and File::open will succeed on them. The
94+
// reliable way to distinguish directories here is to check explicitly.
95+
if entry.file_type().is_dir() {
96+
continue;
97+
}
98+
let file = File::open(entry.path())?;
99+
let mut reader = BufReader::new(file);
100+
while let Ok(buf) = reader.fill_buf() {
101+
if buf.is_empty() {
102+
// EOF is not an error, we just get an empty buffer.
103+
break;
104+
}
105+
hasher.write(buf);
106+
let len = buf.len();
107+
reader.consume(len);
108+
}
109+
}
110+
Ok(())
111+
}
112+
87113
/// The build mode to use for this sysroot.
88114
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
89115
pub enum BuildMode {
@@ -220,18 +246,16 @@ impl SysrootBuilder {
220246
&self,
221247
src_dir: &Path,
222248
rustc_version: &rustc_version::VersionMeta,
223-
) -> u64 {
249+
) -> Result<u64> {
224250
let mut hasher = DefaultHasher::new();
225251

226-
// For now, we just hash in the information we have in `self`.
227-
// Ideally we'd recursively hash the entire folder but that sounds slow?
228-
src_dir.hash(&mut hasher);
252+
hash_recursive(src_dir, &mut hasher)?;
229253
self.config.hash(&mut hasher);
230254
self.mode.hash(&mut hasher);
231255
self.rustflags.hash(&mut hasher);
232256
rustc_version.hash(&mut hasher);
233257

234-
hasher.finish()
258+
Ok(hasher.finish())
235259
}
236260

237261
fn sysroot_read_hash(&self) -> Option<u64> {
@@ -372,7 +396,7 @@ path = "lib.rs"
372396
}
373397

374398
// Check if we even need to do anything.
375-
let cur_hash = self.sysroot_compute_hash(src_dir, &rustc_version);
399+
let cur_hash = self.sysroot_compute_hash(src_dir, &rustc_version)?;
376400
if self.sysroot_read_hash() == Some(cur_hash) {
377401
// Already done!
378402
return Ok(());

0 commit comments

Comments
 (0)