Skip to content

Commit

Permalink
Show summary line during build (#6)
Browse files Browse the repository at this point in the history
* Add summary line during build

* Add indicator to summary line if JS is still evaluating

* Tweak build summary line on final SuperConsole draw

* Print final build summary even when not using SuperConsole
  • Loading branch information
kylewlacy authored Jan 25, 2024
1 parent 681f14d commit 0755248
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 7 deletions.
13 changes: 13 additions & 0 deletions crates/brioche/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{path::PathBuf, process::ExitCode};
use anyhow::Context as _;
use brioche::{fs_utils, sandbox::SandboxExecutionConfig};
use clap::Parser;
use human_repr::HumanDuration;
use tracing::Instrument;

#[derive(Debug, Parser)]
Expand Down Expand Up @@ -98,6 +99,7 @@ struct BuildArgs {

async fn build(args: BuildArgs) -> anyhow::Result<ExitCode> {
let (reporter, mut guard) = brioche::reporter::start_console_reporter()?;
reporter.set_is_evaluating(true);

let brioche = brioche::brioche::BriocheBuilder::new(reporter.clone())
.keep_temps(args.keep)
Expand Down Expand Up @@ -131,10 +133,21 @@ async fn build(args: BuildArgs) -> anyhow::Result<ExitCode> {

let artifact =
brioche::brioche::script::evaluate::evaluate(&brioche, &project, &args.export).await?;

reporter.set_is_evaluating(false);
let result = brioche::brioche::resolve::resolve(&brioche, artifact).await?;

guard.shutdown_console().await;

let elapsed = reporter.elapsed().human_duration();
let num_jobs = reporter.num_jobs();
let jobs_message = match num_jobs {
0 => "(no new jobs)".to_string(),
1 => "1 job".to_string(),
n => format!("{n} jobs"),
};
println!("Build finished, completed {jobs_message} in {elapsed}");

let result_hash = result.value.hash();
println!("Result: {result_hash}");

Expand Down
71 changes: 64 additions & 7 deletions crates/brioche/src/reporter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::{
collections::HashMap,
sync::{atomic::AtomicUsize, Arc, RwLock},
sync::{
atomic::{AtomicBool, AtomicUsize},
Arc, RwLock,
},
};

use bstr::ByteSlice;
Expand All @@ -19,8 +22,13 @@ pub fn start_console_reporter() -> anyhow::Result<(Reporter, ReporterGuard)> {

let brioche_jaeger_endpoint = std::env::var("BRIOCHE_JAEGER_ENDPOINT").ok();

let start = std::time::Instant::now();
let is_evaluating = Arc::new(AtomicBool::new(false));

let reporter = Reporter {
next_id: Arc::new(AtomicUsize::new(0)),
start,
num_jobs: Arc::new(AtomicUsize::new(0)),
is_evaluating: is_evaluating.clone(),
tx: tx.clone(),
};
let guard = ReporterGuard {
Expand All @@ -37,6 +45,8 @@ pub fn start_console_reporter() -> anyhow::Result<(Reporter, ReporterGuard)> {
let mut console = match superconsole {
Some(console) => {
let root = JobsComponent {
start,
is_evaluating,
jobs,
terminal: tokio::sync::RwLock::new(termwiz::surface::Surface::new(80, 24)),
};
Expand Down Expand Up @@ -335,7 +345,9 @@ pub fn start_lsp_reporter(client: tower_lsp::Client) -> (Reporter, ReporterGuard
let (tx, _) = tokio::sync::mpsc::unbounded_channel();

let reporter = Reporter {
next_id: Arc::new(AtomicUsize::new(0)),
start: std::time::Instant::now(),
num_jobs: Arc::new(AtomicUsize::new(0)),
is_evaluating: Arc::new(AtomicBool::new(false)),
tx: tx.clone(),
};
let guard = ReporterGuard {
Expand Down Expand Up @@ -400,7 +412,9 @@ pub fn start_test_reporter() -> (Reporter, ReporterGuard) {
};

let reporter = Reporter {
next_id: Arc::new(AtomicUsize::new(0)),
start: std::time::Instant::now(),
num_jobs: Arc::new(AtomicUsize::new(0)),
is_evaluating: Arc::new(AtomicBool::new(false)),
tx: tx.clone(),
};
let guard = ReporterGuard {
Expand Down Expand Up @@ -685,18 +699,25 @@ pub struct JobId(usize);

#[derive(Debug, Clone)]
pub struct Reporter {
start: std::time::Instant,
num_jobs: Arc<AtomicUsize>,
is_evaluating: Arc<AtomicBool>,
tx: tokio::sync::mpsc::UnboundedSender<ReportEvent>,
next_id: Arc<AtomicUsize>,
}

impl Reporter {
pub fn emit(&self, lines: superconsole::Lines) {
let _ = self.tx.send(ReportEvent::Emit { lines });
}

pub fn set_is_evaluating(&self, is_evaluating: bool) {
self.is_evaluating
.store(is_evaluating, std::sync::atomic::Ordering::SeqCst);
}

pub fn add_job(&self, job: NewJob) -> JobId {
let id = self
.next_id
.num_jobs
.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let id = JobId(id);

Expand All @@ -708,6 +729,14 @@ impl Reporter {
pub fn update_job(&self, id: JobId, update: UpdateJob) {
let _ = self.tx.send(ReportEvent::UpdateJobState { id, update });
}

pub fn elapsed(&self) -> std::time::Duration {
self.start.elapsed()
}

pub fn num_jobs(&self) -> usize {
self.num_jobs.load(std::sync::atomic::Ordering::SeqCst)
}
}

impl tracing_subscriber::fmt::MakeWriter<'_> for Reporter {
Expand Down Expand Up @@ -739,6 +768,8 @@ impl std::io::Write for ReporterWriter {
}

struct JobsComponent {
start: std::time::Instant,
is_evaluating: Arc<AtomicBool>,
jobs: Arc<tokio::sync::RwLock<HashMap<JobId, Job>>>,
terminal: tokio::sync::RwLock<termwiz::surface::Surface>,
}
Expand All @@ -756,6 +787,11 @@ impl superconsole::Component for JobsComponent {
jobs.sort_by(cmp_job_entries);
let job_partition_point = jobs.partition_point(|&(_, job)| !job.is_complete());
let (incomplete_jobs, complete_jobs) = jobs.split_at(job_partition_point);

let num_jobs = jobs.len();
let num_complete_jobs = complete_jobs.len();
let is_evaluating = self.is_evaluating.load(std::sync::atomic::Ordering::SeqCst);

let jobs = incomplete_jobs
.iter()
.chain(complete_jobs.iter().take(3))
Expand All @@ -776,7 +812,7 @@ impl superconsole::Component for JobsComponent {
let num_terminal_lines = dimensions
.height
.saturating_sub(jobs_lines.len())
.saturating_sub(2);
.saturating_sub(3);
let mut terminal = self.terminal.blocking_write();

terminal.resize(dimensions.width, std::cmp::max(num_terminal_lines, 1));
Expand All @@ -788,8 +824,29 @@ impl superconsole::Component for JobsComponent {
.map(|line| superconsole::Line::sanitized(&line.as_str()))
.take(num_terminal_lines);

let elapsed = self.start.elapsed().human_duration();
let summary_line = match mode {
superconsole::DrawMode::Normal => {
let summary_line = format!(
"[{elapsed}] {num_complete_jobs} / {num_jobs}{or_more} job{s} complete",
s = if num_jobs == 1 { "" } else { "s" },
or_more = if is_evaluating { "+" } else { "" },
);
Some(superconsole::Line::from_iter([summary_line
.try_into()
.unwrap()]))
}
superconsole::DrawMode::Final => {
// Don't show the summary line on the final draw. The final
// summary will be written outside the reporter, since we also
// want to show the summary when not using SuperConsole
None
}
};

let lines = terminal_lines
.chain(jobs_lines.into_iter().flatten())
.chain(summary_line)
.collect();
Ok(lines)
}
Expand Down

0 comments on commit 0755248

Please sign in to comment.