diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 5081c323c..4dde40c37 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -3745,6 +3745,8 @@ def bump_commit( expected = dict(document) expected["source_commit"] = report.head new_text = _set_pin(text, document, "source_commit", report.head, "profiled_date") + if document.get("pin_follows"): + new_text, expected = _follow_config_reads(new_text, expected, document, report.head) if upstream_moves: expected["upstream_commit"] = report.upstream_head new_text = _set_pin( @@ -3801,6 +3803,28 @@ def cites_primary(report: ProfileReport) -> bool: return not parts or any(part.repo is None for part in parts) +def _follow_config_reads( + text: str, expected: dict, document: dict, head: str +) -> tuple[str, dict]: + """A config_reads entry read at the pin moves with a pin that follows the + branch tip: RetroPie installs advmame from the tip, so the build its + advmame.rc is read at is the pin itself.""" + pin = str(document.get("source_commit") or "") + reads = document.get("config_reads") or [] + if not pin or not any(isinstance(r, dict) and r.get("revision") == pin for r in reads): + return text, expected + text = re.sub( + r'^(\s*revision:\s*)(["\']?)' + re.escape(pin) + r"\2\s*$", + lambda m: f"{m.group(1)}{m.group(2)}{head}{m.group(2)}", + text, flags=re.M, + ) + expected = {**expected, "config_reads": [ + {**r, "revision": head} if isinstance(r, dict) and r.get("revision") == pin else r + for r in reads + ]} + return text, expected + + def _set_pin(text: str, document: dict, field: str, value: str, after: str) -> str: """Write *field* as *value*, replacing its line or adding one after *after*.""" current = document.get(field) diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index 476ce16fa..b021764a4 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -3399,6 +3399,40 @@ class TestBumpCommit(unittest.TestCase): self.assertTrue(bump_commit(self.path, report)) self.assertIn("newhead", self.path.read_text()) + def test_a_config_read_at_the_pin_follows_it(self): + # RetroPie reads advmame.rc at the build it installs, the pin: the + # config_reads revision is the pin, and moves with it. + pin = "a" * 40 + self.path.write_text( + SAMPLE.replace('profiled_date: "2026-03-29"\n', + f'profiled_date: "2026-03-29"\nsource_commit: "{pin}"\n', 1) + + "built_by: [retropie]\n" + + 'pin_follows: "RetroPie builds the branch tip"\n' + + "config_reads:\n" + + ' - file: "advmame.rc"\n' + + " platforms: [retropie]\n" + + f' revision: "{pin}"\n' + + ' source_ref: "a.c:10-12"\n' + + " - file: \"other.rc\"\n" + + " platforms: [emuelec]\n" + + f' revision: "{"b" * 40}"\n' + + ' source_ref: "a.c:10-12"\n', + encoding="utf-8", + ) + part = PartResult( + RefPart("a.c", 10, 12, "a.c:10-12"), "ANCHORED", None, 10, 12, [] + ) + head = "c" * 40 + report = ProfileReport( + name="p", repo="o/n", pin=pin, head=head, + entries=[EntryReport("a.bin", "a.c:10-12", "ANCHORED", [part])], + counts={"ANCHORED": 1}, + ) + self.assertTrue(bump_commit(self.path, report)) + document = yaml.safe_load(self.path.read_text(encoding="utf-8")) + self.assertEqual(document["source_commit"], head) + self.assertEqual([r["revision"] for r in document["config_reads"]], [head, "b" * 40]) + def test_refused_when_no_ref_reads_the_pinned_repository(self): """gam4980: every bare libretro.c ref anchored in upstream, and the bump wrote the fork's HEAD over refs that never described it."""