diff --git a/po/arch-update.pot b/po/arch-update.pot index 5535b21..491663b 100644 --- a/po/arch-update.pot +++ b/po/arch-update.pot @@ -16,12 +16,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/lib/check.sh:34 src/lib/check.sh:37 +#: src/lib/check.sh:38 src/lib/check.sh:41 #, sh-format msgid "${update_number} update available" msgstr "" -#: src/lib/check.sh:42 src/lib/check.sh:44 +#: src/lib/check.sh:46 src/lib/check.sh:48 #, sh-format msgid "${update_number} updates available" msgstr "" @@ -588,15 +588,39 @@ msgstr "" msgid "No service requiring a post upgrade restart found\\n" msgstr "" -#: src/lib/tray.py:127 +#: src/lib/tray.py:124 +msgid "Arch-Update: 'updates' state file isn't found" +msgstr "" + +#: src/lib/tray.py:141 +msgid "Arch-Update: System is up to date" +msgstr "" + +#: src/lib/tray.py:144 +#, python-brace-format +msgid "" +"Arch-Update: 1 update available\n" +"\n" +"{update_list}" +msgstr "" + +#: src/lib/tray.py:149 +#, python-brace-format +msgid "" +"Arch-Update: {updates} updates available\n" +"\n" +"{update_list}" +msgstr "" + +#: src/lib/tray.py:186 msgid "Run Arch-Update" msgstr "" -#: src/lib/tray.py:128 +#: src/lib/tray.py:187 msgid "Check for updates" msgstr "" -#: src/lib/tray.py:129 +#: src/lib/tray.py:188 msgid "Exit" msgstr "" diff --git a/po/fr.po b/po/fr.po index dde3e4b..9ff0356 100644 --- a/po/fr.po +++ b/po/fr.po @@ -16,12 +16,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/lib/check.sh:34 src/lib/check.sh:37 +#: src/lib/check.sh:38 src/lib/check.sh:41 #, sh-format msgid "${update_number} update available" msgstr "${update_number} mise à jour disponible" -#: src/lib/check.sh:42 src/lib/check.sh:44 +#: src/lib/check.sh:46 src/lib/check.sh:48 #, sh-format msgid "${update_number} updates available" msgstr "${update_number} mises à jour disponibles" @@ -658,15 +658,45 @@ msgstr "" msgid "No service requiring a post upgrade restart found\\n" msgstr "Aucun service nécessitant un redémarrage suite à la mise à jour n'a été trouvé\\n" -#: src/lib/tray.py:127 +#: src/lib/tray.py:124 +msgid "Arch-Update: 'updates' state file isn't found" +msgstr "Arch-Update : fichier d'état 'updates' non trouvé" + +#: src/lib/tray.py:141 +msgid "Arch-Update: System is up to date" +msgstr "Arch-Update : Le système à jour" + +#: src/lib/tray.py:144 +#, python-brace-format +msgid "" +"Arch-Update: 1 update available\n" +"\n" +"{update_list}" +msgstr "" +"Arch-Update : 1 mise à jour disponible\n" +"\n" +"{update_list}" + +#: src/lib/tray.py:149 +#, python-brace-format +msgid "" +"Arch-Update: {updates} updates available\n" +"\n" +"{update_list}" +msgstr "" +"Arch-Update : {updates} mises à jour disponibles\n" +"\n" +"{update_list}" + +#: src/lib/tray.py:186 msgid "Run Arch-Update" msgstr "Lancer Arch-Update" -#: src/lib/tray.py:128 +#: src/lib/tray.py:187 msgid "Check for updates" msgstr "Vérifier les mises à jour" -#: src/lib/tray.py:129 +#: src/lib/tray.py:188 msgid "Exit" msgstr "Quitter" diff --git a/src/lib/check.sh b/src/lib/check.sh index 5800dea..96dc10e 100755 --- a/src/lib/check.sh +++ b/src/lib/check.sh @@ -14,6 +14,10 @@ else update_available=$(checkupdates) fi +if [ -n "${no_version}" ]; then + update_available=$(echo "${update_available}" | awk '{print $1}') +fi + if [ -n "${notif}" ]; then # shellcheck disable=SC2154 echo "${update_available}" > "${statedir}/current_updates_check" diff --git a/src/lib/full_upgrade.sh b/src/lib/full_upgrade.sh index 666b68e..bc515e0 100755 --- a/src/lib/full_upgrade.sh +++ b/src/lib/full_upgrade.sh @@ -18,8 +18,9 @@ if [ -n "${proceed_with_update}" ]; then # shellcheck source=src/lib/update.sh source "${libdir}/update.sh" - # Record the date of the last successful update (used by other stages) + # Record the date of the last successful update (used by other stages) and empty the 'updates' state file (which contains the list of pending updates) date +%Y-%m-%d > "${statedir}/last_update_run" + true > "${statedir}/last_updates_check" fi # Source the "orphan_packages" library which displays orphan packages and offers to remove them diff --git a/src/lib/tray.py b/src/lib/tray.py index 8c62443..0024052 100755 --- a/src/lib/tray.py +++ b/src/lib/tray.py @@ -10,6 +10,7 @@ import os import sys import subprocess +import re from PyQt6.QtGui import QIcon, QAction from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QMenu from PyQt6.QtCore import QFileSystemWatcher @@ -26,9 +27,20 @@ ICON_FILE = os.path.join( os.environ['HOME'], '.local', 'state', 'arch-update', 'tray_icon') if not os.path.isfile(ICON_FILE): - log.error("Statefile does not exist: %s", ICON_FILE) + log.error("State icon file does not exist: %s", ICON_FILE) sys.exit(1) +# Find Updates file +UPDATES_FILE = None +if 'XDG_STATE_HOME' in os.environ: + UPDATES_FILE = os.path.join( + os.environ['XDG_STATE_HOME'], 'arch-update', 'last_updates_check') +elif 'HOME' in os.environ: + UPDATES_FILE = os.path.join( + os.environ['HOME'], '.local', 'state', 'arch-update', 'last_updates_check') +if not os.path.isfile(UPDATES_FILE): + log.error("State updates file does not exist: %s", UPDATES_FILE) + # Find translations paths = [] if 'XDG_DATA_DIRS' in os.environ: @@ -79,21 +91,67 @@ class ArchUpdateQt6: """ System Tray using QT6 library """ def file_changed(self): - """ Called when icon file content changes """ + """ Update icon and tooltip on state file content changes """ + self.update_icon() + self.update_tooltip() - contents = "" + def update_icon(self): + """ Update the tray icon based on the icon state file content """ if self.watcher and not self.iconfile in self.watcher.files(): self.watcher.addPath(self.iconfile) + try: with open(self.iconfile, encoding="utf-8") as f: contents = f.readline().strip() except FileNotFoundError: log.error("Statefile Missing") sys.exit(1) + if contents.startswith("arch-update"): icon = QIcon.fromTheme(contents) self.tray.setIcon(icon) + def update_tooltip(self): + """ Update the tooltip with the number / list of pending updates """ + if self.watcher and not self.updatesfile in self.watcher.files(): + self.watcher.addPath(self.updatesfile) + + try: + with open(self.updatesfile, encoding="utf-8") as f: + updates_list = f.readlines() + except FileNotFoundError: + log.error("State updates file missing") + tooltip = _("Arch-Update: 'updates' state file isn't found") + self.tray.setToolTip(tooltip) + return + + # Define a regex pattern to match ANSI escape / color codes + ansi_escape_pattern = re.compile(r'\x1B\[[0-?9;]*[mK]') + + # Remove ANSI escape / color codes and any empty lines, then strip whitespaces + updates_list = [ + ansi_escape_pattern.sub('', update).strip() + for update in updates_list + if update.strip() + ] + + updates_count = len(updates_list) + + if updates_count == 0: + tooltip = _("Arch-Update: System is up to date") + elif updates_count == 1: + update_list = "".join(updates_list) + tooltip = _("Arch-Update: 1 update available\n\n{update_list}").format( + update_list=update_list + ) + else: + update_list = "\n".join(updates_list) + tooltip = _("Arch-Update: {updates} updates available\n\n{update_list}").format( + updates=updates_count, update_list=update_list + ) + + self.tray.setToolTip(tooltip) + def run(self): """ Start arch-update """ arch_update() @@ -110,6 +168,7 @@ def __init__(self, iconfile): """ Start Qt6 System Tray """ self.iconfile = iconfile + self.updatesfile = UPDATES_FILE self.watcher = None # Application @@ -138,7 +197,7 @@ def __init__(self, iconfile): self.tray.setContextMenu(menu) # File Watcher - self.watcher = QFileSystemWatcher([self.iconfile]) + self.watcher = QFileSystemWatcher([self.iconfile, self.updatesfile]) self.watcher.fileChanged.connect(self.file_changed) app.exec()