diff options
| author | ivar <i@oiee.no> | 2026-05-06 21:21:04 +0200 |
|---|---|---|
| committer | ivar <i@oiee.no> | 2026-05-06 21:21:04 +0200 |
| commit | efae4d08083f454975f08a2c0c6871c6a3d41e95 (patch) | |
| tree | d7b47d02d446b13094d787e961a8737ba08a0b85 | |
| parent | 01eee1c4fe8252bffc9334e4bb2dbbc15f002835 (diff) | |
| download | solverv-efae4d08083f454975f08a2c0c6871c6a3d41e95.tar.xz solverv-efae4d08083f454975f08a2c0c6871c6a3d41e95.zip | |
feat: wire Shared/ files into both Xcode targets via pbxproj
| -rw-r--r-- | Solverv.xcodeproj/project.pbxproj | 60 | ||||
| -rw-r--r-- | scripts/update_pbxproj.py | 177 |
2 files changed, 235 insertions, 2 deletions
diff --git a/Solverv.xcodeproj/project.pbxproj b/Solverv.xcodeproj/project.pbxproj index acb1dd0..093609f 100644 --- a/Solverv.xcodeproj/project.pbxproj +++ b/Solverv.xcodeproj/project.pbxproj @@ -7,6 +7,17 @@ objects = { /* Begin PBXBuildFile section */ + A4D1E5F62BE4C16BF9C35920 /* Season.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAAD0F6249013EFDE6CF3BDB /* Season.swift */; }; + BDE41CA8E12EF58194F0FB28 /* Season.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAAD0F6249013EFDE6CF3BDB /* Season.swift */; }; + 0602B5968563FDCC6AAE214B /* SolsticeEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */; }; + C1829841EA43782BD52878E9 /* SolsticeEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */; }; + 58EC7B50BC5232D031299280 /* SolsticeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */; }; + DB32B658D259B49C522786C8 /* SolsticeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */; }; + 63374A5CD6AAFBBA4A5E87AC /* AppGroupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */; }; + 6FFB4853DA8AF00282F20F96 /* AppGroupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */; }; + 594A94559E2251F892BC158B /* SunTimes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */; }; + 90AEA7599D196072837AE994 /* SunTimes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */; }; + 1B8629D62EF0C656005A1C75 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B8629D52EF0C656005A1C75 /* WidgetKit.framework */; }; 1B8629D82EF0C656005A1C75 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B8629D72EF0C656005A1C75 /* SwiftUI.framework */; }; 1B8629E52EF0C657005A1C75 /* Solsnu.WidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 1B8629D32EF0C656005A1C75 /* Solsnu.WidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -37,6 +48,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + BAAD0F6249013EFDE6CF3BDB /* Season.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Season.swift; sourceTree = "<group>"; }; + A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolsticeEvent.swift; sourceTree = "<group>"; }; + 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolsticeData.swift; sourceTree = "<group>"; }; + 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupManager.swift; sourceTree = "<group>"; }; + 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SunTimes.swift; sourceTree = "<group>"; }; + 1B8629BF2EF0C636005A1C75 /* Solverv.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Solverv.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1B8629D32EF0C656005A1C75 /* Solsnu.WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Solsnu.WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 1B8629D52EF0C656005A1C75 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; @@ -89,6 +106,35 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 0BFB6DC6E4F437012CF2990E /* Models */ = { + isa = PBXGroup; + children = ( + BAAD0F6249013EFDE6CF3BDB /* Season.swift */, + A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */, + 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */, + ); + path = Models; + sourceTree = "<group>"; + }; + 5F48ADA595F6B3DE3DFE2A32 /* Utilities */ = { + isa = PBXGroup; + children = ( + 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */, + 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */, + ); + path = Utilities; + sourceTree = "<group>"; + }; + 0EEEC5869B3AB7A2A2154C10 /* Shared */ = { + isa = PBXGroup; + children = ( + 0BFB6DC6E4F437012CF2990E /* Models */, + 5F48ADA595F6B3DE3DFE2A32 /* Utilities */, + ); + path = Shared; + sourceTree = "<group>"; + }; + 1B8629B62EF0C636005A1C75 = { isa = PBXGroup; children = ( @@ -226,14 +272,24 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); + A4D1E5F62BE4C16BF9C35920 /* Season.swift in Sources */, + 0602B5968563FDCC6AAE214B /* SolsticeEvent.swift in Sources */, + 58EC7B50BC5232D031299280 /* SolsticeData.swift in Sources */, + 63374A5CD6AAFBBA4A5E87AC /* AppGroupManager.swift in Sources */, + 594A94559E2251F892BC158B /* SunTimes.swift in Sources */, +); runOnlyForDeploymentPostprocessing = 0; }; 1B8629CF2EF0C656005A1C75 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - ); + BDE41CA8E12EF58194F0FB28 /* Season.swift in Sources */, + C1829841EA43782BD52878E9 /* SolsticeEvent.swift in Sources */, + DB32B658D259B49C522786C8 /* SolsticeData.swift in Sources */, + 6FFB4853DA8AF00282F20F96 /* AppGroupManager.swift in Sources */, + 90AEA7599D196072837AE994 /* SunTimes.swift in Sources */, +); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ diff --git a/scripts/update_pbxproj.py b/scripts/update_pbxproj.py new file mode 100644 index 0000000..b213f4e --- /dev/null +++ b/scripts/update_pbxproj.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" +Updates Solverv.xcodeproj/project.pbxproj to: + - Add Shared/{Models,Utilities} file references for 5 shared files + - Add those files to both targets' PBXSourcesBuildPhase + - Remove old duplicate file references and build entries from both targets + - Add a Shared group in the project navigator + +Run from the project root: python3 scripts/update_pbxproj.py +""" +import re +import secrets + +PROJ = "Solverv.xcodeproj/project.pbxproj" + +MODELS_FILES = ["Season.swift", "SolsticeEvent.swift", "SolsticeData.swift"] +UTIL_FILES = ["AppGroupManager.swift", "SunTimes.swift"] +ALL_FILES = MODELS_FILES + UTIL_FILES + +def uid(): + return secrets.token_hex(12).upper() + +with open(PROJ) as f: + src = f.read() + +# ── 1. Find existing file-reference UUIDs (expect 2 per name: one per target) ── +old_ref_uids = {} +for name in ALL_FILES: + pat = r'([0-9A-Fa-f]{24})\s*/\*\s*' + re.escape(name) + r'\s*\*/' + found = re.findall(pat, src) + old_ref_uids[name] = [u.upper() for u in found] + if len(found) != 2: + print(f"WARNING: expected 2 PBXFileReference entries for {name}, found {len(found)}: {found}") + +# ── 2. Find existing build-file UUIDs (expect 2 per name: one per target) ── +old_build_uids = {} +for name in ALL_FILES: + pat = r'([0-9A-Fa-f]{24})\s*/\*\s*' + re.escape(name) + r'\s+in\s+Sources\s*\*/' + found = re.findall(pat, src) + old_build_uids[name] = [u.upper() for u in found] + if len(found) != 2: + print(f"WARNING: expected 2 PBXBuildFile entries for {name}, found {len(found)}: {found}") + +# ── 3. Generate new UUIDs ── +new_ref_uid = {name: uid() for name in ALL_FILES} +new_build_uid = {name: [uid(), uid()] for name in ALL_FILES} # [target0, target1] + +# ── 4. Insert new PBXFileReference entries ── +new_refs = "\n".join( + f'\t\t{new_ref_uid[name]} /* {name} */ = ' + f'{{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; ' + f'path = {name}; sourceTree = "<group>"; }};' + for name in ALL_FILES +) + "\n" + +src = src.replace( + "/* Begin PBXFileReference section */", + "/* Begin PBXFileReference section */\n" + new_refs, + 1 +) + +# ── 5. Insert new PBXBuildFile entries ── +new_builds = "\n".join( + f'\t\t{new_build_uid[name][i]} /* {name} in Sources */ = ' + f'{{isa = PBXBuildFile; fileRef = {new_ref_uid[name]} /* {name} */; }};' + for name in ALL_FILES + for i in range(2) +) + "\n" + +src = src.replace( + "/* Begin PBXBuildFile section */", + "/* Begin PBXBuildFile section */\n" + new_builds, + 1 +) + +# ── 6. Add new build files to both PBXSourcesBuildPhase sections ── +phases = list(re.finditer( + r'(isa = PBXSourcesBuildPhase;.*?files = \()(.*?)(\);)', + src, re.DOTALL +)) +if len(phases) != 2: + print(f"ERROR: expected 2 PBXSourcesBuildPhase, found {len(phases)}. Aborting.") + exit(1) + +# Replace in reverse order so offsets stay valid +for i, phase in reversed(list(enumerate(phases))): + additions = "".join( + f'\t\t\t\t{new_build_uid[name][i]} /* {name} in Sources */,\n' + for name in ALL_FILES + ) + new_phase = phase.group(1) + phase.group(2) + additions + phase.group(3) + src = src[:phase.start()] + new_phase + src[phase.end():] + +# ── 7. Remove old build-file entries from PBXSourcesBuildPhase ── +for name in ALL_FILES: + for bu in old_build_uids[name]: + src = re.sub(r'\t{3,4}' + bu + r'\s*/\*[^*]*\*/,\n', '', src) + +# ── 8. Remove old PBXBuildFile entries ── +for name in ALL_FILES: + for bu in old_build_uids[name]: + src = re.sub(r'\t\t' + bu + r'\s*/\*[^*]*\*/\s*=\s*\{[^}]*\};\n', '', src) + +# ── 9. Remove old PBXFileReference entries ── +for name in ALL_FILES: + for ru in old_ref_uids[name]: + src = re.sub(r'\t\t' + ru + r'\s*/\*[^*]*\*/\s*=\s*\{[^}]*\};\n', '', src) + +# ── 10. Remove old file refs from PBXGroup children ── +for name in ALL_FILES: + for ru in old_ref_uids[name]: + src = re.sub(r'\t{3,4}' + ru + r'\s*/\*[^*]*\*/,\n', '', src) + +# ── 11. Add Shared group hierarchy ── +models_grp_uid = uid() +utils_grp_uid = uid() +shared_grp_uid = uid() + +models_children = "".join( + f'\t\t\t\t{new_ref_uid[n]} /* {n} */,\n' for n in MODELS_FILES +) +utils_children = "".join( + f'\t\t\t\t{new_ref_uid[n]} /* {n} */,\n' for n in UTIL_FILES +) + +new_groups = ( + f'\t\t{models_grp_uid} /* Models */ = {{\n' + f'\t\t\tisa = PBXGroup;\n' + f'\t\t\tchildren = (\n' + f'{models_children}' + f'\t\t\t);\n' + f'\t\t\tpath = Models;\n' + f'\t\t\tsourceTree = "<group>";\n' + f'\t\t}};\n' + f'\t\t{utils_grp_uid} /* Utilities */ = {{\n' + f'\t\t\tisa = PBXGroup;\n' + f'\t\t\tchildren = (\n' + f'{utils_children}' + f'\t\t\t);\n' + f'\t\t\tpath = Utilities;\n' + f'\t\t\tsourceTree = "<group>";\n' + f'\t\t}};\n' + f'\t\t{shared_grp_uid} /* Shared */ = {{\n' + f'\t\t\tisa = PBXGroup;\n' + f'\t\t\tchildren = (\n' + f'\t\t\t\t{models_grp_uid} /* Models */,\n' + f'\t\t\t\t{utils_grp_uid} /* Utilities */,\n' + f'\t\t\t);\n' + f'\t\t\tpath = Shared;\n' + f'\t\t\tsourceTree = "<group>";\n' + f'\t\t}};\n' +) + +src = src.replace( + "/* Begin PBXGroup section */", + "/* Begin PBXGroup section */\n" + new_groups, + 1 +) + +# Add Shared group as child of the main project group +main_grp_match = re.search(r'mainGroup = ([0-9A-Fa-f]{24})', src) +if main_grp_match: + main_grp_uid = main_grp_match.group(1).upper() + # Find that group's children list and prepend the Shared group + src = re.sub( + r'(' + main_grp_uid + r'\s*/\*[^*]*\*/\s*=\s*\{[^{]*isa = PBXGroup;[^{]*children = \()', + r'\1\n\t\t\t\t' + shared_grp_uid + r' /* Shared */,', + src + ) +else: + print("WARNING: could not find mainGroup — add Shared group manually in Xcode") + +with open(PROJ, "w") as f: + f.write(src) + +print("project.pbxproj updated.") +print("Open Xcode and verify the Shared group appears with all 5 files under both targets.") |
