Unverified Commit 22f85e12 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Test unification (#72)

* Refactor CargoTomlGenerator to use Toml4J

* Generate Cargo.toml with a TOML lib & create unified test machinery

I'm going to hold off porting all the tests to use the new machinery until the builder refactor lands to avoid heinous conflicts.

* Fixup bad merge
parent 30502ebc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ 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("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
    implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
    runtimeOnly(project(":rust-runtime"))
+19 −0
Original line number Diff line number Diff line
@@ -102,6 +102,25 @@ data class CargoDependency(
        is Local -> "local"
    }

    fun toMap(): Map<String, Any> {
        val attribs = mutableMapOf<String, Any>()
        with(location) {
            when (this) {
                is CratesIo -> attribs["version"] = version
                is Local -> {
                    val fullPath = "$basePath/$name"
                    attribs["path"] = fullPath
                }
            }
        }
        with(features) {
            if (!isEmpty()) {
                attribs["features"] = this
            }
        }
        return attribs
    }

    override fun toString(): String {
        val attribs = mutableListOf<String>()
        with(location) {
+2 −1
Original line number Diff line number Diff line
@@ -125,7 +125,8 @@ fun CodeWriter.escape(text: String): String = text.replace("$expressionStart", "
 */
fun CodeWriter.raw(text: String) = writeInline(escape(text))

class RustWriter private constructor(
class
RustWriter private constructor(
    private val filename: String,
    val namespace: String,
    private val commentCharacter: String = "//",
+58 −0
Original line number Diff line number Diff line
package software.amazon.smithy.rust.codegen.smithy

import software.amazon.smithy.codegen.core.writer.CodegenWriterDelegator
import software.amazon.smithy.rust.codegen.lang.CargoDependency
import software.amazon.smithy.rust.codegen.lang.InlineDependency
import software.amazon.smithy.rust.codegen.lang.RustDependency
import software.amazon.smithy.rust.codegen.lang.RustModule
import software.amazon.smithy.rust.codegen.lang.RustWriter
import software.amazon.smithy.rust.codegen.smithy.generators.CargoTomlGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsGenerator

private fun CodegenWriterDelegator<RustWriter>.includedModules(): List<String> = this.writers.values.mapNotNull { it.module() }

// TODO: this should _probably_ be configurable via RustSettings; 2h
/**
 * Allowlist of modules that will be exposed publicly in generated crates
 */
private val PublicModules = setOf("error", "operation", "model", "input", "output")

/**
 * Finalize all the writers by:
 * - inlining inline dependencies that have been used
 * - generating (and writing) a Cargo.toml based on the settings & the required dependencies
 */
fun CodegenWriterDelegator<RustWriter>.finalize(settings: RustSettings) {
    val loadDependencies = { this.dependencies.map { dep -> RustDependency.fromSymbolDependency(dep) } }
    val inlineDependencies = loadDependencies().filterIsInstance<InlineDependency>().distinctBy { it.key() }
    inlineDependencies.forEach { dep ->
        this.useFileWriter("src/${dep.module}.rs", "crate::${dep.module}") {
            dep.renderer(it)
        }
    }
    val cargoDependencies = loadDependencies().filterIsInstance<CargoDependency>().distinct()
    this.useFileWriter("Cargo.toml") {
        val cargoToml = CargoTomlGenerator(
            settings,
            it,
            cargoDependencies
        )
        cargoToml.render()
    }
    this.useFileWriter("src/lib.rs", "crate::lib") { writer ->
        val includedModules = this.includedModules().toSet().filter { it != "lib" }
        val modules = includedModules.map { moduleName ->
            RustModule.default(moduleName, PublicModules.contains(moduleName))
        }
        LibRsGenerator(modules).render(writer)
    }
    this.flushWriters()
}

fun CodegenWriterDelegator<RustWriter>.withModule(
    moduleName: String,
    moduleWriter: RustWriter.() -> Unit
): CodegenWriterDelegator<RustWriter> {
    this.useFileWriter("src/$moduleName.rs", "crate::$moduleName", moduleWriter)
    return this
}
+3 −35
Original line number Diff line number Diff line
@@ -16,15 +16,9 @@ import software.amazon.smithy.model.shapes.StringShape
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.model.shapes.UnionShape
import software.amazon.smithy.model.traits.EnumTrait
import software.amazon.smithy.rust.codegen.lang.CargoDependency
import software.amazon.smithy.rust.codegen.lang.InlineDependency
import software.amazon.smithy.rust.codegen.lang.RustDependency
import software.amazon.smithy.rust.codegen.lang.RustModule
import software.amazon.smithy.rust.codegen.lang.RustWriter
import software.amazon.smithy.rust.codegen.smithy.generators.CargoTomlGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.EnumGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.HttpProtocolGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.LibRsGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.ModelBuilderGenerator
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolConfig
import software.amazon.smithy.rust.codegen.smithy.generators.ProtocolGeneratorFactory
@@ -39,11 +33,6 @@ import software.amazon.smithy.rust.codegen.util.CommandFailed
import software.amazon.smithy.rust.codegen.util.runCommand
import java.util.logging.Logger

/**
 * Allowlist of modules that will be exposed publicly in generated crates
 */
private val PublicModules = setOf("error", "operation", "model", "output", "input")

class CodegenVisitor(context: PluginContext) : ShapeVisitor.Default<Unit>() {

    private val logger = Logger.getLogger(javaClass.name)
@@ -58,7 +47,8 @@ class CodegenVisitor(context: PluginContext) : ShapeVisitor.Default<Unit>() {
    private val httpGenerator: HttpProtocolGenerator

    init {
        val symbolVisitorConfig = SymbolVisitorConfig(runtimeConfig = settings.runtimeConfig, codegenConfig = settings.codegenConfig)
        val symbolVisitorConfig =
            SymbolVisitorConfig(runtimeConfig = settings.runtimeConfig, codegenConfig = settings.codegenConfig)
        val baseModel = baselineTransform(context.model)
        val service = settings.getService(baseModel)
        val (protocol, generator) = ProtocolLoader.Default.protocolFor(context.model, service)
@@ -87,29 +77,7 @@ class CodegenVisitor(context: PluginContext) : ShapeVisitor.Default<Unit>() {
        val service = settings.getService(model)
        val serviceShapes = Walker(model).walkShapes(service)
        serviceShapes.forEach { it.accept(this) }
        val loadDependencies = { writers.dependencies.map { dep -> RustDependency.fromSymbolDependency(dep) } }
        val inlineDependencies = loadDependencies().filterIsInstance<InlineDependency>().distinctBy { it.key() }
        inlineDependencies.forEach { dep ->
            writers.useFileWriter("src/${dep.module}.rs", "crate::${dep.module}") {
                dep.renderer(it)
            }
        }
        val cargoDependencies = loadDependencies().filterIsInstance<CargoDependency>().distinct()
        writers.useFileWriter("Cargo.toml") {
            val cargoToml = CargoTomlGenerator(
                settings,
                it,
                cargoDependencies
            )
            cargoToml.render()
        }
        writers.useFileWriter("src/lib.rs", "crate::lib") { writer ->
            val includedModules = writers.includedModules().toSet().filter { it != "lib" }
            val modules = includedModules.map { moduleName ->
                RustModule.default(moduleName, PublicModules.contains(moduleName))
            }
            LibRsGenerator(modules).render(writer)
        }
        writers.finalize(settings)
        writers.flushWriters()
        try {
            "cargo fmt".runCommand(fileManifest.baseDir)
Loading