|  | 
|  | 1 | +# coding=utf-8 | 
|  | 2 | +# | 
|  | 3 | +# The Qubes OS Project, http://www.qubes-os.org | 
|  | 4 | +# | 
|  | 5 | +# Copyright (C) 2022  Piotr Bartman <[email protected]> | 
|  | 6 | +# Copyright (C) 2025  Ali Mirjamali <[email protected]> | 
|  | 7 | +# | 
|  | 8 | +# This program is free software; you can redistribute it and/or | 
|  | 9 | +# modify it under the terms of the GNU General Public License | 
|  | 10 | +# as published by the Free Software Foundation; either version 2 | 
|  | 11 | +# of the License, or (at your option) any later version. | 
|  | 12 | +# | 
|  | 13 | +# This program is distributed in the hope that it will be useful, | 
|  | 14 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 15 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 16 | +# GNU General Public License for more details. | 
|  | 17 | +# | 
|  | 18 | +# You should have received a copy of the GNU General Public License | 
|  | 19 | +# along with this program; if not, write to the Free Software | 
|  | 20 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, | 
|  | 21 | +# USA. | 
|  | 22 | + | 
|  | 23 | +from os import environ, path | 
|  | 24 | +from typing import List, Dict | 
|  | 25 | + | 
|  | 26 | +from source.common.package_manager import PackageManager | 
|  | 27 | +from source.common.process_result import ProcessResult | 
|  | 28 | +from source.common.exit_codes import EXIT | 
|  | 29 | + | 
|  | 30 | + | 
|  | 31 | +class APKCLI(PackageManager): | 
|  | 32 | +    def __init__(self, log_handler, log_level): | 
|  | 33 | +        super().__init__(log_handler, log_level) | 
|  | 34 | +        self.package_manager = "apk" | 
|  | 35 | +        self.clear_https_proxy = False | 
|  | 36 | +        self.clear_http_proxy = False | 
|  | 37 | +        if path.exists("/run/qubes-service/updates-proxy-setup"): | 
|  | 38 | +            if not "https_proxy" in environ: | 
|  | 39 | +                environ["https_proxy"] = "http://127.0.0.1:8082/" | 
|  | 40 | +                self.clear_https_proxy = True | 
|  | 41 | +            if not "https_proxy" in environ: | 
|  | 42 | +                environ["https_proxy"] = "http://127.0.0.1:8082/" | 
|  | 43 | +                self.clear_http_proxy = True | 
|  | 44 | + | 
|  | 45 | +    def __del__(self): | 
|  | 46 | +        if self.clear_https_proxy: | 
|  | 47 | +            environ.pop("https_proxy") | 
|  | 48 | +        if self.clear_http_proxy: | 
|  | 49 | +            environ.pop("http_proxy") | 
|  | 50 | + | 
|  | 51 | +    def refresh(self, hard_fail: bool) -> ProcessResult: | 
|  | 52 | +        """ | 
|  | 53 | +        Use package manager to refresh available packages. | 
|  | 54 | +
 | 
|  | 55 | +        :param hard_fail: raise error if some repo is unavailable | 
|  | 56 | +        :return: (exit_code, stdout, stderr) | 
|  | 57 | +        """ | 
|  | 58 | +        cmd = [self.package_manager, "update"] | 
|  | 59 | +        result = self.run_cmd(cmd) | 
|  | 60 | +        if result.code != 0: | 
|  | 61 | +            result.code = 1 | 
|  | 62 | +        result.error_from_messages() | 
|  | 63 | +        return result | 
|  | 64 | + | 
|  | 65 | +    def get_packages(self) -> Dict[str, List[str]]: | 
|  | 66 | +        """ | 
|  | 67 | +        Use apk to return the installed packages and their versions. | 
|  | 68 | +        """ | 
|  | 69 | + | 
|  | 70 | +        cmd = [self.package_manager, "info", "-v"] | 
|  | 71 | +        # EXAMPLE OUTPUT: | 
|  | 72 | +        # qubes-vm-core-4.2.25-r1 | 
|  | 73 | +        result = self.run_cmd(cmd, realtime=False) | 
|  | 74 | + | 
|  | 75 | +        packages: Dict[str, List[str]] = {} | 
|  | 76 | +        for line in result.out.splitlines(): | 
|  | 77 | +            package, version, release = line.rsplit("-", maxsplit=2) | 
|  | 78 | +            packages.setdefault(package, []).append(version + "-" + release) | 
|  | 79 | + | 
|  | 80 | +        return packages | 
|  | 81 | + | 
|  | 82 | +    def get_action(self, remove_obsolete) -> List[str]: | 
|  | 83 | +        """ | 
|  | 84 | +        APK will handle obsoletions itself | 
|  | 85 | +        """ | 
|  | 86 | +        return ["upgrade", "--force", "--no-interactive"] | 
|  | 87 | + | 
|  | 88 | +    def clean(self) -> int: | 
|  | 89 | +        """ | 
|  | 90 | +        Clean cache files of package manager. | 
|  | 91 | +        Should return 0 on success or EXIT.ERR_VM_CLEANUP otherwise. | 
|  | 92 | +        """ | 
|  | 93 | +        cmd = [self.package_manager, "cache", "clean", "-f", "--no-interactive"] | 
|  | 94 | +        result = self.run_cmd(cmd, realtime=False) | 
|  | 95 | +        return_code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0 | 
|  | 96 | +        return return_code | 
0 commit comments