1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
#!/usr/bin/env python3
"""
Replaces old-style PBXGroup+PBXFileReference approach for Shared/ with
PBXFileSystemSynchronizedRootGroup (the Xcode 16 native approach).
Steps:
1. Remove explicit build file entries for all 5 shared files from both build phases
2. Remove explicit PBXBuildFile entries
3. Remove explicit PBXFileReference entries
4. Remove PBXGroup entries for Shared/Models/Utilities
5. Add a PBXFileSystemSynchronizedRootGroup for Shared/
6. Add it to both targets' fileSystemSynchronizedGroups lists
Run from project root: python3 scripts/update_pbxproj.py
"""
import re
import secrets
PROJ = "Solverv.xcodeproj/project.pbxproj"
def uid():
return secrets.token_hex(12).upper()
with open(PROJ) as f:
src = f.read()
# ── UUIDs to remove (explicit PBXBuildFile entries) ──
# Two per file: (main_app_uid, widget_uid)
build_file_uids = [
("A4D1E5F62BE4C16BF9C35920", "BDE41CA8E12EF58194F0FB28"), # Season.swift
("0602B5968563FDCC6AAE214B", "C1829841EA43782BD52878E9"), # SolsticeEvent.swift
("58EC7B50BC5232D031299280", "DB32B658D259B49C522786C8"), # SolsticeData.swift
("63374A5CD6AAFBBA4A5E87AC", "6FFB4853DA8AF00282F20F96"), # AppGroupManager.swift
("594A94559E2251F892BC158B", "90AEA7599D196072837AE994"), # SunTimes.swift
]
# PBXFileReference UUIDs to remove
file_ref_uids = [
"BAAD0F6249013EFDE6CF3BDB", # Season.swift
"A53B1F64353769F3F3D52DCC", # SolsticeEvent.swift
"56A3A45E5A25BDBCC47A23EC", # SolsticeData.swift
"3B12784AD1DE5013F9E3B677", # AppGroupManager.swift
"5C4C2D0816DA7D3E6E6A4358", # SunTimes.swift
]
# PBXGroup UUIDs to remove
group_uids = [
"0BFB6DC6E4F437012CF2990E", # Models
"5F48ADA595F6B3DE3DFE2A32", # Utilities
"0EEEC5869B3AB7A2A2154C10", # Shared
]
# ── 1. Remove explicit entries from both PBXSourcesBuildPhase sections ──
all_build_uids = [u for pair in build_file_uids for u in pair]
for bu in all_build_uids:
src = re.sub(r'\t{3,4}' + bu + r'\s*/\*[^*]*\*/,\n', '', src)
# ── 2. Remove PBXBuildFile entries ──
for bu in all_build_uids:
src = re.sub(r'\t\t' + bu + r'\s*/\*[^*]*\*/\s*=\s*\{[^}]*\};\n', '', src)
# ── 3. Remove PBXFileReference entries ──
for ru in file_ref_uids:
src = re.sub(r'\t\t' + ru + r'\s*/\*[^*]*\*/\s*=\s*\{[^}]*\};\n', '', src)
# ── 4. Remove PBXGroup entries for Shared/Models/Utilities ──
# These span multiple lines so we need a multi-line match
for gu in group_uids:
src = re.sub(r'\t\t' + gu + r'\s*/\*[^*]*\*/\s*=\s*\{[^}]*\};\n', '', src, flags=re.DOTALL)
# ── 5. Remove Shared group from main project group children ──
src = re.sub(r'\t{3,4}0EEEC5869B3AB7A2A2154C10\s*/\*[^*]*\*/,\n', '', src)
# ── 6. Add PBXFileSystemSynchronizedRootGroup for Shared/ ──
shared_sync_uid = uid()
new_sync_group = (
f'\t\t{shared_sync_uid} /* Shared */ = {{\n'
f'\t\t\tisa = PBXFileSystemSynchronizedRootGroup;\n'
f'\t\t\tpath = Shared;\n'
f'\t\t\tsourceTree = "<group>";\n'
f'\t\t}};\n'
)
src = src.replace(
"/* Begin PBXFileSystemSynchronizedRootGroup section */",
"/* Begin PBXFileSystemSynchronizedRootGroup section */\n" + new_sync_group,
1
)
# ── 7. Add shared_sync_uid to both targets' fileSystemSynchronizedGroups ──
# Main app target: 1B8629BE2EF0C636005A1C75
# Widget target: 1B8629D22EF0C656005A1C75
for target_uid, existing_sync in [
("1B8629BE2EF0C636005A1C75", "1B8629C12EF0C636005A1C75"), # Solverv → Solverv group
("1B8629D22EF0C656005A1C75", "1B8629D92EF0C656005A1C75"), # Widget → Solsnu.Widget group
]:
src = src.replace(
f'\t\t\t\t{existing_sync} /* ',
f'\t\t\t\t{shared_sync_uid} /* Shared */,\n\t\t\t\t{existing_sync} /* ',
1
)
with open(PROJ, "w") as f:
f.write(src)
print(f"Done. New Shared synchronized root group UID: {shared_sync_uid}")
print("Run: plutil -lint Solverv.xcodeproj/project.pbxproj")
|