Skip to content

Commit

Permalink
Add Smithy CLI init command
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewFossAWS committed Jun 5, 2023
1 parent aca7df7 commit 39da3cc
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/*
* Copyright 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.cli.commands;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.function.Consumer;
import software.amazon.smithy.cli.ArgumentReceiver;
import software.amazon.smithy.cli.Arguments;
import software.amazon.smithy.cli.Command;
import software.amazon.smithy.cli.HelpPrinter;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.utils.IoUtils;

public class InitCommand implements Command {
private static final String TEMP_DIRECTORY = ".temp";
private static final String SMITHY_TEMPLATE_JSON = "smithy-templates.json";

private final String parentCommandName;

public InitCommand(String parentCommandName) {
this.parentCommandName = parentCommandName;
}

@Override
public String getName() {
return "init";
}

@Override
public String getSummary() {
return "Initialize a smithy project by template";
}

@Override
public int execute(Arguments arguments, Env env) {
arguments.addReceiver(new Options());
CommandAction action = HelpActionWrapper.fromCommand(this, parentCommandName, this::run);
return action.apply(arguments, env);
}

private int run(Arguments arguments, Env env) {
Options options = arguments.getReceiver(Options.class);
try {
this.cloneTemplate(options.repositoryUrl, options.template, options.directory);
} catch (IOException | InterruptedException | URISyntaxException e) {
throw new RuntimeException(e);
}

return 0;
}

private void cloneTemplate(String repositoryUrl, String templateName, String directory)
throws IOException, InterruptedException, URISyntaxException {

if (templateName == null || templateName.isEmpty()) {
throw new IllegalArgumentException("Please specify template via `--template` argument");
}

// Use templateName if directory is not specified
if (directory == null) {
directory = templateName;
}

// Clone the repository without downloading files
new ProcessBuilder(
"git", "clone", "--filter=blob:none", "--no-checkout",
"--depth", "1", "--sparse", repositoryUrl, TEMP_DIRECTORY)
.inheritIO().start().waitFor();

// Download template json file
new ProcessBuilder("git", "sparse-checkout", "set", "--no-cone", SMITHY_TEMPLATE_JSON)
.directory(new File(TEMP_DIRECTORY))
.start().waitFor();

new ProcessBuilder("git", "checkout")
.directory(new File(TEMP_DIRECTORY))
.start().waitFor();

String templatePath = readJsonFileAsNode(Paths.get(TEMP_DIRECTORY, SMITHY_TEMPLATE_JSON))
.expectObjectNode()
.expectObjectMember("templates")
.expectObjectMember(templateName)
.getStringMember("path").get().getValue();

// Specify the subdirectory to download
new ProcessBuilder("git", "sparse-checkout", "set", "--no-cone", templatePath)
.directory(new File(TEMP_DIRECTORY))
.start().waitFor();

new ProcessBuilder("git", "checkout")
.directory(new File(TEMP_DIRECTORY))
.start().waitFor();

Files.move(
Paths.get(TEMP_DIRECTORY, templatePath),
Paths.get(directory),
StandardCopyOption.REPLACE_EXISTING);

deleteDirectory(new File(TEMP_DIRECTORY));
}

private Node readJsonFileAsNode(Path jsonFilePath) throws IOException {
return Node.parse(IoUtils.toUtf8String(Files.newInputStream(jsonFilePath)));
}

private boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}

private static final class Options implements ArgumentReceiver {
private String template;

private String directory;

private String repositoryUrl = "https://github.com/smithy-lang/smithy-examples.git";

@Override
public boolean testOption(String name) {
return false;
}

@Override
public Consumer<String> testParameter(String name) {
switch (name) {
case "--template":
case "-t":
return value -> template = value;
case "--url":
return value -> repositoryUrl = value;
case "--directory":
case "-d":
return value -> directory = value;
default:
return value -> {
};
}
}

@Override
public void registerHelp(HelpPrinter printer) {
printer.param("--template", "-t", "quickstart-cli",
"Specify the template to be used in the Smithy project");
printer.param("--url", null,
"https://github.com/smithy-lang/smithy-examples.git",
"Smithy templates repository url");
printer.param("--directory", "-d", "new-smithy-project",
"Smithy project directory");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public SmithyCommand(DependencyResolver.Factory dependencyResolverFactory) {
new CleanCommand(getName()),
migrateCommand,
deprecated1To2Command,
new WarmupCommand(getName())
new WarmupCommand(getName()),
new InitCommand(getName())
);
}

Expand Down

0 comments on commit 39da3cc

Please sign in to comment.