From: Yehuda Katz + Carl Lerche Date: Wed, 18 Jun 2014 00:05:29 +0000 (-0700) Subject: Paths nested in paths X-Git-Tag: archive/raspbian/0.35.0-2+rpi1~3^2^2^2^2^2^2^2~1007 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=9224a5ae61dc02061568d65e94484ffe6c4f052f;p=cargo.git Paths nested in paths --- diff --git a/src/bin/cargo-git-checkout.rs b/src/bin/cargo-git-checkout.rs index 3a400a914..2fcac0cad 100644 --- a/src/bin/cargo-git-checkout.rs +++ b/src/bin/cargo-git-checkout.rs @@ -7,7 +7,7 @@ extern crate url; use hammer::FlagConfig; use cargo::{execute_main_without_stdin,CLIResult,CLIError,ToResult}; -use cargo::core::source::Source; +use cargo::core::source::{Source,SourceId}; use cargo::sources::git::{GitSource}; use cargo::util::{Config,ToCLI}; use url::Url; @@ -31,7 +31,9 @@ fn execute(options: Options) -> CLIResult> { 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 source = GitSource::new(&url, reference.as_slice(), &try!(Config::new().to_cli(1))); + let source_id = SourceId::for_git(&url, reference.as_slice()); + + let source = GitSource::new(&source_id, &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-read-manifest.rs b/src/bin/cargo-read-manifest.rs index b1a08de0e..3c3b8694d 100644 --- a/src/bin/cargo-read-manifest.rs +++ b/src/bin/cargo-read-manifest.rs @@ -6,7 +6,7 @@ extern crate hammer; use hammer::FlagConfig; use cargo::{execute_main_without_stdin,CLIResult,CLIError}; -use cargo::core::Package; +use cargo::core::{Package,SourceId}; use cargo::sources::{PathSource}; #[deriving(PartialEq,Clone,Decodable)] @@ -21,6 +21,10 @@ fn main() { } fn execute(options: Options) -> CLIResult> { - PathSource::read_package(&Path::new(options.manifest_path.as_slice())).map(|m| Some(m)) + let source_id = SourceId::for_path(&Path::new(options.manifest_path.as_slice())); + + PathSource::new(&source_id) + .get_root_package() + .map(|pkg| Some(pkg)) .map_err(|err| CLIError::new(err.get_desc(), Some(err.get_detail()), 1)) } diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 86f816c98..2502ed3cb 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -16,6 +16,7 @@ use util::{CargoResult, graph}; use serialize::{Encoder,Encodable}; use core::source::SourceId; +// TODO: Is manifest_path a relic? #[deriving(Clone,PartialEq)] pub struct Package { // The package's manifest diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index d093ffc06..dec82d501 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -66,10 +66,29 @@ impl SourceId { SourceId::new(PathKind, url::from_str(format!("file://{}", path.display()).as_slice()).unwrap()) } + pub fn for_git(url: &Url, reference: &str) -> SourceId { + SourceId::new(GitKind(reference.to_str()), url.clone()) + } + pub fn for_central() -> SourceId { SourceId::new(RegistryKind, url::from_str(format!("https://example.com").as_slice()).unwrap()) } + pub fn get_url<'a>(&'a self) -> &'a Url { + &self.url + } + + pub fn is_path(&self) -> bool { + self.kind == PathKind + } + + pub fn is_git(&self) -> bool { + match self.kind { + GitKind(_) => true, + _ => false + } + } + /* let git_sources: Vec> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| { match source_id.kind { @@ -93,9 +112,9 @@ impl SourceId { pub fn load(&self, config: &Config) -> Box { match self.kind { GitKind(ref reference) => { - box GitSource::new(&self.url, reference.as_slice(), config) as Box + box GitSource::new(self, config) as Box }, - PathKind => box PathSource::new(&Path::new(self.url.path.as_slice())) as Box, + PathKind => box PathSource::new(self) as Box, RegistryKind => unimplemented!() } } diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index b78de842f..fd94204fc 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -26,7 +26,7 @@ pub fn compile(manifest_path: &Path) -> CargoResult<()> { log!(4, "compile; manifest-path={}", manifest_path.display()); // TODO: Move this into PathSource - let package = try!(PathSource::read_package(manifest_path)); + let package = try!(PathSource::new(&SourceId::for_path(&manifest_path.dir_path())).get_root_package()); debug!("loaded package; package={}", package); let override_ids = try!(source_ids_from_config()); diff --git a/src/cargo/ops/cargo_read_manifest.rs b/src/cargo/ops/cargo_read_manifest.rs index fb4d15f15..2265e28b4 100644 --- a/src/cargo/ops/cargo_read_manifest.rs +++ b/src/cargo/ops/cargo_read_manifest.rs @@ -1,18 +1,18 @@ use std::io::File; use util; use url::Url; -use core::{Package,Manifest}; +use core::{Package,Manifest,SourceId}; use util::{CargoResult,io_error}; -pub fn read_manifest(contents: &[u8], namespace: &Url) -> CargoResult { - util::toml::to_manifest(contents, namespace) +pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec)> { + util::toml::to_manifest(contents, source_id) } -pub fn read_package(path: &Path, namespace: &Url) -> CargoResult { - log!(5, "read_package; path={}; namespace={}", path.display(), namespace); +pub fn read_package(path: &Path, source_id: &SourceId) -> CargoResult<(Package, Vec)> { + log!(5, "read_package; path={}; source-id={}", path.display(), source_id); let mut file = try!(File::open(path).map_err(io_error)); let data = try!(file.read_to_end().map_err(io_error)); - let manifest = try!(read_manifest(data.as_slice(), namespace)); + let (manifest, nested) = try!(read_manifest(data.as_slice(), source_id)); - Ok(Package::new(manifest, path)) + Ok((Package::new(manifest, path), nested)) } diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs index 991dc71ea..b1693326f 100644 --- a/src/cargo/sources/git/source.rs +++ b/src/cargo/sources/git/source.rs @@ -8,12 +8,13 @@ use url; use url::Url; use ops; -use core::source::Source; +use core::source::{Source,SourceId,GitKind}; use core::{Package,PackageId,Summary}; use util::{CargoResult,Config}; use sources::git::utils::{GitReference,GitRemote,Master,Other}; pub struct GitSource { + id: SourceId, remote: GitRemote, reference: GitReference, db_path: Path, @@ -21,19 +22,27 @@ pub struct GitSource { } impl GitSource { - pub fn new(url: &Url, reference: &str, config: &Config) -> GitSource { - let remote = GitRemote::new(url); - let ident = ident(url); + pub fn new(source_id: &SourceId, config: &Config) -> GitSource { + assert!(source_id.is_git(), "id is not git, id={}", source_id); + + let reference = match source_id.kind { + GitKind(ref reference) => reference, + _ => fail!("Not a git source; id={}", source_id) + }; + + let remote = GitRemote::new(source_id.get_url()); + let ident = ident(&source_id.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); + .join(ident.as_slice()).join(reference.as_slice()); GitSource { + id: source_id.clone(), remote: remote, - reference: GitReference::for_str(reference), + reference: GitReference::for_str(reference.as_slice()), db_path: db_path, checkout_path: checkout_path } @@ -88,7 +97,7 @@ impl Source for GitSource { fn list(&self) -> CargoResult> { log!(5, "listing summaries in git source `{}`", self.remote); - let pkg = try!(read_manifest(&self.checkout_path, self.get_namespace())); + let pkg = try!(read_manifest(&self.checkout_path, &self.id)); Ok(vec!(pkg.get_summary().clone())) } @@ -99,7 +108,7 @@ impl Source for GitSource { fn get(&self, package_ids: &[PackageId]) -> CargoResult> { log!(5, "getting packages for package ids `{}` from `{}`", package_ids, self.remote); // TODO: Support multiple manifests per repo - let pkg = try!(read_manifest(&self.checkout_path, self.remote.get_url())); + let pkg = try!(read_manifest(&self.checkout_path, &self.id)); if package_ids.iter().any(|pkg_id| pkg_id == pkg.get_package_id()) { Ok(vec!(pkg)) @@ -109,9 +118,11 @@ impl Source for GitSource { } } -fn read_manifest(path: &Path, url: &url::Url) -> CargoResult { +fn read_manifest(path: &Path, source_id: &SourceId) -> CargoResult { let path = path.join("Cargo.toml"); - ops::read_package(&path, url) + // TODO: recurse + let (pkg, _) = try!(ops::read_package(&path, source_id)); + Ok(pkg) } #[cfg(test)] diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 1aa03ddb5..a4fd37448 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -1,20 +1,19 @@ use std::fmt; use std::fmt::{Show,Formatter}; -use core::{Package,PackageId,Summary}; -use core::source::Source; +use core::{Package,PackageId,Summary,SourceId,Source}; use ops; use url; use util::{CargoResult,simple_human,io_error,realpath}; -/* - * TODO: Consider whether it may be more appropriate for a PathSource to only - * take in a single path vs. a vec of paths. The pros / cons are unknown at - * this point. - */ pub struct PathSource { - path: Path + id: SourceId, + path: Path, } +/** + * TODO: Figure out if packages should be discovered in new or self should be + * mut and packages are discovered in update + */ impl PathSource { /** @@ -22,20 +21,42 @@ impl PathSource { * 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 new(id: &SourceId) -> PathSource { + log!(5, "new; id={}", id); + assert!(id.is_path(), "does not represent a path source; id={}", id); + + let path = Path::new(id.get_url().path.as_slice()); + + PathSource { + id: id.clone(), + path: path + } } - pub fn read_package(path: &Path) -> CargoResult { - log!(5, "read_package; path={}", path.display()); + /* + pub fn get_path<'a>(&'a self) -> &'a Path { + &self.path + } + */ + + pub fn get_root_package(&self) -> CargoResult { + log!(5, "get_root_package; source={}", self); + + match (try!(self.packages())).as_slice().head() { + Some(pkg) => Ok(pkg.clone()), + None => Err(simple_human("no package found in source")) + } + } - // TODO: Use a realpath fn - let dir = path.dir_path(); - let namespace = try!(namespace(&dir)); + fn packages(&self) -> CargoResult> { + find_packages(&self.path, &self.id) + } - ops::read_package(path, &namespace) + /* + fn get_root_manifest_path(&self) -> Path { + self.path.join("Cargo.toml") } + */ } impl Show for PathSource { @@ -50,15 +71,8 @@ impl Source for PathSource { } fn list(&self) -> CargoResult> { - // 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) - } - } + let pkgs = try!(self.packages()); + Ok(pkgs.iter().map(|p| p.get_summary().clone()).collect()) } fn download(&self, _: &[PackageId]) -> CargoResult<()>{ @@ -69,20 +83,26 @@ impl Source for PathSource { fn get(&self, ids: &[PackageId]) -> CargoResult> { log!(5, "getting packages; ids={}", ids); - 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) { - Ok(vec!(pkg)) - } else { - // TODO: Be smarter - // Err(simple_human(format!("Couldn't find `{}` in path source", ids))) - Ok(vec!()) - } - }) + let pkgs = try!(self.packages()); + + Ok(pkgs.iter() + .filter(|pkg| ids.iter().any(|id| pkg.get_package_id() == id)) + .map(|pkg| pkg.clone()) + .collect()) } } +fn find_packages(path: &Path, source_id: &SourceId) -> CargoResult> { + let (pkg, nested) = try!(ops::read_package(&path.join("Cargo.toml"), source_id)); + let mut ret = vec!(pkg); + + for path in nested.iter() { + ret.push_all(try!(find_packages(path, source_id)).as_slice()); + } + + Ok(ret) +} + 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/toml.rs b/src/cargo/util/toml.rs index f8c2718ce..0bf40537f 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -9,14 +9,14 @@ use core::manifest::{LibKind,Lib}; use core::{Summary,Manifest,Target,Dependency,PackageId}; use util::{CargoResult,Require,simple_human,toml_error}; -pub fn to_manifest(contents: &[u8], namespace: &Url) -> CargoResult { +pub fn to_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec)> { let root = try!(toml::parse_from_bytes(contents).map_err(|_| simple_human("Cargo.toml is not valid Toml"))); let toml = try!(toml_to_manifest(root).map_err(|_| simple_human("Cargo.toml is not a valid Cargo manifest"))); - toml.to_manifest(namespace) + toml.to_manifest(source_id) } fn toml_to_manifest(root: toml::Value) -> CargoResult { @@ -114,8 +114,9 @@ impl TomlProject { } impl TomlManifest { - pub fn to_manifest(&self, namespace: &Url) -> CargoResult { + pub fn to_manifest(&self, source_id: &SourceId) -> CargoResult<(Manifest, Vec)> { let mut sources = vec!(); + let mut nested_paths = vec!(); // Get targets let targets = normalize(self.lib.as_ref().map(|l| l.as_slice()), self.bin.as_ref().map(|b| b.as_slice())); @@ -135,7 +136,7 @@ impl TomlManifest { (string.clone(), SourceId::for_central()) }, DetailedDep(ref details) => { - let source_id = details.other.find_equiv(&"git").map(|git| { + let new_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(); @@ -143,14 +144,14 @@ impl TomlManifest { // TODO: Don't do this for path sources.push(source_id.clone()); source_id - }); - - // 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()) - } + }).or_else(|| { + details.other.find_equiv(&"path").map(|path| { + nested_paths.push(Path::new(path.as_slice())); + source_id.clone() + }) + }).unwrap_or(SourceId::for_central()); + + (details.version.clone(), new_source_id) } }; @@ -160,11 +161,11 @@ impl TomlManifest { None => () } - Ok(Manifest::new( - &Summary::new(&self.project.to_package_id(namespace), deps.as_slice()), + Ok((Manifest::new( + &Summary::new(&self.project.to_package_id(source_id.get_url()), deps.as_slice()), targets.as_slice(), &Path::new("target"), - sources)) + sources), nested_paths)) } } diff --git a/tests/test_cargo_compile_path_deps.rs b/tests/test_cargo_compile_path_deps.rs new file mode 100644 index 000000000..b4481e054 --- /dev/null +++ b/tests/test_cargo_compile_path_deps.rs @@ -0,0 +1,81 @@ +use support::{ProjectBuilder,ResultTest,project,execs,main_file}; +use hamcrest::{assert_that,existing_file}; +use cargo; +use cargo::util::{CargoResult,process}; + +fn setup() { +} + +test!(cargo_compile_with_nested_deps_shorthand { + let mut p = project("foo"); + let bar = p.root().join("bar"); + let baz = p.root().join("baz"); + + p = p + .file("Cargo.toml", r#" + [project] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + + version = "0.5.0" + path = "bar" + + [[bin]] + + name = "foo" + "#) + .file("src/foo.rs", main_file(r#""{}", bar::gimme()"#, ["bar"]).as_slice()) + .file("bar/Cargo.toml", r#" + [project] + + name = "bar" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.baz] + + version = "0.5.0" + path = "baz" + + [[lib]] + + name = "bar" + "#) + .file("bar/src/bar.rs", r#" + extern crate baz; + + pub fn gimme() -> String { + baz::gimme() + } + "#) + .file("baz/Cargo.toml", r#" + [project] + + name = "baz" + version = "0.5.0" + authors = ["wycats@example.com"] + + [[lib]] + + name = "baz" + "#) + .file("baz/src/baz.rs", r#" + pub fn gimme() -> String { + "test passed".to_str() + } + "#); + + p.cargo_process("cargo-compile") + .exec_with_output() + .assert(); + + assert_that(&p.root().join("target/foo"), existing_file()); + + assert_that( + cargo::util::process("foo").extra_path(p.root().join("target")), + execs().with_stdout("test passed\n")); +}) diff --git a/tests/tests.rs b/tests/tests.rs index 3357e0a62..1e99363fc 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -22,4 +22,5 @@ macro_rules! test( mod test_cargo_compile; mod test_cargo_compile_git_deps; +mod test_cargo_compile_path_deps; mod test_shell;