@@ -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
96113class 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
157197class 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
187255class 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