#!/usr/bin/python3
# Armbian: show a notification when updates are available or a restart is
# required. The apt timers refresh the package lists. This script only reads
# them. The notification opens Software Updater.

import os
import subprocess

import apt_pkg
import gi

gi.require_version("Notify", "0.7")
from gi.repository import GLib, Notify

FIRST_CHECK_SECONDS = 5 * 60
CHECK_SECONDS = 6 * 60 * 60
REBOOT_REQUIRED = "/run/reboot-required"
UPDATE_NOTIFIER = "/usr/bin/update-notifier"


def count_updates():
    """Count the packages that a full upgrade installs or upgrades."""
    apt_pkg.init()
    cache = apt_pkg.Cache(None)
    depcache = apt_pkg.DepCache(cache)
    depcache.read_pinfile()
    depcache.init()
    if depcache.broken_count:
        return 0
    depcache.upgrade(True)
    return sum(
        1
        for pkg in cache.packages
        if depcache.marked_install(pkg) or depcache.marked_upgrade(pkg)
    )


def open_updater(notification, action):
    subprocess.Popen(["update-manager"])
    notification.close()


class Notifier:
    def __init__(self):
        self.updates_shown = 0
        self.reboot_shown = False
        self.updates = Notify.Notification.new(
            "", "", "system-software-update"
        )
        self.updates.add_action("default", "Open", open_updater)
        self.updates.add_action("open", "Open Software Updater", open_updater)
        self.reboot = Notify.Notification.new(
            "Restart required",
            "Restart the computer to finish the updates.",
            "system-reboot",
        )

    def check(self):
        try:
            count = count_updates()
        except SystemError:
            # dpkg or apt holds the lock. Try again at the next check.
            count = 0
        if count > self.updates_shown:
            self.updates.update(
                "Software updates available",
                "%d updates are available." % count,
                "system-software-update",
            )
            self.updates.show()
        self.updates_shown = count
        if os.path.exists(REBOOT_REQUIRED) and not self.reboot_shown:
            self.reboot.show()
            self.reboot_shown = True


def main():
    # Ubuntu's update-notifier shows the same information.
    if os.path.exists(UPDATE_NOTIFIER):
        return
    if not Notify.init("Software Updater"):
        return
    notifier = Notifier()
    # A timeout runs again while its callback returns True.
    GLib.timeout_add_seconds(
        FIRST_CHECK_SECONDS, lambda: notifier.check() or False
    )
    GLib.timeout_add_seconds(CHECK_SECONDS, lambda: notifier.check() or True)
    GLib.MainLoop().run()


if __name__ == "__main__":
    main()
