summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2011-07-01 15:47:12 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2011-07-01 23:27:27 +0100
commit31ea94b2171e957358524baf5e9231a985a5450c (patch)
tree0efb4ee5b54216518486ef558d63c6ef81ec92db
parentca4c7c47a8ce8f2c168a0879866bde93348a2645 (diff)
downloadpoky-31ea94b2171e957358524baf5e9231a985a5450c.tar.gz
insane.bbclass: Start to rework this so specific checks can be easily made warnings/errors
This patch means the warning/error handling can be controlled from local.conf and/or from the distro level and no longer uses numbers but strings instead. The system becomes extensible so that other classes can extend the path QA checks at least. It also removes all th duplicate error message code, we should have *one* good error message. Much work remains including making INSANE_SKIP take the classes of QA test to skip but its a start. (From OE-Core rev: 0fbe849b56d6457b6547a1202c4938d35316d8b8) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/classes/insane.bbclass216
1 files changed, 83 insertions, 133 deletions
diff --git a/meta/classes/insane.bbclass b/meta/classes/insane.bbclass
index 35809b9ec2..a6f9c1ea9a 100644
--- a/meta/classes/insane.bbclass
+++ b/meta/classes/insane.bbclass
@@ -91,83 +91,39 @@ def package_qa_get_machine_dict():
91 } 91 }
92 92
93 93
94# Known Error classes 94WARN_QA ?= "dev-so rpaths debug-deps debug-files arch la2 pkgconfig desktop la ldflags perms"
95# 0 - non dev contains .so 95ERROR_QA ?= ""
96# 1 - package contains a dangerous RPATH 96#ERROR_QA ?= "rpaths debug-deps debug-files arch pkgconfig perms"
97# 2 - package depends on debug package
98# 3 - non dbg contains .so
99# 4 - wrong architecture
100# 5 - .la contains installed=yes or reference to the workdir
101# 6 - .pc contains reference to /usr/include or workdir
102# 7 - the desktop file is not valid
103# 8 - .la contains reference to the workdir
104# 9 - LDFLAGS ignored
105# 10 - Build paths in binaries
106 97
107def package_qa_clean_path(path,d): 98def package_qa_clean_path(path,d):
108 """ Remove the common prefix from the path. In this case it is the TMPDIR""" 99 """ Remove the common prefix from the path. In this case it is the TMPDIR"""
109 return path.replace(bb.data.getVar('TMPDIR',d,True),"") 100 return path.replace(bb.data.getVar('TMPDIR',d,True),"")
110 101
111def package_qa_make_fatal_error(error_class, name, path,d): 102def package_qa_write_error(error, d):
112 """ 103 logfile = d.getVar('QA_LOGFILE', True)
113 decide if an error is fatal
114
115 TODO: Load a whitelist of known errors
116 """
117 return False
118 return not error_class in [0, 5, 7, 8, 9]
119
120def package_qa_write_error(error_class, name, path, d):
121 """
122 Log the error
123 """
124
125 ERROR_NAMES =[
126 "non dev contains .so",
127 "package contains RPATH",
128 "package depends on debug package",
129 "non dbg contains .debug",
130 "wrong architecture",
131 "evil hides inside the .la",
132 "evil hides inside the .pc",
133 "the desktop file is not valid",
134 ".la contains reference to the workdir",
135 "LDFLAGS ignored",
136 "package contains reference to tmpdir paths",
137 ]
138
139 log_path = os.path.join( bb.data.getVar('T', d, True), "log.qa_package" )
140 f = file( log_path, "a+")
141 print >> f, "%s, %s, %s" % \
142 (ERROR_NAMES[error_class], name, package_qa_clean_path(path,d))
143 f.close()
144
145 logfile = bb.data.getVar('QA_LOGFILE', d, True)
146 if logfile: 104 if logfile:
147 p = bb.data.getVar('P', d, True) 105 p = d.getVar('P', True)
148 f = file( logfile, "a+") 106 f = file( logfile, "a+")
149 print >> f, "%s, %s, %s, %s" % \ 107 print >> f, "%s: %s" % (p, error)
150 (p, ERROR_NAMES[error_class], name, package_qa_clean_path(path,d))
151 f.close() 108 f.close()
152 109
153def package_qa_handle_error(error_class, error_msg, name, path, d): 110def package_qa_handle_error(error_class, error_msg, d):
154 fatal = package_qa_make_fatal_error(error_class, name, path, d) 111 package_qa_write_error(error_msg, d)
155 if fatal: 112 if error_class in (d.getVar("ERROR_QA", True) or "").split():
156 bb.error("QA Issue: %s" % error_msg) 113 bb.error("QA Issue: %s" % error_msg)
114 return True
157 else: 115 else:
158 bb.warn("QA Issue: %s" % error_msg) 116 bb.warn("QA Issue: %s" % error_msg)
159 package_qa_write_error(error_class, name, path, d) 117 return False
160
161 return not fatal
162 118
163def package_qa_check_rpath(file,name,d, elf): 119QAPATHTEST[rpaths] = "package_qa_check_rpath"
120def package_qa_check_rpath(file,name, d, elf, messages):
164 """ 121 """
165 Check for dangerous RPATHs 122 Check for dangerous RPATHs
166 """ 123 """
167 if not elf: 124 if not elf:
168 return True 125 return
169 126
170 sane = True
171 scanelf = os.path.join(bb.data.getVar('STAGING_BINDIR_NATIVE',d,True),'scanelf') 127 scanelf = os.path.join(bb.data.getVar('STAGING_BINDIR_NATIVE',d,True),'scanelf')
172 bad_dirs = [bb.data.getVar('TMPDIR', d, True) + "/work", bb.data.getVar('STAGING_DIR_TARGET', d, True)] 128 bad_dirs = [bb.data.getVar('TMPDIR', d, True) + "/work", bb.data.getVar('STAGING_DIR_TARGET', d, True)]
173 bad_dir_test = bb.data.getVar('TMPDIR', d, True) 129 bad_dir_test = bb.data.getVar('TMPDIR', d, True)
@@ -182,67 +138,56 @@ def package_qa_check_rpath(file,name,d, elf):
182 for line in txt: 138 for line in txt:
183 for dir in bad_dirs: 139 for dir in bad_dirs:
184 if dir in line: 140 if dir in line:
185 error_msg = "package %s contains bad RPATH %s in file %s" % (name, line, file) 141 messages.append("package %s contains bad RPATH %s in file %s" % (name, line, file))
186 sane = sane + package_qa_handle_error(1, error_msg, name, file, d)
187 142
188 return sane 143QAPATHTEST[dev-so] = "package_qa_check_dev"
189 144def package_qa_check_dev(path, name, d, elf, messages):
190def package_qa_check_dev(path, name,d, elf):
191 """ 145 """
192 Check for ".so" library symlinks in non-dev packages 146 Check for ".so" library symlinks in non-dev packages
193 """ 147 """
194 148
195 sane = True
196
197 if not name.endswith("-dev") and not name.endswith("-dbg") and path.endswith(".so") and os.path.islink(path): 149 if not name.endswith("-dev") and not name.endswith("-dbg") and path.endswith(".so") and os.path.islink(path):
198 error_msg = "non -dev/-dbg package contains symlink .so: %s path '%s'" % \ 150 messages.append("non -dev/-dbg package contains symlink .so: %s path '%s'" % \
199 (name, package_qa_clean_path(path,d)) 151 (name, package_qa_clean_path(path,d)))
200 sane = package_qa_handle_error(0, error_msg, name, path, d)
201 152
202 return sane 153QAPATHTEST[debug-files] = "package_qa_check_dbg"
203 154def package_qa_check_dbg(path, name, d, elf, messages):
204def package_qa_check_dbg(path, name,d, elf):
205 """ 155 """
206 Check for ".debug" files or directories outside of the dbg package 156 Check for ".debug" files or directories outside of the dbg package
207 """ 157 """
208 158
209 sane = True
210
211 if not "-dbg" in name: 159 if not "-dbg" in name:
212 if '.debug' in path.split(os.path.sep): 160 if '.debug' in path.split(os.path.sep):
213 error_msg = "non debug package contains .debug directory: %s path %s" % \ 161 messages.append("non debug package contains .debug directory: %s path %s" % \
214 (name, package_qa_clean_path(path,d)) 162 (name, package_qa_clean_path(path,d)))
215 sane = package_qa_handle_error(3, error_msg, name, path, d)
216 163
217 return sane 164QAPATHTEST[perms] = "package_qa_check_perm"
218 165def package_qa_check_perm(path,name,d, elf, messages):
219def package_qa_check_perm(path,name,d, elf):
220 """ 166 """
221 Check the permission of files 167 Check the permission of files
222 """ 168 """
223 sane = True 169 return
224 return sane
225 170
226def package_qa_check_arch(path,name,d, elf): 171QAPATHTEST[arch] = "package_qa_check_arch"
172def package_qa_check_arch(path,name,d, elf, messages):
227 """ 173 """
228 Check if archs are compatible 174 Check if archs are compatible
229 """ 175 """
230 if not elf: 176 if not elf:
231 return True 177 return
232 178
233 sane = True
234 target_os = bb.data.getVar('TARGET_OS', d, True) 179 target_os = bb.data.getVar('TARGET_OS', d, True)
235 target_arch = bb.data.getVar('TARGET_ARCH', d, True) 180 target_arch = bb.data.getVar('TARGET_ARCH', d, True)
236 181
237 # FIXME: Cross package confuse this check, so just skip them 182 # FIXME: Cross package confuse this check, so just skip them
238 for s in ['cross', 'nativesdk', 'cross-canadian']: 183 for s in ['cross', 'nativesdk', 'cross-canadian']:
239 if bb.data.inherits_class(s, d): 184 if bb.data.inherits_class(s, d):
240 return True 185 return
241 186
242 # avoid following links to /usr/bin (e.g. on udev builds) 187 # avoid following links to /usr/bin (e.g. on udev builds)
243 # we will check the files pointed to anyway... 188 # we will check the files pointed to anyway...
244 if os.path.islink(path): 189 if os.path.islink(path):
245 return True 190 return
246 191
247 #if this will throw an exception, then fix the dict above 192 #if this will throw an exception, then fix the dict above
248 (machine, osabi, abiversion, littleendian, bits) \ 193 (machine, osabi, abiversion, littleendian, bits) \
@@ -250,50 +195,44 @@ def package_qa_check_arch(path,name,d, elf):
250 195
251 # Check the architecture and endiannes of the binary 196 # Check the architecture and endiannes of the binary
252 if not machine == elf.machine(): 197 if not machine == elf.machine():
253 error_msg = "Architecture did not match (%d to %d) on %s" % \ 198 messages.append("Architecture did not match (%d to %d) on %s" % \
254 (machine, elf.machine(), package_qa_clean_path(path,d)) 199 (machine, elf.machine(), package_qa_clean_path(path,d)))
255 sane = package_qa_handle_error(4, error_msg, name, path, d)
256 elif not bits == elf.abiSize(): 200 elif not bits == elf.abiSize():
257 error_msg = "Bit size did not match (%d to %d) on %s" % \ 201 messages.append("Bit size did not match (%d to %d) on %s" % \
258 (bits, elf.abiSize(), package_qa_clean_path(path,d)) 202 (bits, elf.abiSize(), package_qa_clean_path(path,d)))
259 sane = package_qa_handle_error(4, error_msg, name, path, d)
260 elif not littleendian == elf.isLittleEndian(): 203 elif not littleendian == elf.isLittleEndian():
261 error_msg = "Endiannes did not match (%d to %d) on %s" % \ 204 messages.append("Endiannes did not match (%d to %d) on %s" % \
262 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)) 205 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
263 sane = package_qa_handle_error(4, error_msg, name, path, d)
264 206
265 return sane 207QAPATHTEST[desktop] = "package_qa_check_desktop"
266 208def package_qa_check_desktop(path, name, d, elf, messages):
267def package_qa_check_desktop(path, name, d, elf):
268 """ 209 """
269 Run all desktop files through desktop-file-validate. 210 Run all desktop files through desktop-file-validate.
270 """ 211 """
271 sane = True
272 if path.endswith(".desktop"): 212 if path.endswith(".desktop"):
273 desktop_file_validate = os.path.join(bb.data.getVar('STAGING_BINDIR_NATIVE',d,True),'desktop-file-validate') 213 desktop_file_validate = os.path.join(bb.data.getVar('STAGING_BINDIR_NATIVE',d,True),'desktop-file-validate')
274 output = os.popen("%s %s" % (desktop_file_validate, path)) 214 output = os.popen("%s %s" % (desktop_file_validate, path))
275 # This only produces output on errors 215 # This only produces output on errors
276 for l in output: 216 for l in output:
277 sane = package_qa_handle_error(7, l.strip(), name, path, d) 217 messages.append("Desktop file issue: " + l.strip())
278 218
279 return sane 219QAPATHTEST[ldflags] = "package_qa_hash_style"
280 220def package_qa_hash_style(path, name, d, elf, messages):
281def package_qa_hash_style(path, name, d, elf):
282 """ 221 """
283 Check if the binary has the right hash style... 222 Check if the binary has the right hash style...
284 """ 223 """
285 224
286 if not elf: 225 if not elf:
287 return True 226 return
288 227
289 if os.path.islink(path): 228 if os.path.islink(path):
290 return True 229 return
291 230
292 gnu_hash = "--hash-style=gnu" in bb.data.getVar('LDFLAGS', d, True) 231 gnu_hash = "--hash-style=gnu" in bb.data.getVar('LDFLAGS', d, True)
293 if not gnu_hash: 232 if not gnu_hash:
294 gnu_hash = "--hash-style=both" in bb.data.getVar('LDFLAGS', d, True) 233 gnu_hash = "--hash-style=both" in bb.data.getVar('LDFLAGS', d, True)
295 if not gnu_hash: 234 if not gnu_hash:
296 return True 235 return
297 236
298 objdump = bb.data.getVar('OBJDUMP', d, True) 237 objdump = bb.data.getVar('OBJDUMP', d, True)
299 env_path = bb.data.getVar('PATH', d, True) 238 env_path = bb.data.getVar('PATH', d, True)
@@ -314,31 +253,26 @@ def package_qa_hash_style(path, name, d, elf):
314 sane = True 253 sane = True
315 254
316 if elf and not sane: 255 if elf and not sane:
317 error_msg = "No GNU_HASH in the elf binary: '%s'" % path 256 messages.append("No GNU_HASH in the elf binary: '%s'" % path)
318 return package_qa_handle_error(9, error_msg, name, path, d)
319 257
320 return True
321 258
322def package_qa_check_buildpaths(path, name, d, elf): 259QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
260def package_qa_check_buildpaths(path, name, d, elf, messages):
323 """ 261 """
324 Check for build paths inside target files and error if not found in the whitelist 262 Check for build paths inside target files and error if not found in the whitelist
325 """ 263 """
326 sane = True
327
328 # Ignore .debug files, not interesting 264 # Ignore .debug files, not interesting
329 if path.find(".debug") != -1: 265 if path.find(".debug") != -1:
330 return True 266 return
331 267
332 # Ignore symlinks 268 # Ignore symlinks
333 if os.path.islink(path): 269 if os.path.islink(path):
334 return True 270 return
335 271
336 tmpdir = bb.data.getVar('TMPDIR', d, True) 272 tmpdir = bb.data.getVar('TMPDIR', d, True)
337 file_content = open(path).read() 273 file_content = open(path).read()
338 if tmpdir in file_content: 274 if tmpdir in file_content:
339 error_msg = "File %s in package contained reference to tmpdir" % package_qa_clean_path(path,d) 275 messages.append("File %s in package contained reference to tmpdir" % package_qa_clean_path(path,d))
340 sane = package_qa_handle_error(10, error_msg, name, path, d)
341 return sane
342 276
343def package_qa_check_license(workdir, d): 277def package_qa_check_license(workdir, d):
344 """ 278 """
@@ -439,24 +373,25 @@ def package_qa_check_staged(path,d):
439 file_content = open(path).read() 373 file_content = open(path).read()
440 if workdir in file_content: 374 if workdir in file_content:
441 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root) 375 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
442 sane = package_qa_handle_error(8, error_msg, "staging", path, d) 376 sane = package_qa_handle_error("la", error_msg, d)
443 elif file.endswith(".pc"): 377 elif file.endswith(".pc"):
444 file_content = open(path).read() 378 file_content = open(path).read()
445 if pkgconfigcheck in file_content: 379 if pkgconfigcheck in file_content:
446 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root) 380 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
447 sane = package_qa_handle_error(6, error_msg, "staging", path, d) 381 sane = package_qa_handle_error("pkgconfig", error_msg, d)
448 382
449 return sane 383 return sane
450 384
451# Walk over all files in a directory and call func 385# Walk over all files in a directory and call func
452def package_qa_walk(path, funcs, package,d): 386def package_qa_walk(path, warnfuncs, errorfuncs, package, d):
453 import oe.qa 387 import oe.qa
454 388
455 #if this will throw an exception, then fix the dict above 389 #if this will throw an exception, then fix the dict above
456 target_os = bb.data.getVar('TARGET_OS', d, True) 390 target_os = bb.data.getVar('TARGET_OS', d, True)
457 target_arch = bb.data.getVar('TARGET_ARCH', d, True) 391 target_arch = bb.data.getVar('TARGET_ARCH', d, True)
458 392
459 sane = True 393 warnings = []
394 errors = []
460 for root, dirs, files in os.walk(path): 395 for root, dirs, files in os.walk(path):
461 for file in files: 396 for file in files:
462 path = os.path.join(root,file) 397 path = os.path.join(root,file)
@@ -465,11 +400,19 @@ def package_qa_walk(path, funcs, package,d):
465 elf.open() 400 elf.open()
466 except: 401 except:
467 elf = None 402 elf = None
468 for func in funcs: 403 for func in warnfuncs:
469 if not func(path, package,d, elf): 404 func(path, package, d, elf, warnings)
470 sane = False 405 for func in errorfuncs:
406 func(path, package, d, elf, errors)
471 407
472 return sane 408 for w in warnings:
409 bb.warn("QA Issue: %s" % w)
410 package_qa_write_error(w, d)
411 for e in errors:
412 bb.error("QA Issue: %s" % e)
413 package_qa_write_error(e, d)
414
415 return len(errors) == 0
473 416
474def package_qa_check_rdepends(pkg, pkgdest, d): 417def package_qa_check_rdepends(pkg, pkgdest, d):
475 sane = True 418 sane = True
@@ -498,7 +441,7 @@ def package_qa_check_rdepends(pkg, pkgdest, d):
498 for rdepend in rdepends: 441 for rdepend in rdepends:
499 if "-dbg" in rdepend: 442 if "-dbg" in rdepend:
500 error_msg = "%s rdepends on %s" % (pkgname,rdepend) 443 error_msg = "%s rdepends on %s" % (pkgname,rdepend)
501 sane = package_qa_handle_error(2, error_msg, pkgname, rdepend, d) 444 sane = package_qa_handle_error("debug-deps", error_msg, d)
502 445
503 return sane 446 return sane
504 447
@@ -534,11 +477,18 @@ python do_package_qa () {
534 if not packages: 477 if not packages:
535 return 478 return
536 479
537 checks = [package_qa_check_rpath, package_qa_check_dev, 480 testmatrix = d.getVarFlags("QAPATHTEST")
538 package_qa_check_perm, package_qa_check_arch, 481
539 package_qa_check_desktop, package_qa_hash_style, 482 g = globals()
540 package_qa_check_dbg] 483 warnchecks = []
541 # package_qa_check_buildpaths, 484 for w in (d.getVar("WARN_QA", True) or "").split():
485 if w in testmatrix and testmatrix[w] in g:
486 warnchecks.append(g[testmatrix[w]])
487 errorchecks = []
488 for e in (d.getVar("ERROR_QA", True) or "").split():
489 if e in testmatrix and testmatrix[e] in g:
490 errorchecks.append(g[testmatrix[e]])
491
542 walk_sane = True 492 walk_sane = True
543 rdepends_sane = True 493 rdepends_sane = True
544 for package in packages.split(): 494 for package in packages.split():
@@ -548,7 +498,7 @@ python do_package_qa () {
548 498
549 bb.note("Checking Package: %s" % package) 499 bb.note("Checking Package: %s" % package)
550 path = "%s/%s" % (pkgdest, package) 500 path = "%s/%s" % (pkgdest, package)
551 if not package_qa_walk(path, checks, package, d): 501 if not package_qa_walk(path, warnchecks, errorchecks, package, d):
552 walk_sane = False 502 walk_sane = False
553 if not package_qa_check_rdepends(package, pkgdest, d): 503 if not package_qa_check_rdepends(package, pkgdest, d):
554 rdepends_sane = False 504 rdepends_sane = False