Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Server] Implement Gradle subprojects and scaffolding for the Python server. #1366

Merged
merged 11 commits into from
May 18, 2022
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ jobs:
- action: check-sdk-codegen-unit-tests
- action: check-server-codegen-integration-tests
- action: check-server-codegen-unit-tests
- action: check-server-codegen-integration-tests-python
- action: check-server-codegen-unit-tests-python
- action: check-server-e2e-test
- action: check-style-and-lints
steps:
Expand Down
9 changes: 9 additions & 0 deletions ci.mk
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ check-server-codegen-integration-tests:
check-server-codegen-unit-tests:
$(CI_ACTION) $@

.PHONY: check-server-codegen-integration-tests-python
check-server-codegen-integration-tests-python:
$(CI_ACTION) $@

.PHONY: check-server-codegen-unit-tests-python
check-server-codegen-unit-tests-python:
$(CI_ACTION) $@


.PHONY: check-server-e2e-test
check-server-e2e-test:
$(CI_ACTION) $@
Expand Down
102 changes: 102 additions & 0 deletions codegen-server-test/python/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

extra["displayName"] = "Smithy :: Rust :: Codegen :: Server :: Python :: Test"
extra["moduleName"] = "software.amazon.smithy.rust.kotlin.codegen.server.python.test"

tasks["jar"].enabled = false

plugins { id("software.amazon.smithy") }

val smithyVersion: String by project
val defaultRustFlags: String by project
val defaultRustDocFlags: String by project
val properties = PropertyRetriever(rootProject, project)

val pluginName = "rust-server-codegen"
val workingDirUnderBuildDir = "smithyprojections/python/"
crisidev marked this conversation as resolved.
Show resolved Hide resolved

buildscript {
val smithyVersion: String by project
dependencies {
classpath("software.amazon.smithy:smithy-cli:$smithyVersion")
}
}

dependencies {
implementation(project(":codegen-server:python"))
implementation("software.amazon.smithy:smithy-aws-protocol-tests:$smithyVersion")
implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
}

val allCodegenTests = listOf(
CodegenTest("com.amazonaws.simple#SimpleService", "simple"),
CodegenTest("aws.protocoltests.restjson#RestJson", "rest_json"),
CodegenTest("aws.protocoltests.restjson.validation#RestJsonValidation", "rest_json_validation"),
CodegenTest("aws.protocoltests.json10#JsonRpc10", "json_rpc10"),
CodegenTest("aws.protocoltests.json#JsonProtocol", "json_rpc11"),
CodegenTest("aws.protocoltests.misc#MiscService", "misc"),
CodegenTest("com.amazonaws.ebs#Ebs", "ebs"),
CodegenTest("com.amazonaws.s3#AmazonS3", "s3"),
CodegenTest("com.aws.example#PokemonService", "pokemon_service_sdk")
)

task("generateSmithyBuild") {
description = "generate smithy-build.json"
doFirst {
projectDir.resolve("smithy-build.json")
.writeText(
generateSmithyBuild(
rootProject.projectDir.absolutePath,
pluginName,
codegenTests(properties, allCodegenTests)
)
)
}
}

task("generateCargoWorkspace") {
description = "generate Cargo.toml workspace file"
doFirst {
buildDir.resolve("$workingDirUnderBuildDir/Cargo.toml")
.writeText(generateCargoWorkspace(pluginName, codegenTests(properties, allCodegenTests)))
}
}

tasks["smithyBuildJar"].dependsOn("generateSmithyBuild")
tasks["assemble"].finalizedBy("generateCargoWorkspace")

tasks.register<Exec>(Cargo.CHECK.toString) {
workingDir("$buildDir/$workingDirUnderBuildDir")
environment("RUSTFLAGS", defaultRustFlags)
commandLine("cargo", "check")
dependsOn("assemble")
}

tasks.register<Exec>(Cargo.TEST.toString) {
workingDir("$buildDir/$workingDirUnderBuildDir")
environment("RUSTFLAGS", defaultRustFlags)
commandLine("cargo", "test")
dependsOn("assemble")
}

tasks.register<Exec>(Cargo.DOCS.toString) {
workingDir("$buildDir/$workingDirUnderBuildDir")
environment("RUSTDOCFLAGS", defaultRustDocFlags)
commandLine("cargo", "doc", "--no-deps")
dependsOn("assemble")
}

tasks.register<Exec>(Cargo.CLIPPY.toString) {
workingDir("$buildDir/$workingDirUnderBuildDir")
environment("RUSTFLAGS", defaultRustFlags)
commandLine("cargo", "clippy")
dependsOn("assemble")
}
Comment on lines +77 to +103
Copy link
Collaborator

Choose a reason for hiding this comment

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

there's actually a way to share these between projects—I think the smithy project does it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was wondering about this.. I'll figure out how to do it. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried many things, but we really need the working dir which is defined in the build.gradle.kt, so I don't see how this can be shared between projects. Any pointers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If this is not a blocker for this PR, I have created #1378 to track this issue and solve it once I figure out how :)


tasks["test"].finalizedBy(cargoCommands(properties).map { it.toString })

tasks["clean"].doFirst { delete("smithy-build.json") }
1 change: 1 addition & 0 deletions codegen-server-test/python/model
109 changes: 109 additions & 0 deletions codegen-server/python/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

import org.gradle.api.tasks.testing.logging.TestExceptionFormat

plugins {
kotlin("jvm")
id("org.jetbrains.dokka")
jacoco
maven
`maven-publish`
}

description = "Generates Rust/Python server-side code from Smithy models"

extra["displayName"] = "Smithy :: Rust :: Codegen :: Server :: Python"

extra["moduleName"] = "software.amazon.smithy.rust.codegen.server.python"

group = "software.amazon.smithy.rust.codegen.server.python.smithy"

version = "0.1.0"

val smithyVersion: String by project
val kotestVersion: String by project

dependencies {
implementation(kotlin("stdlib-jdk8"))
api("software.amazon.smithy:smithy-codegen-core:$smithyVersion")
api("com.moandjiezana.toml:toml4j:0.7.2")
implementation(project(":codegen"))
implementation(project(":codegen-server"))
implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
implementation("software.amazon.smithy:smithy-waiters:$smithyVersion")
runtimeOnly(project(":rust-runtime"))
testImplementation("org.junit.jupiter:junit-jupiter:5.6.1")
testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion")
crisidev marked this conversation as resolved.
Show resolved Hide resolved
}

// unlike the client-runtime, software.amazon.smithy.rust.codegen.smithy-kotlin codegen package is
// not expected to run on Android...we can target 1.8
crisidev marked this conversation as resolved.
Show resolved Hide resolved
tasks.compileKotlin { kotlinOptions.jvmTarget = "1.8" }

tasks.compileTestKotlin { kotlinOptions.jvmTarget = "1.8" }

// Reusable license copySpec
val licenseSpec = copySpec {
from("${project.rootDir}/LICENSE")
from("${project.rootDir}/NOTICE")
}

// Configure jars to include license related info
tasks.jar {
metaInf.with(licenseSpec)
inputs.property("moduleName", project.name)
manifest { attributes["Automatic-Module-Name"] = project.name }
}

val sourcesJar by tasks.creating(Jar::class) {
group = "publishing"
description = "Assembles Kotlin sources jar"
classifier = "sources"
from(sourceSets.getByName("main").allSource)
}

tasks.test {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
exceptionFormat = TestExceptionFormat.FULL
showCauses = true
showExceptions = true
showStackTraces = true
showStandardStreams = true
}
}

tasks.dokka {
outputFormat = "html"
outputDirectory = "$buildDir/javadoc"
}

// Always build documentation
tasks["build"].finalizedBy(tasks["dokka"])
crisidev marked this conversation as resolved.
Show resolved Hide resolved

// Configure jacoco (code coverage) to generate an HTML report
tasks.jacocoTestReport {
reports {
xml.isEnabled = false
csv.isEnabled = false
html.destination = file("$buildDir/reports/jacoco")
}
}

// Always run the jacoco test report after testing.
tasks["test"].finalizedBy(tasks["jacocoTestReport"])
crisidev marked this conversation as resolved.
Show resolved Hide resolved

publishing {
publications {
create<MavenPublication>("default") {
from(components["java"])
artifact(sourcesJar)
}
}
repositories { maven { url = uri("$buildDir/repository") } }
}
crisidev marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package software.amazon.smithy.rust.codegen.server.python.smithy

import software.amazon.smithy.build.PluginContext
import software.amazon.smithy.build.SmithyBuildPlugin
import software.amazon.smithy.codegen.core.ReservedWordSymbolProvider
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.rust.codegen.rustlang.RustReservedWordSymbolProvider
import software.amazon.smithy.rust.codegen.server.smithy.ServerCodegenVisitor
import software.amazon.smithy.rust.codegen.smithy.BaseSymbolMetadataProvider
import software.amazon.smithy.rust.codegen.smithy.DefaultConfig
import software.amazon.smithy.rust.codegen.smithy.EventStreamSymbolProvider
import software.amazon.smithy.rust.codegen.smithy.StreamingShapeMetadataProvider
import software.amazon.smithy.rust.codegen.smithy.StreamingShapeSymbolProvider
import software.amazon.smithy.rust.codegen.smithy.SymbolVisitor
import software.amazon.smithy.rust.codegen.smithy.SymbolVisitorConfig
import software.amazon.smithy.rust.codegen.smithy.customize.CombinedCodegenDecorator
import java.util.logging.Level
import java.util.logging.Logger

/** Rust Codegen Plugin
* This is the entrypoint for code generation, triggered by the smithy-build plugin.
* `resources/META-INF.services/software.amazon.smithy.build.SmithyBuildPlugin` refers to this class by name which
* enables the smithy-build plugin to invoke `execute` with all of the Smithy plugin context + models.
*/
class RustCodegenServerPlugin : SmithyBuildPlugin {
private val logger = Logger.getLogger(javaClass.name)

override fun getName(): String = "rust-server-codegen"
crisidev marked this conversation as resolved.
Show resolved Hide resolved

override fun execute(context: PluginContext) {
// Suppress extremely noisy logs about reserved words
Logger.getLogger(ReservedWordSymbolProvider::class.java.name).level = Level.OFF
// Discover [RustCodegenDecorators] on the classpath. [RustCodegenDectorator] return different types of
// customization. A customization is a function of:
// - location (e.g. the mutate section of an operation)
// - context (e.g. the of the operation)
// - writer: The active RustWriter at the given location
val codegenDecorator = CombinedCodegenDecorator.fromClasspath(context)

// ServerCodegenVisitor is the main driver of code generation that traverses the model and generates code
logger.info("Loaded plugin to generate Rust/Python bindings for the server SSDK")
ServerCodegenVisitor(context, codegenDecorator).execute()
}

companion object {
/** SymbolProvider
* When generating code, smithy types need to be converted into Rust types—that is the core role of the symbol provider
*
* The Symbol provider is composed of a base [SymbolVisitor] which handles the core functionality, then is layered
* with other symbol providers, documented inline, to handle the full scope of Smithy types.
*/
fun baseSymbolProvider(
model: Model,
serviceShape: ServiceShape,
symbolVisitorConfig: SymbolVisitorConfig = DefaultConfig
) =
SymbolVisitor(model, serviceShape = serviceShape, config = symbolVisitorConfig)
// Generate different types for EventStream shapes (e.g. transcribe streaming)
.let {
EventStreamSymbolProvider(symbolVisitorConfig.runtimeConfig, it, model)
}
// Generate [ByteStream] instead of `Blob` for streaming binary shapes (e.g. S3 GetObject)
.let { StreamingShapeSymbolProvider(it, model) }
// Add Rust attributes (like `#[derive(PartialEq)]`) to generated shapes
.let { BaseSymbolMetadataProvider(it, additionalAttributes = listOf()) }
// Streaming shapes need different derives (e.g. they cannot derive Eq)
.let { StreamingShapeMetadataProvider(it, model) }
// Rename shapes that clash with Rust reserved words & and other SDK specific features e.g. `send()` cannot
// be the name of an operation input
.let { RustReservedWordSymbolProvider(it, model) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.
#
software.amazon.smithy.rust.codegen.server.python.smithy.RustCodegenServerPlugin
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class RustCodegenServerPlugin : SmithyBuildPlugin {
val codegenDecorator = CombinedCodegenDecorator.fromClasspath(context)

// ServerCodegenVisitor is the main driver of code generation that traverses the model and generates code
logger.info("Loaded plugin to generate pure Rust bindings for the server SSDK")
ServerCodegenVisitor(context, codegenDecorator).execute()
}

Expand Down
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ enableFeaturePreview("GRADLE_METADATA")
include(":codegen")
include(":codegen-test")
include(":codegen-server")
include(":codegen-server:python")
include(":codegen-server-test")
include(":codegen-server-test:python")
include(":rust-runtime")
include(":aws:sdk-codegen")
include(":aws:sdk-codegen-test")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.
#

set -eux
cd smithy-rs
./gradlew codegen-server-test:python:test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
#
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.
#

set -eux
cd smithy-rs
./gradlew codegen-server:python:test
Loading