From 14531bc8291a47ef35a47f50a02855beac7bdaf6 Mon Sep 17 00:00:00 2001 From: arcolinuxz Date: Tue, 2 Jul 2024 08:38:31 +0200 Subject: [PATCH] udpate --- README.md | 17 +- usr/share/archlinux-kernel-manager/akm.css | 5 + .../defaults/config.toml | 4 + .../archlinux-kernel-manager/libs/Kernel.py | 2 +- .../libs/functions.py | 747 +++++++++++------- .../archlinux-kernel-manager/ui/FlowBox.py | 83 +- .../ui/KernelStack.py | 10 +- .../archlinux-kernel-manager/ui/ManagerGUI.py | 121 +-- .../ui/MessageWindow.py | 24 +- .../ui/ProgressWindow.py | 360 ++++----- .../ui/SettingsWindow.py | 2 - 11 files changed, 806 insertions(+), 569 deletions(-) diff --git a/README.md b/README.md index a925ff4..69b6636 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ These kernels are considerably out of date and have shown to fail to install pro ## What happens if a kernel installation fails The application will show a message that it has encountered an issue, and the log inside the progress window, should have the information required to understand why. -In the event of a failure, the application will try to reinstall the kernel using the version previously installed. +In the event of a failure, the application will attempt to reinstall the kernel using the version previously installed. # Community based kernels @@ -64,10 +64,6 @@ By default, the application will use `bootctl` to distinguish which bootloader ( `grub-mkconfig` is run to update the grub.cfg file. -## systemd-boot - -`bootctl --no-variables ---graceful update` is run to update systemd-boot entries - # Advanced settings ## Bootloader settings @@ -118,12 +114,16 @@ community = [ { name = "linux-nitrous", description = "Modified Linux kernel optimized for Skylake and newer, compiled using clang", headers = "linux-nitrous-headers", repository = "chaotic-aur" }, ] +[logging] +# Logging is either info or debug +loglevel = "info" + # custom bootloader example #[bootloader] #name = "grub" #grub_config = "/boot/grub/grub.cfg" - ``` + ## Adding new community based kernels Further Kernels can be added using the same format. @@ -140,6 +140,11 @@ Using the Update switch inside Advanced Settings, will force the application to This cache file may take a little while to generate since archived Arch kernel package data is being retrieved from the ALA. +Once the cache file is in place, the application also queries the RESTful API using https://archlinux.org/packages/search/json to search for package updates. +It extracts the `last_update` and compares it against the cache timestamp. + +That way the application will include the latest kernel versions. + # Logs Logs can be found inside `/var/log/archlinux-kernel-manager` diff --git a/usr/share/archlinux-kernel-manager/akm.css b/usr/share/archlinux-kernel-manager/akm.css index 2f67a4b..6754ae9 100644 --- a/usr/share/archlinux-kernel-manager/akm.css +++ b/usr/share/archlinux-kernel-manager/akm.css @@ -75,6 +75,11 @@ label#label_active_kernel { font-size: 12px; } +label#label_flowbox_message{ + padding: 10px 10px 10px 10px; + font-size: medium; +} + label#label_stack_kernel { font-size: 20px; font-weight: 600; diff --git a/usr/share/archlinux-kernel-manager/defaults/config.toml b/usr/share/archlinux-kernel-manager/defaults/config.toml index 3ea002f..419c4cf 100644 --- a/usr/share/archlinux-kernel-manager/defaults/config.toml +++ b/usr/share/archlinux-kernel-manager/defaults/config.toml @@ -25,6 +25,10 @@ community = [ { name = "linux-nitrous", description = "Modified Linux kernel optimized for Skylake and newer, compiled using clang", headers = "linux-nitrous-headers", repository = "chaotic-aur" }, ] +[logging] +# Logging is either info or debug +loglevel = "info" + # Custom bootloader example # Only systemd-boot or grub are valid names # When using grub also set grub_config diff --git a/usr/share/archlinux-kernel-manager/libs/Kernel.py b/usr/share/archlinux-kernel-manager/libs/Kernel.py index 69a1bcd..c379dae 100644 --- a/usr/share/archlinux-kernel-manager/libs/Kernel.py +++ b/usr/share/archlinux-kernel-manager/libs/Kernel.py @@ -25,7 +25,7 @@ class Kernel: .date() ) - if datetime_value_other > datetime_value_self: + if datetime_value_other >= datetime_value_self: return datetime_value_other diff --git a/usr/share/archlinux-kernel-manager/libs/functions.py b/usr/share/archlinux-kernel-manager/libs/functions.py index b8a8e87..772ff86 100644 --- a/usr/share/archlinux-kernel-manager/libs/functions.py +++ b/usr/share/archlinux-kernel-manager/libs/functions.py @@ -47,7 +47,6 @@ supported_kernels_dict = {} community_kernels_dict = {} pacman_repos_list = [] process_timeout = 200 - sudo_username = os.getlogin() home = "/home/" + str(sudo_username) @@ -60,6 +59,9 @@ pacman_lockfile = "/var/lib/pacman/db.lck" # pacman conf file pacman_conf_file = "/etc/pacman.conf" +# pacman cach dir +pacman_cache = "/var/cache/pacman/pkg" + # thread names thread_get_kernels = "thread_get_kernels" thread_get_community_kernels = "thread_get_community_kernels" @@ -83,15 +85,12 @@ config_file_default = "%s/defaults/config.toml" % base_dir config_dir = "%s/.config/archlinux-kernel-manager" % home config_file = "%s/.config/archlinux-kernel-manager/config.toml" % home + logger = logging.getLogger("logger") # create console handler and set level to debug ch = logging.StreamHandler() - -logger.setLevel(logging.DEBUG) -ch.setLevel(logging.DEBUG) - # create formatter formatter = logging.Formatter( "%(asctime)s:%(levelname)s > %(message)s", "%Y-%m-%d %H:%M:%S" @@ -190,26 +189,26 @@ def get_latest_kernel_updates(self): response.json()["results"][0]["last_update"], "%Y-%m-%dT%H:%M:%S.%f%z", ).date() - ) > ( + ) >= ( datetime.datetime.strptime( cache_timestamp, "%Y-%m-%d %H-%M-%S" ).date() ): - logger.info( - "Linux kernel package updated, cache refresh required" - ) + logger.info("Linux kernel package updated") refresh_cache(self) return True else: - logger.info( - "Linux kernel package not updated, cache refresh not required" - ) + logger.info("Linux kernel package not updated") return False + else: + logger.error("Failed to get valid response to check kernel update") + logger.error(response.text) + return False else: logger.info("Kernel update check not required") @@ -327,24 +326,48 @@ def update_config(config_data, bootloader): def read_config(self): try: - logger.debug("Config file = %s" % config_file) - logger.info("Reading in config file") + logger.info("Reading in config file %s" % config_file) config_data = None with open(config_file, "rb") as f: config_data = tomlkit.load(f) - for official_kernel in config_data["kernels"]["official"]: - supported_kernels_dict[official_kernel["name"]] = ( - official_kernel["description"], - official_kernel["headers"], - ) + if ( + config_data.get("kernels") + and "official" in config_data["kernels"] is not None + ): + for official_kernel in config_data["kernels"]["official"]: + supported_kernels_dict[official_kernel["name"]] = ( + official_kernel["description"], + official_kernel["headers"], + ) - for community_kernel in config_data["kernels"]["community"]: - community_kernels_dict[community_kernel["name"]] = ( - community_kernel["description"], - community_kernel["headers"], - community_kernel["repository"], - ) + if ( + config_data.get("kernels") + and "community" in config_data["kernels"] is not None + ): + for community_kernel in config_data["kernels"]["community"]: + community_kernels_dict[community_kernel["name"]] = ( + community_kernel["description"], + community_kernel["headers"], + community_kernel["repository"], + ) + + if ( + config_data.get("logging") is not None + and "loglevel" in config_data["logging"] is not None + ): + + loglevel = config_data["logging"]["loglevel"].lower() + logger.info("Setting loglevel to %s" % loglevel) + if loglevel == "debug": + logger.setLevel(logging.DEBUG) + elif loglevel == "info": + logger.setLevel(logging.INFO) + else: + logger.warning("Invalid logging level set, use info / debug") + logger.setLevel(logging.INFO) + else: + logger.setLevel(logging.INFO) return config_data except Exception as e: @@ -406,6 +429,16 @@ def write_cache(): # install from the ALA def install_archive_kernel(self): try: + # package cache + logger.debug("Cleaning pacman cache, removing official packages") + if os.path.exists(pacman_cache): + for root, dirs, files in os.walk(pacman_cache): + for name in files: + for official_kernel in supported_kernels_dict.keys(): + if name.startswith(official_kernel): + if os.path.exists(os.path.join(root, name)): + os.remove(os.path.join(root, name)) + install_cmd_str = [ "pacman", "-U", @@ -424,14 +457,14 @@ def install_archive_kernel(self): " ".join(install_cmd_str), ) - event_log = [] + error = False + self.messages_queue.put(event) with subprocess.Popen( install_cmd_str, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - bufsize=1, universal_newlines=True, env=locale_env, ) as process: @@ -439,96 +472,62 @@ def install_archive_kernel(self): if process.poll() is not None: break for line in process.stdout: - print(line.strip()) + if logger.getEffectiveLevel() == 10: + print(line.strip()) self.messages_queue.put(line) - event_log.append(line.lower().strip()) - - time.sleep(0.3) - - error = None - - if ( - "installation finished. no error reported." - or "initcpio image generation successful" in event_log - ): - error = False - - 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 - + if "no space left on device" in line.lower().strip(): + self.restore_kernel = None error = True - - GLib.idle_add( - show_mw, - self, - "System changes", - f"Kernel {self.action} failed\n" - f"There have been errors, please review the logs\n", - "images/48x48/akm-warning.png", - priority=GLib.PRIORITY_DEFAULT, - ) - break + if "initcpio" in line.lower().strip(): + if "image generation successful" in line.lower().strip(): + error = False + break + if ( + "installation finished. no error reported" + in line.lower().strip() + ): + error = False + break + if ( + "error" in line.lower().strip() + or "errors" in line.lower().strip() + ): + error = True + break + + # time.sleep(0.1) + + if error is True: + + self.errors_found = True + + error = True + + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} failed\n" + f"There have been errors, please review the logs", + priority=GLib.PRIORITY_DEFAULT, + ) # query to check if kernel installed if check_kernel_installed(self.kernel.name + "-headers") and error is False: - - self.kernel_state_queue.put((0, "install", self.kernel.name + "-headers")) - - event = "%s [INFO]: Installation of %s-headers completed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) - - self.messages_queue.put(event) - + self.kernel_state_queue.put((0, "install")) else: - self.kernel_state_queue.put((1, "install", self.kernel.name + "-headers")) - - event = "%s [ERROR]: Installation of %s-headers failed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) + self.kernel_state_queue.put((1, "install")) self.errors_found = True self.messages_queue.put(event) if check_kernel_installed(self.kernel.name) and error is False: - self.kernel_state_queue.put((0, "install", self.kernel.name)) - - event = "%s [INFO]: Installation of kernel %s completed\n" % ( - datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - self.kernel.name, - ) - - self.messages_queue.put(event) - + self.kernel_state_queue.put((0, "install")) else: - self.kernel_state_queue.put((1, "install", self.kernel.name)) - - 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) + self.kernel_state_queue.put((1, "install")) + self.errors_found = True # signal to say end reached self.kernel_state_queue.put(None) @@ -536,15 +535,18 @@ def install_archive_kernel(self): except Exception as e: logger.error("Exception in install_archive_kernel(): %s" % e) - GLib.idle_add( - show_mw, - self, - "System changes", - f"Kernel {self.action} failed\n" - f"There have been errors, please review the logs\n", - "images/48x48/akm-warning.png", - priority=GLib.PRIORITY_DEFAULT, - ) + # GLib.idle_add( + # show_mw, + # self, + # "System changes", + # f"Kernel {self.action} failed\n" + # f"There have been errors, please review the logs\n", + # "images/48x48/akm-warning.png", + # priority=GLib.PRIORITY_DEFAULT, + # ) + finally: + if os.path.exists(self.lockfile): + os.unlink(self.lockfile) def refresh_cache(self): @@ -712,6 +714,7 @@ def parse_archive_html(response, linux_kernel): version is not None and url is not None and headers is not None + and file_format == ".pkg.tar.zst" and datetime.datetime.now().year - datetime.datetime.strptime( last_modified, "%d-%b-%Y %H:%M" @@ -911,10 +914,13 @@ def check_kernel_installed(name): if process_kernel_query.returncode == 0: for line in out.decode("utf-8").splitlines(): if line.split(" ")[0] == name: - # logger.debug("Kernel installed") + + logger.info("Kernel installed") + return True + else: - # logger.debug("Kernel is not installed") + logger.info("Kernel is not installed") return False return False @@ -923,12 +929,13 @@ def check_kernel_installed(name): def wait_for_pacman_process(): - + logger.info("Waiting for pacman process") timeout = 120 i = 0 while check_pacman_lockfile(): time.sleep(0.1) - logger.debug("Pacman lockfile found .. waiting") + if logger.getEffectiveLevel() == 10: + logger.debug("Pacman lockfile found .. waiting") i += 1 if i == timeout: logger.info("Timeout reached") @@ -949,6 +956,7 @@ def uninstall(self): uninstall_cmd_str = None event_log = [] + # self.errors_found = False if kernel_installed is True and kernel_headers_installed is True: uninstall_cmd_str = [ @@ -964,9 +972,11 @@ def uninstall(self): if kernel_installed == 0: logger.info("Kernel is not installed, uninstall not required") - self.kernel_state_queue.put((0, "uninstall", self.kernel.name)) + self.kernel_state_queue.put((0, "uninstall")) + return - logger.debug("Uninstall cmd = %s" % uninstall_cmd_str) + if logger.getEffectiveLevel() == 10: + logger.debug("Uninstall cmd = %s" % uninstall_cmd_str) # check if kernel, and kernel header is actually installed if uninstall_cmd_str is not None: @@ -985,34 +995,35 @@ def uninstall(self): uninstall_cmd_str, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - bufsize=1, universal_newlines=True, env=locale_env, + bufsize=1, ) as process: while True: if process.poll() is not None: break for line in process.stdout: + if logger.getEffectiveLevel() == 10: + print(line.strip()) + # print(line.strip()) self.messages_queue.put(line) - print(line.strip()) - event_log.append(line.lower().strip()) + # event_log.append(line.lower().strip()) + if ( + "error" in line.lower().strip() + or "errors" in line.lower().strip() + ): + self.errors_found = True + break # self.pacmanlog_queue.put(line) # process_stdout_lst.append(line) - time.sleep(0.3) - - self.errors_found = False - for log in event_log: - if "error" in log: - self.errors_found = True + # time.sleep(0.1) # query to check if kernel installed if "headers" in uninstall_cmd_str: if check_kernel_installed(self.kernel.name + "-headers") is True: - self.kernel_state_queue.put( - (1, "uninstall", self.kernel.name + "-headers") - ) + self.kernel_state_queue.put((1, "uninstall")) event = ( "%s [ERROR]: Uninstall failed\n" @@ -1022,7 +1033,7 @@ def uninstall(self): self.messages_queue.put(event) else: - self.kernel_state_queue.put((0, "uninstall", self.kernel.name)) + self.kernel_state_queue.put((0, "uninstall")) event = ( "%s [INFO]: Uninstall completed\n" @@ -1033,7 +1044,7 @@ def uninstall(self): else: if check_kernel_installed(self.kernel.name) is True: - self.kernel_state_queue.put((1, "uninstall", self.kernel.name)) + self.kernel_state_queue.put((1, "uninstall")) event = ( "%s [ERROR]: Uninstall failed\n" @@ -1043,7 +1054,7 @@ def uninstall(self): self.messages_queue.put(event) else: - self.kernel_state_queue.put((0, "uninstall", self.kernel.name)) + self.kernel_state_queue.put((0, "uninstall")) event = ( "%s [INFO]: Uninstall completed\n" @@ -1098,11 +1109,31 @@ def get_community_kernels(self): version = line.split("Version :")[1].strip() if line.startswith("Installed Size :"): install_size = line.split("Installed Size :")[1].strip() - if "MiB" in install_size: - install_size = round( - float(install_size.replace("MiB", "").strip()) - * 1.048576, + if logger.getEffectiveLevel() == 10: + logger.debug( + "%s installed kernel size = %s" + % (name, install_size) ) + if "MiB" in install_size: + if install_size.find(",") >= 0: + if logger.getEffectiveLevel() == 10: + logger.debug("Comma found inside install size") + install_size = round( + float( + install_size.replace(",", ".") + .strip() + .replace("MiB", "") + .strip() + ) + * 1.048576, + 1, + ) + else: + install_size = round( + float(install_size.replace("MiB", "").strip()) + * 1.048576, + 1, + ) if line.startswith("Build Date :"): build_date = line.split("Build Date :")[1].strip() @@ -1130,6 +1161,16 @@ def get_community_kernels(self): # ===================================================== def install_community_kernel(self): try: + if logger.getEffectiveLevel() == 10: + logger.debug("Cleaning pacman cache, removing community packages") + if os.path.exists(pacman_cache): + for root, dirs, files in os.walk(pacman_cache): + for name in files: + for comm_kernel in community_kernels_dict.keys(): + if name.startswith(comm_kernel): + if os.path.exists(os.path.join(root, name)): + os.remove(os.path.join(root, name)) + error = False install_cmd_str = [ "pacman", @@ -1147,7 +1188,7 @@ def install_community_kernel(self): " ".join(install_cmd_str), ) - event_log = [] + error = False self.messages_queue.put(event) @@ -1155,7 +1196,6 @@ def install_community_kernel(self): install_cmd_str, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - bufsize=1, universal_newlines=True, env=locale_env, ) as process: @@ -1163,22 +1203,49 @@ def install_community_kernel(self): if process.poll() is not None: break for line in process.stdout: - print(line.strip()) + if logger.getEffectiveLevel() == 10: + print(line.strip()) + self.messages_queue.put(line) - event_log.append(line.lower().strip()) - time.sleep(0.3) + if "no space left on device" in line.lower().strip(): + error = True + break + if "initcpio" in line.lower().strip(): + if "image generation successful" in line.lower().strip(): + error = False + break + if ( + "installation finished. no error reported" + in line.lower().strip() + ): + error = False + break + if ( + "error" in line.lower().strip() + or "errors" in line.lower().strip() + ): + error = True + break + time.sleep(0.1) - for log in event_log: - if "installation finished. no error reported." in log: - error = False - break + if error is True: - if "error" in log: - error = True + self.errors_found = True + + error = True + + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} failed\n" + f"There have been errors, please review the logs\n", + priority=GLib.PRIORITY_DEFAULT, + ) if check_kernel_installed(self.kernel.name) and error is False: - self.kernel_state_queue.put((0, "install", self.kernel.name)) + self.kernel_state_queue.put((0, "install")) event = "%s [INFO]: Installation of %s completed\n" % ( datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), @@ -1188,7 +1255,7 @@ def install_community_kernel(self): self.messages_queue.put(event) else: - self.kernel_state_queue.put((1, "install", self.kernel.name)) + self.kernel_state_queue.put((1, "install")) event = "%s [ERROR]: Installation of %s failed\n" % ( datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), @@ -1202,6 +1269,9 @@ def install_community_kernel(self): self.kernel_state_queue.put(None) except Exception as e: logger.error("Exception in install_community_kernel(): %s " % e) + finally: + if os.path.exists(self.lockfile): + os.unlink(self.lockfile) # ===================================================== @@ -1246,10 +1316,10 @@ def get_pacman_repos(): def get_installed_kernel_info(package_name): + logger.info("Installed kernel info - %s" % package_name) query_str = ["pacman", "-Qi", package_name] try: - process_kernel_query = subprocess.Popen( query_str, shell=False, @@ -1264,13 +1334,35 @@ def get_installed_kernel_info(package_name): for line in out.decode("utf-8").splitlines(): if line.startswith("Installed Size :"): install_size = line.split("Installed Size :")[1].strip() - if "MiB" in install_size: - install_size = round( - float(install_size.replace("MiB", "").strip()) * 1.048576, + if logger.getEffectiveLevel() == 10: + logger.debug( + "%s installed kernel size = %s" + % (package_name, install_size) ) + if "MiB" in install_size: + if install_size.find(",") >= 0: + logger.debug("Comma found inside install size") + install_size = round( + float( + install_size.replace(",", ".") + .strip() + .replace("MiB", "") + .strip() + ) + * 1.048576, + 1, + ) + else: + install_size = round( + float(install_size.replace("MiB", "").strip()) + * 1.048576, + 1, + ) if line.startswith("Install Date :"): install_date = line.split("Install Date :")[1].strip() return install_size, install_date + else: + logger.error("Failed to get installed kernel info") except Exception as e: logger.error("Exception in get_installed_kernel_info(): %s" % e) @@ -1281,6 +1373,7 @@ def get_installed_kernel_info(package_name): def get_installed_kernels(): + logger.info("Get installed kernels") query_str = ["pacman", "-Q"] installed_kernels = [] @@ -1305,6 +1398,10 @@ def get_installed_kernels(): package_name in supported_kernels_dict or package_name in community_kernels_dict ): + if logger.getEffectiveLevel() == 10: + logger.debug( + "Installed linux package = %s" % package_name + ) install_size, install_date = get_installed_kernel_info( package_name ) @@ -1329,11 +1426,12 @@ def get_installed_kernels(): def get_active_kernel(): logger.info("Getting active Linux kernel") - query_str = ["uname", "-rs"] + # cmd = ["uname", "-rs"] + cmd = ["kernel-install"] try: process_kernel_query = subprocess.Popen( - query_str, + cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -1345,13 +1443,15 @@ def get_active_kernel(): if process_kernel_query.returncode == 0: for line in out.decode("utf-8").splitlines(): if len(line.strip()) > 0: - kernel = line.strip() - _version = "-".join(kernel.split("-")[:-1]) - _type = kernel.split("-")[-1] + if "Kernel Version:" in line: + logger.info( + "Active kernel = %s" + % line.split("Kernel Version:")[1].strip() + ) + return line.split("Kernel Version:")[1].strip() + else: + return "unknown" - logger.info("Active kernel = %s" % kernel) - - return kernel except Exception as e: logger.error("Exception in get_active_kernel(): %s" % e) @@ -1363,23 +1463,26 @@ def sync_package_db(): try: sync_str = ["pacman", "-Sy"] logger.info("Synchronizing pacman package databases") - process_sync = subprocess.run( - sync_str, + + cmd = ["pacman", "-Sy"] + + if logger.getEffectiveLevel() == 10: + logger.debug("Running cmd = %s" % cmd) + + process = subprocess.Popen( + cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - timeout=process_timeout, env=locale_env, ) - if process_sync.returncode == 0: + out, err = process.communicate(timeout=600) + + if process.returncode == 0: return None else: - if process_sync.stdout: - out = str(process_sync.stdout.decode("utf-8")) - logger.error(out) - - return out + return out.decode("utf-8") except Exception as e: logger.error("Exception in sync_package_db(): %s" % e) @@ -1434,8 +1537,16 @@ def get_boot_loader(): # ====================================================================== -def get_kernel_version(kernel): - cmd = ["pacman", "-Qli", kernel] +def get_kernel_modules_version(kernel, db): + cmd = None + if db == "local": + if logger.getEffectiveLevel() == 10: + logger.debug("Getting kernel module version from local pacman repo") + cmd = ["pacman", "-Qli", kernel] + if db == "package": + if logger.getEffectiveLevel() == 10: + logger.debug("Getting kernel module version from package cache file") + cmd = ["pacman", "-Qlip", kernel] # pacman_kernel_version = None kernel_modules_path = None try: @@ -1447,28 +1558,25 @@ def get_kernel_version(kernel): stderr=subprocess.STDOUT, timeout=process_timeout, universal_newlines=True, - bufsize=1, env=locale_env, ) if process.returncode == 0: for line in process.stdout.splitlines(): - # if line.startswith("Version :"): - # pacman_kernel_version = line.split("Version :")[1].strip() - # print(pacman_kernel_version) - - if "/usr/lib/modules/" in line: + 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] + kernel_modules_path.split("usr/lib/modules/")[1] .strip() .split("/kernel/")[0] .strip() ) + else: + return None else: return None @@ -1489,7 +1597,6 @@ def run_process(self): self.cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - bufsize=1, universal_newlines=True, env=locale_env, ) as process: @@ -1499,7 +1606,8 @@ def run_process(self): for line in process.stdout: self.messages_queue.put(line) self.stdout_lines.append(line.lower().strip()) - print(line.strip()) + if logger.getEffectiveLevel() == 10: + print(line.strip()) for log in self.stdout_lines: if "error" in log or "errors" in log or "failed" in log: @@ -1507,19 +1615,134 @@ def run_process(self): 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() + return True + else: logger.info("%s completed" % " ".join(self.cmd)) + return False + # time.sleep(0.3) +# ====================================================================== +# KERNEL INITRD IMAGES TO AND FROM /BOOT +# ====================================================================== + + +def kernel_initrd(self): + logger.info("Adding and removing kernel and initird images") + pkg_modules_version = None + + if self.action == "install": + if self.source == "official": + + pkg_modules_version = get_kernel_modules_version( + "%s/%s" + % ( + pacman_cache, + "%s-x86_64%s" % (self.kernel.version, self.kernel.file_format), + ), + "package", + ) + + if self.source == "community": + pkg_modules_version = get_kernel_modules_version( + "%s/%s" + % ( + pacman_cache, + "%s-%s-x86_64.pkg.tar.zst" + % (self.kernel.name, self.kernel.version), + ), + "package", + ) + + if pkg_modules_version is None: + logger.error("Failed to extract modules version from package") + return 1 + + logger.debug("Package modules version = %s" % pkg_modules_version) + + # cmd = ["pacman", "-Qlp", "%s/" % pacman_cache] + + if self.action == "install": + logger.info("Adding kernel and initrd images to /boot") + self.image = "images/48x48/akm-install.png" + + if self.local_modules_version is not None: + for self.cmd in [ + [ + "kernel-install", + "remove", + self.local_modules_version, + ], + [ + "kernel-install", + "add", + pkg_modules_version, + "/lib/modules/%s/vmlinuz" % pkg_modules_version, + ], + ]: + err = run_process(self) + if err is True: + return 1 + + else: + self.cmd = [ + "kernel-install", + "add", + pkg_modules_version, + "/lib/modules/%s/vmlinuz" % pkg_modules_version, + ] + err = run_process(self) + if err is True: + return 1 + + else: + logger.info("Removing kernel and initrd images from /boot") + self.image = "images/48x48/akm-remove.png" + if self.local_modules_version is not None: + self.cmd = [ + "kernel-install", + "remove", + self.local_modules_version, + ] + err = run_process(self) + if err is True: + return 1 + + +# ====================================================================== +# CHECK PACMAN REPO +# ====================================================================== +def check_pacman_repo(repo): + logger.info("Checking %s pacman repository is configured" % repo) + cmd = ["pacman-conf", "-r", repo] + + try: + with subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True, + env=locale_env, + ) as process: + while True: + if process.poll() is not None: + break + # for line in process.stdout: + # if logger.getEffectiveLevel() == 10: + # print(line.strip()) + + if process.returncode == 0: + return True + else: + return False + except Exception as e: + logger.error("Exception in check_pacman_repo(): %s" % e) + + # ====================================================================== # UPDATE BOOTLOADER ENTRIES # ====================================================================== @@ -1531,65 +1754,20 @@ def update_bootloader(self): logger.info("Updating bootloader") cmds = [] error = False - self.stdout_lines = [] - - if self.action == "install": - image = "images/48x48/akm-install.png" - if self.installed_kernel_version is not None: - for self.cmd in [ - # ["kernel-install", "add-all", "--verbose"], - [ - "kernel-install", - "add", - self.installed_kernel_version, - "/lib/modules/%s/vmlinuz" % self.installed_kernel_version, - ], - [ - "kernel-install", - "remove", - self.installed_kernel_version, - ], - ]: - run_process(self) - - else: - # self.cmd = ["kernel-install", "add-all", "--verbose"]. - self.installed_kernel_version = get_kernel_version(self.kernel.name) - self.cmd = [ - "kernel-install", - "add", - self.installed_kernel_version, - "/lib/modules/%s/vmlinuz" % self.installed_kernel_version, - ] - run_process(self) - - else: - image = "images/48x48/akm-remove.png" - if self.installed_kernel_version is not None: - self.cmd = [ - "kernel-install", - "remove", - self.installed_kernel_version, - ] - run_process(self) + stdout_lines = [] try: - - """ - kernel-install -add-all - kernel-install remove $kernel_version - this is for systems which do not have any pacman hooks in place - useful for vanilla arch installs - """ - - self.label_notify_revealer.set_text("Updating bootloader %s" % self.bootloader) - self.reveal_notify() - logger.info("Current bootloader = %s" % self.bootloader) cmd = None if self.bootloader == "grub": + + self.label_notify_revealer.set_text( + "Updating bootloader %s" % self.bootloader + ) + self.reveal_notify() + if self.bootloader_grub_cfg is not None: cmd = ["grub-mkconfig", "-o", self.bootloader_grub_cfg] else: @@ -1604,12 +1782,48 @@ def update_bootloader(self): 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), + # 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.label_notify_revealer.set_text( + "%s skipping bootloader update" % self.bootloader ) + self.reveal_notify() + + event = ( + "%s [INFO]: systemd-boot skipping bootloader update\n" + % datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + ) + + logger.info("systemd-boot skipping bootloader update") + self.messages_queue.put(event) + + if ( + self.restore is not None + and self.restore is False + and self.errors_found is False + ): + GLib.idle_add( + show_mw, + self, + "System changes", + f"Kernel {self.action} completed\n" + f"This window can now be closed", + priority=GLib.PRIORITY_DEFAULT, + ) + # elif self.errors_found is True: + # GLib.idle_add( + # show_mw, + # self, + # "System changes", + # f"There have been errors, please review the logs\n", + # self.image, + # priority=GLib.PRIORITY_DEFAULT, + # ) else: logger.error("Bootloader is empty / not supported") @@ -1620,7 +1834,6 @@ def update_bootloader(self): cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - bufsize=1, universal_newlines=True, env=locale_env, ) as process: @@ -1630,7 +1843,9 @@ def update_bootloader(self): for line in process.stdout: self.stdout_lines.append(line.strip()) self.messages_queue.put(line) - print(line.strip()) + if logger.getEffectiveLevel() == 10: + print(line.strip()) + # print(line.strip()) # time.sleep(0.3) @@ -1648,20 +1863,13 @@ def update_bootloader(self): ) 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: + if self.restore is False and self.errors_found 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, + f"This window can now be closed", priority=GLib.PRIORITY_DEFAULT, ) else: @@ -1677,14 +1885,14 @@ def update_bootloader(self): ) self.messages_queue.put(event) - if self.restore is False: + if self.restore is False and self.errors_found 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, + f"This window can now be closed", + self.image, priority=GLib.PRIORITY_DEFAULT, ) @@ -1708,29 +1916,13 @@ def update_bootloader(self): self, "System changes", f"Kernel {self.action} failed .. attempting kernel restore\n" - f"There have been errors, please review the logs\n", - image, + f"There have been errors, please review the logs", 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, - ) - if os.path.exists(self.lockfile): - os.unlink(self.lockfile) - # else: - # logger.error("Bootloader update cannot continue, failed to set command.") except Exception as e: logger.error("Exception in update_bootloader(): %s" % e) + finally: if os.path.exists(self.lockfile): os.unlink(self.lockfile) @@ -1738,11 +1930,10 @@ def update_bootloader(self): # ====================================================================== # SHOW MESSAGE WINDOW AFTER BOOTLOADER UPDATE # ====================================================================== -def show_mw(self, title, msg, image): +def show_mw(self, title, msg): mw = MessageWindow( title=title, message=msg, - image_path=image, detailed_message=False, transient_for=self, ) diff --git a/usr/share/archlinux-kernel-manager/ui/FlowBox.py b/usr/share/archlinux-kernel-manager/ui/FlowBox.py index 142cd5b..716d914 100644 --- a/usr/share/archlinux-kernel-manager/ui/FlowBox.py +++ b/usr/share/archlinux-kernel-manager/ui/FlowBox.py @@ -273,6 +273,8 @@ class FlowBox(Gtk.FlowBox): ) message = None title = None + downgrade = False + community_repo = False if fn.check_pacman_lockfile() is False: # switch widget is currently toggled off @@ -284,38 +286,65 @@ class FlowBox(Gtk.FlowBox): inst_kernel.version > kernel.version.split("%s-" % inst_kernel.name)[1] ): + downgrade = True title = "Downgrading %s kernel" % kernel.name else: + downgrade = False title = "Upgrading %s kernel" % kernel.name break if title is None: - title = "Kernel install" + title = "Kernel installation" if self.source == "community": - message = "This will install %s-%s - Is this ok ?" % ( + message = ( + "Community kernel selected - this may break your system\n" + "Confirm the install of %s-%s" + % ( + kernel.name, + kernel.version, + ) + ) + + # check if the community pacman repo is configured + if fn.check_pacman_repo(kernel.repository) is True: + community_repo = True + else: + community_repo = False + fn.logger.error( + "%s pacman repo is not configured" % kernel.repository + ) + + elif self.source == "official": + message = "Confirm the install of %s-%s" % ( kernel.name, kernel.version, ) - elif self.source == "official": - message = ( - "This will install %s - Is this ok ?" % kernel.version - ) - message_window = FlowBoxMessageWindow( - title=title, - message=message, - action="install", - kernel=kernel, - transient_for=self.manager_gui, - textview=self.manager_gui.textview, - textbuffer=self.manager_gui.textbuffer, - switch=switch, - source=self.source, - manager_gui=self.manager_gui, - ) - message_window.present() + if community_repo is False and self.source == "community": + mw = MessageWindow( + title="Cannot find %s pacman repo" % kernel.repository, + message="Enable the pacman repository then retry the installation", + transient_for=self.manager_gui, + detailed_message=False, + ) + mw.present() + else: + message_window = FlowBoxMessageWindow( + title=title, + message=message, + action="install", + kernel=kernel, + transient_for=self.manager_gui, + textview=self.manager_gui.textview, + textbuffer=self.manager_gui.textbuffer, + switch=switch, + source=self.source, + manager_gui=self.manager_gui, + downgrade=downgrade, + ) + message_window.present() return True # switch widget is currently toggled on @@ -327,17 +356,18 @@ class FlowBox(Gtk.FlowBox): if len(installed_kernels) > 1: if self.source == "community": - message = "This will remove %s-%s - Is this ok ?" % ( + message = "Confirm the removal of %s-%s" % ( kernel.name, kernel.version, ) elif self.source == "official": - message = ( - "This will remove %s - Is this ok ?" % kernel.version + message = "Confirm the removal of %s-%s" % ( + kernel.name, + kernel.version, ) message_window = FlowBoxMessageWindow( - title="Kernel uninstall", + title="Kernel uninstallation", message=message, action="uninstall", kernel=kernel, @@ -347,6 +377,7 @@ class FlowBox(Gtk.FlowBox): switch=switch, source=self.source, manager_gui=self.manager_gui, + downgrade=downgrade, ) message_window.present() return True @@ -361,7 +392,6 @@ class FlowBox(Gtk.FlowBox): title="Warning: Uninstall aborted", message=f"You only have 1 kernel installed\n" f"{kernel.name} {kernel.version} is currently active\n", - image_path="images/48x48/akm-remove.png", transient_for=self.manager_gui, detailed_message=False, ) @@ -378,7 +408,6 @@ class FlowBox(Gtk.FlowBox): message="Pacman lockfile found, which indicates another pacman process is running", transient_for=self.manager_gui, detailed_message=False, - image_path="images/48x48/akm-warning.png", ) msg_win.present() return True @@ -496,6 +525,7 @@ class FlowBoxInstalled(Gtk.FlowBox): switch=None, source=None, manager_gui=self.manager_gui, + downgrade=None, ) message_window.present() else: @@ -507,7 +537,6 @@ class FlowBoxInstalled(Gtk.FlowBox): title="Warning: Uninstall aborted", message=f"You only have 1 kernel installed\n" f"{installed_kernel.name} {installed_kernel.version}\n", - image_path="images/48x48/akm-remove.png", transient_for=self.manager_gui, detailed_message=False, ) @@ -526,6 +555,7 @@ class FlowBoxMessageWindow(Gtk.Window): switch, source, manager_gui, + downgrade, **kwargs, ): super().__init__(**kwargs) @@ -552,6 +582,7 @@ class FlowBoxMessageWindow(Gtk.Window): self.action = action self.switch = switch self.source = source + self.downgrade = downgrade vbox_flowbox_message = Gtk.Box.new( orientation=Gtk.Orientation.VERTICAL, spacing=10 diff --git a/usr/share/archlinux-kernel-manager/ui/KernelStack.py b/usr/share/archlinux-kernel-manager/ui/KernelStack.py index 765792a..2b4d385 100644 --- a/usr/share/archlinux-kernel-manager/ui/KernelStack.py +++ b/usr/share/archlinux-kernel-manager/ui/KernelStack.py @@ -465,7 +465,10 @@ class KernelStack: label_warning = Gtk.Label(xalign=0, yalign=0) label_warning.set_name("label_community_warning") - if len(self.manager_gui.community_kernels) == 0: + if ( + self.manager_gui.community_kernels is not None + and len(self.manager_gui.community_kernels) == 0 + ): label_warning.set_markup( f"Cannot find any supported unofficial pacman repository's\n" f"Add the Chaotic-AUR pacman repository to access Community based kernels" @@ -529,7 +532,10 @@ class KernelStack: # vbox_search_entry.append(search_entry_community) # widget.append(vbox_search_entry) - if len(self.manager_gui.community_kernels) > 0: + if ( + self.manager_gui.community_kernels is not None + and len(self.manager_gui.community_kernels) > 0 + ): self.flowbox_community = FlowBox( self.manager_gui.community_kernels, self.manager_gui.active_kernel, diff --git a/usr/share/archlinux-kernel-manager/ui/ManagerGUI.py b/usr/share/archlinux-kernel-manager/ui/ManagerGUI.py index 4a2857e..d42e8aa 100644 --- a/usr/share/archlinux-kernel-manager/ui/ManagerGUI.py +++ b/usr/share/archlinux-kernel-manager/ui/ManagerGUI.py @@ -28,9 +28,6 @@ class ManagerGUI(Gtk.ApplicationWindow): if self.app_version == "${app_version}": self.app_version = "dev" - fn.logger.info("Version = %s" % self.app_version) - fn.logger.info("Distro = %s" % fn.distro.id()) - self.set_title(app_name) self.set_resizable(True) self.set_default_size(950, 650) @@ -50,10 +47,6 @@ class ManagerGUI(Gtk.ApplicationWindow): self.splash_screen = SplashScreen(app_name) - while self.default_context.pending(): - fn.time.sleep(0.1) - self.default_context.iteration(True) - try: fn.Thread( target=self.wait_for_gui_load, @@ -62,6 +55,10 @@ class ManagerGUI(Gtk.ApplicationWindow): except Exception as e: fn.logger.error(e) + while self.default_context.pending(): + fn.time.sleep(0.1) + self.default_context.iteration(True) + hbox_notify_revealer = Gtk.Box( orientation=Gtk.Orientation.HORIZONTAL, spacing=20 ) @@ -88,6 +85,9 @@ class ManagerGUI(Gtk.ApplicationWindow): config_data = fn.setup_config(self) + fn.logger.info("Version = %s" % self.app_version) + fn.logger.info("Distro = %s" % fn.distro.id()) + if "bootloader" in config_data.keys(): if config_data["bootloader"]["name"] is not None: self.bootloader = config_data["bootloader"]["name"].lower() @@ -185,11 +185,11 @@ class ManagerGUI(Gtk.ApplicationWindow): self.vbox.append(self.notify_revealer) self.installed_kernels = fn.get_installed_kernels() + if self.installed_kernels is not None: + fn.logger.info("Installed kernels = %s" % len(self.installed_kernels)) self.active_kernel = fn.get_active_kernel() - fn.logger.info("Installed kernels = %s" % len(self.installed_kernels)) - self.refresh_cache = False self.refresh_cache = fn.get_latest_kernel_updates(self) @@ -207,7 +207,6 @@ class ManagerGUI(Gtk.ApplicationWindow): message=f"The specified Grub config file: {self.bootloader_grub_cfg} does not exist\n" f"This will cause an issue when updating the bootloader\n" f"Update the configuration file/use the Advanced Settings to change this\n", - image_path="images/48x48/akm-error.png", detailed_message=False, transient_for=self, ) @@ -222,7 +221,6 @@ class ManagerGUI(Gtk.ApplicationWindow): message=f"Cannot select systemd-boot, UEFI boot mode is not available\n" f"Update the configuration file\n" f"Or use the Advanced Settings to change this\n", - image_path="images/48x48/akm-warning.png", detailed_message=False, transient_for=self, ) @@ -289,28 +287,26 @@ class ManagerGUI(Gtk.ApplicationWindow): sync_err = fn.sync_package_db() if sync_err is not None: - fn.logger.error("Pacman db synchronization failed") - - print( - "---------------------------------------------------------------------------" - ) + # fn.logger.error("Pacman db synchronization failed") GLib.idle_add( - self.show_sync_db_message_dialog, + self.show_sync_window, sync_err, priority=GLib.PRIORITY_DEFAULT, ) + return False + else: fn.logger.info("Pacman DB synchronization completed") + return True - def show_sync_db_message_dialog(self, sync_err): + def show_sync_window(self, sync_err): mw = MessageWindow( title="Error - Pacman db synchronization", message=f"Pacman db synchronization failed\n" f"Failed to run 'pacman -Syu'\n" f"{sync_err}\n", - image_path="images/48x48/akm-warning.png", transient_for=self, detailed_message=True, ) @@ -367,25 +363,27 @@ class ManagerGUI(Gtk.ApplicationWindow): self.start_get_kernels_threads() - self.pacman_db_sync() + if self.pacman_db_sync() is False: + fn.logger.error("Pacman DB synchronization failed") + else: - fn.logger.debug("Adding community kernels to UI") + fn.logger.debug("Adding community kernels to UI") - try: - thread_get_community_kernels = fn.Thread( - name=fn.thread_get_community_kernels, - target=fn.get_community_kernels, - daemon=True, - args=(self,), - ) + try: + thread_get_community_kernels = fn.Thread( + name=fn.thread_get_community_kernels, + target=fn.get_community_kernels, + daemon=True, + args=(self,), + ) - thread_get_community_kernels.start() + thread_get_community_kernels.start() - except Exception as e: - fn.logger.error("Exception in thread_get_community_kernels: %s" % e) - finally: - self.community_kernels = self.queue_community_kernels.get() - self.queue_community_kernels.task_done() + except Exception as e: + fn.logger.error("Exception in thread_get_community_kernels: %s" % e) + finally: + self.community_kernels = self.queue_community_kernels.get() + self.queue_community_kernels.task_done() self.installed_kernels = fn.get_installed_kernels() @@ -507,36 +505,39 @@ class ManagerGUI(Gtk.ApplicationWindow): # fn.logger.debug("Adding community kernels to UI") # self.kernel_stack.add_community_kernels_to_stack(reload=False) - self.queue_load_progress.put(1) - fn.logger.info("Starting pacman db synchronization") - self.pacman_db_sync() + if self.pacman_db_sync() is False: + fn.logger.error("Pacman DB synchronization failed") + else: - fn.logger.debug("Adding community kernels to UI") - - try: - thread_get_community_kernels = fn.Thread( - name=fn.thread_get_community_kernels, - target=fn.get_community_kernels, - daemon=True, - args=(self,), - ) - - thread_get_community_kernels.start() - - except Exception as e: - fn.logger.error("Exception in thread_get_community_kernels: %s" % e) - finally: - self.community_kernels = self.queue_community_kernels.get() - self.queue_community_kernels.task_done() fn.logger.debug("Adding community kernels to UI") - self.kernel_stack.add_community_kernels_to_stack(reload=False) + + try: + thread_get_community_kernels = fn.Thread( + name=fn.thread_get_community_kernels, + target=fn.get_community_kernels, + daemon=True, + args=(self,), + ) + + thread_get_community_kernels.start() + + except Exception as e: + fn.logger.error("Exception in thread_get_community_kernels: %s" % e) + finally: + self.community_kernels = self.queue_community_kernels.get() + self.queue_community_kernels.task_done() + + self.kernel_stack.add_community_kernels_to_stack(reload=False) + + while self.default_context.pending(): + + self.default_context.iteration(True) + + fn.time.sleep(0.3) + + self.queue_load_progress.put(1) fn.logger.debug("Adding installed kernels to UI") self.kernel_stack.add_installed_kernels_to_stack(reload=False) - - while self.default_context.pending(): - self.default_context.iteration(True) - - fn.time.sleep(0.1) diff --git a/usr/share/archlinux-kernel-manager/ui/MessageWindow.py b/usr/share/archlinux-kernel-manager/ui/MessageWindow.py index f1c37da..9e3ea1d 100644 --- a/usr/share/archlinux-kernel-manager/ui/MessageWindow.py +++ b/usr/share/archlinux-kernel-manager/ui/MessageWindow.py @@ -9,10 +9,10 @@ base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) class MessageWindow(Gtk.Window): - def __init__(self, title, message, image_path, detailed_message, **kwargs): + def __init__(self, title, message, detailed_message, **kwargs): super().__init__(**kwargs) - # self.set_title(title=title) + self.set_title(title=title) self.set_modal(modal=True) self.set_resizable(False) icon_name = "akm-tux" @@ -34,14 +34,7 @@ class MessageWindow(Gtk.Window): vbox_message = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=10) vbox_message.set_name("vbox_flowbox_message") - image = Gtk.Picture.new_for_filename(os.path.join(base_dir, image_path)) - - image.set_content_fit(content_fit=Gtk.ContentFit.SCALE_DOWN) - image.set_halign(Gtk.Align.START) - - hbox_image = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - - # hbox_image.append(image) + hbox_message = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) self.set_child(child=vbox_message) @@ -65,26 +58,25 @@ class MessageWindow(Gtk.Window): scrolled_window.set_child(textview) - hbox_image.append(scrolled_window) + hbox_message.append(scrolled_window) self.set_size_request(700, 500) self.set_resizable(True) else: - label_message = Gtk.Label(xalign=0, yalign=0) + label_message = Gtk.Label(xalign=0.5, yalign=0.5) label_message.set_markup("%s" % message) label_message.set_name("label_flowbox_message") - hbox_image.append(image) - hbox_image.append(label_message) + hbox_message.append(label_message) - vbox_message.append(hbox_image) + vbox_message.append(hbox_message) button_ok = Gtk.Button.new_with_label("OK") button_ok.set_size_request(100, 30) 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=20) + hbox_buttons = Gtk.Box.new(orientation=Gtk.Orientation.HORIZONTAL, spacing=50) 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 188a820..0fa11e7 100644 --- a/usr/share/archlinux-kernel-manager/ui/ProgressWindow.py +++ b/usr/share/archlinux-kernel-manager/ui/ProgressWindow.py @@ -1,4 +1,5 @@ import random +import shutil import sys import gi import os @@ -27,7 +28,7 @@ class ProgressWindow(Gtk.Window): self.set_title(title=title) self.set_modal(modal=True) self.set_resizable(True) - self.set_size_request(700, 300) + self.set_size_request(700, 250) self.connect("close-request", self.on_close) self.textview = textview @@ -88,6 +89,8 @@ class ProgressWindow(Gtk.Window): image_settings = None + self.local_modules_version = None + if action == "install": image_settings = Gtk.Image.new_from_file( os.path.join(base_dir, "images/48x48/akm-install.png") @@ -105,16 +108,6 @@ 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) - - 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) @@ -237,6 +230,7 @@ class ProgressWindow(Gtk.Window): self.present() self.linux_headers = None + self.restore_kernel = None if ( self.source == "official" @@ -244,6 +238,7 @@ class ProgressWindow(Gtk.Window): or action == "uninstall" and self.source == "official" ): + fn.logger.info("Official kernel selected") if kernel.name == "linux": self.linux_headers = "linux-headers" if kernel.name == "linux-rt": @@ -273,19 +268,17 @@ class ProgressWindow(Gtk.Window): kernel.file_format, ), ] - - # in the event an install goes wrong, fallback and reinstall previous kernel - - if self.source == "official": - self.restore_kernel = None + # in the event an install goes wrong, fallback and reinstall previous kernel for inst_kernel in fn.get_installed_kernels(): if inst_kernel.name == self.kernel.name: - self.restore_kernel = inst_kernel break if self.restore_kernel: + self.local_modules_version = fn.get_kernel_modules_version( + self.restore_kernel.name, "local" + ) fn.logger.info("Restore kernel = %s" % self.restore_kernel.name) fn.logger.info( "Restore kernel version = %s" % self.restore_kernel.version @@ -294,6 +287,9 @@ class ProgressWindow(Gtk.Window): fn.logger.info("No previous %s kernel installed" % self.kernel.name) else: fn.logger.info("Community kernel, no kernel restore available") + self.local_modules_version = fn.get_kernel_modules_version( + self.kernel.name, "local" + ) if fn.check_pacman_lockfile() is False: th_monitor_messages_queue = fn.threading.Thread( @@ -416,7 +412,6 @@ class ProgressWindow(Gtk.Window): mw = MessageWindow( title="Pacman process running", message="Pacman is busy processing a transaction .. please wait", - image_path="images/48x48/akm-progress.png", transient_for=self, detailed_message=False, ) @@ -430,7 +425,6 @@ class ProgressWindow(Gtk.Window): mw = MessageWindow( title="Pacman process running", message="Pacman is busy processing a transaction .. please wait", - image_path="images/48x48/akm-progress.png", transient_for=self, detailed_message=False, ) @@ -442,15 +436,32 @@ class ProgressWindow(Gtk.Window): def check_kernel_state(self): returncode = None - kernel = None + action = None while True: items = self.kernel_state_queue.get() - try: - if items is not None: - returncode, action, kernel = items + if items is not None: + returncode, action = items + + try: + if returncode == 0: + self.errors_found = False + + fn.logger.info("Kernel %s completed" % action) + + self.label_status.set_markup( + "Kernel %s completed" + % self.action + ) + self.label_title.set_markup("Kernel %s completed" % action) + + if fn.kernel_initrd(self) == 1: + self.errors_found = True + self.kernel_fail(action) + else: + + fn.update_bootloader(self) - if returncode == 0: self.label_notify_revealer.set_text( "Kernel %s completed" % action ) @@ -458,170 +469,163 @@ class ProgressWindow(Gtk.Window): fn.logger.info("Kernel %s completed" % action) - if returncode == 1: - self.errors_found = True - - self.label_notify_revealer.set_text("Kernel %s failed" % action) - self.reveal_notify() - - fn.logger.error("Kernel %s failed" % action) - - event = "%s [ERROR]: Kernel %s failed\n" % ( - fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), - action, - ) - self.messages_queue.put(event) + self.spinner.set_spinning(False) + self.hbox_spinner.hide() self.label_status.set_markup( - "Kernel %s failed - see logs above" - % action + "Kernel %s completed" + % self.action + ) + self.label_title.set_markup( + "Kernel %s completed" % action ) - # undo action here if action == install - - if ( - action == "install" - and self.restore_kernel is not None - and self.source == "official" - ): - event = ( - "%s [INFO]: Attempting to undo previous Linux package changes\n" - % ( - fn.datetime.datetime.now().strftime( - "%Y-%m-%d-%H-%M-%S" - ), - ) - ) - - self.messages_queue.put(event) - - self.restore = True - fn.logger.info( - "Installation failed, attempting removal of previous Linux package changes" - ) - self.set_title("Kernel installation failed") - - self.label_spinner_progress.set_markup( - "Please wait restoring kernel %s" - % self.restore_kernel.version - ) - - fn.uninstall(self) - - fn.logger.info( - "Restoring previously installed kernel %s" - % self.restore_kernel.version - ) - - self.official_kernels = [ - "%s/packages/l/%s/%s-%s-x86_64%s" - % ( - fn.archlinux_mirror_archive_url, - self.restore_kernel.name, - self.restore_kernel.name, - self.restore_kernel.version, - ".pkg.tar.zst", - ), - "%s/packages/l/%s/%s-%s-x86_64%s" - % ( - fn.archlinux_mirror_archive_url, - self.linux_headers, - self.linux_headers, - self.restore_kernel.version, - ".pkg.tar.zst", - ), - ] - self.errors_found = False - fn.install_archive_kernel(self) - self.set_title("Kernel installation failed") - self.label_status.set_markup( - f"Kernel %s failed - see logs above\n" - % action - ) - else: - - self.spinner.set_spinning(False) - self.hbox_spinner.hide() - - self.set_title("Kernel installation failed") - self.label_title.set_markup("Install failed") - - # - # self.label_progress_window_desc.set_markup( - # f"This window can be now closed\n" - # f"A reboot is recommended when Linux packages have changed" - # ) - - # break - else: - if ( - returncode == 0 - and "-headers" in kernel - or action == "uninstall" - or action == "install" - and self.errors_found is False - ): - - fn.update_bootloader(self) - self.update_installed_list() - self.update_official_list() - - if len(self.manager_gui.community_kernels) > 0: - self.update_community_list() - - if self.restore == False: - self.label_title.set_markup( - "Kernel %s completed" % action - ) - - self.label_status.set_markup( - "Kernel %s completed" - % action - ) - - self.spinner.set_spinning(False) - self.hbox_spinner.hide() - - self.label_progress_window_desc.set_markup( - f"This window can be now closed\n" - f"A reboot is recommended when Linux packages have changed" - ) - else: - self.label_title.set_markup( - "Kernel %s failed" % action - ) - - self.label_status.set_markup( - "Kernel %s failed" - % action - ) - - self.spinner.set_spinning(False) - self.hbox_spinner.hide() - - self.label_progress_window_desc.set_markup( - f"This window can be now closed\n" - f"Previous kernel restored due to failure\n" - f"A reboot is recommended when Linux packages have changed" - ) - - # # else: - # self.spinner.set_spinning(False) - # self.hbox_spinner.hide() - # - # self.label_progress_window_desc.set_markup( - # f"This window can be now closed\n" - # f"A reboot is recommended when Linux packages have changed" - # ) - break + + elif returncode == 1: + self.errors_found = True + self.kernel_fail(action) + else: + self.restore = None + + fn.kernel_initrd(self) + fn.update_bootloader(self) + + self.spinner.set_spinning(False) + self.hbox_spinner.hide() + + if self.errors_found is True: + + self.label_status.set_markup( + f"Kernel %s failed - see logs above\n" + % action + ) + + break + # + # else: + # break + except Exception as e: fn.logger.error("Exception in check_kernel_state(): %s" % e) + finally: + self.kernel_state_queue.task_done() + if os.path.exists(self.lockfile): os.unlink(self.lockfile) - finally: - self.kernel_state_queue.task_done() + self.update_installed_list() + self.update_official_list() + + if len(self.manager_gui.community_kernels) > 0: + self.update_community_list() + + while self.manager_gui.default_context.pending(): + self.manager_gui.default_context.iteration(True) + fn.time.sleep(0.3) + + self.spinner.set_spinning(False) + self.hbox_spinner.hide() + + if self.errors_found is True: + event = ( + "%s [ERROR]: Problems encountered with the last transaction, see logs" + % (fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"),) + ) + self.messages_queue.put(event) + + else: + event = "%s [INFO]: A reboot is recommended" % ( + fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + ) + self.messages_queue.put(event) + + if os.path.exists("/usr/lib/modules/build"): + shutil.rmtree("/usr/lib/modules/build", ignore_errors=True) + + break + + def kernel_fail(self, action): + self.errors_found = True + self.label_notify_revealer.set_text("Kernel %s failed" % action) + self.reveal_notify() + + fn.logger.error("Kernel %s failed" % action) + self.label_title.set_markup("Kernel %s failed" % action) + + self.label_status.set_markup( + "Kernel %s failed - see logs above" + % action + ) + # self.action = "uninstall" + fn.logger.info( + "Installation failed, attempting removal of previous Linux package changes" + ) + event = "%s [INFO]: Reverting package changes made\n" % ( + fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + ) + + self.label_spinner_progress.set_markup( + "Please wait reverting package changes" + ) + + self.messages_queue.put(event) + + self.label_title.set_markup("Kernel install failed") + self.action = "uninstall" + fn.uninstall(self) + + if self.restore_kernel is not None and self.source == "official": + self.restore = True + + self.label_spinner_progress.set_markup( + "Please wait restoring kernel %s" % self.restore_kernel.version + ) + + fn.logger.info( + "Restoring previously installed kernel %s" % self.restore_kernel.version + ) + + event = "%s [INFO]: Restoring previously installed kernel %s\n" % ( + fn.datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S"), + self.restore_kernel.version, + ) + + self.messages_queue.put(event) + + self.official_kernels = [ + "%s/packages/l/%s/%s-%s-x86_64%s" + % ( + fn.archlinux_mirror_archive_url, + self.restore_kernel.name, + self.restore_kernel.name, + self.restore_kernel.version, + ".pkg.tar.zst", + ), + "%s/packages/l/%s/%s-%s-x86_64%s" + % ( + fn.archlinux_mirror_archive_url, + self.linux_headers, + self.linux_headers, + self.restore_kernel.version, + ".pkg.tar.zst", + ), + ] + self.errors_found = False + self.action = "install" + fn.install_archive_kernel(self) + + self.label_title.set_markup("Kernel restored due to failure") + # elif self.source == "community": + # GLib.idle_add( + # fn.show_mw, + # self, + # "System changes", + # f"Kernel {self.action} failed\n" + # f"There have been errors, please review the logs\n", + # "images/48x48/akm-warning.png", + # priority=GLib.PRIORITY_DEFAULT, + # ) def update_installed_list(self): self.manager_gui.installed_kernels = fn.get_installed_kernels() diff --git a/usr/share/archlinux-kernel-manager/ui/SettingsWindow.py b/usr/share/archlinux-kernel-manager/ui/SettingsWindow.py index 048cf2f..ae3b64c 100644 --- a/usr/share/archlinux-kernel-manager/ui/SettingsWindow.py +++ b/usr/share/archlinux-kernel-manager/ui/SettingsWindow.py @@ -491,7 +491,6 @@ class SettingsWindow(Gtk.Window): mw = MessageWindow( title="Legacy boot detected", message="Cannot select systemd-boot, UEFI boot mode is not available", - image_path="images/48x48/akm-warning.png", transient_for=self, detailed_message=False, ) @@ -544,7 +543,6 @@ class SettingsWindow(Gtk.Window): % self.text_entry_bootloader_file.get_buffer() .get_text() .strip(), - image_path="images/48x48/akm-warning.png", transient_for=self, detailed_message=False, )