Skip to content

Commit a17c53c

Browse files
authored
fix: reduce progress bar flickering (#30349)
Also goes back to showing a single line instead of 3 lines.
1 parent e282367 commit a17c53c

File tree

10 files changed

+116
-51
lines changed

10 files changed

+116
-51
lines changed

cli/factory.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,7 @@ impl CliFactory {
736736
self.npm_installer_if_managed().await?.cloned(),
737737
self.npm_resolver().await?.clone(),
738738
self.resolver_factory()?.parsed_source_cache().clone(),
739+
self.text_only_progress_bar().clone(),
739740
self.resolver().await?.clone(),
740741
self.root_permissions_container()?.clone(),
741742
self.sys(),

cli/graph_util.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ use crate::type_checker::CheckOptions;
6767
use crate::type_checker::TypeChecker;
6868
use crate::util::file_watcher::WatcherCommunicator;
6969
use crate::util::fs::canonicalize_path;
70+
use crate::util::progress_bar::ProgressBar;
7071

7172
#[derive(Clone)]
7273
pub struct GraphValidOptions<'a> {
@@ -609,6 +610,7 @@ pub struct ModuleGraphBuilder {
609610
npm_installer: Option<Arc<CliNpmInstaller>>,
610611
npm_resolver: CliNpmResolver,
611612
parsed_source_cache: Arc<ParsedSourceCache>,
613+
progress_bar: ProgressBar,
612614
resolver: Arc<CliResolver>,
613615
root_permissions_container: PermissionsContainer,
614616
sys: CliSys,
@@ -631,6 +633,7 @@ impl ModuleGraphBuilder {
631633
npm_installer: Option<Arc<CliNpmInstaller>>,
632634
npm_resolver: CliNpmResolver,
633635
parsed_source_cache: Arc<ParsedSourceCache>,
636+
progress_bar: ProgressBar,
634637
resolver: Arc<CliResolver>,
635638
root_permissions_container: PermissionsContainer,
636639
sys: CliSys,
@@ -650,6 +653,7 @@ impl ModuleGraphBuilder {
650653
npm_installer,
651654
npm_resolver,
652655
parsed_source_cache,
656+
progress_bar,
653657
resolver,
654658
root_permissions_container,
655659
sys,
@@ -676,6 +680,7 @@ impl ModuleGraphBuilder {
676680
}
677681
}
678682

683+
let _clear_guard = self.progress_bar.deferred_keep_initialize_alive();
679684
let analyzer = self.module_info_cache.as_module_analyzer();
680685
let mut loader = match options.loader {
681686
Some(loader) => MutLoaderRef::Borrowed(loader),

cli/module_loader.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl ModuleLoadPreparer {
183183
allow_unknown_media_types,
184184
skip_graph_roots_validation,
185185
} = options;
186-
let _pb_clear_guard = self.progress_bar.clear_guard();
186+
let _pb_clear_guard = self.progress_bar.deferred_keep_initialize_alive();
187187

188188
let mut loader = self
189189
.module_graph_builder
@@ -273,7 +273,7 @@ impl ModuleLoadPreparer {
273273
.collect::<Vec<_>>()
274274
.join(", ")
275275
);
276-
let _pb_clear_guard = self.progress_bar.clear_guard();
276+
let _pb_clear_guard = self.progress_bar.deferred_keep_initialize_alive();
277277

278278
let mut loader = self
279279
.module_graph_builder

cli/tools/pm/cache_deps.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ pub async fn cache_top_level_deps(
2525
factory: &CliFactory,
2626
jsr_resolver: Option<Arc<crate::jsr::JsrFetchResolver>>,
2727
) -> Result<(), AnyError> {
28+
let _clear_guard = factory
29+
.text_only_progress_bar()
30+
.deferred_keep_initialize_alive();
2831
let npm_installer = factory.npm_installer().await?;
2932
npm_installer
3033
.ensure_top_level_package_json_install()

cli/tools/pm/deps.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use crate::module_loader::ModuleLoadPreparer;
4545
use crate::npm::CliNpmInstaller;
4646
use crate::npm::CliNpmResolver;
4747
use crate::npm::NpmFetchResolver;
48+
use crate::util::progress_bar::ProgressBar;
4849
use crate::util::sync::AtomicFlag;
4950

5051
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -464,6 +465,7 @@ pub struct DepManager {
464465
npm_resolver: CliNpmResolver,
465466
npm_installer: Arc<CliNpmInstaller>,
466467
permissions_container: PermissionsContainer,
468+
progress_bar: ProgressBar,
467469
main_module_graph_container: Arc<MainModuleGraphContainer>,
468470
lockfile: Option<Arc<CliLockfile>>,
469471
}
@@ -475,6 +477,7 @@ pub struct DepManagerArgs {
475477
pub npm_installer: Arc<CliNpmInstaller>,
476478
pub npm_resolver: CliNpmResolver,
477479
pub permissions_container: PermissionsContainer,
480+
pub progress_bar: ProgressBar,
478481
pub main_module_graph_container: Arc<MainModuleGraphContainer>,
479482
pub lockfile: Option<Arc<CliLockfile>>,
480483
}
@@ -485,13 +488,15 @@ impl DepManager {
485488
new.latest_versions = self.latest_versions;
486489
new
487490
}
491+
488492
fn with_deps_args(deps: Vec<Dep>, args: DepManagerArgs) -> Self {
489493
let DepManagerArgs {
490494
module_load_preparer,
491495
jsr_fetch_resolver,
492496
npm_fetch_resolver,
493497
npm_installer,
494498
npm_resolver,
499+
progress_bar,
495500
permissions_container,
496501
main_module_graph_container,
497502
lockfile,
@@ -506,6 +511,7 @@ impl DepManager {
506511
npm_fetch_resolver,
507512
npm_installer,
508513
npm_resolver,
514+
progress_bar,
509515
permissions_container,
510516
main_module_graph_container,
511517
lockfile,
@@ -546,6 +552,7 @@ impl DepManager {
546552
if self.dependencies_resolved.is_raised() {
547553
return Ok(());
548554
}
555+
let _clear_guard = self.progress_bar.deferred_keep_initialize_alive();
549556

550557
let mut graph_permit = self
551558
.main_module_graph_container

cli/tools/pm/outdated/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ async fn dep_manager_args(
514514
npm_fetch_resolver,
515515
npm_resolver: factory.npm_resolver().await?.clone(),
516516
npm_installer: factory.npm_installer().await?.clone(),
517+
progress_bar: factory.text_only_progress_bar().clone(),
517518
permissions_container: factory.root_permissions_container()?.clone(),
518519
main_module_graph_container: factory
519520
.main_module_graph_container()

cli/tools/run/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ pub async fn maybe_npm_install(factory: &CliFactory) -> Result<(), AnyError> {
258258
if cli_options.specified_node_modules_dir()? == Some(NodeModulesDirMode::Auto)
259259
{
260260
if let Some(npm_installer) = factory.npm_installer_if_managed().await? {
261+
let _clear_guard = factory
262+
.text_only_progress_bar()
263+
.deferred_keep_initialize_alive();
261264
let already_done = npm_installer
262265
.ensure_top_level_package_json_install()
263266
.await?;

cli/tools/task.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ use crate::npm::CliNpmResolver;
4646
use crate::task_runner;
4747
use crate::task_runner::run_future_forwarding_signals;
4848
use crate::util::fs::canonicalize_path;
49+
use crate::util::progress_bar::ProgressBar;
4950

5051
#[derive(Debug)]
5152
struct PackageTaskInfo {
@@ -178,6 +179,7 @@ pub async fn execute_script(
178179
let npm_installer = factory.npm_installer_if_managed().await?;
179180
let npm_resolver = factory.npm_resolver().await?;
180181
let node_resolver = factory.node_resolver().await?;
182+
let progress_bar = factory.text_only_progress_bar();
181183
let mut env_vars = task_runner::real_env_vars();
182184

183185
if let Some(connected) = &flags.connected {
@@ -196,6 +198,7 @@ pub async fn execute_script(
196198
npm_installer: npm_installer.map(|n| n.as_ref()),
197199
npm_resolver,
198200
node_resolver: node_resolver.as_ref(),
201+
progress_bar,
199202
env_vars,
200203
cli_options,
201204
maybe_lockfile,
@@ -250,6 +253,7 @@ struct TaskRunner<'a> {
250253
npm_installer: Option<&'a CliNpmInstaller>,
251254
npm_resolver: &'a CliNpmResolver,
252255
node_resolver: &'a CliNodeResolver,
256+
progress_bar: &'a ProgressBar,
253257
env_vars: HashMap<OsString, OsString>,
254258
cli_options: &'a CliOptions,
255259
maybe_lockfile: Option<Arc<CliLockfile>>,
@@ -567,6 +571,7 @@ impl<'a> TaskRunner<'a> {
567571

568572
async fn maybe_npm_install(&self) -> Result<(), AnyError> {
569573
if let Some(npm_installer) = self.npm_installer {
574+
self.progress_bar.deferred_keep_initialize_alive();
570575
npm_installer
571576
.ensure_top_level_package_json_install()
572577
.await?;

cli/util/progress_bar/mod.rs

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub enum ProgressBarStyle {
7474
/// Shows a progress bar with human readable download size
7575
DownloadBars,
7676

77-
/// Shows a progress bar with numeric progres count
77+
/// Shows a progress bar with numeric progress count
7878
ProgressBars,
7979

8080
/// Shows a list of currently downloaded files.
@@ -134,6 +134,7 @@ struct InternalState {
134134
keep_alive_count: usize,
135135
total_entries: usize,
136136
entries: Vec<Arc<ProgressBarEntry>>,
137+
is_deferring_display: bool,
137138
}
138139

139140
#[derive(Clone, Debug)]
@@ -151,17 +152,42 @@ impl ProgressBarInner {
151152
keep_alive_count: 0,
152153
total_entries: 0,
153154
entries: Vec::new(),
155+
is_deferring_display: false,
154156
})),
155157
renderer,
156158
}
157159
}
158160

161+
/// A deferred entry will only be shown once another entry
162+
/// is added to the progress bar.
163+
pub fn add_deferred_entry(
164+
&self,
165+
kind: ProgressMessagePrompt,
166+
message: String,
167+
) -> Arc<ProgressBarEntry> {
168+
let mut internal_state = self.state.lock();
169+
if internal_state.entries.is_empty() {
170+
internal_state.is_deferring_display = true;
171+
}
172+
self.add_entry_internal(&mut internal_state, kind, message)
173+
}
174+
159175
pub fn add_entry(
160176
&self,
161177
kind: ProgressMessagePrompt,
162178
message: String,
163179
) -> Arc<ProgressBarEntry> {
164180
let mut internal_state = self.state.lock();
181+
internal_state.is_deferring_display = false;
182+
self.add_entry_internal(&mut internal_state, kind, message)
183+
}
184+
185+
fn add_entry_internal(
186+
&self,
187+
internal_state: &mut InternalState,
188+
kind: ProgressMessagePrompt,
189+
message: String,
190+
) -> Arc<ProgressBarEntry> {
165191
let id = internal_state.total_entries;
166192
let entry = Arc::new(ProgressBarEntry {
167193
id,
@@ -175,7 +201,7 @@ impl ProgressBarInner {
175201
internal_state.total_entries += 1;
176202
internal_state.keep_alive_count += 1;
177203

178-
self.maybe_start_draw_thread(&mut internal_state);
204+
self.maybe_start_draw_thread(internal_state);
179205

180206
entry
181207
}
@@ -188,20 +214,13 @@ impl ProgressBarInner {
188214
.binary_search_by(|e| e.id.cmp(&entry_id))
189215
{
190216
internal_state.entries.remove(index);
217+
if internal_state.entries.is_empty() {
218+
internal_state.is_deferring_display = false;
219+
}
191220
self.decrement_keep_alive(&mut internal_state);
192221
}
193222
}
194223

195-
pub fn increment_clear(&self) {
196-
let mut internal_state = self.state.lock();
197-
internal_state.keep_alive_count += 1;
198-
}
199-
200-
pub fn decrement_clear(&self) {
201-
let mut internal_state = self.state.lock();
202-
self.decrement_keep_alive(&mut internal_state);
203-
}
204-
205224
fn decrement_keep_alive(&self, state: &mut InternalState) {
206225
state.keep_alive_count -= 1;
207226

@@ -226,7 +245,7 @@ impl DrawThreadRenderer for ProgressBarInner {
226245
fn render(&self, size: &ConsoleSize) -> String {
227246
let data = {
228247
let state = self.state.lock();
229-
if state.entries.is_empty() {
248+
if state.entries.is_empty() || state.is_deferring_display {
230249
return String::new();
231250
}
232251
let display_entries = state
@@ -268,7 +287,7 @@ pub struct ProgressBar {
268287

269288
impl deno_npm_installer::Reporter for ProgressBar {
270289
type Guard = UpdateGuard;
271-
type ClearGuard = ClearGuard;
290+
type ClearGuard = UpdateGuard;
272291

273292
fn on_blocking(&self, message: &str) -> Self::Guard {
274293
self.update_with_prompt(ProgressMessagePrompt::Blocking, message)
@@ -279,7 +298,7 @@ impl deno_npm_installer::Reporter for ProgressBar {
279298
}
280299

281300
fn clear_guard(&self) -> Self::ClearGuard {
282-
self.clear_guard()
301+
self.deferred_keep_initialize_alive()
283302
}
284303
}
285304

@@ -334,22 +353,27 @@ impl ProgressBar {
334353
}
335354
}
336355

337-
pub fn clear_guard(&self) -> ClearGuard {
338-
self.inner.increment_clear();
339-
ClearGuard { pb: self.clone() }
340-
}
341-
342-
fn decrement_clear(&self) {
343-
self.inner.decrement_clear();
356+
pub fn deferred_keep_initialize_alive(&self) -> UpdateGuard {
357+
self.deferred_update_with_prompt(ProgressMessagePrompt::Initialize, "")
344358
}
345-
}
346-
347-
pub struct ClearGuard {
348-
pb: ProgressBar,
349-
}
350359

351-
impl Drop for ClearGuard {
352-
fn drop(&mut self) {
353-
self.pb.decrement_clear();
360+
/// Add an entry to the progress bar that will only be shown
361+
/// once another entry has been added.
362+
pub fn deferred_update_with_prompt(
363+
&self,
364+
kind: ProgressMessagePrompt,
365+
msg: &str,
366+
) -> UpdateGuard {
367+
// only check if progress bars are supported once we go
368+
// to update so that we lazily initialize the progress bar
369+
if ProgressBar::are_supported() {
370+
let entry = self.inner.add_deferred_entry(kind, msg.to_string());
371+
UpdateGuard {
372+
maybe_entry: Some(entry),
373+
}
374+
} else {
375+
// do not display anything for a deferred update
376+
UpdateGuard { maybe_entry: None }
377+
}
354378
}
355379
}

0 commit comments

Comments
 (0)