Skip to content

Commit f28c787

Browse files
committed
Fix decoding lock files with path dependencies
With the previous changes a path dependency must have the precise path to it listed in its package id. Currently when decoding a lockfile, however, all path dependencies have the same package id, which unfortunately causes a mismatch. This commit alters the decoding of a lockfile to perform some simple path traversals to probe the filesystem to understand where path dependencies are and set the right package id for the found packages.
1 parent a71e574 commit f28c787

File tree

8 files changed

+97
-69
lines changed

8 files changed

+97
-69
lines changed

src/cargo/core/resolver/encode.rs

Lines changed: 75 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::collections::{HashMap, BTreeMap};
33
use regex::Regex;
44
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
55

6-
use core::{PackageId, SourceId};
7-
use util::{CargoResult, Graph};
6+
use core::{Package, PackageId, SourceId};
7+
use util::{CargoResult, Graph, Config};
88

99
use super::Resolve;
1010

@@ -18,66 +18,113 @@ pub struct EncodableResolve {
1818
pub type Metadata = BTreeMap<String, String>;
1919

2020
impl EncodableResolve {
21-
pub fn to_resolve(&self, default: &SourceId) -> CargoResult<Resolve> {
21+
pub fn to_resolve(&self, root: &Package, config: &Config)
22+
-> CargoResult<Resolve> {
23+
let mut path_deps = HashMap::new();
24+
try!(build_path_deps(root, &mut path_deps, config));
25+
let default = root.package_id().source_id();
26+
2227
let mut g = Graph::new();
2328
let mut tmp = HashMap::new();
2429

2530
let packages = Vec::new();
2631
let packages = self.package.as_ref().unwrap_or(&packages);
2732

33+
let root = try!(to_package_id(&self.root.name,
34+
&self.root.version,
35+
self.root.source.as_ref(),
36+
default, &path_deps));
37+
let ids = try!(packages.iter().map(|p| {
38+
to_package_id(&p.name, &p.version, p.source.as_ref(),
39+
default, &path_deps)
40+
}).collect::<CargoResult<Vec<_>>>());
41+
2842
{
29-
let mut register_pkg = |pkg: &EncodableDependency|
30-
-> CargoResult<()> {
31-
let pkgid = try!(pkg.to_package_id(default));
43+
let mut register_pkg = |pkgid: &PackageId| {
3244
let precise = pkgid.source_id().precise()
3345
.map(|s| s.to_string());
3446
assert!(tmp.insert(pkgid.clone(), precise).is_none(),
3547
"a package was referenced twice in the lockfile");
36-
g.add(try!(pkg.to_package_id(default)), &[]);
37-
Ok(())
48+
g.add(pkgid.clone(), &[]);
3849
};
3950

40-
try!(register_pkg(&self.root));
41-
for pkg in packages.iter() {
42-
try!(register_pkg(pkg));
51+
register_pkg(&root);
52+
for id in ids.iter() {
53+
register_pkg(id);
4354
}
4455
}
4556

4657
{
47-
let mut add_dependencies = |pkg: &EncodableDependency|
58+
let mut add_dependencies = |id: &PackageId, pkg: &EncodableDependency|
4859
-> CargoResult<()> {
49-
let package_id = try!(pkg.to_package_id(default));
50-
5160
let deps = match pkg.dependencies {
5261
Some(ref deps) => deps,
5362
None => return Ok(()),
5463
};
5564
for edge in deps.iter() {
56-
let to_depend_on = try!(edge.to_package_id(default));
65+
let to_depend_on = try!(to_package_id(&edge.name,
66+
&edge.version,
67+
edge.source.as_ref(),
68+
default,
69+
&path_deps));
5770
let precise_pkgid =
5871
tmp.get(&to_depend_on)
5972
.map(|p| to_depend_on.with_precise(p.clone()))
6073
.unwrap_or(to_depend_on.clone());
61-
g.link(package_id.clone(), precise_pkgid);
74+
g.link(id.clone(), precise_pkgid);
6275
}
6376
Ok(())
6477
};
6578

66-
try!(add_dependencies(&self.root));
67-
for pkg in packages.iter() {
68-
try!(add_dependencies(pkg));
79+
try!(add_dependencies(&root, &self.root));
80+
for (id, pkg) in ids.iter().zip(packages) {
81+
try!(add_dependencies(id, pkg));
6982
}
7083
}
7184

7285
Ok(Resolve {
7386
graph: g,
74-
root: try!(self.root.to_package_id(default)),
87+
root: root,
7588
features: HashMap::new(),
7689
metadata: self.metadata.clone(),
7790
})
7891
}
7992
}
8093

94+
fn build_path_deps(root: &Package,
95+
map: &mut HashMap<String, SourceId>,
96+
config: &Config)
97+
-> CargoResult<()> {
98+
assert!(root.package_id().source_id().is_path());
99+
100+
let deps = root.dependencies()
101+
.iter()
102+
.map(|d| d.source_id())
103+
.filter(|id| id.is_path())
104+
.filter_map(|id| id.url().to_file_path().ok())
105+
.map(|path| path.join("Cargo.toml"))
106+
.filter_map(|path| Package::for_path(&path, config).ok());
107+
for pkg in deps {
108+
let source_id = pkg.package_id().source_id();
109+
if map.insert(pkg.name().to_string(), source_id.clone()).is_none() {
110+
try!(build_path_deps(&pkg, map, config));
111+
}
112+
}
113+
114+
Ok(())
115+
}
116+
117+
fn to_package_id(name: &str,
118+
version: &str,
119+
source: Option<&SourceId>,
120+
default_source: &SourceId,
121+
path_sources: &HashMap<String, SourceId>)
122+
-> CargoResult<PackageId> {
123+
let source = source.or(path_sources.get(name)).unwrap_or(default_source);
124+
PackageId::new(name, version, source)
125+
}
126+
127+
81128
#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)]
82129
pub struct EncodableDependency {
83130
name: String,
@@ -86,15 +133,6 @@ pub struct EncodableDependency {
86133
dependencies: Option<Vec<EncodablePackageId>>
87134
}
88135

89-
impl EncodableDependency {
90-
fn to_package_id(&self, default_source: &SourceId) -> CargoResult<PackageId> {
91-
PackageId::new(
92-
&self.name,
93-
&self.version,
94-
self.source.as_ref().unwrap_or(default_source))
95-
}
96-
}
97-
98136
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
99137
pub struct EncodablePackageId {
100138
name: String,
@@ -134,15 +172,6 @@ impl Decodable for EncodablePackageId {
134172
}
135173
}
136174

137-
impl EncodablePackageId {
138-
fn to_package_id(&self, default_source: &SourceId) -> CargoResult<PackageId> {
139-
PackageId::new(
140-
&self.name,
141-
&self.version,
142-
self.source.as_ref().unwrap_or(default_source))
143-
}
144-
}
145-
146175
impl Encodable for Resolve {
147176
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
148177
let mut ids: Vec<&PackageId> = self.graph.iter().collect();
@@ -151,28 +180,26 @@ impl Encodable for Resolve {
151180
let encodable = ids.iter().filter_map(|&id| {
152181
if self.root == *id { return None; }
153182

154-
Some(encodable_resolve_node(id, &self.root, &self.graph))
183+
Some(encodable_resolve_node(id, &self.graph))
155184
}).collect::<Vec<EncodableDependency>>();
156185

157186
EncodableResolve {
158187
package: Some(encodable),
159-
root: encodable_resolve_node(&self.root, &self.root, &self.graph),
188+
root: encodable_resolve_node(&self.root, &self.graph),
160189
metadata: self.metadata.clone(),
161190
}.encode(s)
162191
}
163192
}
164193

165-
fn encodable_resolve_node(id: &PackageId, root: &PackageId,
166-
graph: &Graph<PackageId>) -> EncodableDependency {
194+
fn encodable_resolve_node(id: &PackageId, graph: &Graph<PackageId>)
195+
-> EncodableDependency {
167196
let deps = graph.edges(id).map(|edge| {
168-
let mut deps = edge.map(|e| {
169-
encodable_package_id(e, root)
170-
}).collect::<Vec<EncodablePackageId>>();
197+
let mut deps = edge.map(encodable_package_id).collect::<Vec<_>>();
171198
deps.sort();
172199
deps
173200
});
174201

175-
let source = if id.source_id() == root.source_id() {
202+
let source = if id.source_id().is_path() {
176203
None
177204
} else {
178205
Some(id.source_id().clone())
@@ -186,8 +213,8 @@ fn encodable_resolve_node(id: &PackageId, root: &PackageId,
186213
}
187214
}
188215

189-
fn encodable_package_id(id: &PackageId, root: &PackageId) -> EncodablePackageId {
190-
let source = if id.source_id() == root.source_id() {
216+
fn encodable_package_id(id: &PackageId) -> EncodablePackageId {
217+
let source = if id.source_id().is_path() {
191218
None
192219
} else {
193220
Some(id.source_id().with_precise(None))

src/cargo/ops/cargo_compile.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ pub fn resolve_dependencies<'a>(root_package: &Package,
113113

114114
// First, resolve the root_package's *listed* dependencies, as well as
115115
// downloading and updating all remotes and such.
116-
let resolve = try!(ops::resolve_pkg(&mut registry, root_package));
116+
let resolve = try!(ops::resolve_pkg(&mut registry, root_package, config));
117117

118118
// Second, resolve with precisely what we're doing. Filter out
119119
// transitive dependencies if necessary, specify features, handle

src/cargo/ops/cargo_fetch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub fn fetch<'a>(manifest_path: &Path,
1111
-> CargoResult<(Resolve, PackageSet<'a>)> {
1212
let package = try!(Package::for_path(manifest_path, config));
1313
let mut registry = PackageRegistry::new(config);
14-
let resolve = try!(ops::resolve_pkg(&mut registry, &package));
14+
let resolve = try!(ops::resolve_pkg(&mut registry, &package, config));
1515
let packages = get_resolved_packages(&resolve, registry);
1616
for id in resolve.iter() {
1717
try!(packages.get(id));

src/cargo/ops/cargo_generate_lockfile.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ pub fn update_lockfile(manifest_path: &Path,
3131
opts: &UpdateOptions) -> CargoResult<()> {
3232
let package = try!(Package::for_path(manifest_path, opts.config));
3333

34-
let previous_resolve = match try!(ops::load_pkg_lockfile(&package)) {
34+
let previous_resolve = match try!(ops::load_pkg_lockfile(&package,
35+
opts.config)) {
3536
Some(resolve) => resolve,
3637
None => bail!("a Cargo.lock must exist before it is updated")
3738
};

src/cargo/ops/cargo_pkgid.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ pub fn pkgid(manifest_path: &Path,
1010
let package = try!(Package::for_path(manifest_path, config));
1111

1212
let lockfile = package.root().join("Cargo.lock");
13-
let source_id = package.package_id().source_id();
14-
let resolve = match try!(ops::load_lockfile(&lockfile, source_id)) {
13+
let resolve = match try!(ops::load_lockfile(&lockfile, &package, config)) {
1514
Some(resolve) => resolve,
1615
None => bail!("a Cargo.lock must exist for this command"),
1716
};

src/cargo/ops/cargo_read_manifest.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use std::collections::{HashMap, HashSet};
2-
use std::fs::{self, File};
2+
use std::fs;
33
use std::io::prelude::*;
44
use std::io;
55
use std::path::{Path, PathBuf};
66

77
use core::{Package, Manifest, SourceId, PackageId};
8-
use util::{self, CargoResult, human, Config, ChainError};
8+
use util::{self, paths, CargoResult, human, Config, ChainError};
99
use util::important_paths::find_project_manifest_exact;
1010
use util::toml::{Layout, project_layout};
1111

@@ -22,13 +22,11 @@ pub fn read_manifest(contents: &[u8], layout: Layout, source_id: &SourceId,
2222
pub fn read_package(path: &Path, source_id: &SourceId, config: &Config)
2323
-> CargoResult<(Package, Vec<PathBuf>)> {
2424
trace!("read_package; path={}; source-id={}", path.display(), source_id);
25-
let mut file = try!(File::open(path));
26-
let mut data = Vec::new();
27-
try!(file.read_to_end(&mut data));
25+
let data = try!(paths::read(path));
2826

2927
let layout = project_layout(path.parent().unwrap());
3028
let (manifest, nested) =
31-
try!(read_manifest(&data, layout, source_id, config));
29+
try!(read_manifest(data.as_bytes(), layout, source_id, config));
3230

3331
Ok((Package::new(manifest, path), nested))
3432
}

src/cargo/ops/lockfile.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,20 @@ use std::path::Path;
55
use rustc_serialize::{Encodable, Decodable};
66
use toml::{self, Encoder, Value};
77

8-
use core::{Resolve, resolver, Package, SourceId};
9-
use util::{CargoResult, ChainError, human, paths};
8+
use core::{Resolve, resolver, Package};
9+
use util::{CargoResult, ChainError, human, paths, Config};
1010
use util::toml as cargo_toml;
1111

12-
pub fn load_pkg_lockfile(pkg: &Package) -> CargoResult<Option<Resolve>> {
12+
pub fn load_pkg_lockfile(pkg: &Package, config: &Config)
13+
-> CargoResult<Option<Resolve>> {
1314
let lockfile = pkg.root().join("Cargo.lock");
14-
let source_id = pkg.package_id().source_id();
15-
load_lockfile(&lockfile, source_id).chain_error(|| {
15+
load_lockfile(&lockfile, pkg, config).chain_error(|| {
1616
human(format!("failed to parse lock file at: {}", lockfile.display()))
1717
})
1818
}
1919

20-
pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
20+
pub fn load_lockfile(path: &Path, pkg: &Package, config: &Config)
21+
-> CargoResult<Option<Resolve>> {
2122
// If there is no lockfile, return none.
2223
let mut f = match File::open(path) {
2324
Ok(f) => f,
@@ -30,7 +31,7 @@ pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>
3031
let table = toml::Value::Table(try!(cargo_toml::parse(&s, path)));
3132
let mut d = toml::Decoder::new(table);
3233
let v: resolver::EncodableResolve = try!(Decodable::decode(&mut d));
33-
Ok(Some(try!(v.to_resolve(sid))))
34+
Ok(Some(try!(v.to_resolve(pkg, config))))
3435
}
3536

3637
pub fn write_pkg_lockfile(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {

src/cargo/ops/resolve.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,18 @@ use core::{Package, PackageId, SourceId};
44
use core::registry::PackageRegistry;
55
use core::resolver::{self, Resolve, Method};
66
use ops;
7-
use util::CargoResult;
7+
use util::{CargoResult, Config};
88

99
/// Resolve all dependencies for the specified `package` using the previous
1010
/// lockfile as a guide if present.
1111
///
1212
/// This function will also write the result of resolution as a new
1313
/// lockfile.
14-
pub fn resolve_pkg(registry: &mut PackageRegistry, package: &Package)
14+
pub fn resolve_pkg(registry: &mut PackageRegistry,
15+
package: &Package,
16+
config: &Config)
1517
-> CargoResult<Resolve> {
16-
let prev = try!(ops::load_pkg_lockfile(package));
18+
let prev = try!(ops::load_pkg_lockfile(package, config));
1719
let resolve = try!(resolve_with_previous(registry, package,
1820
Method::Everything,
1921
prev.as_ref(), None));

0 commit comments

Comments
 (0)