From 00bc0354c993cb3efa291bcd65df6a3d87b2aa64 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 24 Jul 2025 20:12:39 +0700 Subject: [PATCH] Provide better output when downloading versions fails - include stdout/stderr when utf8_output() fails - don't swallow the error returned by handle_Version_install_or_update - skip codesigning when NODMG set Closes #4224 --- qt/launcher/mac/build.sh | 24 +++++++-------- qt/launcher/src/main.rs | 12 +++++--- rslib/process/src/lib.rs | 65 ++++++++++++++++++++++++++++++---------- 3 files changed, 69 insertions(+), 32 deletions(-) diff --git a/qt/launcher/mac/build.sh b/qt/launcher/mac/build.sh index d521e155b..6143451b4 100755 --- a/qt/launcher/mac/build.sh +++ b/qt/launcher/mac/build.sh @@ -38,19 +38,19 @@ cp ../pyproject.toml "$APP_LAUNCHER/Contents/Resources/" cp ../../../.python-version "$APP_LAUNCHER/Contents/Resources/" cp ../versions.py "$APP_LAUNCHER/Contents/Resources/" -# Codesign -for i in "$APP_LAUNCHER/Contents/MacOS/uv" "$APP_LAUNCHER/Contents/MacOS/launcher" "$APP_LAUNCHER"; do - codesign --force -vvvv -o runtime -s "Developer ID Application:" \ - --entitlements entitlements.python.xml \ - "$i" -done - -# Check -codesign -vvv "$APP_LAUNCHER" -spctl -a "$APP_LAUNCHER" - -# Notarize and bundle (skip if NODMG is set) +# Codesign/bundle if [ -z "$NODMG" ]; then + for i in "$APP_LAUNCHER/Contents/MacOS/uv" "$APP_LAUNCHER/Contents/MacOS/launcher" "$APP_LAUNCHER"; do + codesign --force -vvvv -o runtime -s "Developer ID Application:" \ + --entitlements entitlements.python.xml \ + "$i" + done + + # Check + codesign -vvv "$APP_LAUNCHER" + spctl -a "$APP_LAUNCHER" + + # Notarize and build dmg ./notarize.sh "$OUTPUT_DIR" ./dmg/build.sh "$OUTPUT_DIR" fi \ No newline at end of file diff --git a/qt/launcher/src/main.rs b/qt/launcher/src/main.rs index 15320e84b..a124b7fe1 100644 --- a/qt/launcher/src/main.rs +++ b/qt/launcher/src/main.rs @@ -378,9 +378,7 @@ fn main_menu_loop(state: &State) -> Result<()> { continue; } choice @ (MainMenuChoice::Latest | MainMenuChoice::Version(_)) => { - if handle_version_install_or_update(state, choice.clone()).is_err() { - continue; - } + handle_version_install_or_update(state, choice.clone())?; break; } } @@ -650,7 +648,13 @@ fn fetch_versions(state: &State) -> Result> { .args(["run", "--no-project"]) .arg(&versions_script); - let output = cmd.utf8_output()?; + let output = match cmd.utf8_output() { + Ok(output) => output, + Err(e) => { + print!("Unable to check for Anki versions. Please check your internet connection.\n\n"); + return Err(e.into()); + } + }; let versions = serde_json::from_str(&output.stdout).context("Failed to parse versions JSON")?; Ok(versions) } diff --git a/rslib/process/src/lib.rs b/rslib/process/src/lib.rs index dcf0703f6..2a82bb9cc 100644 --- a/rslib/process/src/lib.rs +++ b/rslib/process/src/lib.rs @@ -11,6 +11,24 @@ use snafu::ensure; use snafu::ResultExt; use snafu::Snafu; +#[derive(Debug)] +pub struct CodeDisplay(Option); + +impl std::fmt::Display for CodeDisplay { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + Some(code) => write!(f, "{code}"), + None => write!(f, "?"), + } + } +} + +impl From> for CodeDisplay { + fn from(code: Option) -> Self { + CodeDisplay(code) + } +} + #[derive(Debug, Snafu)] pub enum Error { #[snafu(display("Failed to execute: {cmdline}"))] @@ -18,8 +36,15 @@ pub enum Error { cmdline: String, source: std::io::Error, }, - #[snafu(display("Failed with code {code:?}: {cmdline}"))] - ReturnedError { cmdline: String, code: Option }, + #[snafu(display("Failed to run ({code}): {cmdline}"))] + ReturnedError { cmdline: String, code: CodeDisplay }, + #[snafu(display("Failed to run ({code}): {cmdline}: {stdout}{stderr}"))] + ReturnedWithOutputError { + cmdline: String, + code: CodeDisplay, + stdout: String, + stderr: String, + }, #[snafu(display("Couldn't decode stdout/stderr as utf8"))] InvalidUtf8 { cmdline: String, @@ -71,31 +96,36 @@ impl CommandExt for Command { status.success(), ReturnedSnafu { cmdline: get_cmdline(self), - code: status.code(), + code: CodeDisplay::from(status.code()), } ); Ok(self) } fn utf8_output(&mut self) -> Result { + let cmdline = get_cmdline(self); let output = self.output().with_context(|_| DidNotExecuteSnafu { - cmdline: get_cmdline(self), + cmdline: cmdline.clone(), })?; + + let stdout = String::from_utf8(output.stdout).with_context(|_| InvalidUtf8Snafu { + cmdline: cmdline.clone(), + })?; + let stderr = String::from_utf8(output.stderr).with_context(|_| InvalidUtf8Snafu { + cmdline: cmdline.clone(), + })?; + ensure!( output.status.success(), - ReturnedSnafu { - cmdline: get_cmdline(self), - code: output.status.code(), + ReturnedWithOutputSnafu { + cmdline, + code: CodeDisplay::from(output.status.code()), + stdout: stdout.clone(), + stderr: stderr.clone(), } ); - Ok(Utf8Output { - stdout: String::from_utf8(output.stdout).with_context(|_| InvalidUtf8Snafu { - cmdline: get_cmdline(self), - })?, - stderr: String::from_utf8(output.stderr).with_context(|_| InvalidUtf8Snafu { - cmdline: get_cmdline(self), - })?, - }) + + Ok(Utf8Output { stdout, stderr }) } fn ensure_spawn(&mut self) -> Result { @@ -135,7 +165,10 @@ mod test { #[cfg(not(windows))] assert!(matches!( Command::new("false").ensure_success(), - Err(Error::ReturnedError { code: Some(1), .. }) + Err(Error::ReturnedError { + code: CodeDisplay(_), + .. + }) )); } }