#!/usr/bin/env python3 from pathlib import Path import uuid ROOT = Path(__file__).parent APP_DIR = ROOT / "MatchLiveTv" TEST_DIR = ROOT / "MatchLiveTvTests" OUT = ROOT / "MatchLiveTv.xcodeproj" / "project.pbxproj" def uid(): return uuid.uuid4().hex[:24].upper() app_files = sorted(APP_DIR.rglob("*.swift")) test_files = sorted(TEST_DIR.rglob("*.swift")) ids = {f: uid() for f in app_files + test_files} bf = {f: uid() for f in app_files + test_files} assets_ref, assets_bf = uid(), uid() info_ref = uid() app_product, test_product = uid(), uid() app_target, test_target = uid(), uid() app_sources, app_frameworks, app_resources = uid(), uid(), uid() test_sources, test_frameworks = uid(), uid() main_group, app_group, test_group, products_group = uid(), uid(), uid(), uid() proj = uid() pkg = uid() hk, rtmp = uid(), uid() hk_bf, rtmp_bf = uid(), uid() bcl_proj_dbg, bcl_proj_rel = uid(), uid() bcl_app_dbg, bcl_app_rel = uid(), uid() bcl_test_dbg, bcl_test_rel = uid(), uid() cfg_app_dbg, cfg_app_rel = uid(), uid() cfg_test_dbg, cfg_test_rel = uid(), uid() cfg_proj_dbg, cfg_proj_rel = uid(), uid() bcl_app, bcl_test, bcl_proj = uid(), uid(), uid() test_dep, test_dep_proxy = uid(), uid() scheme_id = uid() lines = [ "// !$*UTF8*$!", "{", "\tarchiveVersion = 1;", "\tclasses = {};", "\tobjectVersion = 60;", "\tobjects = {", ] for f, fid in ids.items(): lines.append(f'\t\t{fid} /* {f.name} */ = {{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = {f.name}; path = {f.relative_to(ROOT)}; sourceTree = ""; }};') lines += [ f'\t\t{assets_ref} /* Assets.xcassets */ = {{isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MatchLiveTv/Resources/Assets.xcassets; sourceTree = ""; }};', f'\t\t{info_ref} /* Info.plist */ = {{isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MatchLiveTv/Resources/Info.plist; sourceTree = ""; }};', f'\t\t{app_product} /* MatchLiveTv.app */ = {{isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MatchLiveTv.app; sourceTree = BUILT_PRODUCTS_DIR; }};', f'\t\t{test_product} /* MatchLiveTvTests.xctest */ = {{isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatchLiveTvTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }};', f'\t\t{hk} /* HaishinKit */ = {{isa = XCSwiftPackageProductDependency; package = {pkg}; productName = HaishinKit; }};', f'\t\t{rtmp} /* RTMPHaishinKit */ = {{isa = XCSwiftPackageProductDependency; package = {pkg}; productName = RTMPHaishinKit; }};', ] for f, bid in bf.items(): lines.append(f'\t\t{bid} /* {f.name} in Sources */ = {{isa = PBXBuildFile; fileRef = {ids[f]} /* {f.name} */; }};') lines += [ f'\t\t{assets_bf} /* Assets in Resources */ = {{isa = PBXBuildFile; fileRef = {assets_ref}; }};', ] app_children = ", ".join(ids[f] for f in app_files) + f", {assets_ref}, {info_ref}" test_children = ", ".join(ids[f] for f in test_files) lines += [ f'\t\t{main_group} = {{isa = PBXGroup; children = ({app_group}, {test_group}, {products_group}); sourceTree = ""; }};', f'\t\t{app_group} = {{isa = PBXGroup; children = ({app_children}); name = MatchLiveTv; sourceTree = ""; }};', f'\t\t{test_group} = {{isa = PBXGroup; children = ({test_children}); name = MatchLiveTvTests; sourceTree = ""; }};', f'\t\t{products_group} = {{isa = PBXGroup; children = ({app_product}, {test_product}); name = Products; sourceTree = ""; }};', f'\t\t{app_sources} = {{isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ({", ".join(bf[f] for f in app_files)}); runOnlyForDeploymentPostprocessing = 0; }};', f'\t\t{test_sources} = {{isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ({", ".join(bf[f] for f in test_files) if test_files else ""}); runOnlyForDeploymentPostprocessing = 0; }};', f'\t\t{app_resources} = {{isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ({assets_bf}); runOnlyForDeploymentPostprocessing = 0; }};', f'\t\t{app_frameworks} = {{isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; }};', f'\t\t{test_frameworks} = {{isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; }};', ] app_settings = """ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 21; GENERATE_INFOPLIST_FILE = NO; INFOPLIST_FILE = MatchLiveTv/Resources/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 16.0; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SWIFT_ENABLE_EXPLICIT_MODULES = NO; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.matchlivetv.match-live-tv; PRODUCT_NAME = "$(TARGET_NAME)"; API_BASE_URL = "https://www.matchlivetv.it"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; """ app_debug_settings = app_settings + """ ENABLE_TESTABILITY = YES; """ test_settings = """ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 21; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 16.0; MARKETING_VERSION = 2.0.0; PRODUCT_BUNDLE_IDENTIFIER = com.matchlivetv.match-live-tv.tests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/MatchLiveTv.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MatchLiveTv"; """ lines += [ f'\t\t{cfg_app_dbg} = {{isa = XCBuildConfiguration; buildSettings = {{{app_debug_settings}\t\t\t}}; name = Debug; }};', f'\t\t{cfg_app_rel} = {{isa = XCBuildConfiguration; buildSettings = {{{app_settings}\t\t\t}}; name = Release; }};', f'\t\t{cfg_test_dbg} = {{isa = XCBuildConfiguration; buildSettings = {{{test_settings}\t\t\t}}; name = Debug; }};', f'\t\t{cfg_test_rel} = {{isa = XCBuildConfiguration; buildSettings = {{{test_settings}\t\t\t}}; name = Release; }};', f'\t\t{cfg_proj_dbg} = {{isa = XCBuildConfiguration; buildSettings = {{IPHONEOS_DEPLOYMENT_TARGET = 16.0; SWIFT_VERSION = 5.0; }}; name = Debug; }};', f'\t\t{cfg_proj_rel} = {{isa = XCBuildConfiguration; buildSettings = {{IPHONEOS_DEPLOYMENT_TARGET = 16.0; SWIFT_VERSION = 5.0; }}; name = Release; }};', f'\t\t{bcl_app} = {{isa = XCConfigurationList; buildConfigurations = ({cfg_app_dbg}, {cfg_app_rel}); defaultConfigurationName = Release; }};', f'\t\t{bcl_test} = {{isa = XCConfigurationList; buildConfigurations = ({cfg_test_dbg}, {cfg_test_rel}); defaultConfigurationName = Release; }};', f'\t\t{bcl_proj} = {{isa = XCConfigurationList; buildConfigurations = ({cfg_proj_dbg}, {cfg_proj_rel}); defaultConfigurationName = Release; }};', f'\t\t{app_target} = {{isa = PBXNativeTarget; buildConfigurationList = {bcl_app}; buildPhases = ({app_sources}, {app_frameworks}, {app_resources}); buildRules = (); dependencies = (); name = MatchLiveTv; packageProductDependencies = ({hk}, {rtmp}); productName = MatchLiveTv; productReference = {app_product}; productType = "com.apple.product-type.application"; }};', f'\t\t{test_dep_proxy} = {{isa = PBXContainerItemProxy; containerPortal = {proj} /* Project object */; proxyType = 1; remoteGlobalIDString = {app_target}; remoteInfo = MatchLiveTv; }};', f'\t\t{test_dep} = {{isa = PBXTargetDependency; target = {app_target} /* MatchLiveTv */; targetProxy = {test_dep_proxy} /* PBXContainerItemProxy */; }};', f'\t\t{test_target} = {{isa = PBXNativeTarget; buildConfigurationList = {bcl_test}; buildPhases = ({test_sources}, {test_frameworks}); buildRules = (); dependencies = ({test_dep}); name = MatchLiveTvTests; productName = MatchLiveTvTests; productReference = {test_product}; productType = "com.apple.product-type.bundle.unit-test"; }};', f'\t\t{pkg} = {{isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/shogo4405/HaishinKit.swift"; requirement = {{kind = upToNextMajorVersion; minimumVersion = 2.0.0;}}; }};', f'\t\t{proj} = {{isa = PBXProject; attributes = {{BuildIndependentTargetsInParallel = 0; LastSwiftUpdateCheck = 1600;}}; buildConfigurationList = {bcl_proj}; compatibilityVersion = "Xcode 15.0"; developmentRegion = it; mainGroup = {main_group}; packageReferences = ({pkg}); productRefGroup = {products_group}; targets = ({app_target}, {test_target}); }};', "\t};", f"\trootObject = {proj} /* Project object */;", "}", ] OUT.parent.mkdir(parents=True, exist_ok=True) OUT.write_text("\n".join(lines) + "\n") (OUT.parent / "project.xcworkspace").mkdir(exist_ok=True) (OUT.parent / "project.xcworkspace" / "contents.xcworkspacedata").write_text( '\n\n \n\n' ) scheme_dir = OUT.parent / "xcshareddata" / "xcschemes" scheme_dir.mkdir(parents=True, exist_ok=True) (scheme_dir / "MatchLiveTv.xcscheme").write_text(f""" """) print(f"Wrote {OUT} ({len(app_files)} app sources, {len(test_files)} test sources)")