add tracing

This commit is contained in:
nora 2022-12-18 12:03:46 +01:00
parent 1cb5114557
commit e1fd83b4d9
8 changed files with 264 additions and 33 deletions

View file

@ -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<EnvVar>,
}
#[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
}

View file

@ -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<EnvVar>,
#[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<Self, Self::Err> {
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();

View file

@ -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(())

View file

@ -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<String>);
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,

View file

@ -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