Skip to content

Commit 2c247a8

Browse files
committed
Fix watch startup build locking
1 parent e8cdc22 commit 2c247a8

1 file changed

Lines changed: 103 additions & 81 deletions

File tree

rewatch/src/watcher.rs

Lines changed: 103 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,31 @@ fn matches_filter(path_buf: &Path, filter: &Option<regex::Regex>) -> bool {
5858
filter.as_ref().map(|re| !re.is_match(&name)).unwrap_or(true)
5959
}
6060

61+
fn finish_successful_watch_compile(
62+
after_build: Option<String>,
63+
timing_total: Instant,
64+
show_progress: bool,
65+
plain_output: bool,
66+
finished_message: &str,
67+
compilation_kind: Option<&str>,
68+
outcome: build::CompilationOutcome,
69+
) {
70+
if let Some(a) = after_build {
71+
cmd::run(a)
72+
}
73+
let timing_total_elapsed = timing_total.elapsed();
74+
if show_progress {
75+
if plain_output {
76+
println!("{finished_message}")
77+
} else {
78+
println!(
79+
"\n{}\n",
80+
build::format_finished_compilation_message(compilation_kind, outcome, timing_total_elapsed)
81+
);
82+
}
83+
}
84+
}
85+
6186
/// Computes the list of paths to watch based on the build state.
6287
/// Returns tuples of (path, recursive_mode) for each watch target.
6388
fn compute_watch_paths(build_state: &BuildCommandState, root: &Path) -> Vec<(PathBuf, RecursiveMode)> {
@@ -178,13 +203,8 @@ fn carry_forward_compile_warnings(previous: &BuildCommandState, next: &mut Build
178203
}
179204
}
180205

181-
fn should_clear_screen(
182-
clear_screen: bool,
183-
show_progress: bool,
184-
plain_output: bool,
185-
initial_build: bool,
186-
) -> bool {
187-
clear_screen && show_progress && !plain_output && !initial_build
206+
fn should_clear_screen(clear_screen: bool, show_progress: bool, plain_output: bool) -> bool {
207+
clear_screen && show_progress && !plain_output
188208
}
189209

190210
fn clear_terminal_screen() {
@@ -249,8 +269,6 @@ async fn async_watch(
249269
})
250270
.expect("Error setting Ctrl-C handler");
251271

252-
let mut initial_build = true;
253-
254272
loop {
255273
if *ctrlc_pressed_clone.lock().unwrap() {
256274
if show_progress {
@@ -413,7 +431,7 @@ async fn async_watch(
413431

414432
match needs_compile_type {
415433
CompileType::Incremental => {
416-
if should_clear_screen(clear_screen, show_progress, plain_output, initial_build) {
434+
if should_clear_screen(clear_screen, show_progress, plain_output) {
417435
clear_terminal_screen();
418436
print_rebuild_header(CompileType::Incremental);
419437
}
@@ -422,47 +440,36 @@ async fn async_watch(
422440
let result = build::incremental_build(
423441
&mut build_state,
424442
None,
425-
initial_build,
443+
false,
426444
show_progress,
427-
!initial_build,
445+
true,
428446
create_sourcedirs,
429447
plain_output,
430448
);
431449

432450
match result {
433451
Ok(result) => {
434-
if let Some(a) = after_build.clone() {
435-
cmd::run(a)
436-
}
437-
let timing_total_elapsed = timing_total.elapsed();
438-
if show_progress {
439-
let compilation_type = if initial_build { "initial" } else { "incremental" };
440-
if plain_output {
441-
println!("Finished {compilation_type} compilation")
442-
} else {
443-
println!(
444-
"\n{}\n",
445-
build::format_finished_compilation_message(
446-
Some(compilation_type),
447-
result,
448-
timing_total_elapsed,
449-
)
450-
);
451-
}
452-
}
452+
finish_successful_watch_compile(
453+
after_build.clone(),
454+
timing_total,
455+
show_progress,
456+
plain_output,
457+
"Finished incremental compilation",
458+
Some("incremental"),
459+
result,
460+
);
453461
}
454462
Err(_) => {
455-
if should_clear_screen(clear_screen, show_progress, plain_output, initial_build) {
463+
if should_clear_screen(clear_screen, show_progress, plain_output) {
456464
print_build_failed_footer();
457465
}
458466
}
459467
}
460468

461469
needs_compile_type = CompileType::None;
462-
initial_build = false;
463470
}
464471
CompileType::Full => {
465-
if should_clear_screen(clear_screen, show_progress, plain_output, initial_build) {
472+
if should_clear_screen(clear_screen, show_progress, plain_output) {
466473
clear_terminal_screen();
467474
print_rebuild_header(CompileType::Full);
468475
}
@@ -497,7 +504,7 @@ async fn async_watch(
497504
let result = build::incremental_build_without_lock(
498505
&mut build_state,
499506
None,
500-
initial_build,
507+
false,
501508
show_progress,
502509
false,
503510
create_sourcedirs,
@@ -508,34 +515,23 @@ async fn async_watch(
508515
});
509516
match result {
510517
Ok(result) => {
511-
if let Some(a) = after_build.clone() {
512-
cmd::run(a)
513-
}
514-
515-
let timing_total_elapsed = timing_total.elapsed();
516-
if show_progress {
517-
if plain_output {
518-
println!("Finished compilation")
519-
} else {
520-
println!(
521-
"\n{}\n",
522-
build::format_finished_compilation_message(
523-
None,
524-
result,
525-
timing_total_elapsed,
526-
)
527-
);
528-
}
529-
}
518+
finish_successful_watch_compile(
519+
after_build.clone(),
520+
timing_total,
521+
show_progress,
522+
plain_output,
523+
"Finished compilation",
524+
None,
525+
result,
526+
);
530527
}
531528
Err(_) => {
532-
if should_clear_screen(clear_screen, show_progress, plain_output, initial_build) {
529+
if should_clear_screen(clear_screen, show_progress, plain_output) {
533530
print_build_failed_footer();
534531
}
535532
}
536533
}
537534
needs_compile_type = CompileType::None;
538-
initial_build = false;
539535
}
540536
CompileType::None => {
541537
// We want to sleep for a little while so the CPU can schedule other work. That way we end
@@ -569,25 +565,52 @@ pub fn start(
569565

570566
let path = Path::new(folder);
571567

572-
// Do an initial build to discover packages and source folders. Initialization can clean
573-
// previous build artifacts, so it has to be serialized with other build operations.
574-
let build_state: BuildCommandState = build::with_build_lock(path, || {
575-
build::initialize_build(
576-
None,
577-
filter,
578-
show_progress,
579-
path,
580-
plain_output,
581-
warn_error.clone(),
582-
prod,
583-
features.clone(),
584-
)
585-
.with_context(|| "Could not initialize build")
586-
})?;
587-
588-
// Compute and register targeted watches based on source folders
589-
let current_watch_paths = compute_watch_paths(&build_state, path);
590-
register_watches(&mut watcher, &current_watch_paths);
568+
// Initialization can clean previous build artifacts, so it has to be serialized
569+
// with the initial compile too.
570+
let (build_state, current_watch_paths): (BuildCommandState, Vec<(PathBuf, RecursiveMode)>) =
571+
build::with_build_lock(path, || {
572+
let mut build_state = build::initialize_build(
573+
None,
574+
filter,
575+
show_progress,
576+
path,
577+
plain_output,
578+
warn_error.clone(),
579+
prod,
580+
features.clone(),
581+
)
582+
.with_context(|| "Could not initialize build")?;
583+
584+
// Compute and register targeted watches based on source folders.
585+
let current_watch_paths = compute_watch_paths(&build_state, path);
586+
register_watches(&mut watcher, &current_watch_paths);
587+
588+
let timing_total = Instant::now();
589+
if let Ok(result) = build::incremental_build_without_lock(
590+
&mut build_state,
591+
None,
592+
true,
593+
show_progress,
594+
false,
595+
create_sourcedirs,
596+
plain_output,
597+
) {
598+
finish_successful_watch_compile(
599+
after_build.clone(),
600+
timing_total,
601+
show_progress,
602+
plain_output,
603+
"Finished initial compilation",
604+
Some("initial"),
605+
result,
606+
);
607+
}
608+
609+
Ok::<(BuildCommandState, Vec<(PathBuf, RecursiveMode)>), anyhow::Error>((
610+
build_state,
611+
current_watch_paths,
612+
))
613+
})?;
591614

592615
async_watch(AsyncWatchArgs {
593616
watcher: &mut watcher,
@@ -735,12 +758,11 @@ mod tests {
735758
}
736759

737760
#[test]
738-
fn clears_screen_only_for_non_initial_interactive_rebuilds() {
739-
assert!(should_clear_screen(true, true, false, false));
740-
assert!(!should_clear_screen(true, true, false, true));
741-
assert!(!should_clear_screen(true, true, true, false));
742-
assert!(!should_clear_screen(true, false, false, false));
743-
assert!(!should_clear_screen(false, true, false, false));
761+
fn clears_screen_only_for_interactive_rebuilds() {
762+
assert!(should_clear_screen(true, true, false));
763+
assert!(!should_clear_screen(true, true, true));
764+
assert!(!should_clear_screen(true, false, false));
765+
assert!(!should_clear_screen(false, true, false));
744766
}
745767

746768
#[test]

0 commit comments

Comments
 (0)