dennisvang / tufup

Automated updates for stand-alone Python applications.
MIT License
90 stars 1 forks source link

Split download update and apply update #76

Closed wickeat closed 1 year ago

wickeat commented 1 year ago

The current Client.download_and_apply_update() groups the update download (_download_updates()) and update install (_apply_updates()) into one function. Could this function possibly be better broken up into two separate functions, allowing the client side implementation to perform additional logic between these 2 steps ? For example, the use case I have in mind is to allow for a prompt to be shown to the user, allowing them to save or shut down their work before performing the update.

dennisvang commented 1 year ago

For example, the use case I have in mind is to allow for a prompt to be shown to the user, allowing them to save or shut down their work before performing the update.

@wickeat It would be more appropriate to do this right after checking for updates using check_for_updates(), so before calling download_and_apply_update().

For this reason, check_for_updates() returns the version info of the latest available update.

Moreover, Client._apply_updates() includes a confirmation step. So, it is always possible to abort before starting the installation, unless you set skip_confirmation=True.

Also see relevant code in tufup-example.

dennisvang commented 1 year ago

@wickeat I updated tufup-example to make this more explicit.

wickeat commented 1 year ago

Thanks for the reply @dennisvang!

I understand that the current flow allows for the update checking as a precursor to performing the actual update. However, the use case I was interested in implementing does the update checking and update download in a background thread, and then only brings it to the user attention once any update download has finished by bringing the update prompting to the main thread, so that there doesn't have to be unnecessary idle waiting time from the user's POV for the update download.

Furthermore, the confirmation step isn't a customizable one, so it requires a console to be shown, which is not a given in my use case.

So, I'm wondering if there is a reason behind the grouping of the update download and update apply steps, and if this justifies their separation.

dennisvang commented 1 year ago

... However, the use case I was interested in implementing does the update checking and update download in a background thread, and then only brings it to the user attention once any update download has finished by bringing the update prompting to the main thread, ...

@wickeat I see your point.

The reason for the current grouping was simplicity: "if available, then download&install" is just a slightly simpler interface than "if available, then download, then install"

This was sufficient for our own use cases, as we only wanted the user to confirm before the download starts. A minimal implementation of install confirmation on the command line was included for convenience, but I agree this is a bit too simplistic.

Note, however, that there is an install hook which you could use for more advanced cases. The easiest solution would be to wrap the default install_update function, something like this:

from tufup.utils.platform_specific import install_update

def install_update_after_confirmation(**kwargs):
    # your user confirmation code here
    proceed = ...  # get user input
    # call the default install function
    if proceed:
        install_update(**kwargs)

client.download_and_apply_update(
    skip_confirmation=True, install=install_update_after_confirmation, ...
)

The install function is called in _apply_updates(), here.

I haven't tested this specific case, but I suppose it should work.