diff options
Diffstat (limited to 'meta/lib/oeqa/selftest/cases/reproducible.py')
-rw-r--r-- | meta/lib/oeqa/selftest/cases/reproducible.py | 77 |
1 files changed, 41 insertions, 36 deletions
diff --git a/meta/lib/oeqa/selftest/cases/reproducible.py b/meta/lib/oeqa/selftest/cases/reproducible.py index 0d0259477e..80e830136f 100644 --- a/meta/lib/oeqa/selftest/cases/reproducible.py +++ b/meta/lib/oeqa/selftest/cases/reproducible.py | |||
@@ -9,35 +9,13 @@ import bb.utils | |||
9 | import functools | 9 | import functools |
10 | import multiprocessing | 10 | import multiprocessing |
11 | import textwrap | 11 | import textwrap |
12 | import json | ||
13 | import unittest | ||
14 | import tempfile | 12 | import tempfile |
15 | import shutil | 13 | import shutil |
16 | import stat | 14 | import stat |
17 | import os | 15 | import os |
18 | import datetime | 16 | import datetime |
19 | 17 | ||
20 | # For sample packages, see: | ||
21 | # https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-0t7wr_oo/ | ||
22 | # https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-4s9ejwyp/ | ||
23 | # https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-haiwdlbr/ | ||
24 | # https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201127-hwds3mcl/ | ||
25 | # https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20201203-sua0pzvc/ | ||
26 | # (both packages/ and packages-excluded/) | ||
27 | |||
28 | # ruby-ri-docs, meson: | ||
29 | #https://autobuilder.yocto.io/pub/repro-fail/oe-reproducible-20210215-0_td9la2/packages/diff-html/ | ||
30 | exclude_packages = [ | 18 | exclude_packages = [ |
31 | 'glide', | ||
32 | 'go-dep', | ||
33 | 'go-helloworld', | ||
34 | 'go-runtime', | ||
35 | 'go_', | ||
36 | 'go-', | ||
37 | 'meson', | ||
38 | 'ovmf-shell-efi', | ||
39 | 'perf', | ||
40 | 'ruby-ri-docs' | ||
41 | ] | 19 | ] |
42 | 20 | ||
43 | def is_excluded(package): | 21 | def is_excluded(package): |
@@ -65,13 +43,14 @@ class CompareResult(object): | |||
65 | return (self.status, self.test) < (other.status, other.test) | 43 | return (self.status, self.test) < (other.status, other.test) |
66 | 44 | ||
67 | class PackageCompareResults(object): | 45 | class PackageCompareResults(object): |
68 | def __init__(self): | 46 | def __init__(self, exclusions): |
69 | self.total = [] | 47 | self.total = [] |
70 | self.missing = [] | 48 | self.missing = [] |
71 | self.different = [] | 49 | self.different = [] |
72 | self.different_excluded = [] | 50 | self.different_excluded = [] |
73 | self.same = [] | 51 | self.same = [] |
74 | self.active_exclusions = set() | 52 | self.active_exclusions = set() |
53 | exclude_packages.extend((exclusions or "").split()) | ||
75 | 54 | ||
76 | def add_result(self, r): | 55 | def add_result(self, r): |
77 | self.total.append(r) | 56 | self.total.append(r) |
@@ -118,8 +97,9 @@ def compare_file(reference, test, diffutils_sysroot): | |||
118 | result.status = SAME | 97 | result.status = SAME |
119 | return result | 98 | return result |
120 | 99 | ||
121 | def run_diffoscope(a_dir, b_dir, html_dir, **kwargs): | 100 | def run_diffoscope(a_dir, b_dir, html_dir, max_report_size=0, **kwargs): |
122 | return runCmd(['diffoscope', '--no-default-limits', '--exclude-directory-metadata', 'yes', '--html-dir', html_dir, a_dir, b_dir], | 101 | return runCmd(['diffoscope', '--no-default-limits', '--max-report-size', str(max_report_size), |
102 | '--exclude-directory-metadata', 'yes', '--html-dir', html_dir, a_dir, b_dir], | ||
123 | **kwargs) | 103 | **kwargs) |
124 | 104 | ||
125 | class DiffoscopeTests(OESelftestTestCase): | 105 | class DiffoscopeTests(OESelftestTestCase): |
@@ -149,10 +129,15 @@ class ReproducibleTests(OESelftestTestCase): | |||
149 | 129 | ||
150 | package_classes = ['deb', 'ipk', 'rpm'] | 130 | package_classes = ['deb', 'ipk', 'rpm'] |
151 | 131 | ||
132 | # Maximum report size, in bytes | ||
133 | max_report_size = 250 * 1024 * 1024 | ||
134 | |||
152 | # targets are the things we want to test the reproducibility of | 135 | # targets are the things we want to test the reproducibility of |
153 | targets = ['core-image-minimal', 'core-image-sato', 'core-image-full-cmdline', 'core-image-weston', 'world'] | 136 | targets = ['core-image-minimal', 'core-image-sato', 'core-image-full-cmdline', 'core-image-weston', 'world'] |
137 | |||
154 | # sstate targets are things to pull from sstate to potentially cut build/debugging time | 138 | # sstate targets are things to pull from sstate to potentially cut build/debugging time |
155 | sstate_targets = [] | 139 | sstate_targets = [] |
140 | |||
156 | save_results = False | 141 | save_results = False |
157 | if 'OEQA_DEBUGGING_SAVED_OUTPUT' in os.environ: | 142 | if 'OEQA_DEBUGGING_SAVED_OUTPUT' in os.environ: |
158 | save_results = os.environ['OEQA_DEBUGGING_SAVED_OUTPUT'] | 143 | save_results = os.environ['OEQA_DEBUGGING_SAVED_OUTPUT'] |
@@ -167,11 +152,29 @@ class ReproducibleTests(OESelftestTestCase): | |||
167 | 152 | ||
168 | def setUpLocal(self): | 153 | def setUpLocal(self): |
169 | super().setUpLocal() | 154 | super().setUpLocal() |
170 | needed_vars = ['TOPDIR', 'TARGET_PREFIX', 'BB_NUMBER_THREADS'] | 155 | needed_vars = [ |
156 | 'TOPDIR', | ||
157 | 'TARGET_PREFIX', | ||
158 | 'BB_NUMBER_THREADS', | ||
159 | 'BB_HASHSERVE', | ||
160 | 'OEQA_REPRODUCIBLE_TEST_PACKAGE', | ||
161 | 'OEQA_REPRODUCIBLE_TEST_TARGET', | ||
162 | 'OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS', | ||
163 | 'OEQA_REPRODUCIBLE_EXCLUDED_PACKAGES', | ||
164 | ] | ||
171 | bb_vars = get_bb_vars(needed_vars) | 165 | bb_vars = get_bb_vars(needed_vars) |
172 | for v in needed_vars: | 166 | for v in needed_vars: |
173 | setattr(self, v.lower(), bb_vars[v]) | 167 | setattr(self, v.lower(), bb_vars[v]) |
174 | 168 | ||
169 | if bb_vars['OEQA_REPRODUCIBLE_TEST_PACKAGE']: | ||
170 | self.package_classes = bb_vars['OEQA_REPRODUCIBLE_TEST_PACKAGE'].split() | ||
171 | |||
172 | if bb_vars['OEQA_REPRODUCIBLE_TEST_TARGET']: | ||
173 | self.targets = bb_vars['OEQA_REPRODUCIBLE_TEST_TARGET'].split() | ||
174 | |||
175 | if bb_vars['OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS']: | ||
176 | self.sstate_targets = bb_vars['OEQA_REPRODUCIBLE_TEST_SSTATE_TARGETS'].split() | ||
177 | |||
175 | self.extraresults = {} | 178 | self.extraresults = {} |
176 | self.extraresults.setdefault('reproducible.rawlogs', {})['log'] = '' | 179 | self.extraresults.setdefault('reproducible.rawlogs', {})['log'] = '' |
177 | self.extraresults.setdefault('reproducible', {}).setdefault('files', {}) | 180 | self.extraresults.setdefault('reproducible', {}).setdefault('files', {}) |
@@ -180,7 +183,7 @@ class ReproducibleTests(OESelftestTestCase): | |||
180 | self.extraresults['reproducible.rawlogs']['log'] += msg | 183 | self.extraresults['reproducible.rawlogs']['log'] += msg |
181 | 184 | ||
182 | def compare_packages(self, reference_dir, test_dir, diffutils_sysroot): | 185 | def compare_packages(self, reference_dir, test_dir, diffutils_sysroot): |
183 | result = PackageCompareResults() | 186 | result = PackageCompareResults(self.oeqa_reproducible_excluded_packages) |
184 | 187 | ||
185 | old_cwd = os.getcwd() | 188 | old_cwd = os.getcwd() |
186 | try: | 189 | try: |
@@ -219,12 +222,10 @@ class ReproducibleTests(OESelftestTestCase): | |||
219 | bb.utils.remove(tmpdir, recurse=True) | 222 | bb.utils.remove(tmpdir, recurse=True) |
220 | 223 | ||
221 | config = textwrap.dedent('''\ | 224 | config = textwrap.dedent('''\ |
222 | INHERIT += "reproducible_build" | ||
223 | PACKAGE_CLASSES = "{package_classes}" | 225 | PACKAGE_CLASSES = "{package_classes}" |
224 | INHIBIT_PACKAGE_STRIP = "1" | ||
225 | TMPDIR = "{tmpdir}" | 226 | TMPDIR = "{tmpdir}" |
226 | LICENSE_FLAGS_WHITELIST = "commercial" | 227 | LICENSE_FLAGS_ACCEPTED = "commercial" |
227 | DISTRO_FEATURES_append = ' systemd pam' | 228 | DISTRO_FEATURES:append = ' pam' |
228 | USERADDEXTENSION = "useradd-staticids" | 229 | USERADDEXTENSION = "useradd-staticids" |
229 | USERADD_ERROR_DYNAMIC = "skip" | 230 | USERADD_ERROR_DYNAMIC = "skip" |
230 | USERADD_UID_TABLES += "files/static-passwd" | 231 | USERADD_UID_TABLES += "files/static-passwd" |
@@ -242,7 +243,7 @@ class ReproducibleTests(OESelftestTestCase): | |||
242 | # mirror, forcing a complete build from scratch | 243 | # mirror, forcing a complete build from scratch |
243 | config += textwrap.dedent('''\ | 244 | config += textwrap.dedent('''\ |
244 | SSTATE_DIR = "${TMPDIR}/sstate" | 245 | SSTATE_DIR = "${TMPDIR}/sstate" |
245 | SSTATE_MIRRORS = "" | 246 | SSTATE_MIRRORS = "file://.*/.*-native.* http://sstate.yoctoproject.org/all/PATH;downloadfilename=PATH file://.*/.*-cross.* http://sstate.yoctoproject.org/all/PATH;downloadfilename=PATH" |
246 | ''') | 247 | ''') |
247 | 248 | ||
248 | self.logger.info("Building %s (sstate%s allowed)..." % (name, '' if use_sstate else ' NOT')) | 249 | self.logger.info("Building %s (sstate%s allowed)..." % (name, '' if use_sstate else ' NOT')) |
@@ -309,9 +310,13 @@ class ReproducibleTests(OESelftestTestCase): | |||
309 | self.copy_file(d.reference, '/'.join([save_dir, 'packages-excluded', strip_topdir(d.reference)])) | 310 | self.copy_file(d.reference, '/'.join([save_dir, 'packages-excluded', strip_topdir(d.reference)])) |
310 | self.copy_file(d.test, '/'.join([save_dir, 'packages-excluded', strip_topdir(d.test)])) | 311 | self.copy_file(d.test, '/'.join([save_dir, 'packages-excluded', strip_topdir(d.test)])) |
311 | 312 | ||
312 | if result.missing or result.different: | 313 | if result.different: |
313 | fails.append("The following %s packages are missing or different and not in exclusion list: %s" % | 314 | fails.append("The following %s packages are different and not in exclusion list:\n%s" % |
314 | (c, '\n'.join(r.test for r in (result.missing + result.different)))) | 315 | (c, '\n'.join(r.test for r in (result.different)))) |
316 | |||
317 | if result.missing and len(self.sstate_targets) == 0: | ||
318 | fails.append("The following %s packages are missing and not in exclusion list:\n%s" % | ||
319 | (c, '\n'.join(r.test for r in (result.missing)))) | ||
315 | 320 | ||
316 | # Clean up empty directories | 321 | # Clean up empty directories |
317 | if self.save_results: | 322 | if self.save_results: |
@@ -325,7 +330,7 @@ class ReproducibleTests(OESelftestTestCase): | |||
325 | # Copy jquery to improve the diffoscope output usability | 330 | # Copy jquery to improve the diffoscope output usability |
326 | self.copy_file(os.path.join(jquery_sysroot, 'usr/share/javascript/jquery/jquery.min.js'), os.path.join(package_html_dir, 'jquery.js')) | 331 | self.copy_file(os.path.join(jquery_sysroot, 'usr/share/javascript/jquery/jquery.min.js'), os.path.join(package_html_dir, 'jquery.js')) |
327 | 332 | ||
328 | run_diffoscope('reproducibleA', 'reproducibleB', package_html_dir, | 333 | run_diffoscope('reproducibleA', 'reproducibleB', package_html_dir, max_report_size=self.max_report_size, |
329 | native_sysroot=diffoscope_sysroot, ignore_status=True, cwd=package_dir) | 334 | native_sysroot=diffoscope_sysroot, ignore_status=True, cwd=package_dir) |
330 | 335 | ||
331 | if fails: | 336 | if fails: |