Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed — calmer message when WinGet doesn't have the new version yet

Right after a release, the WinGet package manifest publishes a little later than
the GitHub release, so `uffs --update`'s winget step would print a scary
`winget upgrade did not complete (0x8a15002b)`. That exit code just means "no
newer version available yet." It is now recognised and narrated as a plain note
("WinGet doesn't have vX.Y.Z yet — the winget copy catches up on the next
`uffs --update`"), and any genuine winget failure still explains the likely
publish-lag cause rather than only showing a raw code.

### Fixed — self-update now sees a dormant WinGet install

`uffs --update` finds a WinGet-managed install even when nothing is running from
Expand Down
60 changes: 53 additions & 7 deletions crates/uffs-cli/src/commands/update/winget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,17 @@ mod windows_impl {
}

match spinner_while("Running winget upgrade", || run_winget_upgrade(root.scope)) {
Ok(()) => println!("\u{2713} winget package updated to {latest}."),
Ok(WingetUpgrade::Updated) => println!("\u{2713} winget package updated to {latest}."),
Ok(WingetUpgrade::NotAvailableYet) => println!(
"note: WinGet doesn't have {latest} yet — a new release's package manifest\n\
\x20 usually publishes shortly after the GitHub release. Your install is\n\
\x20 updated; the winget-managed copy catches up on the next `uffs --update`\n\
\x20 once it's live (or `winget upgrade {WINGET_PACKAGE_ID}` then)."
),
Err(err) => println!(
"\u{26a0} winget upgrade did not complete ({err:#}).\n\
\x20 Re-run `uffs --update`, or `winget upgrade {WINGET_PACKAGE_ID}` directly."
\x20 Often this is just the new manifest not being on WinGet yet — re-run\n\
\x20 `uffs --update` in a bit, or `winget upgrade {WINGET_PACKAGE_ID}` directly."
),
}
Ok(UpgradeOutcome::Ran)
Expand Down Expand Up @@ -616,8 +623,32 @@ mod windows_impl {
Ok(())
}

/// Run `winget upgrade` for the package, scope-aware, silent.
fn run_winget_upgrade(scope: Scope) -> Result<()> {
/// winget's "no applicable upgrade found" exit code. Returned when the
/// installed version already matches the catalog's newest — the common case
/// right after a release, before the new version's manifest has published
/// to `WinGet`. It is a benign "nothing newer yet", not a real failure,
/// so it is narrated as a note. (Value observed from a live `uffs
/// --update` run whose target release was not yet on `WinGet`.)
const WINGET_NO_APPLICABLE_UPGRADE: i32 = 0x8A15_002B_u32.cast_signed();

/// The outcome of a `winget upgrade` worth distinguishing to the user.
enum WingetUpgrade {
/// The winget package was upgraded.
Updated,
/// `WinGet` had no newer version to install (typically the new
/// release's manifest has not published yet).
NotAvailableYet,
}

/// Whether `code` is winget's benign "no applicable upgrade" exit code.
const fn is_no_applicable_upgrade(code: Option<i32>) -> bool {
matches!(code, Some(WINGET_NO_APPLICABLE_UPGRADE))
}

/// Run `winget upgrade` for the package, scope-aware, silent. Distinguishes
/// a real failure from "`WinGet` has nothing newer yet" (the publish-lag
/// case).
fn run_winget_upgrade(scope: Scope) -> Result<WingetUpgrade> {
let mut command = Command::new("winget");
command.args([
"upgrade",
Expand All @@ -641,10 +672,12 @@ mod windows_impl {
.status()
.context("spawning winget upgrade")?;
if status.success() {
Ok(())
} else {
bail!("winget upgrade exited with {status}")
return Ok(WingetUpgrade::Updated);
}
if is_no_applicable_upgrade(status.code()) {
return Ok(WingetUpgrade::NotAvailableYet);
}
bail!("winget upgrade exited with {status}")
}

/// Defer the upgrade past process exit (the running uffs.exe is part of the
Expand Down Expand Up @@ -675,4 +708,17 @@ mod windows_impl {
.context("scheduling the deferred winget upgrade")?;
Ok(())
}

#[cfg(test)]
mod tests {
use super::{WINGET_NO_APPLICABLE_UPGRADE, is_no_applicable_upgrade};

#[test]
fn classifies_the_no_applicable_upgrade_code() {
assert!(is_no_applicable_upgrade(Some(WINGET_NO_APPLICABLE_UPGRADE)));
assert!(!is_no_applicable_upgrade(Some(0_i32)));
assert!(!is_no_applicable_upgrade(Some(1_i32)));
assert!(!is_no_applicable_upgrade(None));
}
}
}
Loading