Browse Source

Update tutorials to use the build plugin (#2178)

Motivation:

The examples have been updated to use the build plugin; so too should
the tutorials.

Modifications:

Update tutorials to use the build plugin.

Result:

Better tutorials.
George Barnett 1 year ago
parent
commit
4c6357d83d

+ 28 - 16
Sources/GRPCCore/Documentation.docc/Tutorials/Hello-World/Hello-World.tutorial

@@ -28,17 +28,28 @@
   @Section(title: "Run a gRPC application") {
     Let's start by running the existing Greeter application.
 
+    As a prerequisite you must have the Protocol Buffers compiler (`protoc`) installed. You can
+    find the instructions for doing this in the [gRPC Swift Protobuf
+    documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/installing-protoc).
+    The remainder of this tutorial assumes you installed `protoc` and it's available in
+    your `$PATH`.
+
+    You may notice that the `swift` commands are all prefixed with `PROTOC_PATH=$(which protoc)`,
+    this is to let the build system know where `protoc` is located so that it can generate stubs
+    for you. You can read more about it in the  [gRPC Swift Protobuf
+    documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/generating-stubs).
+
     @Steps {
       @Step {
-        In a terminal run `swift run hello-world serve` to start the server. By default it'll start
-        listening on port 31415.
+        In a terminal run `PROTOC_PATH=$(which protoc) swift run hello-world serve` to start the
+        server. By default it'll start listening on port 31415.
 
         @Code(name: "Console.txt", file: "hello-world-sec02-step01.txt")
       }
 
       @Step {
-        In another terminal run `swift run hello-world greet` to create a client, connect
-        to the server you started and send it a request and print the response.
+        In another terminal run `PROTOC_PATH=$(which protoc) swift run hello-world greet` to create
+        a client, connect to the server you started and send it a request and print the response.
 
         @Code(name: "Console.txt", file: "hello-world-sec02-step02.txt")
       }
@@ -75,19 +86,19 @@
   }
 
   @Section(title: "Update and run the application") {
-    You need to regenerate the stubs as the service definition has changed. To do this run the
-    following command from the _root of the checked out repository_:
-
-    ```console
-    dev/protos/generate.sh
-    ```
+    You need to regenerate the stubs as the service definition has changed. As you're using
+    the Swift Package Manager Build Plugin for gRPC Swift the gRPC code is automatically
+    generated if necessary when you build the example. You can learn more about generating stubs in
+    the <doc:Generating-stubs> article.
 
-    To learn how to generate stubs check out the <doc:Generating-stubs> article.
-
-    Now that the stubs have been updated you need to implement and call the new method in the
-    human-written parts of your application.
 
     @Steps {
+      @Step {
+        Run `PROTOC_PATH=$(which protoc) swift build` to build the example. This will fail
+        because the service no longer implements all of the methods declared in the `.proto` file.
+        Let's fix that!
+      }
+
       @Step {
         Open `Serve.swift` in the `Subcommands` directory.
 
@@ -114,13 +125,14 @@
 
       @Step {
         Just like we did before, open a terminal and start the server by
-        running `swift run hello-world serve`
+        running `PROTOC_PATH=$(which protoc) swift run hello-world serve`
 
         @Code(name: "Console.txt", file: "hello-world-sec04-step05.txt")
       }
 
       @Step {
-        In a separate terminal run `swift run hello-world greet` to call the server.
+        In a separate terminal run `PROTOC_PATH=$(which protoc) swift run hello-world greet` to
+        call the server.
 
         @Code(name: "Console.txt", file: "hello-world-sec04-step06.txt")
       }

+ 25 - 0
Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec01-step09-plugin.swift

@@ -0,0 +1,25 @@
+// swift-tools-version: 6.0
+import PackageDescription
+
+let package = Package(
+  name: "RouteGuide",
+  platforms: [.macOS(.v15)],
+  dependencies: [
+    .package(url: "https://github.com/grpc/grpc-swift.git", from: "2.0.0-beta.3"),
+    .package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "1.0.0-beta.3"),
+    .package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "1.0.0-beta.3"),
+  ],
+  targets: [
+    .executableTarget(
+      name: "RouteGuide",
+      dependencies: [
+        .product(name: "GRPCCore", package: "grpc-swift"),
+        .product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
+        .product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
+      ],
+      plugins: [
+        .plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
+      ]
+    )
+  ]
+)

+ 7 - 0
Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec01-step10-plugin-config.json

@@ -0,0 +1,7 @@
+{
+  "generate": {
+    "clients": true,
+    "servers": true,
+    "messages": true
+  }
+}

+ 4 - 0
Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec05-step00-package.swift

@@ -7,6 +7,7 @@ let package = Package(
   dependencies: [
     .package(url: "https://github.com/grpc/grpc-swift.git", from: "2.0.0-beta.3"),
     .package(url: "https://github.com/grpc/grpc-swift-protobuf.git", from: "1.0.0-beta.3"),
+    .package(url: "https://github.com/grpc/grpc-swift-nio-transport.git", from: "1.0.0-beta.3"),
   ],
   targets: [
     .executableTarget(
@@ -15,6 +16,9 @@ let package = Package(
         .product(name: "GRPCCore", package: "grpc-swift"),
         .product(name: "GRPCNIOTransportHTTP2", package: "grpc-swift-nio-transport"),
         .product(name: "GRPCProtobuf", package: "grpc-swift-protobuf"),
+      ],
+      plugins: [
+        .plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
       ]
     )
   ]

+ 3 - 0
Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec05-step01-package.swift

@@ -19,6 +19,9 @@ let package = Package(
       ],
       resources: [
         .copy("route_guide_db.json")
+      ],
+      plugins: [
+        .plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
       ]
     )
   ]

+ 3 - 0
Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Resources/route-guide-sec05-step02-package.swift

@@ -21,6 +21,9 @@ let package = Package(
       ],
       resources: [
         .copy("route_guide_db.json")
+      ],
+      plugins: [
+        .plugin(name: "GRPCProtobufGenerator", package: "grpc-swift-protobuf")
       ]
     )
   ]

+ 54 - 38
Sources/GRPCCore/Documentation.docc/Tutorials/Route-Guide/Route-Guide.tutorial

@@ -20,6 +20,17 @@
     Before we can write any code we need to create a new Swift Package and configure it
     to depend on gRPC Swift.
 
+    As a prerequisite you must have the Protocol Buffers compiler (`protoc`) installed. You can
+    find the instructions for doing this in the [gRPC Swift Protobuf
+    documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/installing-protoc).
+    The remainder of this tutorial assumes you installed `protoc` and it's available in
+    your `$PATH`.
+
+    You may notice that the `swift` commands are all prefixed with `PROTOC_PATH=$(which protoc)`,
+    this is to let the build system know where `protoc` is located so that it can generate stubs
+    for you. You can read more about it in the  [gRPC Swift Protobuf
+    documentation](https://swiftpackageindex.com/grpc/grpc-swift-protobuf/documentation/grpcprotobuf/generating-stubs).
+
     @Steps {
       @Step {
         Create a new directory called for the package called `RouteGuide`.
@@ -84,6 +95,24 @@
 
         @Code(name: "Package.swift", file: "route-guide-sec01-step08-description.swift")
       }
+
+      @Step {
+        We'll also add a build plugin. This allows the build system to generate gRPC code at build
+        time rather than having to generate it with separate tooling.
+
+        @Code(name: "Package.swift", file: "route-guide-sec01-step09-plugin.swift")
+      }
+
+      @Step {
+        A configuration file is required so that the plugin knows what to generate. Create
+        a JSON file in the `Sources/Protos` directory called `grpc-swift-proto-generator-config.json`
+        with this content.
+
+        The name of the file (`grpc-swift-proto-generator-config.json`) is important: the plugin
+        looks for files matching this name in the source directory of your target.
+
+        @Code(name: "Sources/Protos/grpc-swift-proto-generator-config.json", file: "route-guide-sec01-step10-plugin-config.json")
+      }
     }
   }
 
@@ -93,16 +122,26 @@
 
     @Steps {
       @Step {
-        Create a new empty file in the `Protos` directory called `route_guide.proto`. We'll use
-        the "proto3" syntax and our service will be part of the "routeguide" package.
+        Create a new directory in the `Sources/Protos` directory called `routeguide`
+        using `mkdir Sources/Protos/routeguide`.
+      }
+
+      @Step {
+        Create a new empty file in the `Sources/Protos/routeguide` directory
+        called `route_guide.proto`. We'll use the "proto3" syntax and our service will be part of
+        the "routeguide" package.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step01-import.proto")
+        It's good practice to organize your `.proto` files according to the package they are
+        declared in, that's why we created the `routeguide` directory to match the "routeguide"
+        package name.
+
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step01-import.proto")
       }
 
       @Step {
         To define a service we create a named `service` in the `.proto` file.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step02-service.proto")
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step02-service.proto")
       }
 
       @Step {
@@ -113,7 +152,7 @@
         A *unary RPC* where the client sends a request to the server using the stub
         and waits for a response to come back, just like a normal function call.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step03-unary.proto")
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step03-unary.proto")
       }
 
       @Step {
@@ -123,7 +162,7 @@
         example, you specify a server-side streaming method by placing the `stream`
         keyword before the *response* type.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step04-server-streaming.proto")
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step04-server-streaming.proto")
       }
 
       @Step {
@@ -133,7 +172,7 @@
         and return its response. You specify a client-side streaming method by placing
         the `stream` keyword before the *request* type.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step05-client-streaming.proto")
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step05-client-streaming.proto")
       }
 
       @Step {
@@ -146,53 +185,30 @@
         stream is preserved. You specify this type of method by placing the `stream`
         keyword before both the request and the response.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step06-bidi-streaming.proto")
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step06-bidi-streaming.proto")
       }
 
       @Step {
         The `.proto` file also contains the Protocol Buffers message type definitions for all
         request and response messages used by the service.
 
-        @Code(name: "Protos/route_guide.proto", file: "route-guide-sec02-step07-messages.proto")
+        @Code(name: "Sources/Protos/routeguide/route_guide.proto", file: "route-guide-sec02-step07-messages.proto")
       }
     }
   }
 
   @Section(title: "Generating client and server code") {
     Next we need to generate the gRPC client and server interfaces from our `.proto`
-    service definition. We do this using the Protocol Buffer compiler, `protoc`, with
-    two plugins: one with support for Swift (via [Swift Protobuf](https://github.com/apple/swift-protobuf))
-    and the other for gRPC. This section assumes you already have `protoc` installed.
+    service definition. As we're using the build plugin we just need to build our project.
 
     To learn more about generating code check out the <doc:Generating-stubs> article.
 
     @Steps {
       @Step {
-        First we need to build the two plugins for `protoc`, `protoc-gen-swift` and
-        `protoc-gen-grpc-swift`.
-
-        @Code(name: "Console", file: "route-guide-sec03-step01-protoc-plugins.txt")
-      }
-
-      @Step {
-        We'll generate the code into a separate directory within `Sources` called `Generated` which
-        we need to create first.
-
-        @Code(name: "Console", file: "route-guide-sec03-step02-mkdir.txt")
-      }
-
-      @Step {
-        Now run `protoc` to generate the messages. This will create
-        `Sources/Generated/route_guide.pb.swift`.
-
-        @Code(name: "Console", file: "route-guide-sec03-step03-gen-messages.txt")
-      }
-
-      @Step {
-        Run `protoc` again to generate the service code. This will create
-        `Sources/Generated/route_guide.grpc.swift`.
+        Build the project using `PROTOC_PATH=$(which protoc) swift build`.
 
-        @Code(name: "Console", file: "route-guide-sec03-step04-gen-grpc.txt")
+        If you are using Xcode or another IDE then you'll need to set the environment variable
+        appropriately.
       }
     }
   }
@@ -464,13 +480,13 @@
 
     @Steps {
       @Step {
-        In one terminal run `swift run RouteGuide --server` to start the server.
+        In one terminal run `PROTOC_PATH=$(which protoc) swift run RouteGuide --server` to start the server.
 
         @Code(name: "Console", file: "route-guide-sec07-step01-server.txt")
       }
 
       @Step {
-        In another terminal run `swift run RouteGuide` to run the client program.
+        In another terminal run `PROTOC_PATH=$(which protoc) swift run RouteGuide` to run the client program.
 
         @Code(name: "Console", file: "route-guide-sec07-step02-client.txt")
       }