first commit
This commit is contained in:
commit
4cd2267497
10 changed files with 644 additions and 0 deletions
168
src/main.rs
Normal file
168
src/main.rs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
io::{self, Write},
|
||||
panic::{catch_unwind, resume_unwind},
|
||||
process::Command,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crossterm::{
|
||||
cursor,
|
||||
event::{Event, KeyCode, KeyEventKind, KeyModifiers, read},
|
||||
execute,
|
||||
terminal::*,
|
||||
};
|
||||
use rayon::iter::{ParallelBridge, ParallelIterator};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Version {
|
||||
Stable(usize),
|
||||
Beta,
|
||||
Nightly,
|
||||
}
|
||||
|
||||
impl Version {
|
||||
fn iterate() -> impl Iterator<Item = Self> {
|
||||
(0..=95)
|
||||
.filter(|i| *i != 32)
|
||||
.map(Self::Stable)
|
||||
.chain([Self::Beta, Self::Nightly])
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Version {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Version::Stable(v) => write!(f, "1.{v}.0"),
|
||||
Version::Beta => write!(f, "beta"),
|
||||
Version::Nightly => write!(f, "nightly"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
struct Entry {
|
||||
output: Arc<Vec<u8>>,
|
||||
output_noansi: Arc<Vec<u8>>,
|
||||
version: Version,
|
||||
}
|
||||
|
||||
fn run_rustc(version: Version, args: &[String]) -> io::Result<Entry> {
|
||||
let mut cmd = Command::new("rustc");
|
||||
cmd.arg(format!("+{version}"))
|
||||
.args(["--color", "always"])
|
||||
.args(args);
|
||||
|
||||
let output = cmd.output()?;
|
||||
|
||||
Ok(Entry {
|
||||
output: Arc::new(output.stderr.clone()),
|
||||
output_noansi: Arc::new(strip_ansi_escapes::strip(output.stderr)),
|
||||
version,
|
||||
})
|
||||
}
|
||||
|
||||
fn tui(changes: Vec<Entry>) -> io::Result<()> {
|
||||
let mut curr = 0;
|
||||
|
||||
loop {
|
||||
{
|
||||
let mut stdout = io::stdout().lock();
|
||||
execute!(&mut stdout, Clear(ClearType::All))?;
|
||||
execute!(&mut stdout, cursor::MoveTo(0, 0))?;
|
||||
|
||||
let entry = &changes[curr];
|
||||
writeln!(&mut stdout, "in version {}\r", entry.version)?;
|
||||
stdout.write_all(
|
||||
&entry
|
||||
.output
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(|&i| if i == b'\n' { vec![b'\r', i] } else { vec![i] })
|
||||
.collect::<Vec<_>>(),
|
||||
)?;
|
||||
writeln!(&mut stdout)?;
|
||||
}
|
||||
|
||||
match read()? {
|
||||
Event::Key(event) if let KeyEventKind::Press = event.kind => match event.code {
|
||||
KeyCode::Esc | KeyCode::Char('q') => break,
|
||||
KeyCode::Char('c') if event.modifiers.contains(KeyModifiers::CONTROL) => break,
|
||||
KeyCode::Left => {
|
||||
curr = curr.saturating_sub(1);
|
||||
}
|
||||
KeyCode::Right => {
|
||||
if curr < changes.len() - 1 {
|
||||
curr += 1;
|
||||
}
|
||||
}
|
||||
KeyCode::Home => {
|
||||
curr = 0;
|
||||
}
|
||||
KeyCode::End => {
|
||||
curr = changes.len() - 1;
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let args = std::env::args().skip(1).collect::<Vec<_>>();
|
||||
|
||||
let mut outputs = Version::iterate()
|
||||
.par_bridge()
|
||||
.flat_map(|version| {
|
||||
eprintln!("compiling {version}");
|
||||
let output = match run_rustc(version, &args) {
|
||||
Ok(i) => i,
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(output)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
outputs.sort_by_key(|i| i.version);
|
||||
|
||||
let mut changes = Vec::new();
|
||||
let mut last = None::<Entry>;
|
||||
for curr in outputs {
|
||||
if let Some(last) = &last
|
||||
// && last.output_noansi == curr.output_noansi
|
||||
&& last.output == curr.output
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
last = Some(curr.clone());
|
||||
changes.push(curr);
|
||||
}
|
||||
|
||||
if changes.is_empty() {
|
||||
eprintln!("no changes");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
enable_raw_mode()?;
|
||||
let unwind = catch_unwind(move || -> io::Result<()> {
|
||||
execute!(io::stdout(), EnterAlternateScreen)?;
|
||||
tui(changes)?;
|
||||
Ok(())
|
||||
});
|
||||
let _ = execute!(io::stdout(), LeaveAlternateScreen);
|
||||
let _ = disable_raw_mode();
|
||||
match unwind {
|
||||
Err(e) => resume_unwind(e),
|
||||
Ok(r) => r?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue