Skip to content

Commit b91c54f

Browse files
committed
Refactor EncodableResolve::into_resolve
1 parent ab3a1c5 commit b91c54f

File tree

2 files changed

+100
-69
lines changed

2 files changed

+100
-69
lines changed

src/cargo/core/resolver/encode.rs

Lines changed: 70 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{HashMap, BTreeMap};
1+
use std::collections::{HashMap, HashSet, BTreeMap};
22
use std::fmt;
33
use std::str::FromStr;
44

@@ -24,17 +24,6 @@ impl EncodableResolve {
2424
pub fn into_resolve(self, ws: &Workspace) -> CargoResult<Resolve> {
2525
let path_deps = build_path_deps(ws);
2626

27-
let mut g = Graph::new();
28-
let mut tmp = HashMap::new();
29-
let mut replacements = HashMap::new();
30-
31-
let id2pkgid = |id: &EncodablePackageId| {
32-
to_package_id(&id.name, &id.version, id.source.as_ref(), &path_deps)
33-
};
34-
let dep2pkgid = |dep: &EncodableDependency| {
35-
to_package_id(&dep.name, &dep.version, dep.source.as_ref(), &path_deps)
36-
};
37-
3827
let packages = {
3928
let mut packages = self.package.unwrap_or(Vec::new());
4029
if let Some(root) = self.root {
@@ -43,58 +32,83 @@ impl EncodableResolve {
4332
packages
4433
};
4534

46-
let ids = try!(packages.iter().map(&dep2pkgid)
47-
.collect::<CargoResult<Vec<_>>>());
35+
// `PackageId`s in the lock file don't include the `source` part
36+
// for workspace members, so we reconstruct proper ids.
37+
let (live_pkgs, all_pkgs) = {
38+
let mut live_pkgs = HashMap::new();
39+
let mut all_pkgs = HashSet::new();
40+
for pkg in packages.iter() {
41+
let enc_id = EncodablePackageId {
42+
name: pkg.name.clone(),
43+
version: pkg.version.clone(),
44+
source: pkg.source.clone(),
45+
};
4846

49-
{
50-
let mut register_pkg = |pkgid: &PackageId| {
51-
let precise = pkgid.source_id().precise()
52-
.map(|s| s.to_string());
53-
if tmp.insert(pkgid.clone(), precise).is_some() {
47+
if !all_pkgs.insert(enc_id.clone()) {
5448
return Err(internal(format!("package `{}` is specified twice in the lockfile",
55-
pkgid.name())));
49+
pkg.name)));
5650
}
57-
g.add(pkgid.clone(), &[]);
58-
Ok(())
59-
};
51+
let id = match pkg.source.as_ref().or(path_deps.get(&pkg.name)) {
52+
// We failed to find a local package in the workspace.
53+
// It must have been removed and should be ignored.
54+
None => continue,
55+
Some(source) => try!(PackageId::new(&pkg.name, &pkg.version, source))
56+
};
6057

61-
for id in ids.iter() {
62-
try!(register_pkg(id));
58+
assert!(live_pkgs.insert(enc_id, (id, pkg)).is_none())
6359
}
64-
}
60+
(live_pkgs, all_pkgs)
61+
};
6562

66-
{
67-
let mut add_dependencies = |id: &PackageId, pkg: &EncodableDependency|
68-
-> CargoResult<()> {
69-
if let Some(ref replace) = pkg.replace {
70-
let replace = try!(id2pkgid(replace));
71-
let replace_precise = tmp.get(&replace).map(|p| {
72-
replace.with_precise(p.clone())
73-
}).unwrap_or(replace);
74-
replacements.insert(id.clone(), replace_precise);
75-
assert!(pkg.dependencies.is_none());
76-
return Ok(())
63+
let lookup_id = |enc_id: &EncodablePackageId| -> CargoResult<Option<PackageId>> {
64+
match live_pkgs.get(enc_id) {
65+
Some(&(ref id, _)) => Ok(Some(id.clone())),
66+
None => if all_pkgs.contains(enc_id) {
67+
// Package is found in the lockfile, but it is
68+
// no longer a member of the workspace.
69+
Ok(None)
70+
} else {
71+
Err(internal(format!("package `{}` is specified as a dependency, \
72+
but is missing from the package list", enc_id)))
7773
}
74+
}
75+
};
7876

77+
let g = {
78+
let mut g = Graph::new();
79+
80+
for &(ref id, _) in live_pkgs.values() {
81+
g.add(id.clone(), &[]);
82+
}
83+
84+
for &(ref id, ref pkg) in live_pkgs.values() {
7985
let deps = match pkg.dependencies {
8086
Some(ref deps) => deps,
81-
None => return Ok(()),
87+
None => continue
8288
};
89+
8390
for edge in deps.iter() {
84-
let to_depend_on = try!(id2pkgid(edge));
85-
let precise_pkgid =
86-
tmp.get(&to_depend_on)
87-
.map(|p| to_depend_on.with_precise(p.clone()))
88-
.unwrap_or(to_depend_on.clone());
89-
g.link(id.clone(), precise_pkgid);
91+
if let Some(to_depend_on) = try!(lookup_id(edge)) {
92+
g.link(id.clone(), to_depend_on);
93+
}
9094
}
91-
Ok(())
92-
};
95+
}
96+
g
97+
};
9398

94-
for (id, ref pkg) in ids.iter().zip(packages) {
95-
try!(add_dependencies(id, pkg));
99+
let replacements = {
100+
let mut replacements = HashMap::new();
101+
for &(ref id, ref pkg) in live_pkgs.values() {
102+
if let Some(ref replace) = pkg.replace {
103+
assert!(pkg.dependencies.is_none());
104+
if let Some(replace_id) = try!(lookup_id(replace)) {
105+
replacements.insert(id.clone(), replace_id);
106+
}
107+
}
96108
}
97-
}
109+
replacements
110+
};
111+
98112
let mut metadata = self.metadata.unwrap_or(BTreeMap::new());
99113

100114
// Parse out all package checksums. After we do this we can be in a few
@@ -118,13 +132,14 @@ impl EncodableResolve {
118132
for (k, v) in metadata.iter().filter(|p| p.0.starts_with(prefix)) {
119133
to_remove.push(k.to_string());
120134
let k = &k[prefix.len()..];
121-
let id: EncodablePackageId = try!(k.parse().chain_error(|| {
135+
let enc_id: EncodablePackageId = try!(k.parse().chain_error(|| {
122136
internal("invalid encoding of checksum in lockfile")
123137
}));
124-
let id = try!(to_package_id(&id.name,
125-
&id.version,
126-
id.source.as_ref(),
127-
&path_deps));
138+
let id = match lookup_id(&enc_id) {
139+
Ok(Some(id)) => id,
140+
_ => continue,
141+
};
142+
128143
let v = if v == "<none>" {
129144
None
130145
} else {
@@ -187,20 +202,6 @@ fn build_path_deps(ws: &Workspace) -> HashMap<String, SourceId> {
187202
}
188203
}
189204

190-
fn to_package_id(name: &str,
191-
version: &str,
192-
source: Option<&SourceId>,
193-
path_sources: &HashMap<String, SourceId>)
194-
-> CargoResult<PackageId> {
195-
if let Some(source) = source.or(path_sources.get(name)) {
196-
PackageId::new(name, version, source)
197-
} else {
198-
let dummy_source = SourceId::from_url("path+file:///dummy_path").unwrap();
199-
PackageId::new(name, version, &dummy_source)
200-
}
201-
}
202-
203-
204205
#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)]
205206
pub struct EncodableDependency {
206207
name: String,
@@ -210,7 +211,7 @@ pub struct EncodableDependency {
210211
replace: Option<EncodablePackageId>,
211212
}
212213

213-
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
214+
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
214215
pub struct EncodablePackageId {
215216
name: String,
216217
version: String,

tests/bad-config.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,36 @@ Caused by:
319319
"));
320320
}
321321

322+
#[test]
323+
fn bad_dependency_in_lockfile() {
324+
let p = project("foo")
325+
.file("Cargo.toml", r#"
326+
[project]
327+
name = "foo"
328+
version = "0.0.1"
329+
authors = []
330+
"#)
331+
.file("src/lib.rs", "")
332+
.file("Cargo.lock", r#"
333+
[root]
334+
name = "foo"
335+
version = "0.0.1"
336+
dependencies = [
337+
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
338+
]
339+
"#);
340+
p.build();
341+
342+
assert_that(p.cargo("build").arg("--verbose"),
343+
execs().with_status(101).with_stderr("\
344+
[ERROR] failed to parse lock file at: [..]
345+
346+
Caused by:
347+
package `bar 0.1.0 ([..])` is specified as a dependency, but is missing from the package list
348+
"));
349+
350+
}
351+
322352
#[test]
323353
fn bad_git_dependency() {
324354
let foo = project("foo")

0 commit comments

Comments
 (0)