-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from JordonPhillips/shape-generation
Generate basic Go module with structures
- Loading branch information
Showing
11 changed files
with
893 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/* | ||
* Copyright 2020 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.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.nio.charset.Charset; | ||
import java.nio.file.Path; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.logging.Logger; | ||
import software.amazon.smithy.codegen.core.CodegenException; | ||
import software.amazon.smithy.utils.StringUtils; | ||
|
||
/** | ||
* Utility methods likely to be needed across packages. | ||
*/ | ||
public final class CodegenUtils { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(CodegenUtils.class.getName()); | ||
|
||
private CodegenUtils() {} | ||
|
||
/** | ||
* Executes a given shell command in a given directory. | ||
* | ||
* @param command The string command to execute, e.g. "go fmt". | ||
* @param directory The directory to run the command in. | ||
* @return Returns the console output of the command. | ||
*/ | ||
public static String runCommand(String command, Path directory) { | ||
String[] finalizedCommand; | ||
if (System.getProperty("os.name").toLowerCase().startsWith("windows")) { | ||
finalizedCommand = new String[]{"cmd.exe", "/c", command}; | ||
} else { | ||
finalizedCommand = new String[]{"sh", "-c", command}; | ||
} | ||
|
||
ProcessBuilder processBuilder = new ProcessBuilder(finalizedCommand) | ||
.redirectErrorStream(true) | ||
.directory(directory.toFile()); | ||
|
||
try { | ||
Process process = processBuilder.start(); | ||
List<String> output = new ArrayList<>(); | ||
|
||
// Capture output for reporting. | ||
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( | ||
process.getInputStream(), Charset.defaultCharset()))) { | ||
String line; | ||
while ((line = bufferedReader.readLine()) != null) { | ||
LOGGER.finest(line); | ||
output.add(line); | ||
} | ||
} | ||
|
||
process.waitFor(); | ||
process.destroy(); | ||
|
||
String joinedOutput = String.join(System.lineSeparator(), output); | ||
if (process.exitValue() != 0) { | ||
throw new CodegenException(String.format( | ||
"Command `%s` failed with output:%n%n%s", command, joinedOutput)); | ||
} | ||
return joinedOutput; | ||
} catch (InterruptedException | IOException e) { | ||
throw new CodegenException(e); | ||
} | ||
} | ||
|
||
/** | ||
* Gets the name under which the given package will be exported by default. | ||
* | ||
* @param packageName The full package name of the exported package. | ||
* @return The name a the package will be imported under by default. | ||
*/ | ||
public static String getDefaultPackageImportName(String packageName) { | ||
if (StringUtils.isBlank(packageName) || !packageName.contains("/")) { | ||
return packageName; | ||
} | ||
return packageName.substring(packageName.lastIndexOf('/') + 1); | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
...gen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/CodegenVisitor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright 2020 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.Set; | ||
import java.util.TreeSet; | ||
import java.util.logging.Logger; | ||
import software.amazon.smithy.build.FileManifest; | ||
import software.amazon.smithy.build.PluginContext; | ||
import software.amazon.smithy.codegen.core.SymbolProvider; | ||
import software.amazon.smithy.model.Model; | ||
import software.amazon.smithy.model.neighbor.Walker; | ||
import software.amazon.smithy.model.shapes.ServiceShape; | ||
import software.amazon.smithy.model.shapes.Shape; | ||
import software.amazon.smithy.model.shapes.ShapeVisitor; | ||
import software.amazon.smithy.model.shapes.StructureShape; | ||
|
||
/** | ||
* Orchestrates Go client generation. | ||
*/ | ||
final class CodegenVisitor extends ShapeVisitor.Default<Void> { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(CodegenVisitor.class.getName()); | ||
|
||
private final GoSettings settings; | ||
private final Model model; | ||
private final Model modelWithoutTraitShapes; | ||
private final ServiceShape service; | ||
private final FileManifest fileManifest; | ||
private final SymbolProvider symbolProvider; | ||
private final GoDelegator writers; | ||
|
||
CodegenVisitor(PluginContext context) { | ||
settings = GoSettings.from(context.getSettings()); | ||
model = context.getModel(); | ||
modelWithoutTraitShapes = context.getModelWithoutTraitShapes(); | ||
service = settings.getService(model); | ||
fileManifest = context.getFileManifest(); | ||
LOGGER.info(() -> "Generating Go client for service " + service.getId()); | ||
|
||
symbolProvider = GoCodegenPlugin.createSymbolProvider(model); | ||
writers = new GoDelegator(settings, model, fileManifest, symbolProvider); | ||
} | ||
|
||
void execute() { | ||
// Generate models that are connected to the service being generated. | ||
LOGGER.fine("Walking shapes from " + service.getId() + " to find shapes to generate"); | ||
Set<Shape> serviceShapes = new TreeSet<>(new Walker(modelWithoutTraitShapes).walkShapes(service)); | ||
|
||
for (Shape shape : serviceShapes) { | ||
shape.accept(this); | ||
} | ||
|
||
LOGGER.fine("Flushing go writers"); | ||
writers.flushWriters(); | ||
|
||
LOGGER.fine("Generating go.mod file"); | ||
GoModGenerator.writeGoMod(settings, fileManifest); | ||
|
||
LOGGER.fine("Running go fmt"); | ||
CodegenUtils.runCommand("go fmt", fileManifest.getBaseDir()); | ||
} | ||
|
||
@Override | ||
protected Void getDefault(Shape shape) { | ||
return null; | ||
} | ||
|
||
@Override | ||
public Void structureShape(StructureShape shape) { | ||
writers.useShapeWriter(shape, writer -> new StructureGenerator(model, symbolProvider, writer, shape).run()); | ||
return null; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
...en/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoCodegenPlugin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
* Copyright 2020 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 software.amazon.smithy.build.PluginContext; | ||
import software.amazon.smithy.build.SmithyBuildPlugin; | ||
import software.amazon.smithy.codegen.core.SymbolProvider; | ||
import software.amazon.smithy.model.Model; | ||
|
||
/** | ||
* Plugin to trigger Go code generation. | ||
*/ | ||
public final class GoCodegenPlugin implements SmithyBuildPlugin { | ||
@Override | ||
public String getName() { | ||
return "go-codegen"; | ||
} | ||
|
||
@Override | ||
public void execute(PluginContext context) { | ||
new CodegenVisitor(context).execute(); | ||
} | ||
|
||
/** | ||
* Creates a Go symbol provider. | ||
* @param model The model to generate symbols for. | ||
* @return Returns the created provider. | ||
*/ | ||
public static SymbolProvider createSymbolProvider(Model model) { | ||
return new SymbolVisitor(model); | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
codegen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoDelegator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
* Copyright 2020 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.nio.file.Paths; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.function.Consumer; | ||
import software.amazon.smithy.build.FileManifest; | ||
import software.amazon.smithy.codegen.core.Symbol; | ||
import software.amazon.smithy.codegen.core.SymbolProvider; | ||
import software.amazon.smithy.model.Model; | ||
import software.amazon.smithy.model.shapes.Shape; | ||
|
||
/** | ||
* Manages writers for Go files. | ||
*/ | ||
final class GoDelegator { | ||
|
||
private final GoSettings settings; | ||
private final Model model; | ||
private final FileManifest fileManifest; | ||
private final SymbolProvider symbolProvider; | ||
private final Map<String, GoWriter> writers = new HashMap<>(); | ||
|
||
GoDelegator(GoSettings settings, Model model, FileManifest fileManifest, SymbolProvider symbolProvider) { | ||
this.settings = settings; | ||
this.model = model; | ||
this.fileManifest = fileManifest; | ||
this.symbolProvider = symbolProvider; | ||
} | ||
|
||
/** | ||
* Writes all pending writers to disk and then clears them out. | ||
*/ | ||
void flushWriters() { | ||
writers.forEach((filename, writer) -> fileManifest.writeFile(filename, writer.toString())); | ||
writers.clear(); | ||
} | ||
|
||
/** | ||
* Gets a previously created writer or creates a new one if needed. | ||
* | ||
* @param shape Shape to create the writer for. | ||
* @param writerConsumer Consumer that accepts and works with the file. | ||
*/ | ||
void useShapeWriter(Shape shape, Consumer<GoWriter> writerConsumer) { | ||
Symbol symbol = symbolProvider.toSymbol(shape); | ||
String namespace = symbol.getNamespace(); | ||
if (namespace.equals(".")) { | ||
namespace = CodegenUtils.getDefaultPackageImportName(settings.getModuleName()); | ||
} | ||
GoWriter writer = checkoutWriter(symbol.getDefinitionFile(), namespace); | ||
|
||
writer.pushState(); | ||
writerConsumer.accept(writer); | ||
writer.popState(); | ||
} | ||
|
||
private GoWriter checkoutWriter(String filename, String namespace) { | ||
String formattedFilename = Paths.get(filename).normalize().toString(); | ||
boolean needsNewline = writers.containsKey(formattedFilename); | ||
|
||
GoWriter writer = writers.computeIfAbsent(formattedFilename, f -> new GoWriter(namespace)); | ||
|
||
if (needsNewline) { | ||
writer.write("\n"); | ||
} | ||
|
||
return writer; | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
...gen/smithy-go-codegen/src/main/java/software/amazon/smithy/go/codegen/GoModGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright 2020 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.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import software.amazon.smithy.build.FileManifest; | ||
import software.amazon.smithy.codegen.core.CodegenException; | ||
|
||
/** | ||
* Generates a go.mod file for the project. | ||
* | ||
* <p>See here for more information on the format: https://github.com/golang/go/wiki/Modules#gomod | ||
* | ||
* TODO: pull in dependencies | ||
*/ | ||
final class GoModGenerator { | ||
|
||
private GoModGenerator() {} | ||
|
||
static void writeGoMod(GoSettings settings, FileManifest manifest) { | ||
Path goModFile = manifest.getBaseDir().resolve("go.mod"); | ||
|
||
// `go mod init` will fail if the `go.mod` already exists, so this deletes | ||
// it if it's present in the output. While it's technically possible | ||
// to simply edit the file, it's easier to just start fresh. | ||
if (Files.exists(goModFile)) { | ||
try { | ||
Files.delete(goModFile); | ||
} catch (IOException e) { | ||
throw new CodegenException("Failed to delete existing go.mod file", e); | ||
} | ||
} | ||
CodegenUtils.runCommand("go mod init " + settings.getModuleName(), manifest.getBaseDir()); | ||
} | ||
} |
Oops, something went wrong.