Skip to content

Commit d2d6bf2

Browse files
committed
Add Alpine Linux (APK) support to vmupdate
related: QubesOS/qubes-issues#7323
1 parent 65eb613 commit d2d6bf2

File tree

4 files changed

+106
-0
lines changed

4 files changed

+106
-0
lines changed

vmupdate/agent/entrypoint.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ def get_package_manager(os_data, log, log_handler, log_level, no_progress):
101101
elif os_data["os_family"] == "ArchLinux":
102102
from source.pacman.pacman_cli import PACMANCLI as PackageManager
103103
print(f"Progress reporting not supported.", flush=True)
104+
elif os_data["os_family"] == "Alpine":
105+
from source.apk.apk_cli import APKCLI as PackageManager
106+
print(f"Progress reporting not supported.", flush=True)
104107
else:
105108
raise NotImplementedError(
106109
"Only Debian, RedHat and ArchLinux based OS is supported.")
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License
9+
# as published by the Free Software Foundation; either version 2
10+
# of the License, or (at your option) any later version.
11+
#
12+
# This program is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with this program; if not, write to the Free Software
19+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20+
# USA.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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 typing import List, Dict
24+
25+
from source.common.package_manager import PackageManager
26+
from source.common.process_result import ProcessResult
27+
from source.common.exit_codes import EXIT
28+
29+
30+
class APKCLI(PackageManager):
31+
def __init__(self, log_handler, log_level):
32+
super().__init__(log_handler, log_level)
33+
self.package_manager = "apk"
34+
35+
def refresh(self, hard_fail: bool) -> ProcessResult:
36+
"""
37+
Use package manager to refresh available packages.
38+
39+
:param hard_fail: raise error if some repo is unavailable
40+
:return: (exit_code, stdout, stderr)
41+
"""
42+
cmd = [self.package_manager, "update"]
43+
result = self.run_cmd(cmd)
44+
if result.code != 0:
45+
result.code = 1
46+
result.error_from_messages()
47+
return result
48+
49+
def get_packages(self) -> Dict[str, List[str]]:
50+
"""
51+
Use apk to return the installed packages and their versions.
52+
"""
53+
54+
cmd = [self.package_manager, "info", "-v"]
55+
# EXAMPLE OUTPUT:
56+
# qubes-vm-core-4.2.25-r1
57+
result = self.run_cmd(cmd, realtime=False)
58+
59+
packages: Dict[str, List[str]] = {}
60+
for line in result.out.splitlines():
61+
package, version, release = line.rsplit("-", maxsplit=2)
62+
packages.setdefault(package, []).append(version + "-" + release)
63+
64+
return packages
65+
66+
def get_action(self, remove_obsolete) -> List[str]:
67+
"""
68+
APK will handle obsoletions itself
69+
"""
70+
return ["upgrade", "--force", "--no-interactive"]
71+
72+
def clean(self) -> int:
73+
"""
74+
Clean cache files of package manager.
75+
Should return 0 on success or EXIT.ERR_VM_CLEANUP otherwise.
76+
"""
77+
cmd = [self.package_manager, "cache", "clean", "-f", "--no-interactive"]
78+
result = self.run_cmd(cmd, realtime=False)
79+
return_code = EXIT.ERR_VM_CLEANUP if result.code != 0 else 0
80+
return return_code

vmupdate/agent/source/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ def get_os_data(logger: Optional = None) -> Dict[str, Any]:
6565
if 'arch' in family:
6666
data["os_family"] = 'ArchLinux'
6767

68+
if 'alpine' in family:
69+
data["os_family"] = 'Alpine'
70+
6871
return data
6972

7073

0 commit comments

Comments
 (0)