Skip to content

Commit

Permalink
Convert calculate-output-groups to Swift
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Pennig <mpennig@slack-corp.com>
  • Loading branch information
pennig committed Jun 18, 2024
1 parent 79eedcb commit 9b32f69
Show file tree
Hide file tree
Showing 18 changed files with 81 additions and 488 deletions.
3 changes: 3 additions & 0 deletions distribution/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"
),
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions tools/calculate_output_groups/CalculateOutputGroups.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 3 additions & 3 deletions tools/calculate_output_groups/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand All @@ -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 \
Expand All @@ -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
""")
}
Expand Down
58 changes: 39 additions & 19 deletions tools/calculate_output_groups/OutputGroupsCalculator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -19,7 +21,6 @@ struct OutputGroupsCalculator {
else {
throw UsageError.pifCache(pifCache.path)
}

async let buildRequest = loadBuildRequestFile(
inPath: arguments.baseObjRoot.appendingPathComponent("XCBuildData"),
since: markerDate
Expand All @@ -30,46 +31,65 @@ 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 {
@Sendable func findBuildRequestURL() -> URL? {
path.newestDescendent(recursive: true, matching: { url in
guard let xcbuilddata = path.newestDescendent(matching: { url in
guard
url.path.hasSuffix(".xcbuilddata/build-request.json"),
url.path.hasSuffix(".xcbuilddata"),
let date = url.modificationDate
else { return false }
return date >= since
})
}) else {
return nil
}

let buildRequest = xcbuilddata.appendingPathComponent("build-request.json")
if FileManager.default.fileExists(atPath: buildRequest.path) {
return buildRequest
} else {
return nil
}
}

if let url = findBuildRequestURL() {
return try url.decode(BuildRequest.self)
}

// 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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
""",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 0 additions & 2 deletions tools/generators/pbxproj_prefix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
Expand All @@ -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)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)";
Expand Down
42 changes: 25 additions & 17 deletions xcodeproj/internal/bazel_integration_files/BUILD
Original file line number Diff line number Diff line change
@@ -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(
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down
Loading

0 comments on commit 9b32f69

Please sign in to comment.