Skip to content

Commit

Permalink
Update DocC rules for rules_swift 2.1.0
Browse files Browse the repository at this point in the history
Updates the DocC rules to support rules_swift 2.x which introduced breaking changes to how Swift symbol graphs are collected.

This PR updates to use the new aspect to extract the symbol graphs. The public API remains unchanged.
  • Loading branch information
luispadron committed Jul 9, 2024
1 parent cf78fc7 commit 168a214
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 59 deletions.
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ bazel_dep(name = "bazel_skylib", version = "1.3.0")
bazel_dep(name = "platforms", version = "0.0.9")
bazel_dep(
name = "rules_swift",
version = "2.0.0",
version = "2.1.0",
max_compatibility_level = 2,
repo_name = "build_bazel_rules_swift",
)
Expand Down
61 changes: 32 additions & 29 deletions apple/internal/aspects/docc_archive_aspect.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,30 @@
"""Defines aspects for collecting information required to build .docc and .doccarchive files."""

load(
"@build_bazel_rules_swift//swift:swift.bzl",
"SwiftInfo",
"@build_bazel_rules_swift//swift:providers.bzl",
"SwiftSymbolGraphInfo",
)
load(
"@build_bazel_rules_apple//apple:providers.bzl",
"@build_bazel_rules_swift//swift:swift_symbol_graph_aspect.bzl",
"swift_symbol_graph_aspect",
)
load(
"//apple:providers.bzl",
"DocCBundleInfo",
"DocCSymbolGraphsInfo",
)

def _swift_symbol_graph(swift_info):
"""Returns the symbol graph from a SwiftInfo provider or fails if it doesn't exist."""
direct_modules = swift_info.direct_modules
if len(direct_modules) != 1:
return None
module = direct_modules[0]
if not module.swift:
return None
swift_module = module.swift
if not swift_module.symbol_graph:
return None
return swift_module.symbol_graph

def _first_docc_bundle(target, ctx):
def _swift_symbol_graphs(*, swift_symbol_graph_info):
"""Returns a `List` of symbol graph directories from a `SwiftSymbolGraphInfo` provider or fails if it doesn't exist."""
direct_symbol_graphs = swift_symbol_graph_info.direct_symbol_graphs
transitive_symbol_graphs = swift_symbol_graph_info.transitive_symbol_graphs

return [
symbol_graph.symbol_graph_dir
for symbol_graph in (direct_symbol_graphs + transitive_symbol_graphs.to_list())
]

def _first_docc_bundle(*, target, ctx):
"""Returns the first .docc bundle for the target or its deps by looking in it's data."""
docc_bundles = []

Expand All @@ -57,15 +58,12 @@ def _docc_symbol_graphs_aspect_impl(target, ctx):

symbol_graphs = []

if SwiftInfo in target:
symbol_graphs.append(_swift_symbol_graph(target[SwiftInfo]))
if SwiftSymbolGraphInfo in target:
symbol_graphs.extend(_swift_symbol_graphs(swift_symbol_graph_info = target[SwiftSymbolGraphInfo]))
elif hasattr(ctx.rule.attr, "deps"):
for dep in ctx.rule.attr.deps:
if SwiftInfo in dep:
symbol_graphs.append(_swift_symbol_graph(dep[SwiftInfo]))

# Filter out None
symbol_graphs = [symbol_graph for symbol_graph in symbol_graphs if symbol_graph]
if SwiftSymbolGraphInfo in dep:
symbol_graphs.extend(_swift_symbol_graphs(swift_symbol_graph_info = dep[SwiftSymbolGraphInfo]))

if not symbol_graphs:
return []
Expand All @@ -76,7 +74,10 @@ def _docc_bundle_info_aspect_impl(target, ctx):
"""Creates a DocCBundleInfo provider for targets which have a .docc bundle (or which bundle a target that does)"""

if hasattr(ctx.rule.attr, "data"):
first_docc_bundle = _first_docc_bundle(target, ctx)
first_docc_bundle = _first_docc_bundle(
target = target,
ctx = ctx
)
if first_docc_bundle:
return [DocCBundleInfo(bundle = first_docc_bundle)]
if hasattr(ctx.rule.attr, "deps"):
Expand All @@ -90,19 +91,21 @@ def _docc_bundle_info_aspect_impl(target, ctx):
docc_bundle_info_aspect = aspect(
implementation = _docc_bundle_info_aspect_impl,
doc = """
Creates or collects the DocCBundleInfo provider for a target or its deps.
Creates or collects the `DocCBundleInfo` provider for a target or its deps.
This aspect works with targets that have a .docc bundle in their data, or which bundle a target that does.
This aspect works with targets that have a `.docc` bundle in their data, or which bundle a target that does.
""",
attr_aspects = ["data", "deps"],
)

docc_symbol_graphs_aspect = aspect(
implementation = _docc_symbol_graphs_aspect_impl,
required_aspect_providers = [SwiftSymbolGraphInfo],
requires = [swift_symbol_graph_aspect],
doc = """
Creates or collects the DocCSymbolGraphsInfo provider for a target or its deps.
Creates or collects the `DocCSymbolGraphsInfo` provider for a target or its deps.
This aspect works with targets that have a SwiftInfo provider, or which bundle a target that does.
This aspect works with targets that have a `SwiftSymbolGraphInfo` provider, or which bundle a target that does.
""",
attr_aspects = ["deps"],
)
47 changes: 28 additions & 19 deletions apple/internal/docc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def _docc_archive_impl(ctx):
platform = ctx.fragments.apple.single_arch_platform
transform_for_static_hosting = ctx.attr.transform_for_static_hosting
xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
dep = ctx.attr.dep[0] # this isn't actually a list target but transition makes it one.
dep = ctx.attr.dep
symbol_graphs_info = None
docc_bundle_info = None
docc_build_inputs = []
Expand Down Expand Up @@ -155,19 +155,6 @@ def _docc_archive_impl(ctx):
doccarchive_binary_info,
]

def _swift_emit_symbol_graph_transition_impl(settings, _attr):
"""A transition that enables "swift.emit_symbol_graph" feature"""
if "//command_line_option:features" in settings:
return {"//command_line_option:features": settings["//command_line_option:features"] + ["swift.emit_symbol_graph"]}
else:
return {"//command_line_option:features": ["swift.emit_symbol_graph"]}

swift_emit_symbol_graph_transition = transition(
implementation = _swift_emit_symbol_graph_transition_impl,
inputs = ["//command_line_option:features"],
outputs = ["//command_line_option:features"],
)

docc_archive = rule(
implementation = _docc_archive_impl,
fragments = ["apple"],
Expand All @@ -179,7 +166,7 @@ NOTE: At this time Swift is the only supported language for this rule.
Example:
```python
```starlark
load("@build_bazel_rules_apple//apple:docc.bzl", "docc_archive")
docc_archive(
Expand All @@ -198,7 +185,6 @@ docc_archive(
docc_bundle_info_aspect,
docc_symbol_graphs_aspect,
],
cfg = swift_emit_symbol_graph_transition,
providers = [[DocCBundleInfo], [DocCSymbolGraphsInfo]],
),
"default_code_listing_language": attr.string(
Expand All @@ -212,6 +198,19 @@ Must be one of "error", "warning", "information", or "hint"
""",
values = ["error", "warning", "information", "hint"],
),
# TODO: use `attr.bool` once https://github.com/bazelbuild/bazel/issues/22809 is resolved.
"emit_extension_block_symbols": attr.string(
default = "0",
doc = """
Defines if the symbol graph information for `extension` blocks should be
emitted in addition to the default symbol graph information.
This value must be either `"0"` or `"1"`.When the value is `"1"`, the symbol
graph information for `extension` blocks will be emitted in addition to
the default symbol graph information. The default value is `"0"`.
""",
values = ["0", "1"],
),
"enable_inherited_docs": attr.bool(
default = False,
doc = "Inherit documentation for inherited symbols.",
Expand All @@ -235,12 +234,22 @@ Must be one of "error", "warning", "information", or "hint"
"kinds": attr.string_list(
doc = "The kinds of entities to filter generated documentation for.",
),
"minimum_access_level": attr.string(
default = "public",
doc = """"
The minimum access level of the declarations that should be emitted in the symbol graphs.
This value must be either `fileprivate`, `internal`, `private`, or `public`. The default value is `public`.
""",
values = [
"fileprivate",
"internal",
"private",
"public",
],
),
"transform_for_static_hosting": attr.bool(
default = True,
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
"_preview_template": attr.label(
allow_single_file = True,
default = "//apple/internal/templates:docc_preview_template",
Expand Down
4 changes: 2 additions & 2 deletions apple/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ def apple_rules_dependencies(ignore_version_differences = False, include_bzlmod_
_maybe(
http_archive,
name = "build_bazel_rules_swift",
sha256 = "32eeb4ef33c708d9c9a4ee0fa8475322ef149dabc81884ddc3b50eb2efff7843",
url = "https://github.com/bazelbuild/rules_swift/releases/download/2.0.0/rules_swift.2.0.0.tar.gz",
sha256 = "8e0c72aa2be5ae44da44521c46e0700df184953e8dbc5d5423222b8cb141c64f",
url = "https://github.com/bazelbuild/rules_swift/releases/download/2.1.0/rules_swift.2.1.0.tar.gz",
ignore_version_differences = ignore_version_differences,
)

Expand Down
2 changes: 2 additions & 0 deletions examples/ios/HelloWorldSwift/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ docc_archive(
default_code_listing_language = "en",
dep = ":HelloWorldSwift",
diagnostic_level = "information",
emit_extension_block_symbols = "1",
enable_inherited_docs = True,
fallback_bundle_identifier = "com.example.hello-world-swift",
fallback_bundle_version = "1.0.0",
fallback_display_name = "HelloWorldSwift",
minimum_access_level = "internal",
)
51 changes: 46 additions & 5 deletions examples/ios/HelloWorldSwift/Sources/BazelApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,61 @@
import SwiftUI

@main
struct BazelApp: App {
var body: some Scene {
public struct BazelApp: App {
public init() { }

public var body: some Scene {
WindowGroup {
Text("Hello World")
.accessibility(identifier: "HELLO_WORLD")
}
}

/// A foo API to test DooC documentation generation.
/// A public API to test DooC documentation generation.
///
/// Example referencing ``AppDelegate``:
/// Example referencing ``BazelApp``:
///
/// ```swift
/// let appDelegate = AppDelegate()
/// let app = BazelApp()
/// ```
public func foo() { }

/// An internal API to test `minimum_access_level` DooC option.
internal func internalFoo() { }
}

// MARK: - View Extension

extension View {

/// A public API extension on ``View`` to test DooC documentation generation.
public func viewFoo() { }

/// An internal API extension on ``View`` to test `minimum_access_level` DooC option.
internal func internalViewFoo() { }
}

// MARK: - Custom type

/// My Struct
///
/// Example referencing ``MyStruct``:
///
/// ```swift
///
/// let foo = MyStruct()
/// ```
public struct MyStruct {
public init() { }

/// My Struct's foo API to test DooC documentation generation.
/// - Parameters:
/// - bar: A bar parameter.
public func foo(bar: Int) { }

/// An internal foo API to test DooC documentation generation with `minimum_access_level` set to `internal`.
///
/// - Parameters:
/// - bar: A bar parameter.
internal func internalFoo(bar: Int) { }
}
2 changes: 1 addition & 1 deletion test/starlark_tests/docc_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def docc_test_suite(name):
text_file_not_contains = [],
text_test_file = "$BUNDLE_ROOT/metadata.json",
text_test_values = [
"\"bundleDisplayName\":\"BasicFramework\"",
"\"bundleDisplayName\":\"BasicFrameworkWithDocCBundle\"",
"\"bundleIdentifier\":\"com.google.example.framework\"",
"\"major\":0",
"\"minor\":1",
Expand Down
4 changes: 2 additions & 2 deletions test/starlark_tests/targets_under_test/ios/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4875,7 +4875,7 @@ swift_library(
name = "basic_framework_lib_with_docc_bundle",
srcs = ["//test/starlark_tests/resources:BasicFramework.swift"],
data = ["//test/starlark_tests/resources:basic_docc_bundle_files"],
module_name = "BasicFramework",
module_name = "BasicFrameworkWithDocCBundle",
tags = common.fixture_tags,
visibility = ["//visibility:public"],
)
Expand All @@ -4901,7 +4901,7 @@ docc_archive(
ios_dynamic_framework(
name = "basic_framework_with_docc_bundle",
bundle_id = "com.google.example.framework",
bundle_name = "BasicFramework",
bundle_name = "BasicFrameworkWithDocCBundle",
families = [
"iphone",
"ipad",
Expand Down

0 comments on commit 168a214

Please sign in to comment.