-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: documentation about rrgcli, gradle plugin and plugins api
- Loading branch information
Showing
4 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
# CLI | ||
The `rrgcli` tool allows you to generate code from `.proto` files for use with the rRPC framework. It supports creating | ||
Kotlin-based (and other, in future) client stubs, server stubs, data types, and metadata. | ||
|
||
<note> | ||
If you're using Gradle, it's a much more convenient to use <a href="CodeGen-Gradle.md"/> for generating the code. | ||
</note> | ||
|
||
## Installation | ||
|
||
Download the latest release of `rrgcli` from the [rRPC GitHub Releases](https://github.com/timemates/rrpc-kotlin/releases). | ||
Once downloaded, ensure the binary is executable and optionally add it to your system's PATH: | ||
|
||
```Bash | ||
chmod +x rrgcli | ||
mv rrgcli /usr/local/bin | ||
``` | ||
## Usage | ||
The tool processes .proto files and outputs generated code based on the options you provide. | ||
Use the --help option to see available parameters: | ||
``` | ||
Usage: rrgcli [<options>] | ||
Options: | ||
--protos_input=<text> Folder with `.proto` files to be used for generation | ||
(repeatable). | ||
--permit_package_cycles=true|false | ||
Indicates whether package cycles should be ignored | ||
while parsing `.proto` files. | ||
--kotlin_output=<text> Specifies the output path for generated Kotlin files. | ||
--kotlin_client_generation=true|false | ||
Indicates whether client stubs should be generated | ||
for Kotlin. Default is `false`. | ||
--kotlin_server_generation=true|false | ||
Indicates whether server stubs should be generated | ||
for Kotlin. Default is `false`. | ||
--kotlin_type_generation=true|false | ||
Indicates whether data types should be generated for | ||
Kotlin. Default is `false`. | ||
--kotlin_metadata_generation=true|false | ||
Specifies whether metadata should be generated. | ||
--kotlin_metadata_scope_name=<text> | ||
Specifies the scope name for metadata generation. If | ||
not specified, a global instance of Metadata Container | ||
is used. | ||
-h, --help Show this message and exit. | ||
``` | ||
> **Additionally about metadata generation** | ||
> | ||
> Enabling the `--kotlin_metadata_generation` flag generates debugging information about the whole schema, meaning that, | ||
> factually, it provides the same information as any generator have on generation time, but on app's runtime. | ||
> This can be helpful for servers that need details about options attached to specific levels (e.g., file-level options for a service declaration). Metadata may also provide insight into the | ||
> organization and layout of services for tooling. | ||
> | ||
> | ||
> The `--kotlin_metadata_scope_name` flag is used to make metadata scoped to a specific instance rather than placing it | ||
> in the global object. This allows you to: | ||
> - Filter out unnecessary schema information from your SchemaService. | ||
> - Avoid polluting the global scope with unrelated or redundant metadata. | ||
> - Tailor metadata for specific use cases or service groups. | ||
> | ||
> By scoping metadata, you can maintain cleaner separation of concerns, particularly in larger projects with diverse requirements. | ||
|
||
## Examples | ||
### Generate Client Stubs and Types | ||
This example generates Kotlin client stubs and data types from .proto files located in the protos directory: | ||
```Bash | ||
rrgcli \ | ||
--protos_input=protos \ | ||
--kotlin_output=build/generated \ | ||
--kotlin_client_generation=true \ | ||
--kotlin_type_generation=true | ||
``` | ||
|
||
### Handle Package Cycles and Metadata | ||
This example resolves package cycles in .proto files and generates metadata with a custom scope name: | ||
```Bash | ||
rrgcli \ | ||
--protos_input=protos \ | ||
--kotlin_output=build/generated \ | ||
--permit_package_cycles=true \ | ||
--kotlin_metadata_generation=true \ | ||
--kotlin_metadata_scope_name=my_custom_scope | ||
``` | ||
|
||
### Multiple `.proto` Input Directories | ||
To include .proto files from multiple locations: | ||
```Bash | ||
rrgcli \ | ||
--protos_input=protos1 \ | ||
--protos_input=protos2 \ | ||
--kotlin_output=build/generated \ | ||
--kotlin_server_generation=true | ||
``` | ||
_______ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Gradle Plugin | ||
The rRPC Gradle Plugin helps automate code generation for rRPC services in Gradle-based projects using `.proto` files. | ||
|
||
<note> | ||
If your project is not Gradle-based, you can use the <a href="CodeGen-CLI.md">rrgcli</a> for generating code. | ||
</note> | ||
|
||
## Applying the Plugin | ||
Add the plugin to your `build.gradle.kts`: | ||
```kotlin | ||
plugins { | ||
id("org.timemates.rrpc") version "$latestVersion" | ||
} | ||
``` | ||
|
||
<note> | ||
Make sure that you have Gradle Plugin Portal specified in your repositories. | ||
</note> | ||
|
||
## Configuring the Plugin | ||
The plugin is configured using the rrpc extension, allowing customization for .proto file locations, output configurations, and generation behavior. | ||
|
||
### Basic Example | ||
```Kotlin | ||
rrpc { | ||
targetSourceSet.set("commonMain") // Specify the source set for generated code | ||
protosInput.set(listOf("src/main/proto")) // Define where to find .proto files | ||
|
||
kotlin { | ||
output = "build/generated/kotlin" // Specify output directory | ||
clientGeneration = true // Generate client stubs | ||
serverGeneration = true // Generate server stubs | ||
typeGeneration = true // Generate data types | ||
metadataEnabled = true // Enable metadata generation | ||
metadataScopeName = "MyScope" // Define metadata scope | ||
} | ||
} | ||
``` | ||
|
||
### Configuration Properties | ||
|
||
#### `targetSourceSet` | ||
- **Purpose:** Specifies the source set for code generation. | ||
- **Why it's important:** Code generation tasks depend on this source set to correctly manage input and output directories for the build process. For instance, setting `commonMain` ensures that the generated files are included in the correct build phase. Especially useful for the custom source-set layouts. | ||
- **Default:** `null` (falls back to default source sets like `commonMain` or `main`). | ||
|
||
```Kotlin | ||
targetSourceSet.set("commonMain") | ||
``` | ||
#### `protosInput` | ||
- **Purpose**: Specifies the list of directories containing .proto files for generation. | ||
- **Default**: An empty list. | ||
|
||
#### Kotlin Configuration Options | ||
|
||
These options are defined under the `kotlin` block: | ||
|
||
- **`output`**: Specifies the directory where Kotlin code will be generated. | ||
- **Example**: | ||
`output = "build/generated/kotlin"` | ||
- **`clientGeneration`**: Enables or disables generation of client stubs. | ||
- **Default**: `false`. | ||
- **Example**: | ||
`clientGeneration = true` | ||
- **`serverGeneration`**: Enables or disables generation of server stubs. | ||
- **Default**: `false`. | ||
- **Example**: | ||
`serverGeneration = true` | ||
- **`typeGeneration`**: Enables or disables generation of data types from `.proto` definitions. | ||
- **Default**: `false`. | ||
- **Example**: | ||
`typeGeneration = true` | ||
- **`metadataEnabled`**: Enables generation of metadata. This can help in debugging (for rRPC Inspector) or providing additional context to the server about file-level or declaration-level options. | ||
- **Default**: `false`. | ||
- **Example**: | ||
`metadataEnabled = true` | ||
- **`metadataScopeName`**: Specifies a scope for metadata, allowing you to filter or separate metadata from the global scope. Useful if you don’t want all metadata combined in a single container. | ||
- **Default**: Empty string (uses global scope). | ||
- **Example**: | ||
`metadataScopeName = "PotatoSchema"` | ||
|
||
## Additional Notes | ||
- For projects with unusual directory structures or source sets, make sure to adjust targetSourceSet and protosInput accordingly. | ||
- Generated files should not be modified manually. They are regenerated during each build. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Developing your own plugins | ||
Plugins are a powerful way to extend the functionality of a generator, enabling dynamic behavior, custom workflows or | ||
generating code for different languages. By developing your own plugin, you can tailor the generator to suit specific | ||
needs, such as processing custom inputs, providing options, or integrating with external systems. | ||
|
||
This guide will walk you through the steps of creating your own plugin, covering everything from adding dependencies to | ||
handling specific signals and sending back appropriate responses. Whether you are building a plugin to modify the behavior of an existing generator or to introduce new options, this tutorial will help you get started with the Plugin API. | ||
|
||
## Step 1: Add Dependencies | ||
|
||
Before starting development, you need to add the necessary dependencies for the plugin to interact with the host system and exchange data. Ensure that your project includes the required libraries for communication via the Plugin API. | ||
|
||
In your `build.gradle.kts` file (for Gradle projects), include the following dependencies: | ||
```Kotlin | ||
dependencies { | ||
implementation("org.timemates.rrpc:generator-core:$latestVersion") | ||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0") | ||
} | ||
``` | ||
Ensure you use the correct version numbers according to your setup. | ||
|
||
## Step 2: Define the Adapter | ||
|
||
The adapter is used to map the available options and process the input received from the generator. Its purpose | ||
is to generate code, based on the input received: | ||
```Kotlin | ||
public interface SchemaAdapter { | ||
/** | ||
* List of available options for schema adapter with description. For CLI and Gradle plugin. | ||
*/ | ||
public val options: List<GenerationOption> | ||
|
||
/** | ||
* This method is used for generating the code usually, but can be used for other | ||
* purposes, for an example, – logging. | ||
* | ||
* @return RMResolver that might be the same as [resolver] or new in cases | ||
* when you want to modify incoming data to the following adapters. | ||
*/ | ||
public fun process( | ||
options: GenerationOptions, | ||
resolver: RSResolver, | ||
): RSResolver | ||
} | ||
``` | ||
For the reference, you might want to see the implementation of [Kotlin Code Generator](https://github.com/timemates/rrpc-kotlin/blob/0.7.0/generator/kotlin/src/commonMain/kotlin/org/timemates/rrpc/generator/kotlin/adapter/KotlinSchemaAdapter.kt). | ||
|
||
<warning> | ||
This section is yet to be finalized. | ||
</warning> | ||
|
||
Once you implemented the `SchemaAdapter` for your needs, we can continue to the setup of communication between Generator | ||
and the Plugin: | ||
|
||
## Step 3: Setup Plugin Communication | ||
The next step is setting up the communication between your plugin and the generator. | ||
The plugin will send and receive signals, which are the core units of communication. | ||
|
||
To begin, create an instance of the PluginCommunication class to handle the input and output streams: | ||
```Kotlin | ||
val client = PluginCommunication( | ||
System.`in`.source().buffer(), // Input stream from the generator | ||
System.out.sink().buffer() // Output stream to the generator | ||
) | ||
``` | ||
|
||
> [```rrcli```](CodeGen-CLI.md) as well as a Gradle Plugin, communicate with plugins through stdin/stdout. In the | ||
> example we will use java.lang.System to obtain it, but it's not locked up – we use okio for ability to target non-JVM | ||
> targets. | ||
## Step 4: Handling Incoming Signals | ||
When your plugin receives a signal, it processes the signal based on its type. A plugin will always receive a G | ||
eneratorSignal.FetchOptionsList at the very beginning, which requests the available options. | ||
In response, you can send a list of options back to the generator. | ||
|
||
The generator might also send a GeneratorSignal.SendInput, but it is up to the generator to decide whether this signal | ||
is needed, for example, when requesting input for certain options, such as --help. | ||
|
||
Here’s an example of how to handle these signals: | ||
```Kotlin | ||
client.receive { signal -> | ||
when (signal) { | ||
GeneratorSignal.FetchOptionsList -> listOf( | ||
PluginSignal.SendOptions( | ||
schemaAdapter.options.map { it.toOptionDescriptor() } | ||
), | ||
PluginSignal.RequestInput, | ||
) | ||
is GeneratorSignal.SendInput -> { | ||
schemaAdapter.process( | ||
options = GenerationOptions(signal.args), | ||
resolver = RSResolver(signal.files), | ||
) | ||
emptyList() // No further response needed | ||
} | ||
} | ||
} | ||
``` | ||
In this example: | ||
- GeneratorSignal.FetchOptionsList is always received and is responded to by sending a list of available options and potentially a RequestInput signal. | ||
- GeneratorSignal.SendInput may or may not be received, depending on the generator’s requirements. | ||
|
||
## Step 5: Testing the Plugin | ||
|
||
Before deploying your plugin, it’s essential to test it to ensure that it reacts correctly to signals and sends the appropriate responses. You can use unit tests or a local testing environment to simulate the interactions between your plugin and the generator. | ||
|
||
<warning> | ||
This section is yet to be finalized. | ||
</warning> | ||
|
||
## Conclusion | ||
|
||
By following these steps, you can develop a plugin that communicates with the generator using the Plugin API. The key steps include adding dependencies, setting up communication, handling signals (particularly FetchOptionsList), and sending appropriate responses. This allows your plugin to seamlessly integrate with the generator’s functionality. | ||
|
||
For more details and further examples, refer to the Plugin API documentation. |