blob: 02b18b21b1b3fa7e81cca0bc6285c168b4b00a16 [file] [log] [blame]
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use console::{Style, Term};
use indicatif::{HumanDuration, ProgressBar, ProgressStyle};
use rand::Rng;
static CRATES: &[(&str, &str)] = &[
("console", "v0.14.1"),
("lazy_static", "v1.4.0"),
("libc", "v0.2.93"),
("regex", "v1.4.6"),
("regex-syntax", "v0.6.23"),
("terminal_size", "v0.1.16"),
("libc", "v0.2.93"),
("unicode-width", "v0.1.8"),
("lazy_static", "v1.4.0"),
("number_prefix", "v0.4.0"),
("regex", "v1.4.6"),
("rand", "v0.8.3"),
("getrandom", "v0.2.2"),
("cfg-if", "v1.0.0"),
("libc", "v0.2.93"),
("rand_chacha", "v0.3.0"),
("ppv-lite86", "v0.2.10"),
("rand_core", "v0.6.2"),
("getrandom", "v0.2.2"),
("rand_core", "v0.6.2"),
("tokio", "v1.5.0"),
("bytes", "v1.0.1"),
("pin-project-lite", "v0.2.6"),
("slab", "v0.4.3"),
("indicatif", "v0.15.0"),
];
fn main() {
// number of cpus
const NUM_CPUS: usize = 4;
let start = Instant::now();
// mimic cargo progress bar although it behaves a bit different
let pb = ProgressBar::new(CRATES.len() as u64);
pb.set_style(
ProgressStyle::with_template(
// note that bar size is fixed unlike cargo which is dynamic
// and also the truncation in cargo uses trailers (`...`)
if Term::stdout().size().1 > 80 {
"{prefix:>12.cyan.bold} [{bar:57}] {pos}/{len} {wide_msg}"
} else {
"{prefix:>12.cyan.bold} [{bar:57}] {pos}/{len}"
},
)
.unwrap()
.progress_chars("=> "),
);
pb.set_prefix("Building");
// process in another thread
// crates to be iterated but not exactly a tree
let crates = Arc::new(Mutex::new(CRATES.iter()));
let (tx, rx) = mpsc::channel();
for n in 0..NUM_CPUS {
let tx = tx.clone();
let crates = crates.clone();
thread::spawn(move || {
let mut rng = rand::thread_rng();
loop {
let krate = crates.lock().unwrap().next();
// notify main thread if n thread is processing a crate
tx.send((n, krate)).unwrap();
if let Some(krate) = krate {
thread::sleep(Duration::from_millis(
// last compile and linking is always slow, let's mimic that
if CRATES.last() == Some(krate) {
rng.gen_range(1_000..2_000)
} else {
rng.gen_range(250..1_000)
},
));
} else {
break;
}
}
});
}
// drop tx to stop waiting
drop(tx);
let green_bold = Style::new().green().bold();
// do progress drawing in main thread
let mut processing = vec![None; NUM_CPUS];
while let Ok((n, krate)) = rx.recv() {
processing[n] = krate;
let crates: Vec<&str> = processing
.iter()
.filter_map(|t| t.copied().map(|(name, _)| name))
.collect();
pb.set_message(crates.join(", "));
if let Some((name, version)) = krate {
// crate is being built
let line = format!(
"{:>12} {} {}",
green_bold.apply_to("Compiling"),
name,
version
);
pb.println(line);
pb.inc(1);
}
}
pb.finish_and_clear();
// compilation is finished
println!(
"{:>12} dev [unoptimized + debuginfo] target(s) in {}",
green_bold.apply_to("Finished"),
HumanDuration(start.elapsed())
);
}