mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-07-04 06:30:52 +00:00
Merge pull request #547 from lanwen/cli
add - new command line interface in distribution module
This commit is contained in:
commit
b36f3c98ca
@ -1,80 +1,95 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<parent>
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<groupId>com.wordnik</groupId>
|
<parent>
|
||||||
<artifactId>swagger-codegen-project</artifactId>
|
<groupId>com.wordnik</groupId>
|
||||||
<version>2.1.3-M1-SNAPSHOT</version>
|
<artifactId>swagger-codegen-project</artifactId>
|
||||||
<relativePath>../..</relativePath>
|
<version>2.1.3-M1-SNAPSHOT</version>
|
||||||
</parent>
|
<relativePath>../..</relativePath>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
</parent>
|
||||||
<groupId>com.wordnik</groupId>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>swagger-codegen-distribution</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
<artifactId>swagger-codegen-distribution</artifactId>
|
||||||
<name>swagger-codegen (executable)</name>
|
<packaging>jar</packaging>
|
||||||
<version>2.1.3-M1-SNAPSHOT</version>
|
|
||||||
<build>
|
<name>swagger-codegen (executable)</name>
|
||||||
<testSourceDirectory>src/test/scala</testSourceDirectory>
|
|
||||||
<outputDirectory>target/classes</outputDirectory>
|
<build>
|
||||||
<testOutputDirectory>target/test-classes</testOutputDirectory>
|
<finalName>swagger-cli</finalName>
|
||||||
<defaultGoal>install</defaultGoal>
|
<plugins>
|
||||||
<directory>target</directory>
|
<plugin>
|
||||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<plugins>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
<plugin>
|
<configuration>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<archive>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<manifest>
|
||||||
<configuration>
|
<mainClass>com.wordnik.swagger.codegen.SwaggerCodegen</mainClass>
|
||||||
<archive>
|
</manifest>
|
||||||
<manifest>
|
</archive>
|
||||||
<mainClass>com.wordnik.swagger.codegen.Codegen</mainClass>
|
</configuration>
|
||||||
</manifest>
|
</plugin>
|
||||||
</archive>
|
<plugin>
|
||||||
</configuration>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
</plugin>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<plugin>
|
<version>2.3</version>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<executions>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<execution>
|
||||||
<version>2.3</version>
|
<id>reduced-pom</id>
|
||||||
<executions>
|
<phase>package</phase>
|
||||||
<execution>
|
<goals>
|
||||||
<phase>package</phase>
|
<goal>shade</goal>
|
||||||
<goals>
|
</goals>
|
||||||
<goal>shade</goal>
|
<configuration>
|
||||||
</goals>
|
<minimizeJar>false</minimizeJar>
|
||||||
<configuration>
|
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||||
<minimizeJar>false</minimizeJar>
|
<dependencyReducedPomLocation>
|
||||||
<createDependencyReducedPom>true</createDependencyReducedPom>
|
${java.io.tmpdir}/dependency-reduced-pom.xml
|
||||||
<dependencyReducedPomLocation>
|
</dependencyReducedPomLocation>
|
||||||
${java.io.tmpdir}/dependency-reduced-pom.xml
|
</configuration>
|
||||||
</dependencyReducedPomLocation>
|
</execution>
|
||||||
</configuration>
|
<execution>
|
||||||
</execution>
|
<id>process-resources</id>
|
||||||
</executions>
|
<phase>package</phase>
|
||||||
</plugin>
|
<goals>
|
||||||
<plugin>
|
<goal>shade</goal>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
</goals>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<configuration>
|
||||||
<version>2.3</version>
|
<transformers>
|
||||||
<executions>
|
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||||
<execution>
|
</transformers>
|
||||||
<phase>package</phase>
|
</configuration>
|
||||||
<goals>
|
</execution>
|
||||||
<goal>shade</goal>
|
</executions>
|
||||||
</goals>
|
</plugin>
|
||||||
<configuration>
|
</plugins>
|
||||||
<transformers>
|
</build>
|
||||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
|
||||||
</transformers>
|
<dependencies>
|
||||||
</configuration>
|
|
||||||
</execution>
|
<dependency>
|
||||||
</executions>
|
<groupId>com.wordnik</groupId>
|
||||||
</plugin>
|
<artifactId>swagger-codegen</artifactId>
|
||||||
</plugins>
|
<version>${project.version}</version>
|
||||||
</build>
|
</dependency>
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
<!--https://github.com/airlift/airline-->
|
||||||
<groupId>com.wordnik</groupId>
|
<dependency>
|
||||||
<artifactId>swagger-codegen</artifactId>
|
<groupId>io.airlift</groupId>
|
||||||
<version>${project.parent.version}</version>
|
<artifactId>airline</artifactId>
|
||||||
</dependency>
|
<version>0.7</version>
|
||||||
</dependencies>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.lambdaj</groupId>
|
||||||
|
<artifactId>lambdaj</artifactId>
|
||||||
|
<version>2.3.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
<version>${slf4j-version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.wordnik.swagger.codegen;
|
||||||
|
|
||||||
|
import com.wordnik.swagger.codegen.cmd.Generate;
|
||||||
|
import com.wordnik.swagger.codegen.cmd.Langs;
|
||||||
|
import com.wordnik.swagger.codegen.cmd.Meta;
|
||||||
|
import io.airlift.airline.Cli;
|
||||||
|
import io.airlift.airline.Help;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: lanwen
|
||||||
|
* Date: 24.03.15
|
||||||
|
* Time: 17:56
|
||||||
|
*/
|
||||||
|
public class SwaggerCodegen {
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Cli.CliBuilder<Runnable> builder = Cli.<Runnable>builder("swagger")
|
||||||
|
.withDescription("Swagger code generator CLI. More info on swagger.io")
|
||||||
|
.withDefaultCommand(Langs.class)
|
||||||
|
.withCommands(
|
||||||
|
Generate.class,
|
||||||
|
Meta.class,
|
||||||
|
Langs.class,
|
||||||
|
Help.class
|
||||||
|
);
|
||||||
|
|
||||||
|
builder.build().parse(args).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package com.wordnik.swagger.codegen.cmd;
|
||||||
|
|
||||||
|
import com.wordnik.swagger.codegen.ClientOptInput;
|
||||||
|
import com.wordnik.swagger.codegen.ClientOpts;
|
||||||
|
import com.wordnik.swagger.codegen.CodegenConfig;
|
||||||
|
import com.wordnik.swagger.codegen.DefaultGenerator;
|
||||||
|
import com.wordnik.swagger.models.Swagger;
|
||||||
|
import io.airlift.airline.Command;
|
||||||
|
import io.airlift.airline.Option;
|
||||||
|
import io.swagger.parser.SwaggerParser;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import static java.util.ServiceLoader.load;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: lanwen
|
||||||
|
* Date: 24.03.15
|
||||||
|
* Time: 20:22
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Command(name = "generate", description = "Generate code with chosen lang")
|
||||||
|
public class Generate implements Runnable {
|
||||||
|
|
||||||
|
public static final Logger LOG = LoggerFactory.getLogger(Generate.class);
|
||||||
|
|
||||||
|
public static final String TEMPLATE_DIR_PARAM = "templateDir";
|
||||||
|
|
||||||
|
@Option(name = {"-v", "--verbose"}, description = "verbose mode")
|
||||||
|
public boolean verbose;
|
||||||
|
|
||||||
|
@Option(name = {"-l", "--lang"}, title = "language", required = true,
|
||||||
|
description = "client language to generate (maybe class name in classpath, required)")
|
||||||
|
public String lang;
|
||||||
|
|
||||||
|
@Option(name = {"-o", "--output"}, title = "output directory",
|
||||||
|
description = "where to write the generated files (current dir by default)")
|
||||||
|
public String output = "";
|
||||||
|
|
||||||
|
@Option(name = {"-i", "--input-spec"}, title = "spec file", required = true,
|
||||||
|
description = "location of the swagger spec, as URL or file (required)")
|
||||||
|
public String spec;
|
||||||
|
|
||||||
|
@Option(name = {"-t", "--template-dir"}, title = "template directory",
|
||||||
|
description = "folder containing the template files")
|
||||||
|
public String templateDir;
|
||||||
|
|
||||||
|
@Option(name = {"-a", "--auth"}, title = "authorization",
|
||||||
|
description = "adds authorization headers when fetching the swagger definitions remotely. " +
|
||||||
|
"Pass in a URL-encoded string of name:header with a comma separating multiple values")
|
||||||
|
public String auth;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
verbosed(verbose);
|
||||||
|
|
||||||
|
ClientOptInput input = new ClientOptInput();
|
||||||
|
|
||||||
|
if (isNotEmpty(auth)) {
|
||||||
|
input.setAuth(auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
CodegenConfig config = forName(lang);
|
||||||
|
config.setOutputDir(new File(output).getAbsolutePath());
|
||||||
|
|
||||||
|
if (null != templateDir) {
|
||||||
|
config.additionalProperties().put(TEMPLATE_DIR_PARAM, new File(templateDir).getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
input.setConfig(config);
|
||||||
|
|
||||||
|
Swagger swagger = new SwaggerParser().read(spec, input.getAuthorizationValues(), true);
|
||||||
|
new DefaultGenerator().opts(input.opts(new ClientOpts()).swagger(swagger)).generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true parameter, adds system properties which enables debug mode in generator
|
||||||
|
* @param verbose - if true, enables debug mode
|
||||||
|
*/
|
||||||
|
private void verbosed(boolean verbose) {
|
||||||
|
if (!verbose) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG.info("\nVERBOSE MODE: ON. Additional debug options are injected" +
|
||||||
|
"\n - [debugSwagger] prints the swagger specification as interpreted by the codegen" +
|
||||||
|
"\n - [debugModels] prints models passed to the template engine" +
|
||||||
|
"\n - [debugOperations] prints operations passed to the template engine" +
|
||||||
|
"\n - [debugSupportingFiles] prints additional data passed to the template engine");
|
||||||
|
|
||||||
|
System.setProperty("debugSwagger", "");
|
||||||
|
System.setProperty("debugModels", "");
|
||||||
|
System.setProperty("debugOperations", "");
|
||||||
|
System.setProperty("debugSupportingFiles", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to load config class with SPI first, then with class name directly from classpath
|
||||||
|
* @param name name of config, or full qualified class name in classpath
|
||||||
|
* @return config class
|
||||||
|
*/
|
||||||
|
private static CodegenConfig forName(String name) {
|
||||||
|
ServiceLoader<CodegenConfig> loader = load(CodegenConfig.class);
|
||||||
|
for (CodegenConfig config : loader) {
|
||||||
|
if (config.getName().equals(name)) {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// else try to load directly
|
||||||
|
try {
|
||||||
|
return (CodegenConfig) Class.forName(name).newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Can't load config class with name ".concat(name), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.wordnik.swagger.codegen.cmd;
|
||||||
|
|
||||||
|
import ch.lambdaj.collection.LambdaIterable;
|
||||||
|
import com.wordnik.swagger.codegen.CodegenConfig;
|
||||||
|
import io.airlift.airline.Command;
|
||||||
|
|
||||||
|
import static ch.lambdaj.Lambda.on;
|
||||||
|
import static ch.lambdaj.collection.LambdaCollections.with;
|
||||||
|
import static java.util.ServiceLoader.load;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: lanwen
|
||||||
|
* Date: 24.03.15
|
||||||
|
* Time: 20:25
|
||||||
|
*/
|
||||||
|
@Command(name = "langs", description = "Shows available langs")
|
||||||
|
public class Langs implements Runnable {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
LambdaIterable<String> langs = with(load(CodegenConfig.class)).extract(on(CodegenConfig.class).getName());
|
||||||
|
System.out.printf("Available languages: %s%n", langs);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
package com.wordnik.swagger.codegen.cmd;
|
||||||
|
|
||||||
|
import ch.lambdaj.function.convert.Converter;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.samskivert.mustache.Mustache;
|
||||||
|
import com.wordnik.swagger.codegen.DefaultGenerator;
|
||||||
|
import com.wordnik.swagger.codegen.SupportingFile;
|
||||||
|
import io.airlift.airline.Command;
|
||||||
|
import io.airlift.airline.Option;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static ch.lambdaj.collection.LambdaCollections.with;
|
||||||
|
import static com.google.common.base.Joiner.on;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: lanwen
|
||||||
|
* Date: 24.03.15
|
||||||
|
* Time: 20:22
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Command(name = "meta", description = "MetaGenerator. Generator for creating a new template set " +
|
||||||
|
"and configuration for Codegen. The output will be based on the language you " +
|
||||||
|
"specify, and includes default templates to include.")
|
||||||
|
public class Meta implements Runnable {
|
||||||
|
|
||||||
|
public static final Logger LOG = LoggerFactory.getLogger(Meta.class);
|
||||||
|
|
||||||
|
public static final String TEMPLATE_DIR_CLASSPATH = "codegen";
|
||||||
|
public static final String MUSTACHE_EXTENSION = ".mustache";
|
||||||
|
|
||||||
|
@Option(name = {"-o", "--output"}, title = "output directory",
|
||||||
|
description = "where to write the generated files (current dir by default)")
|
||||||
|
public String outputFolder = "";
|
||||||
|
|
||||||
|
@Option(name = {"-n", "--name"}, title = "name",
|
||||||
|
description = "the human-readable name of the generator")
|
||||||
|
public String name = "default";
|
||||||
|
|
||||||
|
@Option(name = {"-p", "--package"}, title = "package",
|
||||||
|
description = "the package to put the main class into (defaults to com.wordnik.swagger.codegen)")
|
||||||
|
public String targetPackage = "com.wordnik.swagger.codegen";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
final File targetDir = new File(outputFolder);
|
||||||
|
LOG.info("writing to folder [{}]", targetDir.getAbsolutePath());
|
||||||
|
|
||||||
|
String mainClass = StringUtils.capitalize(name) + "Generator";
|
||||||
|
|
||||||
|
List<SupportingFile> supportingFiles = ImmutableList.of(
|
||||||
|
new SupportingFile("pom.mustache", "", "pom.xml"),
|
||||||
|
new SupportingFile("generatorClass.mustache",
|
||||||
|
on(File.separator).join("src/main/java", asPath(targetPackage)), mainClass.concat(".java")),
|
||||||
|
new SupportingFile("README.mustache", "", "README.md"),
|
||||||
|
new SupportingFile("api.template", "src/main/resources" + File.separator + name, "api.mustache"),
|
||||||
|
new SupportingFile("model.template", "src/main/resources" + File.separator + name, "model.mustache"),
|
||||||
|
new SupportingFile("services.mustache",
|
||||||
|
"src/main/resources/META-INF/services", "com.wordnik.swagger.codegen.CodegenConfig")
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, Object> data = new ImmutableMap.Builder<String, Object>()
|
||||||
|
.put("generatorPackage", targetPackage)
|
||||||
|
.put("generatorClass", mainClass)
|
||||||
|
.put("name", name)
|
||||||
|
.put("fullyQualifiedGeneratorClass", targetPackage + "." + mainClass).build();
|
||||||
|
|
||||||
|
|
||||||
|
with(supportingFiles).convert(processFiles(targetDir, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter method to process supporting files: execute with mustache,
|
||||||
|
* or simply copy to destination directory
|
||||||
|
* @param targetDir - destination directory
|
||||||
|
* @param data - map with additional params needed to process templates
|
||||||
|
* @return converter object to pass to lambdaj
|
||||||
|
*/
|
||||||
|
private Converter<SupportingFile, File> processFiles(final File targetDir, final Map<String, Object> data) {
|
||||||
|
return new Converter<SupportingFile, File>() {
|
||||||
|
private DefaultGenerator generator = new DefaultGenerator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File convert(SupportingFile support) {
|
||||||
|
try {
|
||||||
|
File destinationFolder = new File(new File(targetDir.getAbsolutePath()), support.folder);
|
||||||
|
File outputFile = new File(destinationFolder, support.destinationFilename);
|
||||||
|
|
||||||
|
String template = generator
|
||||||
|
.readTemplate(new File(TEMPLATE_DIR_CLASSPATH, support.templateFile).getPath());
|
||||||
|
String formatted = template;
|
||||||
|
|
||||||
|
if (support.templateFile.endsWith(MUSTACHE_EXTENSION)) {
|
||||||
|
LOG.info("writing file to {}", outputFile.getAbsolutePath());
|
||||||
|
formatted = Mustache.compiler().withLoader(loader(generator))
|
||||||
|
.defaultValue("")
|
||||||
|
.compile(template)
|
||||||
|
.execute(data);
|
||||||
|
} else {
|
||||||
|
LOG.info("copying file to {}", outputFile.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils.writeStringToFile(outputFile, formatted);
|
||||||
|
return outputFile;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Can't generate project", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates mustache loader for template using classpath loader
|
||||||
|
* @param generator - class with reader getter
|
||||||
|
* @return loader for template
|
||||||
|
*/
|
||||||
|
private Mustache.TemplateLoader loader(final DefaultGenerator generator) {
|
||||||
|
return new Mustache.TemplateLoader() {
|
||||||
|
public Reader getTemplate(String name) {
|
||||||
|
return generator.getTemplateReader(TEMPLATE_DIR_CLASSPATH
|
||||||
|
+ File.separator + name.concat(MUSTACHE_EXTENSION));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts package name to path on file system
|
||||||
|
* @param packageName - package name to convert
|
||||||
|
* @return relative path
|
||||||
|
*/
|
||||||
|
private String asPath(String packageName) {
|
||||||
|
return packageName.replace(".", File.separator);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user