171 lines
4.3 KiB
Rust
171 lines
4.3 KiB
Rust
use std::{
|
|
env::temp_dir,
|
|
ffi::OsString,
|
|
fmt::{Debug, Display},
|
|
fs::{self, File},
|
|
mem,
|
|
path::PathBuf,
|
|
process::{Command, exit},
|
|
str::FromStr,
|
|
};
|
|
|
|
mod tui;
|
|
|
|
use clap::{Parser, Subcommand, ValueEnum, builder::PossibleValue};
|
|
use jiff::Zoned;
|
|
use ratatui_themes::ThemeName;
|
|
|
|
#[repr(transparent)]
|
|
#[derive(Clone)]
|
|
pub struct Theme(ThemeName);
|
|
|
|
impl Debug for Theme {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.0)
|
|
}
|
|
}
|
|
|
|
impl Display for Theme {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.0.slug())
|
|
}
|
|
}
|
|
|
|
impl FromStr for Theme {
|
|
type Err = <ThemeName as FromStr>::Err;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
Ok(Self(s.parse()?))
|
|
}
|
|
}
|
|
|
|
impl ValueEnum for Theme {
|
|
fn value_variants<'a>() -> &'a [Self] {
|
|
// Safety: repr transparent
|
|
unsafe { mem::transmute(ThemeName::all()) }
|
|
}
|
|
|
|
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
|
|
Some(PossibleValue::new(self.to_string()))
|
|
}
|
|
}
|
|
|
|
macro_rules! types_crates {
|
|
() => {
|
|
"rustc_hir_typeck,rustc_infer,rustc_next_trait_solver,rustc_middle,rustc_traits,rustc_trait_selection,rustc_type_ir,rustc_ty_utils"
|
|
}
|
|
}
|
|
|
|
#[derive(Subcommand, Debug)]
|
|
enum Preset {
|
|
/// Explore logs
|
|
Show {
|
|
/// Path where the compiler source code lives, for links in the TUI to work.
|
|
#[arg(long = "compiler-root")]
|
|
compiler_root: Option<PathBuf>,
|
|
|
|
/// Path where the compiler source code lives, for links in the TUI to work.
|
|
#[arg(default_value_t = Theme(ThemeName::Dracula))]
|
|
#[arg(long = "theme")]
|
|
theme: Theme,
|
|
},
|
|
|
|
#[command(about = concat!("Get all the typesystem related logs: ", types_crates!()))]
|
|
Types,
|
|
/// Get all logs
|
|
All,
|
|
/// Specific, comma-separated crates to gather logs from
|
|
Crates {
|
|
#[arg(short, long)]
|
|
crates: Vec<String>,
|
|
},
|
|
}
|
|
|
|
fn default_tempdir() -> PathBuf {
|
|
let home = std::env::var("HOME").unwrap();
|
|
let t_rs_tempdirs = PathBuf::from(home).join("tempdirs");
|
|
let tempdir = if t_rs_tempdirs.exists() {
|
|
t_rs_tempdirs
|
|
} else {
|
|
temp_dir()
|
|
};
|
|
|
|
tempdir.join("rustc-logviz")
|
|
}
|
|
|
|
#[derive(Parser, Debug)]
|
|
#[command(version, about, long_about)]
|
|
struct Args {
|
|
#[command(subcommand)]
|
|
preset: Preset,
|
|
|
|
#[arg(default_value_os_t = default_tempdir())]
|
|
#[arg(global = true)]
|
|
#[arg(long = "logs-dir")]
|
|
logs_dir: PathBuf,
|
|
|
|
#[arg(trailing_var_arg = true)]
|
|
#[arg(allow_hyphen_values = true)]
|
|
#[arg(global = true)]
|
|
rest: Vec<OsString>,
|
|
}
|
|
|
|
fn main() {
|
|
let Args {
|
|
preset,
|
|
logs_dir,
|
|
rest,
|
|
} = Args::parse();
|
|
|
|
let rustc_log = match preset {
|
|
Preset::Show {
|
|
compiler_root,
|
|
theme: Theme(theme),
|
|
} => {
|
|
tui::run(logs_dir, compiler_root, theme);
|
|
exit(0);
|
|
}
|
|
Preset::Types => types_crates!().to_string(),
|
|
Preset::All => "debug".to_string(),
|
|
Preset::Crates { crates } => crates.join(",").to_string(),
|
|
};
|
|
|
|
let (first, rest) = {
|
|
let mut rest = rest.into_iter();
|
|
let Some(first) = rest.next() else {
|
|
eprintln!("no command given, exiting");
|
|
exit(0);
|
|
};
|
|
(first, rest.collect::<Vec<_>>())
|
|
};
|
|
|
|
if let Err(e) = fs::create_dir_all(&logs_dir) {
|
|
eprintln!("failed to create logs dir at {}: {e:?}", logs_dir.display());
|
|
exit(1)
|
|
}
|
|
|
|
let now = Zoned::now().strftime("%b %e %H:%M:%S");
|
|
let log_file_path = logs_dir.join(format!("{now}.log"));
|
|
let _log_file = match File::create(&log_file_path) {
|
|
Ok(i) => i,
|
|
Err(e) => {
|
|
eprintln!(
|
|
"failed to create logfile at {}: {e:?}",
|
|
log_file_path.display()
|
|
);
|
|
exit(1)
|
|
}
|
|
};
|
|
|
|
eprintln!("outputting json logs to {}", log_file_path.display());
|
|
if let Err(e) = Command::new(first)
|
|
.args(rest)
|
|
.env("RUSTC_LOG", rustc_log)
|
|
.env("RUSTC_LOG_FORMAT_JSON", "1")
|
|
.env("RUSTC_LOG_OUTPUT_TARGET", log_file_path)
|
|
.status()
|
|
{
|
|
eprintln!("failed to spawn command: {e:?}, exiting");
|
|
exit(1);
|
|
}
|
|
}
|