From 8a5c21be3ac67c17e812478c0248e4a5be096fb6 Mon Sep 17 00:00:00 2001 From: Hunter Mellema <124718352+hpmellema@users.noreply.github.com> Date: Fri, 19 Apr 2024 10:39:53 -0600 Subject: [PATCH] Add a new plugin for setting up a trait package (#138) Add a new plugin for setting up a trait package. --- .../kotlin-jvm-project/build.gradle.kts | 2 +- settings.gradle.kts | 1 + .../amazon/smithy/gradle/SmithyUtils.java | 13 +++ .../internal/CliDependencyResolver.java | 15 ++-- smithy-trait-package/build.gradle.kts | 23 ++++++ .../gradle/SmithyTraitPackagePlugin.java | 82 +++++++++++++++++++ 6 files changed, 126 insertions(+), 10 deletions(-) create mode 100644 smithy-trait-package/build.gradle.kts create mode 100644 smithy-trait-package/src/main/java/software/amazon/smithy/gradle/SmithyTraitPackagePlugin.java diff --git a/examples/jar-plugin/kotlin-jvm-project/build.gradle.kts b/examples/jar-plugin/kotlin-jvm-project/build.gradle.kts index ee658d8..8899cec 100644 --- a/examples/jar-plugin/kotlin-jvm-project/build.gradle.kts +++ b/examples/jar-plugin/kotlin-jvm-project/build.gradle.kts @@ -1,7 +1,7 @@ // This project adds smithy models to a JAR created by a Kotlin project plugins { - kotlin("jvm") version "1.9.0" + kotlin("jvm") version "1.9.23" id("software.amazon.smithy.gradle.smithy-jar").version("1.0.0") } diff --git a/settings.gradle.kts b/settings.gradle.kts index 35e344b..e4ac09a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,4 +2,5 @@ rootProject.name = "smithy-gradle" include("smithy-base") include("smithy-jar") +include("smithy-trait-package") include("integ-test-utils") diff --git a/smithy-base/src/main/java/software/amazon/smithy/gradle/SmithyUtils.java b/smithy-base/src/main/java/software/amazon/smithy/gradle/SmithyUtils.java index 19aa172..d9806a5 100644 --- a/smithy-base/src/main/java/software/amazon/smithy/gradle/SmithyUtils.java +++ b/smithy-base/src/main/java/software/amazon/smithy/gradle/SmithyUtils.java @@ -19,6 +19,7 @@ import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.Directory; import org.gradle.api.file.FileCollection; @@ -238,5 +239,17 @@ static String getRelativeSourceSetName(SourceSet sourceSet, String name) { public static Configuration getCliConfiguration(Project project) { return project.getConfigurations().getByName(SMITHY_CLI_CONFIGURATION_NAME); } + + /** + * Checks if a dependency matches an expected name. + * + * @param dependency Dependency to check + * @param name Name of expected dependency + * @return true if the dependency matches the expected name + */ + public static boolean isMatchingDependency(Dependency dependency, String name) { + return Objects.equals(dependency.getGroup(), "software.amazon.smithy") + && dependency.getName().equals(name); + } } diff --git a/smithy-base/src/main/java/software/amazon/smithy/gradle/internal/CliDependencyResolver.java b/smithy-base/src/main/java/software/amazon/smithy/gradle/internal/CliDependencyResolver.java index 2fdce5e..071290e 100644 --- a/smithy-base/src/main/java/software/amazon/smithy/gradle/internal/CliDependencyResolver.java +++ b/smithy-base/src/main/java/software/amazon/smithy/gradle/internal/CliDependencyResolver.java @@ -6,7 +6,6 @@ package software.amazon.smithy.gradle.internal; import java.io.File; -import java.util.Objects; import java.util.Optional; import org.gradle.api.GradleException; import org.gradle.api.Project; @@ -46,18 +45,19 @@ private CliDependencyResolver() {} * * @param project Project to add dependencies to. * + * @return Returns the resolved CLI version */ - public static void resolve(Project project) { + public static String resolve(Project project) { Configuration cli = SmithyUtils.getCliConfiguration(project); // Prefer explicitly set dependency first. Optional explicitCliDepOptional = cli.getAllDependencies().stream() - .filter(CliDependencyResolver::isMatchingDependency) + .filter(d -> SmithyUtils.isMatchingDependency(d, SMITHY_CLI_DEP_NAME)) .findFirst(); if (explicitCliDepOptional.isPresent()) { project.getLogger().info(String.format("(using explicitly configured Smithy CLI: %s)", explicitCliDepOptional.get().getVersion())); - return; + return explicitCliDepOptional.get().getVersion(); } // Force projects in the main smithy repo to use an explicit smithy cli dependency @@ -66,6 +66,8 @@ public static void resolve(Project project) { // If no explicit dependency was found, find the CLI version by scanning and set this as a dependency String cliVersion = getCliVersion(project); project.getDependencies().add(cli.getName(), String.format(DEPENDENCY_NOTATION, cliVersion)); + + return cliVersion; } private static String getCliVersion(Project project) { @@ -101,11 +103,6 @@ public static String detectCliVersionInRuntimeDependencies(ConfigurationContaine .orElse(null); } - private static boolean isMatchingDependency(Dependency dependency) { - return Objects.equals(dependency.getGroup(), "software.amazon.smithy") - && dependency.getName().equals(SMITHY_CLI_DEP_NAME); - } - private static String scanForSmithyCliVersion(Project project) { // Finally, scan the buildScript dependencies for a smithy-model dependency. This // should be found because the Gradle plugin has a dependency on it. diff --git a/smithy-trait-package/build.gradle.kts b/smithy-trait-package/build.gradle.kts new file mode 100644 index 0000000..7b35e2b --- /dev/null +++ b/smithy-trait-package/build.gradle.kts @@ -0,0 +1,23 @@ +description = "Configures a Java library package for Smithy traits, using " + + "Smithy's trait-codegen plugin to generate Java implementation of traits." + +plugins { + id("smithy-gradle-plugin.plugin-conventions") +} + +gradlePlugin { + plugins { + create("smithy-trait-package-plugin") { + id = "${group}.smithy-trait-package" + displayName = "Smithy Gradle Trait Package plugin." + description = project.description + implementationClass = "software.amazon.smithy.gradle.SmithyTraitPackagePlugin" + tags.addAll("smithy", "api", "building") + } + } +} + +dependencies { + implementation(project(":smithy-jar")) + implementation(project(":smithy-base")) +} diff --git a/smithy-trait-package/src/main/java/software/amazon/smithy/gradle/SmithyTraitPackagePlugin.java b/smithy-trait-package/src/main/java/software/amazon/smithy/gradle/SmithyTraitPackagePlugin.java new file mode 100644 index 0000000..5276e07 --- /dev/null +++ b/smithy-trait-package/src/main/java/software/amazon/smithy/gradle/SmithyTraitPackagePlugin.java @@ -0,0 +1,82 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.gradle; + +import java.nio.file.Path; +import java.util.Optional; +import javax.inject.Inject; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.plugins.JavaLibraryPlugin; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import software.amazon.smithy.gradle.internal.CliDependencyResolver; + +/** + * A {@link org.gradle.api.Plugin} that adds sets up a package for a custom trait. + */ +public class SmithyTraitPackagePlugin implements Plugin { + private static final String SMITHY_TRAIT_CODEGEN_DEP_NAME = "smithy-trait-codegen"; + private static final String TRAIT_CODEGEN_PLUGIN_NAME = "trait-codegen"; + private static final String DEPENDENCY_NOTATION = "software.amazon.smithy:%s:%s"; + + private static final String SOURCE = "source"; + + private SmithyExtension extension; + private final Project project; + + @Inject + public SmithyTraitPackagePlugin(Project project) { + this.project = project; + } + + @Override + public void apply(Project project) { + project.getPlugins().apply(JavaLibraryPlugin.class); + project.getPlugins().apply(SmithyJarPlugin.class); + + extension = project.getExtensions().getByType(SmithyExtension.class); + + // Only configure trait codegen dependency for main sourceSet + project.getExtensions().getByType(SourceSetContainer.class).all(sourceSet -> { + if (SourceSet.isMain(sourceSet)) { + // Add Trait codegen outputs to source set + addGeneratedTraits(sourceSet); + project.afterEvaluate(p -> configureDependencies(sourceSet)); + } + }); + } + + private void addGeneratedTraits(SourceSet sourceSet) { + Path pluginOutput = extension.getPluginProjectionPath(SOURCE, TRAIT_CODEGEN_PLUGIN_NAME).get(); + sourceSet.getJava().srcDir(pluginOutput); + sourceSet.getResources().srcDir(pluginOutput).exclude("**/*.java"); + } + + // TODO: Add smithy-model dependency? + private void configureDependencies(SourceSet sourceSet) { + Configuration smithyBuild = project.getConfigurations() + .getByName(SmithyUtils.getSmithyBuildConfigurationName(sourceSet)); + + // Prefer explicit dependency + Optional explicitDepOptional = smithyBuild.getAllDependencies().stream() + .filter(d -> SmithyUtils.isMatchingDependency(d, + SmithyTraitPackagePlugin.SMITHY_TRAIT_CODEGEN_DEP_NAME)) + .findFirst(); + if (explicitDepOptional.isPresent()) { + project.getLogger().info(String.format("(using explicitly configured Dependency for %s: %s)", + SmithyTraitPackagePlugin.SMITHY_TRAIT_CODEGEN_DEP_NAME, explicitDepOptional.get().getVersion())); + return; + } + + // If trait codegen does not exist, add the dependency with the same version as the resolved CLI version + String cliVersion = CliDependencyResolver.resolve(project); + project.getDependencies().add(smithyBuild.getName(), + String.format(DEPENDENCY_NOTATION, SmithyTraitPackagePlugin.SMITHY_TRAIT_CODEGEN_DEP_NAME, cliVersion)); + } +}