Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert calculate_output_groups.py into a Swift binary #3019

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

34 changes: 34 additions & 0 deletions tools/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ load("//xcodeproj:defs.bzl", "xcodeproj", "xcschemes")
load("//xcodeproj/internal:collections.bzl", "flatten", "uniq")

_TOOLS = {
"calculate_output_groups": "//tools/calculate_output_groups",
"files_and_groups": "//tools/generators/files_and_groups",
"import_indexstores": "//tools/import_indexstores",
"pbxnativetargets": "//tools/generators/pbxnativetargets",
Expand Down Expand Up @@ -51,6 +52,38 @@ _XCSCHEME_DIAGNOSTICS = xcschemes.diagnostics(
)

_XCSCHEMES = [
xcschemes.scheme(
name = "calculate_output_groups",
profile = xcschemes.profile(
launch_target = xcschemes.launch_target(
_TOOLS["calculate_output_groups"],
),
xcode_configuration = "Release",
),
run = xcschemes.run(
args = [
# colorDiagnostics
"NO",
# xcodeVersionActual
"1540",
# nonPreviewObjRoot
"/Users/brentley/Library/Developer/Xcode/DerivedData/tools-exxvdkcaoxdlhndlfnwxqvucohsr/Build/Intermediates.noindex",
# baseObjRoot
"/Users/brentley/Library/Developer/Xcode/DerivedData/tools-exxvdkcaoxdlhndlfnwxqvucohsr/Build/Intermediates.noindex",
# buildMarkerFile
"/Users/brentley/Library/Developer/Xcode/DerivedData/tools-exxvdkcaoxdlhndlfnwxqvucohsr/Build/Intermediates.noindex/build_marker",
# outputGroupPrefixes
"bc,bp,bi",
],
build_targets = [
_TOOLS["calculate_output_groups"],
],
diagnostics = _XCSCHEME_DIAGNOSTICS,
launch_target = xcschemes.launch_target(
_TOOLS["calculate_output_groups"],
),
),
),
xcschemes.scheme(
name = "files_and_groups",
profile = xcschemes.profile(
Expand Down Expand Up @@ -561,6 +594,7 @@ xcodeproj(
filegroup(
name = "release_files",
srcs = [
"//" + package_name() + "/calculate_output_groups:release_files",
"//" + package_name() + "/extension_point_identifiers_parser:release_files",
"//" + package_name() + "/generators:release_files",
"//" + package_name() + "/import_indexstores:release_files",
Expand Down
41 changes: 41 additions & 0 deletions tools/calculate_output_groups/Arguments.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import ArgumentParser
import Foundation

extension OutputGroupsCalculator {
struct Arguments: ParsableArguments {
@Argument(
help: "Value of the 'XCODE_VERSION_ACTUAL' environment variable."
)
var xcodeVersionActual: Int

@Argument(
help: """
Value of the 'OBJROOT' build setting when 'ENABLE_PREVIEWS = NO'.
""",
transform: { URL(fileURLWithPath: $0, isDirectory: true) }
)
var nonPreviewObjRoot: URL

@Argument(
help: """
Value of 'nonPreviewObjRoot' when 'INDEX_ENABLE_BUILD_ARENA = NO'.
""",
transform: { URL(fileURLWithPath: $0, isDirectory: true) }
)
var baseObjRoot: URL

@Argument(
help: """
Path to a file that has a ctime at or after the start of the build.
""",
transform: { URL(fileURLWithPath: $0, isDirectory: false) }
)
var buildMarkerFile: URL

@Argument(
help: "Comma seperated list of output group prefixes.",
transform: { $0.split(separator: ",").map(String.init) }
)
var outputGroupPrefixes: [String]
}
}
64 changes: 64 additions & 0 deletions tools/calculate_output_groups/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
load("@build_bazel_rules_apple//apple:apple.bzl", "apple_universal_binary")
load(
"@build_bazel_rules_apple//apple:macos.bzl",
"macos_command_line_application",
)
load(
"@build_bazel_rules_swift//swift:swift.bzl",
"swift_binary",
"swift_library",
)

# This target exists to keep configurations the same between the generator
# and the tests, which makes the Xcode development experience better. If we used
# `swift_binary` or `apple_universal_binary` in `xcodeproj`, then the
# `macos_unit_test` transition (which is used to be able to set a minimum os
# version on the tests) will create slightly different configurations for our
# `swift_library`s. Maybe https://github.com/bazelbuild/bazel/issues/6526 will
# fix that for us.
macos_command_line_application(
name = "calculate_output_groups",
minimum_os_version = "13.0",
visibility = ["//visibility:public"],
deps = [":calculate_output_groups.library"],
)

swift_library(
name = "calculate_output_groups.library",
srcs = glob(["*.swift"]),
module_name = "calculate_output_groups",
deps = [
"//tools/lib/ToolCommon",
"@com_github_apple_swift_argument_parser//:ArgumentParser",
"@com_github_michaeleisel_zippyjson//:ZippyJSON",
],
)

swift_binary(
name = "calculate_output_groups_binary",
deps = [":calculate_output_groups.library"],
)

apple_universal_binary(
name = "universal_calculate_output_groups",
binary = ":calculate_output_groups_binary",
forced_cpus = [
"x86_64",
"arm64",
],
minimum_os_version = "13.0",
platform_type = "macos",
visibility = ["//visibility:public"],
)

# Release

filegroup(
name = "release_files",
srcs = [
"BUILD.release.bazel",
":universal_calculate_output_groups",
],
tags = ["manual"],
visibility = ["//:__subpackages__"],
)
1 change: 1 addition & 0 deletions tools/calculate_output_groups/BUILD.release.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports_files(["universal_calculate_output_groups"])
34 changes: 34 additions & 0 deletions tools/calculate_output_groups/CalculateOutputGroups.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import ArgumentParser
import Darwin
import Foundation
import ToolCommon

@main
struct CalculateOutputGroups: AsyncParsableCommand {
@Argument(
help: "Value of the 'COLOR_DIAGNOSTICS' environment variable.",
transform: { $0 == "YES" }
)
var colorDiagnostics: Bool

@OptionGroup var arguments: OutputGroupsCalculator.Arguments

func run() async throws {
var output = StdoutOutputStream()
let logger = DefaultLogger(
standardError: StderrOutputStream(),
standardOutput: output,
colorize: colorDiagnostics
)

let calculator = OutputGroupsCalculator(logger: logger)

do {
let groups = try await calculator.calculateOutputGroups(arguments: arguments)
print(groups, to: &output)
} catch {
logger.logError(error.localizedDescription)
Darwin.exit(1)
}
}
}
32 changes: 32 additions & 0 deletions tools/calculate_output_groups/Errors.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import ToolCommon

extension UsageError {
static func buildMarker(_ path: String) -> Self {
.init(message: """
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 \
file a bug report here: \
https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md
""")
}

static func pifCache(_ path: String) -> Self {
.init(message: """
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 \
file a bug report here: \
https://github.com/MobileNativeFoundation/rules_xcodeproj/issues/new?template=bug.md
""")
}

static func buildRequest(_ path: String) -> Self {
.init(message: """
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
""")
}
}
79 changes: 79 additions & 0 deletions tools/calculate_output_groups/Models.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
enum PIF {
struct Project: Decodable {
let targets: [String]
}

struct Target: Decodable {
struct BuildConfiguration: Decodable {
let name: String
let buildSettings: [String: String]
}

let guid: String
let buildConfigurations: [BuildConfiguration]
}
}

struct BuildRequest: Decodable {
let command: String = "build" // TODO: support other commands (e.g. "buildFiles")
let configurationName: String
let configuredTargets: [String]
let platform: String

enum Root: CodingKey {
case configuredTargets
case parameters

enum ConfiguredTargets: CodingKey {
case guid
}
enum Parameters: CodingKey {
case activeRunDestination
case configurationName

enum ActiveRunDestination: CodingKey {
case platform
}
}
}

init(from decoder: Decoder) throws {
let root = try decoder.container(keyedBy: Root.self)
let parameters = try root.nestedContainer(keyedBy: Root.Parameters.self, forKey: .parameters)

// configurationName
self.configurationName = try parameters.decode(String.self, forKey: .configurationName)

// configuredTargets
var configuredTargets = try root.nestedUnkeyedContainer(forKey: .configuredTargets)
var decodedTargets = [String]()
while !configuredTargets.isAtEnd {
let target = try configuredTargets.nestedContainer(keyedBy: Root.ConfiguredTargets.self)
decodedTargets.append(try target.decode(String.self, forKey: .guid))
}
self.configuredTargets = decodedTargets

// platform
let activeRunDestination = try parameters.nestedContainer(keyedBy: Root.Parameters.ActiveRunDestination.self, forKey: .activeRunDestination)
self.platform = try activeRunDestination.decode(String.self, forKey: .platform)
}
}

enum Output {
typealias Map = [String: Target]

struct Target: Codable {
struct Config: Codable {
struct Settings: Codable {
let base: [String]
var platforms: [String: [String]?]
}

let build: Settings?
let buildFiles: Settings?
}

let label: String
let configs: [String: Config]
}
}
Loading
Loading