Skip to content

Commit

Permalink
feat: Implement support for new swift_proto_library rule (#834)
Browse files Browse the repository at this point in the history
This PR implements support in the gazelle plugin for the new swift proto
library implementation created in rules_swift:
bazelbuild/rules_swift#1140

There is more context on why the rewrite was necessary and what
opportunities the new implementation affords us on that PR.

The new implementation allows us to address the two most significant
issues with the current proto support:
- The old implementation used the SwiftProtobuf / GRPC libraries from
rules_swift, making them mutually exclusive with SPM-provided versions
in the same binary.
- As a workaround to the previous issue, we could generate the targets
but could not resolve the GRPC runtime dependencies because they came
from rules_swift, so you would see warnings about unknown GRPC,
SwiftProtobuf and SwiftNIO targets.

The new implementation fixes these issues by allowing us to declare our
own swift_proto_compiler target which uses the SwiftProtobuf and GRPC
targets provided through Swift Package Manager /
rules_swift_package_manager.

E.g.
```
swift_proto_compiler(
    name = "swift_proto",
    plugin = "@swiftpkg_swift_protobuf//:Sources_protoc-gen-swift",
    plugin_name = "swift",
    plugin_options = BASE_PLUGIN_OPTIONS,
    protoc = "@com_google_protobuf//:protoc",
    suffixes = [".pb.swift"],
    visibility = ["//visibility:public"],
    deps = [
        "@swiftpkg_swift_protobuf//:Sources_SwiftProtobuf",
    ],
)
```

These can then be passed into the swift_proto_library targets like so:
```
swift_proto_library(
    name = "echo_service_messages_swift_proto",
    compilers = ["//compilers:swift_proto"],
    module_name = "EchoServiceMessages",
    protos = [":echo_service_messages_proto"],
    visibility = ["//visibility:public"],
)
```

This is how the go_proto_library rule works as well.

I updated the gazelle plugin to support generating the new rules, with a
directive that allows you to pass these custom compiler targets. I also
updated the GRPC example to leverage all of these capabilities.

Now the gazelle plugin can properly resolve swift imports of the proto
libraries by their module name,
E.g. "import EchoServiceMessages", and it can also resolve dependencies
between proto libraries mapped to swift proto libraries, so if the
code-generated swift imports the same target, it'll receive the same
dependency.

NOTE: Due to a bug in rules_swift_package_manager, the GRPC dependencies
generated by this repository from the Package.swift are failing to
compile on Ubuntu 22.04 in CI.
#1012

Until this issue is fixed, we need to continue using the GRPC
dependencies from rules_swift, but I have split out a follow-up PR to
use the SPM version which I can land after the bug is fixed.
#1019

---------

Co-authored-by: Logan Shire <[email protected]>
Co-authored-by: Chuck Grindel <[email protected]>
  • Loading branch information
3 people authored Apr 18, 2024
1 parent 4080822 commit 75b5a7e
Show file tree
Hide file tree
Showing 55 changed files with 1,097 additions and 277 deletions.
4 changes: 2 additions & 2 deletions .bazelrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# To update these lines, execute
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
build --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Sources/System,bzlmod/workspace/Tests/MyLibraryTests,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/grpc_example,examples/grpc_example/aaa_test,examples/grpc_example/protos/echoservice,examples/grpc_example/protos/echoservice/messages,examples/grpc_example/sources,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/grpc_example/sources/test,examples/http_archive_ext_deps,examples/http_archive_ext_deps/Sources/MyDequeModule,examples/http_archive_ext_deps/Sources/PrintStuff,examples/http_archive_ext_deps/Tests/MyDequeModuleTests,examples/http_archive_ext_deps/third_party,examples/interesting_deps,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/ios_sim/third-party/swift-cmark,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources,examples/messagekit_example/UITests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example
query --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Sources/System,bzlmod/workspace/Tests/MyLibraryTests,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/grpc_example,examples/grpc_example/aaa_test,examples/grpc_example/protos/echoservice,examples/grpc_example/protos/echoservice/messages,examples/grpc_example/sources,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/grpc_example/sources/test,examples/http_archive_ext_deps,examples/http_archive_ext_deps/Sources/MyDequeModule,examples/http_archive_ext_deps/Sources/PrintStuff,examples/http_archive_ext_deps/Tests/MyDequeModuleTests,examples/http_archive_ext_deps/third_party,examples/interesting_deps,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/ios_sim/third-party/swift-cmark,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources,examples/messagekit_example/UITests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example
build --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Sources/System,bzlmod/workspace/Tests/MyLibraryTests,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/grpc_example,examples/grpc_example/aaa_test,examples/grpc_example/protos,examples/grpc_example/protos/echo_service,examples/grpc_example/protos/echo_service/requests,examples/grpc_example/protos/echo_service/responses,examples/grpc_example/sources,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/grpc_example/sources/test,examples/grpc_package_example,examples/grpc_package_example/aaa_test,examples/grpc_package_example/protos,examples/grpc_package_example/protos/echo_service,examples/grpc_package_example/sources,examples/grpc_package_example/sources/client,examples/grpc_package_example/sources/server,examples/grpc_package_example/sources/test,examples/http_archive_ext_deps,examples/http_archive_ext_deps/Sources/MyDequeModule,examples/http_archive_ext_deps/Sources/PrintStuff,examples/http_archive_ext_deps/Tests/MyDequeModuleTests,examples/http_archive_ext_deps/third_party,examples/interesting_deps,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/ios_sim/third-party/swift-cmark,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources,examples/messagekit_example/UITests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example
query --deleted_packages=bzlmod/workspace,bzlmod/workspace/Sources/MyExecutable,bzlmod/workspace/Sources/MyLibrary,bzlmod/workspace/Sources/System,bzlmod/workspace/Tests/MyLibraryTests,examples/firebase_example,examples/firebase_example/abtesting,examples/firebase_example/abtesting/SharedApp,examples/firebase_example/analytics/AnalyticsExample,examples/firebase_example/appdistribution,examples/firebase_example/appdistribution/AppDistributionExample,examples/firebase_example/appdistribution/AppDistributionTests,examples/firebase_example/crashlytics,examples/grpc_example,examples/grpc_example/aaa_test,examples/grpc_example/protos,examples/grpc_example/protos/echo_service,examples/grpc_example/protos/echo_service/requests,examples/grpc_example/protos/echo_service/responses,examples/grpc_example/sources,examples/grpc_example/sources/client,examples/grpc_example/sources/server,examples/grpc_example/sources/test,examples/grpc_package_example,examples/grpc_package_example/aaa_test,examples/grpc_package_example/protos,examples/grpc_package_example/protos/echo_service,examples/grpc_package_example/sources,examples/grpc_package_example/sources/client,examples/grpc_package_example/sources/server,examples/grpc_package_example/sources/test,examples/http_archive_ext_deps,examples/http_archive_ext_deps/Sources/MyDequeModule,examples/http_archive_ext_deps/Sources/PrintStuff,examples/http_archive_ext_deps/Tests/MyDequeModuleTests,examples/http_archive_ext_deps/third_party,examples/interesting_deps,examples/ios_sim,examples/ios_sim/Sources/Foo,examples/ios_sim/Tests/FooTests,examples/ios_sim/third-party/swift-cmark,examples/lottie_ios_example,examples/lottie_ios_example/LottieExample,examples/lottie_ios_example/LottieExampleUITest,examples/messagekit_example,examples/messagekit_example/Sources,examples/messagekit_example/UITests,examples/nimble_example,examples/nimble_example/Sources/NimbleExample,examples/objc_code,examples/phone_number_kit,examples/phone_number_kit/Tests/PhoneNumberKitTests,examples/pkg_manifest_minimal,examples/pkg_manifest_minimal/Sources/MyExecutable,examples/pkg_manifest_minimal/Sources/MyLibrary,examples/pkg_manifest_minimal/Tests/MyLibraryTests,examples/pkg_manifest_minimal/third_party,examples/resources_example,examples/resources_example/Sources/MyApp,examples/resources_example/Tests/MyAppTests,examples/resources_example/Tests/MyAppUITests,examples/resources_example/third_party,examples/shake_ios_example,examples/shake_ios_example/ShakeIOSExample,examples/shake_ios_example/ShakeIOSExampleUITests,examples/snapkit_example,examples/soto_example,examples/soto_example/Tests/SotoTests,examples/stripe_example,examples/stripe_example/PaymentSheet/PaymentSheetExample,examples/stripe_example/PaymentSheet/PaymentSheetUITest,examples/tca_example,examples/tca_example/Sources,examples/tca_example/Tests,examples/vapor_example,examples/vapor_example/Sources/App,examples/vapor_example/Sources/Run,examples/vapor_example/Tests/AppTests,examples/vapor_example/swift,examples/xcmetrics_example

# Import Shared settings
import %workspace%/shared.bazelrc
Expand Down
7 changes: 5 additions & 2 deletions examples/grpc_example/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ tidy(
# MARK: - Gazelle

# Ignore the Swift build folder
# gazelle:exclude .build
# gazelle:proto file
# gazelle:proto_strip_import_prefix /protos
# gazelle:proto_import_prefix example
# gazelle:swift_module_naming_convention pascal_case
# gazelle:swift_generate_proto_libraries true
# gazelle:swift_generate_grpc_libraries_with_flavors client,client_stubs,server
# gazelle:swift_generate_grpc_libraries_with_flavors swift_client_proto,swift_server_proto
# gazelle:exclude .build

gazelle_binary(
name = "gazelle_bin",
Expand Down
10 changes: 4 additions & 6 deletions examples/grpc_example/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
Example module for grpc + proto target generation.
"""

bazel_dep(
name = "rules_swift_package_manager",
version = "0.0.0",
Expand Down Expand Up @@ -25,12 +29,6 @@ use_repo(
"build_bazel_rules_swift_index_import",
"build_bazel_rules_swift_local_config",
"com_github_apple_swift_log",
"com_github_apple_swift_nio",
"com_github_apple_swift_nio_extras",
"com_github_apple_swift_nio_http2",
"com_github_apple_swift_nio_transport_services",
"com_github_apple_swift_protobuf",
"com_github_grpc_grpc_swift",
)

bazel_dep(
Expand Down
Empty file.
44 changes: 44 additions & 0 deletions examples/grpc_example/protos/echo_service/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")

proto_library(
name = "echo_service_proto",
srcs = ["echo_service.proto"],
import_prefix = "example",
strip_import_prefix = "/protos",
visibility = ["//visibility:public"],
deps = [
"//protos/echo_service/requests:echo_request_proto",
"//protos/echo_service/responses:echo_response_proto",
],
)

swift_proto_library(
name = "echo_service_swift_client_proto",
compilers = [
"@build_bazel_rules_swift//proto/compilers:swift_proto",
"@build_bazel_rules_swift//proto/compilers:swift_client_proto",
],
module_name = "EchoServiceClient",
protos = [":echo_service_proto"],
visibility = ["//visibility:public"],
deps = [
"//protos/echo_service/requests:echo_request_swift_proto",
"//protos/echo_service/responses:echo_response_swift_proto",
],
)

swift_proto_library(
name = "echo_service_swift_server_proto",
compilers = [
"@build_bazel_rules_swift//proto/compilers:swift_proto",
"@build_bazel_rules_swift//proto/compilers:swift_server_proto",
],
module_name = "EchoServiceServer",
protos = [":echo_service_proto"],
visibility = ["//visibility:public"],
deps = [
"//protos/echo_service/requests:echo_request_swift_proto",
"//protos/echo_service/responses:echo_response_swift_proto",
],
)
10 changes: 10 additions & 0 deletions examples/grpc_example/protos/echo_service/echo_service.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";

package echo_service;

import "example/echo_service/requests/echo_request.proto";
import "example/echo_service/responses/echo_response.proto";

service Echo {
rpc Echo(EchoRequest) returns (EchoResponse);
}
19 changes: 19 additions & 0 deletions examples/grpc_example/protos/echo_service/requests/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")

proto_library(
name = "echo_request_proto",
srcs = ["echo_request.proto"],
import_prefix = "example",
strip_import_prefix = "/protos",
visibility = ["//visibility:public"],
deps = ["@com_google_protobuf//:any_proto"],
)

swift_proto_library(
name = "echo_request_swift_proto",
compilers = ["@build_bazel_rules_swift//proto/compilers:swift_proto"],
module_name = "EchoRequest",
protos = [":echo_request_proto"],
visibility = ["//visibility:public"],
)
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
syntax = "proto3";

package messages;
package echo_service;

import "google/protobuf/any.proto";

message EchoRequest {
string contents = 1;
google.protobuf.Any extra = 2;
}

message EchoResponse {
string contents = 1;
}
18 changes: 18 additions & 0 deletions examples/grpc_example/protos/echo_service/responses/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load("@build_bazel_rules_swift//proto:proto.bzl", "swift_proto_library")
load("@rules_proto//proto:defs.bzl", "proto_library")

proto_library(
name = "echo_response_proto",
srcs = ["echo_response.proto"],
import_prefix = "example",
strip_import_prefix = "/protos",
visibility = ["//visibility:public"],
)

swift_proto_library(
name = "echo_response_swift_proto",
compilers = ["@build_bazel_rules_swift//proto/compilers:swift_proto"],
module_name = "EchoResponse",
protos = [":echo_response_proto"],
visibility = ["//visibility:public"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
syntax = "proto3";

package echo_service;

message EchoResponse {
string contents = 1;
}
39 changes: 0 additions & 39 deletions examples/grpc_example/protos/echoservice/BUILD.bazel

This file was deleted.

9 changes: 0 additions & 9 deletions examples/grpc_example/protos/echoservice/echoservice.proto

This file was deleted.

15 changes: 0 additions & 15 deletions examples/grpc_example/protos/echoservice/messages/BUILD.bazel

This file was deleted.

6 changes: 3 additions & 3 deletions examples/grpc_example/sources/client/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ swift_binary(
module_name = "Client",
visibility = ["//visibility:public"],
deps = [
"//protos/echoservice:echoservice_client_swift_grpc",
"//protos/echoservice:echoservice_swift_proto",
"//protos/echoservice/messages:messages_swift_proto",
"//protos/echo_service:echo_service_swift_client_proto",
"//protos/echo_service/requests:echo_request_swift_proto",
"//protos/echo_service/responses:echo_response_swift_proto",
],
)
10 changes: 5 additions & 5 deletions examples/grpc_example/sources/client/client_main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import SwiftProtobuf
import GRPC
import NIOCore
import NIOPosix
import protos_echoservice_messages_messages_proto
import protos_echoservice_echoservice_proto
import protos_echoservice_echoservice_client_swift_grpc
import EchoRequest
import EchoResponse
import EchoServiceClient

@main
struct ClientMain {
Expand All @@ -42,10 +42,10 @@ struct ClientMain {
)

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

// Construct a request to the echo service.
let request = Messages_EchoRequest.with {
let request = EchoService_EchoRequest.with {
$0.contents = "Hello, world!"
let timestamp = Google_Protobuf_Timestamp(date: Date())
$0.extra = try! Google_Protobuf_Any(message: timestamp)
Expand Down
6 changes: 3 additions & 3 deletions examples/grpc_example/sources/server/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ swift_binary(
module_name = "Server",
visibility = ["//visibility:public"],
deps = [
"//protos/echoservice:echoservice_server_swift_grpc",
"//protos/echoservice:echoservice_swift_proto",
"//protos/echoservice/messages:messages_swift_proto",
"//protos/echo_service:echo_service_swift_server_proto",
"//protos/echo_service/requests:echo_request_swift_proto",
"//protos/echo_service/responses:echo_response_swift_proto",
],
)
Loading

0 comments on commit 75b5a7e

Please sign in to comment.