diff --git a/Makefile b/Makefile index 7a422faff7c..e10fedb1aaf 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,11 @@ ifeq ($(wildcard rustc/bin),) export RUSTC := rustc else export RUSTC := $(CURDIR)/rustc/bin/rustc +export LD_LIBRARY_PATH := $(CURDIR)/rustc/lib:$(LD_LIBRARY_PATH) +export DYLD_LIBRARY_PATH := $(CURDIR)/rustc/lib:$(DYLD_LIBRARY_PATH) endif -export PATH := $(PATH):$(CURDIR)/rustc/bin +export PATH := $(CURDIR)/rustc/bin:$(PATH) # Link flags to pull in dependencies BINS = cargo \ diff --git a/README.md b/README.md index 32c7308e772..cef99a6d4c1 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ $ ./cargo-nightly/bin/cargo build The current nightlies available are: -* `cargo-nightly-linux` -* `cargo-nightly-win` -* `cargo-nightly-mac` +* [`cargo-nightly-linux`](http://static.rust-lang.org/cargo-dist/cargo-nightly-linux.tar.gz) +* [`cargo-nightly-win`](http://static.rust-lang.org/cargo-dist/cargo-nightly-win.tar.gz) +* [`cargo-nightly-mac`](http://static.rust-lang.org/cargo-dist/cargo-nightly-mac.tar.gz) ## Compiling cargo diff --git a/libs/hamcrest-rust b/libs/hamcrest-rust index a3844d6e0c6..60b649957b5 160000 --- a/libs/hamcrest-rust +++ b/libs/hamcrest-rust @@ -1 +1 @@ -Subproject commit a3844d6e0c6b84934078b7ee0e6e702c59cc5242 +Subproject commit 60b649957b556c934929b7b6205ec95e20a2cd9e diff --git a/libs/hammer.rs b/libs/hammer.rs index bbb78486766..fa1255d4ba1 160000 --- a/libs/hammer.rs +++ b/libs/hammer.rs @@ -1 +1 @@ -Subproject commit bbb7848676698ec94d186e2c910ab82452d07433 +Subproject commit fa1255d4ba109f82d1b0e8be61dde4ea70047be9 diff --git a/libs/toml-rs b/libs/toml-rs index 624d5398184..a0f1ea65fc8 160000 --- a/libs/toml-rs +++ b/libs/toml-rs @@ -1 +1 @@ -Subproject commit 624d5398184ccd500c3ce02338006f32f380fcc9 +Subproject commit a0f1ea65fc80379f0c6c095d92fad840004aaa56 diff --git a/src/bin/cargo-test.rs b/src/bin/cargo-test.rs index 257b7024ef7..1967c59fdf2 100644 --- a/src/bin/cargo-test.rs +++ b/src/bin/cargo-test.rs @@ -22,11 +22,12 @@ use cargo::util::important_paths::find_project_manifest; struct Options { manifest_path: Option, jobs: Option, + update: bool, rest: Vec, } hammer_config!(Options "Run the package's test suite", |c| { - c.short("jobs", 'j') + c.short("jobs", 'j').short("update", 'u') }) fn main() { @@ -45,7 +46,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult> { }; let compile_opts = ops::CompileOptions { - update: false, + update: options.update, env: "test", shell: shell, jobs: options.jobs @@ -64,7 +65,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult> { for file in walk { // TODO: The proper fix is to have target knows its expected // output and only run expected executables. - if file.display().to_str().as_slice().contains("dSYM") { continue; } + if file.display().to_string().as_slice().contains("dSYM") { continue; } if !is_executable(&file) { continue; } try!(util::process(file).exec().map_err(|e| { diff --git a/src/bin/cargo-verify-project.rs b/src/bin/cargo-verify-project.rs index 9760ecd4f11..777b4305297 100644 --- a/src/bin/cargo-verify-project.rs +++ b/src/bin/cargo-verify-project.rs @@ -34,7 +34,7 @@ fn main() { } }; let file = Path::new(manifest); - let contents = match File::open(&file).read_to_str() { + let contents = match File::open(&file).read_to_string() { Ok(s) => s, Err(e) => return fail("invalid", format!("error reading file: {}", e).as_slice()) diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index c3577bdd814..3be5ec81760 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -81,7 +81,7 @@ fn execute() { fn process(args: Vec) -> (String, Vec) { let mut args = Vec::from_slice(args.tail()); - let head = args.shift().unwrap_or("--help".to_str()); + let head = args.shift().unwrap_or("--help".to_string()); (head, args) } @@ -156,5 +156,5 @@ fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult SerializedDependency { SerializedDependency { - name: dep.get_name().to_str(), - req: dep.get_version_req().to_str() + name: dep.get_name().to_string(), + req: dep.get_version_req().to_string() } } } diff --git a/src/cargo/core/errors.rs b/src/cargo/core/errors.rs index 03ea07809e2..695ecba9de6 100644 --- a/src/cargo/core/errors.rs +++ b/src/cargo/core/errors.rs @@ -32,8 +32,8 @@ pub struct CLIError { impl CLIError { pub fn new(msg: T, detail: Option, exit_code: uint) -> CLIError { - let detail = detail.map(|d| d.to_str()); - CLIError { msg: msg.to_str(), detail: detail, exit_code: exit_code } + let detail = detail.map(|d| d.to_string()); + CLIError { msg: msg.to_string(), detail: detail, exit_code: exit_code } } } @@ -84,7 +84,7 @@ impl CargoError { } pub fn described(description: T) -> CargoError { - CargoInternalError(Described(description.to_str())) + CargoInternalError(Described(description.to_string())) } pub fn other() -> CargoError { diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 3eee275913f..724f5216ea8 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -47,14 +47,14 @@ pub struct SerializedManifest { impl> Encodable for Manifest { fn encode(&self, s: &mut S) -> Result<(), E> { SerializedManifest { - name: self.summary.get_name().to_str(), - version: self.summary.get_version().to_str(), + name: self.summary.get_name().to_string(), + version: self.summary.get_version().to_string(), dependencies: self.summary.get_dependencies().iter().map(|d| { SerializedDependency::from_dependency(d) }).collect(), authors: self.authors.clone(), targets: self.targets.clone(), - target_dir: self.target_dir.display().to_str(), + target_dir: self.target_dir.display().to_string(), build: if self.build.len() == 0 { None } else { Some(self.build.clone()) }, }.encode(s) } @@ -100,7 +100,7 @@ pub enum TargetKind { BinTarget } -#[deriving(Encodable, Decodable, Clone, Hash, PartialEq)] +#[deriving(Encodable, Decodable, Clone, Hash, PartialEq, Show)] pub struct Profile { env: String, // compile, test, dev, bench, etc. opt_level: uint, @@ -112,7 +112,7 @@ pub struct Profile { impl Profile { pub fn default_dev() -> Profile { Profile { - env: "compile".to_str(), // run in the default environment only + env: "compile".to_string(), // run in the default environment only opt_level: 0, debug: true, test: false, // whether or not to pass --test @@ -122,31 +122,31 @@ impl Profile { pub fn default_test() -> Profile { Profile { - env: "test".to_str(), // run in the default environment only + env: "test".to_string(), // run in the default environment only opt_level: 0, debug: true, test: true, // whether or not to pass --test - dest: Some("test".to_str()) + dest: Some("test".to_string()) } } pub fn default_bench() -> Profile { Profile { - env: "bench".to_str(), // run in the default environment only + env: "bench".to_string(), // run in the default environment only opt_level: 3, debug: false, test: true, // whether or not to pass --test - dest: Some("bench".to_str()) + dest: Some("bench".to_string()) } } pub fn default_release() -> Profile { Profile { - env: "release".to_str(), // run in the default environment only + env: "release".to_string(), // run in the default environment only opt_level: 3, debug: false, test: false, // whether or not to pass --test - dest: Some("release".to_str()) + dest: Some("release".to_string()) } } @@ -218,7 +218,7 @@ impl> Encodable for Target { SerializedTarget { kind: kind, name: self.name.clone(), - src_path: self.src_path.display().to_str(), + src_path: self.src_path.display().to_string(), profile: self.profile.clone(), metadata: self.metadata.clone() }.encode(s) @@ -227,8 +227,8 @@ impl> Encodable for Target { impl Show for Target { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}(name={}, path={})", self.kind, self.name, - self.src_path.display()) + write!(f, "{}(name={}, path={}, profile={})", self.kind, self.name, + self.src_path.display(), self.profile) } } @@ -298,6 +298,13 @@ impl Manifest { } impl Target { + pub fn file_stem(&self) -> String { + match self.metadata { + Some(ref metadata) => format!("{}{}", self.name, metadata.extra_filename), + None => self.name.clone() + } + } + pub fn lib_target(name: &str, crate_targets: Vec, src_path: &Path, profile: &Profile, metadata: &Metadata) @@ -305,7 +312,7 @@ impl Target { { Target { kind: LibTarget(crate_targets), - name: name.to_str(), + name: name.to_string(), src_path: src_path.clone(), profile: profile.clone(), metadata: Some(metadata.clone()) @@ -315,7 +322,7 @@ impl Target { pub fn bin_target(name: &str, src_path: &Path, profile: &Profile) -> Target { Target { kind: BinTarget, - name: name.to_str(), + name: name.to_string(), src_path: src_path.clone(), profile: profile.clone(), metadata: None @@ -337,6 +344,21 @@ impl Target { } } + pub fn is_dylib(&self) -> bool { + match self.kind { + LibTarget(ref kinds) => kinds.iter().any(|&k| k == Dylib), + _ => false + } + } + + pub fn is_rlib(&self) -> bool { + match self.kind { + LibTarget(ref kinds) => + kinds.iter().any(|&k| k == Rlib || k == Lib), + _ => false + } + } + pub fn is_bin(&self) -> bool { match self.kind { BinTarget => true, diff --git a/src/cargo/core/mod.rs b/src/cargo/core/mod.rs index 23716f6be8c..80fb64eed73 100644 --- a/src/cargo/core/mod.rs +++ b/src/cargo/core/mod.rs @@ -42,6 +42,7 @@ pub use self::dependency::{ }; pub use self::version_req::VersionReq; +pub use self::resolver::Resolve; pub mod errors; pub mod source; diff --git a/src/cargo/core/package.rs b/src/cargo/core/package.rs index 275cc26b45e..d43fe26d835 100644 --- a/src/cargo/core/package.rs +++ b/src/cargo/core/package.rs @@ -45,14 +45,14 @@ impl> Encodable for Package { let package_id = summary.get_package_id(); SerializedPackage { - name: package_id.get_name().to_str(), - version: package_id.get_version().to_str(), + name: package_id.get_name().to_string(), + version: package_id.get_version().to_string(), dependencies: summary.get_dependencies().iter().map(|d| { SerializedDependency::from_dependency(d) }).collect(), authors: Vec::from_slice(manifest.get_authors()), targets: Vec::from_slice(manifest.get_targets()), - manifest_path: self.manifest_path.display().to_str() + manifest_path: self.manifest_path.display().to_string() }.encode(s) } } @@ -123,7 +123,7 @@ impl Package { // Sort the sources just to make sure we have a consistent fingerprint. sources.sort_by(|a, b| { cmp::lexical_ordering(a.kind.cmp(&b.kind), - a.location.to_str().cmp(&b.location.to_str())) + a.location.to_string().cmp(&b.location.to_string())) }); let sources = sources.iter().map(|source_id| { source_id.load(config) diff --git a/src/cargo/core/package_id.rs b/src/cargo/core/package_id.rs index 03236aa36dd..6225d1c150f 100644 --- a/src/cargo/core/package_id.rs +++ b/src/cargo/core/package_id.rs @@ -1,7 +1,9 @@ use semver; use url::Url; +use std::hash::Hash; use std::fmt; use std::fmt::{Show,Formatter}; +use collections::hash; use serialize::{ Encodable, Encoder, @@ -60,6 +62,16 @@ pub struct PackageId { source_id: SourceId, } +impl Hash for PackageId { + fn hash(&self, state: &mut S) { + self.name.hash(state); + self.version.to_string().hash(state); + self.source_id.hash(state); + } +} + +impl Eq for PackageId {} + #[deriving(Clone, Show, PartialEq)] pub enum PackageIdError { InvalidVersion(String), @@ -87,7 +99,7 @@ impl PackageId { sid: &SourceId) -> CargoResult { let v = try!(version.to_version().map_err(InvalidVersion)); Ok(PackageId { - name: name.to_str(), + name: name.to_string(), version: v, source_id: sid.clone() }) @@ -108,9 +120,9 @@ impl PackageId { pub fn generate_metadata(&self) -> Metadata { let metadata = format!("{}:-:{}:-:{}", self.name, self.version, self.source_id); let extra_filename = short_hash( - &(self.name.as_slice(), self.version.to_str(), &self.source_id)); + &(self.name.as_slice(), self.version.to_string(), &self.source_id)); - Metadata { metadata: metadata, extra_filename: extra_filename } + Metadata { metadata: metadata, extra_filename: format!("-{}", extra_filename) } } } @@ -120,7 +132,7 @@ impl Show for PackageId { fn fmt(&self, f: &mut Formatter) -> fmt::Result { try!(write!(f, "{} v{}", self.name, self.version)); - if self.source_id.to_str().as_slice() != central_repo { + if self.source_id.to_string().as_slice() != central_repo { try!(write!(f, " ({})", self.source_id)); } @@ -141,7 +153,7 @@ impl>> impl> Encodable for PackageId { fn encode(&self, e: &mut S) -> Result<(), E> { - (self.name.clone(), self.version.to_str(), self.source_id.clone()).encode(e) + (self.name.clone(), self.version.to_string(), self.source_id.clone()).encode(e) } } diff --git a/src/cargo/core/resolver.rs b/src/cargo/core/resolver.rs index 6a50c71084b..69f03fc248c 100644 --- a/src/cargo/core/resolver.rs +++ b/src/cargo/core/resolver.rs @@ -1,68 +1,136 @@ use std::collections::HashMap; +use util::graph::{Nodes,Edges}; use core::{ Dependency, PackageId, - Summary, Registry, + SourceId, }; -use util::{CargoResult, human, internal}; +use semver; -/* TODO: - * - 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> { +use util::{CargoResult, Graph, human, internal}; + +pub struct Resolve { + graph: Graph +} + +impl Resolve { + fn new() -> Resolve { + Resolve { graph: Graph::new() } + } + + pub fn iter<'a>(&'a self) -> Nodes<'a, PackageId> { + self.graph.iter() + } + + pub fn deps<'a>(&'a self, pkg: &PackageId) -> Option> { + self.graph.edges(pkg) + } +} + +struct Context<'a, R> { + registry: &'a mut R, + resolve: Resolve, + + // Eventually, we will have smarter logic for checking for conflicts in the resolve, + // but without the registry, conflicts should not exist in practice, so this is just + // a sanity check. + seen: HashMap<(String, SourceId), semver::Version> +} + +impl<'a, R: Registry> Context<'a, R> { + fn new(registry: &'a mut R) -> Context<'a, R> { + Context { + registry: registry, + resolve: Resolve::new(), + seen: HashMap::new() + } + } +} + +pub fn resolve(root: &PackageId, deps: &[Dependency], registry: &mut R) + -> CargoResult +{ log!(5, "resolve; deps={}", deps); - let mut remaining = Vec::from_slice(deps); - let mut resolve = HashMap::::new(); - - loop { - let curr = match remaining.pop() { - Some(curr) => curr, - None => { - let ret = resolve.values().map(|summary| { - summary.get_package_id().clone() - }).collect(); - log!(5, "resolve complete; ret={}", ret); - return Ok(ret); - } - }; + let mut context = Context::new(registry); + try!(resolve_deps(root, deps, &mut context)); + Ok(context.resolve) +} - let opts = try!(registry.query(&curr)); +fn resolve_deps<'a, R: Registry>(parent: &PackageId, + deps: &[Dependency], + ctx: &mut Context<'a, R>) + -> CargoResult<()> +{ + if deps.is_empty() { + return Ok(()); + } + + for dep in deps.iter() { + let pkgs = try!(ctx.registry.query(dep)); - if opts.len() == 0 { - return Err(human(format!("No package named {} found", curr.get_name()))); + if pkgs.is_empty() { + return Err(human(format!("No package named {} found", dep))); } - if opts.len() > 1 { + if pkgs.len() > 1 { return Err(internal(format!("At the moment, Cargo only supports a \ - single source for a particular package name ({}).", curr.get_name()))); + single source for a particular package name ({}).", dep))); } - let pkg = opts.get(0).clone(); - resolve.insert(pkg.get_name().to_str(), pkg.clone()); + let summary = pkgs.get(0).clone(); + let name = summary.get_name().to_string(); + let source_id = summary.get_source_id().clone(); + let version = summary.get_version().clone(); + + ctx.resolve.graph.link(parent.clone(), summary.get_package_id().clone()); - for dep in pkg.get_dependencies().iter() { - if !dep.is_transitive() { continue; } + let found = { + let found = ctx.seen.find(&(name.clone(), source_id.clone())); - if !resolve.contains_key_equiv(&dep.get_name()) { - remaining.push(dep.clone()); + if found.is_some() { + if found == Some(&version) { continue; } + return Err(human(format!("Cargo found multiple copies of {} in {}. This \ + is not currently supported", + summary.get_name(), summary.get_source_id()))); + } else { + false } + }; + + if !found { + ctx.seen.insert((name, source_id), version); } + + ctx.resolve.graph.add(summary.get_package_id().clone(), []); + + let deps: Vec = summary.get_dependencies().iter() + .filter(|d| d.is_transitive()) + .map(|d| d.clone()) + .collect(); + + try!(resolve_deps(summary.get_package_id(), deps.as_slice(), ctx)); } + + Ok(()) } #[cfg(test)] mod test { use hamcrest::{assert_that, equal_to, contains}; - use core::source::{SourceId, RegistryKind, Location, Remote}; - use core::{Dependency, PackageId, Summary}; - use super::resolve; + use core::source::{SourceId, RegistryKind, GitKind, Location, Remote}; + use core::{Dependency, PackageId, Summary, Registry}; + use util::CargoResult; + + fn resolve(pkg: &PackageId, deps: &[Dependency], registry: &mut R) + -> CargoResult> + { + Ok(try!(super::resolve(pkg, deps, registry)).iter().map(|p| p.clone()).collect()) + } trait ToDep { fn to_dep(self) -> Dependency; @@ -102,8 +170,23 @@ mod test { } fn pkg(name: &str) -> Summary { - Summary::new(&PackageId::new(name, "1.0.0", ®istry_loc()).unwrap(), - &[]) + Summary::new(&pkg_id(name), &[]) + } + + fn pkg_id(name: &str) -> PackageId { + PackageId::new(name, "1.0.0", ®istry_loc()).unwrap() + } + + fn pkg_id_loc(name: &str, loc: &str) -> PackageId { + let remote = Location::parse(loc); + let source_id = SourceId::new(GitKind("master".to_string()), + remote.unwrap()); + + PackageId::new(name, "1.0.0", &source_id).unwrap() + } + + fn pkg_loc(name: &str, loc: &str) -> Summary { + Summary::new(&pkg_id_loc(name, loc), &[]) } fn dep(name: &str) -> Dependency { @@ -112,6 +195,12 @@ mod test { Dependency::parse(name, Some("1.0.0"), &source_id).unwrap() } + fn dep_loc(name: &str, location: &str) -> Dependency { + let url = from_str(location).unwrap(); + let source_id = SourceId::new(GitKind("master".to_string()), Remote(url)); + Dependency::parse(name, Some("1.0.0"), &source_id).unwrap() + } + fn registry(pkgs: Vec) -> Vec { pkgs } @@ -122,9 +211,14 @@ mod test { .collect() } + fn loc_names(names: &[(&'static str, &'static str)]) -> Vec { + names.iter() + .map(|&(name, loc)| pkg_id_loc(name, loc)).collect() + } + #[test] pub fn test_resolving_empty_dependency_list() { - let res = resolve([], &mut registry(vec!())).unwrap(); + let res = resolve(&pkg_id("root"), [], &mut registry(vec!())).unwrap(); assert_that(&res, equal_to(&names([]))); } @@ -132,41 +226,60 @@ mod test { #[test] pub fn test_resolving_only_package() { let mut reg = registry(vec!(pkg("foo"))); - let res = resolve([dep("foo")], &mut reg); + let res = resolve(&pkg_id("root"), [dep("foo")], &mut reg); - assert_that(&res.unwrap(), equal_to(&names(["foo"]))); + assert_that(&res.unwrap(), contains(names(["root", "foo"])).exactly()); } #[test] pub fn test_resolving_one_dep() { let mut reg = registry(vec!(pkg("foo"), pkg("bar"))); - let res = resolve([dep("foo")], &mut reg); + let res = resolve(&pkg_id("root"), [dep("foo")], &mut reg); - assert_that(&res.unwrap(), equal_to(&names(["foo"]))); + assert_that(&res.unwrap(), contains(names(["root", "foo"])).exactly()); } #[test] pub fn test_resolving_multiple_deps() { let mut reg = registry(vec!(pkg!("foo"), pkg!("bar"), pkg!("baz"))); - let res = resolve([dep("foo"), dep("baz")], &mut reg).unwrap(); + let res = resolve(&pkg_id("root"), [dep("foo"), dep("baz")], &mut reg).unwrap(); - assert_that(&res, contains(names(["foo", "baz"])).exactly()); + assert_that(&res, contains(names(["root", "foo", "baz"])).exactly()); } #[test] pub fn test_resolving_transitive_deps() { let mut reg = registry(vec!(pkg!("foo"), pkg!("bar" => "foo"))); - let res = resolve([dep("bar")], &mut reg).unwrap(); + let res = resolve(&pkg_id("root"), [dep("bar")], &mut reg).unwrap(); - assert_that(&res, contains(names(["foo", "bar"]))); + assert_that(&res, contains(names(["root", "foo", "bar"]))); } #[test] pub fn test_resolving_common_transitive_deps() { let mut reg = registry(vec!(pkg!("foo" => "bar"), pkg!("bar"))); - let res = resolve([dep("foo"), dep("bar")], &mut reg).unwrap(); + let res = resolve(&pkg_id("root"), [dep("foo"), dep("bar")], &mut reg).unwrap(); + + assert_that(&res, contains(names(["root", "foo", "bar"]))); + } + + #[test] + pub fn test_resolving_with_same_name() { + let list = vec!(pkg_loc("foo", "http://first.example.com"), + pkg_loc("foo", "http://second.example.com")); + + let mut reg = registry(list); + let res = resolve(&pkg_id("root"), + [dep_loc("foo", "http://first.example.com"), + dep_loc("foo", "http://second.example.com")], + &mut reg); + + let mut names = loc_names([("foo", "http://first.example.com"), + ("foo", "http://second.example.com")]); + + names.push(pkg_id("root")); - assert_that(&res, contains(names(["foo", "bar"]))); + assert_that(&res.unwrap(), contains(names).exactly()); } #[test] @@ -178,8 +291,8 @@ mod test { pkg!("bat") )); - let res = resolve([dep("foo"), dep("baz").as_dev()], &mut reg).unwrap(); + let res = resolve(&pkg_id("root"), [dep("foo"), dep("baz").as_dev()], &mut reg).unwrap(); - assert_that(&res, contains(names(["foo", "bar", "baz"]))); + assert_that(&res, contains(names(["root", "foo", "bar", "baz"]))); } } diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index 32ca19934c6..37a81610240 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -42,7 +42,7 @@ impl MultiShell { &mut self.err } - pub fn say(&mut self, message: T, color: Color) -> IoResult<()> { + pub fn say(&mut self, message: T, color: Color) -> IoResult<()> { self.out().say(message, color) } @@ -60,11 +60,11 @@ impl MultiShell { Ok(()) } - pub fn error(&mut self, message: T) -> IoResult<()> { + pub fn error(&mut self, message: T) -> IoResult<()> { self.err().say(message, RED) } - pub fn warn(&mut self, message: T) -> IoResult<()> { + pub fn warn(&mut self, message: T) -> IoResult<()> { self.err().say(message, YELLOW) } } @@ -96,10 +96,10 @@ impl Shell { Ok(()) } - pub fn say(&mut self, message: T, color: Color) -> IoResult<()> { + pub fn say(&mut self, message: T, color: Color) -> IoResult<()> { try!(self.reset()); if color != BLACK { try!(self.fg(color)); } - try!(self.write_line(message.to_str().as_slice())); + try!(self.write_line(message.to_string().as_slice())); try!(self.reset()); try!(self.flush()); Ok(()) diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index 22590a892f9..6284f755ad8 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -73,7 +73,7 @@ impl> Decodable for Location { impl> Encodable for Location { fn encode(&self, e: &mut S) -> Result<(), E> { - self.to_str().encode(e) + self.to_string().encode(e) } } @@ -137,8 +137,8 @@ impl PartialEq for SourceId { match (&self.kind, &other.kind, &self.location, &other.location) { (&GitKind(..), &GitKind(..), &Remote(ref u1), &Remote(ref u2)) => { - git::canonicalize_url(u1.to_str().as_slice()) == - git::canonicalize_url(u2.to_str().as_slice()) + git::canonicalize_url(u1.to_string().as_slice()) == + git::canonicalize_url(u2.to_string().as_slice()) } _ => false, } @@ -156,7 +156,7 @@ impl SourceId { } pub fn for_git(url: &Url, reference: &str) -> SourceId { - SourceId::new(GitKind(reference.to_str()), Remote(url.clone())) + SourceId::new(GitKind(reference.to_string()), Remote(url.clone())) } pub fn for_central() -> SourceId { diff --git a/src/cargo/core/summary.rs b/src/cargo/core/summary.rs index fcad56a2f69..59cf9e75f5c 100644 --- a/src/cargo/core/summary.rs +++ b/src/cargo/core/summary.rs @@ -48,7 +48,7 @@ pub trait SummaryVec { impl SummaryVec for Vec { // TODO: Move to Registry fn names(&self) -> Vec { - self.iter().map(|summary| summary.get_name().to_str()).collect() + self.iter().map(|summary| summary.get_name().to_string()).collect() } } diff --git a/src/cargo/core/version_req.rs b/src/cargo/core/version_req.rs index 75a5b0df67d..eec15106733 100644 --- a/src/cargo/core/version_req.rs +++ b/src/cargo/core/version_req.rs @@ -487,14 +487,14 @@ mod test { pub fn test_parsing_exact() { let r = req("1.0.0"); - assert!(r.to_str() == "= 1.0.0".to_str()); + assert!(r.to_string() == "= 1.0.0".to_string()); assert_match(&r, ["1.0.0"]); assert_not_match(&r, ["1.0.1", "0.9.9", "0.10.0", "0.1.0"]); let r = req("0.9.0"); - assert!(r.to_str() == "= 0.9.0".to_str()); + assert!(r.to_string() == "= 0.9.0".to_string()); assert_match(&r, ["0.9.0"]); assert_not_match(&r, ["0.9.1", "1.9.0", "0.0.9"]); @@ -504,7 +504,7 @@ mod test { pub fn test_parsing_greater_than() { let r = req(">= 1.0.0"); - assert!(r.to_str() == ">= 1.0.0".to_str()); + assert!(r.to_string() == ">= 1.0.0".to_string()); assert_match(&r, ["1.0.0"]); } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 32a07fd9c13..a20ea11b528 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -2,9 +2,11 @@ #![crate_type="rlib"] #![feature(macro_rules, phase)] +#![feature(default_type_params)] extern crate debug; extern crate term; +extern crate collections; extern crate url; extern crate serialize; extern crate semver; @@ -204,7 +206,7 @@ pub fn handle_error(err: CliError, shell: &mut MultiShell) { if unknown { let _ = shell.error("An unknown error occurred"); } else { - let _ = shell.error(error.to_str()); + let _ = shell.error(error.to_string()); } if error.cause().is_some() { @@ -246,7 +248,7 @@ fn global_flags() -> CliResult { fn json_from_stdin() -> CliResult { let mut reader = io::stdin(); - let input = try!(reader.read_to_str().map_err(|_| { + let input = try!(reader.read_to_string().map_err(|_| { CliError::new("Standard in did not exist or was not UTF-8", 1) })); diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index cadc97a9c44..340ff4c26db 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -24,7 +24,7 @@ use std::os; use util::config::{Config, ConfigValue}; -use core::{MultiShell, Source, SourceId, PackageSet, Target, resolver}; +use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId, resolver}; use core::registry::PackageRegistry; use ops; use sources::{PathSource}; @@ -57,18 +57,22 @@ pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<()> let override_ids = try!(source_ids_from_config()); let source_ids = package.get_source_ids(); - let packages = { + let (packages, resolve) = { let mut config = try!(Config::new(shell, update, jobs)); let mut registry = try!(PackageRegistry::new(source_ids, override_ids, &mut config)); - let resolved = - try!(resolver::resolve(package.get_dependencies(), &mut registry)); + let resolved = try!(resolver::resolve(package.get_package_id(), + package.get_dependencies(), + &mut registry)); - try!(registry.get(resolved.as_slice()).wrap({ + let req: Vec = resolved.iter().map(|r| r.clone()).collect(); + let packages = try!(registry.get(req.as_slice()).wrap({ human("Unable to get packages from source") - })) + })); + + (packages, resolved) }; debug!("packages={}", packages); @@ -78,8 +82,9 @@ pub fn compile(manifest_path: &Path, options: CompileOptions) -> CargoResult<()> }).collect::>(); let mut config = try!(Config::new(shell, update, jobs)); - try!(ops::compile_targets(targets.as_slice(), &package, - &PackageSet::new(packages.as_slice()), &mut config)); + + try!(ops::compile_targets(env.as_slice(), targets.as_slice(), &package, + &PackageSet::new(packages.as_slice()), &resolve, &mut config)); Ok(()) } diff --git a/src/cargo/ops/cargo_rustc.rs b/src/cargo/ops/cargo_rustc.rs index 3d3b5660e06..d8be4f11ab3 100644 --- a/src/cargo/ops/cargo_rustc.rs +++ b/src/cargo/ops/cargo_rustc.rs @@ -6,9 +6,9 @@ use std::os::args; use std::str; use term::color::YELLOW; -use core::{Package, PackageSet, Target}; +use core::{Package, PackageSet, Target, Resolve}; use util; -use util::{CargoResult, ChainError, ProcessBuilder, internal, human, CargoError}; +use util::{CargoResult, ChainError, ProcessBuilder, CargoError, internal, human}; use util::{Config, TaskPool, DependencyQueue, Fresh, Dirty, Freshness}; type Args = Vec; @@ -18,7 +18,10 @@ struct Context<'a, 'b> { deps_dir: &'a Path, primary: bool, rustc_version: &'a str, - config: &'b mut Config<'b> + resolve: &'a Resolve, + package_set: &'a PackageSet, + config: &'b mut Config<'b>, + dylib: (String, String) } type Job = proc():Send -> CargoResult<()>; @@ -41,9 +44,10 @@ fn uniq_target_dest<'a>(targets: &[&'a Target]) -> Option<&'a str> { curr.unwrap() } -pub fn compile_targets<'a>(targets: &[&Target], pkg: &Package, deps: &PackageSet, - config: &'a mut Config<'a>) -> CargoResult<()> { - +pub fn compile_targets<'a>(env: &str, targets: &[&Target], pkg: &Package, + deps: &PackageSet, resolve: &'a Resolve, + config: &'a mut Config<'a>) -> CargoResult<()> +{ if targets.is_empty() { return Ok(()); } @@ -68,12 +72,27 @@ pub fn compile_targets<'a>(targets: &[&Target], pkg: &Package, deps: &PackageSet internal(format!("Couldn't create the directory for dependencies for {} at {}", pkg.get_name(), deps_target_dir.display())))); + let output = try!(util::process("rustc") + .arg("-") + .arg("--crate-name").arg("-") + .arg("--crate-type").arg("dylib") + .arg("--print-file-name") + .exec_with_output()); + + let output = str::from_utf8(output.output.as_slice()).unwrap(); + + let parts: Vec<&str> = output.slice_to(output.len() - 1).split('-').collect(); + assert!(parts.len() == 2, "rustc --print-file-name output has changed"); + let mut cx = Context { dest: &deps_target_dir, deps_dir: &deps_target_dir, primary: false, rustc_version: rustc_version.as_slice(), - config: config + resolve: resolve, + package_set: deps, + config: config, + dylib: (parts.get(0).to_string(), parts.get(1).to_string()) }; // Build up a list of pending jobs, each of which represent compiling a @@ -82,13 +101,17 @@ pub fn compile_targets<'a>(targets: &[&Target], pkg: &Package, deps: &PackageSet // everything in order with proper parallelism. let mut jobs = Vec::new(); for dep in deps.iter() { + if dep == pkg { continue; } + // Only compile lib targets for dependencies let targets = dep.get_targets().iter().filter(|target| { - target.is_lib() && target.get_profile().is_compile() + target.is_lib() && match env { + "test" => target.get_profile().is_compile(), + _ => target.get_profile().get_env() == env, + } }).collect::>(); - jobs.push((dep, - try!(compile(targets.as_slice(), dep, &mut cx)))); + jobs.push((dep, try!(compile(targets.as_slice(), dep, &mut cx)))); } cx.primary = true; @@ -101,7 +124,7 @@ pub fn compile_targets<'a>(targets: &[&Target], pkg: &Package, deps: &PackageSet fn compile(targets: &[&Target], pkg: &Package, cx: &mut Context) -> CargoResult<(Freshness, Job)> { - debug!("compile_pkg; pkg={}; targets={}", pkg, pkg.get_targets()); + debug!("compile_pkg; pkg={}; targets={}", pkg, targets); if targets.is_empty() { return Ok((Fresh, proc() Ok(()))) @@ -135,7 +158,7 @@ fn compile(targets: &[&Target], pkg: &Package, // After the custom command has run, execute rustc for all targets of our // package. for &target in targets.iter() { - cmds.push(rustc(&pkg.get_root(), target, cx)); + cmds.push(rustc(pkg, target, cx)); } cmds.push(proc() { @@ -169,7 +192,7 @@ fn is_fresh(dep: &Package, loc: &Path, Err(..) => return Ok((false, new_fingerprint)), }; - let old_fingerprint = try!(file.read_to_str()); + let old_fingerprint = try!(file.read_to_string()); log!(5, "old fingerprint: {}", old_fingerprint); log!(5, "new fingerprint: {}", new_fingerprint); @@ -207,37 +230,42 @@ fn compile_custom(pkg: &Package, cmd: &str, proc() p.exec_with_output().map(|_| ()).map_err(|e| e.mark_human()) } -fn rustc(root: &Path, target: &Target, cx: &mut Context) -> Job { +fn rustc(package: &Package, target: &Target, cx: &mut Context) -> Job { let crate_types = target.rustc_crate_types(); + let root = package.get_root(); log!(5, "root={}; target={}; crate_types={}; dest={}; deps={}; verbose={}", root.display(), target, crate_types, cx.dest.display(), cx.deps_dir.display(), cx.primary); let primary = cx.primary; - let rustc = prepare_rustc(root, target, crate_types, cx); + let rustc = prepare_rustc(package, target, crate_types, cx); log!(5, "command={}", rustc); - let _ = cx.config.shell().verbose(|shell| shell.status("Running", rustc.to_str())); + let _ = cx.config.shell().verbose(|shell| shell.status("Running", rustc.to_string())); proc() { if primary { - rustc.exec().map_err(|err| human(err.to_str())) + log!(5, "executing primary"); + rustc.exec().map_err(|err| human(err.to_string())) } else { + log!(5, "executing deps"); rustc.exec_with_output().and(Ok(())).map_err(|err| { - human(err.to_str()) + human(err.to_string()) }) } } } -fn prepare_rustc(root: &Path, target: &Target, crate_types: Vec<&str>, - cx: &Context) -> ProcessBuilder { +fn prepare_rustc(package: &Package, target: &Target, crate_types: Vec<&str>, + cx: &Context) -> ProcessBuilder +{ + let root = package.get_root(); let mut args = Vec::new(); build_base_args(&mut args, target, crate_types, cx); - build_deps_args(&mut args, cx); + build_deps_args(&mut args, package, cx); util::process("rustc") .cwd(root.clone()) @@ -253,57 +281,96 @@ fn build_base_args(into: &mut Args, let metadata = target.get_metadata(); // TODO: Handle errors in converting paths into args - into.push(target.get_src_path().display().to_str()); + into.push(target.get_src_path().display().to_string()); - into.push("--crate-name".to_str()); - into.push(target.get_name().to_str()); + into.push("--crate-name".to_string()); + into.push(target.get_name().to_string()); for crate_type in crate_types.iter() { - into.push("--crate-type".to_str()); - into.push(crate_type.to_str()); + into.push("--crate-type".to_string()); + into.push(crate_type.to_string()); } let out = cx.dest.clone(); let profile = target.get_profile(); if profile.get_opt_level() != 0 { - into.push("--opt-level".to_str()); - into.push(profile.get_opt_level().to_str()); + into.push("--opt-level".to_string()); + into.push(profile.get_opt_level().to_string()); } - if profile.get_debug() { - into.push("-g".to_str()); - } + // Right now -g is a little buggy, so we're not passing -g just yet + // if profile.get_debug() { + // into.push("-g".to_string()); + // } if profile.is_test() { - into.push("--test".to_str()); + into.push("--test".to_string()); } match metadata { Some(m) => { - into.push("-C".to_str()); + into.push("-C".to_string()); into.push(format!("metadata={}", m.metadata)); - into.push("-C".to_str()); + into.push("-C".to_string()); into.push(format!("extra-filename={}", m.extra_filename)); } None => {} } if target.is_lib() { - into.push("--out-dir".to_str()); - into.push(out.display().to_str()); + into.push("--out-dir".to_string()); + into.push(out.display().to_string()); + } else { + into.push("-o".to_string()); + into.push(out.join(target.get_name()).display().to_string()); + } +} + +fn build_deps_args(dst: &mut Args, package: &Package, cx: &Context) { + dst.push("-L".to_string()); + dst.push(cx.dest.display().to_string()); + dst.push("-L".to_string()); + dst.push(cx.deps_dir.display().to_string()); + + for target in dep_targets(package, cx).iter() { + dst.push("--extern".to_string()); + dst.push(format!("{}={}/{}", + target.get_name(), + cx.deps_dir.display(), + target_filename(target, cx))); + } +} + +fn target_filename(target: &Target, cx: &Context) -> String { + let stem = target.file_stem(); + + if target.is_dylib() { + let (ref prefix, ref suffix) = cx.dylib; + format!("{}{}{}", prefix, stem, suffix) + } else if target.is_rlib() { + format!("lib{}.rlib", stem) } else { - into.push("-o".to_str()); - into.push(out.join(target.get_name()).display().to_str()); + unreachable!() } } -fn build_deps_args(dst: &mut Args, cx: &Context) { - dst.push("-L".to_str()); - dst.push(cx.dest.display().to_str()); - dst.push("-L".to_str()); - dst.push(cx.deps_dir.display().to_str()); +fn dep_targets(pkg: &Package, cx: &Context) -> Vec { + match cx.resolve.deps(pkg.get_package_id()) { + None => vec!(), + Some(deps) => deps + .map(|pkg_id| { + cx.package_set.iter() + .find(|pkg| pkg_id == pkg.get_package_id()) + .expect("Should have found package") + }) + .filter_map(|pkg| { + pkg.get_targets().iter().find(|&t| t.is_lib() && t.get_profile().is_compile()) + }) + .map(|t| t.clone()) + .collect() + } } /// Execute all jobs necessary to build the dependency graph. diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs index cb8677b3d92..120e91eab12 100644 --- a/src/cargo/sources/git/source.rs +++ b/src/cargo/sources/git/source.rs @@ -65,11 +65,11 @@ fn ident(location: &Location) -> String { let ident = match *location { Local(ref path) => { let last = path.components().last().unwrap(); - str::from_utf8(last).unwrap().to_str() + str::from_utf8(last).unwrap().to_string() } Remote(ref url) => { let path = canonicalize_url(url.path.path.as_slice()); - path.as_slice().split('/').last().unwrap().to_str() + path.as_slice().split('/').last().unwrap().to_string() } }; @@ -79,7 +79,7 @@ fn ident(location: &Location) -> String { ident }; - let location = canonicalize_url(location.to_str().as_slice()); + let location = canonicalize_url(location.to_string().as_slice()); format!("{}-{}", ident, to_hex(hasher.hash(&location.as_slice()))) } diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 73d1c91372b..a94ab58accf 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -19,7 +19,7 @@ impl GitReference { if string.as_slice() == "master" { Master } else { - Other(string.as_slice().to_str()) + Other(string.as_slice().to_string()) } } } @@ -79,7 +79,7 @@ struct EncodableGitRemote { impl> Encodable for GitRemote { fn encode(&self, s: &mut S) -> Result<(), E> { EncodableGitRemote { - location: self.location.to_str() + location: self.location.to_string() }.encode(s) } } @@ -102,7 +102,7 @@ impl> Encodable for GitDatabase { fn encode(&self, s: &mut S) -> Result<(), E> { EncodableGitDatabase { remote: self.remote.clone(), - path: self.path.display().to_str() + path: self.path.display().to_string() }.encode(s) } } @@ -129,9 +129,9 @@ impl> Encodable for GitCheckout { fn encode(&self, s: &mut S) -> Result<(), E> { EncodableGitCheckout { database: self.database.clone(), - location: self.location.display().to_str(), - reference: self.reference.to_str(), - revision: self.revision.to_str() + location: self.location.display().to_string(), + reference: self.reference.to_string(), + revision: self.revision.to_string() }.encode(s) } } @@ -182,8 +182,8 @@ impl GitRemote { fn fetch_location(&self) -> String { match self.location { - Local(ref p) => p.display().to_str(), - Remote(ref u) => u.to_str(), + Local(ref p) => p.display().to_string(), + Remote(ref u) => u.to_string(), } } } @@ -308,10 +308,10 @@ fn git_output(path: &Path, str: String) -> CargoResult { .chain_error(|| human(format!("Executing `git {}` failed", str)))); - Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str()) + Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_string()) } fn to_str(vec: &[u8]) -> String { - str::from_utf8_lossy(vec).to_str() + str::from_utf8_lossy(vec).to_string() } diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index e5a2a5757e7..dc19769563b 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -102,7 +102,7 @@ impl Source for PathSource { let loc = pkg.get_manifest_path().dir_path(); max = cmp::max(max, try!(walk(&loc, true))); } - return Ok(max.to_str()); + return Ok(max.to_string()); fn walk(path: &Path, is_root: bool) -> CargoResult { if !path.is_dir() { diff --git a/src/cargo/util/config.rs b/src/cargo/util/config.rs index e733f672e85..de48b375d9e 100644 --- a/src/cargo/util/config.rs +++ b/src/cargo/util/config.rs @@ -118,7 +118,7 @@ impl> Encodable for ConfigValue { impl fmt::Show for ConfigValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let paths: Vec = self.path.iter().map(|p| { - p.display().to_str() + p.display().to_string() }).collect(); write!(f, "{} (from {})", self.value, paths) } @@ -184,16 +184,16 @@ fn walk_tree(pwd: &Path, } fn extract_config(mut file: io::fs::File, key: &str) -> CargoResult { - let contents = try!(file.read_to_str()); + let contents = try!(file.read_to_string()); let toml = try!(cargo_toml::parse(contents.as_slice(), file.path().filename_display() - .to_str().as_slice())); + .to_string().as_slice())); let val = try!(toml.find_equiv(&key).require(|| internal(""))); let v = match *val { toml::String(ref val) => String(val.clone()), toml::Array(ref val) => { - List(val.iter().map(|s: &toml::Value| s.to_str()).collect()) + List(val.iter().map(|s: &toml::Value| s.to_string()).collect()) } _ => return Err(internal("")) }; @@ -204,8 +204,8 @@ fn extract_config(mut file: io::fs::File, key: &str) -> CargoResult fn extract_all_configs(mut file: io::fs::File, map: &mut HashMap) -> CargoResult<()> { let path = file.path().clone(); - let contents = try!(file.read_to_str()); - let file = path.filename_display().to_str(); + let contents = try!(file.read_to_string()); + let file = path.filename_display().to_string(); let table = try!(cargo_toml::parse(contents.as_slice(), file.as_slice()).chain_error(|| { internal(format!("could not parse Toml manifest; path={}", diff --git a/src/cargo/util/dependency_queue.rs b/src/cargo/util/dependency_queue.rs index 1f4d29be5cc..bb651207e8c 100644 --- a/src/cargo/util/dependency_queue.rs +++ b/src/cargo/util/dependency_queue.rs @@ -61,7 +61,7 @@ impl DependencyQueue { /// /// Only registered packages will be returned from dequeue(). pub fn register(&mut self, pkg: &Package) { - self.reverse_dep_map.insert(pkg.get_name().to_str(), HashSet::new()); + self.reverse_dep_map.insert(pkg.get_name().to_string(), HashSet::new()); } /// Adds a new package to this dependency queue. @@ -70,10 +70,10 @@ impl DependencyQueue { /// be added to the dependency queue. pub fn enqueue(&mut self, pkg: &Package, fresh: Freshness, data: T) { // ignore self-deps - if self.pkgs.contains_key(&pkg.get_name().to_str()) { return } + if self.pkgs.contains_key(&pkg.get_name().to_string()) { return } if fresh == Dirty { - self.dirty.insert(pkg.get_name().to_str()); + self.dirty.insert(pkg.get_name().to_string()); } let mut my_dependencies = HashSet::new(); @@ -84,12 +84,12 @@ impl DependencyQueue { continue } - let name = dep.get_name().to_str(); + let name = dep.get_name().to_string(); assert!(my_dependencies.insert(name.clone())); let rev = self.reverse_dep_map.find_or_insert(name, HashSet::new()); - assert!(rev.insert(pkg.get_name().to_str())); + assert!(rev.insert(pkg.get_name().to_string())); } - assert!(self.pkgs.insert(pkg.get_name().to_str(), + assert!(self.pkgs.insert(pkg.get_name().to_string(), (my_dependencies, data))); } @@ -100,7 +100,7 @@ impl DependencyQueue { pub fn dequeue(&mut self) -> Option<(String, Freshness, T)> { let pkg = match self.pkgs.iter() .find(|&(_, &(ref deps, _))| deps.len() == 0) - .map(|(ref name, _)| name.to_str()) { + .map(|(ref name, _)| name.to_string()) { Some(pkg) => pkg, None => return None }; diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 3d9953b04aa..902f8cd375f 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -120,20 +120,20 @@ impl ChainError for Result { } impl CargoError for IoError { - fn description(&self) -> String { self.to_str() } + fn description(&self) -> String { self.to_string() } } from_error!(IoError) impl CargoError for TomlError { - fn description(&self) -> String { self.to_str() } + fn description(&self) -> String { self.to_string() } } from_error!(TomlError) impl CargoError for FormatError { fn description(&self) -> String { - "formatting failed".to_str() + "formatting failed".to_string() } } @@ -152,8 +152,8 @@ from_error!(ProcessError) impl Show for ProcessError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let exit = match self.exit { - Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_str(), - None => "never executed".to_str() + Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_string(), + None => "never executed".to_string() }; try!(write!(f, "{} (status={})", self.msg, exit)); match self.output { @@ -178,7 +178,7 @@ impl Show for ProcessError { } impl CargoError for ProcessError { - fn description(&self) -> String { self.to_str() } + fn description(&self) -> String { self.to_string() } fn detail(&self) -> Option { self.detail.clone() @@ -248,7 +248,7 @@ pub struct CliError { impl CargoError for CliError { fn description(&self) -> String { - self.error.to_str() + self.error.to_string() } } @@ -256,7 +256,7 @@ from_error!(CliError) impl CliError { pub fn new(error: S, code: uint) -> CliError { - let error = human(error.as_slice().to_str()); + let error = human(error.as_slice().to_string()); CliError::from_boxed(error, code) } @@ -276,7 +276,7 @@ pub fn process_error(msg: S, status: Option<&ProcessExit>, output: Option<&ProcessOutput>) -> ProcessError { ProcessError { - msg: msg.as_slice().to_str(), + msg: msg.as_slice().to_string(), exit: status.map(|o| o.clone()), output: output.map(|o| o.clone()), detail: None, @@ -287,8 +287,8 @@ pub fn process_error(msg: S, pub fn internal_error(error: S1, detail: S2) -> Box { box ConcreteCargoError { - description: error.as_slice().to_str(), - detail: Some(detail.as_slice().to_str()), + description: error.as_slice().to_string(), + detail: Some(detail.as_slice().to_string()), cause: None, is_human: false } as Box @@ -296,7 +296,7 @@ pub fn internal_error(error: S1, pub fn internal(error: S) -> Box { box ConcreteCargoError { - description: error.to_str(), + description: error.to_string(), detail: None, cause: None, is_human: false @@ -305,7 +305,7 @@ pub fn internal(error: S) -> Box { pub fn human(error: S) -> Box { box ConcreteCargoError { - description: error.to_str(), + description: error.to_string(), detail: None, cause: None, is_human: true diff --git a/src/cargo/util/graph.rs b/src/cargo/util/graph.rs index 7fc62aa3c12..cf96c2d47eb 100644 --- a/src/cargo/util/graph.rs +++ b/src/cargo/util/graph.rs @@ -1,8 +1,9 @@ use std::hash::Hash; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; +use std::collections::hashmap::{Keys, SetItems}; pub struct Graph { - nodes: HashMap> + nodes: HashMap> } enum Mark { @@ -10,13 +11,30 @@ enum Mark { Done } +pub type Nodes<'a, N> = Keys<'a, N, HashSet>; +pub type Edges<'a, N> = SetItems<'a, N>; + impl Graph { pub fn new() -> Graph { Graph { nodes: HashMap::new() } } pub fn add(&mut self, node: N, children: &[N]) { - self.nodes.insert(node, children.to_owned()); + self.nodes.insert(node, children.iter().map(|n| n.clone()).collect()); + } + + pub fn link(&mut self, node: N, child: N) { + self.nodes + .find_or_insert_with(node, |_| HashSet::new()) + .insert(child); + } + + pub fn get_nodes<'a>(&'a self) -> &'a HashMap> { + &self.nodes + } + + pub fn edges<'a>(&'a self, node: &N) -> Option> { + self.nodes.find(node).map(|set| set.iter()) } pub fn sort(&self) -> Option> { @@ -44,4 +62,8 @@ impl Graph { dst.push(node.clone()); marks.insert(node.clone(), Done); } + + pub fn iter<'a>(&'a self) -> Nodes<'a, N> { + self.nodes.keys() + } } diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 12f86c7d96d..71240d00676 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -8,6 +8,7 @@ pub use self::paths::realpath; pub use self::hex::{to_hex, short_hash}; pub use self::pool::TaskPool; pub use self::dependency_queue::{DependencyQueue, Fresh, Dirty, Freshness}; +pub use self::graph::Graph; pub mod graph; pub mod process_builder; diff --git a/src/cargo/util/process_builder.rs b/src/cargo/util/process_builder.rs index 772109404d3..7b286e8929d 100644 --- a/src/cargo/util/process_builder.rs +++ b/src/cargo/util/process_builder.rs @@ -36,12 +36,12 @@ static PATH_SEP : &'static str = ";"; impl ProcessBuilder { pub fn arg(mut self, arg: T) -> ProcessBuilder { - self.args.push(arg.as_slice().to_str()); + self.args.push(arg.as_slice().to_string()); self } pub fn args(mut self, arguments: &[T]) -> ProcessBuilder { - self.args = arguments.iter().map(|a| a.as_slice().to_str()).collect(); + self.args = arguments.iter().map(|a| a.as_slice().to_string()).collect(); self } @@ -51,7 +51,7 @@ impl ProcessBuilder { pub fn extra_path(mut self, path: Path) -> ProcessBuilder { // For now, just convert to a string, but we should do something better - self.path.unshift(path.display().to_str()); + self.path.unshift(path.display().to_string()); self } @@ -63,10 +63,10 @@ impl ProcessBuilder { pub fn env(mut self, key: &str, val: Option<&str>) -> ProcessBuilder { match val { Some(v) => { - self.env.insert(key.to_str(), v.to_str()); + self.env.insert(key.to_string(), v.to_string()); }, None => { - self.env.remove(&key.to_str()); + self.env.remove(&key.to_string()); } } @@ -139,7 +139,7 @@ impl ProcessBuilder { } match self.build_path() { - Some(path) => ret.push(("PATH".to_str(), path)), + Some(path) => ret.push(("PATH".to_string(), path)), _ => () } diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index d7713194a47..854609c2fa8 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -198,9 +198,9 @@ struct Context<'a> { fn inferred_lib_target(name: &str, layout: &Layout) -> Option> { layout.lib.as_ref().map(|lib| { vec![TomlTarget { - name: name.to_str(), + name: name.to_string(), crate_type: None, - path: Some(lib.display().to_str()), + path: Some(lib.display().to_string()), test: None }] }) @@ -209,16 +209,16 @@ fn inferred_lib_target(name: &str, layout: &Layout) -> Option> { fn inferred_bin_targets(name: &str, layout: &Layout) -> Option> { Some(layout.bins.iter().filter_map(|bin| { let name = if bin.as_str() == Some("src/main.rs") { - Some(name.to_str()) + Some(name.to_string()) } else { - bin.filestem_str().map(|f| f.to_str()) + bin.filestem_str().map(|f| f.to_string()) }; name.map(|name| { TomlTarget { name: name, crate_type: None, - path: Some(bin.display().to_str()), + path: Some(bin.display().to_string()), test: None } }) @@ -252,7 +252,7 @@ impl TomlManifest { TomlTarget { name: t.name.clone(), crate_type: t.crate_type.clone(), - path: layout.lib.as_ref().map(|p| p.display().to_str()), + path: layout.lib.as_ref().map(|p| p.display().to_string()), test: t.test } } else { @@ -271,7 +271,7 @@ impl TomlManifest { TomlTarget { name: t.name.clone(), crate_type: t.crate_type.clone(), - path: bin.as_ref().map(|p| p.display().to_str()), + path: bin.as_ref().map(|p| p.display().to_string()), test: t.test } } else { @@ -336,7 +336,7 @@ fn process_dependencies<'a>(cx: &mut Context<'a>, dev: bool, let reference = details.branch.clone() .or_else(|| details.tag.clone()) .or_else(|| details.rev.clone()) - .unwrap_or_else(|| "master".to_str()); + .unwrap_or_else(|| "master".to_string()); let new_source_id = match details.git { Some(ref git) => { @@ -386,25 +386,34 @@ fn normalize(lib: Option<&[TomlLibTarget]>, { log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin); - fn target_profiles(target: &TomlTarget) -> Vec { + enum TestDep { Needed, NotNeeded } + + fn target_profiles(target: &TomlTarget, + dep: Option) -> Vec { let mut ret = vec!(Profile::default_dev(), Profile::default_release()); match target.test { Some(true) | None => ret.push(Profile::default_test()), + Some(false) => {} + } + + match dep { + Some(Needed) => ret.push(Profile::default_test().test(false)), _ => {} - }; + } ret } - fn lib_targets(dst: &mut Vec, libs: &[TomlLibTarget], metadata: &Metadata) { + fn lib_targets(dst: &mut Vec, libs: &[TomlLibTarget], + dep: TestDep, metadata: &Metadata) { let l = &libs[0]; let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name)); let crate_types = l.crate_type.clone().and_then(|kinds| { LibKind::from_strs(kinds).ok() }).unwrap_or_else(|| vec!(Lib)); - for profile in target_profiles(l).iter() { + for profile in target_profiles(l, Some(dep)).iter() { dst.push(Target::lib_target(l.name.as_slice(), crate_types.clone(), &Path::new(path.as_slice()), profile, metadata)); @@ -416,7 +425,7 @@ fn normalize(lib: Option<&[TomlLibTarget]>, for bin in bins.iter() { let path = bin.path.clone().unwrap_or_else(|| default(bin)); - for profile in target_profiles(bin).iter() { + for profile in target_profiles(bin, None).iter() { dst.push(Target::bin_target(bin.name.as_slice(), &Path::new(path.as_slice()), profile)); @@ -428,12 +437,12 @@ fn normalize(lib: Option<&[TomlLibTarget]>, match (lib, bin) { (Some(ref libs), Some(ref bins)) => { - lib_targets(&mut ret, libs.as_slice(), metadata); + lib_targets(&mut ret, libs.as_slice(), Needed, metadata); bin_targets(&mut ret, bins.as_slice(), |bin| format!("src/bin/{}.rs", bin.name)); }, (Some(ref libs), None) => { - lib_targets(&mut ret, libs.as_slice(), metadata); + lib_targets(&mut ret, libs.as_slice(), NotNeeded, metadata); }, (None, Some(ref bins)) => { bin_targets(&mut ret, bins.as_slice(), diff --git a/tests/support/mod.rs b/tests/support/mod.rs index 9dfcd696ba9..90a3542ff91 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -30,7 +30,7 @@ struct FileBuilder { impl FileBuilder { pub fn new(path: Path, body: &str) -> FileBuilder { - FileBuilder { path: path, body: body.to_str() } + FileBuilder { path: path, body: body.to_string() } } fn mk(&self) -> Result<(), String> { @@ -86,7 +86,7 @@ pub struct ProjectBuilder { impl ProjectBuilder { pub fn new(name: &str, root: Path) -> ProjectBuilder { ProjectBuilder { - name: name.to_str(), + name: name.to_string(), root: root, files: vec!(), symlinks: vec!() @@ -108,7 +108,7 @@ impl ProjectBuilder { pub fn process(&self, program: T) -> ProcessBuilder { process(program) .cwd(self.root()) - .env("HOME", Some(paths::home().display().to_str().as_slice())) + .env("HOME", Some(paths::home().display().to_string().as_slice())) .extra_path(cargo_dir()) } @@ -195,7 +195,7 @@ pub fn main_file(println: T, deps: &[&str]) -> String { buf.push_str(println.as_slice()); buf.push_str("); }\n"); - buf.to_str() + buf.to_string() } trait ErrMsg { @@ -238,13 +238,13 @@ struct Execs { impl Execs { - pub fn with_stdout(mut ~self, expected: S) -> Box { - self.expect_stdout = Some(expected.to_str()); + pub fn with_stdout(mut ~self, expected: S) -> Box { + self.expect_stdout = Some(expected.to_string()); self } - pub fn with_stderr(mut ~self, expected: S) -> Box { - self.expect_stderr = Some(expected.to_str()); + pub fn with_stderr(mut ~self, expected: S) -> Box { + self.expect_stderr = Some(expected.to_string()); self } @@ -310,7 +310,7 @@ impl Execs { impl ham::SelfDescribing for Execs { fn describe(&self) -> String { - "execs".to_str() + "execs".to_string() } } @@ -354,13 +354,13 @@ impl<'a> ham::Matcher<&'a [u8]> for ShellWrites { { println!("{}", actual); let actual = std::str::from_utf8_lossy(actual); - let actual = actual.to_str(); + let actual = actual.to_string(); ham::expect(actual == self.expected, actual) } } pub fn shell_writes(string: T) -> Box { - box ShellWrites { expected: string.to_str() } + box ShellWrites { expected: string.to_string() } } pub trait ResultTest { @@ -397,7 +397,7 @@ impl Tap for T { } pub fn escape_path(p: &Path) -> String { - p.display().to_str().as_slice().replace("\\", "\\\\") + p.display().to_string().as_slice().replace("\\", "\\\\") } pub fn basic_bin_manifest(name: &str) -> String { @@ -414,6 +414,7 @@ pub fn basic_bin_manifest(name: &str) -> String { "#, name, name) } +pub static RUNNING: &'static str = " Running"; pub static COMPILING: &'static str = " Compiling"; pub static FRESH: &'static str = " Fresh"; pub static UPDATING: &'static str = " Updating"; diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index 0cc9214ee83..57ef09cebce 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -1,9 +1,10 @@ use std::io::fs; use std::os; use std::path; +use std::str; use support::{ResultTest, project, execs, main_file, escape_path, basic_bin_manifest}; -use support::COMPILING; +use support::{COMPILING, RUNNING}; use hamcrest::{assert_that, existing_file}; use cargo; use cargo::util::{process, realpath}; @@ -92,7 +93,7 @@ test!(cargo_compile_with_invalid_code { {filename}:1 invalid rust code! ^~~~~~~ Could not execute process \ -`rustc {filename} --crate-name foo --crate-type bin -g -o {} -L {} -L {}` (status=101)\n", +`rustc {filename} --crate-name foo --crate-type bin -o {} -L {} -L {}` (status=101)\n", target.join("foo").display(), target.display(), target.join("deps").display(), @@ -152,7 +153,7 @@ test!(cargo_compile_with_warnings_in_a_dep_package { "#) .file("bar/src/bar.rs", r#" pub fn gimme() -> String { - "test passed".to_str() + "test passed".to_string() } fn dead() {} @@ -229,7 +230,7 @@ test!(cargo_compile_with_nested_deps_inferred { "#) .file("baz/src/lib.rs", r#" pub fn gimme() -> String { - "test passed".to_str() + "test passed".to_string() } "#); @@ -297,7 +298,7 @@ test!(cargo_compile_with_nested_deps_correct_bin { "#) .file("baz/src/lib.rs", r#" pub fn gimme() -> String { - "test passed".to_str() + "test passed".to_string() } "#); @@ -373,7 +374,7 @@ test!(cargo_compile_with_nested_deps_shorthand { "#) .file("baz/src/baz.rs", r#" pub fn gimme() -> String { - "test passed".to_str() + "test passed".to_string() } "#); @@ -449,7 +450,7 @@ test!(cargo_compile_with_nested_deps_longhand { "#) .file("baz/src/baz.rs", r#" pub fn gimme() -> String { - "test passed".to_str() + "test passed".to_string() } "#); @@ -691,8 +692,8 @@ test!(custom_build_env_vars { .file("src/foo.rs", format!(r#" use std::os; fn main() {{ - assert_eq!(os::getenv("OUT_DIR").unwrap(), "{}".to_str()); - assert_eq!(os::getenv("DEPS_DIR").unwrap(), "{}".to_str()); + assert_eq!(os::getenv("OUT_DIR").unwrap(), "{}".to_string()); + assert_eq!(os::getenv("DEPS_DIR").unwrap(), "{}".to_string()); }} "#, escape_path(&p.root().join("target")), @@ -736,8 +737,8 @@ test!(custom_build_in_dependency { .file("src/foo.rs", format!(r#" use std::os; fn main() {{ - assert_eq!(os::getenv("OUT_DIR").unwrap(), "{}".to_str()); - assert_eq!(os::getenv("DEPS_DIR").unwrap(), "{}".to_str()); + assert_eq!(os::getenv("OUT_DIR").unwrap(), "{}".to_string()); + assert_eq!(os::getenv("DEPS_DIR").unwrap(), "{}".to_string()); }} "#, escape_path(&p.root().join("target/deps")), @@ -807,7 +808,7 @@ test!(many_crate_types_old_style_lib_location { match f.filename_str().unwrap() { "deps" => None, s if s.contains("fingerprint") || s.contains("dSYM") => None, - s => Some(s.to_str()) + s => Some(s.to_string()) } }).collect(); files.sort(); @@ -845,7 +846,7 @@ test!(many_crate_types_correct { match f.filename_str().unwrap() { "deps" => None, s if s.contains("fingerprint") || s.contains("dSYM") => None, - s => Some(s.to_str()) + s => Some(s.to_string()) } }).collect(); files.sort(); @@ -954,3 +955,120 @@ test!(missing_lib_and_bin { .with_stderr("either a [[lib]] or [[bin]] section \ must be present\n")); }) + +test!(verbose_build { + let mut p = project("foo"); + p = p + .file("Cargo.toml", r#" + [package] + + name = "test" + version = "0.0.0" + authors = [] + "#) + .file("src/lib.rs", ""); + let output = p.cargo_process("cargo-build").arg("-v") + .exec_with_output().assert(); + let out = str::from_utf8(output.output.as_slice()).assert(); + let hash = out.slice_from(out.find_str("extra-filename=").unwrap() + 15); + let hash = hash.slice_to(17); + assert_eq!(out, format!("\ +{} `rustc {dir}{sep}src{sep}lib.rs --crate-name test --crate-type lib \ + -C metadata=test:-:0.0.0:-:file:{dir} \ + -C extra-filename={hash} \ + --out-dir {dir}{sep}target \ + -L {dir}{sep}target \ + -L {dir}{sep}target{sep}deps` +{} test v0.0.0 (file:{dir})\n", + RUNNING, COMPILING, + dir = p.root().display(), + sep = path::SEP, + hash = hash).as_slice()); +}) + +test!(verbose_release_build { + let mut p = project("foo"); + p = p + .file("Cargo.toml", r#" + [package] + + name = "test" + version = "0.0.0" + authors = [] + "#) + .file("src/lib.rs", ""); + let output = p.cargo_process("cargo-build").arg("-v").arg("--release") + .exec_with_output().assert(); + let out = str::from_utf8(output.output.as_slice()).assert(); + let hash = out.slice_from(out.find_str("extra-filename=").unwrap() + 15); + let hash = hash.slice_to(17); + assert_eq!(out, format!("\ +{} `rustc {dir}{sep}src{sep}lib.rs --crate-name test --crate-type lib \ + --opt-level 3 \ + -C metadata=test:-:0.0.0:-:file:{dir} \ + -C extra-filename={hash} \ + --out-dir {dir}{sep}target{sep}release \ + -L {dir}{sep}target{sep}release \ + -L {dir}{sep}target{sep}release{sep}deps` +{} test v0.0.0 (file:{dir})\n", + RUNNING, COMPILING, + dir = p.root().display(), + sep = path::SEP, + hash = hash).as_slice()); +}) + +test!(verbose_release_build_deps { + let mut p = project("foo"); + p = p + .file("Cargo.toml", r#" + [package] + + name = "test" + version = "0.0.0" + authors = [] + + [dependencies.foo] + path = "foo" + "#) + .file("src/lib.rs", "") + .file("foo/Cargo.toml", r#" + [package] + + name = "foo" + version = "0.0.0" + authors = [] + "#) + .file("foo/src/lib.rs", ""); + let output = p.cargo_process("cargo-build").arg("-v").arg("--release") + .exec_with_output().assert(); + let out = str::from_utf8(output.output.as_slice()).assert(); + let pos1 = out.find_str("extra-filename=").unwrap(); + let hash1 = out.slice_from(pos1 + 15).slice_to(17); + let pos2 = out.slice_from(pos1 + 10).find_str("extra-filename=").unwrap(); + let hash2 = out.slice_from(pos1 + 10 + pos2 + 15).slice_to(17); + assert_eq!(out, format!("\ +{running} `rustc {dir}{sep}foo{sep}src{sep}lib.rs --crate-name foo \ + --crate-type lib \ + --opt-level 3 \ + -C metadata=foo:-:0.0.0:-:file:{dir} \ + -C extra-filename={hash1} \ + --out-dir {dir}{sep}target{sep}release{sep}deps \ + -L {dir}{sep}target{sep}release{sep}deps \ + -L {dir}{sep}target{sep}release{sep}deps` +{running} `rustc {dir}{sep}src{sep}lib.rs --crate-name test --crate-type lib \ + --opt-level 3 \ + -C metadata=test:-:0.0.0:-:file:{dir} \ + -C extra-filename={hash2} \ + --out-dir {dir}{sep}target{sep}release \ + -L {dir}{sep}target{sep}release \ + -L {dir}{sep}target{sep}release{sep}deps \ + --extern foo={dir}{sep}target{sep}release{sep}deps/libfoo{hash1}.rlib` +{compiling} foo v0.0.0 (file:{dir}) +{compiling} test v0.0.0 (file:{dir})\n", + running = RUNNING, + compiling = COMPILING, + dir = p.root().display(), + sep = path::SEP, + hash1 = hash1, + hash2 = hash2).as_slice()); +}) diff --git a/tests/test_cargo_compile_path_deps.rs b/tests/test_cargo_compile_path_deps.rs index 42a25f10c4c..3b031301c6d 100644 --- a/tests/test_cargo_compile_path_deps.rs +++ b/tests/test_cargo_compile_path_deps.rs @@ -66,7 +66,7 @@ test!(cargo_compile_with_nested_deps_shorthand { "#) .file("bar/baz/src/baz.rs", r#" pub fn gimme() -> String { - "test passed".to_str() + "test passed".to_string() } "#); @@ -97,32 +97,28 @@ test!(cargo_compile_with_root_dev_deps { [dev-dependencies.bar] version = "0.5.0" - path = "bar" + path = "../bar" [[bin]] - name = "foo" "#) - .file("src/foo.rs", - main_file(r#""{}", bar::gimme()"#, ["bar"]).as_slice()) - .file("bar/Cargo.toml", r#" - [project] + .file("src/main.rs", + main_file(r#""{}", bar::gimme()"#, ["bar"]).as_slice()); + let p2 = project("bar") + .file("Cargo.toml", r#" + [package] name = "bar" version = "0.5.0" authors = ["wycats@example.com"] - - [[lib]] - - name = "bar" "#) - .file("bar/src/bar.rs", r#" + .file("src/lib.rs", r#" pub fn gimme() -> &'static str { "zoidberg" } - "#) - ; + "#); + p2.build(); assert_that(p.cargo_process("cargo-build"), execs().with_stdout(format!("{} bar v0.5.0 (file:{})\n\ {} foo v0.5.0 (file:{})\n", diff --git a/tests/test_cargo_test.rs b/tests/test_cargo_test.rs index 426f0f2e4fb..bdc429a4ec3 100644 --- a/tests/test_cargo_test.rs +++ b/tests/test_cargo_test.rs @@ -1,4 +1,7 @@ +use std::str; + use support::{project, execs, basic_bin_manifest, COMPILING, cargo_dir}; +use support::{ResultTest}; use hamcrest::{assert_that, existing_file}; use cargo::util::process; @@ -38,3 +41,94 @@ test!(cargo_test_simple { assert_that(&p.bin("test/foo"), existing_file()); }) + +test!(test_with_lib_dep { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", " + pub fn foo(){} + #[test] fn lib_test() {} + ") + .file("src/main.rs", " + extern crate foo; + + fn main() {} + + #[test] + fn bin_test() {} + "); + + let output = p.cargo_process("cargo-test") + .exec_with_output().assert(); + let out = str::from_utf8(output.output.as_slice()).assert(); + + let bin = "\ +running 1 test +test bin_test ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured"; + let lib = "\ +running 1 test +test lib_test ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured"; + + let head = format!("{compiling} foo v0.0.1 (file:{dir})", + compiling = COMPILING, dir = p.root().display()); + + assert!(out == format!("{}\n\n{}\n\n\n{}\n\n", head, bin, lib).as_slice() || + out == format!("{}\n\n{}\n\n\n{}\n\n", head, lib, bin).as_slice()); +}) + +test!(test_with_deep_lib_dep { + let p = project("bar") + .file("Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + + [dependencies.foo] + path = "../foo" + "#) + .file("src/lib.rs", " + extern crate foo; + #[test] + fn bar_test() { + foo::foo(); + } + "); + let p2 = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", " + pub fn foo() {} + + #[test] + fn foo_test() {} + "); + + p2.build(); + assert_that(p.cargo_process("cargo-test"), + execs().with_status(0) + .with_stdout(format!("\ +{compiling} foo v0.0.1 (file:{dir}) +{compiling} bar v0.0.1 (file:{dir}) + +running 1 test +test bar_test ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured\n\n\ + ", + compiling = COMPILING, + dir = p.root().display()).as_slice())); +}) diff --git a/tests/test_shell.rs b/tests/test_shell.rs index aa6d6bb07ce..e7dc72eb7b5 100644 --- a/tests/test_shell.rs +++ b/tests/test_shell.rs @@ -56,5 +56,5 @@ fn colored_output(string: S, color: color::Color) -> IoResult { try!(term.write_str(string.as_slice())); try!(term.reset()); try!(term.flush()); - Ok(from_utf8_lossy(term.get_ref().get_ref()).to_str()) + Ok(from_utf8_lossy(term.get_ref().get_ref()).to_string()) }