Skip to content

Commit

Permalink
Add ExtensionKit support to ios_extension, macos_extension and tvos_e…
Browse files Browse the repository at this point in the history
…xtension rules.

PiperOrigin-RevId: 537994618
  • Loading branch information
nglevin authored and swiple-rules-gardener committed Jun 5, 2023
1 parent 736d977 commit 3eb01c3
Show file tree
Hide file tree
Showing 18 changed files with 334 additions and 33 deletions.
6 changes: 6 additions & 0 deletions apple/internal/apple_product_type.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ visibility([
# if needed.
# * `dylib`: A dynamically-loadable library. This is the default product type for
# `macos_dylib`; it does not need to be set explicitly (and cannot be changed).
# * `extensionkit_extension`: A basic iOS, macOS, or tvOS ExtensionKit extension.
# These are `.appex` bundles located in an application's `Extensions`
# subdirectory. Third-party specs to define the integration points for third-
# party ExtensionKit extensions can be defined through `.appextensionpoint` XML
# plists on macOS.
# * `framework`: A basic dynamic framework. This is the default product type for
# those targets; it does not need to be set explicitly (and cannot be changed).
# * `kernel_extension`: A macOS kernel extension. This product type should be used
Expand Down Expand Up @@ -90,6 +95,7 @@ apple_product_type = struct(
app_extension = "com.apple.product-type.app-extension",
bundle = "com.apple.product-type.bundle",
dylib = "com.apple.product-type.library.dynamic",
extensionkit_extension = "com.apple.product-type.extensionkit-extension",
framework = "com.apple.product-type.framework",
kernel_extension = "com.apple.product-type.kernel-extension",
messages_application = "com.apple.product-type.application.messages",
Expand Down
23 changes: 20 additions & 3 deletions apple/internal/ios_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -975,10 +975,18 @@ def _ios_framework_impl(ctx):
] + processor_result.providers

def _ios_extension_impl(ctx):
"""Experimental implementation of ios_extension."""
"""Implementation of ios_extension."""

product_type = apple_product_type.app_extension
if ctx.attr.extensionkit_extension:
# TODO(b/283788062): Add a new type of Info.plist verification around the new
# EXExtensionPointIdentifier and EXAppExtensionAttributes keys to make sure that they are
# defined, and (potentially) that references to NSExtension keys are not present.
product_type = apple_product_type.extensionkit_extension

rule_descriptor = rule_support.rule_descriptor(
platform_type = ctx.attr.platform_type,
product_type = apple_product_type.app_extension,
product_type = product_type,
)

actions = ctx.actions
Expand Down Expand Up @@ -1073,6 +1081,14 @@ def _ios_extension_impl(ctx):
predeclared_outputs = predeclared_outputs,
)

embedded_bundles_args = {}
if rule_descriptor.product_type == apple_product_type.app_extension:
embedded_bundles_args["plugins"] = [archive_for_embedding]
elif rule_descriptor.product_type == apple_product_type.extensionkit_extension:
embedded_bundles_args["extensions"] = [archive_for_embedding]
else:
fail("Internal Error: Unexpectedly found product_type " + rule_descriptor.product_type)

processor_partials = [
partials.app_assets_validation_partial(
app_icons = ctx.files.app_icons,
Expand Down Expand Up @@ -1135,7 +1151,7 @@ def _ios_extension_impl(ctx):
partials.embedded_bundles_partial(
embeddable_targets = ctx.attr.frameworks,
platform_prerequisites = platform_prerequisites,
plugins = [archive_for_embedding],
**embedded_bundles_args
),
partials.extension_safe_validation_partial(
is_extension_safe = True,
Expand Down Expand Up @@ -1975,6 +1991,7 @@ ios_extension = rule_factory.create_apple_rule(
allowed_families = rule_attrs.defaults.allowed_families.ios,
is_mandatory = True,
),
rule_attrs.extensionkit_attrs(),
rule_attrs.infoplist_attrs(),
rule_attrs.platform_attrs(
platform_type = "ios",
Expand Down
23 changes: 20 additions & 3 deletions apple/internal/macos_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,18 @@ def _macos_bundle_impl(ctx):
] + processor_result.providers

def _macos_extension_impl(ctx):
"""Experimental implementation of macos_extension."""
"""Implementation of macos_extension."""

product_type = apple_product_type.app_extension
if ctx.attr.extensionkit_extension:
# TODO(b/283788062): Add a new type of Info.plist verification around the new
# EXExtensionPointIdentifier and EXAppExtensionAttributes keys to make sure that they are
# defined, and (potentially) that references to NSExtension keys are not present.
product_type = apple_product_type.extensionkit_extension

rule_descriptor = rule_support.rule_descriptor(
platform_type = ctx.attr.platform_type,
product_type = apple_product_type.app_extension,
product_type = product_type,
)

actions = ctx.actions
Expand Down Expand Up @@ -703,6 +711,14 @@ def _macos_extension_impl(ctx):
predeclared_outputs = predeclared_outputs,
)

embedded_bundles_args = {}
if rule_descriptor.product_type == apple_product_type.app_extension:
embedded_bundles_args["plugins"] = [archive]
elif rule_descriptor.product_type == apple_product_type.extensionkit_extension:
embedded_bundles_args["extensions"] = [archive]
else:
fail("Internal Error: Unexpectedly found product_type " + rule_descriptor.product_type)

processor_partials = [
partials.apple_bundle_info_partial(
actions = actions,
Expand Down Expand Up @@ -758,7 +774,7 @@ def _macos_extension_impl(ctx):
),
partials.embedded_bundles_partial(
platform_prerequisites = platform_prerequisites,
plugins = [archive],
**embedded_bundles_args
),
partials.macos_additional_contents_partial(
additional_contents = ctx.attr.additional_contents,
Expand Down Expand Up @@ -2110,6 +2126,7 @@ macos_extension = rule_factory.create_apple_rule(
allowed_families = rule_attrs.defaults.allowed_families.macos,
is_mandatory = False,
),
rule_attrs.extensionkit_attrs(),
rule_attrs.infoplist_attrs(),
rule_attrs.platform_attrs(
add_environment_plist = True,
Expand Down
11 changes: 8 additions & 3 deletions apple/internal/partials/embedded_bundles.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def _embedded_bundles_partial_impl(
# Map of embedded bundle type to their final location in the top-level bundle.
bundle_type_to_location = {
"app_clips": processor.location.app_clip,
"extensions": processor.location.extension,
"frameworks": processor.location.framework,
"plugins": processor.location.plugin,
"watch_bundles": processor.location.watch,
Expand Down Expand Up @@ -150,6 +151,7 @@ def embedded_bundles_partial(
app_clips = [],
bundle_embedded_bundles = False,
embeddable_targets = [],
extensions = [],
frameworks = [],
platform_prerequisites,
plugins = [],
Expand All @@ -159,9 +161,9 @@ def embedded_bundles_partial(
"""Constructor for the embedded bundles processing partial.
This partial is used to propagate and package embedded bundles into their respective locations
inside top level bundling targets. Embeddable bundles are considered to be
frameworks, plugins (i.e. extensions) and watchOS applications in the case of
ios_application.
inside top level bundling targets. Embeddable bundles are considered to be extensions (i.e.
ExtensionKit extensions), frameworks, plugins (i.e. NSExtension extensions) and watchOS
applications in the case of ios_application.
Args:
app_clips: List of plugin bundles that should be propagated downstream for a top level
Expand All @@ -171,6 +173,8 @@ def embedded_bundles_partial(
embeddable bundles will be propagated downstream for a top level target to bundle them.
embeddable_targets: The list of targets that propagate embeddable bundles to bundle or
propagate.
extensions: List of ExtensionKit extension bundles that should be propagated downstream for
a top level target to bundle inside `Extensions`.
frameworks: List of framework bundles that should be propagated downstream for a top level
target to bundle inside `Frameworks`.
platform_prerequisites: Struct containing information on the platform being targeted.
Expand All @@ -191,6 +195,7 @@ def embedded_bundles_partial(
app_clips = app_clips,
bundle_embedded_bundles = bundle_embedded_bundles,
embeddable_targets = embeddable_targets,
extensions = extensions,
frameworks = frameworks,
platform_prerequisites = platform_prerequisites,
plugins = plugins,
Expand Down
6 changes: 6 additions & 0 deletions apple/internal/processor.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Location types can be:
- binary: Files are to be placed in the binary section of the bundle.
- bundle: Files are to be placed at the root of the bundle.
- content: Files are to be placed in the contents section of the bundle.
- extension: Files are to be placed in the Extensions section of the bundle.
- framework: Files are to be placed in the Frameworks section of the bundle.
- plugin: Files are to be placed in the PlugIns section of the bundle.
- resources: Files are to be placed in the resources section of the bundle.
Expand Down Expand Up @@ -112,6 +113,7 @@ _LOCATION_ENUM = struct(
binary = "binary",
bundle = "bundle",
content = "content",
extension = "extension",
framework = "framework",
plugin = "plugin",
resource = "resource",
Expand Down Expand Up @@ -196,6 +198,10 @@ def _archive_paths(
),
_LOCATION_ENUM.bundle: bundle_path,
_LOCATION_ENUM.content: contents_path,
_LOCATION_ENUM.extension: paths.join(
contents_path,
rule_descriptor.bundle_locations.contents_relative_extensions,
),
_LOCATION_ENUM.framework: paths.join(
contents_path,
rule_descriptor.bundle_locations.contents_relative_frameworks,
Expand Down
3 changes: 3 additions & 0 deletions apple/internal/providers/embeddable_info.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Do not depend on this provider for non Apple rules.
"app_clips": """
A depset with the zipped archives of bundles that need to be expanded into the
AppClips section of the packaging bundle.""",
"extensions": """
A depset with the zipped archives of bundles that need to be expanded into the
Extensions section of the packaging bundle.""",
"frameworks": """
A depset with the zipped archives of bundles that need to be expanded into the
Frameworks section of the packaging bundle.""",
Expand Down
9 changes: 9 additions & 0 deletions apple/internal/rule_attrs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,14 @@ least one must be specified.
),
}

def _extensionkit_attrs():
"""Returns the attributes required to define a target as an ExtensionKit extension."""
return {
"extensionkit_extension": attr.bool(
doc = "Indicates if this target should be treated as an ExtensionKit extension.",
),
}

def _app_icon_attrs(*, icon_extension = ".appiconset", icon_parent_extension = ".xcassets"):
"""Returns the attribute required to define app icons for the given target.
Expand Down Expand Up @@ -687,6 +695,7 @@ rule_attrs = struct(
common_tool_attrs = _common_tool_attrs,
custom_transition_allowlist_attr = _custom_transition_allowlist_attr,
device_family_attrs = _device_family_attrs,
extensionkit_attrs = _extensionkit_attrs,
infoplist_attrs = _infoplist_attrs,
launch_images_attrs = _launch_images_attrs,
platform_attrs = _platform_attrs,
Expand Down
50 changes: 47 additions & 3 deletions apple/internal/rule_support.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def _describe_bundle_locations(
bundle_relative_contents = "",
contents_relative_app_clips = "AppClips",
contents_relative_binary = "",
contents_relative_extensions = "Extensions",
contents_relative_frameworks = "Frameworks",
contents_relative_plugins = "PlugIns",
contents_relative_resources = "",
Expand All @@ -64,6 +65,7 @@ def _describe_bundle_locations(
bundle_relative_contents = bundle_relative_contents,
contents_relative_app_clips = contents_relative_app_clips,
contents_relative_binary = contents_relative_binary,
contents_relative_extensions = contents_relative_extensions,
contents_relative_frameworks = contents_relative_frameworks,
contents_relative_plugins = contents_relative_plugins,
contents_relative_resources = contents_relative_resources,
Expand Down Expand Up @@ -179,7 +181,7 @@ _RULE_TYPE_DESCRIPTORS = {
"@executable_path/Frameworks",
],
),
# ios_extension
# ios_extension (NSExtension)
apple_product_type.app_extension: _describe_rule_type(
allowed_device_families = ["iphone", "ipad"],
allows_locale_trimming = True,
Expand All @@ -192,6 +194,19 @@ _RULE_TYPE_DESCRIPTORS = {
"@executable_path/../../Frameworks",
],
),
# ios_extension (ExtensionKit)
apple_product_type.extensionkit_extension: _describe_rule_type(
allowed_device_families = ["iphone", "ipad"],
allows_locale_trimming = True,
bundle_extension = ".appex",
bundle_package_type = bundle_package_type.extension_or_xpc,
product_type = apple_product_type.extensionkit_extension,
rpaths = [
# ExtensionKit binaries live in Application.app/Extensions/Extension.appex/Extension
# Frameworks are packaged in Application.app/Frameworks
"@executable_path/../../Frameworks",
],
),
# ios_framework
apple_product_type.framework: _describe_rule_type(
allowed_device_families = ["iphone", "ipad"],
Expand Down Expand Up @@ -302,7 +317,7 @@ _RULE_TYPE_DESCRIPTORS = {
product_type = apple_product_type.dylib,
requires_signing_for_device = False,
),
# macos_extension
# macos_extension (NSExtension)
apple_product_type.app_extension: _describe_rule_type(
allowed_device_families = ["mac"],
allows_locale_trimming = True,
Expand All @@ -318,6 +333,22 @@ _RULE_TYPE_DESCRIPTORS = {
"@executable_path/../../../../Frameworks",
],
),
# macos_extension (ExtensionKit)
apple_product_type.extensionkit_extension: _describe_rule_type(
allowed_device_families = ["mac"],
allows_locale_trimming = True,
bundle_extension = ".appex",
bundle_locations = _DEFAULT_MACOS_BUNDLE_LOCATIONS,
bundle_package_type = bundle_package_type.extension_or_xpc,
product_type = apple_product_type.extensionkit_extension,
requires_signing_for_device = False,
rpaths = [
# ExtensionKit binaries live in
# Application.app/Contents/Extensions/Extension.appex/Contents/MacOS/Extension
# Frameworks are packaged in Application.app/Contents/Frameworks
"@executable_path/../../../../Frameworks",
],
),
# macos_quick_look_plugin
apple_product_type.quicklook_plugin: _describe_rule_type(
allowed_device_families = ["mac"],
Expand Down Expand Up @@ -428,7 +459,7 @@ _RULE_TYPE_DESCRIPTORS = {
"@executable_path/Frameworks",
],
),
# tvos_extension
# tvos_extension (NSExtension)
apple_product_type.app_extension: _describe_rule_type(
allowed_device_families = ["tv"],
allows_locale_trimming = True,
Expand All @@ -441,6 +472,19 @@ _RULE_TYPE_DESCRIPTORS = {
"@executable_path/../../Frameworks",
],
),
# tvos_extension (ExtensionKit)
apple_product_type.extensionkit_extension: _describe_rule_type(
allowed_device_families = ["tv"],
allows_locale_trimming = True,
bundle_extension = ".appex",
bundle_package_type = bundle_package_type.extension_or_xpc,
product_type = apple_product_type.extensionkit_extension,
rpaths = [
# Extension binaries live in Application.app/Extensions/Extension.appex/Extension
# Frameworks are packaged in Application.app/Frameworks
"@executable_path/../../Frameworks",
],
),
# tvos_framework
apple_product_type.framework: _describe_rule_type(
allowed_device_families = ["tv"],
Expand Down
23 changes: 20 additions & 3 deletions apple/internal/tvos_rules.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -630,10 +630,18 @@ def _tvos_framework_impl(ctx):
] + processor_result.providers

def _tvos_extension_impl(ctx):
"""Experimental implementation of tvos_extension."""
"""Implementation of tvos_extension."""

product_type = apple_product_type.app_extension
if ctx.attr.extensionkit_extension:
# TODO(b/283788062): Add a new type of Info.plist verification around the new
# EXExtensionPointIdentifier and EXAppExtensionAttributes keys to make sure that they are
# defined, and (potentially) that references to NSExtension keys are not present.
product_type = apple_product_type.extensionkit_extension

rule_descriptor = rule_support.rule_descriptor(
platform_type = ctx.attr.platform_type,
product_type = apple_product_type.app_extension,
product_type = product_type,
)

actions = ctx.actions
Expand Down Expand Up @@ -725,6 +733,14 @@ def _tvos_extension_impl(ctx):
predeclared_outputs = predeclared_outputs,
)

embedded_bundles_args = {}
if rule_descriptor.product_type == apple_product_type.app_extension:
embedded_bundles_args["plugins"] = [archive]
elif rule_descriptor.product_type == apple_product_type.extensionkit_extension:
embedded_bundles_args["extensions"] = [archive]
else:
fail("Internal Error: Unexpectedly found product_type " + rule_descriptor.product_type)

processor_partials = [
partials.apple_bundle_info_partial(
actions = actions,
Expand Down Expand Up @@ -782,7 +798,7 @@ def _tvos_extension_impl(ctx):
partials.embedded_bundles_partial(
embeddable_targets = ctx.attr.frameworks,
platform_prerequisites = platform_prerequisites,
plugins = [archive],
**embedded_bundles_args
),
partials.extension_safe_validation_partial(
is_extension_safe = True,
Expand Down Expand Up @@ -1070,6 +1086,7 @@ tvos_extension = rule_factory.create_apple_rule(
rule_attrs.device_family_attrs(
allowed_families = rule_attrs.defaults.allowed_families.tvos,
),
rule_attrs.extensionkit_attrs(),
rule_attrs.infoplist_attrs(),
rule_attrs.platform_attrs(
add_environment_plist = True,
Expand Down
Loading

1 comment on commit 3eb01c3

@keith
Copy link
Member

@keith keith commented on 3eb01c3 Aug 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.