diff --git a/scripts/packextras.py b/scripts/packextras.py index 3be6f835..33d5d1bf 100644 --- a/scripts/packextras.py +++ b/scripts/packextras.py @@ -567,9 +567,14 @@ def _collect_emulator_extras( claimants: dict[tuple[str, str, str], str] | None = None, unplaceable: list[dict] | None = None, baseline_claims: dict[str, dict] | None = None, + absent: list[dict] | None = None, ) -> list[dict]: """Collect core requirement files from emulator profiles not in the platform pack. + ``absent`` receives, placed like the others, the entries the collection + does not hold: the region pass groups them as it groups the platform's + own missing files, so the report withdraws the ones a request excludes. + ``baseline_claims`` receives, for each destination in ``seen``, the core claims made on it: a pack built for a target that drops the platform's system frees the destination, and the first core claiming it fills it. @@ -628,7 +633,7 @@ def _collect_emulator_extras( for destination in seen: taken[destination] = baseline_claims.setdefault(destination, {}) for u in undeclared: - if not u["in_repo"]: + if not u["in_repo"] and absent is None: continue # For archive entries, use the archive name for resolution archive = u.get("archive") @@ -639,6 +644,10 @@ def _collect_emulator_extras( # Slug-based platforms: prefix dest with system slug placed = placement.place(u, dest) + if not u["in_repo"]: + if placed is not None: + absent.append(_report_extra(u, name, placed[0])) + continue if placed is None: if unplaceable is not None: unplaceable.append(u) @@ -894,6 +903,7 @@ def platform_region_groups( if not include_extras or db is None: return groups, extra_dests + absent: list[dict] = [] extras = _collect_emulator_extras( config, emulators_dir, @@ -904,8 +914,10 @@ def platform_region_groups( target_cores=target_cores, include_all=include_all, claimants=extra_dests, + absent=absent, ) - for extra in _kept(extras, required_only): + held = {id(extra) for extra in extras} + for extra in _kept(extras + absent, required_only): dest = sanitize_pack_path(extra.get("destination", extra.get("name", ""))) if not dest: continue @@ -924,7 +936,7 @@ def platform_region_groups( competes = not extra.get("agnostic_scan") or extra.get("region") for group_id in extra_region_groups(extra) if competes else (): groups.setdefault(group_id, []).append((dest, name)) - if extras_out is not None: + if extras_out is not None and id(extra) in held: extras_out.append(extra) return groups, extra_dests diff --git a/tests/test_region.py b/tests/test_region.py index 1ef17ae3..79736067 100644 --- a/tests/test_region.py +++ b/tests/test_region.py @@ -616,6 +616,38 @@ class TestReportAndBuilderNarrowTogether(unittest.TestCase): common._emulator_profiles_cache.clear() tmp.cleanup() + def test_a_missing_regional_core_file_is_withdrawn_too(self): + """A missing platform file is grouped and withdrawn under --region; a + missing core file was never grouped and stayed "required missing" + for a region the request excludes.""" + sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts")) + import common + import verify as reporter + + tmp, root, db, config = self._fixture() + try: + jp = next(k for k, v in db["files"].items() if v["name"] == "jp.bin") + del db["files"][jp] + del db["indexes"]["by_name"]["jp.bin"] + common._emulator_profiles_cache.clear() + profiles = common.load_emulator_profiles(str(root / "emulators")) + plain = reporter.verify_platform( + config, db, str(root / "emulators"), profiles, + supplemental_names=set(), + ) + narrowed = reporter.verify_platform( + config, db, str(root / "emulators"), profiles, + supplemental_names=set(), regions=["north-america"], + ) + missing = [u["name"] for u in plain["undeclared_files"] if not u["in_repo"]] + self.assertEqual(missing, ["jp.bin"]) + self.assertEqual( + {u["name"] for u in narrowed["undeclared_files"]}, {"us.bin"} + ) + finally: + common._emulator_profiles_cache.clear() + tmp.cleanup() + def test_one_grouping_pass_serves_both_sides(self): """A second hand-rolled grouping is how the two drifted apart.