From f162aed2c743328b827da866e6cb906081c7bee8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 25 Mar 2015 11:39:47 -0700 Subject: [PATCH] Lazily load hashes for registry sources The hashes would occasionally disappear when the main package registry overwrote a previous registry source, so this just adds logic to load hashes if they're missing. Closes #1355 --- src/cargo/core/registry.rs | 12 ++++++++++-- src/cargo/sources/registry.rs | 23 ++++++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs index adf05b0fad6..54f3ff87ed6 100644 --- a/src/cargo/core/registry.rs +++ b/src/cargo/core/registry.rs @@ -110,11 +110,15 @@ impl<'a, 'b> PackageRegistry<'a, 'b> { // We've previously loaded this source, and we've already locked it, // so we're not allowed to change it even if `namespace` has a // slightly different precise version listed. - Some(&(_, Kind::Locked)) => return Ok(()), + Some(&(_, Kind::Locked)) => { + debug!("load/locked {}", namespace); + return Ok(()) + } // If the previous source was not a precise source, then we can be // sure that it's already been updated if we've already loaded it. Some(&(ref previous, _)) if previous.precise().is_none() => { + debug!("load/precise {}", namespace); return Ok(()) } @@ -123,10 +127,14 @@ impl<'a, 'b> PackageRegistry<'a, 'b> { // updating this source. Some(&(ref previous, _)) => { if previous.precise() == namespace.precise() { + debug!("load/match {}", namespace); return Ok(()) } + debug!("load/mismatch {}", namespace); + } + None => { + debug!("load/missing {}", namespace); } - None => {} } try!(self.load(namespace, Kind::Normal)); diff --git a/src/cargo/sources/registry.rs b/src/cargo/sources/registry.rs index cf5db84eaed..ad7ed0ba593 100644 --- a/src/cargo/sources/registry.rs +++ b/src/cargo/sources/registry.rs @@ -298,13 +298,14 @@ impl<'a, 'b> RegistrySource<'a, 'b> { /// No action is taken if the package is already downloaded. fn download_package(&mut self, pkg: &PackageId, url: &Url) -> CargoResult { - // TODO: should discover from the S3 redirect + // TODO: should discover filename from the S3 redirect let filename = format!("{}-{}.crate", pkg.name(), pkg.version()); let dst = self.cache_path.join(&filename); if fs::metadata(&dst).is_ok() { return Ok(dst) } try!(self.config.shell().status("Downloading", pkg)); try!(fs::create_dir_all(dst.parent().unwrap())); + let expected_hash = try!(self.hash(pkg)); let handle = match self.handle { Some(ref mut handle) => handle, None => { @@ -320,17 +321,12 @@ impl<'a, 'b> RegistrySource<'a, 'b> { } // Verify what we just downloaded - let expected = self.hashes.get(&(pkg.name().to_string(), - pkg.version().to_string())); - let expected = try!(expected.chain_error(|| { - internal(format!("no hash listed for {}", pkg)) - })); let actual = { let mut state = Sha256::new(); state.update(resp.get_body()); state.finish() }; - if actual.to_hex() != *expected { + if actual.to_hex() != expected_hash { return Err(human(format!("Failed to verify the checksum of `{}`", pkg))) } @@ -339,6 +335,19 @@ impl<'a, 'b> RegistrySource<'a, 'b> { Ok(dst) } + /// Return the hash listed for a specified PackageId. + fn hash(&mut self, pkg: &PackageId) -> CargoResult { + let key = (pkg.name().to_string(), pkg.version().to_string()); + if let Some(s) = self.hashes.get(&key) { + return Ok(s.clone()) + } + // Ok, we're missing the key, so parse the index file to load it. + try!(self.summaries(pkg.name())); + self.hashes.get(&key).chain_error(|| { + internal(format!("no hash listed for {}", pkg)) + }).map(|s| s.clone()) + } + /// Unpacks a downloaded package into a location where it's ready to be /// compiled. ///