Skip to content
This repository was archived by the owner on Nov 24, 2023. It is now read-only.

Commit 17bcea9

Browse files
authored
Merge pull request #93 from alexcrichton/warn-when-break
Warn users when fixes break code
2 parents 5de95a9 + 8f44658 commit 17bcea9

File tree

4 files changed

+137
-40
lines changed

4 files changed

+137
-40
lines changed

cargo-fix/src/cli.rs

+54-24
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
use std::env;
22
use std::process::Command;
3+
use std::io::Write;
34

4-
use failure::{Error, ResultExt};
55
use clap::{App, AppSettings, Arg, SubCommand};
6-
use atty;
6+
use failure::{Error, ResultExt};
7+
use termcolor::{Color, ColorSpec, StandardStream, WriteColor};
78

89
use lock;
9-
use diagnostics;
10+
use diagnostics::{Message, Server};
1011
use super::exit_with;
1112

13+
static PLEASE_REPORT_THIS_BUG: &str = "\
14+
This likely indicates a bug in either rustc or rustfix itself,\n\
15+
and we would appreciate a bug report! You're likely to see \n\
16+
a number of compiler warnings after this message which rustfix\n\
17+
attempted to fix but failed. If you could open an issue at\n\
18+
https://github.com/rust-lang-nursery/rustfix/issues\n\
19+
quoting the full output of this command we'd be very appreciative!\n\n\
20+
";
21+
1222
pub fn run() -> Result<(), Error> {
1323
let matches = App::new("Cargo Fix")
1424
.bin_name("cargo")
@@ -41,8 +51,10 @@ pub fn run() -> Result<(), Error> {
4151

4252
// Spin up our diagnostics server which our subprocesses will use to send
4353
// use their dignostics messages in an ordered way.
44-
let _lockserver = diagnostics::Server::new()?.start(|m| {
45-
let _ = log_message(&m);
54+
let _lockserver = Server::new()?.start(|m, stream| {
55+
if let Err(e) = log_message(&m, stream) {
56+
warn!("failed to log message: {}", e);
57+
}
4658
})?;
4759

4860
let cargo = env::var_os("CARGO").unwrap_or("cargo".into());
@@ -74,7 +86,7 @@ pub fn run() -> Result<(), Error> {
7486
exit_with(status);
7587
}
7688

77-
fn log_message(msg: &diagnostics::Message) -> Result<(), Error> {
89+
fn log_message(msg: &Message, stream: &mut StandardStream) -> Result<(), Error> {
7890
use diagnostics::Message::*;
7991

8092
match *msg {
@@ -87,33 +99,51 @@ fn log_message(msg: &diagnostics::Message) -> Result<(), Error> {
8799
n = fixes,
88100
fixes = if *fixes > 1 { "fixes" } else { "fix" },
89101
),
102+
stream,
90103
)?;
91104
}
105+
FixFailed { ref files, ref krate } => {
106+
stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)))?;
107+
write!(stream, "warning")?;
108+
stream.reset()?;
109+
stream.set_color(ColorSpec::new().set_bold(true))?;
110+
write!(stream, ": ")?;
111+
if let Some(ref krate) = *krate {
112+
write!(
113+
stream,
114+
"failed to automatically apply fixes suggested by rustc \
115+
to crate `{}`\n",
116+
krate,
117+
)?;
118+
} else {
119+
write!(stream, "failed to automatically apply fixes suggested by rustc\n")?;
120+
}
121+
if files.len() > 0 {
122+
write!(
123+
stream,
124+
"\nafter fixes were automatically applied the compiler \
125+
reported errors within these files:\n\n"
126+
)?;
127+
for file in files {
128+
write!(stream, " * {}\n", file)?;
129+
}
130+
write!(stream, "\n")?;
131+
132+
}
133+
stream.write(PLEASE_REPORT_THIS_BUG.as_bytes())?;
134+
}
92135
}
93136

137+
stream.reset()?;
138+
stream.flush()?;
94139
Ok(())
95140
}
96141

97-
fn log_for_human(kind: &str, msg: &str) -> Result<(), Error> {
98-
use std::io::Write;
99-
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
100-
101-
// Adapted from cargo, cf. <https://github.com/rust-lang/cargo/blob/5986492773e6de61cced57f457da3700607f4a3a/src/cargo/core/shell.rs#L291>
102-
let color_choice = if atty::is(atty::Stream::Stderr) {
103-
ColorChoice::Auto
104-
} else {
105-
ColorChoice::Never
106-
};
107-
let mut stream = StandardStream::stderr(color_choice);
108-
stream.reset()?;
109-
142+
fn log_for_human(kind: &str, msg: &str, stream: &mut StandardStream) -> Result<(), Error> {
110143
stream.set_color(ColorSpec::new().set_bold(true).set_fg(Some(Color::Cyan)))?;
111144
// Justify to 12 chars just like cargo
112-
write!(&mut stream, "{:>12}", kind)?;
145+
write!(stream, "{:>12}", kind)?;
113146
stream.reset()?;
114-
115-
write!(&mut stream, " {}\n", msg)?;
116-
stream.flush()?;
117-
147+
write!(stream, " {}\n", msg)?;
118148
Ok(())
119149
}

cargo-fix/src/diagnostics.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,17 @@ use std::io::{BufReader, Write, Read};
66
use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream};
77
use std::thread::{self, JoinHandle};
88

9+
use atty;
910
use failure::{Error, ResultExt};
1011
use serde_json;
12+
use termcolor::{ColorChoice, StandardStream};
1113

1214
static DIAGNOSICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER";
1315

1416
#[derive(Deserialize, Serialize)]
1517
pub enum Message {
1618
Fixing { file: String, fixes: usize },
19+
FixFailed { files: Vec<String>, krate: Option<String> },
1720
}
1821

1922
impl Message {
@@ -62,10 +65,9 @@ impl Server {
6265
Ok(Server { listener })
6366
}
6467

65-
pub fn start<F: Fn(Message) + Send + 'static>(
66-
self,
67-
on_message: F,
68-
) -> Result<StartedServer, Error> {
68+
pub fn start<F>(self, on_message: F) -> Result<StartedServer, Error>
69+
where F: Fn(Message, &mut StandardStream) + Send + 'static,
70+
{
6971
let _addr = self.listener.local_addr()?;
7072
let thread = thread::spawn(move || {
7173
self.run(on_message);
@@ -77,11 +79,19 @@ impl Server {
7779
})
7880
}
7981

80-
fn run<F: Fn(Message)>(self, on_message: F) {
82+
fn run<F>(self, on_message: F)
83+
where F: Fn(Message, &mut StandardStream)
84+
{
85+
let color_choice = if atty::is(atty::Stream::Stderr) {
86+
ColorChoice::Auto
87+
} else {
88+
ColorChoice::Never
89+
};
90+
let mut stream = StandardStream::stderr(color_choice);
8191
while let Ok((client, _)) = self.listener.accept() {
8292
let mut client = BufReader::new(client);
8393
match serde_json::from_reader(client) {
84-
Ok(message) => on_message(message),
94+
Ok(message) => on_message(message, &mut stream),
8595
Err(e) => {
8696
warn!("invalid diagnostics message: {}", e);
8797
}

cargo-fix/src/main.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extern crate serde_derive;
1111
extern crate serde_json;
1212
extern crate termcolor;
1313

14-
use std::collections::{HashMap, HashSet};
14+
use std::collections::{HashMap, HashSet, BTreeSet};
1515
use std::env;
1616
use std::fs::File;
1717
use std::io::{Read, Write};
@@ -86,6 +86,7 @@ fn cargo_fix_rustc() -> Result<(), Error> {
8686
let mut cmd = Command::new(&rustc);
8787
cmd.args(env::args().skip(1));
8888
cmd.arg("--cap-lints=warn");
89+
cmd.arg("--error-format=json");
8990
if fixes.original_files.len() > 0 {
9091
let output = cmd.output().context("failed to spawn rustc")?;
9192

@@ -111,9 +112,13 @@ fn cargo_fix_rustc() -> Result<(), Error> {
111112
.and_then(|mut f| f.write_all(v.as_bytes()))
112113
.with_context(|_| format!("failed to write file `{}`", k))?;
113114
}
115+
log_failed_fix(&output.stderr)?;
114116
}
115117
}
116118

119+
let mut cmd = Command::new(&rustc);
120+
cmd.args(env::args().skip(1));
121+
cmd.arg("--cap-lints=warn");
117122
exit_with(cmd.status().context("failed to spawn rustc")?);
118123
}
119124

@@ -248,3 +253,36 @@ fn exit_with(status: ExitStatus) -> ! {
248253
}
249254
process::exit(status.code().unwrap_or(3));
250255
}
256+
257+
fn log_failed_fix(stderr: &[u8]) -> Result<(), Error> {
258+
let stderr = str::from_utf8(stderr)
259+
.context("failed to parse rustc stderr as utf-8")?;
260+
261+
let diagnostics = stderr.lines()
262+
.filter(|x| !x.is_empty())
263+
.filter_map(|line| serde_json::from_str::<Diagnostic>(line).ok());
264+
let mut files = BTreeSet::new();
265+
for diagnostic in diagnostics {
266+
for span in diagnostic.spans.into_iter() {
267+
files.insert(span.file_name);
268+
}
269+
}
270+
let mut krate = None;
271+
let mut prev_dash_dash_krate_name = false;
272+
for arg in env::args() {
273+
if prev_dash_dash_krate_name {
274+
krate = Some(arg.clone());
275+
}
276+
277+
if arg == "--crate-name" {
278+
prev_dash_dash_krate_name = true;
279+
} else {
280+
prev_dash_dash_krate_name = false;
281+
}
282+
}
283+
284+
let files = files.into_iter().collect();
285+
Message::FixFailed { files, krate }.post()?;
286+
287+
Ok(())
288+
}

cargo-fix/tests/all/broken_build.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ fn broken_fixes_backed_out() {
5353
)
5454
.file(
5555
"foo/src/main.rs",
56-
r#"
56+
r##"
5757
use std::env;
58-
use std::process::{self, Command};
59-
use std::path::{Path, PathBuf};
6058
use std::fs;
59+
use std::io::Write;
60+
use std::path::{Path, PathBuf};
61+
use std::process::{self, Command};
6162
6263
fn main() {
6364
let is_lib_rs = env::args_os()
@@ -67,7 +68,10 @@ fn broken_fixes_backed_out() {
6768
let path = PathBuf::from(env::var_os("OUT_DIR").unwrap());
6869
let path = path.join("foo");
6970
if path.exists() {
70-
panic!("failing the second compilation, oh no!");
71+
fs::File::create("src/lib.rs")
72+
.unwrap()
73+
.write_all(b"not rust code")
74+
.unwrap();
7175
} else {
7276
fs::File::create(&path).unwrap();
7377
}
@@ -79,7 +83,7 @@ fn broken_fixes_backed_out() {
7983
.expect("failed to run rustc");
8084
process::exit(status.code().unwrap_or(2));
8185
}
82-
"#,
86+
"##,
8387
)
8488
.file(
8589
"bar/Cargo.toml",
@@ -109,11 +113,26 @@ fn broken_fixes_backed_out() {
109113
p.expect_cmd("cargo-fix fix")
110114
.cwd("bar")
111115
.env("RUSTC", p.root.join("foo/target/debug/foo"))
112-
.stderr_contains("oh no")
116+
.stderr_contains("not rust code")
117+
.stderr_contains(
118+
"\
119+
warning: failed to automatically apply fixes suggested by rustc \
120+
to crate `bar`\n\
121+
\n\
122+
after fixes were automatically applied the compiler reported \
123+
errors within these files:\n\
124+
\n \
125+
* src/lib.rs\n\
126+
\n\
127+
This likely indicates a bug in either rustc or rustfix itself,\n\
128+
and we would appreciate a bug report! You're likely to see \n\
129+
a number of compiler warnings after this message which rustfix\n\
130+
attempted to fix but failed. If you could open an issue at\n\
131+
https://github.com/rust-lang-nursery/rustfix/issues\n\
132+
quoting the full output of this command we'd be very appreciative!\n\n\
133+
"
134+
)
113135
.stderr_not_contains("[FIXING]")
114136
.status(101)
115137
.run();
116-
117-
// Make sure the fix which should have been applied was backed out
118-
assert!(p.read("bar/src/lib.rs").contains("let mut x = 3;"));
119138
}

0 commit comments

Comments
 (0)