use regex::Regex;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
-use core::{PackageId, SourceId};
-use util::{CargoResult, Graph};
+use core::{Package, PackageId, SourceId};
+use util::{CargoResult, Graph, Config};
use super::Resolve;
pub type Metadata = BTreeMap<String, String>;
impl EncodableResolve {
- pub fn to_resolve(&self, default: &SourceId) -> CargoResult<Resolve> {
+ pub fn to_resolve(&self, root: &Package, config: &Config)
+ -> CargoResult<Resolve> {
+ let mut path_deps = HashMap::new();
+ try!(build_path_deps(root, &mut path_deps, config));
+ let default = root.package_id().source_id();
+
let mut g = Graph::new();
let mut tmp = HashMap::new();
let packages = Vec::new();
let packages = self.package.as_ref().unwrap_or(&packages);
+ let root = try!(to_package_id(&self.root.name,
+ &self.root.version,
+ self.root.source.as_ref(),
+ default, &path_deps));
+ let ids = try!(packages.iter().map(|p| {
+ to_package_id(&p.name, &p.version, p.source.as_ref(),
+ default, &path_deps)
+ }).collect::<CargoResult<Vec<_>>>());
+
{
- let mut register_pkg = |pkg: &EncodableDependency|
- -> CargoResult<()> {
- let pkgid = try!(pkg.to_package_id(default));
+ let mut register_pkg = |pkgid: &PackageId| {
let precise = pkgid.source_id().precise()
.map(|s| s.to_string());
assert!(tmp.insert(pkgid.clone(), precise).is_none(),
"a package was referenced twice in the lockfile");
- g.add(try!(pkg.to_package_id(default)), &[]);
- Ok(())
+ g.add(pkgid.clone(), &[]);
};
- try!(register_pkg(&self.root));
- for pkg in packages.iter() {
- try!(register_pkg(pkg));
+ register_pkg(&root);
+ for id in ids.iter() {
+ register_pkg(id);
}
}
{
- let mut add_dependencies = |pkg: &EncodableDependency|
+ let mut add_dependencies = |id: &PackageId, pkg: &EncodableDependency|
-> CargoResult<()> {
- let package_id = try!(pkg.to_package_id(default));
-
let deps = match pkg.dependencies {
Some(ref deps) => deps,
None => return Ok(()),
};
for edge in deps.iter() {
- let to_depend_on = try!(edge.to_package_id(default));
+ let to_depend_on = try!(to_package_id(&edge.name,
+ &edge.version,
+ edge.source.as_ref(),
+ default,
+ &path_deps));
let precise_pkgid =
tmp.get(&to_depend_on)
.map(|p| to_depend_on.with_precise(p.clone()))
.unwrap_or(to_depend_on.clone());
- g.link(package_id.clone(), precise_pkgid);
+ g.link(id.clone(), precise_pkgid);
}
Ok(())
};
- try!(add_dependencies(&self.root));
- for pkg in packages.iter() {
- try!(add_dependencies(pkg));
+ try!(add_dependencies(&root, &self.root));
+ for (id, pkg) in ids.iter().zip(packages) {
+ try!(add_dependencies(id, pkg));
}
}
Ok(Resolve {
graph: g,
- root: try!(self.root.to_package_id(default)),
+ root: root,
features: HashMap::new(),
metadata: self.metadata.clone(),
})
}
}
+fn build_path_deps(root: &Package,
+ map: &mut HashMap<String, SourceId>,
+ config: &Config)
+ -> CargoResult<()> {
+ assert!(root.package_id().source_id().is_path());
+
+ let deps = root.dependencies()
+ .iter()
+ .map(|d| d.source_id())
+ .filter(|id| id.is_path())
+ .filter_map(|id| id.url().to_file_path().ok())
+ .map(|path| path.join("Cargo.toml"))
+ .filter_map(|path| Package::for_path(&path, config).ok());
+ for pkg in deps {
+ let source_id = pkg.package_id().source_id();
+ if map.insert(pkg.name().to_string(), source_id.clone()).is_none() {
+ try!(build_path_deps(&pkg, map, config));
+ }
+ }
+
+ Ok(())
+}
+
+fn to_package_id(name: &str,
+ version: &str,
+ source: Option<&SourceId>,
+ default_source: &SourceId,
+ path_sources: &HashMap<String, SourceId>)
+ -> CargoResult<PackageId> {
+ let source = source.or(path_sources.get(name)).unwrap_or(default_source);
+ PackageId::new(name, version, source)
+}
+
+
#[derive(RustcEncodable, RustcDecodable, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct EncodableDependency {
name: String,
dependencies: Option<Vec<EncodablePackageId>>
}
-impl EncodableDependency {
- fn to_package_id(&self, default_source: &SourceId) -> CargoResult<PackageId> {
- PackageId::new(
- &self.name,
- &self.version,
- self.source.as_ref().unwrap_or(default_source))
- }
-}
-
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct EncodablePackageId {
name: String,
}
}
-impl EncodablePackageId {
- fn to_package_id(&self, default_source: &SourceId) -> CargoResult<PackageId> {
- PackageId::new(
- &self.name,
- &self.version,
- self.source.as_ref().unwrap_or(default_source))
- }
-}
-
impl Encodable for Resolve {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
let mut ids: Vec<&PackageId> = self.graph.iter().collect();
let encodable = ids.iter().filter_map(|&id| {
if self.root == *id { return None; }
- Some(encodable_resolve_node(id, &self.root, &self.graph))
+ Some(encodable_resolve_node(id, &self.graph))
}).collect::<Vec<EncodableDependency>>();
EncodableResolve {
package: Some(encodable),
- root: encodable_resolve_node(&self.root, &self.root, &self.graph),
+ root: encodable_resolve_node(&self.root, &self.graph),
metadata: self.metadata.clone(),
}.encode(s)
}
}
-fn encodable_resolve_node(id: &PackageId, root: &PackageId,
- graph: &Graph<PackageId>) -> EncodableDependency {
+fn encodable_resolve_node(id: &PackageId, graph: &Graph<PackageId>)
+ -> EncodableDependency {
let deps = graph.edges(id).map(|edge| {
- let mut deps = edge.map(|e| {
- encodable_package_id(e, root)
- }).collect::<Vec<EncodablePackageId>>();
+ let mut deps = edge.map(encodable_package_id).collect::<Vec<_>>();
deps.sort();
deps
});
- let source = if id.source_id() == root.source_id() {
+ let source = if id.source_id().is_path() {
None
} else {
Some(id.source_id().clone())
}
}
-fn encodable_package_id(id: &PackageId, root: &PackageId) -> EncodablePackageId {
- let source = if id.source_id() == root.source_id() {
+fn encodable_package_id(id: &PackageId) -> EncodablePackageId {
+ let source = if id.source_id().is_path() {
None
} else {
Some(id.source_id().with_precise(None))
use std::collections::{HashMap, HashSet};
-use std::fs::{self, File};
+use std::fs;
use std::io::prelude::*;
use std::io;
use std::path::{Path, PathBuf};
use core::{Package, Manifest, SourceId, PackageId};
-use util::{self, CargoResult, human, Config, ChainError};
+use util::{self, paths, CargoResult, human, Config, ChainError};
use util::important_paths::find_project_manifest_exact;
use util::toml::{Layout, project_layout};
pub fn read_package(path: &Path, source_id: &SourceId, config: &Config)
-> CargoResult<(Package, Vec<PathBuf>)> {
trace!("read_package; path={}; source-id={}", path.display(), source_id);
- let mut file = try!(File::open(path));
- let mut data = Vec::new();
- try!(file.read_to_end(&mut data));
+ let data = try!(paths::read(path));
let layout = project_layout(path.parent().unwrap());
let (manifest, nested) =
- try!(read_manifest(&data, layout, source_id, config));
+ try!(read_manifest(data.as_bytes(), layout, source_id, config));
Ok((Package::new(manifest, path), nested))
}
use rustc_serialize::{Encodable, Decodable};
use toml::{self, Encoder, Value};
-use core::{Resolve, resolver, Package, SourceId};
-use util::{CargoResult, ChainError, human, paths};
+use core::{Resolve, resolver, Package};
+use util::{CargoResult, ChainError, human, paths, Config};
use util::toml as cargo_toml;
-pub fn load_pkg_lockfile(pkg: &Package) -> CargoResult<Option<Resolve>> {
+pub fn load_pkg_lockfile(pkg: &Package, config: &Config)
+ -> CargoResult<Option<Resolve>> {
let lockfile = pkg.root().join("Cargo.lock");
- let source_id = pkg.package_id().source_id();
- load_lockfile(&lockfile, source_id).chain_error(|| {
+ load_lockfile(&lockfile, pkg, config).chain_error(|| {
human(format!("failed to parse lock file at: {}", lockfile.display()))
})
}
-pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
+pub fn load_lockfile(path: &Path, pkg: &Package, config: &Config)
+ -> CargoResult<Option<Resolve>> {
// If there is no lockfile, return none.
let mut f = match File::open(path) {
Ok(f) => f,
let table = toml::Value::Table(try!(cargo_toml::parse(&s, path)));
let mut d = toml::Decoder::new(table);
let v: resolver::EncodableResolve = try!(Decodable::decode(&mut d));
- Ok(Some(try!(v.to_resolve(sid))))
+ Ok(Some(try!(v.to_resolve(pkg, config))))
}
pub fn write_pkg_lockfile(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {