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;
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)
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)]
}
fn execute(options: Options) -> CLIResult<Option<Package>> {
- 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))
}
use serialize::{Encoder,Encodable};
use core::source::SourceId;
+// TODO: Is manifest_path a relic?
#[deriving(Clone,PartialEq)]
pub struct Package {
// The package's manifest
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<Box<Source>> = try!(result::collect(package.get_sources().iter().map(|source_id: &SourceId| {
match source_id.kind {
pub fn load(&self, config: &Config) -> Box<Source> {
match self.kind {
GitKind(ref reference) => {
- box GitSource::new(&self.url, reference.as_slice(), config) as Box<Source>
+ box GitSource::new(self, config) as Box<Source>
},
- PathKind => box PathSource::new(&Path::new(self.url.path.as_slice())) as Box<Source>,
+ PathKind => box PathSource::new(self) as Box<Source>,
RegistryKind => unimplemented!()
}
}
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());
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<Manifest> {
- util::toml::to_manifest(contents, namespace)
+pub fn read_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
+ util::toml::to_manifest(contents, source_id)
}
-pub fn read_package(path: &Path, namespace: &Url) -> CargoResult<Package> {
- log!(5, "read_package; path={}; namespace={}", path.display(), namespace);
+pub fn read_package(path: &Path, source_id: &SourceId) -> CargoResult<(Package, Vec<Path>)> {
+ 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))
}
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,
}
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
}
fn list(&self) -> CargoResult<Vec<Summary>> {
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()))
}
fn get(&self, package_ids: &[PackageId]) -> CargoResult<Vec<Package>> {
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))
}
}
-fn read_manifest(path: &Path, url: &url::Url) -> CargoResult<Package> {
+fn read_manifest(path: &Path, source_id: &SourceId) -> CargoResult<Package> {
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)]
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 {
/**
* 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<Package> {
- 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<Package> {
+ 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<Vec<Package>> {
+ 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 {
}
fn list(&self) -> CargoResult<Vec<Summary>> {
- // 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<()>{
fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
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<Vec<Package>> {
+ 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<url::Url> {
let real = try!(realpath(path).map_err(io_error));
url::from_str(format!("file://{}", real.display()).as_slice()).map_err(|err|
use core::{Summary,Manifest,Target,Dependency,PackageId};
use util::{CargoResult,Require,simple_human,toml_error};
-pub fn to_manifest(contents: &[u8], namespace: &Url) -> CargoResult<Manifest> {
+pub fn to_manifest(contents: &[u8], source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
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<TomlManifest> {
}
impl TomlManifest {
- pub fn to_manifest(&self, namespace: &Url) -> CargoResult<Manifest> {
+ pub fn to_manifest(&self, source_id: &SourceId) -> CargoResult<(Manifest, Vec<Path>)> {
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()));
(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();
// 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)
}
};
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))
}
}
--- /dev/null
+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"));
+})
mod test_cargo_compile;
mod test_cargo_compile_git_deps;
+mod test_cargo_compile_path_deps;
mod test_shell;