Unverified Commit d952ccd8 authored by david-perez's avatar david-perez Committed by GitHub
Browse files

Fix `codegen-server` and `codegen-server:python` projects when crate name contains hyphens (#1581)

Rust crate names are allowed to contain hyphens, while Rust identifiers
are not [0]. However, the Rust and Python server projects are currently
broken because we use the user-provided crate name verbatim
(`moduleName` in `settings`) in places where Rust expects valid
identifiers:

* The Rust server's generated operation registry Rust docs use the crate
  name verbatim in import statements.
* The Python server uses the crate name verbatim to generate a shared
  library, but library target names in `Cargo.toml` cannot contain
  hyphens.

We never caught this bug because we don't generate any crates with
hyphens in their names.

This commit:

* fixes the above usages of verbatim crate names where identifiers are
  expected by calling `toSnakeCase()`,
* modifies the unit test for the server's operation registry generator
  to generate a crate with hyphens in its name,
* changes the Pokémon service server SDK crate names from
  `pokemon_service_sdk` to `pokemon-service-server-sdk`, so that we
  exercise generation of a crate with hyphens in its name, and to better
  convey that the generated SDK is server-specific; and
* changes the Pokémon service client SDK crate name from
  `pokemon_service_client` to `pokemon-service-client`, and changes the
  Pokémon service crate name itself from `pokemon_service` to
  `pokemon-service`, for symmetry.

[0]: https://doc.rust-lang.org/reference/identifiers.html
parent 0f2fae11
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ val allCodegenTests = listOf(
    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")
    CodegenTest("com.aws.example#PokemonService", "pokemon-service-server-sdk")
)

project.registerGenerateSmithyBuildTask(rootProject, pluginName, allCodegenTests)
+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ dependencies {

val allCodegenTests = listOf(
    CodegenTest("com.amazonaws.simple#SimpleService", "simple"),
    CodegenTest("com.aws.example#PokemonService", "pokemon_service_sdk")
    CodegenTest("com.aws.example#PokemonService", "pokemon-service-server-sdk")
)

project.registerGenerateSmithyBuildTask(rootProject, pluginName, allCodegenTests)
+8 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import software.amazon.smithy.rust.codegen.smithy.customize.RustCodegenDecorator
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsCustomization
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsSection
import software.amazon.smithy.rust.codegen.smithy.generators.ManifestCustomizations
import software.amazon.smithy.rust.codegen.util.toSnakeCase

/**
 * Configure the [lib] section of `Cargo.toml`.
@@ -36,7 +37,13 @@ class CdylibManifestDecorator : RustCodegenDecorator<ServerCodegenContext> {
    override fun crateManifestCustomizations(
        codegenContext: ServerCodegenContext
    ): ManifestCustomizations =
        mapOf("lib" to mapOf("name" to codegenContext.settings.moduleName, "crate-type" to listOf("cdylib")))
        mapOf(
            "lib" to mapOf(
                // Library target names cannot contain hyphen names.
                "name" to codegenContext.settings.moduleName.toSnakeCase(),
                "crate-type" to listOf("cdylib")
            )
        )
}

/**
+9 −8
Original line number Diff line number Diff line
@@ -61,11 +61,12 @@ import software.amazon.smithy.rust.codegen.util.toSnakeCase
 * that abstracts the processes / event loops / workers lifecycles.
 */
class PythonApplicationGenerator(
    coreCodegenContext: CoreCodegenContext,
    private val coreCodegenContext: CoreCodegenContext,
    private val operations: List<OperationShape>,
) {
    private val crateName = coreCodegenContext.settings.moduleName
    private val symbolProvider = coreCodegenContext.symbolProvider
    private val libName = "lib${coreCodegenContext.settings.moduleName.toSnakeCase()}"
    private val runtimeConfig = coreCodegenContext.runtimeConfig
    private val model = coreCodegenContext.model
    private val codegenScope =
@@ -196,20 +197,20 @@ class PythonApplicationGenerator(
/// Main Python application, used to register operations and context and start multiple
/// workers on the same shared socket.
///
/// Operations can be registrered using the application object as a decorator (`@app.operation_name`).
/// Operations can be registered using the application object as a decorator (`@app.operation_name`).
///
/// Here's a full example to get you started:
///
/// ```python
${ if (operations.any { it.errors.isNotEmpty() }) {
"""/// from $crateName import ${Inputs.namespace}
/// from $crateName import ${Outputs.namespace}
/// from $crateName import ${Errors.namespace}"""
"""/// from $libName import ${Inputs.namespace}
/// from $libName import ${Outputs.namespace}
/// from $libName import ${Errors.namespace}"""
            } else {
"""/// from $crateName import ${Inputs.namespace}
/// from $crateName import ${Outputs.namespace}"""
"""/// from $libName import ${Inputs.namespace}
/// from $libName import ${Outputs.namespace}"""
            } }
/// from $crateName import App
/// from $libName import App
///
/// @dataclass
/// class Context:
+3 −2
Original line number Diff line number Diff line
@@ -18,9 +18,10 @@ import software.amazon.smithy.rust.codegen.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.server.python.smithy.PythonServerCargoDependency
import software.amazon.smithy.rust.codegen.smithy.RustCrate
import software.amazon.smithy.rust.codegen.smithy.ServerCodegenContext
import software.amazon.smithy.rust.codegen.util.toSnakeCase

class PythonServerModuleGenerator(
    private val codegenContext: ServerCodegenContext,
    codegenContext: ServerCodegenContext,
    private val rustCrate: RustCrate,
    private val serviceShapes: Set<Shape>
) {
@@ -29,7 +30,7 @@ class PythonServerModuleGenerator(
        "pyo3" to PythonServerCargoDependency.PyO3.asType(),
    )
    private val symbolProvider = codegenContext.symbolProvider
    private val libName = "lib${codegenContext.settings.moduleName}"
    private val libName = "lib${codegenContext.settings.moduleName.toSnakeCase()}"

    fun render() {
        rustCrate.withModule(
Loading