Improvements to transitive dependency infra
authorYehuda Katz + Carl Lerche <engineering@tilde.io>
Tue, 17 Jun 2014 22:36:50 +0000 (15:36 -0700)
committerTim Carey-Smith <tim@spork.in>
Tue, 17 Jun 2014 22:36:50 +0000 (15:36 -0700)
Initial work to enable cross-source transitive dependencies.

17 files changed:
Makefile
src/bin/cargo-compile.rs
src/bin/cargo-git-checkout.rs
src/bin/cargo.rs
src/cargo/core/manifest.rs
src/cargo/core/package.rs
src/cargo/core/registry.rs
src/cargo/core/resolver.rs
src/cargo/core/source.rs
src/cargo/core/summary.rs
src/cargo/ops/cargo_compile.rs
src/cargo/sources/git/source.rs
src/cargo/sources/git/utils.rs
src/cargo/sources/path.rs
src/cargo/util/config.rs
src/cargo/util/mod.rs
src/cargo/util/toml.rs

index edb5b69095f340e24bab3398e3ef5ce0b592b246..256ef9cf923276e2056f903eac43a90f18d98097 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ BINS = cargo \
             cargo-verify-project \
             cargo-git-checkout \
 
-SRC = $(shell find src -name '*.rs')
+SRC = $(shell find src -name '*.rs' -not -path 'src/bin*')
 
 DEPS = -L libs/hammer.rs/target -L libs/rust-toml/lib
 TOML = libs/rust-toml/lib/$(shell rustc --crate-file-name libs/rust-toml/src/toml/lib.rs)
index fd741c691c7d5e42c5c8d1626bcf3c5bd687c7c3..1c02203835424d4a4decd0d76b38d13bf0292716 100644 (file)
@@ -13,7 +13,7 @@ use hammer::FlagConfig;
 use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
 use cargo::ops;
 use cargo::util::important_paths::find_project;
-use cargo::util::{ToCLI,simple_human};
+use cargo::util::{ToCLI};
 
 #[deriving(PartialEq,Clone,Decodable,Encodable)]
 pub struct Options {
index 3b0bc57551f6dc22b960fbe5e42af2f971fbabd3..3a400a9147489fc710b2edf212f0d2a4f0ee2e84 100644 (file)
@@ -8,13 +8,12 @@ extern crate url;
 use hammer::FlagConfig;
 use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult};
 use cargo::core::source::Source;
-use cargo::sources::git::{GitSource,GitRemote};
+use cargo::sources::git::{GitSource};
+use cargo::util::{Config,ToCLI};
 use url::Url;
 
 #[deriving(PartialEq,Clone,Decodable)]
 struct Options {
-    database_path: String,
-    checkout_path: String,
     url: String,
     reference: String,
     verbose: bool
@@ -27,13 +26,13 @@ fn main() {
 }
 
 fn execute(options: Options) -> CLIResult<Option<()>> {
-    let Options { database_path, checkout_path, url, reference, verbose } = options;
+    let Options { url, reference, .. } = options;
 
     let url: Url = try!(from_str(url.as_slice()).to_result(|_|
         CLIError::new(format!("The URL `{}` you passed was not a valid URL", url), None::<&str>, 1)));
 
-    let remote = GitRemote::new(url, verbose);
-    let source = GitSource::new(remote, reference, Path::new(database_path), Path::new(checkout_path));
+    let source = GitSource::new(&url, reference.as_slice(), &try!(Config::new().to_cli(1)));
+
     try!(source.update().map_err(|e| {
         CLIError::new(format!("Couldn't update {}: {}", source, e), None::<&str>, 1)
     }));
index 8646a6adb4f00fdbc0a30f2b228f1414cbe1d898..5293000e4ce676f7cc103d4dfb7efa343fb72fe4 100644 (file)
@@ -14,7 +14,7 @@ use serialize::Encodable;
 use cargo::{NoFlags,execute_main_without_stdin,handle_error};
 use cargo::core::errors::{CLIError,CLIResult,ToResult};
 use cargo::util::important_paths::find_project;
-use cargo::util::{ToCLI,Wrap,config,io_error,simple_human};
+use cargo::util::{ToCLI,config,simple_human};
 
 fn main() {
     execute();
index 6b9d1b57b1b17e45354e03c4a6d8145a81fbfbd8..b8d8b48ec3485176bc4d0e7e7e8fcc6e4562bce5 100644 (file)
@@ -167,7 +167,7 @@ impl Manifest {
         &self.target_dir
     }
 
-    pub fn get_sources<'a>(&'a self) -> &'a [SourceId] {
+    pub fn get_source_ids<'a>(&'a self) -> &'a [SourceId] {
         self.sources.as_slice()
     }
 }
index da9c13eac71f988e93b0d83ac5382bfe6b7978dc..86f816c98eeeb57044f09e5e7b1ec73ed53258c1 100644 (file)
@@ -103,8 +103,10 @@ impl Package {
         self.get_root().join(self.get_target_dir())
     }
 
-    pub fn get_sources<'a>(&'a self) -> &'a [SourceId] {
-        self.manifest.get_sources()
+    pub fn get_source_ids(&self) -> Vec<SourceId> {
+        let mut ret = vec!(SourceId::for_path(&self.get_root()));
+        ret.push_all(self.manifest.get_source_ids());
+        ret
     }
 }
 
index 91b8ea5259f6947d3525185a55f210beda2bf3ad..508c121bf4149228ac2af977318bed5979d2ab1e 100644 (file)
@@ -1,6 +1,6 @@
 use std::vec::Vec;
-use core::{Source, SourceId, SourceSet, Summary, Dependency, PackageSet};
-use util::CargoResult;
+use core::{Source, SourceId, Summary, Dependency, PackageId, Package};
+use util::{CargoResult,Config};
 
 pub trait Registry {
     fn query(&mut self, name: &Dependency) -> CargoResult<Vec<Summary>>;
@@ -23,33 +23,71 @@ pub struct PackageRegistry {
 }
 
 impl PackageRegistry {
-    pub fn new(sources: Vec<Box<Source>>, overrides: SourceSet) -> CargoResult<PackageRegistry> {
-        Ok(PackageRegistry {
-            sources: sources,
-            overrides: try!(overrides.list()),
+    pub fn new(source_ids: Vec<SourceId>, override_ids: Vec<SourceId>) -> CargoResult<PackageRegistry> {
+        let mut reg = PackageRegistry::empty();
+
+        for id in source_ids.iter() {
+            try!(reg.load(id, false));
+        }
+
+        for id in override_ids.iter() {
+            try!(reg.load(id, true));
+        }
+
+        Ok(reg)
+    }
+
+    fn empty() -> PackageRegistry {
+        PackageRegistry {
+            sources: vec!(),
+            overrides: vec!(),
             summaries: vec!(),
             searched: vec!()
-        })
+        }
+    }
+
+    pub fn get(&self, package_ids: &[PackageId]) -> CargoResult<Vec<Package>> {
+        log!(5, "getting packags; sources={}; ids={}", self.sources.len(), package_ids);
+
+        // TODO: Only call source with package ID if the package came from the source
+        let mut ret = Vec::new();
+
+        for source in self.sources.iter() {
+            try!(source.download(package_ids));
+            let packages = try!(source.get(package_ids));
+
+            ret.push_all_move(packages);
+        }
+
+        // TODO: Return earlier if fail
+        assert!(package_ids.len() == ret.len(), "could not get packages from registry; ids={}", package_ids);
+
+        Ok(ret)
     }
 
     fn ensure_loaded(&mut self, namespace: &SourceId) -> CargoResult<()> {
         if self.searched.contains(namespace) { return Ok(()); }
-        self.load(namespace);
+        try!(self.load(namespace, false));
         Ok(())
     }
 
-    fn load(&mut self, namespace: &SourceId) -> CargoResult<()> {
-        let source = namespace.load();
+    fn load(&mut self, namespace: &SourceId, override: bool) -> CargoResult<()> {
+        let source = namespace.load(&try!(Config::new()));
+        let dst = if override { &mut self.overrides } else { &mut self.summaries };
 
         // 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());
+            assert!(!dst.contains(summary), "duplicate summaries");
+            dst.push(summary.clone());
+            // self.summaries.push(summary.clone());
         }
 
+        // Save off the source
+        self.sources.push(source);
+
         // Track that the source has been searched
         self.searched.push(namespace.clone());
 
index 882c7399fa6749110754996cd2284b9dadebdc9c..23eac0b6bb2cf7c7b50990695056acb69f36d029 100644 (file)
@@ -1,4 +1,3 @@
-use std::fmt::Show;
 use std::collections::HashMap;
 use core::{
     Dependency,
@@ -12,8 +11,8 @@ 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<R: Registry + Show>(deps: &[Dependency], registry: &mut R) -> CargoResult<Vec<PackageId>> {
-    log!(5, "resolve; deps={}; registry={}", deps, registry);
+pub fn resolve<R: Registry>(deps: &[Dependency], registry: &mut R) -> CargoResult<Vec<PackageId>> {
+    log!(5, "resolve; deps={}", deps);
 
     let mut remaining = Vec::from_slice(deps);
     let mut resolve = HashMap::<String, Summary>::new();
index 2188b316ae05d04bf7468b8f0fbe5e9c2875b4bf..d093ffc065200766c8fd833f6a25f188e5161585 100644 (file)
@@ -1,6 +1,8 @@
+use url;
 use url::Url;
 use core::{Summary,Package,PackageId};
-use util::CargoResult;
+use sources::{PathSource,GitSource};
+use util::{Config,CargoResult};
 
 /**
  * A Source finds and downloads remote packages based on names and
@@ -58,10 +60,43 @@ impl SourceId {
         SourceId { kind: kind, url: url }
     }
 
-    pub fn load(&self) -> Box<Source> {
+    // Pass absolute path
+    pub fn for_path(path: &Path) -> SourceId {
+        // TODO: use proper path -> URL
+        SourceId::new(PathKind, url::from_str(format!("file://{}", path.display()).as_slice()).unwrap())
+    }
+
+    pub fn for_central() -> SourceId {
+        SourceId::new(RegistryKind, url::from_str(format!("https://example.com").as_slice()).unwrap())
+    }
+
+    /*
+    let git_sources: Vec<Box<Source>> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| {
+        match source_id.kind {
+            GitKind(ref reference) => {
+                let remote = GitRemote::new(source_id.url.clone(), false);
+                let home = try!(os::homedir().require(simple_human("Cargo couldn't find a home directory")));
+                let git = home.join(".cargo").join("git");
+                let ident = url_to_path_ident(&source_id.url);
+
+                // .cargo/git/db
+                // .cargo/git/checkouts
+                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")
+        }
+    })));
+     */
+
+    pub fn load(&self, config: &Config) -> Box<Source> {
         match self.kind {
-            GitKind(ref reference) => unimplemented!(),
-            _ => unimplemented!()
+            GitKind(ref reference) => {
+                box GitSource::new(&self.url, reference.as_slice(), config) as Box<Source>
+            },
+            PathKind => box PathSource::new(&Path::new(self.url.path.as_slice())) as Box<Source>,
+            RegistryKind => unimplemented!()
         }
     }
 }
index 928e57f66023f69f0f6969561de2df4502f6b94f..7ab20b8e7e9d3091d1cf6e868c309cd74b6ebb6f 100644 (file)
@@ -4,6 +4,10 @@ use core::{
     PackageId
 };
 
+/**
+ * Summaries are cloned, and should not be mutated after creation
+ */
+
 #[deriving(Show,Clone,PartialEq)]
 pub struct Summary {
     package_id: PackageId,
index 67b4e7cbba7985d22d8434679f71d4871d3cda55..b78de842f9103a9d71423efb6ee89e5d17e834eb 100644 (file)
  *    b. Compile each dependency in order, passing in the -L's pointing at each previously compiled dependency
  */
 
-use std::io::MemWriter;
 use std::os;
-use std::result;
-use std::hash::sip::SipHasher;
-use std::hash::Hasher;
-use serialize::hex::ToHex;
-use url::Url;
-use util::config;
 use util::config::{ConfigValue};
-use core::{Package,PackageSet,Source,SourceSet};
-use core::resolver::resolve;
-use core::source::{GitKind,SourceId};
+use core::{SourceId,PackageSet,resolver};
 use core::registry::PackageRegistry;
-use sources::{PathSource,GitSource};
-use sources::git::GitRemote;
 use ops;
-use util::{CargoResult, Wrap, Require, simple_human, other_error};
+use sources::{PathSource};
+use util::{CargoResult,Wrap,config,other_error};
 
 pub fn compile(manifest_path: &Path) -> CargoResult<()> {
     log!(4, "compile; manifest-path={}", manifest_path.display());
@@ -39,112 +29,32 @@ 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));
+    let override_ids = try!(source_ids_from_config());
+    let source_ids = package.get_source_ids();
 
-    let registry = PackageRegistry::new(sources, overrides);
+    let mut registry = try!(PackageRegistry::new(source_ids, override_ids));
+    let resolved = try!(resolver::resolve(package.get_dependencies(), &mut registry).wrap("unable to resolve dependencies"));
 
-    //try!(sources.update().wrap("unable to update sources"));
-    //let summaries = try!(sources.list().wrap("unable to list packages from source"));
+    let packages = try!(registry.get(resolved.as_slice()).wrap("unable to get packages from source"));
 
-    //let registry = PackageRegistry::new(&summaries, &overrides);
+    debug!("packages={}", packages);
 
-    //let resolved = try!(resolve(package.get_dependencies(), &summaries).wrap("unable to resolve dependencies"));
-
-    //try!(sources.download(resolved.as_slice()).wrap("unable to download packages"));
-
-    //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));
+    try!(ops::compile_packages(&package, &PackageSet::new(packages.as_slice())));
 
     Ok(())
 }
 
-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 {
-            GitKind(ref reference) => {
-                let remote = GitRemote::new(source_id.url.clone(), false);
-                let home = try!(os::homedir().require(simple_human("Cargo couldn't find a home directory")));
-                let git = home.join(".cargo").join("git");
-                let ident = url_to_path_ident(&source_id.url);
-
-                // .cargo/git/db
-                // .cargo/git/checkouts
-                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(sources)
-}
-
-fn sources_from_config() -> CargoResult<SourceSet> {
+fn source_ids_from_config() -> CargoResult<Vec<SourceId>> {
     let configs = try!(config::all_configs(os::getcwd()));
 
     debug!("loaded config; configs={}", configs);
 
     let config_paths = configs.find_equiv(&"paths").map(|v| v.clone()).unwrap_or_else(|| ConfigValue::new());
 
-    let mut paths: Vec<Path> = match config_paths.get_value() {
+    let paths: Vec<Path> = match config_paths.get_value() {
         &config::String(_) => return Err(other_error("The path was configured as a String instead of a List")),
         &config::List(ref list) => list.iter().map(|path| Path::new(path.as_slice())).collect()
     };
 
-    Ok(SourceSet::new(vec!(box PathSource::new(paths) as Box<Source>)))
-}
-
-fn url_to_path_ident(url: &Url) -> String {
-    let hasher = SipHasher::new_with_keys(0,0);
-
-    let mut ident = url.path.as_slice().split('/').last().unwrap();
-
-    ident = if ident == "" {
-        "_empty"
-    } else {
-        ident
-    };
-
-    format!("{}-{}", ident, to_hex(hasher.hash(&url.to_str())))
-}
-
-fn to_hex(num: u64) -> String {
-    let mut writer = MemWriter::with_capacity(8);
-    writer.write_le_u64(num).unwrap(); // this should never fail
-    writer.get_ref().to_hex()
-}
-
-#[cfg(test)]
-mod test {
-    use url;
-    use url::Url;
-    use super::url_to_path_ident;
-
-    #[test]
-    pub fn test_url_to_path_ident_with_path() {
-        let ident = url_to_path_ident(&url("https://github.com/carlhuda/cargo"));
-        assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
-    }
-
-    #[test]
-    pub fn test_url_to_path_ident_without_path() {
-        let ident = url_to_path_ident(&url("https://github.com"));
-        assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
-    }
-
-
-    fn url(s: &str) -> Url {
-        url::from_str(s).unwrap()
-    }
+    Ok(paths.iter().map(|p| SourceId::for_path(p)).collect())
 }
index 12c68af8bc865f78e09856f1fac9e6dcdb96146a..991dc71eacdb4e1903dd551cd4ca884fdfa1d9d6 100644 (file)
@@ -1,11 +1,17 @@
-use ops;
+use std::fmt;
+use std::hash::sip::SipHasher;
+use std::hash::Hasher;
+use std::fmt::{Show,Formatter};
+use std::io::MemWriter;
+use serialize::hex::ToHex;
 use url;
+use url::Url;
+
+use ops;
 use core::source::Source;
 use core::{Package,PackageId,Summary};
-use util::CargoResult;
+use util::{CargoResult,Config};
 use sources::git::utils::{GitReference,GitRemote,Master,Other};
-use std::fmt;
-use std::fmt::{Show,Formatter};
 
 pub struct GitSource {
     remote: GitRemote,
@@ -15,13 +21,48 @@ pub struct GitSource {
 }
 
 impl GitSource {
-    pub fn new(remote: GitRemote, reference: String, db: Path, checkout: Path) -> GitSource {
-        GitSource { remote: remote, reference: GitReference::for_str(reference), db_path: db, checkout_path: checkout }
+    pub fn new(url: &Url, reference: &str, config: &Config) -> GitSource {
+        let remote = GitRemote::new(url);
+        let ident = ident(url);
+
+        let db_path = config.git_db_path()
+            .join(ident.as_slice());
+
+        let checkout_path = config.git_checkout_path()
+            .join(ident.as_slice()).join(reference);
+
+        GitSource {
+            remote: remote,
+            reference: GitReference::for_str(reference),
+            db_path: db_path,
+            checkout_path: checkout_path
+        }
     }
 
     pub fn get_namespace<'a>(&'a self) -> &'a url::Url {
         self.remote.get_url()
     }
+
+}
+
+fn ident(url: &Url) -> String {
+    let hasher = SipHasher::new_with_keys(0,0);
+
+    let mut ident = url.path.as_slice().split('/').last().unwrap();
+
+    ident = if ident == "" {
+        "_empty"
+    } else {
+        ident
+    };
+
+    format!("{}-{}", ident, to_hex(hasher.hash(&url.to_str())))
+}
+
+fn to_hex(num: u64) -> String {
+    let mut writer = MemWriter::with_capacity(8);
+    writer.write_le_u64(num).unwrap(); // this should never fail
+    writer.get_ref().to_hex()
 }
 
 impl Show for GitSource {
@@ -72,3 +113,27 @@ fn read_manifest(path: &Path, url: &url::Url) -> CargoResult<Package> {
     let path = path.join("Cargo.toml");
     ops::read_package(&path, url)
 }
+
+#[cfg(test)]
+mod test {
+    use url;
+    use url::Url;
+    use super::ident;
+
+    #[test]
+    pub fn test_url_to_path_ident_with_path() {
+        let ident = ident(&url("https://github.com/carlhuda/cargo"));
+        assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
+    }
+
+    #[test]
+    pub fn test_url_to_path_ident_without_path() {
+        let ident = ident(&url("https://github.com"));
+        assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
+    }
+
+
+    fn url(s: &str) -> Url {
+        url::from_str(s).unwrap()
+    }
+}
index 4118364cd25153f48460facdbcfde817c1590798..8cccdb5845e4d504786189041d7a2dd28469ccea 100644 (file)
@@ -40,22 +40,22 @@ impl Show for GitReference {
 
 
 macro_rules! git(
-    ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
-        try!(git_inherit(&$config, $verbose, format!($str, $($rest),*)))
+    ($config:expr, $str:expr, $($rest:expr),*) => (
+        try!(git_inherit(&$config, format!($str, $($rest),*)))
     );
 
-    ($config:expr, $verbose:expr, $str:expr) => (
-        try!(git_inherit(&$config, $verbose, format!($str)))
+    ($config:expr, $str:expr) => (
+        try!(git_inherit(&$config, format!($str)))
     );
 )
 
 macro_rules! git_output(
-    ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
-        try!(git_output(&$config, $verbose, format!($str, $($rest),*)))
+    ($config:expr, $str:expr, $($rest:expr),*) => (
+        try!(git_output(&$config, format!($str, $($rest),*)))
     );
 
-    ($config:expr, $verbose:expr, $str:expr) => (
-        try!(git_output(&$config, $verbose, format!($str)))
+    ($config:expr, $str:expr) => (
+        try!(git_output(&$config, format!($str)))
     );
 )
 
@@ -70,7 +70,6 @@ macro_rules! errln(
 #[deriving(PartialEq,Clone,Show)]
 pub struct GitRemote {
     url: Url,
-    verbose: bool
 }
 
 #[deriving(PartialEq,Clone,Encodable)]
@@ -95,7 +94,6 @@ impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
 pub struct GitDatabase {
     remote: GitRemote,
     path: Path,
-    verbose: bool
 }
 
 #[deriving(Encodable)]
@@ -124,7 +122,6 @@ pub struct GitCheckout {
     location: Path,
     reference: GitReference,
     revision: String,
-    verbose: bool
 }
 
 #[deriving(Encodable)]
@@ -151,8 +148,8 @@ impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
  */
 
 impl GitRemote {
-    pub fn new(url: Url, verbose: bool) -> GitRemote {
-        GitRemote { url: url, verbose: verbose }
+    pub fn new(url: &Url) -> GitRemote {
+        GitRemote { url: url.clone() }
     }
 
     pub fn get_url<'a>(&'a self) -> &'a Url {
@@ -166,11 +163,11 @@ impl GitRemote {
             try!(self.clone_into(into));
         }
 
-        Ok(GitDatabase { remote: self.clone(), path: into.clone(), verbose: self.verbose })
+        Ok(GitDatabase { remote: self.clone(), path: into.clone() })
     }
 
     fn fetch_into(&self, path: &Path) -> CargoResult<()> {
-        Ok(git!(*path, self.verbose, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.fetch_location()))
+        Ok(git!(*path, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.fetch_location()))
     }
 
     fn clone_into(&self, path: &Path) -> CargoResult<()> {
@@ -179,7 +176,7 @@ impl GitRemote {
         try!(mkdir_recursive(path, UserDir).map_err(|err|
             human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err))));
 
-        Ok(git!(dirname, self.verbose, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display()))
+        Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet", self.fetch_location(), path.display()))
     }
 
     fn fetch_location(&self) -> String {
@@ -196,8 +193,7 @@ impl GitDatabase {
     }
 
     pub fn copy_to<S: Str>(&self, reference: S, dest: &Path) -> CargoResult<GitCheckout> {
-        let verbose = self.verbose;
-        let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()), verbose));
+        let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice())));
 
         try!(checkout.fetch());
         try!(checkout.update_submodules());
@@ -206,15 +202,15 @@ impl GitDatabase {
     }
 
     pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<String> {
-        Ok(git_output!(self.path, self.verbose, "rev-parse {}", reference.as_slice()))
+        Ok(git_output!(self.path, "rev-parse {}", reference.as_slice()))
     }
 
 }
 
 impl GitCheckout {
-    fn clone_into(into: &Path, database: GitDatabase, reference: GitReference, verbose: bool) -> CargoResult<GitCheckout> {
+    fn clone_into(into: &Path, database: GitDatabase, reference: GitReference) -> CargoResult<GitCheckout> {
         let revision = try!(database.rev_for(reference.as_slice()));
-        let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision, verbose: verbose };
+        let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision };
 
         // If the git checkout already exists, we don't need to clone it again
         if !checkout.location.join(".git").exists() {
@@ -239,40 +235,40 @@ impl GitCheckout {
                 human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e))));
         }
 
-        git!(dirname, self.verbose, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display());
+        git!(dirname, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display());
         try!(chmod(&self.location, AllPermissions).map_err(io_error));
 
         Ok(())
     }
 
     fn fetch(&self) -> CargoResult<()> {
-        git!(self.location, self.verbose, "fetch --force --quiet --tags {}", self.get_source().display());
+        git!(self.location, "fetch --force --quiet --tags {}", self.get_source().display());
         try!(self.reset(self.revision.as_slice()));
         Ok(())
     }
 
     fn reset<T: Show>(&self, revision: T) -> CargoResult<()> {
-        Ok(git!(self.location, self.verbose, "reset -q --hard {}", revision))
+        Ok(git!(self.location, "reset -q --hard {}", revision))
     }
 
     fn update_submodules(&self) -> CargoResult<()> {
-        Ok(git!(self.location, self.verbose, "submodule update --init --recursive --quiet"))
+        Ok(git!(self.location, "submodule update --init --recursive --quiet"))
     }
 }
 
-fn git(path: &Path, verbose: bool, str: &str) -> ProcessBuilder {
+fn git(path: &Path, str: &str) -> ProcessBuilder {
     debug!("Executing git {} @ {}", str, path.display());
 
     process("git").args(str.split(' ').collect::<Vec<&str>>().as_slice()).cwd(path.clone())
 }
 
-fn git_inherit(path: &Path, verbose: bool, str: String) -> CargoResult<()> {
-    git(path, verbose, str.as_slice()).exec().map_err(|err|
+fn git_inherit(path: &Path, str: String) -> CargoResult<()> {
+    git(path, str.as_slice()).exec().map_err(|err|
         human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err))
 }
 
-fn git_output(path: &Path, verbose: bool, str: String) -> CargoResult<String> {
-    let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err|
+fn git_output(path: &Path, str: String) -> CargoResult<String> {
+    let output = try!(git(path, str.as_slice()).exec_with_output().map_err(|err|
         human_error(format!("Executing `git {}` failed", str), None::<&str>, err)));
 
     Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
index 07d9678d3a79b1163adbbe76df81457d64ec9351..1aa03ddb59b545bd750ea49659349dd14629df02 100644 (file)
@@ -11,12 +11,20 @@ use util::{CargoResult,simple_human,io_error,realpath};
  * take in a single path vs. a vec of paths. The pros / cons are unknown at
  * this point.
  */
-pub struct PathSource { paths: Vec<Path> }
+pub struct PathSource {
+    path: Path
+}
 
 impl PathSource {
-    pub fn new(paths: Vec<Path>) -> PathSource {
-        log!(5, "new; paths={}", display(paths.as_slice()));
-        PathSource { paths: paths }
+
+    /**
+     * Invoked with an absolute path to a directory that contains a Cargo.toml.
+     * The source will read the manifest and find any other packages contained
+     * in the directory structure reachable by the root manifest.
+     */
+    pub fn new(path: &Path) -> PathSource {
+        log!(5, "new; path={}", path.display());
+        PathSource { path: path.clone() }
     }
 
     pub fn read_package(path: &Path) -> CargoResult<Package> {
@@ -37,48 +45,44 @@ impl Show for PathSource {
 }
 
 impl Source for PathSource {
-    fn update(&self) -> CargoResult<()> { Ok(()) }
+    fn update(&self) -> CargoResult<()> {
+        Ok(())
+    }
 
     fn list(&self) -> CargoResult<Vec<Summary>> {
-        Ok(self.paths.iter().filter_map(|path| {
-            match PathSource::read_package(&path.join("Cargo.toml")) {
-                Ok(ref pkg) => Some(pkg.get_summary().clone()),
-                Err(e) => {
-                    debug!("failed to read manifest; path={}; err={}", path.display(), e);
-                    None
-                }
+        // TODO: Recursively find manifests
+
+        match PathSource::read_package(&self.path.join("Cargo.toml")) {
+            Ok(ref pkg) => Ok(vec!(pkg.get_summary().clone())),
+            Err(e) => {
+                debug!("failed to read manifest; path={}; err={}", self.path.display(), e);
+                Err(e)
             }
-        }).collect())
+        }
     }
 
     fn download(&self, _: &[PackageId])  -> CargoResult<()>{
+        // TODO: assert! that the PackageId is contained by the source
         Ok(())
     }
 
     fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
         log!(5, "getting packages; ids={}", ids);
 
-        Ok(self.paths.iter().filter_map(|path| {
-            match PathSource::read_package(&path.join("Cargo.toml")) {
-                Ok(pkg) => {
-                    log!(5, "comparing; pkg={}", pkg);
+        PathSource::read_package(&self.path.join("Cargo.toml")).and_then(|pkg| {
+            log!(5, "comparing; pkg={}", pkg);
 
-                    if ids.iter().any(|pkg_id| pkg.get_package_id() == pkg_id) {
-                        Some(pkg)
-                    } else {
-                        None
-                    }
-                }
-                Err(_) => None
+            if ids.iter().any(|pkg_id| pkg.get_package_id() == pkg_id) {
+                Ok(vec!(pkg))
+            } else {
+                // TODO: Be smarter
+                // Err(simple_human(format!("Couldn't find `{}` in path source", ids)))
+                Ok(vec!())
             }
-        }).collect())
+        })
     }
 }
 
-fn display(paths: &[Path]) -> Vec<String> {
-    paths.iter().map(|p| p.display().to_str()).collect()
-}
-
 fn namespace(path: &Path) -> CargoResult<url::Url> {
     let real = try!(realpath(path).map_err(io_error));
     url::from_str(format!("file://{}", real.display()).as_slice()).map_err(|err|
index 540d0a305ebc8d9c0bf820043182e483a6f535f4..ab1126ea28659d65fdb3fc575eea8de74ce03bbc 100644 (file)
@@ -1,8 +1,29 @@
-use std::{io,fmt};
+use std::{io,fmt,os};
 use std::collections::HashMap;
 use serialize::{Encodable,Encoder};
 use toml;
-use util::{other_error,CargoResult,Require};
+use util::{CargoResult,Require,other_error,simple_human};
+
+pub struct Config {
+    home_path: Path
+}
+
+impl Config {
+    pub fn new() -> CargoResult<Config> {
+        Ok(Config {
+            home_path: try!(os::homedir()
+                            .require(simple_human("Couldn't find the home directory")))
+        })
+    }
+
+    pub fn git_db_path(&self) -> Path {
+        self.home_path.join(".cargo").join("git").join("db")
+    }
+
+    pub fn git_checkout_path(&self) -> Path {
+        self.home_path.join(".cargo").join("git").join("checkouts")
+    }
+}
 
 #[deriving(Eq,PartialEq,Clone,Encodable,Decodable)]
 pub enum Location {
index 58eaf1829d64a92face918462d4900dab0d0c125..848d94cc9174ec24ba58f8790ac1e6d10db93e75 100644 (file)
@@ -1,3 +1,4 @@
+pub use self::config::Config;
 pub use self::process_builder::{process,ProcessBuilder};
 pub use self::result::{CargoError,CargoResult,Wrap,Require,ToCLI,other_error,human_error,simple_human,toml_error,io_error,process_error};
 pub use self::paths::realpath;
index a5fae1fb21ae058183d26ca8c615c727b390d6c5..f8c2718ce596e0f7771366fdeae9afa72c571951 100644 (file)
@@ -4,7 +4,7 @@ use url::Url;
 use std::collections::HashMap;
 use serialize::Decodable;
 
-use core::{SourceId,GitKind,RegistryKind};
+use core::{SourceId,GitKind};
 use core::manifest::{LibKind,Lib};
 use core::{Summary,Manifest,Target,Dependency,PackageId};
 use util::{CargoResult,Require,simple_human,toml_error};
@@ -132,8 +132,7 @@ impl TomlManifest {
                 for (n, v) in dependencies.iter() {
                     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)
+                            (string.clone(), SourceId::for_central())
                         },
                         DetailedDep(ref details) => {
                             let source_id = details.other.find_equiv(&"git").map(|git| {
@@ -141,11 +140,17 @@ impl TomlManifest {
                                 let kind = GitKind("master".to_str());
                                 let url = url::from_str(git.as_slice()).unwrap();
                                 let source_id = SourceId::new(kind, url);
+                                // TODO: Don't do this for path
                                 sources.push(source_id.clone());
                                 source_id
                             });
 
-                            (details.version.clone(), try!(source_id.require(simple_human("Dependencies must supply a git location"))))
+                            // TODO: Convert relative path dependencies to namespace
+
+                            match source_id {
+                                Some(source_id) => (details.version.clone(), source_id),
+                                None => (details.version.clone(), SourceId::for_central())
+                            }
                         }
                     };