Skip to content

Commit 4ce9dd7

Browse files
Add Package.get_packages() to return all installed packages
Get all installed packages with name version number, release number (if available) and architecture: >>> host.package.get_packages() {'acl.x86_64': {'arch': 'x86_64', 'name': 'acl', 'release': '4.3.1', 'version': '2.2.52'}, <redacted> 'zypper.x86_64': {'arch': 'x86_64', 'name': 'zypper', 'release': '150200.39.1', 'version': '1.14.57'}}
1 parent 5e7c46c commit 4ce9dd7

File tree

2 files changed

+117
-0
lines changed

2 files changed

+117
-0
lines changed

Diff for: test/test_modules.py

+26
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,32 @@ def test_package(host, docker_image):
5858
assert sshd_release in ssh.release
5959

6060

61+
@all_images
62+
def test_get_packages(host, docker_image):
63+
arch = docker_image_info[docker_image][2]
64+
sshd_release_number = ssh_pkg_info[docker_image][1]
65+
66+
package_ssh = host.package("openssh-server")
67+
assert package_ssh.is_installed
68+
69+
all_pkgs = host.package.get_packages()
70+
assert f"zsh.{arch}" not in all_pkgs
71+
72+
name_arch = f"openssh-server.{arch}"
73+
assert name_arch in all_pkgs
74+
75+
pkg = all_pkgs[name_arch]
76+
assert pkg["version"] == package_ssh.version
77+
assert pkg["arch"] == arch
78+
assert pkg["name"] == "openssh-server"
79+
if sshd_release_number is None:
80+
with pytest.raises(NotImplementedError):
81+
package_ssh.release
82+
else:
83+
assert sshd_release_number in pkg["release"]
84+
assert pkg["release"] == package_ssh.release
85+
86+
6187
def test_held_package(host):
6288
python = host.package("python3")
6389
assert python.is_installed

Diff for: testinfra/modules/package.py

+91
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ def __init__(self, name):
2020
self.name = name
2121
super().__init__()
2222

23+
@classmethod
24+
def get_packages(cls):
25+
"""Get all installed packages with name version number, release number (if available) and architecture
26+
27+
>>> host.package.get_packages()
28+
{'acl.x86_64': {'arch': 'x86_64',
29+
'name': 'acl',
30+
'release': '4.3.1',
31+
'version': '2.2.52'},
32+
<redacted>
33+
'zypper.x86_64': {'arch': 'x86_64',
34+
'name': 'zypper',
35+
'release': '150200.39.1',
36+
'version': '1.14.57'}}
37+
"""
38+
raise NotImplementedError
39+
2340
@property
2441
def is_installed(self):
2542
"""Test if the package is installed
@@ -94,6 +111,29 @@ def get_module_class(cls, host):
94111

95112

96113
class DebianPackage(Package):
114+
@classmethod
115+
def get_packages(cls):
116+
out = cls.run(r"dpkg-query -f '${Package}|${Version}|${Architecture}\n' -W")
117+
assert not out.stderr
118+
pkgs = {}
119+
for line in out.stdout.splitlines():
120+
line = line.strip()
121+
if not line:
122+
continue
123+
name, version, arch = line.split("|")
124+
pkg_key = f"{name}.{arch}"
125+
assert pkg_key not in pkgs, (
126+
f"Package {pkg_key} already added to package list. "
127+
"Check for duplicate package in command output"
128+
)
129+
pkgs[pkg_key] = {
130+
"name": name,
131+
"version": version,
132+
"release": None,
133+
"arch": arch,
134+
}
135+
return pkgs
136+
97137
@property
98138
def is_installed(self):
99139
result = self.run_test("dpkg-query -f '${Status}' -W %s", self.name)
@@ -155,6 +195,34 @@ def version(self):
155195

156196

157197
class RpmPackage(Package):
198+
@classmethod
199+
def get_packages(cls):
200+
out = cls.run(
201+
r'rpm -qa --queryformat "%{NAME}|%{VERSION}|%{RELEASE}|%{ARCH}\n"'
202+
)
203+
assert not out.stderr
204+
pkgs = {}
205+
for line in out.stdout.splitlines():
206+
line = line.strip()
207+
if not line:
208+
continue
209+
name, version, release, arch = line.split("|")
210+
# Ignore GPG keys imported with "rpm --import" e.g. "gpg-pubkey|50a3dd1c|50f35137|(none)"
211+
if name == "gpg-pubkey" and arch == "(none)":
212+
continue
213+
pkg_key = f"{name}.{arch}"
214+
assert pkg_key not in pkgs, (
215+
f"Package {pkg_key} already added to package list. "
216+
"Check for duplicate package in command output"
217+
)
218+
pkgs[pkg_key] = {
219+
"name": name,
220+
"version": version,
221+
"release": release,
222+
"arch": arch,
223+
}
224+
return pkgs
225+
158226
@property
159227
def is_installed(self):
160228
return self.run_test("rpm -q %s", self.name).rc == 0
@@ -185,6 +253,29 @@ def release(self):
185253

186254

187255
class ArchPackage(Package):
256+
@classmethod
257+
def get_packages(cls):
258+
out = cls.run(r'expac "%n|%v|%a"')
259+
assert not out.stderr
260+
pkgs = {}
261+
for line in out.stdout.splitlines():
262+
line = line.strip()
263+
if not line:
264+
continue
265+
name, version, arch = line.split("|")
266+
pkg_key = f"{name}.{arch}"
267+
assert pkg_key not in pkgs, (
268+
f"Package {pkg_key} already added to package list. "
269+
"Check for duplicate package in command output"
270+
)
271+
pkgs[pkg_key] = {
272+
"name": name,
273+
"version": version,
274+
"release": None,
275+
"arch": arch,
276+
}
277+
return pkgs
278+
188279
@property
189280
def is_installed(self):
190281
return self.run_test("pacman -Q %s", self.name).rc == 0

0 commit comments

Comments
 (0)