Skip to content

Commit

Permalink
misc: add visibility build setting (#951)
Browse files Browse the repository at this point in the history
  • Loading branch information
lauzadis authored Sep 19, 2023
1 parent c63170f commit d40e71f
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changes/b6288fbe-a409-473c-a6ac-12c3c310b963.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "b6288fbe-a409-473c-a6ac-12c3c310b963",
"type": "misc",
"description": "Generate internal-only clients with `internal` visibility"
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import software.amazon.smithy.model.node.StringNode
import software.amazon.smithy.model.shapes.ServiceShape
import software.amazon.smithy.model.shapes.Shape
import software.amazon.smithy.model.shapes.ShapeId
import java.lang.IllegalArgumentException
import java.util.Optional
import java.util.logging.Logger
import kotlin.streams.toList
Expand All @@ -25,6 +26,7 @@ private const val PACKAGE_NAME = "name"
private const val PACKAGE_VERSION = "version"
private const val PACKAGE_DESCRIPTION = "description"
private const val BUILD_SETTINGS = "build"
private const val API_SETTINGS = "api"

// Optional specification of sdkId for models that provide them, otherwise Service's shape id name is used
private const val SDK_ID = "sdkId"
Expand All @@ -37,6 +39,7 @@ data class KotlinSettings(
val pkg: PackageSettings,
val sdkId: String,
val build: BuildSettings = BuildSettings.Default,
val api: ApiSettings = ApiSettings.Default,
) {

/**
Expand Down Expand Up @@ -91,11 +94,13 @@ data class KotlinSettings(
// Load the sdk id from configurations that define it, fall back to service name for those that don't.
val sdkId = config.getStringMemberOrDefault(SDK_ID, serviceId.name)
val build = config.getObjectMember(BUILD_SETTINGS)
val api = config.getObjectMember(API_SETTINGS)
return KotlinSettings(
serviceId,
PackageSettings(packageName, version, desc),
sdkId,
BuildSettings.fromNode(build),
ApiSettings.fromNode(api),
)
}
}
Expand Down Expand Up @@ -170,8 +175,7 @@ data class BuildSettings(
fun fromNode(node: Optional<ObjectNode>): BuildSettings = node.map {
val generateFullProject = node.get().getBooleanMemberOrDefault(ROOT_PROJECT, false)
val generateBuildFiles = node.get().getBooleanMemberOrDefault(GENERATE_DEFAULT_BUILD_FILES, true)
val generateMultiplatformProject =
node.get().getBooleanMemberOrDefault(GENERATE_MULTIPLATFORM_MODULE, false)
val generateMultiplatformProject = node.get().getBooleanMemberOrDefault(GENERATE_MULTIPLATFORM_MODULE, false)
val annotations = node.get().getArrayMember(ANNOTATIONS).map {
it.elements.mapNotNull { node ->
node.asStringNode().map { stringNode ->
Expand All @@ -193,3 +197,45 @@ data class BuildSettings(
class UnresolvableProtocolException(message: String) : CodegenException(message)

private fun <T> Optional<T>.orNull(): T? = if (isPresent) get() else null

/**
* The visibility of code-generated classes, objects, interfaces, etc.
* Valid values are `public` and `internal`. `private` not supported because codegen would not compile with private classes.
*/
enum class Visibility(val value: String) {
PUBLIC("public"),
INTERNAL("internal"),
;

override fun toString(): String = value

companion object {
public fun fromValue(value: String): Visibility = when (value.lowercase()) {
"public" -> PUBLIC
"internal" -> INTERNAL
else -> throw IllegalArgumentException("$value is not a valid Visibility value, expected $PUBLIC or $INTERNAL")
}
}
}

/**
* Contains API settings for a Kotlin project
* @param visibility Enum representing the visibility of code-generated classes, objects, interfaces, etc.
*/
data class ApiSettings(
val visibility: Visibility = Visibility.PUBLIC,
) {
companion object {
const val VISIBILITY = "visibility"

fun fromNode(node: Optional<ObjectNode>): ApiSettings = node.map {
val visibility = Visibility.fromValue(node.get().getStringMemberOrDefault(VISIBILITY, "public"))
ApiSettings(visibility)
}.orElse(Default)

/**
* Default build settings
*/
val Default: ApiSettings = ApiSettings()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ object ExceptionBaseClassGenerator {
val name = clientName(ctx.settings.sdkId)
writer.dokka("Base class for all service related exceptions thrown by the $name client")
writer.withBlock(
"public open class #T : #T {",
"#L open class #T : #T {",
"}",
ctx.settings.api.visibility,
serviceException,
baseException,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class ServiceClientGenerator(private val ctx: RenderingContext<ServiceShape>) {

fun render() {
writer.write("\n\n")
writer.write("public const val ServiceId: String = #S", ctx.settings.sdkId)
writer.write("public const val SdkVersion: String = #S", ctx.settings.pkg.version)
writer.write("#L const val ServiceId: String = #S", ctx.settings.api.visibility, ctx.settings.sdkId)
writer.write("#L const val SdkVersion: String = #S", ctx.settings.api.visibility, ctx.settings.pkg.version)
writer.write("\n\n")

writer.putContext("service.name", ctx.settings.sdkId)
Expand All @@ -82,7 +82,11 @@ class ServiceClientGenerator(private val ctx: RenderingContext<ServiceShape>) {

writer.renderDocumentation(service)
writer.renderAnnotations(service)
writer.openBlock("public interface ${serviceSymbol.name} : #T {", RuntimeTypes.SmithyClient.SdkClient)
writer.openBlock(
"#L interface ${serviceSymbol.name} : #T {",
ctx.settings.api.visibility,
RuntimeTypes.SmithyClient.SdkClient,
)
.call {
// allow access to client's Config
writer.dokka("${serviceSymbol.name}'s configuration")
Expand Down Expand Up @@ -198,7 +202,12 @@ class ServiceClientGenerator(private val ctx: RenderingContext<ServiceShape>) {
write("Any resources created on your behalf will be shared between clients, and will only be closed when ALL clients using them are closed.")
write("If you provide a resource (e.g. [HttpClientEngine]) to the SDK, you are responsible for managing the lifetime of that resource.")
}
writer.withBlock("public fun #1T.withConfig(block: #1T.Config.Builder.() -> Unit): #1T {", "}", serviceSymbol) {
writer.withBlock(
"#1L fun #2T.withConfig(block: #2T.Config.Builder.() -> Unit): #2T {",
"}",
ctx.settings.api.visibility,
serviceSymbol,
) {
write("val newConfig = config.toBuilder().apply(block).build()")
write("return Default#L(newConfig)", serviceSymbol.name)
}
Expand All @@ -219,7 +228,8 @@ class ServiceClientGenerator(private val ctx: RenderingContext<ServiceShape>) {
writer.renderDocumentation(op)
writer.renderAnnotations(op)
writer.write(
"public suspend inline fun #T.#L(crossinline block: #T.Builder.() -> Unit): #T = #L(#T.Builder().apply(block).build())",
"#L suspend inline fun #T.#L(crossinline block: #T.Builder.() -> Unit): #T = #L(#T.Builder().apply(block).build())",
ctx.settings.api.visibility,
serviceSymbol,
operationName,
inputSymbol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ class StructureGenerator(
* Renders a normal (non-error) Smithy structure to a Kotlin class
*/
private fun renderStructure() {
writer.openBlock("public class #T private constructor(builder: Builder) {", symbol)
writer.openBlock(
"#L class #T private constructor(builder: Builder) {",
ctx.settings.api.visibility,
symbol,
)
.call { renderImmutableProperties() }
.write("")
.call { renderCompanionObject() }
Expand Down Expand Up @@ -299,7 +303,11 @@ class StructureGenerator(
val exceptionBaseClass = ExceptionBaseClassGenerator.baseExceptionSymbol(ctx.settings)
writer.addImport(exceptionBaseClass)

writer.openBlock("public class #T private constructor(builder: Builder) : ${exceptionBaseClass.name}() {", symbol)
writer.openBlock(
"#L class #T private constructor(builder: Builder) : ${exceptionBaseClass.name}() {",
ctx.settings.api.visibility,
symbol,
)
.write("")
.call { renderImmutableProperties() }
.write("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ class AuthSchemeParametersGenerator : AbstractConfigGenerator() {
val implSymbol = getImplementationSymbol(ctx.settings)

ctx.delegator.useSymbolWriter(symbol) { writer ->
writer.withBlock("public interface #T {", "}", symbol) {
writer.withBlock(
"#L interface #T {",
"}",
ctx.settings.api.visibility,
symbol,
) {
dokka("The name of the operation currently being invoked.")
write("public val operationName: String")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ open class AuthSchemeProviderGenerator {
write("See [#T] for the default SDK behavior of this interface.", getDefaultSymbol(ctx.settings))
}
writer.write(
"public interface #T : #T<#T>",
"#L interface #T : #T<#T>",
ctx.settings.api.visibility,
symbol,
RuntimeTypes.Auth.Identity.AuthSchemeProvider,
paramsSymbol,
Expand All @@ -64,8 +65,9 @@ open class AuthSchemeProviderGenerator {
private fun renderDefaultImpl(ctx: ProtocolGenerator.GenerationContext, writer: KotlinWriter) {
// FIXME - probably can't remain an object
writer.withBlock(
"public object #T : #T {",
"#L object #T : #T {",
"}",
ctx.settings.api.visibility,
getDefaultSymbol(ctx.settings),
getSymbol(ctx.settings),
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class DefaultEndpointProviderGenerator(
private val defaultProviderSymbol: Symbol,
private val interfaceSymbol: Symbol,
private val paramsSymbol: Symbol,
private val settings: KotlinSettings,
private val externalFunctions: Map<String, Symbol> = emptyMap(),
private val propertyRenderers: Map<String, EndpointPropertyRenderer> = emptyMap(),
) : ExpressionRenderer {
Expand All @@ -78,7 +79,13 @@ class DefaultEndpointProviderGenerator(

fun render() {
renderDocumentation()
writer.withBlock("public class #T: #T {", "}", defaultProviderSymbol, interfaceSymbol) {
writer.withBlock(
"#L class #T: #T {",
"}",
settings.api.visibility,
defaultProviderSymbol,
interfaceSymbol,
) {
renderResolve()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ interface EndpointDelegator {
val defaultProviderSymbol = DefaultEndpointProviderGenerator.getSymbol(ctx.settings)

ctx.delegator.useFileWriter(providerSymbol) {
EndpointProviderGenerator(it, providerSymbol, paramsSymbol).render()
EndpointProviderGenerator(it, ctx.settings, providerSymbol, paramsSymbol).render()
}

if (rules != null) {
ctx.delegator.useFileWriter(defaultProviderSymbol) {
DefaultEndpointProviderGenerator(it, rules, defaultProviderSymbol, providerSymbol, paramsSymbol).render()
DefaultEndpointProviderGenerator(it, rules, defaultProviderSymbol, providerSymbol, paramsSymbol, ctx.settings).render()
}
}
}
Expand All @@ -49,7 +49,7 @@ interface EndpointDelegator {
fun generateEndpointParameters(ctx: ProtocolGenerator.GenerationContext, rules: EndpointRuleSet?) {
val paramsSymbol = EndpointParametersGenerator.getSymbol(ctx.settings)
ctx.delegator.useFileWriter(paramsSymbol) {
EndpointParametersGenerator(it, rules, paramsSymbol).render()
EndpointParametersGenerator(it, ctx.settings, rules, paramsSymbol).render()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ private const val DEFAULT_DEPRECATED_MESSAGE =
*/
class EndpointParametersGenerator(
private val writer: KotlinWriter,
private val settings: KotlinSettings,
rules: EndpointRuleSet?,
private val paramsSymbol: Symbol,
) {
Expand Down Expand Up @@ -51,7 +52,12 @@ class EndpointParametersGenerator(
fun render() {
renderDocumentation()
// FIXME - this should probably be an interface
writer.withBlock("public class #T private constructor(builder: Builder) {", "}", paramsSymbol) {
writer.withBlock(
"#L class #T private constructor(builder: Builder) {",
"}",
settings.api.visibility,
paramsSymbol,
) {
renderFields()
renderCompanionObject()
write("")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import software.amazon.smithy.kotlin.codegen.model.buildSymbol
*/
class EndpointProviderGenerator(
private val writer: KotlinWriter,
private val settings: KotlinSettings,
private val providerSymbol: Symbol,
private val paramsSymbol: Symbol,
) {
Expand All @@ -33,7 +34,8 @@ class EndpointProviderGenerator(
fun render() {
renderDocumentation()
writer.write(
"public fun interface #T: #T<#T>",
"#L fun interface #T: #T<#T>",
settings.api.visibility,
providerSymbol,
RuntimeTypes.SmithyClient.Endpoints.EndpointProvider,
paramsSymbol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ class EndpointDiscovererGenerator(private val ctx: CodegenContext, private val d
calls.
""".trimIndent(),
)
withBlock("public class #T {", "}", symbol) {
withBlock(
"#L class #T {",
"}",
ctx.settings.api.visibility,
symbol,
) {
write(
"private val cache = #T<DiscoveryParams, #T>(10.#T, #T.System)",
RuntimeTypes.Core.Utils.ReadThroughCache,
Expand Down
Loading

0 comments on commit d40e71f

Please sign in to comment.