From e1fd83b4d9be173d3ebeb187c8133a66a1afaba4 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 18 Dec 2022 12:03:46 +0100 Subject: [PATCH] add tracing --- Cargo.lock | 133 ++++++++++++++++++++++++++++ Cargo.toml | 5 +- src/build.rs | 78 ++++++++++++---- src/lib.rs | 30 ++++++- src/main.rs | 12 +++ src/processor/mod.rs | 27 ++++-- src/processor/reaper.rs | 8 +- test-cases/unused-code/src/other.rs | 4 +- 8 files changed, 264 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c7d758a..5a986db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,6 +159,9 @@ dependencies = [ "serde", "serde_json", "syn", + "tracing", + "tracing-subscriber", + "tracing-tree", "walkdir", ] @@ -802,6 +805,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.5.0" @@ -826,6 +838,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num_cpus" version = "1.13.1" @@ -914,6 +936,12 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pathdiff" version = "0.2.1" @@ -926,6 +954,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "pkg-config" version = "0.3.25" @@ -1024,6 +1058,9 @@ name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] [[package]] name = "regex-syntax" @@ -1146,6 +1183,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -1162,6 +1208,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.7" @@ -1280,6 +1332,81 @@ dependencies = [ "serde", ] +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-tree" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758e983ab7c54fee18403994507e7f212b9005e957ce7984996fac8d11facedb" +dependencies = [ + "atty", + "nu-ansi-term", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "typenum" version = "1.15.0" @@ -1336,6 +1463,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 0c4b85a..2b468c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ exclude = ["test-cases/*"] name = "cargo-minimize" version = "0.1.0" edition = "2021" -about = "A tool for minimizing rustc ICEs" +description = "A tool for minimizing rustc ICEs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -20,4 +20,7 @@ rustfix = "0.6.1" serde = { version = "1.0.151", features = ["derive"] } serde_json = "1.0.90" syn = { version = "1.0.101", features = ["full", "visit", "visit-mut"] } +tracing = "0.1.37" +tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +tracing-tree = "0.2.2" walkdir = "2.3.2" diff --git a/src/build.rs b/src/build.rs index a8d98ed..88207fa 100644 --- a/src/build.rs +++ b/src/build.rs @@ -1,9 +1,9 @@ -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use rustfix::diagnostics::Diagnostic; use serde::Deserialize; use std::{collections::HashSet, fmt::Display, path::PathBuf, process::Command, rc::Rc}; -use crate::Options; +use crate::{EnvVar, Options}; #[derive(Debug, Clone)] pub struct Build { @@ -15,6 +15,7 @@ struct BuildInner { mode: BuildMode, input_path: PathBuf, no_verify: bool, + env: Vec, } #[derive(Debug)] @@ -38,11 +39,13 @@ impl Build { .map(|cmd| cmd.split_whitespace().map(ToString::to_string).collect()), } }; + Self { inner: Rc::new(BuildInner { mode, input_path: options.path.clone(), no_verify: options.no_verify, + env: options.env.clone(), }), } } @@ -52,10 +55,11 @@ impl Build { return Ok(BuildResult { reproduces_issue: false, no_verify: true, + output: String::new(), }); } - let reproduces_issue = match &self.inner.mode { + let (reproduces_issue, output) = match &self.inner.mode { BuildMode::Cargo { args } => { let mut cmd = Command::new("cargo"); cmd.arg("build"); @@ -64,33 +68,58 @@ impl Build { cmd.arg(arg); } - let output = - String::from_utf8(cmd.output().context("spawning rustc process")?.stderr) - .unwrap(); + for env in &self.inner.env { + cmd.env(&env.key, &env.value); + } - output.contains("internal compiler error") + let outputs = cmd.output().context("spawning rustc process")?; + + let output = String::from_utf8(outputs.stderr)?; + + ( + outputs.status.code() == Some(101) + || output.contains("internal compiler error"), + output, + ) } BuildMode::Script(script_path) => { let mut cmd = Command::new(script_path); - cmd.output().context("spawning script")?.status.success() + for env in &self.inner.env { + cmd.env(&env.key, &env.value); + } + + let outputs = cmd.output().context("spawning script")?; + + let output = String::from_utf8(outputs.stderr)?; + + (outputs.status.success(), output) } BuildMode::Rustc => { let mut cmd = Command::new("rustc"); - cmd.args(["--edition", "2018"]); + cmd.args(["--edition", "2021"]); cmd.arg(&self.inner.input_path); - cmd.output() - .context("spawning rustc process")? - .status - .code() - == Some(101) + for env in &self.inner.env { + cmd.env(&env.key, &env.value); + } + + let outputs = cmd.output().context("spawning rustc process")?; + + let output = String::from_utf8(outputs.stderr)?; + + ( + outputs.status.code() == Some(101) + || output.contains("internal compiler error"), + output, + ) } }; Ok(BuildResult { reproduces_issue, no_verify: self.inner.no_verify, + output, }) } @@ -104,6 +133,10 @@ impl Build { cmd.arg(arg); } + for env in &self.inner.env { + cmd.env(&env.key, &env.value); + } + let cmd_output = cmd.output()?; let output = String::from_utf8(cmd_output.stdout.clone())?; @@ -121,9 +154,13 @@ impl Build { } BuildMode::Rustc => { let mut cmd = std::process::Command::new("rustc"); - cmd.args(["--edition", "2018", "--error-format=json"]); + cmd.args(["--edition", "2021", "--error-format=json"]); cmd.arg(&self.inner.input_path); + for env in &self.inner.env { + cmd.env(&env.key, &env.value); + } + let output = cmd.output()?.stderr; let output = String::from_utf8(output)?; @@ -153,9 +190,20 @@ impl Build { pub struct BuildResult { reproduces_issue: bool, no_verify: bool, + output: String, } impl BuildResult { + pub fn require_reproduction(&self, build: &str) -> Result<()> { + if !self.reproduces_issue() { + bail!( + "{build} build must reproduce issue. Output:\n{}", + self.output + ); + } + Ok(()) + } + pub fn reproduces_issue(&self) -> bool { self.reproduces_issue || self.no_verify } diff --git a/src/lib.rs b/src/lib.rs index 29a21c3..00b0f55 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,7 @@ -use std::path::PathBuf; +#[macro_use] +extern crate tracing; + +use std::{path::PathBuf, str::FromStr}; mod build; mod everybody_loops; @@ -31,10 +34,35 @@ pub struct Options { #[arg(long)] no_verify: bool, + #[arg(long)] + env: Vec, + #[arg(default_value = "src")] path: PathBuf, } +#[derive(Debug, Clone)] +struct EnvVar { + key: String, + value: String, +} + +impl FromStr for EnvVar { + type Err = &'static str; + fn from_str(s: &str) -> Result { + let mut split = s.split("="); + let key = split + .next() + .ok_or("env var must have KEY=VALUE format")? + .to_string(); + let value = split + .next() + .ok_or("env var must have KEY=VALUE format")? + .to_string(); + Ok(Self { key, value }) + } +} + pub fn minimize() -> Result<()> { let Cargo::Minimize(options) = Cargo::parse(); diff --git a/src/main.rs b/src/main.rs index 3e7d641..0ea65b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,18 @@ use anyhow::Result; +use tracing::info; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry}; fn main() -> Result<()> { + let registry = Registry::default().with(EnvFilter::from_default_env()); + + info!("Starting cargo-minimize"); + + let tree_layer = tracing_tree::HierarchicalLayer::new(2) + .with_targets(true) + .with_bracketed_fields(true); + + registry.with(tree_layer).init(); + cargo_minimize::minimize()?; Ok(()) diff --git a/src/processor/mod.rs b/src/processor/mod.rs index c9cea22..bbe3c66 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -1,9 +1,9 @@ mod files; mod reaper; -use std::{borrow::Borrow, collections::HashSet, ffi::OsStr, mem, path::Path}; +use std::{borrow::Borrow, collections::HashSet, ffi::OsStr, fmt::Debug, mem, path::Path}; -use anyhow::{ensure, Context, Result}; +use anyhow::{Context, Result}; use crate::{build::Build, processor::files::Changes}; @@ -27,6 +27,12 @@ pub trait Processor { fn name(&self) -> &'static str; } +impl Debug for dyn Processor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.name()) + } +} + #[derive(Debug, PartialEq, Eq)] pub enum ProcessState { NoChange, @@ -71,10 +77,7 @@ impl Minimizer { ) -> Result<()> { let inital_build = self.build.build()?; println!("Initial build: {}", inital_build); - ensure!( - inital_build.reproduces_issue(), - "Initial build must reproduce issue" - ); + inital_build.require_reproduction("Initial")?; for mut pass in passes { self.run_pass(&mut *pass)?; @@ -89,7 +92,9 @@ impl Minimizer { let mut refresh_and_try_again = false; loop { - println!("Starting a round of {}", pass.name()); + let span = info_span!("Starting round of pass", name = pass.name()); + let _enter = span.enter(); + let mut changes = Changes::default(); for file in &self.files { @@ -176,7 +181,7 @@ impl Minimizer { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash)] struct AstPath(Vec); impl Borrow<[String]> for AstPath { @@ -185,6 +190,12 @@ impl Borrow<[String]> for AstPath { } } +impl Debug for AstPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "AstPath({:?})", self.0) + } +} + #[derive(Debug)] pub struct PassController { state: PassControllerState, diff --git a/src/processor/reaper.rs b/src/processor/reaper.rs index 3b0f39b..9412da1 100644 --- a/src/processor/reaper.rs +++ b/src/processor/reaper.rs @@ -5,7 +5,7 @@ use crate::build::Build; use super::{ files::Changes, tracking, Minimizer, PassController, ProcessState, Processor, SourceFile, }; -use anyhow::{ensure, Context, Result}; +use anyhow::{Context, Result}; use proc_macro2::Span; use quote::ToTokens; use rustfix::{diagnostics::Diagnostic, Suggestion}; @@ -24,10 +24,8 @@ impl Minimizer { pub fn delete_dead_code(&mut self) -> Result<()> { let inital_build = self.build.build()?; println!("Before reaper: {}", inital_build); - ensure!( - inital_build.reproduces_issue(), - "Initial build must reproduce issue" - ); + + inital_build.require_reproduction("Initial")?; let (diags, suggestions) = self .build diff --git a/test-cases/unused-code/src/other.rs b/test-cases/unused-code/src/other.rs index aefc744..85682db 100644 --- a/test-cases/unused-code/src/other.rs +++ b/test-cases/unused-code/src/other.rs @@ -1,3 +1 @@ -pub fn unused() { - -} +pub(crate) fn unused() {}