From 9f98208d5e42c6d832fc0f309b02f157f4453973 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 12 Aug 2016 00:47:49 +0300 Subject: [PATCH 1/6] Add --message-format flag. --- src/bin/bench.rs | 7 ++- src/bin/build.rs | 6 +++ src/bin/doc.rs | 6 +++ src/bin/install.rs | 1 + src/bin/run.rs | 6 +++ src/bin/rustc.rs | 6 +++ src/bin/rustdoc.rs | 6 +++ src/bin/test.rs | 7 +++ src/cargo/ops/cargo_compile.rs | 22 +++++++++- src/cargo/ops/cargo_package.rs | 1 + src/cargo/ops/cargo_rustc/mod.rs | 43 ++++++++++++++++-- src/cargo/ops/mod.rs | 2 +- tests/build.rs | 75 ++++++++++++++++++++++++++++++++ tests/cargotest/support/mod.rs | 31 ++++++++----- 14 files changed, 201 insertions(+), 18 deletions(-) diff --git a/src/bin/bench.rs b/src/bin/bench.rs index f2d028d34e4..521c87c2f70 100644 --- a/src/bin/bench.rs +++ b/src/bin/bench.rs @@ -16,6 +16,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_lib: bool, flag_bin: Vec, flag_example: Vec, @@ -50,6 +51,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -75,7 +77,9 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); let ops = ops::TestOptions { no_run: options.flag_no_run, no_fail_fast: false, @@ -96,6 +100,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + message_format: message_format, target_rustdoc_args: None, target_rustc_args: None, }, diff --git a/src/bin/build.rs b/src/bin/build.rs index 2f23ce1be3b..c4619f541e9 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -18,6 +18,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_release: bool, flag_lib: bool, flag_bin: Vec, @@ -52,6 +53,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -73,6 +75,9 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -92,6 +97,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + message_format: message_format, target_rustdoc_args: None, target_rustc_args: None, }; diff --git a/src/bin/doc.rs b/src/bin/doc.rs index c4139987cf7..83431ef66ff 100644 --- a/src/bin/doc.rs +++ b/src/bin/doc.rs @@ -17,6 +17,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_package: Vec, flag_lib: bool, flag_bin: Vec, @@ -47,6 +48,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -65,6 +67,9 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -85,6 +90,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &empty, &empty, &empty), + message_format: message_format, release: options.flag_release, mode: ops::CompileMode::Doc { deps: !options.flag_no_deps, diff --git a/src/bin/install.rs b/src/bin/install.rs index 544b115e9a2..b5d67fd411f 100644 --- a/src/bin/install.rs +++ b/src/bin/install.rs @@ -114,6 +114,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { release: !options.flag_debug, filter: ops::CompileFilter::new(false, &options.flag_bin, &[], &options.flag_example, &[]), + message_format: ops::MessageFormat::Human, target_rustc_args: None, target_rustdoc_args: None, }; diff --git a/src/bin/run.rs b/src/bin/run.rs index 5f9843c83ba..4b03b53bc53 100644 --- a/src/bin/run.rs +++ b/src/bin/run.rs @@ -16,6 +16,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_release: bool, flag_frozen: bool, flag_locked: bool, @@ -42,6 +43,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -61,6 +63,9 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -91,6 +96,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { bins: &bins, examples: &examples, } }, + message_format: message_format, target_rustdoc_args: None, target_rustc_args: None, }; diff --git a/src/bin/rustc.rs b/src/bin/rustc.rs index e81c8d18f7a..2743c3669f0 100644 --- a/src/bin/rustc.rs +++ b/src/bin/rustc.rs @@ -19,6 +19,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_release: bool, flag_lib: bool, flag_bin: Vec, @@ -55,6 +56,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -80,6 +82,9 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -110,6 +115,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + message_format: message_format, target_rustdoc_args: None, target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]), }; diff --git a/src/bin/rustdoc.rs b/src/bin/rustdoc.rs index 15e4a91ca66..79e368090b6 100644 --- a/src/bin/rustdoc.rs +++ b/src/bin/rustdoc.rs @@ -17,6 +17,7 @@ pub struct Options { flag_release: bool, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_package: Option, flag_lib: bool, flag_bin: Vec, @@ -52,6 +53,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -74,6 +76,9 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -95,6 +100,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + message_format: message_format, mode: ops::CompileMode::Doc { deps: false }, target_rustdoc_args: Some(&options.arg_opts), target_rustc_args: None, diff --git a/src/bin/test.rs b/src/bin/test.rs index c5e687a6483..a2f1f5f129b 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -23,6 +23,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, + flag_message_format: Option, flag_release: bool, flag_no_fail_fast: bool, flag_frozen: bool, @@ -55,6 +56,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never + --message-format FMT Error format: human, json-v1 --no-fail-fast Run all tests regardless of failure --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -92,6 +94,10 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); + let message_format = try!(ops::MessageFormat::from_option( + &options.flag_message_format + )); + let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); let empty = Vec::new(); @@ -124,6 +130,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { release: options.flag_release, mode: mode, filter: filter, + message_format: message_format, target_rustdoc_args: None, target_rustc_args: None, }, diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 512117ed8ba..3b88365d5f9 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -59,6 +59,8 @@ pub struct CompileOptions<'a> { pub release: bool, /// Mode for this compile. pub mode: CompileMode, + /// `--error_format` flag for the compiler. + pub message_format: MessageFormat, /// Extra arguments to be passed to rustdoc (for main crate and dependencies) pub target_rustdoc_args: Option<&'a [String]>, /// The specified target will be compiled with all the available arguments, @@ -74,6 +76,23 @@ pub enum CompileMode { Doc { deps: bool }, } +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum MessageFormat { + Human, + Json +} + +impl MessageFormat { + pub fn from_option(opt: &Option) -> CargoResult { + match opt.as_ref().map(|s| s.as_ref()) { + None | Some("human") => Ok(MessageFormat::Human), + Some("json-v1") => Ok(MessageFormat::Json), + Some(other) => bail!("argument for --message-format must be human or json-v1, \ + but found `{}`", other) + } + } +} + pub enum CompileFilter<'a> { Everything, Only { @@ -150,7 +169,7 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>, let root_package = try!(ws.current()); let CompileOptions { config, jobs, target, spec, features, all_features, no_default_features, - release, mode, + release, mode, message_format, ref filter, ref exec_engine, ref target_rustdoc_args, ref target_rustc_args } = *options; @@ -242,6 +261,7 @@ pub fn compile_ws<'a>(ws: &Workspace<'a>, build_config.exec_engine = exec_engine.clone(); build_config.release = release; build_config.test = mode == CompileMode::Test; + build_config.json_errors = message_format == MessageFormat::Json; if let CompileMode::Doc { deps } = mode { build_config.doc_all = deps; } diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index dc12e46ffe8..2001c6c8711 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -295,6 +295,7 @@ fn run_verify(ws: &Workspace, tar: &File, opts: &PackageOpts) -> CargoResult<()> filter: ops::CompileFilter::Everything, exec_engine: None, release: false, + message_format: ops::MessageFormat::Human, mode: ops::CompileMode::Build, target_rustdoc_args: None, target_rustc_args: None, diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 59d1ec57f63..dac09a7ea38 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -5,6 +5,8 @@ use std::fs; use std::path::{self, PathBuf}; use std::sync::Arc; +use rustc_serialize::json; + use core::{Package, PackageId, PackageSet, Target, Resolve}; use core::{Profile, Profiles, Workspace}; use core::shell::ColorConfig; @@ -44,6 +46,7 @@ pub struct BuildConfig { pub release: bool, pub test: bool, pub doc_all: bool, + pub json_errors: bool, } #[derive(Clone, Default)] @@ -212,7 +215,6 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { } } let has_custom_args = unit.profile.rustc_args.is_some(); - let exec_engine = cx.exec_engine.clone(); let filenames = try!(cx.target_filenames(unit)); let root = cx.out_dir(unit); @@ -240,7 +242,9 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { let cwd = cx.config.cwd().to_path_buf(); rustc.args(&try!(cx.rustflags_args(unit))); - + let json_errors = cx.build_config.json_errors; + let package_id = unit.pkg.package_id().clone(); + let target = unit.target.clone(); return Ok(Work::new(move |state| { // Only at runtime have we discovered what the extra -L and -l // arguments are for native libraries, so we process those here. We @@ -266,7 +270,36 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { } state.running(&rustc); - try!(exec_engine.exec(rustc).chain_error(|| { + let process_builder = rustc.into_process_builder(); + try!(if json_errors { + #[derive(RustcEncodable)] + struct Message<'a> { + reason: &'a str, + package_id: &'a PackageId, + target: &'a Target, + message: json::Json, + } + process_builder.exec_with_streaming( + &mut |line| assert!(line.is_empty()), + &mut |line| { + let rustc_message = json::Json::from_str(line).unwrap_or_else(|_| { + panic!("Compiler produced invalid json: `{}`", line) + }); + + let message = Message { + reason: "rustc-message", + package_id: &package_id, + target: &target, + message: rustc_message, + }; + let encoded = json::encode(&message).unwrap(); + println!("{}", encoded); + + }, + ).map(|_| ()) + } else { + process_builder.exec() + }.chain_error(|| { human(format!("Could not compile `{}`.", name)) })); @@ -495,6 +528,10 @@ fn build_base_args(cx: &Context, cmd.arg("--color").arg(&color_config.to_string()); } + if cx.build_config.json_errors { + cmd.arg("--error-format").arg("json"); + } + cmd.arg("--crate-name").arg(&unit.target.crate_name()); if !test { diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs index 48edabd9462..442d8c5a8ae 100644 --- a/src/cargo/ops/mod.rs +++ b/src/cargo/ops/mod.rs @@ -1,6 +1,6 @@ pub use self::cargo_clean::{clean, CleanOptions}; pub use self::cargo_compile::{compile, compile_ws, resolve_dependencies, CompileOptions}; -pub use self::cargo_compile::{CompileFilter, CompileMode}; +pub use self::cargo_compile::{CompileFilter, CompileMode, MessageFormat}; pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages}; pub use self::cargo_rustc::{compile_targets, Compilation, Layout, Kind, Unit}; pub use self::cargo_rustc::{Context, LayoutProxy}; diff --git a/tests/build.rs b/tests/build.rs index 5657396382c..14817b167cd 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2276,6 +2276,81 @@ fn explicit_color_config_is_propagated_to_rustc() { ")); } +#[test] +fn compiler_json_error_format() { + if !is_nightly() { return } + + let p = project("foo") + .file("Cargo.toml", r#" + [project] + + name = "foo" + version = "0.5.0" + authors = ["wycats@example.com"] + + [dependencies.bar] + path = "bar" + "#) + .file("src/main.rs", "fn main() { let unused = 92; }") + .file("bar/Cargo.toml", r#" + [project] + + name = "bar" + version = "0.5.0" + authors = ["wycats@example.com"] + "#) + .file("bar/src/lib.rs", r#"fn dead() {}"#); + + assert_that(p.cargo_process("build").arg("-v") + .arg("--message-format").arg("json-v1"), + execs().with_json(r#" + { + "reason":"rustc-message", + "package_id":"bar 0.5.0 ([..])", + "target":{"kind":["lib"],"name":"bar","src_path":"[..]lib.rs"}, + "message":{ + "children":[],"code":null,"level":"warning","rendered":null, + "message":"function is never used: `dead`, #[warn(dead_code)] on by default", + "spans":[{ + "byte_end":12,"byte_start":0,"column_end":13,"column_start":1,"expansion":null, + "file_name":"[..]","is_primary":true,"label":null,"line_end":1,"line_start":1, + "suggested_replacement":null, + "text":[{"highlight_end":13,"highlight_start":1,"text":"fn dead() {}"}] + }] + } + } + + { + "reason":"rustc-message", + "package_id":"foo 0.5.0 ([..])", + "target":{"kind":["bin"],"name":"foo","src_path":"[..]main.rs"}, + "message":{ + "children":[],"code":null,"level":"warning","rendered":null, + "message":"unused variable: `unused`, #[warn(unused_variables)] on by default", + "spans":[{ + "byte_end":22,"byte_start":16,"column_end":23,"column_start":17,"expansion":null, + "file_name":"[..]","is_primary":true,"label":null,"line_end":1,"line_start":1, + "suggested_replacement":null, + "text":[{"highlight_end":23,"highlight_start":17,"text":"[..]"}] + }] + } + } +"#)); +} + +#[test] +fn wrong_message_format_option() { + let p = project("foo") + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file("src/main.rs", "fn main() {}"); + p.build(); + + assert_that(p.cargo_process("build").arg("--message-format").arg("XML"), + execs().with_status(101) + .with_stderr_contains("\ +[ERROR] argument for --message-format must be human or json-v1, but found `XML`")); +} + #[test] fn no_warn_about_package_metadata() { let p = project("foo") diff --git a/tests/cargotest/support/mod.rs b/tests/cargotest/support/mod.rs index fb6c7daf629..6de6df19764 100644 --- a/tests/cargotest/support/mod.rs +++ b/tests/cargotest/support/mod.rs @@ -258,7 +258,7 @@ pub struct Execs { expect_exit_code: Option, expect_stdout_contains: Vec, expect_stderr_contains: Vec, - expect_json: Option, + expect_json: Option>, } impl Execs { @@ -288,7 +288,9 @@ impl Execs { } pub fn with_json(mut self, expected: &str) -> Execs { - self.expect_json = Some(Json::from_str(expected).unwrap()); + self.expect_json = Some(expected.split("\n\n").map(|obj| { + Json::from_str(obj).unwrap() + }).collect()); self } @@ -324,8 +326,18 @@ impl Execs { &actual.stdout, true)); } - if let Some(ref expect_json) = self.expect_json { - try!(self.match_json(expect_json, &actual.stdout)); + if let Some(ref objects) = self.expect_json { + let lines = match str::from_utf8(&actual.stdout) { + Err(..) => return Err("stdout was not utf8 encoded".to_owned()), + Ok(stdout) => stdout.lines().collect::>(), + }; + if lines.len() != objects.len() { + return Err(format!("expected {} json lines, got {}", + objects.len(), lines.len())); + } + for (obj, line) in objects.iter().zip(lines) { + try!(self.match_json(obj, line)); + } } Ok(()) } @@ -375,14 +387,9 @@ impl Execs { } - fn match_json(&self, expected: &Json, stdout: &[u8]) -> ham::MatchResult { - let stdout = match str::from_utf8(stdout) { - Err(..) => return Err("stdout was not utf8 encoded".to_owned()), - Ok(stdout) => stdout, - }; - - let actual = match Json::from_str(stdout) { - Err(..) => return Err(format!("Invalid json {}", stdout)), + fn match_json(&self, expected: &Json, line: &str) -> ham::MatchResult { + let actual = match Json::from_str(line) { + Err(e) => return Err(format!("invalid json, {}:\n`{}`", e, line)), Ok(actual) => actual, }; From e4643b52b18f0ff2e091de1226dd052e82ae7a63 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 27 Sep 2016 14:39:08 +0300 Subject: [PATCH 2/6] Don't panic while streaming compiler output --- src/cargo/ops/cargo_rustc/custom_build.rs | 4 ++-- src/cargo/ops/cargo_rustc/mod.rs | 14 ++++++++----- src/cargo/util/errors.rs | 9 ++++---- src/cargo/util/process_builder.rs | 25 +++++++++++++++-------- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/cargo/ops/cargo_rustc/custom_build.rs b/src/cargo/ops/cargo_rustc/custom_build.rs index 8835824898c..5a15e85a853 100644 --- a/src/cargo/ops/cargo_rustc/custom_build.rs +++ b/src/cargo/ops/cargo_rustc/custom_build.rs @@ -206,8 +206,8 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>) state.running(&p); let cmd = p.into_process_builder(); let output = try!(cmd.exec_with_streaming( - &mut |out_line| state.stdout(out_line), - &mut |err_line| state.stderr(err_line), + &mut |out_line| { state.stdout(out_line); Ok(()) }, + &mut |err_line| { state.stderr(err_line); Ok(()) }, ).map_err(|mut e| { e.desc = format!("failed to run custom build command for `{}`\n{}", pkg_name, e.desc); diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index dac09a7ea38..7d423dd8dcb 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -280,11 +280,15 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { message: json::Json, } process_builder.exec_with_streaming( - &mut |line| assert!(line.is_empty()), + &mut |line| if !line.is_empty() { + Err(internal(&format!("compiler stdout is not empty: `{}`", line))) + } else { + Ok(()) + }, &mut |line| { - let rustc_message = json::Json::from_str(line).unwrap_or_else(|_| { - panic!("Compiler produced invalid json: `{}`", line) - }); + let rustc_message = try!(json::Json::from_str(line).map_err(|_| { + internal(&format!("compiler produced invalid json: `{}`", line)) + })); let message = Message { reason: "rustc-message", @@ -294,7 +298,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { }; let encoded = json::encode(&message).unwrap(); println!("{}", encoded); - + Ok(()) }, ).map(|_| ()) } else { diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 8b41dd3e6ce..39e22cbe5da 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -110,13 +110,13 @@ pub struct ProcessError { pub desc: String, pub exit: Option, pub output: Option, - cause: Option, + cause: Option>, } impl Error for ProcessError { fn description(&self) -> &str { &self.desc } fn cause(&self) -> Option<&Error> { - self.cause.as_ref().map(|s| s as &Error) + self.cause.as_ref().map(|e| &**e as &Error) } } @@ -375,9 +375,10 @@ impl CargoError for str::ParseBoolError {} // Construction helpers pub fn process_error(msg: &str, - cause: Option, + cause: Option>, status: Option<&ExitStatus>, - output: Option<&Output>) -> ProcessError { + output: Option<&Output>) -> ProcessError +{ let exit = match status { Some(s) => status_to_string(s), None => "never executed".to_string(), diff --git a/src/cargo/util/process_builder.rs b/src/cargo/util/process_builder.rs index 856e337e200..c0d88d2ae86 100644 --- a/src/cargo/util/process_builder.rs +++ b/src/cargo/util/process_builder.rs @@ -5,7 +5,7 @@ use std::fmt; use std::path::Path; use std::process::{Command, Stdio, Output}; -use util::{ProcessError, process_error, read2}; +use util::{CargoResult, ProcessError, process_error, read2}; use util::shell_escape::escape; #[derive(Clone, PartialEq, Debug)] @@ -77,7 +77,7 @@ impl ProcessBuilder { let exit = try!(command.status().map_err(|e| { process_error(&format!("could not execute process `{}`", self.debug_string()), - Some(e), None, None) + Some(Box::new(e)), None, None) })); if exit.success() { @@ -94,8 +94,8 @@ impl ProcessBuilder { let output = try!(command.output().map_err(|e| { process_error(&format!("could not execute process `{}`", - self.debug_string()), - Some(e), None, None) + self.debug_string()), + Some(Box::new(e)), None, None) })); if output.status.success() { @@ -108,8 +108,8 @@ impl ProcessBuilder { } pub fn exec_with_streaming(&self, - on_stdout_line: &mut FnMut(&str), - on_stderr_line: &mut FnMut(&str)) + on_stdout_line: &mut FnMut(&str) -> CargoResult<()>, + on_stderr_line: &mut FnMut(&str) -> CargoResult<()>) -> Result { let mut stdout = Vec::new(); let mut stderr = Vec::new(); @@ -119,6 +119,7 @@ impl ProcessBuilder { .stderr(Stdio::piped()) .stdin(Stdio::null()); + let mut callback_error = None; let status = try!((|| { let mut child = try!(cmd.spawn()); let out = child.stdout.take().unwrap(); @@ -137,10 +138,14 @@ impl ProcessBuilder { let start = dst.len(); dst.extend(data); for line in String::from_utf8_lossy(&dst[start..]).lines() { - if is_out { + if callback_error.is_some() { break } + let callback_result = if is_out { on_stdout_line(line) } else { on_stderr_line(line) + }; + if let Err(e) = callback_result { + callback_error = Some(e); } } })); @@ -148,7 +153,7 @@ impl ProcessBuilder { })().map_err(|e| { process_error(&format!("could not execute process `{}`", self.debug_string()), - Some(e), None, None) + Some(Box::new(e)), None, None) })); let output = Output { stdout: stdout, @@ -159,6 +164,10 @@ impl ProcessBuilder { Err(process_error(&format!("process didn't exit successfully: `{}`", self.debug_string()), None, Some(&output.status), Some(&output))) + } else if let Some(e) = callback_error { + Err(process_error(&format!("failed to parse process output: `{}`", + self.debug_string()), + Some(Box::new(e)), Some(&output.status), Some(&output))) } else { Ok(output) } From ef94f4679633451c2f372cbab6a66a5179d19ed6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 28 Sep 2016 19:54:35 +0300 Subject: [PATCH 3/6] Create a centralized machine_message module --- src/cargo/ops/cargo_rustc/mod.rs | 25 ++++++++----------------- src/cargo/util/machine_message.rs | 30 ++++++++++++++++++++++++++++++ src/cargo/util/mod.rs | 7 ++++--- tests/build.rs | 4 ++-- 4 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 src/cargo/util/machine_message.rs diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 7d423dd8dcb..0b321c0c9c4 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -10,7 +10,7 @@ use rustc_serialize::json; use core::{Package, PackageId, PackageSet, Target, Resolve}; use core::{Profile, Profiles, Workspace}; use core::shell::ColorConfig; -use util::{self, CargoResult, human}; +use util::{self, CargoResult, human, machine_message}; use util::{Config, internal, ChainError, profile, join_paths, short_hash}; use self::job::{Job, Work}; @@ -272,13 +272,6 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { state.running(&rustc); let process_builder = rustc.into_process_builder(); try!(if json_errors { - #[derive(RustcEncodable)] - struct Message<'a> { - reason: &'a str, - package_id: &'a PackageId, - target: &'a Target, - message: json::Json, - } process_builder.exec_with_streaming( &mut |line| if !line.is_empty() { Err(internal(&format!("compiler stdout is not empty: `{}`", line))) @@ -286,18 +279,16 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult { Ok(()) }, &mut |line| { - let rustc_message = try!(json::Json::from_str(line).map_err(|_| { + let compiler_message = try!(json::Json::from_str(line).map_err(|_| { internal(&format!("compiler produced invalid json: `{}`", line)) })); - let message = Message { - reason: "rustc-message", - package_id: &package_id, - target: &target, - message: rustc_message, - }; - let encoded = json::encode(&message).unwrap(); - println!("{}", encoded); + machine_message::FromCompiler::new( + &package_id, + &target, + compiler_message + ).emit(); + Ok(()) }, ).map(|_| ()) diff --git a/src/cargo/util/machine_message.rs b/src/cargo/util/machine_message.rs new file mode 100644 index 00000000000..7de1ead0e67 --- /dev/null +++ b/src/cargo/util/machine_message.rs @@ -0,0 +1,30 @@ +use rustc_serialize::json; +use core::{PackageId, Target}; + +#[derive(RustcEncodable)] +pub struct FromCompiler<'a> { + reason: &'static str, + package_id: &'a PackageId, + target: &'a Target, + message: json::Json, +} + +impl<'a> FromCompiler<'a> { + pub fn new(package_id: &'a PackageId, + target: &'a Target, + message: json::Json) + -> FromCompiler<'a> { + FromCompiler { + reason: "compiler-message", + package_id: package_id, + target: target, + message: message, + } + } + + pub fn emit(self) { + let json = json::encode(&self).unwrap(); + println!("{}", json); + } +} + diff --git a/src/cargo/util/mod.rs b/src/cargo/util/mod.rs index 3b18fb1e573..56bbeed0d99 100644 --- a/src/cargo/util/mod.rs +++ b/src/cargo/util/mod.rs @@ -25,15 +25,16 @@ pub mod errors; pub mod graph; pub mod hex; pub mod important_paths; +pub mod job; +pub mod lev_distance; +pub mod machine_message; +pub mod network; pub mod paths; pub mod process_builder; pub mod profile; pub mod to_semver; pub mod to_url; pub mod toml; -pub mod lev_distance; -pub mod job; -pub mod network; mod cfg; mod dependency_queue; mod rustc; diff --git a/tests/build.rs b/tests/build.rs index 14817b167cd..f30dc54f676 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2305,7 +2305,7 @@ fn compiler_json_error_format() { .arg("--message-format").arg("json-v1"), execs().with_json(r#" { - "reason":"rustc-message", + "reason":"compiler-message", "package_id":"bar 0.5.0 ([..])", "target":{"kind":["lib"],"name":"bar","src_path":"[..]lib.rs"}, "message":{ @@ -2321,7 +2321,7 @@ fn compiler_json_error_format() { } { - "reason":"rustc-message", + "reason":"compiler-message", "package_id":"foo 0.5.0 ([..])", "target":{"kind":["bin"],"name":"foo","src_path":"[..]main.rs"}, "message":{ From a58f6bb65cb5329c49f0f5b75dc43d32f12ad6a5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 1 Oct 2016 13:31:12 +0300 Subject: [PATCH 4/6] Rename message-format flag to json --- src/bin/bench.rs | 11 ++++------- src/bin/build.rs | 12 ++++-------- src/bin/doc.rs | 11 ++++------- src/bin/run.rs | 11 ++++------- src/bin/rustc.rs | 12 ++++-------- src/bin/rustdoc.rs | 11 ++++------- src/bin/test.rs | 11 ++++------- src/cargo/lib.rs | 3 +-- src/cargo/ops/cargo_compile.rs | 13 +------------ tests/build.rs | 8 ++++---- 10 files changed, 34 insertions(+), 69 deletions(-) diff --git a/src/bin/bench.rs b/src/bin/bench.rs index 521c87c2f70..d9abefe40b8 100644 --- a/src/bin/bench.rs +++ b/src/bin/bench.rs @@ -1,5 +1,5 @@ use cargo::core::Workspace; -use cargo::ops; +use cargo::ops::{self, MessageFormat}; use cargo::util::{CliResult, CliError, Human, Config, human}; use cargo::util::important_paths::{find_root_manifest_for_wd}; @@ -16,7 +16,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_lib: bool, flag_bin: Vec, flag_example: Vec, @@ -51,7 +51,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -77,9 +77,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let ops = ops::TestOptions { no_run: options.flag_no_run, no_fail_fast: false, @@ -100,7 +97,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), - message_format: message_format, + message_format: options.flag_message_format, target_rustdoc_args: None, target_rustc_args: None, }, diff --git a/src/bin/build.rs b/src/bin/build.rs index c4619f541e9..0357fe08096 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -1,8 +1,7 @@ use std::env; use cargo::core::Workspace; -use cargo::ops::CompileOptions; -use cargo::ops; +use cargo::ops::{self, CompileOptions, MessageFormat}; use cargo::util::important_paths::{find_root_manifest_for_wd}; use cargo::util::{CliResult, Config}; @@ -18,7 +17,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_release: bool, flag_lib: bool, flag_bin: Vec, @@ -53,7 +52,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -75,9 +74,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -97,7 +93,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), - message_format: message_format, + message_format: options.flag_message_format, target_rustdoc_args: None, target_rustc_args: None, }; diff --git a/src/bin/doc.rs b/src/bin/doc.rs index 83431ef66ff..c1841c20a54 100644 --- a/src/bin/doc.rs +++ b/src/bin/doc.rs @@ -1,5 +1,5 @@ use cargo::core::Workspace; -use cargo::ops; +use cargo::ops::{self, MessageFormat}; use cargo::util::{CliResult, Config}; use cargo::util::important_paths::{find_root_manifest_for_wd}; @@ -17,7 +17,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_package: Vec, flag_lib: bool, flag_bin: Vec, @@ -48,7 +48,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -67,9 +67,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -90,7 +87,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &empty, &empty, &empty), - message_format: message_format, + message_format: options.flag_message_format, release: options.flag_release, mode: ops::CompileMode::Doc { deps: !options.flag_no_deps, diff --git a/src/bin/run.rs b/src/bin/run.rs index 4b03b53bc53..f5055b5eba0 100644 --- a/src/bin/run.rs +++ b/src/bin/run.rs @@ -1,5 +1,5 @@ use cargo::core::Workspace; -use cargo::ops; +use cargo::ops::{self, MessageFormat}; use cargo::util::{CliResult, CliError, Config, Human}; use cargo::util::important_paths::{find_root_manifest_for_wd}; @@ -16,7 +16,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_release: bool, flag_frozen: bool, flag_locked: bool, @@ -43,7 +43,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -63,9 +63,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -96,7 +93,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { bins: &bins, examples: &examples, } }, - message_format: message_format, + message_format: options.flag_message_format, target_rustdoc_args: None, target_rustc_args: None, }; diff --git a/src/bin/rustc.rs b/src/bin/rustc.rs index 2743c3669f0..fa9334f5b29 100644 --- a/src/bin/rustc.rs +++ b/src/bin/rustc.rs @@ -1,8 +1,7 @@ use std::env; use cargo::core::Workspace; -use cargo::ops::{CompileOptions, CompileMode}; -use cargo::ops; +use cargo::ops::{self, CompileOptions, CompileMode, MessageFormat}; use cargo::util::important_paths::{find_root_manifest_for_wd}; use cargo::util::{CliResult, CliError, Config, human}; @@ -19,7 +18,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_release: bool, flag_lib: bool, flag_bin: Vec, @@ -56,7 +55,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -82,9 +81,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -115,7 +111,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), - message_format: message_format, + message_format: options.flag_message_format, target_rustdoc_args: None, target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]), }; diff --git a/src/bin/rustdoc.rs b/src/bin/rustdoc.rs index 79e368090b6..587046200df 100644 --- a/src/bin/rustdoc.rs +++ b/src/bin/rustdoc.rs @@ -1,5 +1,5 @@ use cargo::core::Workspace; -use cargo::ops; +use cargo::ops::{self, MessageFormat}; use cargo::util::{CliResult, Config}; use cargo::util::important_paths::{find_root_manifest_for_wd}; @@ -17,7 +17,7 @@ pub struct Options { flag_release: bool, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_package: Option, flag_lib: bool, flag_bin: Vec, @@ -53,7 +53,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -76,9 +76,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -100,7 +97,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), - message_format: message_format, + message_format: options.flag_message_format, mode: ops::CompileMode::Doc { deps: false }, target_rustdoc_args: Some(&options.arg_opts), target_rustc_args: None, diff --git a/src/bin/test.rs b/src/bin/test.rs index a2f1f5f129b..410c0a2c4d5 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -1,5 +1,5 @@ use cargo::core::Workspace; -use cargo::ops; +use cargo::ops::{self, MessageFormat}; use cargo::util::{CliResult, CliError, Human, human, Config}; use cargo::util::important_paths::{find_root_manifest_for_wd}; @@ -23,7 +23,7 @@ pub struct Options { flag_verbose: u32, flag_quiet: Option, flag_color: Option, - flag_message_format: Option, + flag_message_format: MessageFormat, flag_release: bool, flag_no_fail_fast: bool, flag_frozen: bool, @@ -56,7 +56,7 @@ Options: -v, --verbose ... Use verbose output -q, --quiet No output printed to stdout --color WHEN Coloring: auto, always, never - --message-format FMT Error format: human, json-v1 + --message-format FMT Error format: human, json [default: human] --no-fail-fast Run all tests regardless of failure --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date @@ -94,9 +94,6 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_color, options.flag_frozen, options.flag_locked)); - let message_format = try!(ops::MessageFormat::from_option( - &options.flag_message_format - )); let root = try!(find_root_manifest_for_wd(options.flag_manifest_path, config.cwd())); @@ -130,7 +127,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { release: options.flag_release, mode: mode, filter: filter, - message_format: message_format, + message_format: options.flag_message_format, target_rustdoc_args: None, target_rustc_args: None, }, diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index b96da7d6606..d1a8f908866 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -211,8 +211,7 @@ pub fn version() -> String { }) } -fn flags_from_args(usage: &str, args: &[String], - options_first: bool) -> CliResult +fn flags_from_args(usage: &str, args: &[String], options_first: bool) -> CliResult where T: Decodable { let docopt = Docopt::new(usage).unwrap() diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 3b88365d5f9..0767e9e467a 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -76,23 +76,12 @@ pub enum CompileMode { Doc { deps: bool }, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, RustcDecodable)] pub enum MessageFormat { Human, Json } -impl MessageFormat { - pub fn from_option(opt: &Option) -> CargoResult { - match opt.as_ref().map(|s| s.as_ref()) { - None | Some("human") => Ok(MessageFormat::Human), - Some("json-v1") => Ok(MessageFormat::Json), - Some(other) => bail!("argument for --message-format must be human or json-v1, \ - but found `{}`", other) - } - } -} - pub enum CompileFilter<'a> { Everything, Only { diff --git a/tests/build.rs b/tests/build.rs index f30dc54f676..739a5b9c467 100644 --- a/tests/build.rs +++ b/tests/build.rs @@ -2302,7 +2302,7 @@ fn compiler_json_error_format() { .file("bar/src/lib.rs", r#"fn dead() {}"#); assert_that(p.cargo_process("build").arg("-v") - .arg("--message-format").arg("json-v1"), + .arg("--message-format").arg("json"), execs().with_json(r#" { "reason":"compiler-message", @@ -2346,9 +2346,9 @@ fn wrong_message_format_option() { p.build(); assert_that(p.cargo_process("build").arg("--message-format").arg("XML"), - execs().with_status(101) - .with_stderr_contains("\ -[ERROR] argument for --message-format must be human or json-v1, but found `XML`")); + execs().with_status(1) + .with_stderr_contains( +r#"[ERROR] Could not match 'xml' with any of the allowed variants: ["Human", "Json"]"#)); } #[test] From 1e15d0af59a2a1db9d974e1a47b98ad3d6d08431 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 1 Oct 2016 13:53:42 +0300 Subject: [PATCH 5/6] Store CargoError inside the ProcessError --- src/cargo/util/errors.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 39e22cbe5da..0f1bfe9efb4 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -23,6 +23,7 @@ pub type CargoResult = Result>; pub trait CargoError: Error + Send + 'static { fn is_human(&self) -> bool { false } fn cargo_cause(&self) -> Option<&CargoError>{ None } + fn as_error(&self) -> &Error where Self: Sized { self as &Error } } impl Error for Box { @@ -110,13 +111,13 @@ pub struct ProcessError { pub desc: String, pub exit: Option, pub output: Option, - cause: Option>, + cause: Option>, } impl Error for ProcessError { fn description(&self) -> &str { &self.desc } fn cause(&self) -> Option<&Error> { - self.cause.as_ref().map(|e| &**e as &Error) + self.cause.as_ref().map(|e| e.as_error()) } } @@ -375,7 +376,7 @@ impl CargoError for str::ParseBoolError {} // Construction helpers pub fn process_error(msg: &str, - cause: Option>, + cause: Option>, status: Option<&ExitStatus>, output: Option<&Output>) -> ProcessError { From b9ec2b11ad98167ae9546155b2efda7b5cf34ac4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 5 Oct 2016 21:26:15 +0300 Subject: [PATCH 6/6] Add some docs about JSON messages --- src/doc/header.html | 1 + src/doc/machine-readable-output.md | 78 ++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/doc/machine-readable-output.md diff --git a/src/doc/header.html b/src/doc/header.html index 2ab3c4b4273..83e76173c95 100644 --- a/src/doc/header.html +++ b/src/doc/header.html @@ -39,6 +39,7 @@

CARGO

  • Package ID specs
  • Environment Variables
  • Source Replacement
  • +
  • Machine readable output
  • Policies
  • diff --git a/src/doc/machine-readable-output.md b/src/doc/machine-readable-output.md new file mode 100644 index 00000000000..e486fd6c685 --- /dev/null +++ b/src/doc/machine-readable-output.md @@ -0,0 +1,78 @@ +% Machine readable output. + +Cargo can output information about project and build in JSON format. + +# Information about project structure + +You can use `cargo metadata` command to get information about project structure +and dependencies. The output of the command looks like this: + +``` +{ + // Integer version number of the format. + "version": integer, + + // List of packages for this workspace, including dependencies. + "packages": [ + { + // Opaque package identifier. + "id": PackageId, + + "name": string, + + "version": string, + + "source": SourceId, + + // A list of declared dependencies, see `resolve` field for actual dependencies. + "dependencies": [ Dependency ], + + "targets: [ Target ], + + // Path to Cargo.toml + "manifest_path": string, + } + ], + + "workspace_members": [ PackageId ], + + // Dependencies graph. + "resolve": { + "nodes": [ + { + "id": PackageId, + "dependencies": [ PackageId ] + } + ] + } +} +``` + + +# Compiler errors + +If you supply `--message-format json` to commands like `cargo build`, Cargo +reports compilation errors and warnings in JSON format. Messages go to the +standard output. Each message occupies exactly one line and does not contain +internal `\n` symbols, so it is possible to process messages one by one +without waiting for the whole build to finish. + +The message format looks like this: + +``` +{ + // Type of the message. + "reason": "compiler-message", + + // Unique opaque identifier of compiled package. + "package_id": PackageId, + + // Unique specification of a particular target within the package. + "target": Target, + + // The error message from the compiler in JSON format. + "message": {...} +} +``` + +Package and target specification are the same that `cargo metadata` uses.