fingerprint: Recover from fs::stat errors

Fingerprinting will fail at an fs::stat() call if there is a broken
symlink in a package's directory.  This commit recovers from fs::stat()
errors on broken symlinks by treating them as having mtime 0, which
should not affect the overall fingerprint.

Fix #135
This commit is contained in:
Tom Jakubowski 2014-07-07 14:46:03 -07:00
parent ffd985f1f4
commit f488174208
3 changed files with 59 additions and 3 deletions

View File

@ -106,7 +106,12 @@ impl Source for PathSource {
fn walk(path: &Path, is_root: bool) -> CargoResult<u64> {
if !path.is_dir() {
return Ok(try!(fs::stat(path)).modified)
// An fs::stat error here is either because path is a
// broken symlink, a permissions error, or a race
// condition where this path was rm'ed - either way,
// we can ignore the error and treat the path's mtime
// as 0.
return Ok(fs::stat(path).map(|s| s.modified).unwrap_or(0))
}
// Don't recurse into any sub-packages that we have
if !is_root && path.join("Cargo.toml").exists() { return Ok(0) }

View File

@ -51,11 +51,36 @@ impl FileBuilder {
}
}
#[deriving(PartialEq,Clone)]
struct SymlinkBuilder {
dst: Path,
src: Path
}
impl SymlinkBuilder {
pub fn new(dst: Path, src: Path) -> SymlinkBuilder {
SymlinkBuilder { dst: dst, src: src }
}
fn mk(&self) -> Result<(), String> {
try!(mkdir_recursive(&self.dirname()));
fs::symlink(&self.dst, &self.src)
.with_err_msg(format!("Could not create symlink; dst={} src={}",
self.dst.display(), self.src.display()))
}
fn dirname(&self) -> Path {
Path::new(self.src.dirname())
}
}
#[deriving(PartialEq,Clone)]
pub struct ProjectBuilder {
name: String,
root: Path,
files: Vec<FileBuilder>
files: Vec<FileBuilder>,
symlinks: Vec<SymlinkBuilder>
}
impl ProjectBuilder {
@ -63,7 +88,8 @@ impl ProjectBuilder {
ProjectBuilder {
name: name.to_str(),
root: root,
files: vec!()
files: vec!(),
symlinks: vec!()
}
}
@ -93,6 +119,13 @@ impl ProjectBuilder {
self
}
pub fn symlink<T: BytesContainer>(mut self, dst: T,
src: T) -> ProjectBuilder {
self.symlinks.push(SymlinkBuilder::new(self.root.join(dst),
self.root.join(src)));
self
}
// TODO: return something different than a ProjectBuilder
pub fn build<'a>(&'a self) -> &'a ProjectBuilder {
match self.build_with_result() {
@ -112,6 +145,10 @@ impl ProjectBuilder {
try!(file.mk());
}
for symlink in self.symlinks.iter() {
try!(symlink.mk());
}
Ok(())
}

View File

@ -626,3 +626,17 @@ test!(self_dependency {
assert_that(p.cargo_process("cargo-build"),
execs().with_status(0));
})
test!(ignore_bogus_symlinks {
let p = project("foo")
.file("Cargo.toml", basic_bin_manifest("foo").as_slice())
.file("src/foo.rs", main_file(r#""i am foo""#, []).as_slice())
.symlink("Notafile", "bar");
assert_that(p.cargo_process("cargo-build"), execs());
assert_that(&p.bin("foo"), existing_file());
assert_that(
process(p.bin("foo")),
execs().with_stdout("i am foo\n"));
})