From 9b278af150b66c995f8d865ea45e6478aa7db718 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Mon, 16 Jun 2014 18:16:34 -0700 Subject: [PATCH] WIP3 --- src/cargo/core/dependency.rs | 18 ++++++--- src/cargo/core/mod.rs | 8 +++- src/cargo/core/package.rs | 20 ++++------ src/cargo/core/registry.rs | 73 +++++++++++++++++++++++++++++----- src/cargo/core/resolver.rs | 45 ++++++++++++--------- src/cargo/core/source.rs | 18 +++++++-- src/cargo/core/summary.rs | 5 --- src/cargo/ops/cargo_compile.rs | 38 ++++++++++-------- src/cargo/util/toml.rs | 20 ++++++---- 9 files changed, 168 insertions(+), 77 deletions(-) diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index 836c962dd..ab1629819 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -1,31 +1,35 @@ use semver::Version; -use core::{VersionReq}; +use core::{VersionReq,SourceId}; use util::CargoResult; #[deriving(PartialEq,Clone,Show)] pub struct Dependency { name: String, + namespace: SourceId, req: VersionReq } impl Dependency { - pub fn new(name: &str, req: &VersionReq) -> Dependency { + pub fn new(name: &str, req: &VersionReq, namespace: &SourceId) -> Dependency { Dependency { name: name.to_str(), + namespace: namespace.clone(), req: req.clone() } } - pub fn parse(name: &str, version: &str) -> CargoResult { + pub fn parse(name: &str, version: &str, namespace: &SourceId) -> CargoResult { Ok(Dependency { name: name.to_str(), - req: try!(VersionReq::parse(version)) + namespace: namespace.clone(), + req: try!(VersionReq::parse(version)), }) } - pub fn exact(name: &str, version: &Version) -> Dependency { + pub fn exact(name: &str, version: &Version, namespace: &SourceId) -> Dependency { Dependency { name: name.to_str(), + namespace: namespace.clone(), req: VersionReq::exact(version) } } @@ -37,6 +41,10 @@ impl Dependency { pub fn get_name<'a>(&'a self) -> &'a str { self.name.as_slice() } + + pub fn get_namespace<'a>(&'a self) -> &'a SourceId { + &self.namespace + } } #[deriving(PartialEq,Clone,Encodable)] diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index 781d20087..9d041299e 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -19,7 +19,11 @@ pub use self::package_id::{ pub use self::source::{ Source, - SourceSet + SourceId, + SourceSet, + GitKind, + PathKind, + RegistryKind }; pub use self::summary::{ @@ -38,5 +42,5 @@ pub mod manifest; pub mod resolver; pub mod summary; pub mod shell; -mod registry; +pub mod registry; mod version_req; diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 6cd9562a1..da9c13eac 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -12,7 +12,7 @@ use core::{ Summary }; use core::dependency::SerializedDependency; -use util::graph; +use util::{CargoResult, graph}; use serialize::{Encoder,Encodable}; use core::source::SourceId; @@ -59,10 +59,6 @@ impl Package { } } - pub fn to_dependency(&self) -> Dependency { - Dependency::exact(self.manifest.get_name(), self.manifest.get_version()) - } - pub fn get_manifest<'a>(&'a self) -> &'a Manifest { &self.manifest } @@ -120,7 +116,7 @@ impl Show for Package { #[deriving(PartialEq,Clone,Show)] pub struct PackageSet { - packages: Vec + packages: Vec, } impl PackageSet { @@ -178,10 +174,10 @@ impl PackageSet { } impl Registry for PackageSet { - fn query<'a>(&'a self, name: &str) -> Vec<&'a Summary> { - self.packages.iter() - .filter(|pkg| name == pkg.get_name()) - .map(|pkg| pkg.get_summary()) - .collect() - } + fn query(&mut self, name: &Dependency) -> CargoResult> { + Ok(self.packages.iter() + .filter(|pkg| name.get_name() == pkg.get_name()) + .map(|pkg| pkg.get_summary().clone()) + .collect()) + } } diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs index 2aeeca19d..91b8ea525 100644 --- a/src/cargo/core/registry.rs +++ b/src/cargo/core/registry.rs @@ -1,17 +1,72 @@ use std::vec::Vec; - -use core::{ - Summary -}; +use core::{Source, SourceId, SourceSet, Summary, Dependency, PackageSet}; +use util::CargoResult; pub trait Registry { - fn query<'a>(&'a self, name: &str) -> Vec<&'a Summary>; + fn query(&mut self, name: &Dependency) -> CargoResult>; } impl Registry for Vec { - fn query<'a>(&'a self, name: &str) -> Vec<&'a Summary> { - self.iter() - .filter(|summary| name == summary.get_name()) - .collect() + fn query(&mut self, name: &Dependency) -> CargoResult> { + Ok(self.iter() + .filter(|summary| name.get_name() == summary.get_name()) + .map(|summary| summary.clone()) + .collect()) + } +} + +pub struct PackageRegistry { + sources: Vec>, + overrides: Vec, + summaries: Vec, + searched: Vec +} + +impl PackageRegistry { + pub fn new(sources: Vec>, overrides: SourceSet) -> CargoResult { + Ok(PackageRegistry { + sources: sources, + overrides: try!(overrides.list()), + summaries: vec!(), + searched: vec!() + }) + } + + fn ensure_loaded(&mut self, namespace: &SourceId) -> CargoResult<()> { + if self.searched.contains(namespace) { return Ok(()); } + self.load(namespace); + Ok(()) + } + + fn load(&mut self, namespace: &SourceId) -> CargoResult<()> { + let source = namespace.load(); + + // Ensure the source has fetched all necessary remote data. + try!(source.update()); + + // Get the summaries + for summary in (try!(source.list())).iter() { + assert!(!self.summaries.contains(summary), "duplicate summaries"); + self.summaries.push(summary.clone()); + } + + // Track that the source has been searched + self.searched.push(namespace.clone()); + + Ok(()) + } +} + +impl Registry for PackageRegistry { + fn query(&mut self, dep: &Dependency) -> CargoResult> { + let overrides = try!(self.overrides.query(dep)); + + if overrides.is_empty() { + // Ensure the requested namespace is loaded + try!(self.ensure_loaded(dep.get_namespace())); + self.summaries.query(dep) + } else { + Ok(overrides) + } } } diff --git a/src/cargo/core/resolver.rs b/src/cargo/core/resolver.rs index a67cbf1d1..882c7399f 100644 --- a/src/cargo/core/resolver.rs +++ b/src/cargo/core/resolver.rs @@ -12,11 +12,11 @@ use util::result::CargoResult; * - The correct input here is not a registry. Resolves should be performable * on package summaries vs. the packages themselves. */ -pub fn resolve(deps: &[Dependency], registry: &R) -> CargoResult> { +pub fn resolve(deps: &[Dependency], registry: &mut R) -> CargoResult> { log!(5, "resolve; deps={}; registry={}", deps, registry); let mut remaining = Vec::from_slice(deps); - let mut resolve = HashMap::<&str, &Summary>::new(); + let mut resolve = HashMap::::new(); loop { let curr = match remaining.pop() { @@ -28,14 +28,14 @@ pub fn resolve(deps: &[Dependency], registry: &R) -> CargoRe } }; - let opts = registry.query(curr.get_name()); + let opts = try!(registry.query(&curr)); assert!(opts.len() > 0, "no matches for {}", curr.get_name()); // Temporary, but we must have exactly one option to satisfy the dep assert!(opts.len() == 1, "invalid num of results {}", opts.len()); - let pkg = opts.get(0); - resolve.insert(pkg.get_name(), *pkg); + let pkg = opts.get(0).clone(); + resolve.insert(pkg.get_name().to_str(), pkg.clone()); for dep in pkg.get_dependencies().iter() { if !resolve.contains_key_equiv(&dep.get_name()) { @@ -47,12 +47,19 @@ pub fn resolve(deps: &[Dependency], registry: &R) -> CargoRe #[cfg(test)] mod test { + use url; + use hamcrest::{ assert_that, equal_to, contains }; + use core::source::{ + SourceId, + RegistryKind + }; + use core::{ Dependency, PackageId, @@ -66,7 +73,8 @@ mod test { macro_rules! pkg( ($name:expr => $($deps:expr),+) => ( { - let d: Vec = vec!($($deps),+).iter().map(|s| Dependency::parse(*s, "1.0.0").unwrap()).collect(); + let source_id = SourceId::new(RegistryKind, url::from_str("http://example.com").unwrap()); + let d: Vec = vec!($($deps),+).iter().map(|s| Dependency::parse(*s, "1.0.0", &source_id).unwrap()).collect(); Summary::new(&PackageId::new($name, "1.0.0", "http://www.example.com/"), d.as_slice()) } ); @@ -81,7 +89,8 @@ mod test { } fn dep(name: &str) -> Dependency { - Dependency::parse(name, "1.0.0").unwrap() + let source_id = SourceId::new(RegistryKind, url::from_str("http://example.com").unwrap()); + Dependency::parse(name, "1.0.0", &source_id).unwrap() } fn registry(pkgs: Vec) -> Vec { @@ -96,47 +105,47 @@ mod test { #[test] pub fn test_resolving_empty_dependency_list() { - let res = resolve([], ®istry(vec!())).unwrap(); + let res = resolve([], &mut registry(vec!())).unwrap(); assert_that(&res, equal_to(&names([]))); } #[test] pub fn test_resolving_only_package() { - let reg = registry(vec!(pkg("foo"))); - let res = resolve([dep("foo")], ®); + let mut reg = registry(vec!(pkg("foo"))); + let res = resolve([dep("foo")], &mut reg); assert_that(&res.unwrap(), equal_to(&names(["foo"]))); } #[test] pub fn test_resolving_one_dep() { - let reg = registry(vec!(pkg("foo"), pkg("bar"))); - let res = resolve([dep("foo")], ®); + let mut reg = registry(vec!(pkg("foo"), pkg("bar"))); + let res = resolve([dep("foo")], &mut reg); assert_that(&res.unwrap(), equal_to(&names(["foo"]))); } #[test] pub fn test_resolving_multiple_deps() { - let reg = registry(vec!(pkg!("foo"), pkg!("bar"), pkg!("baz"))); - let res = resolve([dep("foo"), dep("baz")], ®).unwrap(); + let mut reg = registry(vec!(pkg!("foo"), pkg!("bar"), pkg!("baz"))); + let res = resolve([dep("foo"), dep("baz")], &mut reg).unwrap(); assert_that(&res, contains(names(["foo", "baz"])).exactly()); } #[test] pub fn test_resolving_transitive_deps() { - let reg = registry(vec!(pkg!("foo"), pkg!("bar" => "foo"))); - let res = resolve([dep("bar")], ®).unwrap(); + let mut reg = registry(vec!(pkg!("foo"), pkg!("bar" => "foo"))); + let res = resolve([dep("bar")], &mut reg).unwrap(); assert_that(&res, contains(names(["foo", "bar"]))); } #[test] pub fn test_resolving_common_transitive_deps() { - let reg = registry(vec!(pkg!("foo" => "bar"), pkg!("bar"))); - let res = resolve([dep("foo"), dep("bar")], ®).unwrap(); + let mut reg = registry(vec!(pkg!("foo" => "bar"), pkg!("bar"))); + let res = resolve([dep("foo"), dep("bar")], &mut reg).unwrap(); assert_that(&res, contains(names(["foo", "bar"]))); } diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index 132f764e6..2188b316a 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -37,12 +37,17 @@ pub trait Source { fn get(&self, packages: &[PackageId]) -> CargoResult>; } -#[deriving(Clone,PartialEq)] +#[deriving(Show,Clone,PartialEq)] pub enum SourceKind { - GitKind(String) + /// GitKind() represents a git repository + GitKind(String), + /// represents a local path + PathKind, + /// represents the central registry + RegistryKind } -#[deriving(Clone,PartialEq)] +#[deriving(Show,Clone,PartialEq)] pub struct SourceId { pub kind: SourceKind, pub url: Url @@ -52,6 +57,13 @@ impl SourceId { pub fn new(kind: SourceKind, url: Url) -> SourceId { SourceId { kind: kind, url: url } } + + pub fn load(&self) -> Box { + match self.kind { + GitKind(ref reference) => unimplemented!(), + _ => unimplemented!() + } + } } pub struct SourceSet { diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index 0b3dfede7..928e57f66 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -37,7 +37,6 @@ impl Summary { pub trait SummaryVec { fn names(&self) -> Vec; - fn deps(&self) -> Vec; } impl SummaryVec for Vec { @@ -46,8 +45,4 @@ impl SummaryVec for Vec { self.iter().map(|summary| summary.get_name().to_str()).collect() } - // TODO: Delete - fn deps(&self) -> Vec { - self.iter().map(|summary| Dependency::exact(summary.get_name(), summary.get_version())).collect() - } } diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 2353989c3..67b4e7cbb 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -26,6 +26,7 @@ use util::config::{ConfigValue}; use core::{Package,PackageSet,Source,SourceSet}; use core::resolver::resolve; use core::source::{GitKind,SourceId}; +use core::registry::PackageRegistry; use sources::{PathSource,GitSource}; use sources::git::GitRemote; use ops; @@ -38,27 +39,33 @@ pub fn compile(manifest_path: &Path) -> CargoResult<()> { let package = try!(PathSource::read_package(manifest_path)); debug!("loaded package; package={}", package); + let overrides = try!(sources_from_config()); let sources = try!(sources_for(&package)); - try!(sources.update().wrap("unable to update sources")); - let summaries = try!(sources.list().wrap("unable to list packages from source")); - let resolved = try!(resolve(package.get_dependencies(), &summaries).wrap("unable to resolve dependencies")); + let registry = PackageRegistry::new(sources, overrides); - try!(sources.download(resolved.as_slice()).wrap("unable to download packages")); + //try!(sources.update().wrap("unable to update sources")); + //let summaries = try!(sources.list().wrap("unable to list packages from source")); - let packages = try!(sources.get(resolved.as_slice()).wrap("unable to get packages from source")); + //let registry = PackageRegistry::new(&summaries, &overrides); - log!(5, "fetch packages from source; packages={}; ids={}", packages, resolved); + //let resolved = try!(resolve(package.get_dependencies(), &summaries).wrap("unable to resolve dependencies")); - let package_set = PackageSet::new(packages.as_slice()); + //try!(sources.download(resolved.as_slice()).wrap("unable to download packages")); - try!(ops::compile_packages(&package, &package_set)); + //let packages = try!(sources.get(resolved.as_slice()).wrap("unable to get packages from source")); + + //log!(5, "fetch packages from source; packages={}; ids={}", packages, resolved); + + //let package_set = PackageSet::new(packages.as_slice()); + + //try!(ops::compile_packages(&package, &package_set)); Ok(()) } -fn sources_for(package: &Package) -> CargoResult { - let mut sources = try!(sources_from_config([package.get_manifest_path().dir_path()])); +fn sources_for(package: &Package) -> CargoResult>> { + let mut sources = vec!(box PathSource::new(vec!(package.get_manifest_path().dir_path())) as Box); let git_sources: Vec> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| { match source_id.kind { @@ -73,16 +80,17 @@ fn sources_for(package: &Package) -> CargoResult { let db_path = git.join("db").join(ident.as_slice()); let checkout_path = git.join("checkouts").join(ident.as_slice()).join(reference.as_slice()); Ok(box GitSource::new(remote, reference.clone(), db_path, checkout_path) as Box) - } + }, + ref PathKind => fail!("Cannot occur") } }))); sources.push_all_move(git_sources); - Ok(SourceSet::new(sources)) + Ok(sources) } -fn sources_from_config(additional: &[Path]) -> CargoResult>> { +fn sources_from_config() -> CargoResult { let configs = try!(config::all_configs(os::getcwd())); debug!("loaded config; configs={}", configs); @@ -94,9 +102,7 @@ fn sources_from_config(additional: &[Path]) -> CargoResult>> { &config::List(ref list) => list.iter().map(|path| Path::new(path.as_slice())).collect() }; - paths.push_all(additional); - - Ok(vec!(box PathSource::new(paths) as Box)) + Ok(SourceSet::new(vec!(box PathSource::new(paths) as Box))) } fn url_to_path_ident(url: &Url) -> String { diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 57f1f67b1..a5fae1fb2 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -4,7 +4,7 @@ use url::Url; use std::collections::HashMap; use serialize::Decodable; -use core::source::{SourceId,GitKind}; +use core::{SourceId,GitKind,RegistryKind}; use core::manifest::{LibKind,Lib}; use core::{Summary,Manifest,Target,Dependency,PackageId}; use util::{CargoResult,Require,simple_human,toml_error}; @@ -130,20 +130,26 @@ impl TomlManifest { match self.dependencies { Some(ref dependencies) => { for (n, v) in dependencies.iter() { - let version = match *v { - SimpleDep(ref string) => string.clone(), + let (version, source_id) = match *v { + SimpleDep(ref string) => { + let source_id = SourceId::new(RegistryKind, url::from_str("http://example.com").unwrap()); + (string.clone(), source_id) + }, DetailedDep(ref details) => { - details.other.find_equiv(&"git").map(|git| { + let source_id = details.other.find_equiv(&"git").map(|git| { // TODO: Don't unwrap here let kind = GitKind("master".to_str()); let url = url::from_str(git.as_slice()).unwrap(); - sources.push(SourceId::new(kind, url)); + let source_id = SourceId::new(kind, url); + sources.push(source_id.clone()); + source_id }); - details.version.clone() + + (details.version.clone(), try!(source_id.require(simple_human("Dependencies must supply a git location")))) } }; - deps.push(try!(Dependency::parse(n.as_slice(), version.as_slice()))) + deps.push(try!(Dependency::parse(n.as_slice(), version.as_slice(), &source_id))) } } None => () -- 2.30.2