diff --git a/schemas/emulator.schema.json b/schemas/emulator.schema.json index 99e8e178..23c3356c 100644 --- a/schemas/emulator.schema.json +++ b/schemas/emulator.schema.json @@ -912,6 +912,10 @@ "type": "string", "description": "Why source_commit is held on purpose rather than followed. The profile is then judged against its own revision, like one pinned to a superseded tag: comparing it to HEAD says nothing and recaling would repoint its refs at code the build it documents never had." }, + "upstream_frozen": { + "type": "string", + "description": "Why upstream_commit is held on purpose rather than followed: the port vendors that upstream tree, synced to that release, or merged that commit. The upstream view is judged against its own revision and a bump leaves it, the way pin_frozen holds source_commit." + }, "version_source": { "type": "object", "additionalProperties": false, diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 4868bca7..1fb9098e 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -1136,7 +1136,20 @@ def select_views( continue seen.add((repo.host, repo.slug)) views.append(RepoView(repo, pin, head, origin, field)) - return _follow_fork_base(_follow_submodule(views, cache_dir, offline), cache_dir, offline) + views = _follow_fork_base(_follow_submodule(views, cache_dir, offline), cache_dir, offline) + return _hold_upstream(profile, views) + + +def _hold_upstream(profile: dict, views: list[RepoView]) -> list[RepoView]: + """An upstream tree the port vendors or synced to is judged at that + revision: aps3e carries RPCS3 1f080485, yaps2 PCSX2 342db515.""" + if not str(profile.get("upstream_frozen") or "").strip(): + return views + return [ + replace(view, head=view.pin, origin=f"{view.origin}, held") + if view.field == "upstream" else view + for view in views + ] def _follow_submodule( diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index 202e75e0..6abc5471 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -4912,6 +4912,20 @@ class UpstreamVendoredAsASubmodule(unittest.TestCase): self.assertEqual(views[1].head, "nesbox-tip") +class AHeldUpstreamStaysOnItsPin(unittest.TestCase): + """aps3e vendors RPCS3 1f080485 and yaps2 PCSX2 342db515: a bump moved + upstream_commit to the upstream HEAD neither port carries.""" + + def test_the_upstream_view_is_read_at_its_pin(self): + views = [ + profile_sync.RepoView("fork", "p", "h", "source_commit", "source"), + profile_sync.RepoView("up", "vendored", "tip", "upstream_commit", "upstream"), + ] + held = profile_sync._hold_upstream({"upstream_frozen": "vendored tree"}, views) + self.assertEqual((held[0].head, held[1].head), ("h", "vendored")) + self.assertEqual(profile_sync._hold_upstream({}, views), views) + + class RealignReadsThePathAsWritten(unittest.TestCase): """hatarib cites hatari/src/tos.c, a path of hatariB. When only upstream_commit moved, realign stripped the hatari/ prefix, read