Skip to content

Commit

Permalink
Add swift_proto_library_group rule (#1173)
Browse files Browse the repository at this point in the history
  • Loading branch information
AttilaTheFun authored Apr 5, 2024
1 parent 72347ab commit ea2d4bd
Show file tree
Hide file tree
Showing 29 changed files with 1,139 additions and 209 deletions.
1 change: 1 addition & 0 deletions doc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ _DOC_SRCS = {
"swift_package_configuration",
"swift_test",
"swift_proto_library",
"swift_proto_library_group",
"swift_proto_compiler",
"deprecated_swift_grpc_library",
"deprecated_swift_proto_library",
Expand Down
2 changes: 2 additions & 0 deletions doc/doc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ load(
# rules
_swift_proto_compiler = "swift_proto_compiler",
_swift_proto_library = "swift_proto_library",
_swift_proto_library_group = "swift_proto_library_group",
)
load(
"//swift:swift.bzl",
Expand Down Expand Up @@ -77,6 +78,7 @@ SwiftProtoCompilerInfo = _SwiftProtoCompilerInfo
SwiftProtoInfo = _SwiftProtoInfo
swift_proto_compiler = _swift_proto_compiler
swift_proto_library = _swift_proto_library
swift_proto_library_group = _swift_proto_library_group

# swift symbols
swift_common = _swift_common
Expand Down
5 changes: 3 additions & 2 deletions doc/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ has reasonable defaults for any fields not explicitly set.
## SwiftProtoCompilerInfo

<pre>
SwiftProtoCompilerInfo(<a href="#SwiftProtoCompilerInfo-compile">compile</a>, <a href="#SwiftProtoCompilerInfo-compiler_deps">compiler_deps</a>, <a href="#SwiftProtoCompilerInfo-internal">internal</a>)
SwiftProtoCompilerInfo(<a href="#SwiftProtoCompilerInfo-bundled_proto_paths">bundled_proto_paths</a>, <a href="#SwiftProtoCompilerInfo-compile">compile</a>, <a href="#SwiftProtoCompilerInfo-compiler_deps">compiler_deps</a>, <a href="#SwiftProtoCompilerInfo-internal">internal</a>)
</pre>

Provides information needed to generate Swift code from `ProtoInfo` providers
Expand All @@ -72,7 +72,8 @@ Provides information needed to generate Swift code from `ProtoInfo` providers

| Name | Description |
| :------------- | :------------- |
| <a id="SwiftProtoCompilerInfo-compile"></a>compile | A function which compiles Swift source files from `ProtoInfo` providers.<br><br>Args: ctx: the `swift_proto_library` target's context swift_proto_compiler_info: this `SwiftProtoCompilerInfo` provider additional_compiler_info: information passed from the `swift_proto_library` target to the compiler proto_infos: the list of `ProtoInfo` providers to compile module_mappings: the module_mappings field of the `SwiftProtoInfo` for the `swift_proto_library` target<br><br>Returns: A list of .swift Files generated by the compiler. |
| <a id="SwiftProtoCompilerInfo-bundled_proto_paths"></a>bundled_proto_paths | List of proto paths for which to skip generation because they're built into the modules imported by the generated Swift proto code, e.g., SwiftProtobuf. |
| <a id="SwiftProtoCompilerInfo-compile"></a>compile | A function which compiles Swift source files from `ProtoInfo` providers.<br><br>Args: label: The label of the target for which the Swift files are being generated. actions: The actions object used to declare the files to be generated and the actions that generate them. swift_proto_compiler_info: This `SwiftProtoCompilerInfo` provider. additional_compiler_info: Additional information passed from the target target to the compiler. proto_infos: The list of `ProtoInfo` providers to compile. module_mappings: The module_mappings field of the `SwiftProtoInfo` for the target.<br><br>Returns: A list of .swift Files generated by the compiler. |
| <a id="SwiftProtoCompilerInfo-compiler_deps"></a>compiler_deps | List of targets providing SwiftInfo and CcInfo. These are added as dependencies to the swift compile action of the swift_proto_library. Typically these are proto runtime libraries.<br><br>Well Known Types should be added as dependencies of the swift_proto_library targets as needed to avoid compiling them unnecessarily. |
| <a id="SwiftProtoCompilerInfo-internal"></a>internal | Opaque struct passing information from the compiler target to the compile function. |

Expand Down
84 changes: 82 additions & 2 deletions doc/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ On this page:
* [swift_package_configuration](#swift_package_configuration)
* [swift_test](#swift_test)
* [swift_proto_library](#swift_proto_library)
* [swift_proto_library_group](#swift_proto_library_group)
* [swift_proto_compiler](#swift_proto_compiler)
* [deprecated_swift_grpc_library](#deprecated_swift_grpc_library)
* [deprecated_swift_proto_library](#deprecated_swift_proto_library)
Expand Down Expand Up @@ -594,8 +595,8 @@ target's label is included by the package specifications in the configuration.
## swift_proto_compiler

<pre>
swift_proto_compiler(<a href="#swift_proto_compiler-name">name</a>, <a href="#swift_proto_compiler-deps">deps</a>, <a href="#swift_proto_compiler-plugin">plugin</a>, <a href="#swift_proto_compiler-plugin_name">plugin_name</a>, <a href="#swift_proto_compiler-plugin_option_allowlist">plugin_option_allowlist</a>, <a href="#swift_proto_compiler-plugin_options">plugin_options</a>,
<a href="#swift_proto_compiler-protoc">protoc</a>, <a href="#swift_proto_compiler-suffixes">suffixes</a>)
swift_proto_compiler(<a href="#swift_proto_compiler-name">name</a>, <a href="#swift_proto_compiler-deps">deps</a>, <a href="#swift_proto_compiler-bundled_proto_paths">bundled_proto_paths</a>, <a href="#swift_proto_compiler-plugin">plugin</a>, <a href="#swift_proto_compiler-plugin_name">plugin_name</a>, <a href="#swift_proto_compiler-plugin_option_allowlist">plugin_option_allowlist</a>,
<a href="#swift_proto_compiler-plugin_options">plugin_options</a>, <a href="#swift_proto_compiler-protoc">protoc</a>, <a href="#swift_proto_compiler-suffixes">suffixes</a>)
</pre>


Expand All @@ -607,6 +608,7 @@ swift_proto_compiler(<a href="#swift_proto_compiler-name">name</a>, <a href="#sw
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="swift_proto_compiler-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="swift_proto_compiler-deps"></a>deps | List of targets providing SwiftInfo and CcInfo. Added as implicit dependencies for any swift_proto_library using this compiler. Typically, these are Well Known Types and proto runtime libraries. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |
| <a id="swift_proto_compiler-bundled_proto_paths"></a>bundled_proto_paths | List of proto paths for which to skip generation because they're built into the modules imported by the generated Swift proto code, e.g., SwiftProtobuf. | List of strings | optional | `["google/protobuf/any.proto", "google/protobuf/api.proto", "google/protobuf/descriptor.proto", "google/protobuf/duration.proto", "google/protobuf/empty.proto", "google/protobuf/field_mask.proto", "google/protobuf/source_context.proto", "google/protobuf/struct.proto", "google/protobuf/timestamp.proto", "google/protobuf/type.proto", "google/protobuf/wrappers.proto"]` |
| <a id="swift_proto_compiler-plugin"></a>plugin | A proto compiler plugin executable binary.<br><br>For example: "//tools/protoc_wrapper:protoc-gen-grpc-swift" "//tools/protoc_wrapper:ProtoCompilerPlugin" | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="swift_proto_compiler-plugin_name"></a>plugin_name | Name of the proto compiler plugin passed to protoc.<br><br>For example:<br><br><pre><code>protoc --plugin=protoc-gen-NAME=path/to/plugin/binary</code></pre><br><br>This name will be used to prefix the option and output directory arguments. E.g.:<br><br><pre><code>protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR --NAME_opt=Visibility=Public</code></pre><br><br>See the [protobuf API reference](https://protobuf.dev/reference/cpp/api-docs/google.protobuf.compiler.plugin) for more information. | String | required | |
| <a id="swift_proto_compiler-plugin_option_allowlist"></a>plugin_option_allowlist | Allowlist of options allowed by the plugin. This is used to filter out any irrelevant plugin options passed down to the compiler from the library, which is especially useful when using multiple plugins in combination like GRPC and SwiftProtobuf. | List of strings | required | |
Expand Down Expand Up @@ -690,6 +692,84 @@ swift_proto_library(
| <a id="swift_proto_library-swiftc_inputs"></a>swiftc_inputs | Additional files that are referenced using `$(location ...)` in attributes that support location expansion. | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional | `[]` |


<a id="swift_proto_library_group"></a>

## swift_proto_library_group

<pre>
swift_proto_library_group(<a href="#swift_proto_library_group-name">name</a>, <a href="#swift_proto_library_group-compiler">compiler</a>, <a href="#swift_proto_library_group-proto">proto</a>)
</pre>

Generates a collection of Swift static library from a target producing `ProtoInfo` and its dependencies.

This rule is intended to facilitate migration from the deprecated swift proto library rules to the new ones.
Unlike `swift_proto_library` which is a drop-in-replacement for `swift_library`,
this rule uses an aspect over the direct proto library dependency and its transitive dependencies,
compiling each into a swift static library.

For example, in the following targets, the `proto_library_group_swift_proto` target only depends on
`package_2_proto` target, and this transitively depends on `package_1_proto`.

When used as a dependency from a `swift_library` or `swift_binary` target,
two modules generated from these proto library targets are visible.

Because these are derived from the proto library targets via an aspect, though,
you cannot customize many of the attributes including the swift proto compiler targets or
the module names. The module names are derived from the proto library names.

In this case, the module names are:
```
import examples_xplatform_proto_library_group_package_1_package_1_proto
import examples_xplatform_proto_library_group_package_2_package_2_proto
```

For this reason, we would encourage new consumers of the proto rules to use
`swift_proto_library` when possible.

```python
proto_library(
name = "package_1_proto",
srcs = glob(["*.proto"]),
visibility = ["//visibility:public"],
)

...

proto_library(
name = "package_2_proto",
srcs = glob(["*.proto"]),
visibility = ["//visibility:public"],
deps = ["//examples/xplatform/proto_library_group/package_1:package_1_proto"],
)

...

swift_proto_library_group(
name = "proto_library_group_swift_proto",
proto = "//examples/xplatform/proto_library_group/package_2:package_2_proto",
)

...

swift_binary(
name = "proto_library_group_example",
srcs = ["main.swift"],
deps = [
":proto_library_group_swift_proto",
],
)
```

**ATTRIBUTES**


| Name | Description | Type | Mandatory | Default |
| :------------- | :------------- | :------------- | :------------- | :------------- |
| <a id="swift_proto_library_group-name"></a>name | A unique name for this target. | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required | |
| <a id="swift_proto_library_group-compiler"></a>compiler | A `swift_proto_compiler` target (or target producing `SwiftProtoCompilerInfo`), from which the Swift protos will be generated. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `"@build_bazel_rules_swift//proto/compilers:swift_proto"` |
| <a id="swift_proto_library_group-proto"></a>proto | Exactly one `proto_library` target (or target producing `ProtoInfo`), from which the Swift source files should be generated. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |


<a id="swift_test"></a>

## swift_test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ load(
"SwiftInfo",
)

def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compiler_info, proto_infos, module_mappings):
def _custom_swift_proto_compile(label, actions, swift_proto_compiler_info, additional_compiler_info, proto_infos, module_mappings):
"""Compiles Swift source files from `ProtoInfo` providers.
Args:
ctx: the `swift_proto_library` target's context
swift_proto_compiler_info: this `SwiftProtoCompilerInfo` provider
additional_compiler_info: information passed from the `swift_proto_library` target to the compiler
proto_infos: the list of `ProtoInfo` providers to compile
module_mappings: the module_mappings field of the `SwiftProtoInfo` for the `swift_proto_library` target
label: The label of the target for which the Swift files are being generated.
actions: The actions object used to declare the files to be generated and the actions that generate them.
swift_proto_compiler_info: This `SwiftProtoCompilerInfo` provider.
additional_compiler_info: Additional information passed from the target target to the compiler.
proto_infos: The list of `ProtoInfo` providers to compile.
module_mappings: The module_mappings field of the `SwiftProtoInfo` for the target.
Returns:
A list of .swift Files generated by the compiler.
A `list` of `.swift` `File`s generated by the compiler.
"""

# Declare the Swift files that will be generated:
Expand All @@ -68,8 +69,8 @@ def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compi

# Declare the Swift source files that will be generated:
base_swift_src_path = paths.replace_extension(path, ".swift")
swift_src_path = paths.join(ctx.label.name, base_swift_src_path)
swift_src = ctx.actions.declare_file(swift_src_path)
swift_src_path = paths.join(label.name, base_swift_src_path)
swift_src = actions.declare_file(swift_src_path)
swift_srcs.append(swift_src)
transitive_proto_srcs = depset(direct = [], transitive = transitive_proto_srcs_list)

Expand All @@ -78,15 +79,15 @@ def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compi
swift_srcs.extend([])

# Build the arguments for compiler:
arguments = ctx.actions.args()
arguments = actions.args()
arguments.use_param_file("--param=%s")

# Finally, add the proto paths:
# arguments.add_all(proto_paths.keys())
arguments.add_all(swift_srcs)

# Run the compiler action:
ctx.actions.run(
actions.run(
inputs = depset(
direct = [],
transitive = [transitive_proto_srcs],
Expand All @@ -103,6 +104,7 @@ def _custom_swift_proto_compile(ctx, swift_proto_compiler_info, additional_compi
def _custom_swift_proto_compiler_impl(ctx):
return [
SwiftProtoCompilerInfo(
bundled_proto_paths = [],
compile = _custom_swift_proto_compile,
compiler_deps = ctx.attr.deps,
internal = struct(
Expand Down
33 changes: 33 additions & 0 deletions examples/xplatform/proto_library_group/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
load(
"//swift:swift.bzl",
"swift_binary",
"swift_test",
)

swift_binary(
name = "echo_server",
srcs = ["server_main.swift"],
deps = [
"//examples/xplatform/proto_library_group/service:service_server_swift_proto",
],
)

swift_binary(
name = "echo_client",
srcs = ["client_main.swift"],
deps = [
"//examples/xplatform/proto_library_group/service:service_client_swift_proto",
],
)

swift_test(
name = "echo_client_unit_test",
srcs = [
"client_unit_test.swift",
"main.swift",
],
deps = [
"//examples/xplatform/proto_library_group/service:service_client_swift_proto",
"//examples/xplatform/proto_library_group/service:service_server_swift_proto",
],
)
64 changes: 64 additions & 0 deletions examples/xplatform/proto_library_group/client_main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2019 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.

import Foundation
import SwiftProtobuf
import GRPC
import NIOCore
import NIOPosix
import examples_xplatform_proto_library_group_request_request_proto
import ServiceClient

@main
struct ClientMain {
static func main() throws {
// Setup an `EventLoopGroup` for the connection to run on.
//
// See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)

// Make sure the group is shutdown when we're done with it.
defer {
try! group.syncShutdownGracefully()
}

// Configure the channel, we're not using TLS so the connection is `insecure`.
let channel = try GRPCChannelPool.with(
target: .host("localhost", port: 9000),
transportSecurity: .plaintext,
eventLoopGroup: group
)

// Initialize the client using the same address the server is started on.
let client = Service_EchoServiceNIOClient(channel: channel)

// Construct a request to the echo service.
let request = Request_Request.with {
$0.message = "Hello, world!"
let timestamp = Google_Protobuf_Timestamp(date: Date())
$0.extra = try! Google_Protobuf_Any(message: timestamp)
}

let call = client.echo(request)

// Make the remote method call and print the response we receive.
do {
let response = try call.response.wait()
print(response.request.message)
print(response.request.extra)
} catch {
print("Echo failed: \(error)")
}
}
}
Loading

0 comments on commit ea2d4bd

Please sign in to comment.