diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java index 4ef351e47..9eb3cc8cf 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java @@ -255,10 +255,15 @@ void execute() { List dependencies = writers.getDependencies(); writers.flushWriters(); - GoModGenerator.writeGoMod(settings, fileManifest, SymbolDependency.gatherDependencies(dependencies.stream())); + GoModuleInfo goModuleInfo = new GoModuleInfo.Builder() + .goDirective(settings.getGoDirective()) + .dependencies(dependencies) + .build(); + + GoModGenerator.writeGoMod(settings, fileManifest, goModuleInfo); LOGGER.fine("Generating build manifest file"); - ManifestWriter.writeManifest(settings, model, fileManifest, dependencies); + ManifestWriter.writeManifest(settings, model, fileManifest, goModuleInfo); } @Override diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModGenerator.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModGenerator.java index bdc460f23..93208adf5 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModGenerator.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModGenerator.java @@ -19,12 +19,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; -import java.util.TreeMap; import java.util.logging.Logger; -import java.util.stream.Collectors; import software.amazon.smithy.build.FileManifest; import software.amazon.smithy.codegen.core.CodegenException; -import software.amazon.smithy.codegen.core.SymbolDependency; /** * Generates a go.mod file for the project. @@ -40,7 +37,7 @@ private GoModGenerator() {} static void writeGoMod( GoSettings settings, FileManifest manifest, - Map> dependencies + GoModuleInfo goModuleInfo ) { Boolean generateGoMod = settings.getGenerateGoMod(); if (!generateGoMod) { @@ -63,25 +60,14 @@ static void writeGoMod( manifest.addFile(goModFile); CodegenUtils.runCommand("go mod init " + settings.getModuleName(), manifest.getBaseDir()); - Map externalDependencies = getExternalDependencies(dependencies); - for (Map.Entry dependency : externalDependencies.entrySet()) { + for (Map.Entry dependency : goModuleInfo.getMinimumNonStdLibDependencies().entrySet()) { CodegenUtils.runCommand( String.format("go mod edit -require=%s@%s", dependency.getKey(), dependency.getValue()), manifest.getBaseDir()); } CodegenUtils.runCommand( - String.format("go mod edit -go=%s", settings.getGoDirective()), + String.format("go mod edit -go=%s", goModuleInfo.getGoDirective()), manifest.getBaseDir()); } - - private static Map getExternalDependencies( - Map> dependencies - ) { - return dependencies.entrySet().stream() - .filter(entry -> !entry.getKey().equals("stdlib")) - .flatMap(entry -> entry.getValue().entrySet().stream()) - .collect(Collectors.toMap( - Map.Entry::getKey, entry -> entry.getValue().getVersion(), (a, b) -> b, TreeMap::new)); - } } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModuleInfo.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModuleInfo.java new file mode 100644 index 000000000..d49c81ce5 --- /dev/null +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModuleInfo.java @@ -0,0 +1,126 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.smithy.go.codegen; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import software.amazon.smithy.codegen.core.SymbolDependency; +import software.amazon.smithy.utils.BuilderRef; +import software.amazon.smithy.utils.SmithyBuilder; + +public final class GoModuleInfo { + + public static final String DEFAULT_GO_DIRECTIVE = "1.15"; + + private List dependencies; + + private List stdLibDependencies; + private List nonStdLibDependencies; + + private String goDirective; + private Map minimumNonStdLibDependencies; + + private GoModuleInfo(Builder builder) { + goDirective = SmithyBuilder.requiredState("goDirective", builder.goDirective); + dependencies = builder.dependencies.copy(); + + // Intermediate dependency information + stdLibDependencies = gatherStdLibDependencies(); + nonStdLibDependencies = gatherNonStdLibDependencies(); + + // Module information used by ManifestWriter and GoModGenerator + goDirective = calculateMinimumGoDirective(); + minimumNonStdLibDependencies = gatherMinimumNonStdDependencies(); + } + + public String getGoDirective() { + return goDirective; + } + + public Map getMinimumNonStdLibDependencies() { + return minimumNonStdLibDependencies; + } + + private String calculateMinimumGoDirective() { + String minimumGoDirective = goDirective; + if (minimumGoDirective.compareTo(DEFAULT_GO_DIRECTIVE) < 0) { + throw new IllegalArgumentException( + "`goDirective` must be greater than or equal to the default go directive (" + + DEFAULT_GO_DIRECTIVE + "): " + minimumGoDirective); + } + for (SymbolDependency dependency : stdLibDependencies) { + var otherVersion = dependency.getVersion(); + if (minimumGoDirective.compareTo(otherVersion) < 0) { + minimumGoDirective = otherVersion; + } + } + return minimumGoDirective; + } + + private List gatherStdLibDependencies() { + return filterDependencies(dependency -> + dependency.getDependencyType().equals(GoDependency.Type.STANDARD_LIBRARY.toString())); + } + + private List gatherNonStdLibDependencies() { + return filterDependencies(dependency -> + !dependency.getDependencyType().equals(GoDependency.Type.STANDARD_LIBRARY.toString())); + } + + private List filterDependencies( + Predicate predicate + ) { + List filteredDependencies = new ArrayList<>(); + for (SymbolDependency dependency : dependencies) { + if (predicate.test(dependency)) { + filteredDependencies.add(dependency); + } + } + return filteredDependencies; + } + + private Map gatherMinimumNonStdDependencies() { + return SymbolDependency.gatherDependencies(nonStdLibDependencies.stream(), + GoDependency::mergeByMinimumVersionSelection).entrySet().stream().flatMap( + entry -> entry.getValue().entrySet().stream()).collect( + Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getVersion(), (a, b) -> b, TreeMap::new)); + } + + public static class Builder implements SmithyBuilder { + private String goDirective = DEFAULT_GO_DIRECTIVE; + private final BuilderRef> dependencies = BuilderRef.forList(); + + public Builder goDirective(String goDirective) { + this.goDirective = goDirective; + return this; + } + + public Builder dependencies(List dependencies) { + this.dependencies.clear(); + this.dependencies.get().addAll(dependencies); + return this; + } + + @Override + public GoModuleInfo build() { + return new GoModuleInfo(this); + } + } +} diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoSettings.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoSettings.java index ea6e348b0..c9f44ac48 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoSettings.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoSettings.java @@ -31,8 +31,6 @@ */ public final class GoSettings { - private static final String DEFAULT_GO_DIRECTIVE = "1.15"; - private static final String SERVICE = "service"; private static final String MODULE_NAME = "module"; private static final String MODULE_DESCRIPTION = "moduleDescription"; @@ -45,7 +43,7 @@ public final class GoSettings { private String moduleDescription = ""; private String moduleVersion; private Boolean generateGoMod = false; - private String goDirective = DEFAULT_GO_DIRECTIVE; + private String goDirective = GoModuleInfo.DEFAULT_GO_DIRECTIVE; private ShapeId protocol; /** @@ -65,7 +63,7 @@ public static GoSettings from(ObjectNode config) { MODULE_DESCRIPTION, settings.getModuleName() + " client")); settings.setModuleVersion(config.getStringMemberOrDefault(MODULE_VERSION, null)); settings.setGenerateGoMod(config.getBooleanMemberOrDefault(GENERATE_GO_MOD, false)); - settings.setGoDirective(config.getStringMemberOrDefault(GO_DIRECTIVE, DEFAULT_GO_DIRECTIVE)); + settings.setGoDirective(config.getStringMemberOrDefault(GO_DIRECTIVE, GoModuleInfo.DEFAULT_GO_DIRECTIVE)); return settings; } diff --git a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/ManifestWriter.java b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/ManifestWriter.java index 69d3679c8..0cbeb50a0 100644 --- a/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/ManifestWriter.java +++ b/codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/ManifestWriter.java @@ -21,16 +21,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.TreeMap; import java.util.logging.Logger; import java.util.stream.Collectors; -import java.util.stream.Stream; import software.amazon.smithy.build.FileManifest; import software.amazon.smithy.codegen.core.CodegenException; -import software.amazon.smithy.codegen.core.SymbolDependency; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.node.ArrayNode; import software.amazon.smithy.model.node.BooleanNode; @@ -38,7 +33,6 @@ import software.amazon.smithy.model.node.ObjectNode; import software.amazon.smithy.model.node.StringNode; import software.amazon.smithy.model.traits.UnstableTrait; -import software.amazon.smithy.utils.BuilderRef; import software.amazon.smithy.utils.SmithyBuilder; /** @@ -53,15 +47,13 @@ public final class ManifestWriter { private final String moduleName; private final FileManifest fileManifest; - private final List dependencies; - private final String goDirective; + private final GoModuleInfo goModuleInfo; private final boolean isUnstable; private ManifestWriter(Builder builder) { moduleName = SmithyBuilder.requiredState("moduleName", builder.moduleName); fileManifest = SmithyBuilder.requiredState("fileManifest", builder.fileManifest); - dependencies = builder.dependencies.copy(); - goDirective = builder.goDirective; + goModuleInfo = SmithyBuilder.requiredState("goModuleInfo", builder.goModuleInfo); isUnstable = builder.isUnstable; } @@ -71,19 +63,18 @@ private ManifestWriter(Builder builder) { * @param settings the go settings * @param model the smithy model * @param fileManifest the file manifest - * @param dependencies the list of symbol dependencies + * @param goModuleInfo the go module info */ public static void writeManifest( GoSettings settings, Model model, FileManifest fileManifest, - List dependencies + GoModuleInfo goModuleInfo ) { builder() .moduleName(settings.getModuleName()) .fileManifest(fileManifest) - .dependencies(dependencies) - .goDirective(settings.getGoDirective()) + .goModuleInfo(goModuleInfo) .isUnstable(settings.getService(model).getTrait(UnstableTrait.class).isPresent()) .build() .writeManifest(); @@ -113,57 +104,33 @@ public void writeManifest() { } private Node buildManifestFile() { - List nonStdLib = new ArrayList<>(); - Optional minimumGoVersion = Optional.empty(); - - for (SymbolDependency dependency : dependencies) { - if (!dependency.getDependencyType().equals(GoDependency.Type.STANDARD_LIBRARY.toString())) { - nonStdLib.add(dependency); - continue; - } - - var otherVersion = dependency.getVersion(); - if (minimumGoVersion.isPresent()) { - if (minimumGoVersion.get().compareTo(otherVersion) < 0) { - minimumGoVersion = Optional.of(otherVersion); - } - } else { - minimumGoVersion = Optional.of(otherVersion); - } - } - - Map manifestNodes = new HashMap<>(); - - Map minimumDependencies = gatherMinimumDependencies(nonStdLib.stream()); + Map dependencyNodes = gatherDependencyNodes(goModuleInfo.getMinimumNonStdLibDependencies()); + Collection generatedFiles = gatherGeneratedFiles(fileManifest); + return ObjectNode.objectNode(Map.of( + StringNode.from("module"), StringNode.from(moduleName), + StringNode.from("go"), StringNode.from(goModuleInfo.getGoDirective()), + StringNode.from("dependencies"), ObjectNode.objectNode(dependencyNodes), + StringNode.from("files"), ArrayNode.fromStrings(generatedFiles), + StringNode.from("unstable"), BooleanNode.from(isUnstable) + )).withDeepSortedKeys(); + } + private Map gatherDependencyNodes(Map dependencies) { Map dependencyNodes = new HashMap<>(); - for (Map.Entry entry : minimumDependencies.entrySet()) { + for (Map.Entry entry : dependencies.entrySet()) { dependencyNodes.put(StringNode.from(entry.getKey()), StringNode.from(entry.getValue())); } + return dependencyNodes; + } + private static Collection gatherGeneratedFiles(FileManifest fileManifest) { Collection generatedFiles = new ArrayList<>(); Path baseDir = fileManifest.getBaseDir(); for (Path filePath : fileManifest.getFiles()) { generatedFiles.add(baseDir.relativize(filePath).toString()); } generatedFiles = generatedFiles.stream().sorted().collect(Collectors.toList()); - - manifestNodes.put(StringNode.from("module"), StringNode.from(moduleName)); - manifestNodes.put(StringNode.from("go"), StringNode.from(minimumGoVersion.orElse(this.goDirective))); - manifestNodes.put(StringNode.from("dependencies"), ObjectNode.objectNode(dependencyNodes)); - manifestNodes.put(StringNode.from("files"), ArrayNode.fromStrings(generatedFiles)); - manifestNodes.put(StringNode.from("unstable"), BooleanNode.from(isUnstable)); - - return ObjectNode.objectNode(manifestNodes).withDeepSortedKeys(); - } - - private static Map gatherMinimumDependencies( - Stream symbolStream - ) { - return SymbolDependency.gatherDependencies(symbolStream, - GoDependency::mergeByMinimumVersionSelection).entrySet().stream().flatMap( - entry -> entry.getValue().entrySet().stream()).collect( - Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getVersion(), (a, b) -> b, TreeMap::new)); + return generatedFiles; } public static Builder builder() { @@ -173,8 +140,7 @@ public static Builder builder() { public static class Builder implements SmithyBuilder { private String moduleName; private FileManifest fileManifest; - private final BuilderRef> dependencies = BuilderRef.forList(); - private String goDirective; + private GoModuleInfo goModuleInfo; private boolean isUnstable; public Builder moduleName(String moduleName) { @@ -187,14 +153,8 @@ public Builder fileManifest(FileManifest fileManifest) { return this; } - public Builder dependencies(List dependencies) { - this.dependencies.clear(); - this.dependencies.get().addAll(dependencies); - return this; - } - - public Builder goDirective(String minimumGoVersion) { - this.goDirective = minimumGoVersion; + public Builder goModuleInfo(GoModuleInfo goModuleInfo) { + this.goModuleInfo = goModuleInfo; return this; } diff --git a/codegen/smithy-go-codegen/src/test/java/software/amazon/smithy/go/codegen/GenerateStandaloneGoModuleTest.java b/codegen/smithy-go-codegen/src/test/java/software/amazon/smithy/go/codegen/GenerateStandaloneGoModuleTest.java index 20660c42f..b152e16a9 100644 --- a/codegen/smithy-go-codegen/src/test/java/software/amazon/smithy/go/codegen/GenerateStandaloneGoModuleTest.java +++ b/codegen/smithy-go-codegen/src/test/java/software/amazon/smithy/go/codegen/GenerateStandaloneGoModuleTest.java @@ -1,13 +1,11 @@ package software.amazon.smithy.go.codegen; import static software.amazon.smithy.go.codegen.GoWriter.goBlockTemplate; -import static software.amazon.smithy.go.codegen.GoWriter.goTemplate; import static software.amazon.smithy.go.codegen.TestUtils.hasGoInstalled; import static software.amazon.smithy.go.codegen.TestUtils.makeGoModule; import static software.amazon.smithy.go.codegen.TestUtils.testGoModule; import java.nio.file.Files; -import java.nio.file.Path; import java.util.Map; import java.util.logging.Logger; import org.junit.jupiter.api.Test; @@ -78,10 +76,15 @@ public void testGenerateGoModule() throws Exception { var dependencies = writers.getDependencies(); writers.flushWriters(); + var goModuleInfo = new GoModuleInfo.Builder() + .goDirective(GoModuleInfo.DEFAULT_GO_DIRECTIVE) + .dependencies(dependencies) + .build(); + ManifestWriter.builder() .moduleName("github.com/aws/smithy-go/internal/testmodule") .fileManifest(fileManifest) - .dependencies(dependencies) + .goModuleInfo(goModuleInfo) .build() .writeManifest();