#!/usr/bin/env python3 """Generate igiRadio.xcodeproj using PBXFileSystemSynchronizedRootGroup.""" from pathlib import Path ROOT = Path(__file__).resolve().parent.parent PROJECT = "igiRadio" BUNDLE = "com.digiradio.igiRadio" def uid(n): # 24-char hex IDs (stable) import hashlib return hashlib.md5(f"igiRadio-{n}".encode()).hexdigest()[:24].upper() IDS = {k: uid(k) for k in [ "project", "main", "products", "app", "test", "app_product", "test_product", "sources", "resources", "fw_app", "fw_test", "test_sources", "test_fw", "sync_app", "sync_tests", "sync_exception", "proj_cfg", "app_cfg", "test_cfg", "dbg_proj", "rel_proj", "dbg_app", "rel_app", "dbg_test", "rel_test", "proxy", "dep", ]} pbx = f'''// !$*UTF8*$! {{ \tarchiveVersion = 1; \tclasses = {{ \t}}; \tobjectVersion = 77; \tobjects = {{ /* Begin PBXBuildFile section */ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ \t\t{IDS["proxy"]} /* PBXContainerItemProxy */ = {{ \t\t\tisa = PBXContainerItemProxy; \t\t\tcontainerPortal = {IDS["project"]} /* Project object */; \t\t\tproxyType = 1; \t\t\tremoteGlobalIDString = {IDS["app"]}; \t\t\tremoteInfo = {PROJECT}; \t\t}}; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ \t\t{IDS["app_product"]} /* {PROJECT}.app */ = {{isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = {PROJECT}.app; sourceTree = BUILT_PRODUCTS_DIR; }}; \t\t{IDS["test_product"]} /* {PROJECT}Tests.xctest */ = {{isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = {PROJECT}Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }}; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ \t\t{IDS["sync_exception"]} /* Exceptions for "{PROJECT}" folder in "{PROJECT}" target */ = {{ \t\t\tisa = PBXFileSystemSynchronizedBuildFileExceptionSet; \t\t\tmembershipExceptions = ( \t\t\t\tResources/Info.plist, \t\t\t); \t\t\ttarget = {IDS["app"]} /* {PROJECT} */; \t\t}}; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ \t\t{IDS["sync_app"]} /* {PROJECT} */ = {{ \t\t\tisa = PBXFileSystemSynchronizedRootGroup; \t\t\texceptions = ( \t\t\t\t{IDS["sync_exception"]} /* Exceptions for "{PROJECT}" folder in "{PROJECT}" target */, \t\t\t); \t\t\tpath = {PROJECT}; \t\t\tsourceTree = ""; \t\t}}; \t\t{IDS["sync_tests"]} /* {PROJECT}Tests */ = {{ \t\t\tisa = PBXFileSystemSynchronizedRootGroup; \t\t\tpath = Tests/{PROJECT}Tests; \t\t\tsourceTree = ""; \t\t}}; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ \t\t{IDS["fw_app"]} /* Frameworks */ = {{ \t\t\tisa = PBXFrameworksBuildPhase; \t\t\tbuildActionMask = 2147483647; \t\t\tfiles = ( \t\t\t); \t\t\trunOnlyForDeploymentPostprocessing = 0; \t\t}}; \t\t{IDS["test_fw"]} /* Frameworks */ = {{ \t\t\tisa = PBXFrameworksBuildPhase; \t\t\tbuildActionMask = 2147483647; \t\t\tfiles = ( \t\t\t); \t\t\trunOnlyForDeploymentPostprocessing = 0; \t\t}}; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ \t\t{IDS["products"]} /* Products */ = {{ \t\t\tisa = PBXGroup; \t\t\tchildren = ( \t\t\t\t{IDS["app_product"]} /* {PROJECT}.app */, \t\t\t\t{IDS["test_product"]} /* {PROJECT}Tests.xctest */, \t\t\t); \t\t\tname = Products; \t\t\tsourceTree = ""; \t\t}}; \t\t{IDS["main"]} = {{ \t\t\tisa = PBXGroup; \t\t\tchildren = ( \t\t\t\t{IDS["sync_app"]} /* {PROJECT} */, \t\t\t\t{IDS["sync_tests"]} /* {PROJECT}Tests */, \t\t\t\t{IDS["products"]} /* Products */, \t\t\t); \t\t\tsourceTree = ""; \t\t}}; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ \t\t{IDS["app"]} /* {PROJECT} */ = {{ \t\t\tisa = PBXNativeTarget; \t\t\tbuildConfigurationList = {IDS["app_cfg"]} /* Build configuration list for PBXNativeTarget "{PROJECT}" */; \t\t\tbuildPhases = ( \t\t\t\t{IDS["sources"]} /* Sources */, \t\t\t\t{IDS["fw_app"]} /* Frameworks */, \t\t\t\t{IDS["resources"]} /* Resources */, \t\t\t); \t\t\tbuildRules = ( \t\t\t); \t\t\tdependencies = ( \t\t\t); \t\t\tfileSystemSynchronizedGroups = ( \t\t\t\t{IDS["sync_app"]} /* {PROJECT} */, \t\t\t); \t\t\tname = {PROJECT}; \t\t\tproductName = {PROJECT}; \t\t\tproductReference = {IDS["app_product"]} /* {PROJECT}.app */; \t\t\tproductType = "com.apple.product-type.application"; \t\t}}; \t\t{IDS["test"]} /* {PROJECT}Tests */ = {{ \t\t\tisa = PBXNativeTarget; \t\t\tbuildConfigurationList = {IDS["test_cfg"]} /* Build configuration list for PBXNativeTarget "{PROJECT}Tests" */; \t\t\tbuildPhases = ( \t\t\t\t{IDS["test_sources"]} /* Sources */, \t\t\t\t{IDS["test_fw"]} /* Frameworks */, \t\t\t); \t\t\tbuildRules = ( \t\t\t); \t\t\tdependencies = ( \t\t\t\t{IDS["dep"]} /* PBXTargetDependency */, \t\t\t); \t\t\tfileSystemSynchronizedGroups = ( \t\t\t\t{IDS["sync_tests"]} /* {PROJECT}Tests */, \t\t\t); \t\t\tname = {PROJECT}Tests; \t\t\tproductName = {PROJECT}Tests; \t\t\tproductReference = {IDS["test_product"]} /* {PROJECT}Tests.xctest */; \t\t\tproductType = "com.apple.product-type.bundle.unit-test"; \t\t}}; /* End PBXNativeTarget section */ /* Begin PBXProject section */ \t\t{IDS["project"]} /* Project object */ = {{ \t\t\tisa = PBXProject; \t\t\tattributes = {{ \t\t\t\tBuildIndependentTargetsInParallel = 1; \t\t\t\tLastSwiftUpdateCheck = 2600; \t\t\t\tLastUpgradeCheck = 2600; \t\t\t\tTargetAttributes = {{ \t\t\t\t\t{IDS["app"]} = {{ \t\t\t\t\t\tCreatedOnToolsVersion = 26.0; \t\t\t\t\t}}; \t\t\t\t\t{IDS["test"]} = {{ \t\t\t\t\t\tCreatedOnToolsVersion = 26.0; \t\t\t\t\t\tTestTargetID = {IDS["app"]}; \t\t\t\t\t}}; \t\t\t\t}}; \t\t\t}}; \t\t\tbuildConfigurationList = {IDS["proj_cfg"]} /* Build configuration list for PBXProject "{PROJECT}" */; \t\t\tcompatibilityVersion = "Xcode 16.0"; \t\t\tdevelopmentRegion = en; \t\t\thasScannedForEncodings = 0; \t\t\tknownRegions = ( \t\t\t\ten, \t\t\t\tBase, \t\t\t); \t\t\tmainGroup = {IDS["main"]}; \t\t\tproductRefGroup = {IDS["products"]} /* Products */; \t\t\tprojectDirPath = ""; \t\t\tprojectRoot = ""; \t\t\ttargets = ( \t\t\t\t{IDS["app"]} /* {PROJECT} */, \t\t\t\t{IDS["test"]} /* {PROJECT}Tests */, \t\t\t); \t\t}}; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ \t\t{IDS["resources"]} /* Resources */ = {{ \t\t\tisa = PBXResourcesBuildPhase; \t\t\tbuildActionMask = 2147483647; \t\t\tfiles = ( \t\t\t); \t\t\trunOnlyForDeploymentPostprocessing = 0; \t\t}}; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ \t\t{IDS["sources"]} /* Sources */ = {{ \t\t\tisa = PBXSourcesBuildPhase; \t\t\tbuildActionMask = 2147483647; \t\t\tfiles = ( \t\t\t); \t\t\trunOnlyForDeploymentPostprocessing = 0; \t\t}}; \t\t{IDS["test_sources"]} /* Sources */ = {{ \t\t\tisa = PBXSourcesBuildPhase; \t\t\tbuildActionMask = 2147483647; \t\t\tfiles = ( \t\t\t); \t\t\trunOnlyForDeploymentPostprocessing = 0; \t\t}}; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ \t\t{IDS["dep"]} /* PBXTargetDependency */ = {{ \t\t\tisa = PBXTargetDependency; \t\t\ttarget = {IDS["app"]} /* {PROJECT} */; \t\t\ttargetProxy = {IDS["proxy"]} /* PBXContainerItemProxy */; \t\t}}; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ \t\t{IDS["dbg_proj"]} /* Debug */ = {{ \t\t\tisa = XCBuildConfiguration; \t\t\tbuildSettings = {{ \t\t\t\tALWAYS_SEARCH_USER_PATHS = NO; \t\t\t\tCLANG_ENABLE_MODULES = YES; \t\t\t\tCOPY_PHASE_STRIP = NO; \t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf; \t\t\t\tENABLE_TESTABILITY = YES; \t\t\t\tGCC_OPTIMIZATION_LEVEL = 0; \t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0; \t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; \t\t\t\tONLY_ACTIVE_ARCH = YES; \t\t\t\tSDKROOT = iphoneos; \t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; \t\t\t\tSWIFT_OPTIMIZATION_LEVEL = "-Onone"; \t\t\t}}; \t\t\tname = Debug; \t\t}}; \t\t{IDS["rel_proj"]} /* Release */ = {{ \t\t\tisa = XCBuildConfiguration; \t\t\tbuildSettings = {{ \t\t\t\tALWAYS_SEARCH_USER_PATHS = NO; \t\t\t\tCLANG_ENABLE_MODULES = YES; \t\t\t\tCOPY_PHASE_STRIP = NO; \t\t\t\tDEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; \t\t\t\tENABLE_NS_ASSERTIONS = NO; \t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0; \t\t\t\tMTL_ENABLE_DEBUG_INFO = NO; \t\t\t\tSDKROOT = iphoneos; \t\t\t\tSWIFT_COMPILATION_MODE = wholemodule; \t\t\t\tVALIDATE_PRODUCT = YES; \t\t\t}}; \t\t\tname = Release; \t\t}}; \t\t{IDS["dbg_app"]} /* Debug */ = {{ \t\t\tisa = XCBuildConfiguration; \t\t\tbuildSettings = {{ \t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; \t\t\t\tCODE_SIGN_STYLE = Automatic; \t\t\t\tCURRENT_PROJECT_VERSION = 1; \t\t\t\tENABLE_PREVIEWS = YES; \t\t\t\tGENERATE_INFOPLIST_FILE = NO; \t\t\t\tINFOPLIST_FILE = {PROJECT}/Resources/Info.plist; \t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0; \t\t\t\tLD_RUNPATH_SEARCH_PATHS = ( \t\t\t\t\t"$(inherited)", \t\t\t\t\t"@executable_path/Frameworks", \t\t\t\t); \t\t\t\tMARKETING_VERSION = 1.0; \t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = {BUNDLE}; \t\t\t\tPRODUCT_NAME = "$(TARGET_NAME)"; \t\t\t\tSDKROOT = iphoneos; \t\t\t\tSUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; \t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES; \t\t\t\tSWIFT_VERSION = 5.0; \t\t\t\tTARGETED_DEVICE_FAMILY = "1,2"; \t\t\t}}; \t\t\tname = Debug; \t\t}}; \t\t{IDS["rel_app"]} /* Release */ = {{ \t\t\tisa = XCBuildConfiguration; \t\t\tbuildSettings = {{ \t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; \t\t\t\tCODE_SIGN_STYLE = Automatic; \t\t\t\tCURRENT_PROJECT_VERSION = 1; \t\t\t\tENABLE_PREVIEWS = YES; \t\t\t\tGENERATE_INFOPLIST_FILE = NO; \t\t\t\tINFOPLIST_FILE = {PROJECT}/Resources/Info.plist; \t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0; \t\t\t\tLD_RUNPATH_SEARCH_PATHS = ( \t\t\t\t\t"$(inherited)", \t\t\t\t\t"@executable_path/Frameworks", \t\t\t\t); \t\t\t\tMARKETING_VERSION = 1.0; \t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = {BUNDLE}; \t\t\t\tPRODUCT_NAME = "$(TARGET_NAME)"; \t\t\t\tSDKROOT = iphoneos; \t\t\t\tSUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; \t\t\t\tSWIFT_EMIT_LOC_STRINGS = YES; \t\t\t\tSWIFT_VERSION = 5.0; \t\t\t\tTARGETED_DEVICE_FAMILY = "1,2"; \t\t\t}}; \t\t\tname = Release; \t\t}}; \t\t{IDS["dbg_test"]} /* Debug */ = {{ \t\t\tisa = XCBuildConfiguration; \t\t\tbuildSettings = {{ \t\t\t\tBUNDLE_LOADER = "$(TEST_HOST)"; \t\t\t\tCODE_SIGN_STYLE = Automatic; \t\t\t\tCURRENT_PROJECT_VERSION = 1; \t\t\t\tGENERATE_INFOPLIST_FILE = YES; \t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0; \t\t\t\tMARKETING_VERSION = 1.0; \t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = {BUNDLE}Tests; \t\t\t\tPRODUCT_NAME = "$(TARGET_NAME)"; \t\t\t\tSDKROOT = iphoneos; \t\t\t\tSUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; \t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO; \t\t\t\tSWIFT_VERSION = 5.0; \t\t\t\tTARGETED_DEVICE_FAMILY = "1,2"; \t\t\t\tTEST_HOST = "$(BUILT_PRODUCTS_DIR)/{PROJECT}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{PROJECT}"; \t\t\t}}; \t\t\tname = Debug; \t\t}}; \t\t{IDS["rel_test"]} /* Release */ = {{ \t\t\tisa = XCBuildConfiguration; \t\t\tbuildSettings = {{ \t\t\t\tBUNDLE_LOADER = "$(TEST_HOST)"; \t\t\t\tCODE_SIGN_STYLE = Automatic; \t\t\t\tCURRENT_PROJECT_VERSION = 1; \t\t\t\tGENERATE_INFOPLIST_FILE = YES; \t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 17.0; \t\t\t\tMARKETING_VERSION = 1.0; \t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = {BUNDLE}Tests; \t\t\t\tPRODUCT_NAME = "$(TARGET_NAME)"; \t\t\t\tSDKROOT = iphoneos; \t\t\t\tSUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; \t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO; \t\t\t\tSWIFT_VERSION = 5.0; \t\t\t\tTARGETED_DEVICE_FAMILY = "1,2"; \t\t\t\tTEST_HOST = "$(BUILT_PRODUCTS_DIR)/{PROJECT}.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/{PROJECT}"; \t\t\t}}; \t\t\tname = Release; \t\t}}; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ \t\t{IDS["proj_cfg"]} /* Build configuration list for PBXProject "{PROJECT}" */ = {{ \t\t\tisa = XCConfigurationList; \t\t\tbuildConfigurations = ( \t\t\t\t{IDS["dbg_proj"]} /* Debug */, \t\t\t\t{IDS["rel_proj"]} /* Release */, \t\t\t); \t\t\tdefaultConfigurationIsVisible = 0; \t\t\tdefaultConfigurationName = Release; \t\t}}; \t\t{IDS["app_cfg"]} /* Build configuration list for PBXNativeTarget "{PROJECT}" */ = {{ \t\t\tisa = XCConfigurationList; \t\t\tbuildConfigurations = ( \t\t\t\t{IDS["dbg_app"]} /* Debug */, \t\t\t\t{IDS["rel_app"]} /* Release */, \t\t\t); \t\t\tdefaultConfigurationIsVisible = 0; \t\t\tdefaultConfigurationName = Release; \t\t}}; \t\t{IDS["test_cfg"]} /* Build configuration list for PBXNativeTarget "{PROJECT}Tests" */ = {{ \t\t\tisa = XCConfigurationList; \t\t\tbuildConfigurations = ( \t\t\t\t{IDS["dbg_test"]} /* Debug */, \t\t\t\t{IDS["rel_test"]} /* Release */, \t\t\t); \t\t\tdefaultConfigurationIsVisible = 0; \t\t\tdefaultConfigurationName = Release; \t\t}}; /* End XCConfigurationList section */ \t}}; \trootObject = {IDS["project"]} /* Project object */; }} ''' out = ROOT / f"{PROJECT}.xcodeproj" / "project.pbxproj" out.parent.mkdir(parents=True, exist_ok=True) out.write_text(pbx) scheme_dir = ROOT / f"{PROJECT}.xcodeproj" / "xcshareddata" / "xcschemes" scheme_dir.mkdir(parents=True, exist_ok=True) scheme = f''' ''' (scheme_dir / f"{PROJECT}.xcscheme").write_text(scheme) print(f"Wrote {out}") if __name__ == "__main__": pass