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<Dependency> {
+ pub fn parse(name: &str, version: &str, namespace: &SourceId) -> CargoResult<Dependency> {
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)
}
}
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)]
pub use self::source::{
Source,
- SourceSet
+ SourceId,
+ SourceSet,
+ GitKind,
+ PathKind,
+ RegistryKind
};
pub use self::summary::{
pub mod resolver;
pub mod summary;
pub mod shell;
-mod registry;
+pub mod registry;
mod version_req;
Summary
};
use core::dependency::SerializedDependency;
-use util::graph;
+use util::{CargoResult, graph};
use serialize::{Encoder,Encodable};
use core::source::SourceId;
}
}
- 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
}
#[deriving(PartialEq,Clone,Show)]
pub struct PackageSet {
- packages: Vec<Package>
+ packages: Vec<Package>,
}
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<Vec<Summary>> {
+ Ok(self.packages.iter()
+ .filter(|pkg| name.get_name() == pkg.get_name())
+ .map(|pkg| pkg.get_summary().clone())
+ .collect())
+ }
}
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<Vec<Summary>>;
}
impl Registry for Vec<Summary> {
- 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<Vec<Summary>> {
+ Ok(self.iter()
+ .filter(|summary| name.get_name() == summary.get_name())
+ .map(|summary| summary.clone())
+ .collect())
+ }
+}
+
+pub struct PackageRegistry {
+ sources: Vec<Box<Source>>,
+ overrides: Vec<Summary>,
+ summaries: Vec<Summary>,
+ searched: Vec<SourceId>
+}
+
+impl PackageRegistry {
+ pub fn new(sources: Vec<Box<Source>>, overrides: SourceSet) -> CargoResult<PackageRegistry> {
+ 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<Vec<Summary>> {
+ 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)
+ }
}
}
* - The correct input here is not a registry. Resolves should be performable
* on package summaries vs. the packages themselves.
*/
-pub fn resolve<R: Registry + Show>(deps: &[Dependency], registry: &R) -> CargoResult<Vec<PackageId>> {
+pub fn resolve<R: Registry + Show>(deps: &[Dependency], registry: &mut R) -> CargoResult<Vec<PackageId>> {
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::<String, Summary>::new();
loop {
let curr = match remaining.pop() {
}
};
- 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()) {
#[cfg(test)]
mod test {
+ use url;
+
use hamcrest::{
assert_that,
equal_to,
contains
};
+ use core::source::{
+ SourceId,
+ RegistryKind
+ };
+
use core::{
Dependency,
PackageId,
macro_rules! pkg(
($name:expr => $($deps:expr),+) => (
{
- let d: Vec<Dependency> = 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<Dependency> = 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())
}
);
}
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<Summary>) -> Vec<Summary> {
#[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"])));
}
fn get(&self, packages: &[PackageId]) -> CargoResult<Vec<Package>>;
}
-#[deriving(Clone,PartialEq)]
+#[deriving(Show,Clone,PartialEq)]
pub enum SourceKind {
- GitKind(String)
+ /// GitKind(<git reference>) 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
pub fn new(kind: SourceKind, url: Url) -> SourceId {
SourceId { kind: kind, url: url }
}
+
+ pub fn load(&self) -> Box<Source> {
+ match self.kind {
+ GitKind(ref reference) => unimplemented!(),
+ _ => unimplemented!()
+ }
+ }
}
pub struct SourceSet {
pub trait SummaryVec {
fn names(&self) -> Vec<String>;
- fn deps(&self) -> Vec<Dependency>;
}
impl SummaryVec for Vec<Summary> {
self.iter().map(|summary| summary.get_name().to_str()).collect()
}
- // TODO: Delete
- fn deps(&self) -> Vec<Dependency> {
- self.iter().map(|summary| Dependency::exact(summary.get_name(), summary.get_version())).collect()
- }
}
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;
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<SourceSet> {
- let mut sources = try!(sources_from_config([package.get_manifest_path().dir_path()]));
+fn sources_for(package: &Package) -> CargoResult<Vec<Box<Source>>> {
+ let mut sources = vec!(box PathSource::new(vec!(package.get_manifest_path().dir_path())) as Box<Source>);
let git_sources: Vec<Box<Source>> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| {
match source_id.kind {
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<Source>)
- }
+ },
+ ref PathKind => fail!("Cannot occur")
}
})));
sources.push_all_move(git_sources);
- Ok(SourceSet::new(sources))
+ Ok(sources)
}
-fn sources_from_config(additional: &[Path]) -> CargoResult<Vec<Box<Source>>> {
+fn sources_from_config() -> CargoResult<SourceSet> {
let configs = try!(config::all_configs(os::getcwd()));
debug!("loaded config; configs={}", configs);
&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<Source>))
+ Ok(SourceSet::new(vec!(box PathSource::new(paths) as Box<Source>)))
}
fn url_to_path_ident(url: &Url) -> String {
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};
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 => ()