Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@


def _entry(configuration="Debug", arch="arm64"):
target_id = f"@@//app:app {configuration}-{arch}"
return {
"action": "build",
"bazelLabel": "@@//app:app",
"configuration": configuration,
"outputGroup": f"bp @@//app:app {configuration}-{arch}",
"indexOutputGroups": [f"bc {target_id}", f"bi {target_id}"],
"outputGroup": f"bp {target_id}",
"previewOutputGroups": [
f"bc {target_id}",
f"bp {target_id}",
f"bl {target_id}",
],
"product": {
"basename": "App.app",
"materialization": "copy_tree",
"name": "App",
"path": "bazel-out/App.app",
"type": "com.apple.product-type.application",
},
"targetID": f"@@//app:app {configuration}-{arch}",
"targetID": target_id,
"variant": {
"arch": arch,
"minimumOSVersion": "18.0",
Expand All @@ -39,29 +47,41 @@ def test_assemble_is_versioned_and_byte_deterministic(self):
[("a", 1, release), ("b", 1, debug)],
bazel_path="/usr/local/bin/bazel",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)
reverse = build_proxy_manifest_lib.assemble(
[("b", 1, debug), ("a", 1, release)],
bazel_path="/usr/local/bin/bazel",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)

self.assertEqual(forward, reverse)
manifest = json.loads(forward)
self.assertEqual(manifest["schemaVersion"], 1)
self.assertEqual(manifest["capabilities"], {"actions": ["build"]})
self.assertEqual(manifest["schemaVersion"], 2)
self.assertEqual(
manifest["capabilities"],
{"actions": ["build", "clean", "indexbuild", "preview"]},
)
self.assertEqual(
manifest["ignoredXcodeTargetGUIDs"],
["FF0100000000000000000001"],
)
self.assertEqual(
manifest["invocation"],
{
"adapterPath": "rules_xcodeproj/bazel/generate_bazel_dependencies.sh",
"bazelPath": "/usr/local/bin/bazel",
"bazelrcPath": "rules_xcodeproj/bazel/xcodeproj.bazelrc",
"environmentKeys": build_proxy_manifest_lib.INVOCATION_ENVIRONMENT_KEYS,
"generatorLabel": "@@//app:project",
"receiptSchemaVersion": 1,
},
)
self.assertEqual(
manifest["project"],
{"containerName": "App.xcodeproj", "identity": "@@//app:project"},
)
self.assertEqual(
[entry["configuration"] for entry in manifest["targets"]],
["Debug", "Release"],
Expand All @@ -79,6 +99,7 @@ def test_missing_required_key_is_rejected(self):
[("fragment", 1, _line(entry))],
bazel_path="bazel",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)

def test_unsupported_action_is_rejected(self):
Expand All @@ -93,6 +114,7 @@ def test_unsupported_action_is_rejected(self):
[("fragment", 1, _line(entry))],
bazel_path="bazel",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)

def test_duplicate_mapping_is_rejected(self):
Expand All @@ -106,6 +128,7 @@ def test_duplicate_mapping_is_rejected(self):
[("fragment", 1, entry), ("fragment", 2, entry)],
bazel_path="bazel",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)

def test_missing_generator_label_is_rejected(self):
Expand All @@ -117,6 +140,7 @@ def test_missing_generator_label_is_rejected(self):
[],
bazel_path="bazel",
generator_label="",
project_container="App.xcodeproj",
)

def test_missing_bazel_path_is_rejected(self):
Expand All @@ -128,6 +152,34 @@ def test_missing_bazel_path_is_rejected(self):
[],
bazel_path="",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)

def test_product_path_traversal_is_rejected(self):
entry = _entry()
entry["product"]["path"] = "bazel-out/../foreign/App.app"

with self.assertRaisesRegex(
build_proxy_manifest_lib.ManifestError,
"product path must not contain traversal",
):
build_proxy_manifest_lib.assemble(
[("fragment", 1, _line(entry))],
bazel_path="bazel",
generator_label="@@//app:project",
project_container="App.xcodeproj",
)

def test_project_container_must_be_a_xcodeproj_basename(self):
with self.assertRaisesRegex(
build_proxy_manifest_lib.ManifestError,
"project container must be a basename",
):
build_proxy_manifest_lib.assemble(
[],
bazel_path="bazel",
generator_label="@@//app:project",
project_container="../App.xcodeproj",
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ToolCommon
struct BuildProxyManifestEntry: Codable, Equatable {
struct Product: Codable, Equatable {
let basename: String
let materialization: String
let name: String
let path: String?
let type: String
Expand All @@ -25,7 +26,9 @@ struct BuildProxyManifestEntry: Codable, Equatable {
let action: String
let bazelLabel: String
let configuration: String
let indexOutputGroups: [String]
let outputGroup: String
let previewOutputGroups: [String]
let product: Product
let targetID: String
let variant: Variant
Expand Down Expand Up @@ -56,6 +59,10 @@ Missing target arguments for build proxy manifest target ID \(targetID).
let topLevelAttributes = topLevelTargetAttributes[targetID]
let product = Product(
basename: arguments.productBasename,
materialization: Self.materializationStrategy(
basename: arguments.productBasename,
path: topLevelAttributes?.outputsProductPath
),
name: arguments.productName,
path: topLevelAttributes?.outputsProductPath,
type: arguments.productType.identifier
Expand All @@ -72,7 +79,13 @@ Missing target arguments for build proxy manifest target ID \(targetID).
action: "build",
bazelLabel: consolidationMapEntry.label.description,
configuration: configuration,
indexOutputGroups: ["bc \(targetID.rawValue)", "bi \(targetID.rawValue)"],
outputGroup: "bp \(targetID.rawValue)",
previewOutputGroups: [
"bc \(targetID.rawValue)",
"bp \(targetID.rawValue)",
"bl \(targetID.rawValue)",
],
product: product,
targetID: targetID.rawValue,
variant: variant,
Expand All @@ -86,6 +99,15 @@ Missing target arguments for build proxy manifest target ID \(targetID).
return entries.sorted(by: stableLessThan)
}

private static func materializationStrategy(
basename: String,
path: String?
) -> String {
guard path != nil else { return "none" }
let treeExtensions = [".app", ".appex", ".bundle", ".framework", ".xctest"]
return treeExtensions.contains(where: basename.hasSuffix) ? "copy_tree" : "copy_file"
}

static func encodeJSONLines(_ entries: [Self]) throws -> Data {
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys, .withoutEscapingSlashes]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ class BuildProxyManifestEntryTests: XCTestCase {
action: "build",
bazelLabel: "@@//app:app",
configuration: "Release",
indexOutputGroups: ["bc @@//app:app ios-opt", "bi @@//app:app ios-opt"],
outputGroup: "bp @@//app:app ios-opt",
previewOutputGroups: [
"bc @@//app:app ios-opt", "bp @@//app:app ios-opt", "bl @@//app:app ios-opt",
],
product: .init(
basename: "App.app",
materialization: "copy_tree",
name: "App",
path: "bazel-out/App.app",
type: "com.apple.product-type.application"
Expand All @@ -27,9 +32,14 @@ class BuildProxyManifestEntryTests: XCTestCase {
action: "build",
bazelLabel: "@@//app:app",
configuration: "Debug",
indexOutputGroups: ["bc @@//app:app ios-sim-dbg", "bi @@//app:app ios-sim-dbg"],
outputGroup: "bp @@//app:app ios-sim-dbg",
previewOutputGroups: [
"bc @@//app:app ios-sim-dbg", "bp @@//app:app ios-sim-dbg", "bl @@//app:app ios-sim-dbg",
],
product: .init(
basename: "App.app",
materialization: "copy_tree",
name: "App",
path: "bazel-out/App.app",
type: "com.apple.product-type.application"
Expand All @@ -47,10 +57,19 @@ class BuildProxyManifestEntryTests: XCTestCase {
let reverse = try BuildProxyManifestEntry.encodeJSONLines([second, first])

XCTAssertEqual(forward, reverse)
let objects = try forward.split(separator: 0x0A).map { line in
try XCTUnwrap(
JSONSerialization.jsonObject(with: Data(line)) as? [String: Any]
)
}
XCTAssertEqual(objects.compactMap { $0["configuration"] as? String }, ["Debug", "Release"])
XCTAssertEqual(
String(decoding: forward, as: UTF8.self),
#"{"action":"build","bazelLabel":"@@//app:app","configuration":"Debug","outputGroup":"bp @@//app:app ios-sim-dbg","product":{"basename":"App.app","name":"App","path":"bazel-out/App.app","type":"com.apple.product-type.application"},"targetID":"@@//app:app ios-sim-dbg","variant":{"arch":"arm64","minimumOSVersion":"18.0","platform":"iphonesimulator"},"xcodeTargetGUID":"0000AAAAAAAA000000000001"}"# + "\n" +
#"{"action":"build","bazelLabel":"@@//app:app","configuration":"Release","outputGroup":"bp @@//app:app ios-opt","product":{"basename":"App.app","name":"App","path":"bazel-out/App.app","type":"com.apple.product-type.application"},"targetID":"@@//app:app ios-opt","variant":{"arch":"arm64","minimumOSVersion":"18.0","platform":"iphoneos"},"xcodeTargetGUID":"0000AAAAAAAA000000000001"}"# + "\n"
objects.first?["previewOutputGroups"] as? [String],
[
"bc @@//app:app ios-sim-dbg",
"bp @@//app:app ios-sim-dbg",
"bl @@//app:app ios-sim-dbg",
]
)
}

Expand All @@ -59,9 +78,14 @@ class BuildProxyManifestEntryTests: XCTestCase {
action: "build",
bazelLabel: "@@//lib",
configuration: "Debug",
indexOutputGroups: ["bc @@//lib macos-dbg", "bi @@//lib macos-dbg"],
outputGroup: "bp @@//lib macos-dbg",
previewOutputGroups: [
"bc @@//lib macos-dbg", "bp @@//lib macos-dbg", "bl @@//lib macos-dbg",
],
product: .init(
basename: "libLib.a",
materialization: "none",
name: "Lib",
path: nil,
type: "com.apple.product-type.library.static"
Expand Down
29 changes: 28 additions & 1 deletion xcodeproj/internal/bazel_integration_files/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("@rules_python//python:defs.bzl", "py_library", "py_test")

_BASE_FILES = [
"calculate_output_groups.py",
"copy_dsyms.sh",
Expand All @@ -6,6 +8,31 @@ _BASE_FILES = [
"process_bazel_build_log.py",
]

_TEST_FILES = [
"process_bazel_build_log_tests.py",
"write_build_proxy_invocation_receipt_tests.py",
]

py_library(
name = "write_build_proxy_invocation_receipt_lib",
srcs = ["write_build_proxy_invocation_receipt.py"],
)

py_test(
name = "write_build_proxy_invocation_receipt_tests",
srcs = ["write_build_proxy_invocation_receipt_tests.py"],
deps = [":write_build_proxy_invocation_receipt_lib"],
)

py_test(
name = "process_bazel_build_log_tests",
srcs = [
"process_bazel_build_log.py",
"process_bazel_build_log_tests.py",
],
main = "process_bazel_build_log_tests.py",
)

filegroup(
name = "bazel_integration_files",
srcs = _BASE_FILES + [
Expand All @@ -14,7 +41,7 @@ filegroup(
":rsync_excludes",
] + glob(
["**/*"],
exclude = _BASE_FILES + [
exclude = _BASE_FILES + _TEST_FILES + [
"**/*.bzl",
"BUILD",
],
Expand Down
Loading
Loading