Fix "WSL already reported" panic (#1344)

This commit is contained in:
Andre Toerien
2025-09-28 08:25:10 +02:00
committed by GitHub
parent fec08a5ad1
commit 7c7e7c3ce4
5 changed files with 59 additions and 77 deletions

View File

@@ -38,7 +38,6 @@ mod ctrlc;
mod error; mod error;
mod execution_context; mod execution_context;
mod executor; mod executor;
mod report;
mod runner; mod runner;
#[cfg(windows)] #[cfg(windows)]
mod self_renamer; mod self_renamer;
@@ -200,12 +199,19 @@ fn run() -> Result<()> {
step.run(&mut runner, &ctx)? step.run(&mut runner, &ctx)?
} }
if !runner.report().data().is_empty() { let mut failed = false;
let report = runner.report();
if !report.is_empty() {
print_separator(t!("Summary")); print_separator(t!("Summary"));
for (key, result) in runner.report().data() { for (key, result) in report {
if !failed && result.failed() {
failed = true;
}
print_result(key, result); print_result(key, result);
} }
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
@@ -213,13 +219,12 @@ fn run() -> Result<()> {
distribution.show_summary(); distribution.show_summary();
} }
} }
}
let mut post_command_failed = false;
if let Some(commands) = config.post_commands() { if let Some(commands) = config.post_commands() {
for (name, command) in commands { for (name, command) in commands {
if generic::run_custom_command(name, command, &ctx).is_err() { let result = generic::run_custom_command(name, command, &ctx);
post_command_failed = true; if !failed && result.is_err() {
failed = true;
} }
} }
} }
@@ -244,8 +249,6 @@ fn run() -> Result<()> {
} }
} }
let failed = post_command_failed || runner.report().data().iter().any(|(_, result)| result.failed());
if !config.skip_notify() { if !config.skip_notify() {
notify_desktop( notify_desktop(
if failed { if failed {

View File

@@ -1,45 +0,0 @@
use std::borrow::Cow;
pub enum StepResult {
Success,
Failure,
Ignored,
Skipped(String),
}
impl StepResult {
pub fn failed(&self) -> bool {
match self {
StepResult::Success | StepResult::Ignored | StepResult::Skipped(_) => false,
StepResult::Failure => true,
}
}
}
type CowString<'a> = Cow<'a, str>;
type ReportData<'a> = Vec<(CowString<'a>, StepResult)>;
pub struct Report<'a> {
data: ReportData<'a>,
}
impl<'a> Report<'a> {
pub fn new() -> Self {
Self { data: Vec::new() }
}
pub fn push_result<M>(&mut self, result: Option<(M, StepResult)>)
where
M: Into<CowString<'a>>,
{
if let Some((key, success)) = result {
let key = key.into();
debug_assert!(!self.data.iter().any(|(k, _)| k == &key), "{key} already reported");
self.data.push((key, success));
}
}
pub fn data(&self) -> &ReportData<'a> {
&self.data
}
}

View File

@@ -1,15 +1,34 @@
use crate::ctrlc;
use crate::error::{DryRun, SkipStep};
use crate::execution_context::ExecutionContext;
use crate::report::{Report, StepResult};
use crate::step::Step;
use crate::terminal::print_error;
use crate::terminal::should_retry;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::Debug; use std::fmt::Debug;
use tracing::debug; use tracing::debug;
use crate::ctrlc;
use crate::error::{DryRun, SkipStep};
use crate::execution_context::ExecutionContext;
use crate::step::Step;
use crate::terminal::{print_error, should_retry};
pub enum StepResult {
Success,
Failure,
Ignored,
Skipped(String),
}
impl StepResult {
pub fn failed(&self) -> bool {
use StepResult::*;
match self {
Success | Ignored | Skipped(_) => false,
Failure => true,
}
}
}
type Report<'a> = Vec<(Cow<'a, str>, StepResult)>;
pub struct Runner<'a> { pub struct Runner<'a> {
ctx: &'a ExecutionContext<'a>, ctx: &'a ExecutionContext<'a>,
report: Report<'a>, report: Report<'a>,
@@ -19,20 +38,25 @@ impl<'a> Runner<'a> {
pub fn new(ctx: &'a ExecutionContext) -> Runner<'a> { pub fn new(ctx: &'a ExecutionContext) -> Runner<'a> {
Runner { Runner {
ctx, ctx,
report: Report::new(), report: Vec::new(),
} }
} }
pub fn execute<F, M>(&mut self, step: Step, key: M, func: F) -> Result<()> fn push_result(&mut self, key: Cow<'a, str>, result: StepResult) {
debug_assert!(!self.report.iter().any(|(k, _)| k == &key), "{key} already reported");
self.report.push((key, result));
}
pub fn execute<K, F>(&mut self, step: Step, key: K, func: F) -> Result<()>
where where
K: Into<Cow<'a, str>> + Debug,
F: Fn() -> Result<()>, F: Fn() -> Result<()>,
M: Into<Cow<'a, str>> + Debug,
{ {
if !self.ctx.config().should_run(step) { if !self.ctx.config().should_run(step) {
return Ok(()); return Ok(());
} }
let key = key.into(); let key: Cow<'a, str> = key.into();
debug!("Step {:?}", key); debug!("Step {:?}", key);
// alter the `func` to put it in a span // alter the `func` to put it in a span
@@ -46,13 +70,13 @@ impl<'a> Runner<'a> {
loop { loop {
match func() { match func() {
Ok(()) => { Ok(()) => {
self.report.push_result(Some((key, StepResult::Success))); self.push_result(key, StepResult::Success);
break; break;
} }
Err(e) if e.downcast_ref::<DryRun>().is_some() => break, Err(e) if e.downcast_ref::<DryRun>().is_some() => break,
Err(e) if e.downcast_ref::<SkipStep>().is_some() => { Err(e) if e.downcast_ref::<SkipStep>().is_some() => {
if self.ctx.config().verbose() || self.ctx.config().show_skipped() { if self.ctx.config().verbose() || self.ctx.config().show_skipped() {
self.report.push_result(Some((key, StepResult::Skipped(e.to_string())))); self.push_result(key, StepResult::Skipped(e.to_string()));
} }
break; break;
} }
@@ -73,14 +97,14 @@ impl<'a> Runner<'a> {
}; };
if !should_retry { if !should_retry {
self.report.push_result(Some(( self.push_result(
key, key,
if ignore_failure { if ignore_failure {
StepResult::Ignored StepResult::Ignored
} else { } else {
StepResult::Failure StepResult::Failure
}, },
))); );
break; break;
} }
} }

View File

@@ -664,7 +664,7 @@ impl Step {
WslUpdate => WslUpdate =>
{ {
#[cfg(windows)] #[cfg(windows)]
runner.execute(*self, "WSL", || windows::update_wsl(ctx))? runner.execute(*self, "Update WSL", || windows::update_wsl(ctx))?
} }
Xcodes => Xcodes =>
{ {

View File

@@ -16,7 +16,7 @@ use tracing::{debug, error};
use which_crate::which; use which_crate::which;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::report::StepResult; use crate::runner::StepResult;
static TERMINAL: LazyLock<Mutex<Terminal>> = LazyLock::new(|| Mutex::new(Terminal::new())); static TERMINAL: LazyLock<Mutex<Terminal>> = LazyLock::new(|| Mutex::new(Terminal::new()));