#!/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 = "";\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")