Comment 0 for bug 2038958

Revision history for this message
Simon Quigley (tsimonq2) wrote :

[ Impact ]

The lubuntu-update-notifier package is a PyQt 5-based application which automatically checks for updates and helps the user install them. It is the main update notifier system in Lubuntu, using update-notifier-common to check for updates and apply them using the aptdaemon library. It was originally written by Hans Möller, a former Lubuntu Member, but maintained by the Lubuntu team.

In bug 2002255, a precedent was set regarding updates to this software. When initially shipped, it was a rather primitive application with rough edges, especially around error handling. We have since polished it, adding necessary information (for example, debconf prompts).

This bug is regarding the default user experience around upgrading to the latest version of Lubuntu. There is currently no graphical way in which the user is prompted for or allowed to proceed with the upgrade. In our notes, we typically ask them to run `sudo do-release-upgrade`, which does do the job at a basic level, but does not integrate it with Lubuntu's existing, light, Qt-based UI.

The upload at hand fixes that. When the user is prompted for updates, they will be asked afterwards about upgrading to the latest release (if available). This evaluation is done via `do-release-upgrade -c`, not by re-implementing any existing logic. If they choose to accept, the existing Qt frontend is launched, via `lxqt-sudo do-release-upgrade -m desktop -f DistUpgradeViewKDE`. When that process completes, the update notifier cleanly exits. I have added a hard dependency on ubuntu-release-upgrader-qt to ensure this process is successful.

[ Technical Details ]

The update notifier is started by `lubuntu-upg-notifier.sh`, which is ran as an autostart application within LXQt (I have tested patches pending for next cycle which moves this to a systemd user timer). This patch starts off by calling `do-release-upgrade -c` and capturing the exit code via `$?`. That exit code is directly fed into lubuntu-notifier.py as an argument.

In the Python file, I added an argument via ArgParse which converts that exit code into a boolean (for more Pythonic use later). That boolean is then passed (through a few functions and class declarations) to `Dialog.initUI()`.

If the dialog is launched without any packages to upgrade but with a release to upgrade to, it will skip right to that function. (Setting the title to "Upgrade Lubuntu" is declared twice, once for a window without any upgrades, and another for the "after-upgrade" step.)

This is where the additional import of QThread (etc.) comes in; while it's not the original bug, when an additional window pops up, the original update notifier window freezes. To fix that, I created a special class which inherits QThread, and used that to call subprocess (I tried to use the Python threading library, but the freeze was still happening).

Both `Dialog.on_upgrade_finished()` and `Dialog.initUI()` call `Dialog.call_release_upgrader()`, which uses `RunUpgradeThread()` as well. You'll notice I created an additional `self.thread2` variable; if I were to re-define `self.thread` within that function, that kills its own parent (in the case of upgrades), which makes the additional thread entirely non-functional.

When that QThread process is done, a clean `app.exit()` is performed (via an existing function).

You might notice `self.buttonBox.clicked.disconnect(self.call_upgrade)` - this is required because otherwise the connect below it simply *adds* to the one performed in `__init__()`, causing two password popups.

Additionally, if Launchpad can be queried, a link to our release announcement is generated.

[ Test Plan ]

 (Jammy only)
 * Run `sudo sed -i "s/lts/normal/" /etc/update-manager/release-upgrades`

 * Log out and log back in (to restart the notifier).
 * Install any updates (if there are any to install).
   - There's two sub-testcases here. The first is a system where updates are being applied, and when prompted, the user goes ahead with the upgrade. The second is a system where all updates are already applied, and on first launch it prompts the user to upgrade.
 * Click the link to ensure it brings you to the correct release notes.
 * Go through the upgrade process, ensuring the window smoothly closes.

[ Where problems could occur ]

 * If `do-release-upgrade` decides to return a non-integer exit code, or the shell changes in an unexpected way where that code is no longer being captured correctly, it will cause an ArgParse exception.
 * If the output of `do-release-upgrade -c` changes drastically, the version will not be detected.
 * All Launchpad error handling is pretty bluntly done; if it can't access it for any reason, the fallback is no link.
 * Existing Qt bugs could very well manifest themselves in this application. By importing an additional Qt library, you're technically increasing the surface area in which errors can occur.
 * This relies on the increasingly-bitrotting ubuntu-release-upgrader-qt, which needs some cleanup work. It's our best shot for now, since re-implementing it should be done for all Qt flavors.