-Subproject commit 6d26b74a66ce16f9d146a407a2384aa6ef431f7c
+Subproject commit 6c442daa3550d791333c4e382587d63fd12c89d2
manifest_path: Option<String>
}
-hammer_config!(Options)
+hammer_config!(Options "Compile the current project")
fn main() {
execute_main_without_stdin(execute);
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
-use cargo::{NoFlags,execute_main_without_stdin,handle_error};
+use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error};
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};
Err(err) => return handle_error(err, false)
};
- if cmd == "config-for-key".to_str() {
- log!(4, "cmd == config-for-key");
- execute_main_without_stdin(config_for_key)
- }
- else if cmd == "config-list".to_str() {
- log!(4, "cmd == config-list");
- execute_main_without_stdin(config_list)
- }
- else if cmd == "locate-project".to_str() {
- log!(4, "cmd == locate-project");
- execute_main_without_stdin(locate_project)
- }
- else {
- let command = Command::new(format!("cargo-{}", cmd))
- .args(args.as_slice())
- .stdin(InheritFd(0))
- .stdout(InheritFd(1))
- .stderr(InheritFd(2))
- .status();
-
- match command {
- Ok(ExitStatus(0)) => (),
- Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
- handle_error(CliError::new("", i as uint), false)
+ match cmd.as_slice() {
+ "config-for-key" => {
+ log!(4, "cmd == config-for-key");
+ execute_main_without_stdin(config_for_key)
+ },
+ "config-list" => {
+ log!(4, "cmd == config-list");
+ execute_main_without_stdin(config_list)
+ },
+ "locate-project" => {
+ log!(4, "cmd == locate-project");
+ execute_main_without_stdin(locate_project)
+ },
+ "--help" | "-h" | "help" | "-?" => {
+ println!("Commands:");
+ println!(" compile # compile the current project\n");
+
+ let (_, options) = hammer::usage::<GlobalFlags>(false);
+ println!("Options (for all commands):\n\n{}", options);
+ },
+ _ => {
+ let command = Command::new(format!("cargo-{}", cmd))
+ .args(args.as_slice())
+ .stdin(InheritFd(0))
+ .stdout(InheritFd(1))
+ .stderr(InheritFd(2))
+ .status();
+
+ match command {
+ Ok(ExitStatus(0)) => (),
+ Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
+ handle_error(CliError::new("", i as uint), false)
+ }
+ Err(_) => handle_error(CliError::new("No such subcommand", 127), false)
}
- Err(_) => handle_error(CliError::new("No such subcommand", 127), false)
}
}
}
Summary
};
+pub use self::shell::{
+ Shell,
+ ShellConfig
+};
+
pub use self::dependency::Dependency;
pub use self::version_req::VersionReq;
use term;
use term::{Terminal,color};
-use term::color::Color;
+use term::color::{Color, BLACK};
use term::attr::Attr;
-use std::io::IoResult;
+use std::io::{IoResult, stderr};
pub struct ShellConfig {
pub color: bool,
pub tty: bool
}
-enum AdequateTerminal<T> {
- NoColor(T),
- Color(Box<Terminal<T>>)
+enum AdequateTerminal {
+ NoColor(Box<Writer>),
+ Color(Box<Terminal<Box<Writer>>>)
}
-pub struct Shell<T> {
- terminal: AdequateTerminal<T>,
+pub struct Shell {
+ terminal: AdequateTerminal,
config: ShellConfig
}
-impl<T: Writer + Send> Shell<T> {
- pub fn create(out: T, config: ShellConfig) -> Option<Shell<T>> {
+impl Shell {
+ pub fn create(out: Box<Writer>, config: ShellConfig) -> Shell {
if config.tty && config.color {
- let term: Option<term::TerminfoTerminal<T>> = Terminal::new(out);
+ let term: Option<term::TerminfoTerminal<Box<Writer>>> = Terminal::new(out);
term.map(|t| Shell {
- terminal: Color(box t as Box<Terminal<T>>),
+ terminal: Color(box t as Box<Terminal<Box<Writer>>>),
config: config
+ }).unwrap_or_else(|| {
+ Shell { terminal: NoColor(box stderr() as Box<Writer>), config: config }
})
} else {
- Some(Shell { terminal: NoColor(out), config: config })
+ Shell { terminal: NoColor(out), config: config }
}
}
pub fn verbose(&mut self,
- callback: |&mut Shell<T>| -> IoResult<()>) -> IoResult<()> {
+ callback: |&mut Shell| -> IoResult<()>) -> IoResult<()> {
if self.config.verbose {
return callback(self)
}
Ok(())
}
- pub fn say<T: Str>(&mut self, message: T, color: Color) -> IoResult<()> {
+ pub fn say<T: ToStr>(&mut self, message: T, color: Color) -> IoResult<()> {
try!(self.reset());
- try!(self.fg(color));
- try!(self.write_line(message.as_slice()));
+ if color != BLACK { try!(self.fg(color)); }
+ try!(self.write_line(message.to_str().as_slice()));
try!(self.reset());
try!(self.flush());
Ok(())
}
}
-impl<T: Writer + Send> Terminal<T> for Shell<T> {
- fn new(out: T) -> Option<Shell<T>> {
- Shell::create(out, ShellConfig {
- color: true,
- verbose: false,
- tty: false,
+impl Terminal<Box<Writer>> for Shell {
+ fn new(out: Box<Writer>) -> Option<Shell> {
+ Some(Shell {
+ terminal: NoColor(out),
+ config: ShellConfig {
+ color: true,
+ verbose: false,
+ tty: false,
+ }
})
}
}
}
- fn unwrap(self) -> T {
+ fn unwrap(self) -> Box<Writer> {
fail!("Can't unwrap a Shell");
}
- fn get_ref<'a>(&'a self) -> &'a T {
+ fn get_ref<'a>(&'a self) -> &'a Box<Writer> {
match self.terminal {
Color(ref c) => c.get_ref(),
NoColor(ref w) => w
}
}
- fn get_mut<'a>(&'a mut self) -> &'a mut T {
+ fn get_mut<'a>(&'a mut self) -> &'a mut Box<Writer> {
match self.terminal {
Color(ref mut c) => c.get_mut(),
NoColor(ref mut w) => w
}
}
-impl<T: Writer + Send> Writer for Shell<T> {
+impl Writer for Shell {
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
match self.terminal {
Color(ref mut c) => c.write(buf),
use serialize::{Decoder, Encoder, Decodable, Encodable, json};
use std::io;
-use hammer::{FlagDecoder, FlagConfig, UsageDecoder, HammerError, FlagConfiguration};
+use std::io::stderr;
+use std::io::stdio::stderr_raw;
+use hammer::{FlagDecoder, FlagConfig, UsageDecoder, HammerError};
+
+use core::{Shell, ShellConfig};
+use term::color::{RED, BLACK};
pub use util::{CargoError, CliError, CliResult, human};
fn decode_flags(d: &mut FlagDecoder) -> Result<Self, HammerError>;
}
-trait FlagUsage : FlagConfig {
- fn decode_usage(d: &mut UsageDecoder) -> Result<Self, HammerError>;
-}
-
-//impl<T: FlagConfig + Decodable<FlagDecoder, HammerError>> FlagParse for T {}
-//impl<T: FlagConfig + Decodable<UsageDecoder, HammerError>> FlagUsage for T {}
-
impl<T: FlagConfig + Decodable<FlagDecoder, HammerError>> FlagParse for T {
fn decode_flags(d: &mut FlagDecoder) -> Result<T, HammerError> {
Decodable::decode(d)
}
}
-impl<T: FlagConfig + Decodable<UsageDecoder, HammerError>> FlagUsage for T {
- fn decode_usage(d: &mut UsageDecoder) -> Result<T, HammerError> {
- Decodable::decode(d)
- }
-}
-
trait RepresentsFlags : FlagParse + Decodable<UsageDecoder, HammerError> {}
impl<T: FlagParse + Decodable<UsageDecoder, HammerError>> RepresentsFlags for T {}
Err(e) => handle_error(e, true),
Ok(val) => {
if val.help {
- println!("Usage:\n");
+ let (desc, options) = hammer::usage::<T>(true);
+
+ desc.map(|d| println!("{}\n", d));
- print!("{}", hammer::usage::<T>(true));
- print!("{}", hammer::usage::<GlobalFlags>(false));
+ println!("Options:\n");
+
+ print!("{}", options);
+
+ let (_, options) = hammer::usage::<GlobalFlags>(false);
+ print!("{}", options);
} else {
process_executed(call(exec, val.rest.as_slice()), val)
}
pub fn handle_error(err: CliError, verbose: bool) {
log!(4, "handle_error; err={}", err);
- let CliError { error, exit_code, .. } = err;
- let _ = write!(&mut std::io::stderr(), "{}", error);
+
+ let CliError { error, exit_code, unknown, .. } = err;
+
+ 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);
+
+ if unknown {
+ let _ = shell.say("An unknown error occurred", RED);
+ } else {
+ let _ = shell.say(error.to_str(), RED);
+ }
+
+ if unknown && !verbose {
+ let _ = shell.say("\nTo learn more, run the command again with --verbose.", BLACK);
+ }
if verbose {
- error.cause().map(handle_cause);
+ handle_cause(error, &mut shell);
}
std::os::set_exit_status(exit_code as int);
}
-fn handle_cause(err: &CargoError) {
- println!("\nCaused by:");
- println!(" {}", err.description());
+fn handle_cause(err: &CargoError, shell: &mut Shell) {
+ let _ = shell.say("\nCaused by:", BLACK);
+ let _ = shell.say(format!(" {}", err.description()), BLACK);
- err.cause().map(handle_cause);
+ err.cause().map(|e| handle_cause(e, shell));
}
fn args() -> Vec<String> {
use std::os::args;
use std::io;
-use std::io::File;
+use std::io::{File, IoError};
use std::str;
use core::{Package, PackageSet, Target};
// First ensure that the destination directory exists
debug!("creating target dir; path={}", target_dir.display());
- try!(mk_target(&target_dir));
- try!(mk_target(&deps_target_dir));
+
+ try!(mk_target(&target_dir).chain_error(||
+ internal(format!("Couldn't create the target directory for {} at {}",
+ pkg.get_name(), target_dir.display()))));
+
+ try!(mk_target(&deps_target_dir).chain_error(||
+ internal(format!("Couldn't create the directory for dependencies for {} at {}",
+ pkg.get_name(), deps_target_dir.display()))));
let mut cx = Context {
dest: &deps_target_dir,
Ok((old_fingerprint == new_fingerprint, new_fingerprint))
}
-fn mk_target(target: &Path) -> CargoResult<()> {
- io::fs::mkdir_recursive(target, io::UserRWX).chain_error(|| {
- internal("could not create target directory")
- })
+fn mk_target(target: &Path) -> Result<(), IoError> {
+ io::fs::mkdir_recursive(target, io::UserRWX)
}
fn compile_custom(pkg: &Package, cmd: &str, cx: &Context) -> CargoResult<()> {
#[deriving(Show)]
pub struct CliError {
pub error: Box<CargoError>,
+ pub unknown: bool,
pub exit_code: uint
}
}
pub fn from_boxed(error: Box<CargoError>, code: uint) -> CliError {
- let error = if error.is_human() {
- error
- } else {
- human("An unknown error occurred").with_cause(error)
- };
-
- CliError { error: error, exit_code: code }
+ let human = error.is_human();
+ CliError { error: error, exit_code: code, unknown: !human }
}
}
}
}
-impl<'a> ham::Matcher<&'a mut shell::Shell<std::io::MemWriter>> for ShellWrites {
- fn matches(&self, actual: &mut shell::Shell<std::io::MemWriter>)
+impl<'a> ham::Matcher<&'a [u8]> for ShellWrites {
+ fn matches(&self, actual: &[u8])
-> ham::MatchResult
{
use term::Terminal;
- let actual = std::str::from_utf8_lossy(actual.get_ref().get_ref());
+ println!("{}", actual);
+ let actual = std::str::from_utf8_lossy(actual);
let actual = actual.to_str();
ham::expect(actual == self.expected, actual)
}
assert_that(p.cargo_process("cargo-compile"),
execs()
.with_status(101)
- .with_stderr("Cargo.toml is not a valid manifest"));
+ .with_stderr("Cargo.toml is not a valid manifest\n"));
})
test!(cargo_compile_without_manifest {
execs()
.with_status(102)
.with_stderr("Could not find Cargo.toml in this directory or any \
- parent directory"));
+ parent directory\n"));
})
test!(cargo_compile_with_invalid_code {
src/foo.rs:1 invalid rust code!
^~~~~~~
Could not execute process \
-`rustc src/foo.rs --crate-type bin --out-dir {} -L {} -L {}` (status=101)",
+`rustc src/foo.rs --crate-type bin --out-dir {} -L {} -L {}` (status=101)\n",
target.display(),
target.display(),
target.join("deps").display()).as_slice()));
Could not execute process `{}` (status=101)
--- stderr
task '<main>' failed at 'nope', src/foo.rs:2
+
", build.root().join("target/foo").display())));
})
use support::{ResultTest,Tap,shell_writes};
use hamcrest::{assert_that};
-use std::io::{MemWriter,IoResult};
+use std::io::{MemWriter, BufWriter, IoResult};
use std::str::from_utf8_lossy;
use cargo::core::shell::{Shell,ShellConfig};
use term::{Terminal,TerminfoTerminal,color};
fn setup() {
}
+fn writer(buf: &mut [u8]) -> Box<Writer> {
+ box BufWriter::new(buf) as Box<Writer>
+}
+
test!(non_tty {
let config = ShellConfig { color: true, verbose: true, tty: false };
- Shell::create(MemWriter::new(), config).assert().tap(|shell| {
+ let mut buf: Vec<u8> = Vec::from_elem(9, 0 as u8);
+
+ Shell::create(writer(buf.as_mut_slice()), config).tap(|shell| {
shell.say("Hey Alex", color::RED).assert();
- assert_that(shell, shell_writes("Hey Alex\n"));
+ assert_that(buf.as_slice(), shell_writes("Hey Alex\n"));
});
})
test!(color_explicitly_disabled {
let config = ShellConfig { color: false, verbose: true, tty: true };
- Shell::create(MemWriter::new(), config).assert().tap(|shell| {
+ let mut buf: Vec<u8> = Vec::from_elem(9, 0 as u8);
+
+ Shell::create(writer(buf.as_mut_slice()), config).tap(|shell| {
shell.say("Hey Alex", color::RED).assert();
- assert_that(shell, shell_writes("Hey Alex\n"));
+ assert_that(buf.as_slice(), shell_writes("Hey Alex\n"));
});
})
test!(colored_shell {
let config = ShellConfig { color: true, verbose: true, tty: true };
- Shell::create(MemWriter::new(), config).assert().tap(|shell| {
+ let mut buf: Vec<u8> = Vec::from_elem(22, 0 as u8);
+
+ Shell::create(writer(buf.as_mut_slice()), config).tap(|shell| {
shell.say("Hey Alex", color::RED).assert();
- assert_that(shell, shell_writes(colored_output("Hey Alex\n",
+ assert_that(buf.as_slice(), shell_writes(colored_output("Hey Alex\n",
color::RED).assert()));
});
})