Skip to content

Commit

Permalink
Merge pull request #217 from disneystreaming/avoid-depending-on-publi…
Browse files Browse the repository at this point in the history
…sh-local

Rewrite the model loading logic to avoid having to depend on publishL…
  • Loading branch information
Baccata authored May 19, 2022
2 parents aca5285 + edf9c19 commit b25026c
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 40 deletions.
42 changes: 17 additions & 25 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ lazy val core = projectMatrix
"smithy.waiters",
"smithy4s.api"
),
genDiscoverModels := true,
Compile / sourceGenerators := Seq(genSmithyScala(Compile).taskValue),
Compile / sourceGenerators += sourceDirectory
.map(Boilerplate.gen(_, Boilerplate.BoilerplateModule.Core))
Expand All @@ -140,18 +141,15 @@ lazy val core = projectMatrix
(ThisBuild / baseDirectory).value / "sampleSpecs" / "adtMember.smithy"
),
(Test / sourceGenerators) := Seq(genSmithyScala(Test).taskValue),
testFrameworks += new TestFramework("weaver.framework.CatsEffect")
// TODO: bring back
// Compile / packageSrc / mappings ++= {
// val base = (Compile / sourceManaged).value
// val files = (Compile / managedSources).value
// files.map(f =>
// (
// f,
// f.relativeTo(base).get.getPath
// )
// )
// }
testFrameworks += new TestFramework("weaver.framework.CatsEffect"),
Compile / packageSrc / mappings ++= {
val base = (Compile / sourceManaged).value
val files = (Compile / managedSources).value
files
.map(f => (f, f.relativeTo(base)))
// this excludes modules/core/src/generated/PartiallyAppliedStruct.scala
.collect { case (f, Some(relF)) => f -> relF.getPath() }
}
)
.jvmPlatform(allJvmScalaVersions, jvmDimSettings)
.jsPlatform(allJsScalaVersions, jsDimSettings)
Expand Down Expand Up @@ -192,6 +190,7 @@ lazy val `aws-kernel` = projectMatrix
Dependencies.Weaver.scalacheck.value % Test
),
testFrameworks += new TestFramework("weaver.framework.CatsEffect"),
genDiscoverModels := true,
Compile / allowedNamespaces := Seq(
"aws.api",
"aws.auth",
Expand Down Expand Up @@ -247,6 +246,7 @@ lazy val `aws-http4s` = projectMatrix
.dependsOn(aws)
.settings(
isCE3 := true,
Test / genDiscoverModels := true,
libraryDependencies ++= {
Seq(
Dependencies.Http4s.client.value,
Expand All @@ -272,16 +272,7 @@ lazy val codegen = projectMatrix
.dependsOn(openapi)
.jvmPlatform(buildtimejvmScala2Versions, jvmDimSettings)
.settings(
buildInfoKeys := Seq[BuildInfoKey](
organization,
version,
scalaBinaryVersion,
"protocolArtifact" -> (protocol
.jvm(autoScalaLibrary = false) / moduleName).value,
"smithyOrg" -> Dependencies.Smithy.model.organization,
"smithyVersion" -> Dependencies.Smithy.model.revision,
"smithyArtifact" -> Dependencies.Smithy.model.name
),
buildInfoKeys := Seq[BuildInfoKey](version, scalaBinaryVersion),
buildInfoPackage := "smithy4s.codegen",
isCE3 := true,
libraryDependencies ++= Seq(
Expand Down Expand Up @@ -716,6 +707,7 @@ lazy val genSmithyOpenapiOutput = SettingKey[File]("genSmithyOpenapiOutput")
lazy val allowedNamespaces = SettingKey[Seq[String]]("allowedNamespaces")
lazy val genSmithyDependencies =
SettingKey[Seq[String]]("genSmithyDependencies")
lazy val genDiscoverModels = SettingKey[Boolean]("genDiscoverModels")

(ThisBuild / smithySpecs) := Seq.empty

Expand All @@ -727,9 +719,6 @@ def genSmithyResources(config: Configuration) = genSmithyImpl(config).map(_._2)
* library code, aws-specific code.
*/
def genSmithyImpl(config: Configuration) = Def.task {
// codegen needs the `protocol` jar to be published
(protocol.jvm(autoScalaLibrary = false) / publishLocal).value

val inputFiles = (config / smithySpecs).value
val outputDir = (config / genSmithyOutput).?.value
.getOrElse((config / sourceManaged).value)
Expand All @@ -741,6 +730,8 @@ def genSmithyImpl(config: Configuration) = Def.task {
val allowedNS = (config / allowedNamespaces).?.value.filterNot(_.isEmpty)
val smithyDeps =
(config / genSmithyDependencies).?.value.getOrElse(List.empty)
val discoverModels =
(config / genDiscoverModels).?.value.getOrElse(false)

val codegenCp =
(`codegen-cli`.jvm(Smithy4sPlugin.Scala213) / Compile / fullClasspath).value
Expand All @@ -765,6 +756,7 @@ def genSmithyImpl(config: Configuration) = Def.task {
val args =
List("--output", outputDir) ++
List("--openapi-output", openapiOutputDir) ++
(if (discoverModels) List("--discover-models") else Nil) ++
(if (allowedNS.isDefined)
List("--allowed-ns", allowedNS.get.mkString(","))
else Nil) ++ inputs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ object CodegenCommand {
)
.orFalse

val discoverModelsOpt =
Opts
.flag(
long = "discover-models",
help =
"Indicates whether the model assembler should try to discover models in the classpath"
)
.orFalse

val allowedNSOpt: Opts[Option[Set[String]]] =
Opts
.option[String](
Expand All @@ -93,6 +102,7 @@ object CodegenCommand {
openApiOutputOpt,
skipScalaOpt,
skipOpenapiOpt,
discoverModelsOpt,
allowedNSOpt,
excludedNSOpt,
repositoriesOpt,
Expand All @@ -102,14 +112,15 @@ object CodegenCommand {
)
.mapN {
// format: off
case (output, openApiOutput, skipScala, skipOpenapi, allowedNS, excludedNS, repositories, dependencies, transformers, specsArgs) =>
case (output, openApiOutput, skipScala, skipOpenapi, discoverModels, allowedNS, excludedNS, repositories, dependencies, transformers, specsArgs) =>
// format: on
CodegenArgs(
specsArgs,
output.getOrElse(os.pwd),
openApiOutput.getOrElse(os.pwd),
skipScala,
skipOpenapi,
discoverModels,
allowedNS,
excludedNS,
repositories.getOrElse(List.empty),
Expand Down
3 changes: 2 additions & 1 deletion modules/codegen-cli/src/smithy4s/codegen/cli/DumpModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ object DumpModel {
args.specs.map(_.toIO).toSet,
args.dependencies,
args.repositories,
args.transformers
args.transformers,
discoverModels = false
)

Node.prettyPrintJson(ModelSerializer.builder().build.serialize(model))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ object CommandParsingSpec extends FunSuite {
openapiOutput = os.pwd,
skipScala = false,
skipOpenapi = false,
discoverModels = false,
allowedNS = None,
excludedNS = None,
repositories = Nil,
Expand Down Expand Up @@ -77,6 +78,7 @@ object CommandParsingSpec extends FunSuite {
openapiOutput = os.pwd / "target" / "openapi",
skipScala = true,
skipOpenapi = true,
discoverModels = false,
allowedNS = Some(Set("name1", "name2")),
excludedNS = None,
repositories = List("repo1", "repo2"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ object Smithy4sCodegenPlugin extends AutoPlugin {
* to decide whether or not Codegen should run.
*/
def cachedSmithyCodegen(conf: Configuration) = Def.task {
val outputPath = (conf / smithy4sOutputDir).value.getAbsolutePath()
val openApiOutputPath = (conf / smithy4sOpenapiDir).value.getAbsolutePath()
val outputPath = (conf / smithy4sOutputDir).value
val openApiOutputPath = (conf / smithy4sOpenapiDir).value
val allowedNamespaces =
(conf / smithy4sAllowedNamespaces).?.value.map(_.toSet)
val excludedNamespaces =
Expand All @@ -149,7 +149,7 @@ object Smithy4sCodegenPlugin extends AutoPlugin {
val out = streams.value
val cacheFile =
out.cacheDirectory / s"smithy4s_${scalaBinaryVersion.value}"

// This is important - it's what re-triggers this task on file changes
val _ = (conf / smithy4sCodegen).inputFileChanges

Expand All @@ -169,6 +169,7 @@ object Smithy4sCodegenPlugin extends AutoPlugin {
openapiOutput = os.Path(openApiOutputPath),
skipScala = false,
skipOpenapi = false,
discoverModels = true, // we need protocol here
allowedNS = allowedNamespaces,
excludedNS = excludedNamespaces,
repositories = res,
Expand Down
6 changes: 4 additions & 2 deletions modules/codegen/src/smithy4s/codegen/Codegen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ object Codegen { self =>
args.specs.map(_.toIO).toSet,
args.dependencies,
args.repositories,
args.transformers
args.transformers,
args.discoverModels
)

val scalaFiles = if (!args.skipScala) {
Expand Down Expand Up @@ -95,7 +96,8 @@ object Codegen { self =>
Renderer(amended)
}
.map { result =>
val relPath = os.RelPath(result.namespace.replace('.', '/'))
val relPath =
os.RelPath(result.namespace.split('.').toIndexedSeq, ups = 0)
(relPath, result.name, result.content)
}
}
Expand Down
1 change: 1 addition & 0 deletions modules/codegen/src/smithy4s/codegen/CodegenArgs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ case class CodegenArgs(
openapiOutput: os.Path,
skipScala: Boolean,
skipOpenapi: Boolean,
discoverModels: Boolean,
allowedNS: Option[Set[String]],
excludedNS: Option[Set[String]],
repositories: List[String],
Expand Down
41 changes: 33 additions & 8 deletions modules/codegen/src/smithy4s/codegen/ModelLoader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,33 @@ import coursier.parse.RepositoryParser
import software.amazon.smithy.build.ProjectionTransformer
import software.amazon.smithy.build.TransformContext
import software.amazon.smithy.model.Model
import software.amazon.smithy.model.loader.ModelAssembler

import java.io.File
import java.net.URL
import java.net.URLClassLoader

object ModelLoader {
private val requiredDeps =
s"${smithy4s.codegen.BuildInfo.organization}:${smithy4s.codegen.BuildInfo.protocolArtifact}:${smithy4s.codegen.BuildInfo.version}" ::
s"${smithy4s.codegen.BuildInfo.smithyOrg}:${smithy4s.codegen.BuildInfo.smithyArtifact}:${smithy4s.codegen.BuildInfo.smithyVersion}" ::
Nil

def load(
specs: Set[File],
dependencies: List[String],
repositories: List[String],
transformers: List[String]
transformers: List[String],
discoverModels: Boolean
): (ClassLoader, Model) = {
val allDeps = dependencies ++ requiredDeps
val allDeps = dependencies
val maybeDeps = resolveDependencies(allDeps, repositories)
val currentClassLoader = this.getClass().getClassLoader()

// Loads a model using whatever's on the current classpath (in particular, anything that
// might be provided by smithy4s itself out of the box)
val modelBuilder = Model.builder()
val modelBuilder = Model
.assembler()
.addClasspathModels(currentClassLoader, discoverModels)
.assemble()
.unwrap()
.toBuilder()

maybeDeps.foreach { deps =>
// Loading the model just from upstream dependencies, in isolation
Expand All @@ -69,7 +72,9 @@ object ModelLoader {
}

val modelAssembler =
Model.assembler(validatorClassLoader).addModel(modelBuilder.build())
Model
.assembler(validatorClassLoader)
.addModel(modelBuilder.build())

specs.map(_.toPath()).foreach {
modelAssembler.addImport
Expand Down Expand Up @@ -127,4 +132,24 @@ object ModelLoader {
else None
}

implicit class ModelAssemblerOps(assembler: ModelAssembler) {
def addImports(urls: List[java.net.URL]): ModelAssembler = {
urls.foreach(assembler.addImport)
assembler
}

def addClasspathModels(
classLoader: ClassLoader,
flag: Boolean
): ModelAssembler = {
val smithy4sResources = List(
"META-INF/smithy/smithy4s.smithy",
"META-INF/smithy/smithy4s.meta.smithy"
).map(classLoader.getResource)

if (flag) assembler.discoverModels(classLoader)
else addImports(smithy4sResources)
}
}

}

0 comments on commit b25026c

Please sign in to comment.