From 98322afd90da78f7286110ac10a3a4ab8965a7e4 Mon Sep 17 00:00:00 2001 From: Yehuda Katz + Carl Lerche Date: Tue, 17 Jun 2014 15:36:50 -0700 Subject: [PATCH] Improvements to transitive dependency infra Initial work to enable cross-source transitive dependencies. --- Makefile | 2 +- src/bin/cargo-compile.rs | 2 +- src/bin/cargo-git-checkout.rs | 11 ++- src/bin/cargo.rs | 2 +- src/cargo/core/manifest.rs | 2 +- src/cargo/core/package.rs | 6 +- src/cargo/core/registry.rs | 62 +++++++++++++---- src/cargo/core/resolver.rs | 5 +- src/cargo/core/source.rs | 43 ++++++++++-- src/cargo/core/summary.rs | 4 ++ src/cargo/ops/cargo_compile.rs | 116 ++++---------------------------- src/cargo/sources/git/source.rs | 77 +++++++++++++++++++-- src/cargo/sources/git/utils.rs | 56 +++++++-------- src/cargo/sources/path.rs | 62 +++++++++-------- src/cargo/util/config.rs | 25 ++++++- src/cargo/util/mod.rs | 1 + src/cargo/util/toml.rs | 13 ++-- 17 files changed, 284 insertions(+), 205 deletions(-) diff --git a/Makefile b/Makefile index edb5b6909..256ef9cf9 100644 --- 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) diff --git a/src/bin/cargo-compile.rs b/src/bin/cargo-compile.rs index fd741c691..1c0220383 100644 --- a/src/bin/cargo-compile.rs +++ b/src/bin/cargo-compile.rs @@ -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 { diff --git a/src/bin/cargo-git-checkout.rs b/src/bin/cargo-git-checkout.rs index 3b0bc5755..3a400a914 100644 --- a/src/bin/cargo-git-checkout.rs +++ b/src/bin/cargo-git-checkout.rs @@ -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> { - 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) })); diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index 8646a6adb..5293000e4 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -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(); diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 6b9d1b57b..b8d8b48ec 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -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() } } diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index da9c13eac..86f816c98 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -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 { + let mut ret = vec!(SourceId::for_path(&self.get_root())); + ret.push_all(self.manifest.get_source_ids()); + ret } } diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs index 91b8ea525..508c121bf 100644 --- a/src/cargo/core/registry.rs +++ b/src/cargo/core/registry.rs @@ -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>; @@ -23,33 +23,71 @@ pub struct PackageRegistry { } impl PackageRegistry { - pub fn new(sources: Vec>, overrides: SourceSet) -> CargoResult { - Ok(PackageRegistry { - sources: sources, - overrides: try!(overrides.list()), + pub fn new(source_ids: Vec, override_ids: Vec) -> CargoResult { + 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> { + 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()); diff --git a/src/cargo/core/resolver.rs b/src/cargo/core/resolver.rs index 882c7399f..23eac0b6b 100644 --- a/src/cargo/core/resolver.rs +++ b/src/cargo/core/resolver.rs @@ -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(deps: &[Dependency], registry: &mut R) -> CargoResult> { - log!(5, "resolve; deps={}; registry={}", deps, registry); +pub fn resolve(deps: &[Dependency], registry: &mut R) -> CargoResult> { + log!(5, "resolve; deps={}", deps); let mut remaining = Vec::from_slice(deps); let mut resolve = HashMap::::new(); diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index 2188b316a..d093ffc06 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -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 { + // 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> = 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) + }, + ref PathKind => fail!("Cannot occur") + } + }))); + */ + + pub fn load(&self, config: &Config) -> Box { match self.kind { - GitKind(ref reference) => unimplemented!(), - _ => unimplemented!() + GitKind(ref reference) => { + box GitSource::new(&self.url, reference.as_slice(), config) as Box + }, + PathKind => box PathSource::new(&Path::new(self.url.path.as_slice())) as Box, + RegistryKind => unimplemented!() } } } diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index 928e57f66..7ab20b8e7 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -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, diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 67b4e7cbb..b78de842f 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -14,23 +14,13 @@ * 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>> { - 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 { - 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) - }, - ref PathKind => fail!("Cannot occur") - } - }))); - - sources.push_all_move(git_sources); - - Ok(sources) -} - -fn sources_from_config() -> CargoResult { +fn source_ids_from_config() -> CargoResult> { 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 = match config_paths.get_value() { + let paths: Vec = 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))) -} - -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()) } diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs index 12c68af8b..991dc71ea 100644 --- a/src/cargo/sources/git/source.rs +++ b/src/cargo/sources/git/source.rs @@ -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 { 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() + } +} diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 4118364cd..8cccdb584 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -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> Encodable 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> Encodable 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(&self, reference: S, dest: &Path) -> CargoResult { - 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(&self, reference: S) -> CargoResult { - 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 { + fn clone_into(into: &Path, database: GitDatabase, reference: GitReference) -> CargoResult { 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(&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::>().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 { - let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err| +fn git_output(path: &Path, str: String) -> CargoResult { + 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()) diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 07d9678d3..1aa03ddb5 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -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 } +pub struct PathSource { + path: Path +} impl PathSource { - pub fn new(paths: Vec) -> 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 { @@ -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> { - 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> { 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 { - paths.iter().map(|p| p.display().to_str()).collect() -} - fn namespace(path: &Path) -> CargoResult { let real = try!(realpath(path).map_err(io_error)); url::from_str(format!("file://{}", real.display()).as_slice()).map_err(|err| diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index 540d0a305..ab1126ea2 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -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 { + 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 { diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 58eaf1829..848d94cc9 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -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; diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index a5fae1fb2..f8c2718ce 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::{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()) + } } }; -- 2.30.2