sparkle-project / Sparkle

A software update framework for macOS
https://sparkle-project.org
Other
7.34k stars 1.04k forks source link

Delete locally stored update and download more recent version #2469

Open kaylagalway opened 9 months ago

kaylagalway commented 9 months ago

Summary

If Sparkle has already downloaded an update, but my macOS application has not yet installed/completed the update, I would like to be able to check for newer updates and override the older downloaded update.

I can not find any function/stored property that would handle this functionality as of right now. It seems like I would need to manually delete the stored downloaded update and manually reset things, which feels unsafe.

Am I missing the straight forward way to handle this?

Possible Fix

Adjust the logic in checkForUpdates so that we can check the sparkle feed for a new update, and if an old one is already downloaded, we discard it and prioritize the newer update.

Version

All

zorgiepoo commented 9 months ago

This was last discussed in #2092. It isn't possible. I don't think I'd be happy with how this would work with deltas in Sparkle's architecture (and I'm unsure about reentrancy for the helpers too). Today you can only nudge the user about the currently downloaded update or try to force updating the app. Sparkle by default nudges the user after a week has passed.

Also if the user manually checks for updates (i.e checkForUpdates), it's much faster to install if Sparkle has already downloaded/staged that update for installation, than it is to download/extract/install a newer one.

kaylagalway commented 9 months ago

My main use case is this:

If we have released a broken build that crashes on launch and a user has already downloaded that build, but not restarted to install it - they should be able to manually checkForUpdates and install a newer safe build that we released to remedy the issue. Or we should be able to force an update check to trigger without them knowing and download the new safe build. Otherwise a user will have no choice but to update to the known broken build or uninstall/reinstall.

Is there any way this could be reconsidered?

zorgiepoo commented 9 months ago

Personally, the most important issue in that scenario is shipping a build that broken and most of the effort should go into improving qualification process to minimize that from happening in the future. Even with this change, you can still end up with a lot of users installing your broken build. Not all users can silently install updates or users that can could quit the app / reboot the system before such a hot-fix is delivered. New users could download your app online.

If we want to make this change, the rationale needs to be that it's better to opportunistically install a more newer update, not assume that an old update may be bad.

The way I think this potential change might work:

I did not want to work on this and didn't think the extra complexity / re-architecture / bug-risk cost outweighed the benefit. This is why I closed https://github.com/sparkle-project/Sparkle/issues/2092. It is also not presently a highly requested feature (it's a rarely requested one even); many developers do not ship updates that frequently in a short interval. I can leave this issue open for a bit if anyone wants to explore this further and is interested though.

If it helps any, Sparkle also provides phased group rollouts. Users today can also manually skip an update that has been downloaded if they happen to know it's bad (e.g, if it's indicated in the release notes or something and they read it); that will delete the downloaded update.

kaylagalway commented 8 months ago

Thank you for such a thorough response!

You are right that the bigger opportunity here is definitely the case where a user cannot easily download the most recent update if they already have one installed. This leaves users in a situation where they may not realize it, but they already have an update downloaded, so they are not updating to the most recent version when they checkForUpdates and they still have to restart twice to update to the most recent update.

From your description, it seems the technical lift on this improvement is quite significant. One question I had after reading is: if a user can currently opt to manually skip an update, could that same machinery be used when they click the button to checkForUpdates?

i.e. could checkForUpdates use the same logic that skipping an update does to delete the downloaded update and download a new one? When a user skips an update, they can still check for new updates afterwards right?

zorgiepoo commented 8 months ago

Note the more common case is not the user checking for updates, but the update being installed in the background by the automatic update driver.

A problem is you need to know when to skip an update. You only want to skip an update if a newer update is available. Sparkle doesn't presently hit the server again when an update is already downloaded, even if the user checks for updates within the app.

As far as I can this doesn't change my first 4 points, may change how point 5 is implemented (i.e, when to cancel the existing update), and we may disagree about point 6.