1 import os.path
2 import re
3
4 from inca.Reporter import Reporter
5
7 """VersionReporter - Convenience module for creating version reporters::
8
9 from inca.VersionReporter import VersionReporter
10 reporter = VersionReporter()
11 command = 'somecommand -version'
12 pattern = '^version "(.*)"'
13 ...
14 reporter.setPackageName('packageX')
15 reporter.setVersionByExecutable(command, pattern)
16 reporter.printReporter()
17
18 or
19
20 reporter.setVersionByGptQuery('packageX')
21
22 or
23
24 reporter.setVersionByRpmQuery('packageX')
25
26 or
27
28 reporter->setPackageVersion('x.x.x')
29
30 or
31
32 for subpackage in subpackages:
33 reporter.setSubpackageVersion(subpackage, version)
34
35 This module is a subclass of Reporter that provides convenience methods
36 for creating version reporters. A version reporter reports this version
37 information for a package in the following schema (i.e., this is the body
38 of the Inca report)::
39
40 <packageVersion>
41 <ID>packageX</ID>
42 <version>x.x.x</version>
43 </packageVersion>
44
45 or
46
47 <packageVersion>
48 <ID>packageX</ID>
49 <subpackage>
50 <ID>subpackageX</ID>
51 <version>x.x.x</version>
52 </subpackage>
53 <subpackage>
54 <ID>subpackageY</ID>
55 <version>x.x.x</version>
56 </subpackage>
57 </packageVersion>
58
59 Version information can be set using one of the basic methods
60 setPackageVersion (for the first example) or setSubpackageVersion (for the
61 second). In this case, the user retrieves a package's version information
62 directly and uses one of these two methods to report it. This module also
63 provides convenience methods that retrieve a package version using
64 conventional methods of querying version information.
65 """
66
68 """Class constructor that returns a new VersionReporter object. The
69 constructor supports the following parameters in addition to those
70 supported by Reporter::
71
72 package_name
73 the name of the package for which a version is being determined;
74 default ''.
75
76 package_version
77 the version of the package.
78 """
79 package_name = ''
80 if attributes.has_key('package_name'):
81 package_name = attributes['package_name']
82 del attributes['package_name']
83 package_version = None
84 if attributes.has_key('package_version'):
85 package_version = attributes['package_version']
86 del attributes['package_version']
87 Reporter.__init__(self, **attributes)
88 self.package_name = package_name
89 self.package_version = package_version
90 self.subpackage_versions = {}
91 self.addDependency('inca.VersionReporter')
92
94 """Returns the name of the package."""
95 return self.package_name
96
98 """Returns the version of the package."""
99 return self.package_version
100
102 """Returns a list of all the names of all subpackages with a set version."""
103 return self.subpackage_versions.keys()
104
106 """Returns the version of subpackage name."""
107 result = None
108 if self.subpackage_versions.has_key(name):
109 result = self.subpackage_versions[name]
110 return result
111
112 - def reportBody(self):
113 """Constructs and returns the body of the reporter."""
114 packageXml = [self.xmlElement('ID', 1, self.getPackageName())]
115 if self.getCompleted():
116 if self.getPackageVersion() != None:
117 packageXml.append(
118 self.xmlElement('version', 1, self.getPackageVersion())
119 )
120 subpackages = self.getSubpackageNames()
121 subpackages.sort()
122 for subpackage in subpackages:
123 packageXml.append(self.xmlElement('subpackage', 0,
124 self.xmlElement('ID', 1, subpackage),
125 self.xmlElement('version', 1, self.getSubpackageVersion(subpackage))
126 ))
127 return self.xmlElement('package', 0, *packageXml)
128
130 """Set the name of the package."""
131 self.package_name = name
132
134 """Report the version of a package as version."""
135 self.package_version = version
136 self.setCompleted(1)
137
139 """Report the version of subpackage name as version."""
140 self.subpackage_versions[name] = version
141 self.setCompleted(1)
142
144 """Retrieve the package version by compiling and running a program and
145 matching its output against a pattern. Returns 1 if successful, else 0.
146 The function recognizes the following parameter in addition to those
147 supported by the compiledProgramOutput method of Reporter::
148
149 pattern
150 pattern to search for in program output; default '(.+)'
151 """
152 pattern = '(.+)'
153 if attrs.has_key('pattern'):
154 pattern = attrs['pattern']
155 del attrs['pattern']
156 output = self.compiledProgramOutput(**attrs)
157 if not output:
158 self.setCompleted(0)
159 self.setFailMessage('program compilation/execution failed')
160 else:
161 found = re.search(pattern, output)
162 if not found:
163 self.setCompleted(0)
164 self.setFailMessage("'" + pattern + "' not in '" + output + "'")
165 else:
166 self.setCompleted(1)
167 self.setPackageVersion(found.group(1))
168 return self.getCompleted()
169
171 """Retrieve package version information by executing command and greping
172 the output for pattern. command is the executable and argument string
173 to retrieve the version (e.g., command_name -version) and pattern is a
174 pattern containing one grouping (i.e., memory parentheses) to retrieve
175 the version from the output. pattern defaults to '([\d\.]+)' if not
176 specified. Fails if timeout is specified and command does not complete
177 within timeout seconds. Returns 1 if successful, else 0.
178 """
179 if pattern == None:
180 pattern = r'([\d\.]+)'
181 output = self.loggedCommandOutput(command, timeout)
182 if not output or re.search('command not found', output):
183 self.setCompleted(0)
184 if not output:
185 self.setFailMessage('')
186 else:
187 self.setFailMessage(output)
188 else:
189 found = re.search(pattern, output)
190 if not found:
191 self.setCompleted(0)
192 self.setFailMessage("'" + pattern + "' not in '" + output + "'")
193 else:
194 version = None
195 for group in found.groups():
196 if group != None:
197 version = group
198 if version != None:
199 self.setCompleted(1)
200 self.setPackageVersion(version)
201 else:
202 self.setCompleted(0)
203 self.setFailMessage("'" + pattern + "' not in '" + output + "'")
204 return self.getCompleted()
205
206 - def setVersionByFileContents(self, path, pattern=None):
207 """Retrieve the package version by grep'ing the file path for pattern.
208 pattern defaults to '([\d\.]+)' if not specified. Returns 1 if
209 successful, else 0.
210 """
211 if pattern == None:
212 pattern = r'([\d\.]+)'
213 if not os.path.exists(path):
214 self.setCompleted(0)
215 self.setFailMessage("file '" + path + "' not present")
216 else:
217 input = open(path, 'r')
218 if not input:
219 self.setCompleted(0)
220 self.setFailMessage("file '" + path + "' is not readable")
221 else:
222 line = input.readline()
223 while line != None and not re.search(pattern, line):
224 line = input.readline()
225 input.close()
226 if line == None:
227 self.setCompleted(0)
228 self.setFailMessage("'"+pattern+"' not found in file '"+path+"'")
229 else:
230 self.setCompleted(1)
231 found = re.search(pattern, line)
232 self.setPackageVersion(found.group(1))
233 return self.getCompleted()
234
236 """Set subpackage version information by querying GPT for packages prefixed
237 with any element of prefixes. Returns 1 if successful, else 0.
238 """
239 output = self.loggedCommandOutput('gpt-query')
240 if not output:
241 self.setResult(0, 'gpt-query failed')
242 return 0
243 pat = '^\s*(' + string.join(prefixes, '|') + ')'
244 lastDefined = None
245 for pkg in output.split('\n'):
246 if not re.search(pat, pkg):
247 continue
248 (id, version) = re.search(r'^\s*([^-]+).*version:\s+(.*)$', pkg)
249 if not version:
250 continue
251 self.setSubpackageVersion(id, version)
252 lastDefined = id
253 if lastDefined == None:
254 self.setResult(0, 'package not installed (no GPT packages located)')
255 else:
256 self.setResult(1)
257 return self.getCompleted()
258
260 """Set subpackage version information by querying GPT for packages that
261 contain the regular expression pattern. Returns 1 if successful, else 0.
262 """
263 rpmCommand = \
264 "(rpm -qa --qf='%{NAME} version:%{VERSION}\\n' | " + \
265 "grep '^[^ ]*" + pattern + "')"
266 rpms = self.loggedCommandOutput(rpmCommand).split('\n');
267 rpms.pop()
268 if len(rpms) == 0:
269 self.setResult(0, 'no rpm packages found for ' + pattern)
270 return 0
271 for rpm in rpms:
272 (subpackage, version) = rpm.split(' version:')
273 self.setSubpackageVersion(subpackage, version)
274 self.setResult(1)
275 return 1;
276