diff --git a/docs/bazel.md b/docs/bazel.md index 7c62a1bcb6..41b488a3b5 100755 --- a/docs/bazel.md +++ b/docs/bazel.md @@ -62,12 +62,12 @@ load("@rules_xcodeproj//xcodeproj:defs.bzl", "xcodeproj") xcodeproj(name, adjust_schemes_for_swiftui_previews, associated_extra_files, bazel_path, bazel_env, build_mode, config, default_xcode_configuration, extra_files, fail_for_invalid_extra_files_targets, focused_targets, generation_mode, - import_index_build_indexstores, install_directory, ios_device_cpus, ios_simulator_cpus, - minimum_xcode_version, post_build, pre_build, project_name, project_options, - scheme_autogeneration_mode, scheme_autogeneration_config, schemes, target_name_mode, - top_level_targets, tvos_device_cpus, tvos_simulator_cpus, unfocused_targets, - visionos_device_cpus, visionos_simulator_cpus, watchos_device_cpus, watchos_simulator_cpus, - xcode_configurations, xcschemes, kwargs) + import_index_build_indexstores, include_package_generated_files_group, install_directory, + ios_device_cpus, ios_simulator_cpus, minimum_xcode_version, post_build, pre_build, + project_name, project_options, scheme_autogeneration_mode, scheme_autogeneration_config, + schemes, target_name_mode, top_level_targets, tvos_device_cpus, tvos_simulator_cpus, + unfocused_targets, visionos_device_cpus, visionos_simulator_cpus, watchos_device_cpus, + watchos_simulator_cpus, xcode_configurations, xcschemes, kwargs) Creates an `.xcodeproj` file in the workspace when run. @@ -111,6 +111,7 @@ xcodeproj( | focused_targets | Optional. A `list` of target labels as `string` values.

If specified, only these targets will be included in the generated project; all other targets will be excluded, as if they were listed explicitly in the `unfocused_targets` argument. The labels must match transitive dependencies of the targets specified in the `top_level_targets` argument. | `[]` | | generation_mode | Optional. Determines how the project is generated.

| `"incremental"` | | import_index_build_indexstores | Optional. Whether to import the index stores generated by Index Build.

This is useful if you want to use the index stores generated by Index Build to speed up Xcode's indexing process. You may not want this enabled if the additional work (mainly disk IO) of importing the index stores is not worth it for your project.

This only applies when using `generation_mode = "incremental"`. | `True` | +| include_package_generated_files_group | Optional. Whether the project will create a `Bazel Generated Files` child group for packages with generated files.

This is useful for finding generated files more easily in the project navigator by creating a child group in the path tree for each generated files' package.

This only applies when using `generation_mode = "incremental"`. | `False` | | install_directory | Optional. The directory where the generated project will be written to.

The path is relative to the workspace root.

Defaults to the directory that the `xcodeproj` target is declared in (e.g. if the `xcodeproj` target is declared in `//foo/bar:BUILD` then the default value is `"foo/bar"`). Use `""` to have the project generated in the workspace root. | `None` | | ios_device_cpus | Optional. The value to use for `--ios_multi_cpus` when building the transitive dependencies of the targets specified in the `top_level_targets` argument with the `"device"` `target_environment`.

**Warning:** Changing this value will affect the Starlark transition hash of all transitive dependencies of the targets specified in the `top_level_targets` argument with the `"device"` `target_environment`, even if they aren't iOS targets. | `"arm64"` | | ios_simulator_cpus | Optional. The value to use for `--ios_multi_cpus` when building the transitive dependencies of the targets specified in the `top_level_targets` argument with the `"simulator"` `target_environment`.

If no value is specified, it defaults to the simulator cpu that goes with `--host_cpu` (i.e. `sim_arm64` on Apple Silicon and `x86_64` on Intel).

**Warning:** Changing this value will affect the Starlark transition hash of all transitive dependencies of the targets specified in the `top_level_targets` argument with the `"simulator"` `target_environment`, even if they aren't iOS targets. | `None` | diff --git a/examples/integration/BUILD b/examples/integration/BUILD index 8307c6e38a..1c1dc1b0a1 100644 --- a/examples/integration/BUILD +++ b/examples/integration/BUILD @@ -65,6 +65,7 @@ string_flag( extra_files = EXTRA_FILES, fail_for_invalid_extra_files_targets = FAIL_FOR_INVALID_EXTRA_FILES_TARGETS, generation_mode = generation_mode, + include_package_generated_files_group = True, ios_simulator_cpus = simulator_cpu, pre_build = PRE_BUILD, project_name = "Integration", diff --git a/test/internal/pbxproj_partials/write_files_and_groups_tests.bzl b/test/internal/pbxproj_partials/write_files_and_groups_tests.bzl index 688442fc4b..566db3a530 100644 --- a/test/internal/pbxproj_partials/write_files_and_groups_tests.bzl +++ b/test/internal/pbxproj_partials/write_files_and_groups_tests.bzl @@ -50,6 +50,8 @@ def _write_files_and_groups_test_impl(ctx): # Act + mock_files = [mock_actions.mock_file(f) for f in ctx.attr.files] + ( pbxproject_known_regions, files_and_groups, @@ -63,9 +65,10 @@ def _write_files_and_groups_test_impl(ctx): compile_stub_needed = ctx.attr.compile_stub_needed, execution_root_file = ctx.attr.execution_root_file, generator_name = "a_generator_name", - files = depset(ctx.attr.files), + files = depset(mock_files), file_paths = depset(ctx.attr.file_paths), folders = depset(ctx.attr.folders), + include_package_generated_files_group = False, install_path = ctx.attr.install_path, project_options = ctx.attr.project_options, selected_model_versions_file = ctx.attr.selected_model_versions_file, diff --git a/tools/generators/files_and_groups/src/ElementCreator/CreateGroup.swift b/tools/generators/files_and_groups/src/ElementCreator/CreateGroup.swift index af96e0414a..6550f16713 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/CreateGroup.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/CreateGroup.swift @@ -27,7 +27,8 @@ extension ElementCreator { for node: PathTreeNode, parentBazelPath: BazelPath, specialRootGroupType: SpecialRootGroupType?, - createGroupChild: CreateGroupChild + createGroupChild: CreateGroupChild, + createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChild.ElementAndChildren { return callable( /*node:*/ node, @@ -35,7 +36,8 @@ extension ElementCreator { /*specialRootGroupType:*/ specialRootGroupType, /*createGroupChild:*/ createGroupChild, /*createGroupChildElements:*/ createGroupChildElements, - /*createGroupElement:*/ createGroupElement + /*createGroupElement:*/ createGroupElement, + /*createSpecialGroupElement:*/ createSpecialGroupElement ) } } @@ -50,7 +52,8 @@ extension ElementCreator.CreateGroup { _ specialRootGroupType: SpecialRootGroupType?, _ createGroupChild: ElementCreator.CreateGroupChild, _ createGroupChildElements: ElementCreator.CreateGroupChildElements, - _ createGroupElement: ElementCreator.CreateGroupElement + _ createGroupElement: ElementCreator.CreateGroupElement, + _ createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChild.ElementAndChildren static func defaultCallable( @@ -59,16 +62,24 @@ extension ElementCreator.CreateGroup { specialRootGroupType: SpecialRootGroupType?, createGroupChild: ElementCreator.CreateGroupChild, createGroupChildElements: ElementCreator.CreateGroupChildElements, - createGroupElement: ElementCreator.CreateGroupElement + createGroupElement: ElementCreator.CreateGroupElement, + createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChild.ElementAndChildren { - let bazelPath = parentBazelPath + node + let isBazelGenerated = node.name.hasPrefix("bazel-out") + let bazelPath: BazelPath + if isBazelGenerated { + bazelPath = BazelPath(node.name) + } else { + bazelPath = parentBazelPath + node + } let name = node.name let groupChildren = node.children.map { node in return createGroupChild( for: node, parentBazelPath: bazelPath, - specialRootGroupType: specialRootGroupType + specialRootGroupType: specialRootGroupType, + createSpecialGroupElement: createSpecialGroupElement ) } @@ -76,16 +87,29 @@ extension ElementCreator.CreateGroup { parentBazelPath: bazelPath, groupChildren: groupChildren ) - - let ( - group, - resolvedRepository - ) = createGroupElement( - name: name, - bazelPath: bazelPath, - specialRootGroupType: specialRootGroupType, - childIdentifiers: children.elements.map(\.object.identifier) - ) + + let group: Element + var resolvedRepository: ResolvedRepository? = nil + if isBazelGenerated { + group = createSpecialGroupElement( + specialRootGroupType: .bazelGenerated, + childIdentifiers: children.elements.map(\.object.identifier), + useRootStableIdentifiers: false, + bazelPath: bazelPath + ) + } else { + ( + group, + resolvedRepository + ) = createGroupElement( + name: name, + bazelPath: bazelPath, + specialRootGroupType: specialRootGroupType, + childIdentifiers: children.elements.map(\.object.identifier) + ) + } + + return GroupChild.ElementAndChildren( bazelPath: bazelPath, diff --git a/tools/generators/files_and_groups/src/ElementCreator/CreateGroupChild.swift b/tools/generators/files_and_groups/src/ElementCreator/CreateGroupChild.swift index b728376241..afb3fcd7a3 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/CreateGroupChild.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/CreateGroupChild.swift @@ -29,7 +29,8 @@ extension ElementCreator { func callAsFunction( for node: PathTreeNode, parentBazelPath: BazelPath, - specialRootGroupType: SpecialRootGroupType? + specialRootGroupType: SpecialRootGroupType?, + createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChild { return callable( /*node:*/ node, @@ -39,7 +40,8 @@ extension ElementCreator { /*createGroup:*/ createGroup, /*createGroupChild:*/ self, /*createLocalizedFiles:*/ createLocalizedFiles, - /*createVersionGroup:*/ createVersionGroup + /*createVersionGroup:*/ createVersionGroup, + /*createSpecialGroupElement:*/ createSpecialGroupElement ) } } @@ -56,7 +58,8 @@ extension ElementCreator.CreateGroupChild { _ createGroup: ElementCreator.CreateGroup, _ createGroupChild: ElementCreator.CreateGroupChild, _ createLocalizedFiles: ElementCreator.CreateLocalizedFiles, - _ createVersionGroup: ElementCreator.CreateVersionGroup + _ createVersionGroup: ElementCreator.CreateVersionGroup, + _ createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChild static func defaultCallable( @@ -67,7 +70,8 @@ extension ElementCreator.CreateGroupChild { createGroup: ElementCreator.CreateGroup, createGroupChild: ElementCreator.CreateGroupChild, createLocalizedFiles: ElementCreator.CreateLocalizedFiles, - createVersionGroup: ElementCreator.CreateVersionGroup + createVersionGroup: ElementCreator.CreateVersionGroup, + createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChild { guard !node.children.isEmpty else { // File @@ -108,7 +112,8 @@ extension ElementCreator.CreateGroupChild { for: node, parentBazelPath: parentBazelPath, specialRootGroupType: specialRootGroupType, - createGroupChild: createGroupChild + createGroupChild: createGroupChild, + createSpecialGroupElement: createSpecialGroupElement ) ) } diff --git a/tools/generators/files_and_groups/src/ElementCreator/CreateGroupElement.swift b/tools/generators/files_and_groups/src/ElementCreator/CreateGroupElement.swift index dd7675e8fd..ce595d1acc 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/CreateGroupElement.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/CreateGroupElement.swift @@ -85,7 +85,6 @@ extension ElementCreator.CreateGroupElement { } else { nameAttribute = "" } - // The tabs for indenting are intentional let content = #""" { diff --git a/tools/generators/files_and_groups/src/ElementCreator/CreateRootElements.swift b/tools/generators/files_and_groups/src/ElementCreator/CreateRootElements.swift index 5e3203a913..04d895a7ad 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/CreateRootElements.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/CreateRootElements.swift @@ -9,6 +9,7 @@ extension ElementCreator { private let createGroupChildElements: CreateGroupChildElements private let createInternalGroup: CreateInternalGroup private let createSpecialRootGroup: CreateSpecialRootGroup + private let createSpecialGroupElement: CreateSpecialRootGroupElement private let callable: Callable @@ -23,6 +24,7 @@ extension ElementCreator { createGroupChildElements: CreateGroupChildElements, createInternalGroup: CreateInternalGroup, createSpecialRootGroup: CreateSpecialRootGroup, + createSpecialGroupElement: CreateSpecialRootGroupElement, callable: @escaping Callable ) { self.includeCompileStub = includeCompileStub @@ -32,6 +34,7 @@ extension ElementCreator { self.createGroupChildElements = createGroupChildElements self.createInternalGroup = createInternalGroup self.createSpecialRootGroup = createSpecialRootGroup + self.createSpecialGroupElement = createSpecialGroupElement self.callable = callable } @@ -47,7 +50,8 @@ extension ElementCreator { /*createGroupChild:*/ createGroupChild, /*createGroupChildElements:*/ createGroupChildElements, /*createInternalGroup:*/ createInternalGroup, - /*createSpecialRootGroup:*/ createSpecialRootGroup + /*createSpecialRootGroup:*/ createSpecialRootGroup, + /*createSpecialGroupElement:*/ createSpecialGroupElement ) } } @@ -64,7 +68,8 @@ extension ElementCreator.CreateRootElements { _ createGroupChild: ElementCreator.CreateGroupChild, _ createGroupChildElements: ElementCreator.CreateGroupChildElements, _ createInternalGroup: ElementCreator.CreateInternalGroup, - _ createSpecialRootGroup: ElementCreator.CreateSpecialRootGroup + _ createSpecialRootGroup: ElementCreator.CreateSpecialRootGroup, + _ createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChildElements static func defaultCallable( @@ -75,7 +80,8 @@ extension ElementCreator.CreateRootElements { createGroupChild: ElementCreator.CreateGroupChild, createGroupChildElements: ElementCreator.CreateGroupChildElements, createInternalGroup: ElementCreator.CreateInternalGroup, - createSpecialRootGroup: ElementCreator.CreateSpecialRootGroup + createSpecialRootGroup: ElementCreator.CreateSpecialRootGroup, + createSpecialGroupElement: ElementCreator.CreateSpecialRootGroupElement ) -> GroupChildElements { let bazelPath = BazelPath("") @@ -117,7 +123,8 @@ extension ElementCreator.CreateRootElements { createGroupChild( for: node, parentBazelPath: bazelPath, - specialRootGroupType: nil + specialRootGroupType: nil, + createSpecialGroupElement: createSpecialGroupElement ) ) } diff --git a/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroup.swift b/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroup.swift index a3ab889933..9534eaf9bd 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroup.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroup.swift @@ -65,7 +65,8 @@ extension ElementCreator.CreateSpecialRootGroup { return createGroupChild( for: node, parentBazelPath: bazelPath, - specialRootGroupType: specialRootGroupType + specialRootGroupType: specialRootGroupType, + createSpecialGroupElement: createSpecialRootGroupElement ) } @@ -76,7 +77,9 @@ extension ElementCreator.CreateSpecialRootGroup { let group = createSpecialRootGroupElement( specialRootGroupType: specialRootGroupType, - childIdentifiers: children.elements.map(\.object.identifier) + childIdentifiers: children.elements.map(\.object.identifier), + useRootStableIdentifiers: true, + bazelPath: bazelPath ) return GroupChild.ElementAndChildren( diff --git a/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroupElement.swift b/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroupElement.swift index 91e1453780..0fed4b0f0a 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroupElement.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/CreateSpecialRootGroupElement.swift @@ -2,12 +2,15 @@ import PBXProj extension ElementCreator { struct CreateSpecialRootGroupElement { + private let createIdentifier: ElementCreator.CreateIdentifier + private let callable: Callable /// - Parameters: /// - callable: The function that will be called in /// `callAsFunction()`. - init(callable: @escaping Callable = Self.defaultCallable) { + init(createIdentifier: CreateIdentifier, callable: @escaping Callable = Self.defaultCallable) { + self.createIdentifier = createIdentifier self.callable = callable } @@ -15,11 +18,16 @@ extension ElementCreator { /// External Repositories"). func callAsFunction( specialRootGroupType: SpecialRootGroupType, - childIdentifiers: [String] + childIdentifiers: [String], + useRootStableIdentifiers: Bool, + bazelPath: BazelPath ) -> Element { return callable( /*specialRootGroupType:*/ specialRootGroupType, - /*childIdentifiers:*/ childIdentifiers + /*childIdentifiers:*/ childIdentifiers, + /*useRootStableIdentifiers:*/ useRootStableIdentifiers, + /*createIdentifier:*/ createIdentifier, + /*bazelPath:*/ bazelPath ) } } @@ -30,27 +38,35 @@ extension ElementCreator { extension ElementCreator.CreateSpecialRootGroupElement { typealias Callable = ( _ specialRootGroupType: SpecialRootGroupType, - _ childIdentifiers: [String] + _ childIdentifiers: [String], + _ useRootStableIdentifiers: Bool, + _ createIdentifier: ElementCreator.CreateIdentifier, + _ bazelPath: BazelPath ) -> Element static func defaultCallable( specialRootGroupType: SpecialRootGroupType, - childIdentifiers: [String] + childIdentifiers: [String], + useRootStableIdentifiers: Bool, + createIdentifier: ElementCreator.CreateIdentifier, + bazelPath: BazelPath ) -> Element { - let identifier: String + let identifier: String = groupIdentifier( + useStable: useRootStableIdentifiers, + bazelPath: bazelPath, + type: specialRootGroupType, + createIdentifier: createIdentifier + ) let name: String let path: String let sortOrder: Element.SortOrder switch specialRootGroupType { case .legacyBazelExternal, .siblingBazelExternal: - identifier = - Identifiers.FilesAndGroups.bazelExternalRepositoriesGroup name = "Bazel External Repositories" path = "../../external" sortOrder = .bazelExternalRepositories case .bazelGenerated: - identifier = Identifiers.FilesAndGroups.bazelGeneratedFilesGroup name = "Bazel Generated Files" path = "bazel-out" sortOrder = .bazelGenerated @@ -78,6 +94,26 @@ extension ElementCreator.CreateSpecialRootGroupElement { sortOrder: sortOrder ) } + + private static func groupIdentifier( + useStable: Bool, + bazelPath: BazelPath, + type: SpecialRootGroupType, + createIdentifier: ElementCreator.CreateIdentifier + ) -> String { + if useStable { + switch type { + case .legacyBazelExternal, .siblingBazelExternal: + return + Identifiers.FilesAndGroups.bazelExternalRepositoriesGroup + + case .bazelGenerated: + return Identifiers.FilesAndGroups.bazelGeneratedFilesGroup + } + } else { + return createIdentifier(path: bazelPath.path, name: bazelPath.path, type: .group) + } + } } enum SpecialRootGroupType { diff --git a/tools/generators/files_and_groups/src/ElementCreator/ElementCreatorEnvironment.swift b/tools/generators/files_and_groups/src/ElementCreator/ElementCreatorEnvironment.swift index 4b2f6a896c..0d758730dc 100644 --- a/tools/generators/files_and_groups/src/ElementCreator/ElementCreatorEnvironment.swift +++ b/tools/generators/files_and_groups/src/ElementCreator/ElementCreatorEnvironment.swift @@ -54,7 +54,7 @@ extension ElementCreator { /// `CreateSpecialRootGroup.init()`. let createSpecialRootGroupCallable: CreateSpecialRootGroup.Callable - let createSpecialRootGroupElement: CreateSpecialRootGroupElement + let createSpecialRootGroupElementCallable: CreateSpecialRootGroupElement.Callable /// Passed to the `callable` parameter of `CreateVariantGroup.init()`. let createVariantGroupCallable: CreateVariantGroup.Callable @@ -173,11 +173,13 @@ extension ElementCreator.Environment { let createInternalGroup = ElementCreator.CreateInternalGroup( callable: createInternalGroupCallable ) + + let createSpecialGroupElement = ElementCreator.CreateSpecialRootGroupElement(createIdentifier: createIdentifier) let createSpecialRootGroup = ElementCreator.CreateSpecialRootGroup( createGroupChild: createGroupChild, createGroupChildElements: createGroupChildElements, - createSpecialRootGroupElement: createSpecialRootGroupElement, + createSpecialRootGroupElement: createSpecialGroupElement, callable: createSpecialRootGroupCallable ) @@ -189,6 +191,7 @@ extension ElementCreator.Environment { createGroupChildElements: createGroupChildElements, createInternalGroup: createInternalGroup, createSpecialRootGroup: createSpecialRootGroup, + createSpecialGroupElement: createSpecialGroupElement, callable: createRootElementsCallable ) } @@ -222,8 +225,8 @@ extension ElementCreator.Environment { ElementCreator.CreateRootElements.defaultCallable, createSpecialRootGroupCallable: ElementCreator.CreateSpecialRootGroup.defaultCallable, - createSpecialRootGroupElement: - ElementCreator.CreateSpecialRootGroupElement(), + createSpecialRootGroupElementCallable: + ElementCreator.CreateSpecialRootGroupElement.defaultCallable, createVariantGroupCallable: ElementCreator.CreateVariantGroup.defaultCallable, createVariantGroupElementCallable: diff --git a/tools/generators/files_and_groups/src/Generator/CalculatePathTree.swift b/tools/generators/files_and_groups/src/Generator/CalculatePathTree.swift index 7bba5e7fe1..e277328fc9 100644 --- a/tools/generators/files_and_groups/src/Generator/CalculatePathTree.swift +++ b/tools/generators/files_and_groups/src/Generator/CalculatePathTree.swift @@ -8,13 +8,24 @@ extension Generator { var nodesByComponentCount: [Int: [PathTreeNodeToVisit]] = [:] for path in paths { - let components = path.path.split(separator: "/") - nodesByComponentCount[components.count, default: []] - .append(PathTreeNodeToVisit( - components: components, - isFolder: path.isFolder, - children: [] - )) + if path.path.hasPrefix("bazel-out"), let owner = path.owner { + let generatedPath = "\(owner)/\(path.path)" + let generatedComponents = generatedPath.split(separator: "/") + nodesByComponentCount[generatedComponents.count, default: []] + .append(PathTreeNodeToVisit( + components: generatedComponents, + isFolder: path.isFolder, + children: [] + )) + } else { + let components = path.path.split(separator: "/") + nodesByComponentCount[components.count, default: []] + .append(PathTreeNodeToVisit( + components: components, + isFolder: path.isFolder, + children: [] + )) + } } for componentCount in (1...nodesByComponentCount.keys.max()!) diff --git a/tools/generators/files_and_groups/src/Generator/ReadFilePathsFile.swift b/tools/generators/files_and_groups/src/Generator/ReadFilePathsFile.swift index 47a44f826b..fa6ab7f542 100644 --- a/tools/generators/files_and_groups/src/Generator/ReadFilePathsFile.swift +++ b/tools/generators/files_and_groups/src/Generator/ReadFilePathsFile.swift @@ -32,6 +32,13 @@ extension Generator.ReadFilePathsFile { _ url: URL ) async throws -> [BazelPath] { return try await url.lines.collect() - .map { BazelPath($0, isFolder: false) } + .map { line in + let components = line.split(separator: "--").map(String.init) + if components.count == 2 { + return BazelPath(components[0], isFolder: false, owner: components[1]) + } else { + return BazelPath(components[0], isFolder: false) + } + } } } diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateGroup+Testing.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateGroup+Testing.swift index c62a029b6c..d29a16b83e 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateGroup+Testing.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateGroup+Testing.swift @@ -19,7 +19,6 @@ extension ElementCreator.CreateGroup { groupChildElement: GroupChild.ElementAndChildren ) -> (mock: Self, tracker: MockTracker) { let mockTracker = MockTracker() - let mocked = Self( createGroupChildElements: ElementCreator.Stubs.createGroupChildElements, @@ -30,7 +29,8 @@ extension ElementCreator.CreateGroup { specialRootGroupType, createGroupChild, createGroupChildElements, - createGroupElement + createGroupElement, + createSpecialGroupElement in mockTracker.called.append(.init( node: node, diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateGroupChild+Testing.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateGroupChild+Testing.swift index 9010e29529..130395c2b0 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateGroupChild+Testing.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateGroupChild+Testing.swift @@ -46,7 +46,8 @@ extension ElementCreator.CreateGroupChild { createFile, createGroupElement, createLocalizedFiles, - createVersionGroup + createVersionGroup, + createSpecialGroupElement in mockTracker.called.append(.init( node: node, diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateGroupTests.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateGroupTests.swift index a624fa3244..d127d5807b 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateGroupTests.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateGroupTests.swift @@ -179,7 +179,9 @@ final class CreateGroupTests: XCTestCase { specialRootGroupType: specialRootGroupType, createGroupChild: createGroupChild.mock, createGroupChildElements: createGroupChildElements.mock, - createGroupElement: createGroupElement.mock + createGroupElement: createGroupElement.mock, + createSpecialGroupElement: ElementCreator.Stubs.createSpecialRootGroupElement + ) // Assert diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateRootElementsTests.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateRootElementsTests.swift index 05a6bdc37a..5155057969 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateRootElementsTests.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateRootElementsTests.swift @@ -304,6 +304,8 @@ final class CreateRootElementsTests: XCTestCase { let createGroupChildElements = ElementCreator.CreateGroupChildElements .mock(groupChildElements: stubbedRootElements) + let createSpecialGroupElement = ElementCreator.CreateSpecialRootGroupElement(createIdentifier: ElementCreator.CreateIdentifier()) + // Act let rootElements = ElementCreator.CreateRootElements.defaultCallable( @@ -314,7 +316,8 @@ final class CreateRootElementsTests: XCTestCase { createGroupChild: createGroupChild.mock, createGroupChildElements: createGroupChildElements.mock, createInternalGroup: createInternalGroup.mock, - createSpecialRootGroup: createSpecialRootGroup.mock + createSpecialRootGroup: createSpecialRootGroup.mock, + createSpecialGroupElement: createSpecialGroupElement ) // Assert diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElement+Testing.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElement+Testing.swift index 2c45b8c602..e32e0bf4a3 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElement+Testing.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElement+Testing.swift @@ -14,11 +14,12 @@ extension ElementCreator.CreateSpecialRootGroupElement { fileprivate(set) var called: [Called] = [] } - static func mock(element: Element) -> (mock: Self, tracker: MockTracker) { + static func mock(element: Element, createIdentifier: ElementCreator.CreateIdentifier) -> (mock: Self, tracker: MockTracker) { let mockTracker = MockTracker() let mocked = Self( - callable: { specialRootGroupType, childIdentifiers in + createIdentifier: createIdentifier, + callable: { specialRootGroupType, childIdentifiers, useRootStableIdentifiers, createIdentifier, bazelPath in mockTracker.called.append(.init( specialRootGroupType: specialRootGroupType, childIdentifiers: childIdentifiers @@ -35,7 +36,7 @@ extension ElementCreator.CreateSpecialRootGroupElement { extension ElementCreator.CreateSpecialRootGroupElement { static func stub(element: Element) -> Self { - let (stub, _) = mock(element: element) + let (stub, _) = mock(element: element, createIdentifier: ElementCreator.Stubs.createIdentifier) return stub } } diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElementTests.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElementTests.swift index 43b8d9f4e1..064c99dde9 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElementTests.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupElementTests.swift @@ -38,7 +38,10 @@ final class CreateSpecialRootGroupElementTests: XCTestCase { let element = ElementCreator.CreateSpecialRootGroupElement.defaultCallable( specialRootGroupType: specialRootGroupType, - childIdentifiers: childIdentifiers + childIdentifiers: childIdentifiers, + useRootStableIdentifiers: true, + createIdentifier: ElementCreator.Stubs.createIdentifier, + bazelPath: BazelPath(stringLiteral: "foo/bar") ) // Assert @@ -80,7 +83,10 @@ final class CreateSpecialRootGroupElementTests: XCTestCase { let element = ElementCreator.CreateSpecialRootGroupElement.defaultCallable( specialRootGroupType: specialRootGroupType, - childIdentifiers: childIdentifiers + childIdentifiers: childIdentifiers, + useRootStableIdentifiers: true, + createIdentifier: ElementCreator.Stubs.createIdentifier, + bazelPath: BazelPath(stringLiteral: "foo/bar") ) // Assert @@ -122,7 +128,10 @@ final class CreateSpecialRootGroupElementTests: XCTestCase { let element = ElementCreator.CreateSpecialRootGroupElement.defaultCallable( specialRootGroupType: specialRootGroupType, - childIdentifiers: childIdentifiers + childIdentifiers: childIdentifiers, + useRootStableIdentifiers: true, + createIdentifier: ElementCreator.Stubs.createIdentifier, + bazelPath: BazelPath(stringLiteral: "foo/bar") ) // Assert diff --git a/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupTests.swift b/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupTests.swift index 7845f74151..22415b8bb3 100644 --- a/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupTests.swift +++ b/tools/generators/files_and_groups/test/ElementCreator/CreateSpecialRootGroupTests.swift @@ -188,7 +188,7 @@ final class CreateSpecialRootGroupTests: XCTestCase { ] let createSpecialRootGroupElement = ElementCreator.CreateSpecialRootGroupElement - .mock(element: stubbedElement) + .mock(element: stubbedElement, createIdentifier: ElementCreator.Stubs.createIdentifier) let expectedResult = GroupChild.ElementAndChildren( bazelPath: expectedBazelPath, diff --git a/tools/generators/lib/PBXProj/src/BazelPath.swift b/tools/generators/lib/PBXProj/src/BazelPath.swift index e28a5cf0ef..b4dc4a3a76 100644 --- a/tools/generators/lib/PBXProj/src/BazelPath.swift +++ b/tools/generators/lib/PBXProj/src/BazelPath.swift @@ -4,10 +4,12 @@ import Foundation public struct BazelPath: Hashable { public var path: String public var isFolder: Bool + public var owner: String? - public init(_ path: String, isFolder: Bool = false) { + public init(_ path: String, isFolder: Bool = false, owner: String? = nil) { self.path = path self.isFolder = isFolder + self.owner = owner } } diff --git a/xcodeproj/internal/pbxproj_partials.bzl b/xcodeproj/internal/pbxproj_partials.bzl index 56516574b2..48e0c96d1c 100644 --- a/xcodeproj/internal/pbxproj_partials.bzl +++ b/xcodeproj/internal/pbxproj_partials.bzl @@ -67,6 +67,12 @@ def _generated_file_path(file): return _always_generated_file_path(file) +def _map_file_with_owner(file): + if hasattr(file, "owner") and file.owner != None: + return "{}--{}".format(file.path, file.owner.package) + else: + return file.path + # Partials # enum of flags, mainly to ensure the strings are frozen and reused @@ -359,6 +365,7 @@ def _write_files_and_groups( file_paths, folders, generator_name, + include_package_generated_files_group, install_path, project_options, selected_model_versions_file, @@ -381,6 +388,7 @@ def _write_files_and_groups( file paths. folders: A `depset` of paths to folders to include in the project. generator_name: The name of the `xcodeproj` generator target. + include_package_generated_files_group: Whether to generate child `Bazel Generated Files` groups. install_path: The workspace relative path to where the final `.xcodeproj` will be written. project_options: A `dict` as returned by `project_options`. @@ -432,7 +440,10 @@ def _write_files_and_groups( file_path_args = actions.args() file_path_args.set_param_file_format("multiline") - file_path_args.add_all(files) + if include_package_generated_files_group: + file_path_args.add_all(files, map_each = _map_file_with_owner) + else: + file_path_args.add_all(files) # TODO: Consider moving normalization into `args.add_all.map_each` file_path_args.add_all(file_paths) diff --git a/xcodeproj/internal/templates/generator.incremental.BUILD.bazel b/xcodeproj/internal/templates/generator.incremental.BUILD.bazel index 36a29e8433..f68e52f4b9 100644 --- a/xcodeproj/internal/templates/generator.incremental.BUILD.bazel +++ b/xcodeproj/internal/templates/generator.incremental.BUILD.bazel @@ -19,6 +19,7 @@ xcodeproj( default_xcode_configuration = %default_xcode_configuration%, generation_shard_count = %generation_shard_count%, import_index_build_indexstores = %import_index_build_indexstores%, + include_package_generated_files_group = %include_package_generated_files_group%, install_path = "%install_path%", ios_device_cpus = "%ios_device_cpus%", ios_simulator_cpus = "%ios_simulator_cpus%", diff --git a/xcodeproj/internal/xcodeproj_incremental_rule.bzl b/xcodeproj/internal/xcodeproj_incremental_rule.bzl index 12e1bc2f52..1140cb22a1 100644 --- a/xcodeproj/internal/xcodeproj_incremental_rule.bzl +++ b/xcodeproj/internal/xcodeproj_incremental_rule.bzl @@ -321,6 +321,7 @@ def _write_project_contents( default_xcode_configuration, files_and_groups_generator, generation_shard_count, + include_package_generated_files_group, import_index_build_indexstores, index_import, install_path, @@ -430,6 +431,7 @@ def _write_project_contents( file_paths = file_paths, folders = folders, generator_name = name, + include_package_generated_files_group = include_package_generated_files_group, install_path = install_path, project_options = project_options, selected_model_versions_file = selected_model_versions_file, @@ -648,6 +650,7 @@ Are you using an `alias`? `xcodeproj.focused_targets` and \ default_xcode_configuration = default_xcode_configuration, files_and_groups_generator = ctx.executable._files_and_groups_generator, generation_shard_count = ctx.attr.generation_shard_count, + include_package_generated_files_group = ctx.attr.include_package_generated_files_group, import_index_build_indexstores = ( ctx.attr.import_index_build_indexstores ), @@ -796,6 +799,7 @@ def _xcodeproj_incremental_attrs( "default_xcode_configuration": attr.string(), "generation_shard_count": attr.int(mandatory = True), "import_index_build_indexstores": attr.bool(mandatory = True), + "include_package_generated_files_group": attr.bool(mandatory = True), "install_path": attr.string(mandatory = True), "minimum_xcode_version": attr.string(mandatory = True), "owned_extra_files": attr.label_keyed_string_dict(allow_files = True), diff --git a/xcodeproj/internal/xcodeproj_macro.bzl b/xcodeproj/internal/xcodeproj_macro.bzl index 0a4b16038e..3f1c5c55fa 100644 --- a/xcodeproj/internal/xcodeproj_macro.bzl +++ b/xcodeproj/internal/xcodeproj_macro.bzl @@ -31,6 +31,7 @@ def xcodeproj( focused_targets = [], generation_mode = "incremental", import_index_build_indexstores = True, + include_package_generated_files_group = False, install_directory = None, ios_device_cpus = "arm64", ios_simulator_cpus = None, @@ -215,6 +216,14 @@ def xcodeproj( this enabled if the additional work (mainly disk IO) of importing the index stores is not worth it for your project. + This only applies when using `generation_mode = "incremental"`. + include_package_generated_files_group: Optional. Whether the project + will create a `Bazel Generated Files` child group for packages with generated + files. + + This is useful for finding generated files more easily in the project navigator + by creating a child group in the path tree for each generated files' package. + This only applies when using `generation_mode = "incremental"`. install_directory: Optional. The directory where the generated project will be written to. @@ -638,6 +647,7 @@ for {configuration} ({new_keys}) do not match keys of other configurations \ generation_mode = generation_mode, generation_shard_count = generation_shard_count, import_index_build_indexstores = import_index_build_indexstores, + include_package_generated_files_group = include_package_generated_files_group, install_directory = install_directory, ios_device_cpus = ios_device_cpus, ios_simulator_cpus = ios_simulator_cpus, diff --git a/xcodeproj/internal/xcodeproj_runner.bzl b/xcodeproj/internal/xcodeproj_runner.bzl index e1169cc9e9..f67a0a742d 100644 --- a/xcodeproj/internal/xcodeproj_runner.bzl +++ b/xcodeproj/internal/xcodeproj_runner.bzl @@ -257,6 +257,9 @@ def _write_generator_build_file( "%import_index_build_indexstores%": str( attr.import_index_build_indexstores, ), + "%include_package_generated_files_group%": str( + attr.include_package_generated_files_group, + ), "%install_directory%": attr.install_directory, "%install_path%": install_path, "%ios_device_cpus%": attr.ios_device_cpus, @@ -552,6 +555,7 @@ xcodeproj_runner = rule( ), "generation_shard_count": attr.int(mandatory = True), "import_index_build_indexstores": attr.bool(mandatory = True), + "include_package_generated_files_group": attr.bool(mandatory = True), "install_directory": attr.string(mandatory = True), "ios_device_cpus": attr.string(mandatory = True), "ios_simulator_cpus": attr.string(),