From 9b9e32b078dfd0dfc3530a03bea41c02dee05f49 Mon Sep 17 00:00:00 2001 From: Matt Pennig Date: Tue, 23 Apr 2024 13:58:03 -0500 Subject: [PATCH] Convert `calculate_output_groups.py` into a Swift binary --- distribution/BUILD | 3 + .../fixtures/bwb.xcodeproj/project.pbxproj | 2 - .../fixtures/bwx.xcodeproj/project.pbxproj | 2 - .../fixtures/bwb.xcodeproj/project.pbxproj | 1 - .../CalculateOutputGroups.swift | 8 +- tools/calculate_output_groups/Errors.swift | 6 +- .../OutputGroupsCalculator.swift | 42 +- .../AddBazelDependenciesTarget.swift | 3 - .../Generator/SetTargetConfigurations.swift | 2 +- .../CalculateSharedBuildSettings.swift | 2 +- tools/generators/pbxproj_prefix/README.md | 2 - .../BazelDependenciesBuildSettings.swift | 1 - .../BazelDependenciesBuildSettingsTests.swift | 1 - .../internal/bazel_integration_files/BUILD | 42 +- .../calculate_output_groups.py | 429 ------------------ .../generate_bazel_dependencies.sh | 2 +- .../templates/incremental_installer.sh | 2 +- .../internal/templates/legacy_installer.sh | 2 +- 18 files changed, 68 insertions(+), 484 deletions(-) delete mode 100755 xcodeproj/internal/bazel_integration_files/calculate_output_groups.py diff --git a/distribution/BUILD b/distribution/BUILD index ee4d7ed051..80da6cab88 100644 --- a/distribution/BUILD +++ b/distribution/BUILD @@ -59,6 +59,9 @@ pkg_tar( remap_paths = dicts.add( { "MODULE.release.bazel": "MODULE.bazel", + "tools/calculate_output_groups/BUILD.release.bazel": ( + "tools/calculate_output_groups/BUILD" + ), "tools/import_indexstores/BUILD.release.bazel": ( "tools/import_indexstores/BUILD" ), diff --git a/examples/integration/test/fixtures/bwb.xcodeproj/project.pbxproj b/examples/integration/test/fixtures/bwb.xcodeproj/project.pbxproj index fd8910d666..86a57276a2 100644 --- a/examples/integration/test/fixtures/bwb.xcodeproj/project.pbxproj +++ b/examples/integration/test/fixtures/bwb.xcodeproj/project.pbxproj @@ -15531,7 +15531,6 @@ isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; @@ -17868,7 +17867,6 @@ isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; diff --git a/examples/integration/test/fixtures/bwx.xcodeproj/project.pbxproj b/examples/integration/test/fixtures/bwx.xcodeproj/project.pbxproj index 141f3c9485..ff5f60bdb5 100644 --- a/examples/integration/test/fixtures/bwx.xcodeproj/project.pbxproj +++ b/examples/integration/test/fixtures/bwx.xcodeproj/project.pbxproj @@ -22921,7 +22921,6 @@ isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; @@ -24815,7 +24814,6 @@ isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; diff --git a/examples/rules_ios/test/fixtures/bwb.xcodeproj/project.pbxproj b/examples/rules_ios/test/fixtures/bwb.xcodeproj/project.pbxproj index 4955b6d598..60931e3253 100644 --- a/examples/rules_ios/test/fixtures/bwb.xcodeproj/project.pbxproj +++ b/examples/rules_ios/test/fixtures/bwb.xcodeproj/project.pbxproj @@ -4351,7 +4351,6 @@ isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; diff --git a/tools/calculate_output_groups/CalculateOutputGroups.swift b/tools/calculate_output_groups/CalculateOutputGroups.swift index 47f6cd179e..56fdfaecdd 100644 --- a/tools/calculate_output_groups/CalculateOutputGroups.swift +++ b/tools/calculate_output_groups/CalculateOutputGroups.swift @@ -14,16 +14,18 @@ struct CalculateOutputGroups: AsyncParsableCommand { @OptionGroup var arguments: OutputGroupsCalculator.Arguments func run() async throws { + var output = StdoutOutputStream() let logger = DefaultLogger( standardError: StderrOutputStream(), - standardOutput: StdoutOutputStream(), + standardOutput: output, colorize: colorDiagnostics ) - let calculator = OutputGroupsCalculator() + let calculator = OutputGroupsCalculator(logger: logger) do { - try await calculator.calculateOutputGroups(arguments: arguments) + let groups = try await calculator.calculateOutputGroups(arguments: arguments) + print(groups, to: &output) } catch { logger.logError(error.localizedDescription) Darwin.exit(1) diff --git a/tools/calculate_output_groups/Errors.swift b/tools/calculate_output_groups/Errors.swift index 43259eb900..dec5a45fd2 100644 --- a/tools/calculate_output_groups/Errors.swift +++ b/tools/calculate_output_groups/Errors.swift @@ -3,7 +3,7 @@ import ToolCommon extension UsageError { static func buildMarker(_ path: String) -> Self { .init(message: """ -error: Build marker (\(path)) doesn't exist. If you manually cleared Derived \ +Build marker (\(path)) doesn't exist. If you manually cleared Derived \ Data, you need to close and re-open the project for the file to be created \ again. Using the "Clean Build Folder" command instead (⇧ ⌘ K) won't trigger \ this error. If this error still happens after re-opening the project, please \ @@ -14,7 +14,7 @@ https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bu static func pifCache(_ path: String) -> Self { .init(message: """ -error: PIFCache (\(path)) doesn't exist. If you manually cleared Derived \ +PIFCache (\(path)) doesn't exist. If you manually cleared Derived \ Data, you need to close and re-open the project for the PIFCache to be created \ again. Using the "Clean Build Folder" command instead (⇧ ⌘ K) won't trigger \ this error. If this error still happens after re-opening the project, please \ @@ -25,7 +25,7 @@ https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bu static func buildRequest(_ path: String) -> Self { .init(message: """ -error: Couldn't find a build-request.json file inside \(path)". Please file a bug \ +Couldn't find latest build-request.json file after 30 seconds. Please file a bug \ report here: https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md """) } diff --git a/tools/calculate_output_groups/OutputGroupsCalculator.swift b/tools/calculate_output_groups/OutputGroupsCalculator.swift index d3ce09ef5d..e2266f41eb 100644 --- a/tools/calculate_output_groups/OutputGroupsCalculator.swift +++ b/tools/calculate_output_groups/OutputGroupsCalculator.swift @@ -3,7 +3,9 @@ import ToolCommon import ZippyJSON struct OutputGroupsCalculator { - func calculateOutputGroups(arguments: Arguments) async throws { + let logger: Logger + + func calculateOutputGroups(arguments: Arguments) async throws -> String { let pifCache = arguments.baseObjRoot.appendingPathComponent("XCBuildData/PIFCache") let projectCache = pifCache.appendingPathComponent("project") let targetCache = pifCache.appendingPathComponent("target") @@ -30,12 +32,11 @@ struct OutputGroupsCalculator { targetCache: targetCache ) - let output = try await outputGroups( + return try await outputGroups( buildRequest: buildRequest, targets: targetMap, prefixes: arguments.outputGroupPrefixes ) - print(output) } private func loadBuildRequestFile(inPath path: URL, since: Date) async throws -> BuildRequest { @@ -54,22 +55,33 @@ struct OutputGroupsCalculator { } // If the file was not immediately found, kick off a process to wait for the file to be created (or time out). - let findTask = Task { - while true { - try Task.checkCancellation() - try await Task.sleep(for: .seconds(1)) - if let buildRequestURL = findBuildRequestURL() { - return buildRequestURL + do { + let findTask = Task { + logger.logWarning("The latest build-request.json file has not been updated yet. Waiting…") + while true { + try Task.checkCancellation() + try await Task.sleep(for: .seconds(1)) + if let buildRequestURL = findBuildRequestURL() { + return buildRequestURL + } } } - } - let timeoutTask = Task { - try await Task.sleep(for: .seconds(10)) - findTask.cancel() - } + let waitingTask = Task { + try await Task.sleep(for: .seconds(10)) + try Task.checkCancellation() + logger.logWarning(""" +The latest build-request.json file has still not been updated after 10 seconds. If this happens frequently, please file a bug report here: +https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md +""") + } + let timeoutTask = Task { + try await Task.sleep(for: .seconds(30)) + guard !Task.isCancelled else { return } + findTask.cancel() + } - do { let result = try await findTask.value + waitingTask.cancel() timeoutTask.cancel() return try result.decode(BuildRequest.self) } catch { diff --git a/tools/generators/legacy/src/Generator/AddBazelDependenciesTarget.swift b/tools/generators/legacy/src/Generator/AddBazelDependenciesTarget.swift index f9698f326d..071bb4816f 100644 --- a/tools/generators/legacy/src/Generator/AddBazelDependenciesTarget.swift +++ b/tools/generators/legacy/src/Generator/AddBazelDependenciesTarget.swift @@ -35,9 +35,6 @@ extension Generator { var buildSettings: BuildSettings = [ "BAZEL_PACKAGE_BIN_DIR": "rules_xcodeproj", - "CALCULATE_OUTPUT_GROUPS_SCRIPT": """ -$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py -""", "INDEXING_SUPPORTED_PLATFORMS__": """ $(INDEXING_SUPPORTED_PLATFORMS__NO) """, diff --git a/tools/generators/legacy/src/Generator/SetTargetConfigurations.swift b/tools/generators/legacy/src/Generator/SetTargetConfigurations.swift index 5809329ab1..f950d4af36 100644 --- a/tools/generators/legacy/src/Generator/SetTargetConfigurations.swift +++ b/tools/generators/legacy/src/Generator/SetTargetConfigurations.swift @@ -283,7 +283,7 @@ $(BAZEL_OUT)\#(linkParams.path.string.dropFirst(9)) buildSettings.set("TARGET_NAME", to: target.name) if !target.product.isResourceBundle { - // This is used in `calculate_output_groups.py`. We only want to set + // This is used in `calculate_output_groups`. We only want to set // it on buildable targets buildSettings.set("BAZEL_LABEL", to: target.label.description) } diff --git a/tools/generators/pbxnativetargets/src/Generator/CalculateSharedBuildSettings.swift b/tools/generators/pbxnativetargets/src/Generator/CalculateSharedBuildSettings.swift index 1a3506406c..4b38f814fc 100644 --- a/tools/generators/pbxnativetargets/src/Generator/CalculateSharedBuildSettings.swift +++ b/tools/generators/pbxnativetargets/src/Generator/CalculateSharedBuildSettings.swift @@ -114,7 +114,7 @@ extension Generator.CalculateSharedBuildSettings { } if productType != .resourceBundle { - // This is used in `calculate_output_groups.py`. We only want to set + // This is used in `calculate_output_groups`. We only want to set // it on buildable targets. buildSettings.append( .init( diff --git a/tools/generators/pbxproj_prefix/README.md b/tools/generators/pbxproj_prefix/README.md index 88e63e9ef3..8f037d7651 100644 --- a/tools/generators/pbxproj_prefix/README.md +++ b/tools/generators/pbxproj_prefix/README.md @@ -121,7 +121,6 @@ Here is an example output: isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; @@ -144,7 +143,6 @@ Here is an example output: isa = XCBuildConfiguration; buildSettings = { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; diff --git a/tools/generators/pbxproj_prefix/src/Generator/BazelDependenciesBuildSettings.swift b/tools/generators/pbxproj_prefix/src/Generator/BazelDependenciesBuildSettings.swift index eb2a9d1512..04bef6e842 100644 --- a/tools/generators/pbxproj_prefix/src/Generator/BazelDependenciesBuildSettings.swift +++ b/tools/generators/pbxproj_prefix/src/Generator/BazelDependenciesBuildSettings.swift @@ -24,7 +24,6 @@ extension Generator { return #""" { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; diff --git a/tools/generators/pbxproj_prefix/test/BazelDependenciesBuildSettingsTests.swift b/tools/generators/pbxproj_prefix/test/BazelDependenciesBuildSettingsTests.swift index 583349943b..374a565150 100644 --- a/tools/generators/pbxproj_prefix/test/BazelDependenciesBuildSettingsTests.swift +++ b/tools/generators/pbxproj_prefix/test/BazelDependenciesBuildSettingsTests.swift @@ -20,7 +20,6 @@ class BazelDependenciesBuildSettingsTests: XCTestCase { let expectedBuildSettings = #""" { BAZEL_PACKAGE_BIN_DIR = rules_xcodeproj; - CALCULATE_OUTPUT_GROUPS_SCRIPT = "$(BAZEL_INTEGRATION_DIR)/calculate_output_groups.py"; CC = ""; CXX = ""; INDEXING_SUPPORTED_PLATFORMS__ = "$(INDEXING_SUPPORTED_PLATFORMS__NO)"; diff --git a/xcodeproj/internal/bazel_integration_files/BUILD b/xcodeproj/internal/bazel_integration_files/BUILD index 287a22049d..c57850251f 100644 --- a/xcodeproj/internal/bazel_integration_files/BUILD +++ b/xcodeproj/internal/bazel_integration_files/BUILD @@ -1,10 +1,10 @@ _BASE_FILES = [ - "calculate_output_groups.py", "copy_dsyms.sh", "create_lldbinit.sh", "generate_bazel_dependencies.sh", - ":renamed_import_indexstores", "process_bazel_build_log.py", + ":renamed_calculate_output_groups", + ":renamed_import_indexstores", ] filegroup( @@ -92,19 +92,34 @@ echo '/*.framework/SwiftUIPreviewsFrameworks/***' >> "framework.exclude.rsynclis tags = ["manual"], ) -genrule( - name = "renamed_import_indexstores", - srcs = ["//tools/import_indexstores:universal_import_indexstores"], - outs = ["import_indexstores"], - # Make `import_indexstores` have the right name - cmd = """\ +rename_command = """\ readonly output="$@" if [[ $$(stat -f '%d' "$<") == $$(stat -f '%d' "$${output%/*}") ]]; then cp -c "$<" "$@" else cp "$<" "$@" fi -""", +""" + +genrule( + name = "renamed_calculate_output_groups", + srcs = ["//tools/calculate_output_groups:universal_calculate_output_groups"], + outs = ["calculate_output_groups"], + # Make `calculate_output_groups` have the right name + cmd = rename_command, + message = "Renaming calculate_output_groups", + tags = [ + "manual", + "no-sandbox", + ], +) + +genrule( + name = "renamed_import_indexstores", + srcs = ["//tools/import_indexstores:universal_import_indexstores"], + outs = ["import_indexstores"], + # Make `import_indexstores` have the right name + cmd = rename_command, message = "Renaming import_indexstores", tags = [ "manual", @@ -117,14 +132,7 @@ genrule( srcs = ["//tools/swiftc_stub:universal_swiftc_stub"], outs = ["swiftc"], # Make `swiftc_stub` have the right name - cmd = """\ -readonly output="$@" -if [[ $$(stat -f '%d' "$<") == $$(stat -f '%d' "$${output%/*}") ]]; then - cp -c "$<" "$@" -else - cp "$<" "$@" -fi -""", + cmd = rename_command, message = "Renaming swiftc_stub", tags = [ "manual", diff --git a/xcodeproj/internal/bazel_integration_files/calculate_output_groups.py b/xcodeproj/internal/bazel_integration_files/calculate_output_groups.py deleted file mode 100755 index 2146c803d8..0000000000 --- a/xcodeproj/internal/bazel_integration_files/calculate_output_groups.py +++ /dev/null @@ -1,429 +0,0 @@ -#!/usr/bin/python3 - -import datetime -import glob -import json -import os -import sys -import time -import traceback - -# Ordered the same as we order platforms in the generated Xcode project, except -# macOS is last -_DEVICE_PLATFORMS = { - "iphoneos": None, - "appletvos": None, - "watchos": None, - "macosx": None, -} -_SIMULATOR_PLATFORMS = { - "iphonesimulator": None, - "appletvsimulator": None, - "watchsimulator": None, - "macosx": None, -} - - -def _wait_for_value(calculate_value, value_name): - wait_counter = 0 - while True: - value = calculate_value() - if value: - break - if wait_counter == 0: - now = datetime.datetime.now().strftime('%H:%M:%S') - print( - f"note: ({now}) {value_name} not updated yet, waiting...", - file = sys.stderr, - flush = True, - ) - if wait_counter == 10: - now = datetime.datetime.now().strftime('%H:%M:%S') - print( - f"""\ -warning: ({now}) {value_name} still not updated after 10 seconds. If happens \ -frequently, or the cache is never created, please file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md""", - file = sys.stderr, - flush = True, - ) - time.sleep(1) - wait_counter += 1 - if wait_counter > 0: - now = datetime.datetime.now().strftime('%H:%M:%S') - print( - f"""\ -note: ({now}) {value_name} updated after {wait_counter} seconds.""", - file = sys.stderr, - flush = True, - ) - return value - - -def _get_build_request( - xcode_version, - objroot, - build_request_min_ctime): - if xcode_version < 1430: - # Before Xcode 14.3 - def wait_for_description(): - build_description_cache = max( - glob.iglob( - f"{objroot}/XCBuildData/BuildDescriptionCacheIndex-*", - ), - key = os.path.getctime, - ) - if (os.path.getctime(build_description_cache) >= - build_request_min_ctime): - return build_description_cache - return None - - build_description_cache = ( - _wait_for_value(wait_for_description, "BuildDescriptionCacheIndex") - ) - with open(build_description_cache, 'rb') as f: - f.seek(-32, os.SEEK_END) - build_request_id = f.read().decode('ASCII') - - build_request_file = ( - f"{objroot}/XCBuildData/{build_request_id}-buildRequest.json" - ) - def wait_for_build_request_file(): - if os.path.exists(build_request_file): - with open(build_request_file, encoding = "utf-8") as f: - # Parse the build-request.json file - try: - return json.load(f) - except Exception as error: - print( - f"""\ -error: Failed to parse '{build_request_file}': -{type(error).__name__}: {error}. - -Please file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md""", - file = sys.stderr, - ) - exit(1) - return None - - return _wait_for_value( - wait_for_build_request_file, - f"\"{build_request_file}\"", - ) - - def wait_for_build_request(): - xcbuilddata = max( - glob.iglob(f"{objroot}/XCBuildData/*.xcbuilddata"), - key = os.path.getctime, - ) - if os.path.getctime(xcbuilddata) >= build_request_min_ctime: - build_request_file = f"{xcbuilddata}/build-request.json" - if os.path.exists(build_request_file): - with open(build_request_file, encoding = "utf-8") as f: - # Parse the build-request.json file - try: - return json.load(f) - except Exception as error: - print( - f"""\ -error: Failed to parse '{build_request_file}': -{type(error).__name__}: {error}. - -Please file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md""", - file = sys.stderr, - ) - exit(1) - return None - - return _wait_for_value( - wait_for_build_request, - "newest 'buildRequest.json' file", - ) - - -def _calculate_label_and_target_ids( - build_request, - guid_labels, - guid_target_ids): - # Xcode gets "stuck" in the `buildFiles` or `build` command for - # top-level targets, so we can't reliably change commands here. Leaving - # the code in place in case this is fixed in the future, or we want to - # do something similar in an XCBBuildService proxy. - # - # command = ( - # build_request.get("_buildCommand2", {}).get("command", "build") - # ) - command = "build" - parameters = build_request["parameters"] - platform = ( - parameters["activeRunDestination"]["platform"] - ) - configuration_name = parameters["configurationName"] - - labels_and_target_ids = [] - for target in build_request["configuredTargets"]: - label = guid_labels.get(target["guid"]) - if not label: - # `BazelDependency` and the like - continue - full_target_target_ids = guid_target_ids[target["guid"]] - target_target_ids = ( - full_target_target_ids.get(command) or - # Will only be `null` if `command == "buildFiles"` and there - # isn't a different compile target id - full_target_target_ids["build"] - ) - target_ids = _select_target_ids( - target_target_ids[configuration_name], - platform, - ) - for target_id in target_ids: - labels_and_target_ids.append((label, target_id)) - - if not labels_and_target_ids: - print( - """\ -error: Failed to determine labels and targets. Note, currently `.xcworkspace`s \ -aren't supported. Please make sure you are opening the generated \ -`.xcodeproj` file bundle directly. If you are, try using the "Clean Build \ -Folder" command instead (⇧ ⌘ K). If you still get this error after that, then \ -please file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md""", - file = sys.stderr, - ) - exit(1) - - return labels_and_target_ids - - -def _calculate_guid_labels_and_target_ids(base_objroot): - pif_cache = f"{base_objroot}/XCBuildData/PIFCache" - project_cache = f"{pif_cache}/project" - target_cache = f"{pif_cache}/target" - - # The PIF cache will only be created before the `SetSessionUserInfo` - # command, which normally happens when a project is opened. If Derived Data - # is cleared while the project is open - if not (os.path.exists(project_cache) and os.path.exists(target_cache)): - print( - f"""\ -error: PIFCache ({pif_cache}) doesn't exist. If you manually cleared Derived \ -Data, you need to close and re-open the project for the PIFCache to be created \ -again. Using the "Clean Build Folder" command instead (⇧ ⌘ K) won't trigger \ -this error. If this error still happens after re-opening the project, please \ -file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md""", - file = sys.stderr, - ) - sys.exit(1) - - project_pif = max( - glob.iglob(f"{project_cache}/*"), - key = os.path.getctime, - ) - - guid_payload_parent = f"{base_objroot}/guid_payload" - guid_payload_path = f"""\ -{guid_payload_parent}/{os.path.basename(project_pif)}_v2.json""" - - if os.path.exists(guid_payload_path): - with open(guid_payload_path, encoding = "utf-8") as f: - payload = json.load(f) - return payload["labels"], payload["targetIds"] - - with open(project_pif, encoding = "utf-8") as f: - project_pif = json.load(f) - - targets = project_pif["targets"] - - guid_labels = {} - guid_target_ids = {} - for target_name in targets: - target_file = f"{target_cache}/{target_name}-json" - with open(target_file, encoding = "utf-8") as f: - target_pif = json.load(f) - - label = None - build_target_ids = {} - compile_target_ids = {} - for configuration in target_pif["buildConfigurations"]: - config_build_target_ids = {"key": "BAZEL_TARGET_ID"} - config_compile_target_ids = {"key": "BAZEL_COMPILE_TARGET_IDS"} - for key, value in configuration["buildSettings"].items(): - if key.startswith("BAZEL_TARGET_ID"): - # This uses a list in the case where the value isn't meant to - # be inherited. Otherwise, `$(BAZEL_TARGET_ID)` is used later - # in this processing to pull from an inherited setting. - if value == "$(BAZEL_TARGET_ID)": - target_ids = value - else: - # This is only a single value but the later parsing of - # these target ids assumes a list. - target_ids = [value] - - config_build_target_ids[_platform_from_build_key(key)] = ( - target_ids - ) - elif key.startswith("BAZEL_COMPILE_TARGET_IDS"): - # This uses a list in the case where the value isn't meant to - # be inherited. Otherwise, `$(BAZEL_COMPILE_TARGET_IDS)` is - # used later in this processing to pull from an inherited - # setting. - if value == "$(BAZEL_COMPILE_TARGET_IDS)": - target_ids = "$(BAZEL_COMPILE_TARGET_IDS)" - else: - # Target identifiers contain a space but are space separated. - # Split on all spaces then rejoin across the identifier pairs. - target_ids = value.split(" ") - target_ids = [ - " ".join(target_ids[i:i+2]) - for i in range(0, len(target_ids), 2) - ] - - config_compile_target_ids[_platform_from_compile_key(key)] = ( - target_ids - ) - elif key == "BAZEL_LABEL": - label = value - configuration_name = configuration["name"] - build_target_ids[configuration_name] = config_build_target_ids - compile_target_ids[configuration_name] = config_compile_target_ids - - if not label: - # `BazelDependency` and the like - continue - - target_ids = { - "build": build_target_ids, - } - if len(compile_target_ids) > 1: - target_ids["buildFiles"] = compile_target_ids - - guid = target_pif["guid"] - guid_labels[guid] = label - guid_target_ids[guid] = target_ids - - os.makedirs(guid_payload_parent, exist_ok = True) - with open(guid_payload_path, "w", encoding = "utf-8") as f: - payload = { - "labels": guid_labels, - "targetIds": guid_target_ids, - } - json.dump(payload, f) - - return guid_labels, guid_target_ids - - -def _platform_from_build_key(key): - if key.startswith("BAZEL_TARGET_ID[sdk="): - return key[20:-2] - return "" - - -def _platform_from_compile_key(key): - if key.startswith("BAZEL_COMPILE_TARGET_IDS[sdk="): - return key[29:-2] - return "" - - -def _select_target_ids(target_ids, platform): - key = target_ids["key"] - - platforms = {platform: None} - - # We need to try other similar platforms (i.e. other simulator platforms if - # `platform`` is for a simulator). This is to support schemes with targets - # of multiple platforms in them. Because `dict` is insertion ordered, - # `platform` will be checked first. - platforms.update(_similar_platforms(platform)) - - for platform in platforms: - platform_target_ids = target_ids.get(platform) - if platform_target_ids: - if platform_target_ids == f"$({key})": - return target_ids[""] - return platform_target_ids - return target_ids[""] - - -def _similar_platforms(platform): - if platform == "macosx" or "simulator" in platform: - return _SIMULATOR_PLATFORMS - return _DEVICE_PLATFORMS - - -def _main( - xcode_version, - objroot, - base_objroot, - marker_file, - prefixes_str): - if not os.path.exists(marker_file): - return - - build_request_min_ctime = os.path.getctime(marker_file) - - try: - xcode_version = int(xcode_version) - except ValueError: - print( - """ -warning: xcode_version was not an integer. Please file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md -""", - file = sys.stderr, - ) - xcode_version = 9999 - - prefixes = prefixes_str.split(",") - - try: - build_request = _get_build_request( - xcode_version, - objroot, - build_request_min_ctime, - ) - guid_labels, guid_target_ids = ( - _calculate_guid_labels_and_target_ids(base_objroot) - ) - except Exception: - print( - f"""\ -error: Failed to calculate labels and target ids from PIFCache: -{traceback.format_exc()} -Please file a bug report here: \ -https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md""", - file = sys.stderr, - ) - sys.exit(1) - - labels_and_target_ids = _calculate_label_and_target_ids( - build_request, - guid_labels, - guid_target_ids, - ) - - print("\n".join( - [ - f"{label}\n{prefix} {id}" - for label, id in labels_and_target_ids - for prefix in prefixes - ], - )) - - -if __name__ == "__main__": - _main( - # XCODE_VERSION_ACTUAL - sys.argv[1], - # non_preview_objroot - sys.argv[2], - # base_objroot - sys.argv[3], - # build_marker_file - sys.argv[4], - # output_group_prefixes - sys.argv[5], - ) diff --git a/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh b/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh index 4c352ebf52..157c985b3e 100755 --- a/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh +++ b/xcodeproj/internal/bazel_integration_files/generate_bazel_dependencies.sh @@ -49,7 +49,7 @@ else # writes to it can happen during indexing, which breaks the off-by-one-by-design # nature of it IFS=$'\n' read -r -d '' -a labels_and_output_groups < \ - <( "$CALCULATE_OUTPUT_GROUPS_SCRIPT" \ + <( "$BAZEL_INTEGRATION_DIR/calculate_output_groups" \ "$XCODE_VERSION_ACTUAL" \ "$non_preview_objroot" \ "$base_objroot" \ diff --git a/xcodeproj/internal/templates/incremental_installer.sh b/xcodeproj/internal/templates/incremental_installer.sh index 15cab6716c..d9e334f828 100644 --- a/xcodeproj/internal/templates/incremental_installer.sh +++ b/xcodeproj/internal/templates/incremental_installer.sh @@ -122,7 +122,7 @@ find "$dest/rules_xcodeproj/bazel" \ -type f \( -name "*.sh" -o -name "*.py" \) \ -print0 | xargs -0 chmod u+x find "$dest/rules_xcodeproj/bazel" \ - -type f ! \( -name "swiftc" -o -name "import_indexstores" -o -name "*.sh" -o -name "*.py" \) \ + -type f ! \( -name "swiftc" -o -name "import_indexstores" -o -name "calculate_output_groups" -o -name "*.sh" -o -name "*.py" \) \ -print0 | xargs -0 chmod -x # Copy over `project.xcworkspace/contents.xcworkspacedata` if needed diff --git a/xcodeproj/internal/templates/legacy_installer.sh b/xcodeproj/internal/templates/legacy_installer.sh index 6c62fe06da..8fba2ec7cf 100644 --- a/xcodeproj/internal/templates/legacy_installer.sh +++ b/xcodeproj/internal/templates/legacy_installer.sh @@ -177,7 +177,7 @@ find "$dest/rules_xcodeproj/bazel" \ -type f \( -name "*.sh" -o -name "*.py" \) \ -print0 | xargs -0 chmod u+x find "$dest/rules_xcodeproj/bazel" \ - -type f ! \( -name "swiftc" -o -name "import_indexstores" -o -name "*.sh" -o -name "*.py" \) \ + -type f ! \( -name "swiftc" -o -name "import_indexstores" -o -name "calculate_output_groups" -o -name "*.sh" -o -name "*.py" \) \ -print0 | xargs -0 chmod -x # Copy over project.xcworkspace/contents.xcworkspacedata if needed