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

Fix re-export of SdkError #2931

Merged
2 changes: 1 addition & 1 deletion .github/workflows/ci-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
name: Acquire Base Image
needs: save-docker-login-token
if: ${{ github.event.pull_request.head.repo.full_name == 'awslabs/smithy-rs' }}
runs-on: ubuntu-latest
runs-on: smithy_ubuntu-latest_8-core
env:
ENCRYPTED_DOCKER_PASSWORD: ${{ needs.save-docker-login-token.outputs.docker-login-password }}
DOCKER_LOGIN_TOKEN_PASSPHRASE: ${{ secrets.DOCKER_LOGIN_TOKEN_PASSPHRASE }}
Expand Down
15 changes: 14 additions & 1 deletion .github/workflows/update-sdk-next.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
# This workflow updates the `next` branch with freshly generated
# code from the latest smithy-rs and models that reside in aws-sdk-rust.

# Allow only one release to run at a time
concurrency:
group: update-aws-sdk-next
cancel-in-progress: true

name: Update `aws-sdk-rust/next`
on:
workflow_dispatch:
inputs:
generate_ref:
description: |
Which branch/commit/tag of smithy-rs to use to generate aws-sdk-rust/next. Defaults to `main`.
required: true
type: string
default: main

jobs:
update-next:
Expand All @@ -13,7 +26,7 @@ jobs:
uses: actions/checkout@v3
with:
repository: awslabs/smithy-rs
ref: main
ref: ${{ inputs.generate_ref }}
path: smithy-rs
- name: Check out `aws-sdk-rust`
uses: actions/checkout@v3
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ references = ["smithy-rs#2907", "aws-sdk-rust#864"]
meta = { "breaking" = false, "tada" = false, "bug" = true }
author = "jdisanti"

[[aws-sdk-rust]]
message = "Fixed re-exported `SdkError` type. The previous release had the wrong type for `SdkError`, which caused projects to fail to compile when upgrading."
references = ["smithy-rs#2931", "aws-sdk-rust#875"]
meta = { "breaking" = true, "tada" = false, "bug" = true }
author = "jdisanti"

[[smithy-rs]]
message = "Fixed re-exported `SdkError` type. The previous release had the wrong type for `SdkError` when generating code for orchestrator mode, which caused projects to fail to compile when upgrading."
references = ["smithy-rs#2931", "aws-sdk-rust#875"]
meta = { "breaking" = true, "tada" = false, "bug" = true, "target" = "client" }
author = "jdisanti"

[[smithy-rs]]
message = "Logging via `#[instrument]` in the `aws_smithy_runtime::client::orchestrator` module is now emitted at the `DEBUG` level to reduce the amount of logging when emitted at the `INFO` level."
references = ["smithy-rs#2934", "aws-sdk-rust#872"]
Expand Down
23 changes: 6 additions & 17 deletions aws/sdk/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import aws.sdk.AwsExamplesLayout
import aws.sdk.AwsServices
import aws.sdk.Membership
import aws.sdk.discoverServices
Expand Down Expand Up @@ -246,22 +245,12 @@ tasks.register<ExecRustBuildTool>("fixExampleManifests") {

toolPath = sdkVersionerToolPath
binaryName = "sdk-versioner"
arguments = when (AwsExamplesLayout.detect(project)) {
AwsExamplesLayout.Flat -> listOf(
"use-path-and-version-dependencies",
"--isolate-crates",
"--sdk-path", "../../sdk",
"--versions-toml", outputDir.resolve("versions.toml").absolutePath,
outputDir.resolve("examples").absolutePath,
)
AwsExamplesLayout.Workspaces -> listOf(
"use-path-and-version-dependencies",
"--isolate-crates",
"--sdk-path", sdkOutputDir.absolutePath,
"--versions-toml", outputDir.resolve("versions.toml").absolutePath,
outputDir.resolve("examples").absolutePath,
)
}
arguments = listOf(
"use-path-and-version-dependencies",
"--sdk-path", sdkOutputDir.absolutePath,
"--versions-toml", outputDir.resolve("versions.toml").absolutePath,
outputDir.resolve("examples").absolutePath,
)

outputs.dir(outputDir)
dependsOn("relocateExamples", "generateVersionManifest")
Expand Down
44 changes: 3 additions & 41 deletions buildSrc/src/main/kotlin/aws/sdk/ServiceLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,6 @@ data class RootTest(
val manifestName: String,
)

// TODO(https://github.com/awslabs/smithy-rs/issues/2810): We can remove the `Flat` layout after the switch
// to `Workspaces` has been released. This can be checked by looking at the `examples/` directory in aws-sdk-rust's
// main branch.
//
// The `Flat` layout is retained for backwards compatibility so that the next release process can succeed.
enum class AwsExamplesLayout {
/**
* Directory layout for examples used prior to June 26, 2023,
* where each example was in the `rust_dev_preview/` root directory and
* was considered to be its own workspace.
*
* This layout had issues with CI in terms of time to compile and disk space required
* since the dependencies would get recompiled for every example.
*/
Flat,

/**
* Current directory layout where there are a small number of workspaces
* rooted in `rust_dev_preview/`.
*/
Workspaces,
;

companion object {
fun detect(project: Project): AwsExamplesLayout = if (project.projectDir.resolve("examples/Cargo.toml").exists()) {
AwsExamplesLayout.Flat
} else {
AwsExamplesLayout.Workspaces
}
}
}

class AwsServices(
private val project: Project,
services: List<AwsService>,
Expand All @@ -77,15 +45,9 @@ class AwsServices(

val examples: List<String> by lazy {
val examplesRoot = project.projectDir.resolve("examples")
if (AwsExamplesLayout.detect(project) == AwsExamplesLayout.Flat) {
examplesRoot.listFiles { file -> !file.name.startsWith(".") }.orEmpty().toList()
.filter { file -> manifestCompatibleWithGeneratedServices(file) }
.map { "examples/${it.name}" }
} else {
examplesRoot.listFiles { file ->
!file.name.startsWith(".") && file.isDirectory() && file.resolve("Cargo.toml").exists()
}.orEmpty().toList().map { "examples/${it.name}" }
}
examplesRoot.listFiles { file ->
!file.name.startsWith(".") && file.isDirectory() && file.resolve("Cargo.toml").exists()
}.orEmpty().toList().map { "examples/${it.name}" }
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCus
import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
import software.amazon.smithy.rust.codegen.core.rustlang.Feature
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.smithy.RustCrate
import software.amazon.smithy.rust.codegen.core.smithy.customizations.AllowLintsCustomization
import software.amazon.smithy.rust.codegen.core.smithy.customizations.CrateVersionCustomization
import software.amazon.smithy.rust.codegen.core.smithy.customizations.pubUseSmithyErrorTypes
import software.amazon.smithy.rust.codegen.core.smithy.customizations.pubUseSmithyPrimitives
import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization
import software.amazon.smithy.rust.codegen.core.util.letIf
Expand Down Expand Up @@ -79,6 +81,8 @@ class RequiredCustomizations : ClientCodegenDecorator {
baseCustomizations + AllowLintsCustomization()

override fun extras(codegenContext: ClientCodegenContext, rustCrate: RustCrate) {
val rc = codegenContext.runtimeConfig

// Add rt-tokio feature for `ByteStream::from_path`
rustCrate.mergeFeature(Feature("rt-tokio", true, listOf("aws-smithy-http/rt-tokio")))

Expand All @@ -91,7 +95,29 @@ class RequiredCustomizations : ClientCodegenDecorator {
pubUseSmithyPrimitives(codegenContext, codegenContext.model)(this)
}
rustCrate.withModule(ClientRustModule.Error) {
pubUseSmithyErrorTypes(codegenContext)(this)
// TODO(enableNewSmithyRuntimeCleanup): Change SdkError to a `pub use` after changing the generic's default
rust("/// Error type returned by the client.")
if (codegenContext.smithyRuntimeMode.generateOrchestrator) {
rustTemplate(
"pub type SdkError<E, R = #{R}> = #{SdkError}<E, R>;",
"SdkError" to RuntimeType.sdkError(rc),
"R" to RuntimeType.smithyRuntimeApi(rc).resolve("client::orchestrator::HttpResponse"),
)
} else {
rustTemplate(
"pub type SdkError<E, R = #{R}> = #{SdkError}<E, R>;",
"SdkError" to RuntimeType.sdkError(rc),
"R" to RuntimeType.smithyHttp(rc).resolve("operation::Response"),
)
}
rustTemplate(
"""
pub use #{DisplayErrorContext};
pub use #{ProvideErrorMetadata};
""",
"DisplayErrorContext" to RuntimeType.smithyTypes(rc).resolve("error::display::DisplayErrorContext"),
"ProvideErrorMetadata" to RuntimeType.smithyTypes(rc).resolve("error::metadata::ProvideErrorMetadata"),
)
}

ClientRustModule.Meta.also { metaModule ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,12 @@ import software.amazon.smithy.model.Model
import software.amazon.smithy.model.shapes.Shape
import software.amazon.smithy.model.shapes.StructureShape
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.CodegenContext
import software.amazon.smithy.rust.codegen.core.smithy.CodegenTarget
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
import software.amazon.smithy.rust.codegen.core.util.hasEventStreamMember
import software.amazon.smithy.rust.codegen.core.util.hasStreamingMember
import software.amazon.smithy.rust.codegen.core.util.letIf

private data class PubUseType(
val type: RuntimeType,
val shouldExport: (Model) -> Boolean,
val alias: String? = null,
)

/** Returns true if the model has normal streaming operations (excluding event streams) */
private fun hasStreamingOperations(model: Model): Boolean {
Expand All @@ -48,62 +40,34 @@ private fun hasBlobs(model: Model): Boolean = structUnionMembersMatchPredicate(m
/** Returns true if the model uses any timestamp shapes */
private fun hasDateTimes(model: Model): Boolean = structUnionMembersMatchPredicate(model, Shape::isTimestampShape)

/** Returns a list of types that should be re-exported for the given model */
internal fun pubUseTypes(codegenContext: CodegenContext, model: Model): List<RuntimeType> =
pubUseTypesThatShouldBeExported(codegenContext, model).map { it.type }

private fun pubUseTypesThatShouldBeExported(codegenContext: CodegenContext, model: Model): List<PubUseType> {
val runtimeConfig = codegenContext.runtimeConfig
return (
listOf(
PubUseType(RuntimeType.blob(runtimeConfig), ::hasBlobs),
PubUseType(RuntimeType.dateTime(runtimeConfig), ::hasDateTimes),
PubUseType(RuntimeType.format(runtimeConfig), ::hasDateTimes, "DateTimeFormat"),
) + RuntimeType.smithyHttp(runtimeConfig).let { http ->
listOf(
PubUseType(http.resolve("byte_stream::ByteStream"), ::hasStreamingOperations),
PubUseType(http.resolve("byte_stream::AggregatedBytes"), ::hasStreamingOperations),
PubUseType(http.resolve("byte_stream::error::Error"), ::hasStreamingOperations, "ByteStreamError"),
PubUseType(http.resolve("body::SdkBody"), ::hasStreamingOperations),
)
}
).filter { pubUseType -> pubUseType.shouldExport(model) }
}

/** Adds re-export statements for Smithy primitives */
fun pubUseSmithyPrimitives(codegenContext: CodegenContext, model: Model): Writable = writable {
val types = pubUseTypesThatShouldBeExported(codegenContext, model)
if (types.isNotEmpty()) {
types.forEach {
val useStatement = if (it.alias == null) {
"pub use #T;"
} else {
"pub use #T as ${it.alias};"
}
rust(useStatement, it.type)
}
val rc = codegenContext.runtimeConfig
if (hasBlobs(model)) {
rustTemplate("pub use #{Blob};", "Blob" to RuntimeType.blob(rc))
}
}

/** Adds re-export statements for error types */
fun pubUseSmithyErrorTypes(codegenContext: CodegenContext): Writable = writable {
val runtimeConfig = codegenContext.runtimeConfig
val reexports = listOf(
listOf(
RuntimeType.smithyHttp(runtimeConfig).let { http ->
PubUseType(http.resolve("result::SdkError"), { _ -> true })
},
),
RuntimeType.smithyTypes(runtimeConfig).let { types ->
listOf(PubUseType(types.resolve("error::display::DisplayErrorContext"), { _ -> true }))
// Only re-export `ProvideErrorMetadata` for clients
.letIf(codegenContext.target == CodegenTarget.CLIENT) { list ->
list +
listOf(PubUseType(types.resolve("error::metadata::ProvideErrorMetadata"), { _ -> true }))
}
},
).flatten()
reexports.forEach { reexport ->
rust("pub use #T;", reexport.type)
if (hasDateTimes(model)) {
rustTemplate(
"""
pub use #{DateTime};
pub use #{Format} as DateTimeFormat;
""",
"DateTime" to RuntimeType.dateTime(rc),
"Format" to RuntimeType.format(rc),
)
}
if (hasStreamingOperations(model)) {
rustTemplate(
"""
pub use #{ByteStream};
pub use #{AggregatedBytes};
pub use #{Error} as ByteStreamError;
pub use #{SdkBody};
""",
"ByteStream" to RuntimeType.smithyHttp(rc).resolve("byte_stream::ByteStream"),
"AggregatedBytes" to RuntimeType.smithyHttp(rc).resolve("byte_stream::AggregatedBytes"),
"Error" to RuntimeType.smithyHttp(rc).resolve("byte_stream::error::Error"),
"SdkBody" to RuntimeType.smithyHttp(rc).resolve("body::SdkBody"),
)
}
}
Loading