diff options
Diffstat (limited to 'meta')
-rw-r--r-- | meta/classes/insane.bbclass | 216 |
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 | 94 | WARN_QA ?= "dev-so rpaths debug-deps debug-files arch la2 pkgconfig desktop la ldflags perms" |
95 | # 0 - non dev contains .so | 95 | ERROR_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 | ||
107 | def package_qa_clean_path(path,d): | 98 | def 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 | ||
111 | def package_qa_make_fatal_error(error_class, name, path,d): | 102 | def 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 | |||
120 | def 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 | ||
153 | def package_qa_handle_error(error_class, error_msg, name, path, d): | 110 | def 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 | ||
163 | def package_qa_check_rpath(file,name,d, elf): | 119 | QAPATHTEST[rpaths] = "package_qa_check_rpath" |
120 | def 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 | 143 | QAPATHTEST[dev-so] = "package_qa_check_dev" |
189 | 144 | def package_qa_check_dev(path, name, d, elf, messages): | |
190 | def 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 | 153 | QAPATHTEST[debug-files] = "package_qa_check_dbg" |
203 | 154 | def package_qa_check_dbg(path, name, d, elf, messages): | |
204 | def 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 | 164 | QAPATHTEST[perms] = "package_qa_check_perm" |
218 | 165 | def package_qa_check_perm(path,name,d, elf, messages): | |
219 | def 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 | ||
226 | def package_qa_check_arch(path,name,d, elf): | 171 | QAPATHTEST[arch] = "package_qa_check_arch" |
172 | def 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 | 207 | QAPATHTEST[desktop] = "package_qa_check_desktop" |
266 | 208 | def package_qa_check_desktop(path, name, d, elf, messages): | |
267 | def 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 | 219 | QAPATHTEST[ldflags] = "package_qa_hash_style" |
280 | 220 | def package_qa_hash_style(path, name, d, elf, messages): | |
281 | def 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 | ||
322 | def package_qa_check_buildpaths(path, name, d, elf): | 259 | QAPATHTEST[buildpaths] = "package_qa_check_buildpaths" |
260 | def 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 | ||
343 | def package_qa_check_license(workdir, d): | 277 | def 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 |
452 | def package_qa_walk(path, funcs, package,d): | 386 | def 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 | ||
474 | def package_qa_check_rdepends(pkg, pkgdest, d): | 417 | def 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 |