diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a43a531 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +usr/share/archlinux-kernel-manager/libs/__pycache__ +usr/share/archlinux-kernel-manager/ui/__pycache__ \ No newline at end of file diff --git a/README.md b/README.md index d8ed40d..a925ff4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Arch Linux Kernel Manager -A GTK4 Python application used to install and remove Linux Kernels on an Arch based system. +A GTK4 Python application which installs and removes Linux Kernels on Arch Linux based systems. Installation and removal of Kernels is carried out using Pacman. @@ -20,7 +20,7 @@ Both official and un-official community based Kernels are supported. Since the ALA has a lot of kernel packages any versions found older than 2 years or more are ignored. These kernels are considerably out of date and have shown to fail to install properly with issues related to missing modules. -![Official kernels](https://github.com/DeltaCopy/archlinux-kernel-manager/assets/121581829/d3e0416d-5ba8-4906-bada-835f4d949130) +![Official kernels](https://github.com/arcolinux/archlinux-kernel-manager-dev/assets/121581829/2e30c26f-a06d-4ab9-91a7-14e1ced99389) ## What happens if a kernel installation fails @@ -43,11 +43,11 @@ Most of these are sourced from the [Chaotic AUR](https://aur.chaotic.cx) See updating the [configuration file](#Adding-new-community-based-kernels) for adding new kernels. -![Community kernels](https://github.com/DeltaCopy/archlinux-kernel-manager/assets/121581829/072bc9b2-cca4-4c5a-ae91-be9c0440feb3) +![Community kernels](https://github.com/arcolinux/archlinux-kernel-manager-dev/assets/121581829/8e28de8d-35eb-45b2-b799-cd691c092852) # Installed kernels -![Installed kernels](https://github.com/DeltaCopy/archlinux-kernel-manager/assets/121581829/1120c9cc-adc1-4f2c-92c5-dff8d1d1c841) +![Installed kernels](https://github.com/arcolinux/archlinux-kernel-manager-dev/assets/121581829/75e98bd6-dd46-4c91-807c-a042cb3a3f04) # Progress window @@ -75,13 +75,13 @@ By default, the application will use `bootctl` to distinguish which bootloader ( The bootloader settings can be overridden using the Advanced settings window. Or you can manually update the configuration file (see the custom bootloader example). -![Advanced settings](https://github.com/DeltaCopy/archlinux-kernel-manager/assets/121581829/827033b1-9250-4967-9431-e2b6205ed3a0) +![Advanced settings](https://github.com/arcolinux/archlinux-kernel-manager-dev/assets/121581829/0a5cd26d-7991-4cea-ab43-26c36e57b135) ## Latest kernel versions Based on the latest information taken from the configured pacman mirrors. -![Kernel versions](https://github.com/DeltaCopy/archlinux-kernel-manager/assets/121581829/43416b00-3759-4913-8d09-8f9083edc358) +![Kernel versions](https://github.com/arcolinux/archlinux-kernel-manager-dev/assets/121581829/a4dccbf9-969a-4ef0-bd8c-b212f31ea2cb) # Default configuration file @@ -156,12 +156,6 @@ Logs can be found inside `/var/log/archlinux-kernel-manager` - python-psutil -# Installing the application - -`wget https://raw.githubusercontent.com/DeltaCopy/archlinux-kernel-manager/main/PKGBUILD` - -`makepkg -si` - # Running the application Run `akm` or `archlinux-kernel-manager` to launch the application. diff --git a/usr/bin/archlinux-kernel-manager b/usr/bin/archlinux-kernel-manager index c46d158..a62670d 100755 --- a/usr/bin/archlinux-kernel-manager +++ b/usr/bin/archlinux-kernel-manager @@ -4,49 +4,93 @@ # the polkit agent running on the desktop environment should prompt for root password echo "---------------------------------------------------------------------------" -echo "[INFO] Checking session" -test $(whoami) == "root" && echo "[ERROR] Do not run this script as root." && exit 1 -test -z $DISPLAY && echo "[ERROR] DISPLAY variable is not set." && exit 1 +echo "[INFO]: Checking session" +test $(whoami) == "root" && echo "[ERROR]: Do not run this script as root." && exit 1 +test -z $DISPLAY && echo "[ERROR]: DISPLAY variable is not set." && exit 1 # check session is either one of X11, Wayland or TTY -session=$(loginctl show-session $(loginctl|grep $(whoami) | awk '{print $1}') -p Type | awk -F= '{print $2}' | grep "x11\|wayland\|tty") +SESSION=$(loginctl show-session $(loginctl|grep $(whoami) | awk '{print $1}') -p Type | awk -F= '{print $2}' | grep "x11\|wayland\|tty") +test -z "$SESSION" && echo "[ERROR]: Failed to verify session for user, SESSION = $SESSION" && exit 1 -test -z "$session" && echo "[ERROR] Failed to verify session for user." && exit 1 +XAUTHORITY=$(xauth info | awk -F"Authority file:" '{print $2}' | tr -d ' ') +test -z "$XAUTHORITY" && echo "[ERROR]: XAUTHORIY file is not set" && exit 1 +test -s "$XAUTHORITY" || touch "$XAUTHORITY" -xauth_file=$(xauth info | awk -F"Authority file:" '{print $2}' | tr -d ' ') -test -s "$xauth_file" || touch "$xauth_file" +XAUTH_HONORED=$(xauth info | awk -F"Changes honored:" '{print $2}' | tr -d ' ') +test $XAUTH_HONORED = "yes" || echo "[ERROR]: Xauth changes honored = no, restart X server" || exit 1 -case "$session" in - "wayland") - # Wayland session, generate Xauth session cookie for $DISPLAY - xauth gen $DISPLAY &> /dev/null - echo "[INFO] Display = $DISPLAY" - echo "[INFO] Session = $session" +# GTK_A11Y=none - fixes the dbus-launch errors with GTK4 - test -z "$(xauth list)" || echo "[INFO] Xauth session = OK" - ;; - "x11") - # X11 session, don't do anything here - echo "[INFO] Display = $DISPLAY" - echo "[INFO] Session = $session" +echo "[INFO]: XAUTHORITY = $XAUTHORITY" +echo "[INFO]: DBUS_SESSION_BUS_ADDRESS = $DBUS_SESSION_BUS_ADDRESS" +echo "[INFO]: DESKTOP SESSION = $DESKTOP_SESSION" - # just show msg on whether the Xauth session cookie is setup - test -z "$(xauth list)" || echo "[INFO] Xauth session = OK" - ;; - "tty") - # TTY session, as user may not use a display manager - echo "[INFO] Display = $DISPLAY" - echo "[INFO] Session = $session" +function start_in_wayland() { + echo "[INFO]: Starting in Wayland session" + xauth gen $DISPLAY &> /dev/null - test -z "$(xauth list)" || echo "[INFO] Xauth session = OK" - ;; - *) - # anything here is an unknown session, most likely AKM will fail to load - echo "[WARN] Continuing, but cannot verify session for user." - ;; -esac + case "$DESKTOP_SESSION" in + plasma | gnome) + pkexec env DISPLAY=$DISPLAY WAYLAND_DISPLAY="$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" XAUTHORITY=$XAUTHORITY DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS GDK_BACKEND=x11 GTK_A11Y=none '/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py' + ;; + *) + pkexec env DISPLAY=$DISPLAY WAYLAND_DISPLAY="$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" XAUTHORITY=$XAUTHORITY DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS GTK_A11Y=none '/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py' + ;; + esac +} + +function start_in_x11() { + echo "[INFO]: Starting in X11 session" + pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY DBUS_SESSION_BUS_ADDRESS=$DBUS_SESSION_BUS_ADDRESS GTK_A11Y=none '/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py' +} + +function start_in_tty() { + echo "[INFO]: Starting in TTY session" + pkexec '/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py' +} + +case "$SESSION" in + "wayland") + # Wayland session, generate Xauth session cookie for $DISPLAY + echo "[INFO]: Display = $DISPLAY" + echo "[INFO]: Session = $SESSION" + start_in_wayland + ;; + "x11") + # X11 session, don't do anything here + echo "[INFO]: Display = $DISPLAY" + echo "[INFO]: Session = $SESSION" + + # just show msg on whether the Xauth session cookie is setup + start_in_x11 + ;; + "tty") + # TTY session, as user may not use a display manager + echo "[INFO]: Display = $DISPLAY" + echo "[INFO]: Session = $SESSION" + + start_in_tty + ;; + *) + # anything here is an unknown session, most likely AKM will fail to load + echo "[INFO]: Display = $DISPLAY" + echo "[INFO]: Session could not be verified ... falling back to use XDG_SESSION_TYPE" + + case "$XDG_SESSION_TYPE" in + "wayland") + start_in_wayland + ;; + "tty") + start_in_tty + ;; + "x11") + start_in_x11 + ;; + *) + echo "[ERROR]: $XDG_SESSION_TYPE is empty, cannot continue" + exit 1 + ;; + esac + ;; + esac echo "---------------------------------------------------------------------------" - -echo "[INFO] Starting Arch Linux Kernel Manager" -pkexec '/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py' - diff --git a/usr/share/archlinux-kernel-manager/akm.css b/usr/share/archlinux-kernel-manager/akm.css index 5f2598d..69088b2 100644 --- a/usr/share/archlinux-kernel-manager/akm.css +++ b/usr/share/archlinux-kernel-manager/akm.css @@ -39,7 +39,7 @@ box#box_row{ box#hbox_kernel{ background-color: @theme_base_color; padding-bottom: 8px; - box-shadow: -6px 8px 10px rgba(81,41,10,0.1),0px 2px 2px rgba(81,41,10,0.2); + /*box-shadow: -6px 8px 10px rgba(81,41,10,0.1),0px 2px 2px rgba(81,41,10,0.2);*/ } box#vbox_header{ @@ -53,7 +53,7 @@ box#vbox_header{ border-spacing: 5px; font-weight: bold; font-family: 'Noto Sans', 'Helvetica', sans-serif; - box-shadow: -6px 8px 10px rgba(81,41,10,0.1),0px 2px 2px rgba(81,41,10,0.2); + /*box-shadow: -6px 8px 10px rgba(81,41,10,0.1),0px 2px 2px rgba(81,41,10,0.2);*/ } box#hbox_warning{ @@ -156,15 +156,6 @@ button#button_uninstall_kernel{ padding: 10px 10px 10px 10px; } -.sidebar label:hover, -.sidebar label:focus{ - font-weight: bold; -} - -#hbox_stack_sidebar{ - box-shadow: rgba(33, 35, 38, 0.1) 0px 10px 10px -10px; -} - #textview_log text{ background-color: #232627; color: #fcfcfc; diff --git a/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py b/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py index eef0a83..88e2c83 100755 --- a/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py +++ b/usr/share/archlinux-kernel-manager/archlinux-kernel-manager.py @@ -17,7 +17,7 @@ base_dir = fn.os.path.dirname(fn.os.path.realpath(__file__)) app_name = "Arch Linux Kernel Manager" app_version = "${app_version}" app_name_dir = "archlinux-kernel-manager" -app_id = "com.deltacopy.kernelmanager" +app_id = "com.arcolinux.kernelmanager" lock_file = "/tmp/akm.lock" pid_file = "/tmp/akm.pid" @@ -30,6 +30,7 @@ class Main(Gtk.Application): default_context = GLib.MainContext.default() win = self.props.active_window + if not win: win = ManagerGUI( application=self, @@ -42,7 +43,6 @@ class Main(Gtk.Application): # sourced from /usr/share/icons/hicolor/scalable/apps win.set_icon_name("archlinux-kernel-manager-tux") - provider = Gtk.CssProvider.new() css_file = Gio.file_new_for_path(base_dir + "/akm.css") provider.load_from_file(css_file) diff --git a/usr/share/archlinux-kernel-manager/images/364x408/akm-tux-splash.png b/usr/share/archlinux-kernel-manager/images/364x408/akm-tux-splash.png deleted file mode 100644 index c1479a3..0000000 Binary files a/usr/share/archlinux-kernel-manager/images/364x408/akm-tux-splash.png and /dev/null differ diff --git a/usr/share/archlinux-kernel-manager/images/48x48/akm-tux.png b/usr/share/archlinux-kernel-manager/images/48x48/akm-tux.png index 5719279..8bdcdae 100644 Binary files a/usr/share/archlinux-kernel-manager/images/48x48/akm-tux.png and b/usr/share/archlinux-kernel-manager/images/48x48/akm-tux.png differ diff --git a/usr/share/archlinux-kernel-manager/images/600x400/akm-tux-splash.png b/usr/share/archlinux-kernel-manager/images/600x400/akm-tux-splash.png new file mode 100644 index 0000000..22815b9 Binary files /dev/null and b/usr/share/archlinux-kernel-manager/images/600x400/akm-tux-splash.png differ diff --git a/usr/share/archlinux-kernel-manager/images/96x96/akm-tux.png b/usr/share/archlinux-kernel-manager/images/96x96/akm-tux.png index 5a92094..1b136fe 100644 Binary files a/usr/share/archlinux-kernel-manager/images/96x96/akm-tux.png and b/usr/share/archlinux-kernel-manager/images/96x96/akm-tux.png differ diff --git a/usr/share/archlinux-kernel-manager/libs/functions.py b/usr/share/archlinux-kernel-manager/libs/functions.py index fdb57c9..d3ed11a 100644 --- a/usr/share/archlinux-kernel-manager/libs/functions.py +++ b/usr/share/archlinux-kernel-manager/libs/functions.py @@ -395,64 +395,67 @@ def write_cache(): # install from the ALA def install_archive_kernel(self): try: - for pkg_archive_url in self.official_kernels: - if self.errors_found is True: - break + install_cmd_str = [ + "pacman", + "-U", + self.official_kernels[0], + self.official_kernels[1], + "--noconfirm", + "--needed", + ] - install_cmd_str = [ - "pacman", - "-U", - pkg_archive_url, - "--noconfirm", - "--needed", - ] + wait_for_pacman_process() - wait_for_pacman_process() + logger.info("Running %s" % install_cmd_str) - logger.info("Running %s" % install_cmd_str) + event = "%s [INFO]: Running %s\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + " ".join(install_cmd_str), + ) - event = "%s [INFO]: Running %s\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - " ".join(install_cmd_str), - ) + event_log = [] + self.messages_queue.put(event) - event_log = [] - self.messages_queue.put(event) + with subprocess.Popen( + install_cmd_str, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=1, + universal_newlines=True, + ) as process: + while True: + if process.poll() is not None: + break + for line in process.stdout: + print(line.strip()) + self.messages_queue.put(line) + event_log.append(line.lower().strip()) - with subprocess.Popen( - install_cmd_str, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - bufsize=1, - universal_newlines=True, - ) as process: - while True: - if process.poll() is not None: - break - for line in process.stdout: - print(line.strip()) - self.messages_queue.put(line) - event_log.append(line.lower().strip()) + time.sleep(0.3) - time.sleep(0.3) + error = None - error = None + if ( + "installation finished. no error reported." + or "initcpio image generation successful" in event_log + ): + error = False - if "installation finished. no error reported." in event_log: - error = False - else: + else: + if error is None: # check errors and indicate to user install failed for log in event_log: # if "installation finished. no error reported." in log: # error = False # break if "error" in log or "errors" in log: - event = ( "%s [ERROR]: Errors have been encountered during installation\n" % (datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")) ) + logger.error(log) + self.messages_queue.put(event) self.errors_found = True @@ -471,57 +474,49 @@ def install_archive_kernel(self): break - # query to check if kernel installed - if "headers" in pkg_archive_url: - if ( - check_kernel_installed(self.kernel.name + "-headers") - and error is False - ): + # query to check if kernel installed - self.kernel_state_queue.put( - (0, "install", self.kernel.name + "-headers") - ) + if check_kernel_installed(self.kernel.name + "-headers") and error is False: - event = "%s [INFO]: Installation of %s-headers completed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) + self.kernel_state_queue.put((0, "install", self.kernel.name + "-headers")) - self.messages_queue.put(event) + event = "%s [INFO]: Installation of %s-headers completed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.kernel.name, + ) - else: - self.kernel_state_queue.put( - (1, "install", self.kernel.name + "-headers") - ) + self.messages_queue.put(event) - event = "%s [ERROR]: Installation of %s-headers failed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) + else: + self.kernel_state_queue.put((1, "install", self.kernel.name + "-headers")) - self.errors_found = True - self.messages_queue.put(event) + event = "%s [ERROR]: Installation of %s-headers failed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.kernel.name, + ) - else: - if check_kernel_installed(self.kernel.name) and error is False: - self.kernel_state_queue.put((0, "install", self.kernel.name)) + self.errors_found = True + self.messages_queue.put(event) - event = "%s [INFO]: Installation of kernel %s completed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) + if check_kernel_installed(self.kernel.name) and error is False: + self.kernel_state_queue.put((0, "install", self.kernel.name)) - self.messages_queue.put(event) + event = "%s [INFO]: Installation of kernel %s completed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.kernel.name, + ) - else: - self.kernel_state_queue.put((1, "install", self.kernel.name)) + self.messages_queue.put(event) - event = "%s [ERROR]: Installation of kernel %s failed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) + else: + self.kernel_state_queue.put((1, "install", self.kernel.name)) - self.messages_queue.put(event) + event = "%s [ERROR]: Installation of kernel %s failed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.kernel.name, + ) + + self.messages_queue.put(event) # signal to say end reached self.kernel_state_queue.put(None) @@ -1117,80 +1112,76 @@ def get_community_kernels(self): # ===================================================== def install_community_kernel(self): try: - for kernel in [self.kernel.name, "%s-headers" % self.kernel.name]: - error = False + error = False + install_cmd_str = [ + "pacman", + "-S", + "%s/%s" % (self.kernel.repository, self.kernel.name), + "%s/%s" % (self.kernel.repository, "%s-headers" % self.kernel.name), + "--noconfirm", + "--needed", + ] - if self.errors_found is True: + logger.info("Running %s" % install_cmd_str) + + event = "%s [INFO]: Running %s\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + " ".join(install_cmd_str), + ) + + event_log = [] + + self.messages_queue.put(event) + + with subprocess.Popen( + install_cmd_str, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=1, + universal_newlines=True, + ) as process: + while True: + if process.poll() is not None: + break + for line in process.stdout: + print(line.strip()) + self.messages_queue.put(line) + event_log.append(line.lower().strip()) + + time.sleep(0.3) + + for log in event_log: + if "installation finished. no error reported." in log: + error = False break - install_cmd_str = [ - "pacman", - "-S", - "%s/%s" % (self.kernel.repository, kernel), - "--noconfirm", - "--needed", - ] + if "error" in log: + error = True - logger.info("Running %s" % install_cmd_str) + if check_kernel_installed(self.kernel.name) and error is False: + logger.info("Kernel = installed") - event = "%s [INFO]: Running %s\n" % ( + self.kernel_state_queue.put((0, "install", self.kernel.name)) + + event = "%s [INFO]: Installation of %s completed\n" % ( datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - " ".join(install_cmd_str), + self.kernel.name, ) - event_log = [] - self.messages_queue.put(event) - with subprocess.Popen( - install_cmd_str, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - bufsize=1, - universal_newlines=True, - ) as process: - while True: - if process.poll() is not None: - break - for line in process.stdout: - print(line.strip()) - self.messages_queue.put(line) - event_log.append(line.lower().strip()) + else: + logger.error("Kernel = install failed") - time.sleep(0.3) + self.kernel_state_queue.put((1, "install", self.kernel.name)) - for log in event_log: - if "installation finished. no error reported." in log: - error = False - break + event = "%s [ERROR]: Installation of %s failed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.kernel.name, + ) - if "error" in log: - error = True - - if check_kernel_installed(kernel) and error == False: - logger.info("Kernel = installed") - - self.kernel_state_queue.put((0, "install", kernel)) - - event = "%s [INFO]: Installation of %s completed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - kernel, - ) - - self.messages_queue.put(event) - - else: - logger.error("Kernel = install failed") - - self.kernel_state_queue.put((1, "install", kernel)) - - event = "%s [ERROR]: Installation of %s failed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - kernel, - ) - - self.errors_found = True - self.messages_queue.put(event) + self.errors_found = True + self.messages_queue.put(event) # signal to say end reached self.kernel_state_queue.put(None) @@ -1407,8 +1398,9 @@ def get_boot_loader(): def get_kernel_version(kernel): - cmd = ["pacman", "-Q", kernel] - + cmd = ["pacman", "-Qli", kernel] + # pacman_kernel_version = None + kernel_modules_path = None try: logger.debug("Running %s" % " ".join(cmd)) process = subprocess.run( @@ -1423,12 +1415,68 @@ def get_kernel_version(kernel): if process.returncode == 0: for line in process.stdout.splitlines(): - print(line.strip()) - return line.split(" ")[1] + # if line.startswith("Version :"): + # pacman_kernel_version = line.split("Version :")[1].strip() + # print(pacman_kernel_version) + + if "/usr/lib/modules/" in line: + if "kernel" in line.split(" ")[1]: + kernel_modules_path = line.split(" ")[1] + break + + if kernel_modules_path is not None: + return ( + kernel_modules_path.split("/usr/lib/modules/")[1] + .strip() + .split("/kernel/")[0] + .strip() + ) + else: + return None + except Exception as e: logger.error("Exception in get_kernel_version(): %s" % e) +def run_process(self): + error = False + + logger.debug("Running process = %s" % " ".join(self.cmd)) + with subprocess.Popen( + self.cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=1, + universal_newlines=True, + ) as process: + while True: + if process.poll() is not None: + break + for line in process.stdout: + self.messages_queue.put(line) + self.stdout_lines.append(line.lower().strip()) + print(line.strip()) + + for log in self.stdout_lines: + if "error" in log or "errors" in log: + self.errors_found = True + + error = True + + if error is True: + self.label_notify_revealer.set_text("%s failed" % " ".join(self.cmd)) + self.reveal_notify() + + logger.error("%s failed" % " ".join(self.cmd)) + else: + self.label_notify_revealer.set_text("%s completed" % " ".join(self.cmd)) + self.reveal_notify() + + logger.info("%s completed" % " ".join(self.cmd)) + + # time.sleep(0.3) + + # ====================================================================== # UPDATE BOOTLOADER ENTRIES # ====================================================================== @@ -1437,14 +1485,30 @@ def get_kernel_version(kernel): # grub - grub-mkconfig /boot/grub/grub.cfg # systemd-boot - bootctl update def update_bootloader(self): - cmd = None + cmds = [] + error = False + self.stdout_lines = [] if self.action == "install": image = "images/48x48/akm-install.png" - cmd = ["kernel-install", "add-all"] + + if self.installed_kernel_version is not None: + + for self.cmd in [ + ["kernel-install", "add-all"], + ["kernel-install", "remove", self.installed_kernel_version], + ]: + run_process(self) + + else: + self.cmd = ["kernel-install", "add-all"] + run_process(self) + else: image = "images/48x48/akm-remove.png" - cmd = ["kernel-install", "remove", self.installed_kernel_version] + if self.installed_kernel_version is not None: + self.cmd = ["kernel-install", "remove", self.installed_kernel_version] + run_process(self) try: @@ -1460,17 +1524,35 @@ def update_bootloader(self): logger.info("Current bootloader = %s" % self.bootloader) - if cmd is not None: - stdout_lines = [] + cmd = None + + if self.bootloader == "grub": + if self.bootloader_grub_cfg is not None: + cmd = ["grub-mkconfig", "-o", self.bootloader_grub_cfg] + else: + logger.error("Bootloader grub config file not specified") + event = "%s [INFO]: Running %s\n" % ( datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), " ".join(cmd), ) - self.messages_queue.put(event) - logger.info("Running %s" % " ".join(cmd)) + elif self.bootloader == "systemd-boot": + # cmd = ["bootctl", "update"] + # graceful update systemd-boot + cmd = ["bootctl", "--no-variables", "--graceful", "update"] + event = "%s [INFO]: Running %s\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + " ".join(cmd), + ) + self.messages_queue.put(event) + else: + logger.error("Bootloader is empty / not supported") + if cmd is not None: + self.stdout_lines = [] + logger.info("Running %s" % " ".join(cmd)) with subprocess.Popen( cmd, stdout=subprocess.PIPE, @@ -1482,183 +1564,105 @@ def update_bootloader(self): if process.poll() is not None: break for line in process.stdout: + self.stdout_lines.append(line.strip()) self.messages_queue.put(line) - stdout_lines.append(line.lower().strip()) print(line.strip()) # time.sleep(0.3) - error = False + if process.returncode == 0: + self.label_notify_revealer.set_text( + "Bootloader %s updated" % self.bootloader + ) + self.reveal_notify() - for log in stdout_lines: - if "error" in log or "errors" in log: + logger.info("%s update completed" % self.bootloader) - # event = ( - # "%s [ERROR]: Errors have been encountered during installation\n" - # % (datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")) - # ) - # - # self.messages_queue.put(event) + event = "%s [INFO]: %s update completed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.bootloader, + ) + self.messages_queue.put(event) - self.errors_found = True + logger.info("Linux packages have changed a reboot is recommended") + event = "%s [INFO]: #### Linux packages have changed a reboot is recommended ####\n" % datetime.datetime.now().strftime( + "%Y-%m-%d-%H-%M-%S" + ) + self.messages_queue.put(event) - error = True + if self.restore is False: + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} completed\n" + f"This window can now be closed\n", + image, + priority=GLib.PRIORITY_DEFAULT, + ) + else: + if ( + "Skipping" + or "same boot loader version in place already." in stdout_lines + ): + logger.info("%s update completed" % self.bootloader) - if error is True: - self.label_notify_revealer.set_text("%s failed" % " ".join(cmd)) - self.reveal_notify() + event = "%s [INFO]: %s update completed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.bootloader, + ) + self.messages_queue.put(event) - logger.error("%s failed" % " ".join(cmd)) - else: - self.label_notify_revealer.set_text("%s completed" % " ".join(cmd)) - self.reveal_notify() + if self.restore is False: + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} completed\n" + f"This window can now be closed\n", + image, + priority=GLib.PRIORITY_DEFAULT, + ) - logger.info("%s completed" % " ".join(cmd)) - - if self.bootloader == "grub": - if self.bootloader_grub_cfg is not None: - cmd = ["grub-mkconfig", "-o", self.bootloader_grub_cfg] else: - logger.error("Bootloader grub config file not specified") + self.label_notify_revealer.set_text( + "Bootloader %s update failed" % self.bootloader + ) + self.reveal_notify() - event = "%s [INFO]: Running %s\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - " ".join(cmd), - ) - self.messages_queue.put(event) + event = "%s [ERROR]: %s update failed\n" % ( + datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.bootloader, + ) - elif self.bootloader == "systemd-boot": - # cmd = ["bootctl", "update"] - # graceful update systemd-boot - cmd = ["bootctl", "--no-variables", "--graceful", "update"] - event = "%s [INFO]: Running %s\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - " ".join(cmd), - ) - self.messages_queue.put(event) - else: - logger.error("Bootloader is empty / not supported") + logger.error("%s update failed" % self.bootloader) + logger.error(str(stdout_lines)) + self.messages_queue.put(event) - if cmd is not None: - stdout_lines = [] - logger.info("Running %s" % " ".join(cmd)) - with subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - bufsize=1, - universal_newlines=True, - ) as process: - while True: - if process.poll() is not None: - break - for line in process.stdout: - stdout_lines.append(line.strip()) - self.messages_queue.put(line) - print(line.strip()) + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} failed .. attempting kernel restore\n" + f"There have been errors, please review the logs\n", + image, + priority=GLib.PRIORITY_DEFAULT, + ) - # time.sleep(0.3) - - if process.returncode == 0: - self.label_notify_revealer.set_text( - "Bootloader %s updated" % self.bootloader - ) - self.reveal_notify() - - logger.info("%s update completed" % self.bootloader) - - event = "%s [INFO]: %s update completed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.bootloader, - ) - self.messages_queue.put(event) - - logger.info( - "Linux packages have changed a reboot is recommended" - ) - event = "%s [INFO]: #### Linux packages have changed a reboot is recommended ####\n" % datetime.datetime.now().strftime( - "%Y-%m-%d-%H-%M-%S" - ) - self.messages_queue.put(event) - - if self.restore is False: - GLib.idle_add( - show_mw, - self, - "System changes", - f"Kernel {self.action} completed\n" - f"This window can now be closed\n", - image, - priority=GLib.PRIORITY_DEFAULT, - ) - else: - if ( - "Skipping" - or "same boot loader version in place already." - in stdout_lines - ): - logger.info("%s update completed" % self.bootloader) - - event = "%s [INFO]: %s update completed\n" % ( - datetime.datetime.now().strftime( - "%Y-%m-%d-%H-%M-%S" - ), - self.bootloader, - ) - self.messages_queue.put(event) - - if self.restore is False: - GLib.idle_add( - show_mw, - self, - "System changes", - f"Kernel {self.action} completed\n" - f"This window can now be closed\n", - image, - priority=GLib.PRIORITY_DEFAULT, - ) - - else: - self.label_notify_revealer.set_text( - "Bootloader %s update failed" % self.bootloader - ) - self.reveal_notify() - - event = "%s [ERROR]: %s update failed\n" % ( - datetime.datetime.now().strftime( - "%Y-%m-%d-%H-%M-%S" - ), - self.bootloader, - ) - - logger.error("%s update failed" % self.bootloader) - logger.error(str(stdout_lines)) - self.messages_queue.put(event) - - GLib.idle_add( - show_mw, - self, - "System changes", - f"Kernel {self.action} failed .. attempting kernel restore\n" - f"There have been errors, please review the logs\n", - image, - priority=GLib.PRIORITY_DEFAULT, - ) - - else: - logger.error("Bootloader update failed") - - GLib.idle_add( - show_mw, - self, - "System changes", - f"Kernel {self.action} failed\n" - f"There have been errors, please review the logs\n", - image, - priority=GLib.PRIORITY_DEFAULT, - ) else: - logger.error("Bootloader update cannot continue, failed to set command.") + logger.error("Bootloader update failed") + + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} failed\n" + f"There have been errors, please review the logs\n", + image, + priority=GLib.PRIORITY_DEFAULT, + ) + # else: + # logger.error("Bootloader update cannot continue, failed to set command.") except Exception as e: logger.error("Exception in update_bootloader(): %s" % e) diff --git a/usr/share/archlinux-kernel-manager/ui/AboutDialog.py b/usr/share/archlinux-kernel-manager/ui/AboutDialog.py index 40600fd..6c9ca12 100644 --- a/usr/share/archlinux-kernel-manager/ui/AboutDialog.py +++ b/usr/share/archlinux-kernel-manager/ui/AboutDialog.py @@ -13,14 +13,13 @@ class AboutDialog(Gtk.AboutDialog): def __init__(self, manager_gui, **kwargs): super().__init__(**kwargs) - website = "https://github.com/DeltaCopy/archlinux-kernel-manager" - authors = ["fennec (DeltaCopy)"] + website = "http://arcolinux.info/" + authors = ["Erik Dubois", "Fennec"] program_name = "Arch Linux Kernel Manager" comments = ( f"Add/Remove Officially supported Linux kernels on Arch based systems\n" f"Powered by the Arch Linux Archive (a.k.a ALA)\n" f"Community based Linux kernels are also supported\n" - f"This application matches your system theme !\n" f"Developed in Python with GTK 4\n" ) @@ -40,7 +39,7 @@ class AboutDialog(Gtk.AboutDialog): tux_icon = Gdk.Texture.new_from_file( file=Gio.File.new_for_path( - os.path.join(base_dir, "images/364x408/akm-tux-splash.png") + os.path.join(base_dir, "images/96x96/akm-tux.png") ) ) diff --git a/usr/share/archlinux-kernel-manager/ui/FlowBox.py b/usr/share/archlinux-kernel-manager/ui/FlowBox.py index 99fdfc6..6051e7c 100644 --- a/usr/share/archlinux-kernel-manager/ui/FlowBox.py +++ b/usr/share/archlinux-kernel-manager/ui/FlowBox.py @@ -107,26 +107,29 @@ class FlowBox(Gtk.FlowBox): ) == "{}-{}".format(cache.name, cache.version): installed = True - if ( - cache.name == installed_kernel.name - and cache.version > installed_kernel.version - ): - fn.logger.info( - "Kernel upgrade available - %s %s" - % (cache.name, cache.version) - ) - - tux_icon = Gtk.Picture.new_for_file( - file=Gio.File.new_for_path( - os.path.join(base_dir, "images/48x48/akm-update.png") + if cache.name == installed_kernel.name: + if ( + cache.version > installed_kernel.version + or cache.version != installed_kernel.version + ): + fn.logger.info( + "Kernel upgrade available - %s %s" + % (cache.name, cache.version) ) - ) - tux_icon.set_can_shrink(True) - label_kernel_name.set_markup( - "*%s %s %s" - % (cache.name, cache.version, cache.repository) - ) + tux_icon = Gtk.Picture.new_for_file( + file=Gio.File.new_for_path( + os.path.join( + base_dir, "images/48x48/akm-update.png" + ) + ) + ) + tux_icon.set_can_shrink(True) + + label_kernel_name.set_markup( + "*%s %s %s" + % (cache.name, cache.version, cache.repository) + ) if installed is True: switch_kernel.set_state(True) diff --git a/usr/share/archlinux-kernel-manager/ui/MessageWindow.py b/usr/share/archlinux-kernel-manager/ui/MessageWindow.py index 6ed7915..f1c37da 100644 --- a/usr/share/archlinux-kernel-manager/ui/MessageWindow.py +++ b/usr/share/archlinux-kernel-manager/ui/MessageWindow.py @@ -15,6 +15,8 @@ class MessageWindow(Gtk.Window): # self.set_title(title=title) self.set_modal(modal=True) self.set_resizable(False) + icon_name = "akm-tux" + self.set_icon_name(icon_name) header_bar = Gtk.HeaderBar() header_bar.set_show_title_buttons(True) @@ -57,7 +59,7 @@ class MessageWindow(Gtk.Window): msg_buffer.insert( msg_buffer.get_end_iter(), "Event timestamp = %s\n" - % fn.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + % fn.datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), ) msg_buffer.insert(msg_buffer.get_end_iter(), "%s\n" % message) @@ -82,7 +84,7 @@ class MessageWindow(Gtk.Window): button_ok.set_halign(Gtk.Align.END) button_ok.connect("clicked", self.on_button_ok_clicked) - hbox_buttons = Gtk.Box.new(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + hbox_buttons = Gtk.Box.new(orientation=Gtk.Orientation.HORIZONTAL, spacing=20) hbox_buttons.set_halign(Gtk.Align.END) hbox_buttons.append(button_ok) diff --git a/usr/share/archlinux-kernel-manager/ui/ProgressWindow.py b/usr/share/archlinux-kernel-manager/ui/ProgressWindow.py index e09e0ad..6a75fbb 100644 --- a/usr/share/archlinux-kernel-manager/ui/ProgressWindow.py +++ b/usr/share/archlinux-kernel-manager/ui/ProgressWindow.py @@ -94,8 +94,15 @@ class ProgressWindow(Gtk.Window): % (self.kernel.name, self.kernel.version) ) - # get kernel version from pacman - self.installed_kernel_version = fn.get_kernel_version(self.kernel.name) + # get kernel version from pacman + self.installed_kernel_version = fn.get_kernel_version(self.kernel.name) + + if self.installed_kernel_version is not None: + fn.logger.debug( + "Installed kernel version = %s" % self.installed_kernel_version + ) + else: + fn.logger.debug("Nothing to remove .. previous kernel not installed") image_settings.set_halign(Gtk.Align.START) image_settings.set_icon_size(Gtk.IconSize.LARGE) @@ -418,8 +425,9 @@ class ProgressWindow(Gtk.Window): ) mw.present() - else: - self.destroy() + + return True + return False def check_kernel_state(self): returncode = None @@ -439,12 +447,6 @@ class ProgressWindow(Gtk.Window): fn.logger.info("Kernel %s completed" % action) - event = "%s [INFO]: Kernel %s completed\n" % ( - fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - action, - ) - self.messages_queue.put(event) - if returncode == 1: self.errors_found = True diff --git a/usr/share/archlinux-kernel-manager/ui/SplashScreen.py b/usr/share/archlinux-kernel-manager/ui/SplashScreen.py index b945ca2..f5799dd 100644 --- a/usr/share/archlinux-kernel-manager/ui/SplashScreen.py +++ b/usr/share/archlinux-kernel-manager/ui/SplashScreen.py @@ -2,7 +2,7 @@ import gi import libs.functions as fn gi.require_version("Gtk", "4.0") -from gi.repository import Gtk, Gio, GLib, GdkPixbuf, GObject, Gdk +from gi.repository import Gtk, Gio base_dir = fn.os.path.abspath(fn.os.path.join(fn.os.path.dirname(__file__), "..")) @@ -12,15 +12,18 @@ class SplashScreen(Gtk.Window): super().__init__(**kwargs) self.set_decorated(False) self.set_resizable(False) + self.set_default_size(600, 400) + self.set_modal(True) self.set_title(app_name) self.set_icon_name("archlinux-kernel-manager-tux") tux_icon = Gtk.Picture.new_for_file( file=Gio.File.new_for_path( - fn.os.path.join(base_dir, "images/364x408/akm-tux-splash.png") + fn.os.path.join(base_dir, "images/600x400/akm-tux-splash.png") ) ) + tux_icon.set_content_fit(content_fit=Gtk.ContentFit.FILL) self.set_child(child=tux_icon)