473 lines
22 KiB
Python
473 lines
22 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate Bugger.xcodeproj from source tree."""
|
|
|
|
import hashlib
|
|
import os
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
PROJECT_NAME = "Bugger"
|
|
BUNDLE_ID = "com.xorbitlab.bugger"
|
|
|
|
SOURCE_ROOT = ROOT / "Sources"
|
|
RESOURCE_ROOT = ROOT / "Resources"
|
|
|
|
|
|
def uuid(seed: str) -> str:
|
|
digest = hashlib.md5(seed.encode()).hexdigest().upper()
|
|
return digest[:24]
|
|
|
|
|
|
def collect_swift_files() -> list[Path]:
|
|
return sorted(SOURCE_ROOT.rglob("*.swift"))
|
|
|
|
|
|
def collect_resources() -> list[Path]:
|
|
resources = []
|
|
for path in sorted(RESOURCE_ROOT.rglob("*")):
|
|
if path.is_file():
|
|
resources.append(path)
|
|
return resources
|
|
|
|
|
|
def pbxproj() -> str:
|
|
swift_files = collect_swift_files()
|
|
resources = collect_resources()
|
|
|
|
project_id = uuid("project")
|
|
target_id = uuid("target")
|
|
sources_phase_id = uuid("sources-phase")
|
|
resources_phase_id = uuid("resources-phase")
|
|
frameworks_phase_id = uuid("frameworks-phase")
|
|
product_ref_id = uuid("product-ref")
|
|
project_config_list_id = uuid("project-config-list")
|
|
target_config_list_id = uuid("target-config-list")
|
|
debug_config_id = uuid("debug-config")
|
|
release_config_id = uuid("release-config")
|
|
target_debug_config_id = uuid("target-debug-config")
|
|
target_release_config_id = uuid("target-release-config")
|
|
|
|
main_group_id = uuid("main-group")
|
|
products_group_id = uuid("products-group")
|
|
sources_group_id = uuid("sources-group")
|
|
resources_group_id = uuid("resources-group")
|
|
|
|
file_refs: dict[Path, str] = {}
|
|
build_files: list[tuple[str, str, str]] = []
|
|
|
|
for path in swift_files:
|
|
ref_id = uuid(f"file-{path}")
|
|
build_id = uuid(f"build-{path}")
|
|
file_refs[path] = ref_id
|
|
build_files.append((build_id, ref_id, "Sources"))
|
|
|
|
resource_refs: dict[Path, str] = {}
|
|
for path in resources:
|
|
ref_id = uuid(f"res-{path}")
|
|
build_id = uuid(f"res-build-{path}")
|
|
resource_refs[path] = ref_id
|
|
build_files.append((build_id, ref_id, "Resources"))
|
|
|
|
def group_for(path: Path, parent: str) -> str:
|
|
rel = path.relative_to(ROOT)
|
|
parts = rel.parts[:-1]
|
|
group_ids = [main_group_id]
|
|
current = ""
|
|
for part in parts:
|
|
current = f"{current}/{part}"
|
|
group_ids.append(uuid(f"group-{current}"))
|
|
return group_ids[-1]
|
|
|
|
groups: dict[str, list[str]] = {}
|
|
child_groups: dict[str, set[str]] = {}
|
|
|
|
def add_to_group(group_id: str, child_id: str):
|
|
groups.setdefault(group_id, []).append(child_id)
|
|
|
|
add_to_group(main_group_id, sources_group_id)
|
|
add_to_group(main_group_id, resources_group_id)
|
|
add_to_group(main_group_id, products_group_id)
|
|
add_to_group(products_group_id, product_ref_id)
|
|
|
|
def ensure_group_chain(rel_parts: tuple[str, ...], root_group: str):
|
|
current = root_group
|
|
built = []
|
|
for part in rel_parts:
|
|
built.append(part)
|
|
gid = uuid(f"group-{'/'.join(built)}")
|
|
if gid not in groups and gid != current:
|
|
add_to_group(current, gid)
|
|
current = gid
|
|
return current
|
|
|
|
for path in swift_files:
|
|
rel = path.relative_to(SOURCE_ROOT)
|
|
parent = ensure_group_chain(rel.parts[:-1], sources_group_id)
|
|
add_to_group(parent, file_refs[path])
|
|
|
|
for path in resources:
|
|
rel = path.relative_to(RESOURCE_ROOT)
|
|
if len(rel.parts) > 1:
|
|
parent = ensure_group_chain(rel.parts[:-1], resources_group_id)
|
|
else:
|
|
parent = resources_group_id
|
|
add_to_group(parent, resource_refs[path])
|
|
|
|
lines: list[str] = []
|
|
lines.append("// !$*UTF8*$!")
|
|
lines.append("{")
|
|
lines.append("\tarchiveVersion = 1;")
|
|
lines.append("\tclasses = {};")
|
|
lines.append("\tobjectVersion = 56;")
|
|
lines.append("\tobjects = {")
|
|
|
|
lines.append(f"\n/* Begin PBXBuildFile section */")
|
|
for build_id, ref_id, kind in build_files:
|
|
if kind == "Sources":
|
|
lines.append(f"\t\t{build_id} /* {Path(ref_id).name} in Sources */ = {{isa = PBXBuildFile; fileRef = {ref_id}; }};")
|
|
else:
|
|
lines.append(f"\t\t{build_id} /* {ref_id} in Resources */ = {{isa = PBXBuildFile; fileRef = {ref_id}; }};")
|
|
lines.append("/* End PBXBuildFile section */\n")
|
|
|
|
lines.append("/* Begin PBXFileReference section */")
|
|
lines.append(f"\t\t{product_ref_id} /* {PROJECT_NAME}.app */ = {{isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = {PROJECT_NAME}.app; sourceTree = BUILT_PRODUCTS_DIR; }};")
|
|
for path, ref_id in file_refs.items():
|
|
rel = path.relative_to(ROOT)
|
|
lines.append(f"\t\t{ref_id} /* {path.name} */ = {{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = {path.name}; sourceTree = \"<group>\"; }};")
|
|
for path, ref_id in resource_refs.items():
|
|
rel = path.relative_to(ROOT)
|
|
suffix = path.suffix.lower()
|
|
if suffix == ".plist":
|
|
file_type = "text.plist.xml"
|
|
elif suffix == ".entitlements":
|
|
file_type = "text.plist.entitlements"
|
|
elif path.name == "Contents.json":
|
|
file_type = "text.json"
|
|
else:
|
|
file_type = "folder.assetcatalog" if path.parent.suffix == ".xcassets" and path.name == "Contents.json" and path.parent.parent.name == "Assets.xcassets" else "text.json"
|
|
if path.name == "Contents.json" and "Assets.xcassets" in str(path):
|
|
if path.parent == RESOURCE_ROOT / "Assets.xcassets":
|
|
continue
|
|
if path.parent.name.endswith(".appiconset"):
|
|
file_type = "text.json"
|
|
elif path.parent == RESOURCE_ROOT / "Assets.xcassets":
|
|
file_type = "folder.assetcatalog"
|
|
# asset catalog handled as single folder reference below
|
|
if "Assets.xcassets" in str(path) and path != RESOURCE_ROOT / "Assets.xcassets":
|
|
continue
|
|
if path == RESOURCE_ROOT / "Assets.xcassets":
|
|
lines.append(f"\t\t{ref_id} /* Assets.xcassets */ = {{isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; }};")
|
|
continue
|
|
lines.append(f"\t\t{ref_id} /* {path.name} */ = {{isa = PBXFileReference; lastKnownFileType = {file_type}; path = {path.name}; sourceTree = \"<group>\"; }};")
|
|
lines.append("/* End PBXFileReference section */\n")
|
|
|
|
# Simpler approach: rewrite resource refs cleanly
|
|
resource_file_refs = []
|
|
asset_ref = uuid("asset-catalog")
|
|
info_ref = uuid("info-plist")
|
|
ent_ref = uuid("entitlements")
|
|
resource_file_refs = [
|
|
(RESOURCE_ROOT / "Assets.xcassets", asset_ref, "folder.assetcatalog", "Assets.xcassets"),
|
|
(RESOURCE_ROOT / "Info.plist", info_ref, "text.plist.xml", "Info.plist"),
|
|
(RESOURCE_ROOT / "Bugger.entitlements", ent_ref, "text.plist.entitlements", "Bugger.entitlements"),
|
|
]
|
|
|
|
lines = []
|
|
lines.append("// !$*UTF8*$!")
|
|
lines.append("{")
|
|
lines.append("\tarchiveVersion = 1;")
|
|
lines.append("\tclasses = {};")
|
|
lines.append("\tobjectVersion = 56;")
|
|
lines.append("\tobjects = {")
|
|
|
|
lines.append("\n/* Begin PBXBuildFile section */")
|
|
swift_build_entries = []
|
|
for path in swift_files:
|
|
ref_id = uuid(f"file-{path}")
|
|
build_id = uuid(f"build-{path}")
|
|
swift_build_entries.append((build_id, ref_id, path.name))
|
|
lines.append(f"\t\t{build_id} /* {path.name} in Sources */ = {{isa = PBXBuildFile; fileRef = {ref_id}; }};")
|
|
|
|
asset_build_id = uuid("asset-build")
|
|
lines.append(f"\t\t{asset_build_id} /* Assets.xcassets in Resources */ = {{isa = PBXBuildFile; fileRef = {asset_ref}; }};")
|
|
lines.append("/* End PBXBuildFile section */\n")
|
|
|
|
lines.append("/* Begin PBXFileReference section */")
|
|
lines.append(f"\t\t{product_ref_id} /* {PROJECT_NAME}.app */ = {{isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = {PROJECT_NAME}.app; sourceTree = BUILT_PRODUCTS_DIR; }};")
|
|
swift_ref_entries = []
|
|
for path in swift_files:
|
|
ref_id = uuid(f"file-{path}")
|
|
swift_ref_entries.append((ref_id, path))
|
|
lines.append(f"\t\t{ref_id} /* {path.name} */ = {{isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = {path.name}; sourceTree = \"<group>\"; }};")
|
|
lines.append(f"\t\t{asset_ref} /* Assets.xcassets */ = {{isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; }};")
|
|
lines.append(f"\t\t{info_ref} /* Info.plist */ = {{isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; }};")
|
|
lines.append(f"\t\t{ent_ref} /* Bugger.entitlements */ = {{isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Bugger.entitlements; sourceTree = \"<group>\"; }};")
|
|
lines.append("/* End PBXFileReference section */\n")
|
|
|
|
def render_groups():
|
|
group_defs = []
|
|
|
|
def walk(dir_path: Path, group_name: str, group_id: str, parent_set: list[str]):
|
|
children = []
|
|
for child in sorted(dir_path.iterdir()):
|
|
if child.is_dir() and child.name != ".DS_Store":
|
|
child_id = uuid(f"group-{child}")
|
|
children.append(child_id)
|
|
walk(child, child.name, child_id, [])
|
|
elif child.suffix == ".swift":
|
|
ref_id = uuid(f"file-{child}")
|
|
children.append(ref_id)
|
|
if dir_path == RESOURCE_ROOT:
|
|
children = [asset_ref, info_ref, ent_ref]
|
|
if dir_path == ROOT:
|
|
children = [sources_group_id, resources_group_id, products_group_id]
|
|
if dir_path == SOURCE_ROOT:
|
|
children = []
|
|
for child in sorted(dir_path.iterdir()):
|
|
if child.is_dir():
|
|
children.append(uuid(f"group-{child}"))
|
|
elif child.suffix == ".swift":
|
|
children.append(uuid(f"file-{child}"))
|
|
child_lines = "\n".join([f"\t\t\t\t{id_}," for id_ in children])
|
|
path_line = f"path = {group_name};" if group_name not in ("", PROJECT_NAME) else ""
|
|
if group_id == main_group_id:
|
|
group_defs.append(
|
|
f"\t\t{group_id} = {{\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n{child_lines}\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t}};"
|
|
)
|
|
elif group_id == products_group_id:
|
|
group_defs.append(
|
|
f"\t\t{group_id} = {{\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t{product_ref_id},\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t}};"
|
|
)
|
|
elif group_id == sources_group_id:
|
|
group_defs.append(
|
|
f"\t\t{group_id} = {{\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n{child_lines}\n\t\t\t);\n\t\t\tpath = Sources;\n\t\t\tsourceTree = \"<group>\";\n\t\t}};"
|
|
)
|
|
elif group_id == resources_group_id:
|
|
group_defs.append(
|
|
f"\t\t{group_id} = {{\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t{asset_ref},\n\t\t\t\t{info_ref},\n\t\t\t\t{ent_ref},\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t}};"
|
|
)
|
|
else:
|
|
rel = dir_path.relative_to(SOURCE_ROOT) if str(dir_path).startswith(str(SOURCE_ROOT)) else dir_path.name
|
|
group_defs.append(
|
|
f"\t\t{group_id} = {{\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n{child_lines}\n\t\t\t);\n\t\t\tpath = {dir_path.name};\n\t\t\tsourceTree = \"<group>\";\n\t\t}};"
|
|
)
|
|
|
|
walk(ROOT, PROJECT_NAME, main_group_id, [])
|
|
for child in sorted(SOURCE_ROOT.iterdir()):
|
|
if child.is_dir():
|
|
walk(child, child.name, uuid(f"group-{child}"), [])
|
|
return "\n".join(group_defs)
|
|
|
|
lines.append("/* Begin PBXFrameworksBuildPhase section */")
|
|
lines.append(f"\t\t{frameworks_phase_id} /* Frameworks */ = {{")
|
|
lines.append("\t\t\tisa = PBXFrameworksBuildPhase;")
|
|
lines.append("\t\t\tbuildActionMask = 2147483647;")
|
|
lines.append("\t\t\tfiles = (")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\trunOnlyForDeploymentPostprocessing = 0;")
|
|
lines.append("\t\t};")
|
|
lines.append("/* End PBXFrameworksBuildPhase section */\n")
|
|
|
|
lines.append("/* Begin PBXGroup section */")
|
|
lines.append(render_groups())
|
|
lines.append("/* End PBXGroup section */\n")
|
|
|
|
lines.append("/* Begin PBXNativeTarget section */")
|
|
lines.append(f"\t\t{target_id} /* {PROJECT_NAME} */ = {{")
|
|
lines.append("\t\t\tisa = PBXNativeTarget;")
|
|
lines.append(f"\t\t\tbuildConfigurationList = {target_config_list_id} /* Build configuration list for PBXNativeTarget \"{PROJECT_NAME}\" */;")
|
|
lines.append("\t\t\tbuildPhases = (")
|
|
lines.append(f"\t\t\t\t{sources_phase_id} /* Sources */,")
|
|
lines.append(f"\t\t\t\t{frameworks_phase_id} /* Frameworks */,")
|
|
lines.append(f"\t\t\t\t{resources_phase_id} /* Resources */,")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\tbuildRules = (")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\tdependencies = (")
|
|
lines.append("\t\t\t);")
|
|
lines.append(f"\t\t\tname = {PROJECT_NAME};")
|
|
lines.append(f"\t\t\tproductName = {PROJECT_NAME};")
|
|
lines.append(f"\t\t\tproductReference = {product_ref_id} /* {PROJECT_NAME}.app */;")
|
|
lines.append("\t\t\tproductType = \"com.apple.product-type.application\";")
|
|
lines.append("\t\t};")
|
|
lines.append("/* End PBXNativeTarget section */\n")
|
|
|
|
lines.append("/* Begin PBXProject section */")
|
|
lines.append(f"\t\t{project_id} /* Project object */ = {{")
|
|
lines.append("\t\t\tisa = PBXProject;")
|
|
lines.append("\t\t\tattributes = {")
|
|
lines.append("\t\t\t\tBuildIndependentTargetsInParallel = 1;")
|
|
lines.append("\t\t\t\tLastSwiftUpdateCheck = 1500;")
|
|
lines.append("\t\t\t\tLastUpgradeCheck = 1500;")
|
|
lines.append("\t\t\t\tTargetAttributes = {")
|
|
lines.append(f"\t\t\t\t\t{target_id} = {{")
|
|
lines.append("\t\t\t\t\t\tCreatedOnToolsVersion = 15.0;")
|
|
lines.append("\t\t\t\t\t};")
|
|
lines.append("\t\t\t\t};")
|
|
lines.append("\t\t\t};")
|
|
lines.append(f"\t\t\tbuildConfigurationList = {project_config_list_id} /* Build configuration list for PBXProject \"{PROJECT_NAME}\" */;")
|
|
lines.append("\t\t\tcompatibilityVersion = \"Xcode 14.0\";")
|
|
lines.append("\t\t\tdevelopmentRegion = en;")
|
|
lines.append("\t\t\thasScannedForEncodings = 0;")
|
|
lines.append("\t\t\tknownRegions = (")
|
|
lines.append("\t\t\t\ten,")
|
|
lines.append("\t\t\t\tBase,")
|
|
lines.append("\t\t\t);")
|
|
lines.append(f"\t\t\tmainGroup = {main_group_id};")
|
|
lines.append(f"\t\t\tproductRefGroup = {products_group_id} /* Products */;")
|
|
lines.append("\t\t\tprojectDirPath = \"\";")
|
|
lines.append("\t\t\tprojectRoot = \"\";")
|
|
lines.append("\t\t\ttargets = (")
|
|
lines.append(f"\t\t\t\t{target_id} /* {PROJECT_NAME} */,")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t};")
|
|
lines.append("/* End PBXProject section */\n")
|
|
|
|
lines.append("/* Begin PBXResourcesBuildPhase section */")
|
|
lines.append(f"\t\t{resources_phase_id} /* Resources */ = {{")
|
|
lines.append("\t\t\tisa = PBXResourcesBuildPhase;")
|
|
lines.append("\t\t\tbuildActionMask = 2147483647;")
|
|
lines.append("\t\t\tfiles = (")
|
|
lines.append(f"\t\t\t\t{asset_build_id} /* Assets.xcassets in Resources */,")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\trunOnlyForDeploymentPostprocessing = 0;")
|
|
lines.append("\t\t};")
|
|
lines.append("/* End PBXResourcesBuildPhase section */\n")
|
|
|
|
lines.append("/* Begin PBXSourcesBuildPhase section */")
|
|
lines.append(f"\t\t{sources_phase_id} /* Sources */ = {{")
|
|
lines.append("\t\t\tisa = PBXSourcesBuildPhase;")
|
|
lines.append("\t\t\tbuildActionMask = 2147483647;")
|
|
lines.append("\t\t\tfiles = (")
|
|
for build_id, _, name in swift_build_entries:
|
|
lines.append(f"\t\t\t\t{build_id} /* {name} in Sources */,")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\trunOnlyForDeploymentPostprocessing = 0;")
|
|
lines.append("\t\t};")
|
|
lines.append("/* End PBXSourcesBuildPhase section */\n")
|
|
|
|
common_settings = [
|
|
("ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon"),
|
|
("CODE_SIGN_ENTITLEMENTS", "Resources/Bugger.entitlements"),
|
|
("CODE_SIGN_STYLE", "Automatic"),
|
|
("COMBINE_HIDPI_IMAGES", "YES"),
|
|
("CURRENT_PROJECT_VERSION", "1"),
|
|
("DEVELOPMENT_TEAM", ""),
|
|
("ENABLE_HARDENED_RUNTIME", "YES"),
|
|
("FEISHU_APP_ID", ""),
|
|
("FEISHU_APP_SECRET", ""),
|
|
("FEISHU_BASE_DOMAIN", "xorbitlab.feishu.cn"),
|
|
("GENERATE_INFOPLIST_FILE", "NO"),
|
|
("INFOPLIST_FILE", "Resources/Info.plist"),
|
|
("LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/../Frameworks"),
|
|
("MACOSX_DEPLOYMENT_TARGET", "14.0"),
|
|
("MARKETING_VERSION", "1.0"),
|
|
("PRODUCT_BUNDLE_IDENTIFIER", BUNDLE_ID),
|
|
("PRODUCT_NAME", "$(TARGET_NAME)"),
|
|
("SWIFT_EMIT_LOC_STRINGS", "YES"),
|
|
("SWIFT_VERSION", "5.0"),
|
|
]
|
|
|
|
def config_block(config_id: str, name: str, settings: list[tuple[str, str]]) -> str:
|
|
setting_lines = "\n".join([f"\t\t\t\t{key} = {value};" for key, value in settings])
|
|
return (
|
|
f"\t\t{config_id} /* {name} */ = {{\n"
|
|
f"\t\t\tisa = XCBuildConfiguration;\n"
|
|
f"\t\t\tbuildSettings = {{\n{setting_lines}\n"
|
|
f"\t\t\t}};\n"
|
|
f"\t\t\tname = {name};\n"
|
|
f"\t\t}};"
|
|
)
|
|
|
|
lines.append("/* Begin XCBuildConfiguration section */")
|
|
lines.append(config_block(debug_config_id, "Debug", [("ALWAYS_SEARCH_USER_PATHS", "NO"), ("CLANG_ENABLE_MODULES", "YES"), ("COPY_PHASE_STRIP", "NO"), ("DEBUG_INFORMATION_FORMAT", "dwarf"), ("GCC_DYNAMIC_NO_PIC", "NO"), ("GCC_OPTIMIZATION_LEVEL", "0"), ("ONLY_ACTIVE_ARCH", "YES"), ("SDKROOT", "macosx"), ("SWIFT_ACTIVE_COMPILATION_CONDITIONS", "DEBUG"), ("SWIFT_OPTIMIZATION_LEVEL", "-Onone")]))
|
|
lines.append(config_block(release_config_id, "Release", [("ALWAYS_SEARCH_USER_PATHS", "NO"), ("CLANG_ENABLE_MODULES", "YES"), ("COPY_PHASE_STRIP", "NO"), ("DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym"), ("SDKROOT", "macosx"), ("SWIFT_COMPILATION_MODE", "wholemodule")]))
|
|
lines.append(config_block(target_debug_config_id, "Debug", common_settings))
|
|
lines.append(config_block(target_release_config_id, "Release", common_settings))
|
|
lines.append("/* End XCBuildConfiguration section */\n")
|
|
|
|
lines.append("/* Begin XCConfigurationList section */")
|
|
lines.append(f"\t\t{project_config_list_id} /* Build configuration list for PBXProject \"{PROJECT_NAME}\" */ = {{")
|
|
lines.append("\t\t\tisa = XCConfigurationList;")
|
|
lines.append("\t\t\tbuildConfigurations = (")
|
|
lines.append(f"\t\t\t\t{debug_config_id} /* Debug */,")
|
|
lines.append(f"\t\t\t\t{release_config_id} /* Release */,")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\tdefaultConfigurationIsVisible = 0;")
|
|
lines.append("\t\t\tdefaultConfigurationName = Release;")
|
|
lines.append("\t\t};")
|
|
lines.append(f"\t\t{target_config_list_id} /* Build configuration list for PBXNativeTarget \"{PROJECT_NAME}\" */ = {{")
|
|
lines.append("\t\t\tisa = XCConfigurationList;")
|
|
lines.append("\t\t\tbuildConfigurations = (")
|
|
lines.append(f"\t\t\t\t{target_debug_config_id} /* Debug */,")
|
|
lines.append(f"\t\t\t\t{target_release_config_id} /* Release */,")
|
|
lines.append("\t\t\t);")
|
|
lines.append("\t\t\tdefaultConfigurationIsVisible = 0;")
|
|
lines.append("\t\t\tdefaultConfigurationName = Release;")
|
|
lines.append("\t\t};")
|
|
lines.append("/* End XCConfigurationList section */")
|
|
lines.append("\t};")
|
|
lines.append(f"\trootObject = {project_id} /* Project object */;")
|
|
lines.append("}")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def main():
|
|
project_dir = ROOT / f"{PROJECT_NAME}.xcodeproj"
|
|
project_dir.mkdir(exist_ok=True)
|
|
(project_dir / "project.pbxproj").write_text(pbxproj())
|
|
scheme_dir = project_dir / "xcshareddata" / "xcschemes"
|
|
scheme_dir.mkdir(parents=True, exist_ok=True)
|
|
(scheme_dir / f"{PROJECT_NAME}.xcscheme").write_text(f"""<?xml version="1.0" encoding="UTF-8"?>
|
|
<Scheme
|
|
LastUpgradeVersion = "1500"
|
|
version = "1.7">
|
|
<BuildAction
|
|
parallelizeBuildables = "YES"
|
|
buildImplicitDependencies = "YES">
|
|
<BuildActionEntries>
|
|
<BuildActionEntry
|
|
buildForTesting = "YES"
|
|
buildForRunning = "YES"
|
|
buildForProfiling = "YES"
|
|
buildForArchiving = "YES"
|
|
buildForAnalyzing = "YES">
|
|
<BuildableReference
|
|
BuildableIdentifier = "primary"
|
|
BlueprintIdentifier = "{uuid('target')}"
|
|
BuildableName = "{PROJECT_NAME}.app"
|
|
BlueprintName = "{PROJECT_NAME}"
|
|
ReferencedContainer = "container:{PROJECT_NAME}.xcodeproj">
|
|
</BuildableReference>
|
|
</BuildActionEntry>
|
|
</BuildActionEntries>
|
|
</BuildAction>
|
|
<LaunchAction
|
|
buildConfiguration = "Debug"
|
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
|
launchStyle = "0"
|
|
useCustomWorkingDirectory = "NO"
|
|
ignoresPersistentStateOnLaunch = "NO"
|
|
debugDocumentVersioning = "YES"
|
|
debugServiceExtension = "internal"
|
|
allowLocationSimulation = "YES">
|
|
<BuildableProductRunnable
|
|
runnableDebuggingMode = "0">
|
|
<BuildableReference
|
|
BuildableIdentifier = "primary"
|
|
BlueprintIdentifier = "{uuid('target')}"
|
|
BuildableName = "{PROJECT_NAME}.app"
|
|
BlueprintName = "{PROJECT_NAME}"
|
|
ReferencedContainer = "container:{PROJECT_NAME}.xcodeproj">
|
|
</BuildableReference>
|
|
</BuildableProductRunnable>
|
|
</LaunchAction>
|
|
</Scheme>
|
|
""")
|
|
print(f"Generated {project_dir}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|