Thread the shell through more of the system

This commit is contained in:
Yehuda Katz 2014-06-21 22:22:56 -07:00
parent 687035657d
commit 19bea0ad0c
18 changed files with 270 additions and 179 deletions

View File

@ -14,6 +14,7 @@ extern crate serialize;
use std::os;
use cargo::{execute_main_without_stdin};
use cargo::ops;
use cargo::core::MultiShell;
use cargo::util::{CliResult, CliError};
use cargo::util::important_paths::find_project;
@ -28,7 +29,7 @@ fn main() {
execute_main_without_stdin(execute);
}
fn execute(options: Options) -> CliResult<Option<()>> {
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
debug!("executing; cmd=cargo-compile; args={}", os::args());
let root = match options.manifest_path {
@ -42,7 +43,7 @@ fn execute(options: Options) -> CliResult<Option<()>> {
}))
};
ops::compile(&root).map(|_| None).map_err(|err| {
ops::compile(&root, shell).map(|_| None).map_err(|err| {
CliError::from_boxed(err, 101)
})
}

View File

@ -9,6 +9,7 @@ extern crate url;
extern crate hammer;
use cargo::{execute_main_without_stdin};
use cargo::core::MultiShell;
use cargo::core::source::{Source,SourceId};
use cargo::sources::git::{GitSource};
use cargo::util::{Config, CliResult, CliError, Require, human};
@ -26,7 +27,7 @@ fn main() {
execute_main_without_stdin(execute);
}
fn execute(options: Options) -> CliResult<Option<()>> {
fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
let Options { url, reference, .. } = options;
let url: Url = try!(from_str(url.as_slice())
@ -36,8 +37,8 @@ fn execute(options: Options) -> CliResult<Option<()>> {
let source_id = SourceId::for_git(&url, reference.as_slice());
let config = try!(Config::new().map_err(|e| CliError::from_boxed(e, 1)));
let mut source = GitSource::new(&source_id, &config);
let mut config = try!(Config::new(shell).map_err(|e| CliError::from_boxed(e, 1)));
let mut source = GitSource::new(&source_id, &mut config);
try!(source.update().map_err(|e| {
CliError::new(format!("Couldn't update {}: {}", source, e), 1)

View File

@ -8,7 +8,7 @@ extern crate serialize;
extern crate hammer;
use cargo::{execute_main_without_stdin};
use cargo::core::{Package, Source, SourceId};
use cargo::core::{MultiShell, Package, Source, SourceId};
use cargo::util::{CliResult, CliError};
use cargo::sources::{PathSource};
@ -23,7 +23,7 @@ fn main() {
execute_main_without_stdin(execute);
}
fn execute(options: Options) -> CliResult<Option<Package>> {
fn execute(options: Options, _: &mut MultiShell) -> CliResult<Option<Package>> {
let path = Path::new(options.manifest_path.as_slice());
let source_id = SourceId::for_path(&path);
let mut source = PathSource::new(&source_id);

View File

@ -11,7 +11,8 @@ use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error};
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};
@ -34,7 +35,7 @@ fn execute() {
let (cmd, args) = match process(os::args()) {
Ok((cmd, args)) => (cmd, args),
Err(err) => return handle_error(err, false)
Err(err) => return handle_error(err, &mut shell(), false)
};
match cmd.as_slice() {
@ -68,9 +69,9 @@ fn execute() {
match command {
Ok(ExitStatus(0)) => (),
Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
handle_error(CliError::new("", i as uint), false)
handle_error(CliError::new("", i as uint), &mut shell(), false)
}
Err(_) => handle_error(CliError::new("No such subcommand", 127), false)
Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(), false)
}
}
}
@ -104,7 +105,7 @@ impl FlagConfig for ConfigForKeyFlags {
}
}
fn config_for_key(args: ConfigForKeyFlags) -> CliResult<Option<ConfigOut>> {
fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
let value = try!(config::get_config(os::getcwd(),
args.key.as_slice()).map_err(|_| {
CliError::new("Couldn't load configuration", 1)
@ -132,7 +133,7 @@ impl FlagConfig for ConfigListFlags {
}
}
fn config_list(args: ConfigListFlags) -> CliResult<Option<ConfigOut>> {
fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
CliError::new("Couldn't load configuration", 1)));
@ -146,7 +147,7 @@ fn config_list(args: ConfigListFlags) -> CliResult<Option<ConfigOut>> {
}
}
fn locate_project(_: NoFlags) -> CliResult<Option<ProjectLocation>> {
fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
CliError::from_boxed(e, 1)
}));

View File

@ -32,6 +32,7 @@ pub use self::summary::{
pub use self::shell::{
Shell,
MultiShell,
ShellConfig
};

View File

@ -118,7 +118,7 @@ impl Package {
ret
}
pub fn get_fingerprint(&self, config: &Config) -> CargoResult<String> {
pub fn get_fingerprint(&self, config: &mut Config) -> CargoResult<String> {
let mut sources = self.get_source_ids();
// Sort the sources just to make sure we have a consistent fingerprint.
sources.sort_by(|a, b| {

View File

@ -1,5 +1,5 @@
use std::vec::Vec;
use core::{Source, SourceId, Summary, Dependency, PackageId, Package};
use core::{MultiShell, Source, SourceId, Summary, Dependency, PackageId, Package};
use util::{CargoResult, ChainError, Config, human};
pub trait Registry {
@ -15,17 +15,20 @@ impl Registry for Vec<Summary> {
}
}
pub struct PackageRegistry {
pub struct PackageRegistry<'a> {
sources: Vec<Box<Source>>,
overrides: Vec<Summary>,
summaries: Vec<Summary>,
searched: Vec<SourceId>
searched: Vec<SourceId>,
shell: &'a mut MultiShell
}
impl PackageRegistry {
pub fn new(source_ids: Vec<SourceId>,
override_ids: Vec<SourceId>) -> CargoResult<PackageRegistry> {
let mut reg = PackageRegistry::empty();
impl<'a> PackageRegistry<'a> {
pub fn new<'a>(source_ids: Vec<SourceId>,
override_ids: Vec<SourceId>,
shell: &'a mut MultiShell) -> CargoResult<PackageRegistry<'a>> {
let mut reg = PackageRegistry::empty(shell);
for id in source_ids.iter() {
try!(reg.load(id, false));
@ -38,12 +41,13 @@ impl PackageRegistry {
Ok(reg)
}
fn empty() -> PackageRegistry {
fn empty<'a>(shell: &'a mut MultiShell) -> PackageRegistry<'a> {
PackageRegistry {
sources: vec!(),
overrides: vec!(),
summaries: vec!(),
searched: vec!()
searched: vec!(),
shell: shell
}
}
@ -75,11 +79,10 @@ impl PackageRegistry {
Ok(())
}
fn load(&mut self, namespace: &SourceId,
override: bool) -> CargoResult<()> {
fn load(&mut self, namespace: &SourceId, override: bool) -> CargoResult<()> {
(|| {
let mut source = namespace.load(&try!(Config::new()));
let mut source = namespace.load(&mut try!(Config::new(self.shell)));
let dst = if override {&mut self.overrides} else {&mut self.summaries};
// Ensure the source has fetched all necessary remote data.
@ -103,7 +106,7 @@ impl PackageRegistry {
}
}
impl Registry for PackageRegistry {
impl<'a> Registry for PackageRegistry<'a> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
let overrides = try!(self.overrides.query(dep)); // this can never fail in practice

View File

@ -1,8 +1,9 @@
use term;
use term::{Terminal,color};
use term::color::{Color, BLACK};
use term::attr::Attr;
use term::color::{Color, BLACK, RED, GREEN};
use term::attr::{Attr, Bold};
use std::io::{IoResult, stderr};
use std::fmt::Show;
pub struct ShellConfig {
pub color: bool,
@ -20,6 +21,39 @@ pub struct Shell {
config: ShellConfig
}
pub struct MultiShell {
out: Shell,
err: Shell
}
impl MultiShell {
pub fn new(out: Shell, err: Shell) -> MultiShell {
MultiShell { out: out, err: err }
}
pub fn out<'a>(&'a mut self) -> &'a mut Shell {
&mut self.out
}
pub fn err<'a>(&'a mut self) -> &'a mut Shell {
&mut self.err
}
pub fn say<T: ToStr>(&mut self, message: T, color: Color) -> IoResult<()> {
self.out().say(message, color)
}
pub fn status<T: Show, U: Show>(&mut self, status: T, message: U) -> IoResult<()> {
self.out().say_status(status, message, GREEN)
}
pub fn error<T: ToStr>(&mut self, message: T) -> IoResult<()> {
self.err().say(message, RED)
}
}
impl Shell {
pub fn create(out: Box<Writer>, config: ShellConfig) -> Shell {
if config.tty && config.color {
@ -52,6 +86,17 @@ impl Shell {
try!(self.flush());
Ok(())
}
pub fn say_status<T: Show, U: Show>(&mut self, status: T, message: U, color: Color) -> IoResult<()> {
try!(self.reset());
if color != BLACK { try!(self.fg(color)); }
if self.supports_attr(Bold) { try!(self.attr(Bold)); }
try!(self.write_str(format!("{:>12}", status).as_slice()));
try!(self.reset());
try!(self.write_line(format!(" {}", message).as_slice()));
try!(self.flush());
Ok(())
}
}
impl Terminal<Box<Writer>> for Shell {

View File

@ -115,7 +115,7 @@ impl SourceId {
}
}
pub fn load(&self, config: &Config) -> Box<Source> {
pub fn load(&self, config: &mut Config) -> Box<Source> {
match self.kind {
GitKind(..) => {
box GitSource::new(self, config) as Box<Source>

View File

@ -21,12 +21,12 @@ extern crate hamcrest;
use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use std::io;
use std::io::stderr;
use std::io::stdio::stderr_raw;
use std::io::{stdout, stderr};
use std::io::stdio::{stdout_raw, stderr_raw};
use hammer::{FlagDecoder, FlagConfig, UsageDecoder, HammerError};
use core::{Shell, ShellConfig};
use term::color::{RED, BLACK};
use core::{Shell, MultiShell, ShellConfig};
use term::color::{BLACK};
pub use util::{CargoError, CliError, CliResult, human};
@ -99,47 +99,55 @@ pub fn execute_main<'a,
T: RepresentsFlags,
U: RepresentsJSON,
V: Encodable<json::Encoder<'a>, io::IoError>>(
exec: fn(T, U) -> CliResult<Option<V>>)
exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>)
{
fn call<'a,
T: RepresentsFlags,
U: RepresentsJSON,
V: Encodable<json::Encoder<'a>, io::IoError>>(
exec: fn(T, U) -> CliResult<Option<V>>,
exec: fn(T, U, &mut MultiShell) -> CliResult<Option<V>>,
shell: &mut MultiShell,
args: &[String])
-> CliResult<Option<V>>
{
let flags = try!(flags_from_args::<T>(args));
let json = try!(json_from_stdin::<U>());
exec(flags, json)
exec(flags, json, shell)
}
match global_flags() {
Err(e) => handle_error(e, true),
Ok(val) => process_executed(call(exec, val.rest.as_slice()), val)
}
process::<T, V>(|rest, shell| call(exec, shell, rest));
}
pub fn execute_main_without_stdin<'a,
T: RepresentsFlags,
V: Encodable<json::Encoder<'a>, io::IoError>>(
exec: fn(T) -> CliResult<Option<V>>)
exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>)
{
fn call<'a,
T: RepresentsFlags,
V: Encodable<json::Encoder<'a>, io::IoError>>(
exec: fn(T) -> CliResult<Option<V>>,
exec: fn(T, &mut MultiShell) -> CliResult<Option<V>>,
shell: &mut MultiShell,
args: &[String])
-> CliResult<Option<V>>
{
let flags = try!(flags_from_args::<T>(args));
exec(flags)
exec(flags, shell)
}
process::<T, V>(|rest, shell| call(exec, shell, rest));
}
fn process<'a,
T: RepresentsFlags,
V: Encodable<json::Encoder<'a>, io::IoError>>(
callback: |&[String], &mut MultiShell| -> CliResult<Option<V>>) {
let mut shell = shell();
match global_flags() {
Err(e) => handle_error(e, true),
Err(e) => handle_error(e, &mut shell, true),
Ok(val) => {
if val.help {
let (desc, options) = hammer::usage::<T>(true);
@ -153,7 +161,7 @@ pub fn execute_main_without_stdin<'a,
let (_, options) = hammer::usage::<GlobalFlags>(false);
print!("{}", options);
} else {
process_executed(call(exec, val.rest.as_slice()), val)
process_executed(callback(val.rest.as_slice(), &mut shell), val, &mut shell)
}
}
}
@ -162,10 +170,10 @@ pub fn execute_main_without_stdin<'a,
pub fn process_executed<'a,
T: Encodable<json::Encoder<'a>, io::IoError>>(
result: CliResult<Option<T>>,
flags: GlobalFlags)
flags: GlobalFlags, shell: &mut MultiShell)
{
match result {
Err(e) => handle_error(e, flags.verbose),
Err(e) => handle_error(e, shell, flags.verbose),
Ok(encodable) => {
encodable.map(|encodable| {
let encoded = json::Encoder::str_encode(&encodable);
@ -175,38 +183,47 @@ pub fn process_executed<'a,
}
}
pub fn handle_error(err: CliError, verbose: bool) {
log!(4, "handle_error; err={}", err);
let CliError { error, exit_code, unknown, .. } = err;
pub fn shell() -> MultiShell {
let tty = stderr_raw().isatty();
let stderr = box stderr() as Box<Writer>;
let config = ShellConfig { color: true, verbose: false, tty: tty };
let mut shell = Shell::create(stderr, config);
let err = Shell::create(stderr, config);
let tty = stdout_raw().isatty();
let stdout = box stdout() as Box<Writer>;
let config = ShellConfig { color: true, verbose: false, tty: tty };
let out = Shell::create(stdout, config);
MultiShell::new(out, err)
}
pub fn handle_error(err: CliError, shell: &mut MultiShell, verbose: bool) {
log!(4, "handle_error; err={}", err);
let CliError { error, exit_code, unknown, .. } = err;
if unknown {
let _ = shell.say("An unknown error occurred", RED);
let _ = shell.error("An unknown error occurred");
} else {
let _ = shell.say(error.to_str(), RED);
let _ = shell.error(error.to_str());
}
if unknown && !verbose {
let _ = shell.say("\nTo learn more, run the command again with --verbose.", BLACK);
let _ = shell.err().say("\nTo learn more, run the command again with --verbose.", BLACK);
}
if verbose {
handle_cause(error, &mut shell);
handle_cause(error, shell);
}
std::os::set_exit_status(exit_code as int);
}
fn handle_cause(err: &CargoError, shell: &mut Shell) {
let _ = shell.say("\nCaused by:", BLACK);
let _ = shell.say(format!(" {}", err.description()), BLACK);
fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
let _ = shell.err().say("\nCaused by:", BLACK);
let _ = shell.err().say(format!(" {}", err.description()), BLACK);
err.cause().map(|e| handle_cause(e, shell));
}

View File

@ -24,13 +24,13 @@
use std::os;
use util::config::{ConfigValue};
use core::{Source,SourceId,PackageSet,resolver};
use core::{MultiShell, Source, SourceId, PackageSet, resolver};
use core::registry::PackageRegistry;
use ops;
use sources::{PathSource};
use util::{CargoResult, Wrap, config, internal, human};
pub fn compile(manifest_path: &Path) -> CargoResult<()> {
pub fn compile(manifest_path: &Path, shell: &mut MultiShell) -> CargoResult<()> {
log!(4, "compile; manifest-path={}", manifest_path.display());
let id = SourceId::for_path(&manifest_path.dir_path());
@ -45,19 +45,21 @@ pub fn compile(manifest_path: &Path) -> CargoResult<()> {
let override_ids = try!(source_ids_from_config());
let source_ids = package.get_source_ids();
let mut registry = try!(PackageRegistry::new(source_ids, override_ids));
let resolved = try!(resolver::resolve(package.get_dependencies(),
&mut registry).wrap({
human("unable to resolve dependencies")
}));
let packages = {
let mut registry = try!(PackageRegistry::new(source_ids, override_ids, shell));
let resolved = try!(resolver::resolve(package.get_dependencies(),
&mut registry).wrap({
human("unable to resolve dependencies")
}));
let packages = try!(registry.get(resolved.as_slice()).wrap({
human("unable to get packages from source")
}));
try!(registry.get(resolved.as_slice()).wrap({
human("unable to get packages from source")
}))
};
debug!("packages={}", packages);
try!(ops::compile_packages(&package, &PackageSet::new(packages.as_slice())));
try!(ops::compile_packages(&package, &PackageSet::new(packages.as_slice()), shell));
Ok(())
}

View File

@ -3,7 +3,7 @@ use std::io;
use std::io::{File, IoError};
use std::str;
use core::{Package, PackageSet, Target};
use core::{MultiShell, Package, PackageSet, Target};
use util;
use util::{CargoResult, ChainError, ProcessBuilder, internal, human, CargoError};
use util::{Config};
@ -16,13 +16,13 @@ struct Context<'a> {
primary: bool,
rustc_version: &'a str,
compiled_anything: bool,
config: &'a Config,
config: &'a mut Config<'a>
}
pub fn compile_packages(pkg: &Package, deps: &PackageSet) -> CargoResult<()> {
pub fn compile_packages(pkg: &Package, deps: &PackageSet, shell: &mut MultiShell) -> CargoResult<()> {
debug!("compile_packages; pkg={}; deps={}", pkg, deps);
let config = try!(Config::new());
let mut config = try!(Config::new(shell));
let target_dir = pkg.get_absolute_target_dir();
let deps_target_dir = target_dir.join("deps");
@ -46,7 +46,7 @@ pub fn compile_packages(pkg: &Package, deps: &PackageSet) -> CargoResult<()> {
primary: false,
rustc_version: rustc_version.as_slice(),
compiled_anything: false,
config: &config,
config: &mut config
};
// Traverse the dependencies in topological order
@ -78,14 +78,14 @@ fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
pkg.get_name()));
let (is_fresh, fingerprint) = try!(is_fresh(pkg, &fingerprint_loc, cx));
if !cx.compiled_anything && is_fresh {
println!("Skipping fresh {}", pkg);
try!(cx.config.shell().status("Fresh", pkg));
return Ok(())
}
// Alright, so this package is not fresh and we need to compile it. Start
// off by printing a nice helpful message and then run the custom build
// command if one is present.
println!("Compiling {}", pkg);
try!(cx.config.shell().status("Compiling", pkg));
match pkg.get_manifest().get_build() {
Some(cmd) => try!(compile_custom(pkg, cmd, cx)),
@ -110,7 +110,7 @@ fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
}
fn is_fresh(dep: &Package, loc: &Path,
cx: &Context) -> CargoResult<(bool, String)> {
cx: &mut Context) -> CargoResult<(bool, String)> {
let new_fingerprint = format!("{}{}", cx.rustc_version,
try!(dep.get_fingerprint(cx.config)));
let mut file = match File::open(loc) {

View File

@ -15,16 +15,17 @@ use sources::git::utils::{GitReference,GitRemote,Master,Other};
/* TODO: Refactor GitSource to delegate to a PathSource
*/
pub struct GitSource {
pub struct GitSource<'a, 'b> {
id: SourceId,
remote: GitRemote,
reference: GitReference,
db_path: Path,
checkout_path: Path
checkout_path: Path,
config: &'a mut Config<'b>
}
impl GitSource {
pub fn new(source_id: &SourceId, config: &Config) -> GitSource {
impl<'a, 'b> GitSource<'a, 'b> {
pub fn new<'a, 'b>(source_id: &SourceId, config: &'a mut Config<'b>) -> GitSource<'a, 'b> {
assert!(source_id.is_git(), "id is not git, id={}", source_id);
let reference = match source_id.kind {
@ -46,7 +47,8 @@ impl GitSource {
remote: remote,
reference: GitReference::for_str(reference.as_slice()),
db_path: db_path,
checkout_path: checkout_path
checkout_path: checkout_path,
config: config
}
}
@ -79,7 +81,7 @@ fn to_hex(num: u64) -> String {
writer.get_ref().to_hex()
}
impl Show for GitSource {
impl<'a, 'b> Show for GitSource<'a, 'b> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
try!(write!(f, "git repo at {}", self.remote.get_url()));
@ -90,9 +92,11 @@ impl Show for GitSource {
}
}
impl Source for GitSource {
impl<'a, 'b> Source for GitSource<'a, 'b> {
fn update(&mut self) -> CargoResult<()> {
println!("Updating git repository `{}`", self.remote.get_url());
try!(self.config.shell().status("Updating",
format!("git repository `{}`", self.remote.get_url())));
log!(5, "updating git source `{}`", self.remote);
let repo = try!(self.remote.checkout(&self.db_path));
try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));

View File

@ -2,19 +2,22 @@ use std::{io,fmt,os};
use std::collections::HashMap;
use serialize::{Encodable,Encoder};
use toml;
use core::MultiShell;
use util::{CargoResult, CargoError, ChainError, Require, internal, human};
pub struct Config {
home_path: Path
pub struct Config<'a> {
home_path: Path,
shell: &'a mut MultiShell
}
impl Config {
pub fn new() -> CargoResult<Config> {
impl<'a> Config<'a> {
pub fn new<'a>(shell: &'a mut MultiShell) -> CargoResult<Config<'a>> {
Ok(Config {
home_path: try!(os::homedir().require(|| {
human("Cargo couldn't find your home directory. \
This probably means that $HOME was not set.")
}))
})),
shell: shell
})
}
@ -25,6 +28,10 @@ impl Config {
pub fn git_checkout_path(&self) -> Path {
self.home_path.join(".cargo").join("git").join("checkouts")
}
pub fn shell<'a>(&'a mut self) -> &'a mut MultiShell {
&mut *self.shell
}
}
#[deriving(Eq,PartialEq,Clone,Encodable,Decodable)]

View File

@ -9,7 +9,6 @@ use std::str;
use std::vec::Vec;
use std::fmt::Show;
use ham = hamcrest;
use cargo::core::shell;
use cargo::util::{process,ProcessBuilder};
use cargo::util::ProcessError;
@ -305,8 +304,6 @@ impl<'a> ham::Matcher<&'a [u8]> for ShellWrites {
fn matches(&self, actual: &[u8])
-> ham::MatchResult
{
use term::Terminal;
println!("{}", actual);
let actual = std::str::from_utf8_lossy(actual);
let actual = actual.to_str();

View File

@ -9,6 +9,8 @@ use cargo::util::{process,realpath};
fn setup() {
}
static COMPILING: &'static str = " Compiling";
fn basic_bin_manifest(name: &str) -> String {
format!(r#"
[project]
@ -143,9 +145,10 @@ test!(cargo_compile_with_warnings_in_a_dep_package {
assert_that(p.cargo_process("cargo-compile"),
execs()
.with_stdout(format!("Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
bar.display(), main.display()))
.with_stdout(format!("{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
COMPILING, bar.display(),
COMPILING, main.display()))
.with_stderr(""));
assert_that(&p.root().join("target/foo"), existing_file());
@ -343,7 +346,7 @@ test!(custom_build {
"#);
assert_that(p.cargo_process("cargo-compile"),
execs().with_status(0)
.with_stdout(format!("Compiling foo v0.5.0 (file:{})\n",
.with_stdout(format!(" Compiling foo v0.5.0 (file:{})\n",
p.root().display()))
.with_stderr(""));
})

View File

@ -5,6 +5,10 @@ use hamcrest::{assert_that,existing_file};
use cargo;
use cargo::util::{ProcessError, process};
static COMPILING: &'static str = " Compiling";
static FRESH: &'static str = " Fresh";
static UPDATING: &'static str = " Updating";
fn setup() {
}
@ -83,11 +87,12 @@ test!(cargo_compile_simple_git_dep {
assert_that(project.cargo_process("cargo-compile"),
execs()
.with_stdout(format!("Updating git repository `file:{}`\n\
Compiling dep1 v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
git_root.display(), git_root.display(),
root.display()))
.with_stdout(format!("{} git repository `file:{}`\n\
{} dep1 v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_root.display(),
COMPILING, git_root.display(),
COMPILING, root.display()))
.with_stderr(""));
assert_that(&project.root().join("target/foo"), existing_file());
@ -211,31 +216,31 @@ test!(recompilation {
// First time around we should compile both foo and bar
assert_that(p.cargo_process("cargo-compile"),
execs().with_stdout(format!("Updating git repository `file:{}`\n\
Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
git_project.root().display(),
git_project.root().display(),
p.root().display())));
execs().with_stdout(format!("{} git repository `file:{}`\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_project.root().display(),
COMPILING, git_project.root().display(),
COMPILING, p.root().display())));
// Don't recompile the second time
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Updating git repository `file:{}`\n\
Skipping fresh bar v0.5.0 (file:{})\n\
Skipping fresh foo v0.5.0 (file:{})\n",
git_project.root().display(),
git_project.root().display(),
p.root().display())));
execs().with_stdout(format!("{} git repository `file:{}`\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_project.root().display(),
FRESH, git_project.root().display(),
FRESH, p.root().display())));
// Modify a file manually, shouldn't trigger a recompile
File::create(&git_project.root().join("src/bar.rs")).write_str(r#"
pub fn bar() { println!("hello!"); }
"#).assert();
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Updating git repository `file:{}`\n\
Skipping fresh bar v0.5.0 (file:{})\n\
Skipping fresh foo v0.5.0 (file:{})\n",
git_project.root().display(),
git_project.root().display(),
p.root().display())));
execs().with_stdout(format!("{} git repository `file:{}`\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_project.root().display(),
FRESH, git_project.root().display(),
FRESH, p.root().display())));
// Commit the changes and make sure we trigger a recompile
File::create(&git_project.root().join("src/bar.rs")).write_str(r#"
pub fn bar() { println!("hello!"); }
@ -244,10 +249,10 @@ test!(recompilation {
git_project.process("git").args(["commit", "-m", "test"]).exec_with_output()
.assert();
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Updating git repository `file:{}`\n\
Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
git_project.root().display(),
git_project.root().display(),
p.root().display())));
execs().with_stdout(format!("{} git repository `file:{}`\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
UPDATING, git_project.root().display(),
COMPILING, git_project.root().display(),
COMPILING, p.root().display())));
})

View File

@ -9,6 +9,9 @@ use cargo::util::{process};
fn setup() {
}
static COMPILING: &'static str = " Compiling";
static FRESH: &'static str = " Fresh";
test!(cargo_compile_with_nested_deps_shorthand {
let p = project("foo")
.file("Cargo.toml", r#"
@ -115,23 +118,23 @@ test!(no_rebuild_dependency {
"#);
// First time around we should compile both foo and bar
assert_that(p.cargo_process("cargo-compile"),
execs().with_stdout(format!("Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
COMPILING, bar.display(),
COMPILING, p.root().display())));
// This time we shouldn't compile bar
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Skipping fresh bar v0.5.0 (file:{})\n\
Skipping fresh foo v0.5.0 (file:{})\n",
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
FRESH, bar.display(),
FRESH, p.root().display())));
p.build(); // rebuild the files (rewriting them in the process)
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
COMPILING, bar.display(),
COMPILING, p.root().display())));
})
test!(deep_dependencies_trigger_rebuild {
@ -183,19 +186,19 @@ test!(deep_dependencies_trigger_rebuild {
pub fn baz() {}
"#);
assert_that(p.cargo_process("cargo-compile"),
execs().with_stdout(format!("Compiling baz v0.5.0 (file:{})\n\
Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
baz.display(),
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} baz v0.5.0 (file:{})\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
COMPILING, baz.display(),
COMPILING, bar.display(),
COMPILING, p.root().display())));
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Skipping fresh baz v0.5.0 (file:{})\n\
Skipping fresh bar v0.5.0 (file:{})\n\
Skipping fresh foo v0.5.0 (file:{})\n",
baz.display(),
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} baz v0.5.0 (file:{})\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
FRESH, baz.display(),
FRESH, bar.display(),
FRESH, p.root().display())));
// Make sure an update to baz triggers a rebuild of bar
//
@ -206,12 +209,12 @@ test!(deep_dependencies_trigger_rebuild {
pub fn baz() { println!("hello!"); }
"#).assert();
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Compiling baz v0.5.0 (file:{})\n\
Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
baz.display(),
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} baz v0.5.0 (file:{})\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
COMPILING, baz.display(),
COMPILING, bar.display(),
COMPILING, p.root().display())));
// Make sure an update to bar doesn't trigger baz
File::create(&p.root().join("bar/src/bar.rs")).write_str(r#"
@ -219,12 +222,13 @@ test!(deep_dependencies_trigger_rebuild {
pub fn bar() { println!("hello!"); baz::baz(); }
"#).assert();
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Skipping fresh baz v0.5.0 (file:{})\n\
Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
execs().with_stdout(format!("{} baz v0.5.0 (file:{})\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
FRESH,
baz.display(),
bar.display(),
p.root().display())));
COMPILING, bar.display(),
COMPILING, p.root().display())));
})
test!(no_rebuild_two_deps {
@ -276,17 +280,17 @@ test!(no_rebuild_two_deps {
pub fn baz() {}
"#);
assert_that(p.cargo_process("cargo-compile"),
execs().with_stdout(format!("Compiling baz v0.5.0 (file:{})\n\
Compiling bar v0.5.0 (file:{})\n\
Compiling foo v0.5.0 (file:{})\n",
baz.display(),
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} baz v0.5.0 (file:{})\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
COMPILING, baz.display(),
COMPILING, bar.display(),
COMPILING, p.root().display())));
assert_that(p.process("cargo-compile"),
execs().with_stdout(format!("Skipping fresh baz v0.5.0 (file:{})\n\
Skipping fresh bar v0.5.0 (file:{})\n\
Skipping fresh foo v0.5.0 (file:{})\n",
baz.display(),
bar.display(),
p.root().display())));
execs().with_stdout(format!("{} baz v0.5.0 (file:{})\n\
{} bar v0.5.0 (file:{})\n\
{} foo v0.5.0 (file:{})\n",
FRESH, baz.display(),
FRESH, bar.display(),
FRESH, p.root().display())));
})