summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Solverv.xcodeproj/project.pbxproj39
-rw-r--r--scripts/update_pbxproj.py210
2 files changed, 80 insertions, 169 deletions
diff --git a/Solverv.xcodeproj/project.pbxproj b/Solverv.xcodeproj/project.pbxproj
index f5e3e64..b30d03f 100644
--- a/Solverv.xcodeproj/project.pbxproj
+++ b/Solverv.xcodeproj/project.pbxproj
@@ -7,19 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
- 0602B5968563FDCC6AAE214B /* SolsticeEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53B1F64353769F3F3D52DCC /* SolsticeEvent.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, ); }; };
- 58EC7B50BC5232D031299280 /* SolsticeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */; };
- 594A94559E2251F892BC158B /* SunTimes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */; };
- 63374A5CD6AAFBBA4A5E87AC /* AppGroupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */; };
- 6FFB4853DA8AF00282F20F96 /* AppGroupManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */; };
- 90AEA7599D196072837AE994 /* SunTimes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */; };
- A4D1E5F62BE4C16BF9C35920 /* Season.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAAD0F6249013EFDE6CF3BDB /* Season.swift */; };
- BDE41CA8E12EF58194F0FB28 /* Season.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAAD0F6249013EFDE6CF3BDB /* Season.swift */; };
- C1829841EA43782BD52878E9 /* SolsticeEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */; };
- DB32B658D259B49C522786C8 /* SolsticeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -51,11 +41,6 @@
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; };
1B8629D72EF0C656005A1C75 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
- 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupManager.swift; sourceTree = "<group>"; };
- 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolsticeData.swift; sourceTree = "<group>"; };
- 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SunTimes.swift; sourceTree = "<group>"; };
- A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SolsticeEvent.swift; sourceTree = "<group>"; };
- BAAD0F6249013EFDE6CF3BDB /* Season.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Season.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
@@ -69,6 +54,12 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
+ 67F6206475CCCE6E27C0A963 /* Shared */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = Shared;
+ sourceTree = "<group>";
+ };
+
1B8629C12EF0C636005A1C75 /* Solverv */ = {
isa = PBXFileSystemSynchronizedRootGroup;
path = Solverv;
@@ -107,6 +98,7 @@
1B8629B62EF0C636005A1C75 = {
isa = PBXGroup;
children = (
+ 67F6206475CCCE6E27C0A963 /* Shared */,
1B8629C12EF0C636005A1C75 /* Solverv */,
1B8629D92EF0C656005A1C75 /* Solsnu.Widget */,
1B8629D42EF0C656005A1C75 /* Frameworks */,
@@ -136,11 +128,6 @@
1BC006B72FABC8FE009BB0E6 /* Recovered References */ = {
isa = PBXGroup;
children = (
- BAAD0F6249013EFDE6CF3BDB /* Season.swift */,
- A53B1F64353769F3F3D52DCC /* SolsticeEvent.swift */,
- 56A3A45E5A25BDBCC47A23EC /* SolsticeData.swift */,
- 3B12784AD1DE5013F9E3B677 /* AppGroupManager.swift */,
- 5C4C2D0816DA7D3E6E6A4358 /* SunTimes.swift */,
);
name = "Recovered References";
sourceTree = "<group>";
@@ -163,6 +150,7 @@
1B8629E42EF0C657005A1C75 /* PBXTargetDependency */,
);
fileSystemSynchronizedGroups = (
+ 67F6206475CCCE6E27C0A963 /* Shared */,
1B8629C12EF0C636005A1C75 /* Solverv */,
);
name = Solverv;
@@ -185,6 +173,7 @@
dependencies = (
);
fileSystemSynchronizedGroups = (
+ 67F6206475CCCE6E27C0A963 /* Shared */,
1B8629D92EF0C656005A1C75 /* Solsnu.Widget */,
);
name = Solsnu.WidgetExtension;
@@ -254,11 +243,6 @@
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;
};
@@ -266,11 +250,6 @@
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;
};
diff --git a/scripts/update_pbxproj.py b/scripts/update_pbxproj.py
index b213f4e..d73697a 100644
--- a/scripts/update_pbxproj.py
+++ b/scripts/update_pbxproj.py
@@ -1,177 +1,109 @@
#!/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
+Replaces old-style PBXGroup+PBXFileReference approach for Shared/ with
+PBXFileSystemSynchronizedRootGroup (the Xcode 16 native approach).
-Run from the project root: python3 scripts/update_pbxproj.py
+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"
-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
-)
+# ── 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
+]
-# ── 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)
+# PBXFileReference UUIDs to remove
+file_ref_uids = [
+ "BAAD0F6249013EFDE6CF3BDB", # Season.swift
+ "A53B1F64353769F3F3D52DCC", # SolsticeEvent.swift
+ "56A3A45E5A25BDBCC47A23EC", # SolsticeData.swift
+ "3B12784AD1DE5013F9E3B677", # AppGroupManager.swift
+ "5C4C2D0816DA7D3E6E6A4358", # SunTimes.swift
+]
-# 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():]
+# PBXGroup UUIDs to remove
+group_uids = [
+ "0BFB6DC6E4F437012CF2990E", # Models
+ "5F48ADA595F6B3DE3DFE2A32", # Utilities
+ "0EEEC5869B3AB7A2A2154C10", # Shared
+]
-# ── 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)
+# ── 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)
-# ── 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)
+# ── 2. Remove PBXBuildFile entries ──
+for bu in all_build_uids:
+ 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)
+# ── 3. Remove PBXFileReference entries ──
+for ru in file_ref_uids:
+ 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)
+# ── 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)
-# ── 11. Add Shared group hierarchy ──
-models_grp_uid = uid()
-utils_grp_uid = uid()
-shared_grp_uid = uid()
+# ── 5. Remove Shared group from main project group children ──
+src = re.sub(r'\t{3,4}0EEEC5869B3AB7A2A2154C10\s*/\*[^*]*\*/,\n', '', src)
-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
-)
+# ── 6. Add PBXFileSystemSynchronizedRootGroup for Shared/ ──
+shared_sync_uid = uid()
-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'
+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 PBXGroup section */",
- "/* Begin PBXGroup section */\n" + new_groups,
+ "/* Begin PBXFileSystemSynchronizedRootGroup section */",
+ "/* Begin PBXFileSystemSynchronizedRootGroup section */\n" + new_sync_group,
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
+# ── 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
)
-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.")
+print(f"Done. New Shared synchronized root group UID: {shared_sync_uid}")
+print("Run: plutil -lint Solverv.xcodeproj/project.pbxproj")