Skip to content

Commit

Permalink
Fix docc archive bugs (#2595)
Browse files Browse the repository at this point in the history
  • Loading branch information
AttilaTheFun authored Nov 13, 2024
1 parent 35f9b94 commit af02ac9
Show file tree
Hide file tree
Showing 7 changed files with 221 additions and 36 deletions.
35 changes: 25 additions & 10 deletions apple/internal/aspects/docc_archive_aspect.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,28 @@ def _swift_symbol_graphs(*, swift_symbol_graph_info):

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 = []
docc_bundle_paths = {}

# Find the path to the .docc directory if it exists.
for data_target in ctx.rule.attr.data:
for file in data_target.files.to_list():
if file.extension == "docc":
docc_bundles.append(file)

if len(docc_bundles) > 1:
components = file.short_path.split("/")
for index, component in enumerate(components):
if component.endswith(".docc"):
docc_bundle_path = "/".join(components[0:index + 1])
docc_bundle_files = docc_bundle_paths[docc_bundle_path] if docc_bundle_path in docc_bundle_paths else []
docc_bundle_files.append(file)
docc_bundle_paths[docc_bundle_path] = docc_bundle_files
break

# Validate the docc bundle, if any.
if len(docc_bundle_paths) > 1:
fail("Expected target %s to have at most one .docc bundle in its data" % target.label)
if len(docc_bundle_paths) == 0:
return None, []

return docc_bundles[0] if docc_bundles else None
# Return the docc bundle path and files:
return docc_bundle_paths.items()[0]

def _docc_symbol_graphs_aspect_impl(target, ctx):
"""Creates a DocCSymbolGraphsInfo provider for targets which have a SwiftInfo provider (or which bundle a target that does)."""
Expand All @@ -76,18 +86,23 @@ def _docc_symbol_graphs_aspect_impl(target, ctx):
if not symbol_graphs:
return []

return [DocCSymbolGraphsInfo(symbol_graphs = symbol_graphs)]
return [DocCSymbolGraphsInfo(symbol_graphs = depset(symbol_graphs))]

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(
docc_bundle, docc_bundle_files = _first_docc_bundle(
target = target,
ctx = ctx,
)
if first_docc_bundle:
return [DocCBundleInfo(bundle = first_docc_bundle)]
if docc_bundle:
return [
DocCBundleInfo(
bundle = docc_bundle,
bundle_files = docc_bundle_files,
),
]
if hasattr(ctx.rule.attr, "deps"):
# If this target has "deps", try to find a DocCBundleInfo provider in its deps.
for dep in ctx.rule.attr.deps:
Expand Down
17 changes: 10 additions & 7 deletions apple/internal/docc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ def _docc_archive_impl(ctx):
if not symbol_graphs_info and not docc_bundle_info:
fail("At least one of DocCSymbolGraphsInfo or DocCBundleInfo must be provided for target %s" % ctx.attr.name)

symbol_graphs = symbol_graphs_info.symbol_graphs.to_list() if symbol_graphs_info else []

if ctx.attr.name.endswith(".doccarchive"):
doccarchive_dir = ctx.actions.declare_directory(ctx.attr.name)
else:
Expand All @@ -75,7 +77,6 @@ def _docc_archive_impl(ctx):
arguments = ctx.actions.args()
arguments.add("docc")
arguments.add("convert")
arguments.add("--index")
arguments.add("--fallback-display-name", fallback_display_name)
arguments.add("--fallback-bundle-identifier", fallback_bundle_identifier)
arguments.add("--fallback-bundle-version", fallback_bundle_version)
Expand All @@ -98,11 +99,11 @@ def _docc_archive_impl(ctx):
# Add symbol graphs
if symbol_graphs_info:
arguments.add_all(
symbol_graphs_info.symbol_graphs,
symbol_graphs,
before_each = "--additional-symbol-graph-dir",
expand_directories = False,
)
docc_build_inputs.extend(symbol_graphs_info.symbol_graphs)
docc_build_inputs.extend(symbol_graphs)

# The .docc bundle (if provided, only one is allowed)
if docc_bundle_info:
Expand All @@ -111,7 +112,7 @@ def _docc_archive_impl(ctx):
# TODO: no-sandbox seems to be required when running docc convert with a .docc bundle provided
# in the sandbox the tool is unable to open the .docc bundle.
execution_requirements["no-sandbox"] = "1"
docc_build_inputs.append(docc_bundle_info.bundle)
docc_build_inputs.extend(docc_bundle_info.bundle_files)

apple_support.run(
ctx,
Expand All @@ -130,13 +131,13 @@ def _docc_archive_impl(ctx):
output = preview_script,
template = ctx.file._preview_template,
substitutions = {
"{docc_bundle}": docc_bundle_info.bundle.path if docc_bundle_info else "",
"{docc_bundle}": docc_bundle_info.bundle if docc_bundle_info else "",
"{fallback_bundle_identifier}": fallback_bundle_identifier,
"{fallback_bundle_version}": str(fallback_bundle_version),
"{fallback_display_name}": fallback_display_name,
"{platform}": platform.name_in_plist,
"{sdk_version}": str(xcode_config.sdk_version_for_platform(platform)),
"{symbol_graph_dirs}": ",".join([f.path for f in symbol_graphs_info.symbol_graphs]) if symbol_graphs_info else "",
"{symbol_graph_dirs}": " ".join([f.path for f in symbol_graphs]) if symbol_graphs else "",
"{target_name}": ctx.attr.name,
"{xcode_version}": str(xcode_config.xcode_version()),
},
Expand All @@ -154,7 +155,9 @@ def _docc_archive_impl(ctx):
DefaultInfo(
files = depset([doccarchive_dir]),
executable = preview_script,
runfiles = ctx.runfiles(files = [preview_script] + docc_build_inputs),
runfiles = ctx.runfiles(files = [
preview_script,
] + docc_build_inputs),
),
doccarchive_binary_info,
]
Expand Down
47 changes: 31 additions & 16 deletions apple/internal/templates/docc_preview.template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,40 @@
# See the License for the specific language governing permissions and
# limitations under the License.

set -euo pipefail
set -exuo pipefail

if [ ! -d "{docc_bundle}" ]; then
echo "ERROR: Expected a .docc directory bundle for target: {target_name}"
echo "Previewing requires a .docc bundle to be provided in the target's resources."
exit 1
# Collect templated variables
additional_symbol_graph_dirs=({symbol_graph_dirs})
docc_bundle_path="{docc_bundle}"
fallback_bundle_identifier="{fallback_bundle_identifier}"
fallback_bundle_version="{fallback_bundle_version}"
fallback_display_name="{fallback_display_name}"
platform="{platform}"
sdk_version="{sdk_version}"
xcode_version="{xcode_version}"

arguments=()
output_dir="$(mktemp -d)"

# Add all symbol graph directories to the arguments
for additional_symbol_graph_dir in "${additional_symbol_graph_dirs[@]}"; do
arguments+=("--additional-symbol-graph-dir" "$additional_symbol_graph_dir")
done

# Add the docc bundle path to the arguments
if [ -d "$docc_bundle_path" ]; then
arguments+=("$docc_bundle_path")
fi

# Preview the docc archive
cd "$BUILD_WORKSPACE_DIRECTORY"

env -i \
APPLE_SDK_PLATFORM="{platform}" \
APPLE_SDK_VERSION_OVERRIDE="{sdk_version}" \
XCODE_VERSION_OVERRIDE="{xcode_version}" \
APPLE_SDK_PLATFORM="$platform" \
APPLE_SDK_VERSION_OVERRIDE="$sdk_version" \
XCODE_VERSION_OVERRIDE="$xcode_version" \
/usr/bin/xcrun docc preview \
--index \
--fallback-display-name "{fallback_display_name}" \
--fallback-bundle-identifier "{fallback_bundle_identifier}" \
--fallback-bundle-version "{fallback_bundle_version}" \
--additional-symbol-graph-dir "{symbol_graph_dirs}" \
--output-dir "$(mktemp -d)" \
"{docc_bundle}"
--fallback-display-name "$fallback_display_name" \
--fallback-bundle-identifier "$fallback_bundle_identifier" \
--fallback-bundle-version "$fallback_bundle_version" \
--output-dir "$output_dir" \
"${arguments[@]:-}"
3 changes: 2 additions & 1 deletion apple/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,13 @@ DocCBundleInfo = provider(
doc = "Provides general information about a .docc bundle.",
fields = {
"bundle": "the path to the .docc bundle",
"bundle_files": "the file targets contained within the .docc bundle",
},
)

DocCSymbolGraphsInfo = provider(
doc = "Provides the symbol graphs required to archive a .docc bundle.",
fields = {
"symbol_graphs": "the paths to the symbol graphs",
"symbol_graphs": "the depset of paths to the symbol graphs",
},
)
5 changes: 3 additions & 2 deletions doc/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ requirement.
## DocCBundleInfo

<pre>
DocCBundleInfo(<a href="#DocCBundleInfo-bundle">bundle</a>)
DocCBundleInfo(<a href="#DocCBundleInfo-bundle">bundle</a>, <a href="#DocCBundleInfo-bundle_files">bundle_files</a>)
</pre>

Provides general information about a .docc bundle.
Expand All @@ -483,6 +483,7 @@ Provides general information about a .docc bundle.
| Name | Description |
| :------------- | :------------- |
| <a id="DocCBundleInfo-bundle"></a>bundle | the path to the .docc bundle |
| <a id="DocCBundleInfo-bundle_files"></a>bundle_files | the file targets contained within the .docc bundle |


<a id="DocCSymbolGraphsInfo"></a>
Expand All @@ -500,7 +501,7 @@ Provides the symbol graphs required to archive a .docc bundle.

| Name | Description |
| :------------- | :------------- |
| <a id="DocCSymbolGraphsInfo-symbol_graphs"></a>symbol_graphs | the paths to the symbol graphs |
| <a id="DocCSymbolGraphsInfo-symbol_graphs"></a>symbol_graphs | the depset of paths to the symbol graphs |


<a id="IosAppClipBundleInfo"></a>
Expand Down
5 changes: 5 additions & 0 deletions test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,8 @@ apple_shell_test(
"//test/testdata/resources:resource_data_deps_platform_independent",
],
)

# apple_shell_test(
# name = "docc_archive_test",
# src = "docc_archive_test.sh",
# )
145 changes: 145 additions & 0 deletions test/docc_archive_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/bin/bash

# Copyright 2024 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Integration tests for testing `docc_archive` rules.

set -euo pipefail

function set_up() {
mkdir -p app
}

function tear_down() {
rm -rf app
}

function create_common_files() {
cat > app/BUILD <<EOF
load("@build_bazel_rules_apple//apple:docc.bzl", "docc_archive")
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application")
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "shared_logic",
module_name = "SharedLogic",
srcs = ["shared.swift"],
)
swift_library(
name = "app_lib",
srcs = ["App.swift"],
deps = [":shared_logic"],
)
swift_library(
name = "docc_bundle_lib",
srcs = ["bundle.swift"],
data = glob(["Resources/**"]),
)
ios_application(
name = "app",
bundle_id = "my.bundle.id",
families = ["iphone"],
infoplists = ["Info.plist"],
minimum_os_version = "${MIN_OS_IOS}",
provisioning_profile = "@build_bazel_rules_apple//test/testdata/provisioning:integration_testing_ios.mobileprovision",
deps = [":app_lib"],
)
docc_archive(
name = "docc_archive_without_docc_bundle",
dep = ":app",
fallback_bundle_identifier = "my.bundle.id",
fallback_bundle_version = "1.0",
fallback_display_name = "app",
)
docc_archive(
name = "docc_archive_with_docc_bundle",
dep = ":docc_bundle_lib",
fallback_bundle_identifier = "my.bundle.id.bundle_lib",
fallback_bundle_version = "1.0",
fallback_display_name = "bundle_lib",
)
EOF

cat > app/App.swift <<EOF
import SharedLogic
import SwiftUI
@main
public struct MyApp: App {
/// Initializes the app
public init() { }
/// The main body of the app
public var body: some Scene {
WindowGroup {
Text("Hello World")
.onAppear {
sharedDoSomething()
}
}
}
}
EOF

cat > app/shared.swift <<EOF
import Foundation
/// Does something
public func sharedDoSomething() { }
EOF

cat > app/bundle.swift <<EOF
import Foundation
/// Does something within the bundle
public func bundleDoSomething() { }
EOF

cat > app/Info.plist <<EOF
{
CFBundleIdentifier = "\${PRODUCT_BUNDLE_IDENTIFIER}";
CFBundleName = "\${PRODUCT_NAME}";
CFBundlePackageType = "APPL";
CFBundleShortVersionString = "1.0";
CFBundleVersion = "1.0";
}
EOF

mkdir -p app/Resources/Docs.docc
cat > app/Resources/Docs.docc/README.md <<EOF
# My App
This is a test app.
EOF

}

function test_preview_docc_archive_with_docc_bundle() {
create_common_files
do_action run ios //app:docc_archive_with_docc_bundle
}

function test_preview_docc_archive_without_docc_bundle() {
create_common_files
do_action run ios //app:docc_without_docc_bundle
}

run_suite "docc_archive tests"

0 comments on commit af02ac9

Please sign in to comment.