Unverified Commit 883fc057 authored by Russell Cohen's avatar Russell Cohen Committed by GitHub
Browse files

Generate an AWS-SDK shaped artifact (#92)

* Generate an AWS-SDK shaped artifact

* Fix gradle dependency tree

* Rename artifact to 'sdk'

* Load SdkId from the service shape
parent e2c766b1
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -113,3 +113,47 @@ jobs:
        toolchain: ${{ env.rust_version }}
    - name: execute runtime tests
      run: ./rust-runtime/test.sh

  generate-sdk:
    name: Generate an AWS SDK
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: actions/cache@v2
      name: Gradle Cache
      with:
        path: |
          ~/.gradle/caches
          ~/.gradle/wrapper
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
        restore-keys: |
          ${{ runner.os }}-gradle-
    - uses: actions/cache@v2
      name: Cargo Cache
      with:
        path: |
          ~/.cargo/registry
          ~/.cargo/git
          target
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
    - uses: actions-rs/toolchain@v1
      with:
        toolchain: ${{ env.rust_version }}
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: ${{ env.java_version }}
    - name: integration-tests
      run: ./gradlew :aws-sdk:assemble
    - name: docs
      run: ./gradlew :aws-sdk:cargoDocs
    - uses: actions/upload-artifact@v2
      name: Upload Codegen Output for inspection
        # Always upload the output even if the tests failed
      if: ${{ always() }}
      with:
        name: sdk
        path: |
          aws-sdk/build/aws-sdk/
          aws-sdk/build/target/doc
          !aws-sdk/build/target/debug

aws-sdk/.gitignore

0 → 100644
+1 −0
Original line number Diff line number Diff line
smithy-build.json
+169 −0
Original line number Diff line number Diff line
/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.aws.traits.ServiceTrait
import kotlin.streams.toList

extra["displayName"] = "Smithy :: Rust :: AWS-SDK"
extra["moduleName"] = "software.amazon.smithy.rust.awssdk"

tasks["jar"].enabled = false

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

val smithyVersion: String by project

val sdkOutputDir = buildDir.resolve("aws-sdk")
val awsServices = discoverServices()
// TODO: smithy-http should be removed
val runtimeModules = listOf("smithy-types", "smithy-http")

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

dependencies {
    implementation(project(":codegen"))
    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")
}

data class AwsService(val service: String, val module: String, val modelFile: File, val extraConfig: String? = null)

fun discoverServices(): List<AwsService>  {
    val models = project.file("models")
    return fileTree(models).map { file ->
        val model = Model.assembler().addImport(file.absolutePath).assemble().result.get()
        val services: List<ServiceShape> = model.shapes(ServiceShape::class.java).sorted().toList()
        if (services.size != 1) {
            throw Exception("There must be exactly one service in each aws model file")
        }
        val service = services[0]
        val sdkId = service.expectTrait(ServiceTrait::class.java).sdkId.toLowerCase()
        AwsService(service = service.id.toString(), module = sdkId, modelFile = file)
    }
}

fun generateSmithyBuild(tests: List<AwsService>): String {
    val projections = tests.joinToString(",\n") {
        """
            "${it.module}": {
                "imports": ["${it.modelFile.absolutePath}"],
                "plugins": {
                    "rust-codegen": {
                      "runtimeConfig": {
                        "relativePath": "../"
                      },
                      "service": "${it.service}",
                      "module": "${it.module}",
                      "moduleVersion": "0.0.1",
                      "build": {
                        "rootProject": true
                      }
                      ${it.extraConfig ?: ""}
                 }
               }
            }
        """.trimIndent()
    }
    return """
    {
        "version": "1.0",
        "projections": { $projections }
    }
    """
}


task("generateSmithyBuild") {
    description = "generate smithy-build.json"
    doFirst {
        projectDir.resolve("smithy-build.json").writeText(generateSmithyBuild(awsServices))
    }
    doLast {
        awsServices.forEach {
            copy {
                from("$buildDir/smithyprojections/aws-sdk/${it.module}/rust-codegen")
                into(sdkOutputDir.resolve(it.module))
            }
        }
    }
    finalizedBy("relocateRuntime")
}

tasks.register<Copy>("relocateRuntime") {
    from("$rootDir/rust-runtime") {
        runtimeModules.forEach {
            include("$it/**")
        }
        exclude("**/target")
    }
    into(sdkOutputDir)
}

fun generateCargoWorkspace(services: List<AwsService>): String {
    val modules = services.map(AwsService::module) + runtimeModules
    return """
    [workspace]
    members = [
        ${modules.joinToString(",") { "\"$it\"" }}
    ]
    """.trimIndent()
}
task("generateCargoWorkspace") {
    description = "generate Cargo.toml workspace file"
    doFirst {
        sdkOutputDir.resolve("Cargo.toml").writeText(generateCargoWorkspace(awsServices))
    }
}

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


tasks.register<Exec>("cargoCheck") {
    workingDir(buildDir.resolve("aws-sdk"))
    // disallow warnings
    environment("RUSTFLAGS", "-D warnings")
    commandLine("cargo", "check")
    dependsOn("assemble")
}

tasks.register<Exec>("cargoTest") {
    workingDir(buildDir.resolve("aws-sdk"))
    // disallow warnings
    environment("RUSTFLAGS", "-D warnings")
    commandLine("cargo", "test")
    dependsOn("assemble")
}

tasks.register<Exec>("cargoDocs") {
    workingDir(buildDir.resolve("aws-sdk"))
    // disallow warnings
    environment("RUSTFLAGS", "-D warnings")
    commandLine("cargo", "doc", "--no-deps")
    dependsOn("assemble")
}

tasks.register<Exec>("cargoClippy") {
    workingDir(buildDir.resolve("aws-sdk"))
    // disallow warnings
    environment("RUSTFLAGS", "-D warnings")
    commandLine("cargo", "clippy")
    dependsOn("assemble")
}

tasks["test"].dependsOn("cargoCheck", "cargoClippy", "cargoTest", "cargoDocs")

tasks["clean"].doFirst {
    delete("smithy-build.json")
}
+8964 −0

File added.

Preview size limit exceeded, changes collapsed.

+48 −9
Original line number Diff line number Diff line
@@ -5,7 +5,9 @@

use std::error::Error;

use dynamo::model::{AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType};
use dynamo::model::{
    AttributeDefinition, KeySchemaElement, KeyType, ProvisionedThroughput, ScalarAttributeType,
};
use dynamo::operation::CreateTable;
use dynamo::output::ListTablesOutput;

@@ -18,15 +20,31 @@ async fn main() -> Result<(), Box<dyn Error>> {
        .table_name(table_name)
        .build(&config);
    match io_v0::dispatch!(client, clear_table).parsed() {
        Ok(table_deleted) => println!("{:?} table was deleted", table_deleted),
        Ok(Ok(table_deleted)) => println!(
            "{:?} was deleted",
            table_deleted
                .table_description
                .as_ref()
                .unwrap()
                .table_name
                .as_ref()
                .unwrap()
        ),
        Ok(Err(table_del_error)) => println!("failed to delete table: {}", table_del_error),
        Err(e) => println!("dispatch error: {:?}", e),
    }

    let tables = io_v0::dispatch!(client, dynamo::operation::ListTables::builder().build(&config)).parsed.unwrap();
    let tables = io_v0::dispatch!(
        client,
        dynamo::operation::ListTables::builder().build(&config)
    )
    .parsed
    .unwrap();
    assert_eq!(
        tables.unwrap(),
        ListTablesOutput::builder().table_names(vec![]).build()
    );
    println!("no tables...creating table");

    let create_table = CreateTable::builder()
        .table_name(table_name)
@@ -38,21 +56,42 @@ async fn main() -> Result<(), Box<dyn Error>> {
            .attribute_name("ForumName")
            .key_type(KeyType::from("HASH"))
            .build()])
        .provisioned_throughput(ProvisionedThroughput::builder().read_capacity_units(100).write_capacity_units(100).build())
        .provisioned_throughput(
            ProvisionedThroughput::builder()
                .read_capacity_units(100)
                .write_capacity_units(100)
                .build(),
        )
        .build(&config);

    let response = io_v0::dispatch!(client, create_table);
    match response.parsed {
        Some(Ok(output)) => assert_eq!(output.table_description.unwrap().table_name.unwrap(), table_name),
        _ => println!("{:?}", response.raw)
        Some(Ok(output)) => {
            assert_eq!(
                output.table_description.unwrap().table_name.unwrap(),
                table_name
            );
            println!("{} was created", table_name);
        }
        _ => println!("{:?}", response.raw),
    }

    let tables = io_v0::dispatch!(client, dynamo::operation::ListTables::builder().build(&config)).parsed.unwrap();
    let tables = io_v0::dispatch!(
        client,
        dynamo::operation::ListTables::builder().build(&config)
    )
    .parsed
    .unwrap();
    println!(
        "current tables: {:?}",
        &tables.as_ref().unwrap().table_names
    );
    assert_eq!(
        tables.unwrap(),
        ListTablesOutput::builder().table_names(vec![table_name.to_string()]).build()
        ListTablesOutput::builder()
            .table_names(vec![table_name.to_string()])
            .build()
    );

    //assert_eq!(table_created.table_description.unwrap().table_name.unwrap(), "new table");
    Ok(())
}
Loading