Files
Gaze/.manage_sparkle.py
2026-01-13 17:49:05 -05:00

181 lines
8.4 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Safely add or remove Sparkle package from Xcode project
"""
import sys
import re
SPARKLE_REPO = "https://github.com/sparkle-project/Sparkle"
SPARKLE_VERSION = "2.8.1"
# Consistent IDs for Sparkle references
PKG_REF_ID = "27SPARKLE00000000001"
PKG_PROD_ID = "27SPARKLE00000000002"
BUILD_FILE_ID = "27SPARKLE00000000003"
def remove_sparkle(pbxproj_path):
"""Remove all Sparkle references from project.pbxproj"""
with open(pbxproj_path, 'r') as f:
content = f.read()
# Remove Sparkle from packageReferences array
content = re.sub(r'\t\t\t\t27SPARKLE\d+ /\* XCRemoteSwiftPackageReference "Sparkle" \*/,\n', '', content)
# Remove Sparkle from packageProductDependencies array
content = re.sub(r'\t\t\t\t27SPARKLE\d+ /\* Sparkle \*/,\n', '', content)
# Remove Sparkle from Frameworks build phase
content = re.sub(r'\t\t\t\t27SPARKLE\d+ /\* Sparkle in Frameworks \*/,\n', '', content)
# Remove PBXBuildFile section for Sparkle
content = re.sub(r'\t\t27SPARKLE\d+ /\* Sparkle in Frameworks \*/ = \{isa = PBXBuildFile; productRef = 27SPARKLE\d+ /\* Sparkle \*/; \};\n', '', content)
# Remove XCRemoteSwiftPackageReference section (multi-line)
# Match the entire block including nested braces
pattern = r'\t\t27SPARKLE\d+ /\* XCRemoteSwiftPackageReference "Sparkle" \*/ = \{[^}]*\{[^}]*\}[^}]*\};\n'
content = re.sub(pattern, '', content, flags=re.DOTALL)
# Remove XCSwiftPackageProductDependency section (multi-line)
pattern = r'\t\t27SPARKLE\d+ /\* Sparkle \*/ = \{[^}]*\};\n'
content = re.sub(pattern, '', content, flags=re.DOTALL)
with open(pbxproj_path, 'w') as f:
f.write(content)
print("✓ Removed Sparkle references from project.pbxproj")
return True
def add_sparkle(pbxproj_path):
"""Add Sparkle package to project.pbxproj"""
with open(pbxproj_path, 'r') as f:
content = f.read()
# Check if Sparkle package reference already fully exists (should have 9 references like Lottie)
sparkle_count = content.count('Sparkle')
if sparkle_count >= 9 and f'{PKG_REF_ID} /* XCRemoteSwiftPackageReference "Sparkle" */ =' in content:
print(" Sparkle already fully configured in project")
return True
# Check if partial Sparkle exists and clean it up first
if 'Sparkle' in content:
print(" Cleaning up partial Sparkle references...")
content = re.sub(r'\t\t27SPARKLE\d+ /\* XCRemoteSwiftPackageReference "Sparkle" \*/,\n', '', content)
content = re.sub(r'\t\t\t\t27SPARKLE\d+ /\* Sparkle \*/,\n', '', content)
content = re.sub(r'\t\t\t\t27SPARKLE\d+ /\* Sparkle in Frameworks \*/,\n', '', content)
content = re.sub(r'\t\t27SPARKLE\d+ /\* Sparkle in Frameworks \*/ = \{isa = PBXBuildFile; productRef = 27SPARKLE\d+ /\* Sparkle \*/; \};\n', '', content)
pattern = r'\t\t27SPARKLE\d+ /\* XCRemoteSwiftPackageReference "Sparkle" \*/ = \{[^}]+\};\n'
content = re.sub(pattern, '', content, flags=re.DOTALL)
pattern = r'\t\t27SPARKLE\d+ /\* Sparkle \*/ = \{[^}]+\};\n'
content = re.sub(pattern, '', content, flags=re.DOTALL)
# Write cleaned content back
with open(pbxproj_path, 'w') as f:
f.write(content)
print("✓ Cleaned up partial Sparkle references")
# Re-read for adding fresh references
with open(pbxproj_path, 'r') as f:
content = f.read()
# 1. Add PBXBuildFile for Sparkle (after Lottie, before End section)
pattern = r'(\t\t275915892F132A9200D0E60D /\* Lottie in Frameworks \*/ = \{isa = PBXBuildFile; productRef = 27AE10B12F10B1FC00E00DBC /\* Lottie \*/; \};\n)(/\* End PBXBuildFile section \*/)'
if re.search(pattern, content):
replacement = r'\1\t\t' + BUILD_FILE_ID + r' /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = ' + PKG_PROD_ID + r' /* Sparkle */; };' + '\n' + r'\2'
content = re.sub(pattern, replacement, content)
else:
print("⚠ Warning: Could not find PBXBuildFile insertion point")
# 2. Add Sparkle to Frameworks build phase (after Lottie)
pattern = r'(\t\t\t\t275915892F132A9200D0E60D /\* Lottie in Frameworks \*/,\n)'
if re.search(pattern, content):
replacement = r'\1\t\t\t\t' + BUILD_FILE_ID + r' /* Sparkle in Frameworks */,' + '\n'
content = re.sub(pattern, replacement, content)
else:
print("⚠ Warning: Could not find Frameworks build phase insertion point")
# 3. Add Sparkle to packageProductDependencies (after Lottie)
pattern = r'(packageProductDependencies = \(\n\t\t\t\t27AE10B12F10B1FC00E00DBC /\* Lottie \*/,\n)'
if re.search(pattern, content):
replacement = r'\1\t\t\t\t' + PKG_PROD_ID + r' /* Sparkle */,' + '\n'
content = re.sub(pattern, replacement, content)
else:
print("⚠ Warning: Could not find packageProductDependencies insertion point")
# 4. Add Sparkle to packageReferences (after Lottie)
pattern = r'(packageReferences = \(\n\t\t\t\t27AE10B02F10B1FC00E00DBC /\* XCRemoteSwiftPackageReference "lottie-spm" \*/,\n)'
if re.search(pattern, content):
replacement = r'\1\t\t\t\t' + PKG_REF_ID + r' /* XCRemoteSwiftPackageReference "Sparkle" */,' + '\n'
content = re.sub(pattern, replacement, content)
else:
print("⚠ Warning: Could not find packageReferences insertion point")
# 5. Add XCRemoteSwiftPackageReference section (after Lottie entry, before End section)
sparkle_ref = f'''\t\t{PKG_REF_ID} /* XCRemoteSwiftPackageReference "Sparkle" */ = {{
\t\t\tisa = XCRemoteSwiftPackageReference;
\t\t\trepositoryURL = "{SPARKLE_REPO}";
\t\t\trequirement = {{
\t\t\t\tkind = exactVersion;
\t\t\t\tversion = {SPARKLE_VERSION};
\t\t\t}};
\t\t}};
'''
# Insert after the Lottie package reference
pattern = r'(\t\t27AE10B02F10B1FC00E00DBC /\* XCRemoteSwiftPackageReference "lottie-spm" \*/ = \{\n\t\t\tisa = XCRemoteSwiftPackageReference;\n\t\t\trepositoryURL = "https://github\.com/airbnb/lottie-spm\.git";\n\t\t\trequirement = \{\n\t\t\t\tkind = upToNextMajorVersion;\n\t\t\t\tminimumVersion = [^;]+;\n\t\t\t\};\n\t\t\};\n)'
if re.search(pattern, content):
replacement = r'\1' + sparkle_ref
content = re.sub(pattern, replacement, content)
else:
print("⚠ Warning: Could not find XCRemoteSwiftPackageReference insertion point, trying fallback")
# Fallback: insert before End section
pattern = r'(/\* End XCRemoteSwiftPackageReference section \*/)'
replacement = sparkle_ref + r'\1'
content = re.sub(pattern, replacement, content)
# 6. Add XCSwiftPackageProductDependency section (after Lottie entry, before End section)
sparkle_prod = f'''\t\t{PKG_PROD_ID} /* Sparkle */ = {{
\t\t\tisa = XCSwiftPackageProductDependency;
\t\t\tpackage = {PKG_REF_ID} /* XCRemoteSwiftPackageReference "Sparkle" */;
\t\t\tproductName = Sparkle;
\t\t}};
'''
# Insert after the Lottie product dependency
pattern = r'(\t\t27AE10B12F10B1FC00E00DBC /\* Lottie \*/ = \{\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tpackage = 27AE10B02F10B1FC00E00DBC /\* XCRemoteSwiftPackageReference "lottie-spm" \*/;\n\t\t\tproductName = Lottie;\n\t\t\};\n)'
if re.search(pattern, content):
replacement = r'\1' + sparkle_prod
content = re.sub(pattern, replacement, content)
else:
print("⚠ Warning: Could not find XCSwiftPackageProductDependency insertion point, trying fallback")
# Fallback: insert before End section
pattern = r'(/\* End XCSwiftPackageProductDependency section \*/)'
replacement = sparkle_prod + r'\1'
content = re.sub(pattern, replacement, content)
with open(pbxproj_path, 'w') as f:
f.write(content)
print("✓ Added Sparkle references to project.pbxproj")
return True
if __name__ == '__main__':
if len(sys.argv) != 3:
print("Usage: .manage_sparkle.py [add|remove] <path/to/project.pbxproj>")
sys.exit(1)
action = sys.argv[1]
pbxproj_path = sys.argv[2]
try:
if action == 'add':
success = add_sparkle(pbxproj_path)
elif action == 'remove':
success = remove_sparkle(pbxproj_path)
else:
print(f"Unknown action: {action}")
sys.exit(1)
sys.exit(0 if success else 1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)