Skip to content

Commit 1ae683a

Browse files
committed
Auto merge of #1697 - alexcrichton:fix-path-pkgid, r=brson
The method of creating package ids in Cargo means that all sub-crates of a main repo have the same package id, which encodes the path it came from. This means that if the "root crate" switches, the package id for all dependencies will change, causing an alteration in package id hashes, causing recompiles. This commit alters a few points of hashing to ensure that whenever a package is being hashed for freshness the *source root* of the crate is used instead of the root of the main crate. This cause the hashes to be consistent across compiles, regardless of the root package. Closes #1694
2 parents 78f4080 + ddf3c79 commit 1ae683a

File tree

11 files changed

+85
-34
lines changed

11 files changed

+85
-34
lines changed

src/cargo/core/package.rs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,11 @@ use std::slice;
44
use std::path::{Path, PathBuf};
55
use semver::Version;
66

7-
use core::{
8-
Dependency,
9-
Manifest,
10-
PackageId,
11-
Registry,
12-
Target,
13-
Summary,
14-
};
7+
use core::{Dependency, Manifest, PackageId, Registry, Target, Summary, Metadata};
158
use core::dependency::SerializedDependency;
169
use util::{CargoResult, graph};
1710
use rustc_serialize::{Encoder,Encodable};
18-
use core::source::{SourceId, Source};
11+
use core::source::Source;
1912

2013
/// Informations about a package that is available somewhere in the file system.
2114
///
@@ -27,8 +20,6 @@ pub struct Package {
2720
manifest: Manifest,
2821
// The root of the package
2922
manifest_path: PathBuf,
30-
// Where this package came from
31-
source_id: SourceId,
3223
}
3324

3425
#[derive(RustcEncodable)]
@@ -60,12 +51,10 @@ impl Encodable for Package {
6051

6152
impl Package {
6253
pub fn new(manifest: Manifest,
63-
manifest_path: &Path,
64-
source_id: &SourceId) -> Package {
54+
manifest_path: &Path) -> Package {
6555
Package {
6656
manifest: manifest,
6757
manifest_path: manifest_path.to_path_buf(),
68-
source_id: source_id.clone(),
6958
}
7059
}
7160

@@ -82,6 +71,10 @@ impl Package {
8271
pub fn has_custom_build(&self) -> bool {
8372
self.targets().iter().any(|t| t.is_custom_build())
8473
}
74+
75+
pub fn generate_metadata(&self) -> Metadata {
76+
self.package_id().generate_metadata(self.root())
77+
}
8578
}
8679

8780
impl fmt::Display for Package {
@@ -100,7 +93,15 @@ impl Eq for Package {}
10093

10194
impl hash::Hash for Package {
10295
fn hash<H: hash::Hasher>(&self, into: &mut H) {
103-
self.package_id().hash(into)
96+
// We want to be sure that a path-based package showing up at the same
97+
// location always has the same hash. To that effect we don't hash the
98+
// vanilla package ID if we're a path, but instead feed in our own root
99+
// path.
100+
if self.package_id().source_id().is_path() {
101+
(0, self.root(), self.name(), self.package_id().version()).hash(into)
102+
} else {
103+
(1, self.package_id()).hash(into)
104+
}
104105
}
105106
}
106107

src/cargo/core/package_id.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::error::Error;
33
use std::fmt::{self, Formatter};
44
use std::hash::Hash;
55
use std::hash;
6+
use std::path::Path;
67
use std::sync::Arc;
78

89
use regex::Regex;
@@ -135,10 +136,13 @@ impl PackageId {
135136
pub fn version(&self) -> &semver::Version { &self.inner.version }
136137
pub fn source_id(&self) -> &SourceId { &self.inner.source_id }
137138

138-
pub fn generate_metadata(&self) -> Metadata {
139-
let metadata = short_hash(
140-
&(&self.inner.name, self.inner.version.to_string(),
141-
&self.inner.source_id));
139+
pub fn generate_metadata(&self, source_root: &Path) -> Metadata {
140+
// See comments in Package::hash for why we have this test
141+
let metadata = if self.inner.source_id.is_path() {
142+
short_hash(&(0, &self.inner.name, &self.inner.version, source_root))
143+
} else {
144+
short_hash(&(1, self))
145+
};
142146
let extra_filename = format!("-{}", metadata);
143147

144148
Metadata { metadata: metadata, extra_filename: extra_filename }

src/cargo/core/registry.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ impl Registry for Vec<Summary> {
1919
}
2020
}
2121

22+
impl Registry for Vec<Package> {
23+
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
24+
Ok(self.iter().filter(|pkg| dep.matches(pkg.summary()))
25+
.map(|pkg| pkg.summary().clone()).collect())
26+
}
27+
}
28+
2229
/// This structure represents a registry of known packages. It internally
2330
/// contains a number of `Box<Source>` instances which are used to load a
2431
/// `Package` from.

src/cargo/core/source.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use url::Url;
1212
use core::{Summary, Package, PackageId, Registry, Dependency};
1313
use sources::{PathSource, GitSource, RegistrySource};
1414
use sources::git;
15-
use util::{human, Config, CargoResult, CargoError, ToUrl};
15+
use util::{human, Config, CargoResult, ToUrl};
1616

1717
/// A Source finds and downloads remote packages based on names and
1818
/// versions.
@@ -61,8 +61,6 @@ pub enum GitReference {
6161
Rev(String),
6262
}
6363

64-
type Error = Box<CargoError + Send>;
65-
6664
/// Unique identifier for a source of packages.
6765
#[derive(Clone, Eq, Debug)]
6866
pub struct SourceId {

src/cargo/ops/cargo_package.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ fn run_verify(config: &Config, pkg: &Package, tar: &Path)
175175
});
176176
let mut new_manifest = pkg.manifest().clone();
177177
new_manifest.set_summary(new_summary.override_id(new_pkgid));
178-
let new_pkg = Package::new(new_manifest, &manifest_path, &new_src);
178+
let new_pkg = Package::new(new_manifest, &manifest_path);
179179

180180
// Now that we've rewritten all our path dependencies, compile it!
181181
try!(ops::compile_pkg(&new_pkg, None, &ops::CompileOptions {

src/cargo/ops/cargo_read_manifest.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub fn read_package(path: &Path, source_id: &SourceId, config: &Config)
3030
let (manifest, nested) =
3131
try!(read_manifest(&data, layout, source_id, config));
3232

33-
Ok((Package::new(manifest, path, source_id), nested))
33+
Ok((Package::new(manifest, path), nested))
3434
}
3535

3636
pub fn read_packages(path: &Path, source_id: &SourceId, config: &Config)

src/cargo/ops/cargo_rustc/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
275275
// Make sure that the name of this test executable doesn't
276276
// conflict with a library that has the same name and is
277277
// being tested
278-
let mut metadata = pkg.package_id().generate_metadata();
278+
let mut metadata = pkg.generate_metadata();
279279
metadata.mix(&format!("bin-{}", target.name()));
280280
Some(metadata)
281281
} else if pkg.package_id() == self.resolve.root() && !profile.test {

src/cargo/ops/cargo_rustc/layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl Layout {
130130
}
131131

132132
fn pkg_dir(&self, pkg: &Package) -> String {
133-
format!("{}-{}", pkg.name(), short_hash(pkg.package_id()))
133+
format!("{}-{}", pkg.name(), short_hash(pkg))
134134
}
135135
}
136136

src/cargo/sources/path.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<'cfg> PathSource<'cfg> {
5959
}
6060
}
6161

62-
pub fn read_packages(&self) -> CargoResult<Vec<Package>> {
62+
fn read_packages(&self) -> CargoResult<Vec<Package>> {
6363
if self.updated {
6464
Ok(self.packages.clone())
6565
} else if self.id.is_path() && self.id.precise().is_some() {
@@ -272,10 +272,7 @@ impl<'cfg> Debug for PathSource<'cfg> {
272272

273273
impl<'cfg> Registry for PathSource<'cfg> {
274274
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
275-
let mut summaries: Vec<Summary> = self.packages.iter()
276-
.map(|p| p.summary().clone())
277-
.collect();
278-
summaries.query(dep)
275+
self.packages.query(dep)
279276
}
280277
}
281278

src/cargo/util/toml.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl TomlManifest {
380380
}
381381

382382
let pkgid = try!(project.to_package_id(source_id));
383-
let metadata = pkgid.generate_metadata();
383+
let metadata = pkgid.generate_metadata(&layout.root);
384384

385385
// If we have no lib at all, use the inferred lib if available
386386
// If we have a lib with a path, we're done
@@ -427,8 +427,8 @@ impl TomlManifest {
427427

428428
for bin in bins.iter() {
429429
if blacklist.iter().find(|&x| *x == bin.name) != None {
430-
return Err(human(&format!("the binary target name `{}` is forbidden",
431-
bin.name)));
430+
return Err(human(&format!("the binary target name `{}` is \
431+
forbidden", bin.name)));
432432
}
433433
}
434434

0 commit comments

Comments
 (0)