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

Smithy 1.7 upgrade #340

Merged
merged 7 commits into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions aws/sdk/models/apigateway.json
Original file line number Diff line number Diff line change
Expand Up @@ -5251,7 +5251,8 @@
"parameters": {
"target": "com.amazonaws.apigateway#MapOfStringToString",
"traits": {
"smithy.api#documentation": "<p>A key-value map of query string parameters that specify properties of the export, depending on the requested <code>exportType</code>. For <code>exportType</code> <code>oas30</code> and <code>swagger</code>, any combination of the following parameters are supported: <code>extensions='integrations'</code> or <code>extensions='apigateway'</code> will export the API with x-amazon-apigateway-integration extensions. <code>extensions='authorizers'</code> will export the API with x-amazon-apigateway-authorizer extensions. <code>postman</code> will export the API with Postman extensions, allowing for import to the Postman tool</p>"
"smithy.api#documentation": "<p>A key-value map of query string parameters that specify properties of the export, depending on the requested <code>exportType</code>. For <code>exportType</code> <code>oas30</code> and <code>swagger</code>, any combination of the following parameters are supported: <code>extensions='integrations'</code> or <code>extensions='apigateway'</code> will export the API with x-amazon-apigateway-integration extensions. <code>extensions='authorizers'</code> will export the API with x-amazon-apigateway-authorizer extensions. <code>postman</code> will export the API with Postman extensions, allowing for import to the Postman tool</p>",
"smithy.api#httpQueryParams": {}
}
},
"accepts": {
Expand Down Expand Up @@ -6226,7 +6227,8 @@
"parameters": {
"target": "com.amazonaws.apigateway#MapOfStringToString",
"traits": {
"smithy.api#documentation": "<p>A string-to-string key-value map of query parameters <code>sdkType</code>-dependent properties of the SDK. For <code>sdkType</code> of <code>objectivec</code> or <code>swift</code>, a parameter named <code>classPrefix</code> is required. For <code>sdkType</code> of <code>android</code>, parameters named <code>groupId</code>, <code>artifactId</code>, <code>artifactVersion</code>, and <code>invokerPackage</code> are required. For <code>sdkType</code> of <code>java</code>, parameters named <code>serviceName</code> and <code>javaPackageName</code> are required. </p>"
"smithy.api#documentation": "<p>A string-to-string key-value map of query parameters <code>sdkType</code>-dependent properties of the SDK. For <code>sdkType</code> of <code>objectivec</code> or <code>swift</code>, a parameter named <code>classPrefix</code> is required. For <code>sdkType</code> of <code>android</code>, parameters named <code>groupId</code>, <code>artifactId</code>, <code>artifactVersion</code>, and <code>invokerPackage</code> are required. For <code>sdkType</code> of <code>java</code>, parameters named <code>serviceName</code> and <code>javaPackageName</code> are required. </p>",
"smithy.api#httpQueryParams": {}
}
}
},
Expand Down Expand Up @@ -6965,6 +6967,14 @@
"com.amazonaws.apigateway#ImportApiKeysRequest": {
"type": "structure",
"members": {
"body": {
"target": "com.amazonaws.apigateway#Blob",
"traits": {
"smithy.api#documentation": "<p>The payload of the POST request to import API keys. For the payload format, see <a href=\"https://docs.aws.amazon.com/apigateway/latest/developerguide/api-key-file-format.html\">API Key File Format</a>.</p>",
"smithy.api#httpPayload": {},
"smithy.api#required": {}
}
},
"format": {
"target": "com.amazonaws.apigateway#ApiKeysFormat",
"traits": {
Expand Down Expand Up @@ -7042,6 +7052,14 @@
"smithy.api#documentation": "<p>A query parameter to specify whether to rollback the documentation importation (<code>true</code>) or not (<code>false</code>) when a warning is encountered. The default value is <code>false</code>.</p>",
"smithy.api#httpQuery": "failonwarnings"
}
},
"body": {
"target": "com.amazonaws.apigateway#Blob",
"traits": {
"smithy.api#documentation": "<p>[Required] Raw byte array representing the to-be-imported documentation parts. To import from an OpenAPI file, this is a JSON object.</p>",
"smithy.api#httpPayload": {},
"smithy.api#required": {}
}
}
},
"traits": {
Expand Down Expand Up @@ -7095,7 +7113,16 @@
"parameters": {
"target": "com.amazonaws.apigateway#MapOfStringToString",
"traits": {
"smithy.api#documentation": "<p>A key-value map of context-specific query string parameters specifying the behavior of different API importing operations. The following shows operation-specific parameters and their supported values.</p>\n <p> To exclude <a>DocumentationParts</a> from the import, set <code>parameters</code> as <code>ignore=documentation</code>.</p>\n <p> To configure the endpoint type, set <code>parameters</code> as <code>endpointConfigurationTypes=EDGE</code>, <code>endpointConfigurationTypes=REGIONAL</code>, or <code>endpointConfigurationTypes=PRIVATE</code>. The default endpoint type is <code>EDGE</code>.</p>\n <p> To handle imported <code>basepath</code>, set <code>parameters</code> as <code>basepath=ignore</code>, <code>basepath=prepend</code> or <code>basepath=split</code>.</p>\n <p>For example, the AWS CLI command to exclude documentation from the imported API is:</p> \n <pre><code>aws apigateway import-rest-api --parameters ignore=documentation --body 'file:///path/to/imported-api-body.json'</code></pre>\n <p>The AWS CLI command to set the regional endpoint on the imported API is:</p>\n <pre><code>aws apigateway import-rest-api --parameters endpointConfigurationTypes=REGIONAL --body 'file:///path/to/imported-api-body.json'</code></pre>"
"smithy.api#documentation": "<p>A key-value map of context-specific query string parameters specifying the behavior of different API importing operations. The following shows operation-specific parameters and their supported values.</p>\n <p> To exclude <a>DocumentationParts</a> from the import, set <code>parameters</code> as <code>ignore=documentation</code>.</p>\n <p> To configure the endpoint type, set <code>parameters</code> as <code>endpointConfigurationTypes=EDGE</code>, <code>endpointConfigurationTypes=REGIONAL</code>, or <code>endpointConfigurationTypes=PRIVATE</code>. The default endpoint type is <code>EDGE</code>.</p>\n <p> To handle imported <code>basepath</code>, set <code>parameters</code> as <code>basepath=ignore</code>, <code>basepath=prepend</code> or <code>basepath=split</code>.</p>\n <p>For example, the AWS CLI command to exclude documentation from the imported API is:</p> \n <pre><code>aws apigateway import-rest-api --parameters ignore=documentation --body 'file:///path/to/imported-api-body.json'</code></pre>\n <p>The AWS CLI command to set the regional endpoint on the imported API is:</p>\n <pre><code>aws apigateway import-rest-api --parameters endpointConfigurationTypes=REGIONAL --body 'file:///path/to/imported-api-body.json'</code></pre>",
"smithy.api#httpQueryParams": {}
}
},
"body": {
"target": "com.amazonaws.apigateway#Blob",
"traits": {
"smithy.api#documentation": "<p>[Required] The POST request body containing external API definitions. Currently, only OpenAPI definition JSON/YAML files are supported. The maximum size of the API definition file is 6MB.</p>",
"smithy.api#httpPayload": {},
"smithy.api#required": {}
}
}
},
Expand Down Expand Up @@ -8569,7 +8596,16 @@
"parameters": {
"target": "com.amazonaws.apigateway#MapOfStringToString",
"traits": {
"smithy.api#documentation": "<p>Custom header parameters as part of the request. For example, to exclude <a>DocumentationParts</a> from an imported API, set <code>ignore=documentation</code> as a <code>parameters</code> value, as in the AWS CLI command of <code>aws apigateway import-rest-api --parameters ignore=documentation --body 'file:///path/to/imported-api-body.json'</code>.</p>"
"smithy.api#documentation": "<p>Custom header parameters as part of the request. For example, to exclude <a>DocumentationParts</a> from an imported API, set <code>ignore=documentation</code> as a <code>parameters</code> value, as in the AWS CLI command of <code>aws apigateway import-rest-api --parameters ignore=documentation --body 'file:///path/to/imported-api-body.json'</code>.</p>",
"smithy.api#httpQueryParams": {}
}
},
"body": {
"target": "com.amazonaws.apigateway#Blob",
"traits": {
"smithy.api#documentation": "<p>[Required] The PUT request body containing external API definitions. Currently, only OpenAPI definition JSON/YAML files are supported. The maximum size of the API definition file is 6MB.</p>",
"smithy.api#httpPayload": {},
"smithy.api#required": {}
}
}
},
Expand Down
7 changes: 1 addition & 6 deletions codegen-test/model/naming-obstacle-course.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ structure ReservedWords {
protocol: awsJson1_1,
params: {
"regular_string": "hello!",
"punned_string": { "ps_member": true },
},
method: "POST",
uri: "/",
body: "{\"regular_string\": \"hello!\", \"punned_string\": { \"ps_member\": true }}",
body: "{\"regular_string\": \"hello!\"}",
bodyMediaType: "application/json"
}
])
Expand All @@ -62,17 +61,13 @@ operation StructureNamePunning {

structure StructureNamePunningInput {
regular_string: smithy.api#String,
punned_string: crate#String,
punned_vec: Vec
}

structure Vec {
pv_member: Boolean
}

structure String {
ps_member: Boolean
}

operation ErrCollisions {
errors: [
Expand Down
40 changes: 40 additions & 0 deletions codegen-test/model/rest-json-extras.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,46 @@ use aws.api#service
use smithy.test#httpRequestTests
use smithy.test#httpResponseTests

apply QueryPrecedence @httpRequestTests([
{
id: "UrlParamsKeyEncoding",
documentation: "Keys and values must be url encoded",
protocol: restJson1,
method: "POST",
uri: "/Precedence",
body: "",
queryParams: ["bar=%26%F0%9F%90%B1", "hello%20there=how's%20your%20encoding?", "a%20%26%20b%20%26%20c=better%20encode%20%3D%20this"],
params: {
foo: "&🐱",
baz: {
"hello there": "how's your encoding?",
"a & b & c": "better encode = this"
}
},
appliesTo: "client",
},
{
id: "RestJsonQueryPrecedenceForbid",
documentation: "Prefer named query parameters when serializing",
protocol: restJson1,
method: "POST",
uri: "/Precedence",
body: "",
queryParams: [
"bar=named",
"qux=alsoFromMap"
],
forbidQueryParams: ["bar=fromMap"],
params: {
foo: "named",
baz: {
bar: "fromMap",
qux: "alsoFromMap"
}
},
appliesTo: "client",
}]
)

/// A REST JSON service that sends JSON requests and responses.
@service(sdkId: "Rest Json Protocol")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ class RustWriter private constructor(
}
}

fun ListForEach(
fun listForEach(
target: Shape,
outerField: String,
block: CodeWriter.(field: String, target: ShapeId) -> Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustC
).protocolFor(context.model, service)
protocolGenerator = generator
model = generator.transformModel(baseModel)
val baseProvider = RustCodegenPlugin.BaseSymbolProvider(model, symbolVisitorConfig)
val baseProvider = RustCodegenPlugin.baseSymbolProvider(model, service, symbolVisitorConfig)
symbolProvider = codegenDecorator.symbolProvider(generator.symbolProvider(model, baseProvider))

protocolConfig =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package software.amazon.smithy.rust.codegen.smithy
import software.amazon.smithy.build.PluginContext
import software.amazon.smithy.build.SmithyBuildPlugin
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.smithy.customize.CombinedCodegenDecorator

Expand All @@ -20,8 +21,8 @@ class RustCodegenPlugin : SmithyBuildPlugin {
}

companion object {
fun BaseSymbolProvider(model: Model, symbolVisitorConfig: SymbolVisitorConfig = DefaultConfig) =
SymbolVisitor(model, config = symbolVisitorConfig)
fun baseSymbolProvider(model: Model, serviceShape: ServiceShape, symbolVisitorConfig: SymbolVisitorConfig = DefaultConfig) =
SymbolVisitor(model, serviceShape = serviceShape, config = symbolVisitorConfig)
.let { BaseSymbolMetadataProvider(it) }
.let { RustReservedWordSymbolProvider(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ interface RustSymbolProvider : SymbolProvider {

class SymbolVisitor(
private val model: Model,
private val serviceShape: ServiceShape?,
private val config: SymbolVisitorConfig = DefaultConfig
) : RustSymbolProvider,
ShapeVisitor<Symbol> {
Expand All @@ -132,6 +133,14 @@ class SymbolVisitor(
return shape.accept(this)
}

private fun Shape.contextName(): String {
return if (serviceShape != null) {
id.getName(serviceShape)
} else {
id.name
}
}

override fun toMemberName(shape: MemberShape): String = shape.memberName.toSnakeCase()

override fun blobShape(shape: BlobShape?): Symbol {
Expand Down Expand Up @@ -173,7 +182,7 @@ class SymbolVisitor(
override fun doubleShape(shape: DoubleShape): Symbol = simpleShape(shape)
override fun stringShape(shape: StringShape): Symbol {
return if (shape.hasTrait(EnumTrait::class.java)) {
symbolBuilder(shape, RustType.Opaque(shape.id.name)).locatedIn(Models).build()
symbolBuilder(shape, RustType.Opaque(shape.contextName())).locatedIn(Models).build()
} else {
simpleShape(shape)
}
Expand Down Expand Up @@ -218,7 +227,7 @@ class SymbolVisitor(
}

override fun operationShape(shape: OperationShape): Symbol {
return symbolBuilder(shape, RustType.Opaque(shape.id.name.capitalize())).locatedIn(Operations).build()
return symbolBuilder(shape, RustType.Opaque(shape.contextName().capitalize())).locatedIn(Operations).build()
}

override fun resourceShape(shape: ResourceShape?): Symbol {
Expand All @@ -234,7 +243,7 @@ class SymbolVisitor(
val isInput = shape.hasTrait(SyntheticInputTrait::class.java)
val isOutput = shape.hasTrait(SyntheticOutputTrait::class.java)
val isBody = shape.hasTrait(InputBodyTrait::class.java) || shape.hasTrait(OutputBodyTrait::class.java)
val name = StringUtils.capitalize(shape.id.name).letIf(isError && config.codegenConfig.renameExceptions) {
val name = StringUtils.capitalize(shape.contextName()).letIf(isError && config.codegenConfig.renameExceptions) {
// TODO: Do we want to do this?
// https://github.com/awslabs/smithy-rs/issues/77
it.replace("Exception", "Error")
Expand All @@ -250,7 +259,7 @@ class SymbolVisitor(
}

override fun unionShape(shape: UnionShape): Symbol {
val name = StringUtils.capitalize(shape.id.name)
val name = StringUtils.capitalize(shape.contextName())
val builder = symbolBuilder(shape, RustType.Opaque(name)).locatedIn(Models)

return builder.build()
Expand Down Expand Up @@ -284,7 +293,6 @@ class SymbolVisitor(
// TODO(chore): Move this to a useful place
private const val RUST_TYPE_KEY = "rusttype"
private const val SHAPE_KEY = "shape"
private const val CAN_USE_DEFAULT = "canusedefault"
private const val SYMBOL_DEFAULT = "symboldefault"

fun Symbol.Builder.rustType(rustType: RustType): Symbol.Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ abstract class HttpProtocolGenerator(
val inputShape = operationShape.inputShape(model)
val sdkId =
protocolConfig.serviceShape.getTrait(ServiceTrait::class.java)
.map { it.sdkId.toLowerCase().replace(" ", "") }.orElse(protocolConfig.serviceShape.id.name)
.map { it.sdkId.toLowerCase().replace(" ", "") }
.orElse(protocolConfig.serviceShape.id.getName(protocolConfig.serviceShape))
val builderGenerator = BuilderGenerator(model, symbolProvider, operationShape.inputShape(model))
builderGenerator.render(inputWriter)
// impl OperationInputShape { ... }
Expand Down Expand Up @@ -158,7 +159,12 @@ abstract class HttpProtocolGenerator(
}
}

private fun buildOperation(implBlockWriter: RustWriter, shape: OperationShape, features: List<OperationCustomization>, sdkId: String) {
private fun buildOperation(
implBlockWriter: RustWriter,
shape: OperationShape,
features: List<OperationCustomization>,
sdkId: String
) {
val runtimeConfig = protocolConfig.runtimeConfig
val outputSymbol = symbolProvider.toSymbol(shape)
val operationT = RuntimeType.operation(runtimeConfig)
Expand All @@ -175,7 +181,10 @@ abstract class HttpProtocolGenerator(
val mut = features.any { it.mutSelf() }
val consumes = features.any { it.consumesSelf() }
val self = "self".letIf(mut) { "mut $it" }.letIf(!consumes) { "&$it" }
implBlockWriter.rustBlock("pub fn make_operation($self, _config: &#T::Config) -> $returnType", RuntimeType.Config) {
implBlockWriter.rustBlock(
"pub fn make_operation($self, _config: &#T::Config) -> $returnType",
RuntimeType.Config
) {
withBlock("Ok({", "})") {
features.forEach { it.section(OperationSection.MutateInput("self", "_config"))(this) }
rust("let request = Self::assemble(self.request_builder_base()?, self.build_body());")
Expand All @@ -192,7 +201,9 @@ abstract class HttpProtocolGenerator(
let op = #1T::Operation::new(
request,
#2T::new()
).with_metadata(#1T::Metadata::new(${shape.id.name.dq()}, ${sdkId.dq()}));
).with_metadata(#1T::Metadata::new(${
shape.id.getName(protocolConfig.serviceShape).dq()
}, ${sdkId.dq()}));
""",
operationModule, symbolProvider.toSymbol(shape)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class ErrorGenerator(
writer.rustBlock("impl #T for ${symbol.name}", stdfmt.member("Display")) {
rustBlock("fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result") {
// If the error id and the Rust name don't match, print the actual error id for easy debugging
// Note: Exceptions cannot be renamed so it is OK to not call `getName(service)` here
val errorDesc = symbol.name.letIf(symbol.name != shape.id.name) { symbolName ->
"$symbolName [${shape.id.name}]"
}
Expand Down
Loading