提交 9bd67ac8 编写于 作者: sq3536's avatar sq3536

init

上级 cb92a3f6
*volumes
*target
.settings
*node_modules
*bin
*.project
*.classpath
*.factorypath
.history
.vscode
.idea
**.iml
*.jar
*.log
.DS_Store
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ibizlab-generator-project</artifactId>
<groupId>com.ibizlab</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ibizlab-generator-cli</artifactId>
<build>
<finalName>ibizlab-generator-cli</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<configLocation>${project.parent.basedir}${file.separator}google_checkstyle.xml</configLocation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>${maven-jar-plugin.version}</version>
<configuration>
<archive>
<manifest>
<mainClass>com.ibizlab.codegen.IbizLabGenerator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>process-resources</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<createDependencyReducedPom>true</createDependencyReducedPom>
<dependencyReducedPomLocation>
${java.io.tmpdir}/dependency-reduced-pom.xml
</dependencyReducedPomLocation>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--https://github.com/airlift/airline-->
<dependency>
<groupId>io.airlift</groupId>
<artifactId>airline</artifactId>
<version>0.8</version>
</dependency>
<dependency>
<groupId>com.googlecode.lambdaj</groupId>
<artifactId>lambdaj</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.ibizlab.codegen;
public class Constants {
private Constants(){ }
public static final String CLI_NAME = "ibizlab-generator-cli";
public static final String GIT_REPO = "https://github.com/ibiz4j/ibizlab-generator";
public static final String SITE = "https://www.ibizlab.cn/";
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen;
import io.airlift.airline.Cli;
import io.airlift.airline.ParseArgumentsUnexpectedException;
import io.airlift.airline.ParseOptionMissingException;
import io.airlift.airline.ParseOptionMissingValueException;
import com.ibizlab.codegen.cmd.*;
import java.util.Locale;
import static com.ibizlab.codegen.Constants.CLI_NAME;
/**
* User: lanwen Date: 24.03.15 Time: 17:56
* <p>
* Command line interface for OpenAPI Generator use `openapi-generator-cli.jar help` for more info
*/
public class IbizLabGenerator {
public static void main(String[] args) {
BuildInfo buildInfo = new BuildInfo();
Cli.CliBuilder<IbizLabGeneratorCommand> builder =
Cli.<IbizLabGeneratorCommand>builder(CLI_NAME)
.withDescription(
String.format(
Locale.ROOT,
"ibizLab Generator CLI %s (%s).",
buildInfo.getVersion(),
buildInfo.getSha()))
.withDefaultCommand(HelpCommand.class)
.withCommands(
Generate.class,
HelpCommand.class,
Version.class,
CompletionCommand.class
);
try {
builder.build().parse(args).run();
// If CLI runs without a command, consider this an error. This exists after initial parse/run
// so we can present the configured "default command".
// We can check against empty args because unrecognized arguments/commands result in an exception.
// This is useful to exit with status 1, for example, so that misconfigured scripts fail fast.
// We don't want the default command to exit internally with status 1 because when the default command is something like "list",
// it would prevent scripting using the command directly. Example:
// java -jar cli.jar list --short | tr ',' '\n' | xargs -I{} echo "Doing something with {}"
if (args.length == 0) {
System.exit(1);
}
} catch (ParseArgumentsUnexpectedException e) {
System.err.printf(Locale.ROOT, "[error] %s%n%nSee '%s help' for usage.%n", e.getMessage(), CLI_NAME);
System.exit(1);
} catch (ParseOptionMissingException | ParseOptionMissingValueException e) {
System.err.printf(Locale.ROOT, "[error] %s%n", e.getMessage());
System.exit(1);
}
}
}
package com.ibizlab.codegen.cmd;
import java.io.IOException;
import java.io.InputStream;
import java.time.DateTimeException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.Properties;
import static com.ibizlab.codegen.Constants.CLI_NAME;
import static com.ibizlab.codegen.Constants.GIT_REPO;
import static com.ibizlab.codegen.Constants.SITE;
/**
* Presents build-time information
*/
@SuppressWarnings({"java:S108"})
public class BuildInfo {
private static final String VERSION_PLACEHOLDER = "${project.version}";
private static final String UNSET = "unset";
private static final String UNKNOWN = "unknown";
private static final Properties properties = new Properties();
static {
try (InputStream is = BuildInfo.class.getResourceAsStream("/version.properties")) {
if (is != null) {
Properties versionProps = new Properties();
versionProps.load(is);
properties.putAll(versionProps);
}
} catch (IOException ignored) {
}
try (InputStream is = BuildInfo.class.getResourceAsStream("/openapi-generator-git.properties")) {
if (is != null) {
Properties gitProps = new Properties();
gitProps.load(is);
properties.putAll(gitProps);
}
} catch (IOException ignored) {
}
}
/**
* Gets the version of the toolset.
*
* @return A semver string
*/
public String getVersion() {
String version = (String) properties.getOrDefault("version", UNKNOWN);
if (VERSION_PLACEHOLDER.equals(version)) {
return UNSET;
} else {
return version;
}
}
/**
* Gets the git commit SHA1 hash. Useful for differentiating between SNAPSHOT builds.
*
* @return A short git SHA
*/
public String getSha() {
return (String) properties.getOrDefault("git.commit.id.abbrev", UNKNOWN);
}
/**
* Gets the time when this tool was built.
*
* @return The time as {@link OffsetDateTime}, or {@link OffsetDateTime#MIN} if metadata cannot be parsed.
*/
public OffsetDateTime getBuildTime() {
try {
String time = (String) properties.getOrDefault("git.build.time", "");
return OffsetDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ROOT));
} catch (DateTimeParseException e) {
return OffsetDateTime.MIN;
}
}
/**
* Gets the full version display text, as one would expect from a '--version' CLI option
*
* @return Human-readable version display information
*/
public String versionDisplayText() {
StringBuilder sb = new StringBuilder(CLI_NAME);
sb.append(" ").append(this.getVersion()).append(System.lineSeparator());
sb.append(" commit : ").append(this.getSha()).append(System.lineSeparator());
sb.append(" built : ");
try {
sb.append(this.getBuildTime().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
} catch (DateTimeException e) {
sb.append(UNKNOWN);
}
sb.append(System.lineSeparator());
sb.append(" source : ").append(GIT_REPO).append(System.lineSeparator());
sb.append(" docs : ").append(SITE).append(System.lineSeparator());
return sb.toString();
}
}
/*
* Copyright (C) 2010 the original author or authors.
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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.
*/
/*
* NOTICE: File originally taken from:
* https://github.com/airlift/airline/blob/fc7a55e34b6361cb97235de5a1b21cba9b508f4b/src/main/java/io/airlift/airline/SuggestCommand.java#L1
* Modifications have been made to fit the needs of OpenAPI Tools CLI.
*/
package com.ibizlab.codegen.cmd;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.airline.*;
import io.airlift.airline.model.*;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import static com.google.common.collect.Lists.newArrayList;
import static io.airlift.airline.ParserUtil.createInstance;
@SuppressWarnings({"java:S106"})
@Command(name = "completion", description = "Complete commands (for using in tooling such as Bash Completions).", hidden = true)
public class CompletionCommand extends IbizLabGeneratorCommand
implements Runnable, Callable<Void> {
private static final Map<Context, Class<? extends Suggester>> BUILTIN_SUGGESTERS = ImmutableMap.<Context, Class<? extends Suggester>>builder()
.put(Context.GLOBAL, GlobalSuggester.class)
.put(Context.GROUP, GroupSuggester.class)
.put(Context.COMMAND, CommandSuggester.class)
.build();
@Inject
public GlobalMetadata metadata;
@Arguments
public List<String> arguments = newArrayList();
@Override
public Void call() {
run();
return null;
}
@VisibleForTesting
public Iterable<String> generateSuggestions() {
Parser parser = new Parser();
ParseState state = parser.parse(metadata, arguments);
Class<? extends Suggester> suggesterClass = BUILTIN_SUGGESTERS.get(state.getLocation());
if (suggesterClass != null) {
SuggesterMetadata suggesterMetadata = MetadataLoader.loadSuggester(suggesterClass);
if (suggesterMetadata != null) {
ImmutableMap.Builder<Class<?>, Object> bindings = ImmutableMap.<Class<?>, Object>builder()
.put(GlobalMetadata.class, metadata);
if (state.getGroup() != null) {
bindings.put(CommandGroupMetadata.class, state.getGroup());
}
if (state.getCommand() != null) {
bindings.put(CommandMetadata.class, state.getCommand());
}
Suggester suggester = createInstance(suggesterMetadata.getSuggesterClass(),
ImmutableList.<OptionMetadata>of(),
null,
null,
null,
suggesterMetadata.getMetadataInjections(),
bindings.build(),
new DefaultCommandFactory<Suggester>());
return suggester.suggest();
}
}
return ImmutableList.of();
}
@Override
void execute() {
System.out.println(Joiner.on("\n").join(generateSuggestions()));
}
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.cmd;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.spi.FilterAttachable;
import com.ibizlab.codegen.*;
import com.ibizlab.codegen.config.CodegenConfigurator;
import com.ibizlab.codegen.config.CodegenConfiguratorUtils;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import static com.ibizlab.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvpList;
import static com.ibizlab.codegen.config.CodegenConfiguratorUtils.applyGlobalPropertiesKvpList;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@SuppressWarnings({"java:S106"})
@Command(name = "generate", description = "Generate code with the specified generator.")
public class Generate extends IbizLabGeneratorCommand {
CodegenConfigurator configurator;
Generator generator;
@Option(name = {"-o", "--output"}, title = "output directory",
description = "where to write the generated files (current dir by default)")
private String output = "";
@Option(name = {"-i", "--input-spec"}, title = "spec file",
description = "location of the OpenAPI spec, as URL or file (required if not loaded via config using -c)")
private String spec;
@Option(name = {"-t", "--template-dir"}, title = "template directory",
description = "folder containing the template files")
private String templateDir;
@Option(
name = {"-a", "--auth"},
title = "authorization",
description = "adds authorization headers when fetching the OpenAPI definitions remotely. "
+ "Pass in a URL-encoded string of name:header with a comma separating multiple values")
private String auth;
@Option(
name = {"--global-property"},
title = "global properties",
description = "sets specified global properties (previously called 'system properties') in "
+ "the format of name=value,name=value (or multiple options, each with name=value)")
private List<String> globalProperties = new ArrayList<>();
@Option(
name = {"-c", "--config"},
title = "configuration file",
description = "Path to configuration file. It can be JSON or YAML. "
+ "If file is JSON, the content should have the format {\"optionKey\":\"optionValue\", \"optionKey1\":\"optionValue1\"...}. "
+ "If file is YAML, the content should have the format optionKey: optionValue. "
+ "Supported options can be different for each language. Run config-help -g {generator name} command for language-specific config options.")
private String configFile;
@Option(name = {"-n","--project-name","--system-name"}, title = "package name",
description = CodegenConstants.PROJECT_NAME)
private String name;
@Option(name = {"--package-name"}, title = "package name",
description = CodegenConstants.PACKAGE_NAME_DESC)
private String packageName;
@Option(
name = {"-p", "--additional-properties"},
title = "additional properties",
description = "sets additional properties that can be referenced by the mustache templates in the format of name=value,name=value."
+ " You can also have multiple occurrences of this option.")
private List<String> additionalProperties = new ArrayList<>();
@Option(name = {"--git-host"}, title = "git host",
description = CodegenConstants.GIT_HOST_DESC)
private String gitHost;
@Option(name = {"--git-user-id"}, title = "git user id",
description = CodegenConstants.GIT_USER_ID_DESC)
private String gitUserId;
@Option(name = {"--git-repo-id"}, title = "git repo id",
description = CodegenConstants.GIT_REPO_ID_DESC)
private String gitRepoId;
@Option(name = {"--release-note"}, title = "release note",
description = CodegenConstants.RELEASE_NOTE_DESC)
private String releaseNote;
@Option(name = {"--http-user-agent"}, title = "http user agent",
description = CodegenConstants.HTTP_USER_AGENT_DESC)
private String httpUserAgent;
@Override
public void execute() {
// this initial check allows for field-level package private injection (for unit testing)
if (configurator == null) {
if (configFile != null && configFile.length() > 0) {
// attempt to load from configFile
configurator = CodegenConfigurator.fromFile(configFile);
} else if (StringUtils.isEmpty(spec)) {
// if user doesn't pass configFile and does not pass spec, we can fail immediately because one of these two is required to run.
System.err.println("[error] Required option '-i' is missing");
System.exit(1);
}
// if a config file wasn't specified, or we were unable to read it
if (configurator == null) {
// create a fresh configurator
configurator = new CodegenConfigurator();
}
}
if (isNotEmpty(spec)) {
if (!spec.matches("^http(s)?://.*") && !new File(spec).exists()) {
System.err.println("[error] The spec file is not found: " + spec);
System.err.println("[error] Check the path of the OpenAPI spec and try again.");
System.exit(1);
}
configurator.setInputSpec(spec);
}
if (isNotEmpty(output)) {
configurator.setOutputDir(output);
}
if (isNotEmpty(auth)) {
configurator.setAuth(auth);
}
if (isNotEmpty(templateDir)) {
configurator.setTemplateDir(templateDir);
}
if (isNotEmpty(packageName)) {
configurator.setPackageName(packageName);
}
if (isNotEmpty(name)) {
configurator.setProjectName(name);
}
if (isNotEmpty(gitHost)) {
configurator.setGitHost(gitHost);
}
if (isNotEmpty(gitUserId)) {
configurator.setGitUserId(gitUserId);
}
if (isNotEmpty(gitRepoId)) {
configurator.setGitRepoId(gitRepoId);
}
if (isNotEmpty(releaseNote)) {
configurator.setReleaseNote(releaseNote);
}
if (isNotEmpty(httpUserAgent)) {
configurator.setHttpUserAgent(httpUserAgent);
}
if (globalProperties != null && !globalProperties.isEmpty()) {
applyGlobalPropertiesKvpList(globalProperties, configurator);
}
applyAdditionalPropertiesKvpList(additionalProperties, configurator);
try {
final ClientOptInput clientOptInput = configurator.toClientOptInput();
// this null check allows us to inject for unit testing.
if (generator == null) {
generator = new DefaultGenerator(false);
}
generator.opts(clientOptInput);
generator.generate();
} catch (GeneratorNotFoundException e) {
System.err.println(e.getMessage());
System.err.println("[error] Check the spelling of the generator's name and try again.");
System.exit(1);
}
}
}
package com.ibizlab.codegen.cmd;
import io.airlift.airline.Option;
import static io.airlift.airline.OptionType.GLOBAL;
public class GlobalOptions {
@Option(type = GLOBAL, name = "--version", description = "Display full version output", hidden = true)
public boolean version;
@Option(type = GLOBAL, name = "--help", description = "Display help about the tool", hidden = true)
public boolean help;
}
package com.ibizlab.codegen.cmd;
import io.airlift.airline.Command;
import io.airlift.airline.Help;
import javax.inject.Inject;
@Command(name = "help", description = "Display help information about openapi-generator")
public class HelpCommand extends IbizLabGeneratorCommand {
@Inject
public Help help;
@Override
public void execute() {
help.call();
}
}
package com.ibizlab.codegen.cmd;
import io.airlift.airline.Help;
import io.airlift.airline.model.GlobalMetadata;
import javax.inject.Inject;
@SuppressWarnings({"java:S106"})
public abstract class IbizLabGeneratorCommand implements Runnable {
@Inject
public GlobalOptions globalOptions = new GlobalOptions();
@Inject
public GlobalMetadata global;
protected BuildInfo buildInfo = new BuildInfo();
@Override
public void run() {
if (globalOptions.version) {
System.out.println(buildInfo.versionDisplayText());
return;
}
if (globalOptions.help) {
Help help = new Help();
help.global = global;
help.call();
return;
}
execute();
}
/**
* Logic to be executed by implementing commands
*/
abstract void execute();
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.cmd;
import io.airlift.airline.Command;
import io.airlift.airline.Option;
@SuppressWarnings({"unused", "java:S106"})
@Command(name = "version", description = "Show version information used in tooling")
public class Version extends IbizLabGeneratorCommand {
@Option(name = {"--sha"}, description = "Git commit SHA version")
private Boolean sha;
@Option(name = {"--full"}, description = "Full version details")
private Boolean full;
@Override
public void execute() {
String version;
if (Boolean.TRUE.equals(full)) {
version = buildInfo.versionDisplayText();
} else if (Boolean.TRUE.equals(sha)) {
version = buildInfo.getSha();
} else {
version = buildInfo.getVersion();
}
System.out.println(version);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ibizlab-generator-project</artifactId>
<groupId>com.ibizlab</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator-core</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.github.joschi.jackson</groupId>
<artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp.version}</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>${swagger-core.version}</version>
</dependency>
<dependency>
<groupId>${swagger-parser-groupid.version}</groupId>
<artifactId>swagger-parser</artifactId>
<version>${swagger-parser.version}</version>
</dependency>
<dependency>
<groupId>com.samskivert</groupId>
<artifactId>jmustache</artifactId>
<version>${jmustache.version}</version>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>${handlebars-java.version}</version>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars-jackson2</artifactId>
<version>${handlebars-java.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-ext</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>${commons-cli.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.github.spullara.mustache.java</groupId>
<artifactId>compiler</artifactId>
<version>0.9.10</version>
</dependency>
<dependency>
<groupId>com.atlassian.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.11.0</version>
</dependency>
<dependency>
<groupId>com.github.mifmif</groupId>
<artifactId>generex</artifactId>
<version>${generex.version}</version>
</dependency>
<dependency>
<groupId>com.github.curious-odd-man</groupId>
<artifactId>rgxgen</artifactId>
<version>${rxgen.version}</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>net.ibizsys.model</groupId>
<artifactId>ibizlab-model</artifactId>
<version>1.2.9</version>
<exclusions>
<exclusion>
<artifactId>slf4j-simple</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.ibizlab.codegen.api;
import java.util.Locale;
public abstract class AbstractTemplatingEngineAdapter implements TemplatingEngineAdapter {
/**
* Gets all possible template paths for a given location.
*
* @param location The full location of the template.
*
* @return A new array of locations, modified according to the extensions or other adapter rules.
*/
protected String[] getModifiedFileLocation(String location) {
String[] extensions = getFileExtensions();
String[] result = new String[extensions.length];
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
result[i] = String.format(Locale.ROOT, "%s.%s", getPathWithoutExtension(location), extension);
}
return result;
}
/**
* Returns the path without an extension for an input location.
*
* @param location The location of the file, with original file extension intact.
*
* @return The full path, without extension (e.g. /path/to/file.txt => /path/to/file)
*/
private String getPathWithoutExtension(String location) {
if (location == null) return null;
int idx = location.lastIndexOf('.');
if (idx == -1) return location;
return location.substring(0, idx);
}
}
package com.ibizlab.codegen.api;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.Objects;
import java.util.StringJoiner;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class TemplateDefinition {
private String templateFile;
private String folder;
private String destinationFilename;
protected TemplateFileType templateType;
public TemplateDefinition(String templateFile, String folder, String destinationFilename) {
if (templateFile == null) throw new IllegalArgumentException("templateFile may not be null.");
if (folder == null) throw new IllegalArgumentException("folder may not be null.");
if (destinationFilename == null) throw new IllegalArgumentException("destinationFilename may not be null.");
this.templateFile = templateFile;
this.folder = folder;
this.destinationFilename = destinationFilename;
this.templateType = TemplateFileType.SupportingFiles;
}
}
package com.ibizlab.codegen.api;
import java.util.StringJoiner;
public enum TemplateFileType {
API(Constants.APIS),
Model(Constants.MODELS),
APIDocs(Constants.API_DOCS),
ModelDocs(Constants.MODEL_DOCS),
APITests(Constants.API_TESTS),
ModelTests(Constants.MODEL_TESTS),
SupportingFiles(Constants.SUPPORTING_FILES);
private final String templateType;
TemplateFileType(String templateType) { this.templateType = templateType; }
/**
* Returns the value for this template file type
*
* @return The template type of this enum.
*/
public String value() { return this.templateType; }
/** {@inheritDoc} */
@Override
public String toString() {
return new StringJoiner(", ", TemplateFileType.class.getSimpleName() + "[", "]")
.add("templateType='" + templateType + "'")
.toString();
}
/**
* Obtains the {@link TemplateFileType} for an input string.
*
* @param templateType a {@link String} object.
* @return a {@link TemplateFileType} object.
*/
public static TemplateFileType forTemplateType(String templateType) {
for (TemplateFileType value : values()) {
if (value.templateType.equals(templateType)) {
return value;
}
}
throw new IllegalArgumentException("templateType not found in the available values.");
}
public static class Constants {
public static final String APIS = "apis";
public static final String MODELS = "models";
public static final String SUPPORTING_FILES = "supportingFiles";
public static final String MODEL_TESTS = "modelTests";
public static final String MODEL_DOCS = "modelDocs";
public static final String API_TESTS = "apiTests";
public static final String API_DOCS = "apiDocs";
}
}
package com.ibizlab.codegen.api;
/**
* Provides means for searching for "actual" template location based on relative template file.
*/
public interface TemplatePathLocator {
/**
* Get the full path to a relative template file.
*
* @param relativeTemplateFile Template file
* @return String Full template file path
*/
String getFullTemplatePath(String relativeTemplateFile);
}
package com.ibizlab.codegen.api;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Map;
/**
* Interface for abstractions around writing templated data to a file.
*/
public interface TemplateProcessor {
/**
* Writes data to a compiled template
*
* @param data Input data
* @param template Input template location
* @param target The targeted file output location
*
* @return The actual file
* @throws IOException If file cannot be written.
*/
File write(Map<String, Object> data, String template, File target) throws IOException;
/**
* Write bytes to a file
*
* @param filename The name of file to write
* @param contents The contents bytes. Typically this is a UTF-8 formatted string.
* @return File representing the written file.
* @throws IOException If file cannot be written.
*/
File writeToFile(String filename, byte[] contents) throws IOException;
/**
* Allow a caller to mark a path as ignored with accompanying reason
*
* @param path The ignored path
* @param context The reason for ignoring this path
*/
void ignore(Path path, String context);
/**
* Allow a caller to mark a path as skipped with accompanying reason
*
* @param path The skipped path
* @param context The reason for skipping this path
*/
void skip(Path path, String context);
/**
* Allow a caller to mark a path having errored during processing with accompanying reason
*
* @param path The path which has caused an error
* @param context The reason for the error
*/
default void error(Path path, String context) { }
}
/*
* Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.api;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
/**
* Each templating engine is called by an Adapter, selected at runtime
*/
public interface TemplatingEngineAdapter {
/**
* Provides an identifier used to load the adapter. This could be a name, uuid, or any other string.
*
* @return A string identifier.
*/
String getIdentifier();
/**
* During generation, if a supporting file has a file extension that is
* inside that array, then it is considered a templated supporting file
* and we use the templating engine adapter to generate it
*
* @return string array of the valid file extensions for this templating engine
*/
String[] getFileExtensions();
/**
* Determine if the adapter handles compilation of the file
* @param filename The template filename
*
* @return True if the file should be compiled by this adapter, else false.
*/
default boolean handlesFile(String filename) {
return filename != null && filename.length() > 0 && Arrays.stream(getFileExtensions()).anyMatch(i -> filename.endsWith("." + i));
}
/**
* Compiles a template into a string
*
* @param executor From where we can fetch the templates content (e.g. an instance of DefaultGenerator)
* @param bundle The map of values to pass to the template
* @param templateFile The name of the template (e.g. model.mustache )
* @return the processed template result
* @throws IOException an error occurred in the template processing
*/
String compileTemplate(TemplatingExecutor executor, Map<String, Object> bundle,
String templateFile) throws IOException;
/**
* Determines whether the template file with supported extensions exists. This may be on the filesystem,
* external filesystem, or classpath (implementation is up to TemplatingGenerator).
*
* @param generator The generator holding details about file resolution
* @param templateFile The original target filename
* @return True if the template is available in the template search path, false if it can not be found
*/
@SuppressWarnings({"java:S2093"}) // ignore java:S2093 because we have double-assignment to the closeable
default boolean templateExists(TemplatingExecutor generator, String templateFile) {
return Arrays.stream(getFileExtensions()).anyMatch(ext -> {
int idx = templateFile.lastIndexOf('.');
String baseName;
if (idx > 0 && idx < templateFile.length() - 1) {
baseName = templateFile.substring(0, idx);
} else {
baseName = templateFile;
}
Path path = generator.getFullTemplatePath(String.format(Locale.ROOT, "%s.%s", baseName, ext));
InputStream is = null;
try {
String resourcePath = System.getProperty("os.name").startsWith("Windows") ?
path.toString().replace("\\", "/") :
path.toString();
is = this.getClass().getClassLoader().getResourceAsStream(resourcePath);
if (is == null) {
is = new FileInputStream(path.toFile());
}
return is.available() > 0;
} catch (IOException e) {
// ignore
} finally {
try {
if (is != null) is.close();
} catch (IOException e) {
// ignore
}
}
return false;
});
}
}
package com.ibizlab.codegen.api;
import java.nio.file.Path;
/**
* interface to the full template content
* implementers might take into account the -t cli option,
* look in the resources for a generator specific template, etc
*/
public interface TemplatingExecutor {
/**
* returns the template content by name
*
* @param name the template name (e.g. model.mustache)
* @return the contents of that template
*/
String getFullTemplateContents(String name);
/**
* Returns the path of a template, allowing access to the template where consuming literal contents aren't desirable or possible.
*
* @param name the template name (e.g. model.mustache)
* @return The {@link Path} to the template
*/
Path getFullTemplatePath(String name);
}
\ No newline at end of file
/*
* Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.config;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class Context<TSpecDocument> {
private TSpecDocument specDocument;
private GeneratorSettings generatorSettings;
public static void main(String[] args) throws IOException {
HashMap<String, Object> scopes = new HashMap<String, Object>();
scopes.put("name", "Mustache");
GeneratorSettings generatorSettings=new GeneratorSettings().setGitHost("host");
generatorSettings.getAdditionalProperties().put("sub",new GeneratorSettings().setGitHost("son"));
scopes.put("feature",generatorSettings );
List<String> list=new ArrayList<>();
list.add("a");
list.add("b");
scopes.put("list",list);
Writer writer = new OutputStreamWriter(System.out);
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(new StringReader("{{name}}, {{#list}}{{.}}{{/list}}!"), "example");
mustache.execute(writer, scopes);
writer.flush();
}
}
package com.ibizlab.codegen.config;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class GeneratorSettings implements Serializable {
private static final Logger LOGGER = LoggerFactory.getLogger(GeneratorSettings.class);
private static final String DEFAULT_GIT_HOST = "github.com";
private static final String DEFAULT_GIT_USER_ID = "GIT_USER_ID";
private static final String DEFAULT_GIT_REPO_ID = "GIT_REPO_ID";
private static final String DEFAULT_RELEASE_NOTE = "Minor update";
private String projectName;
private String packageName;
private Map<String, Object> additionalProperties = new LinkedHashMap<>();
private String gitHost;
private String gitUserId;
private String gitRepoId;
private String releaseNote;
private String httpUserAgent;
private Map<String, String> typeMappings;
public String getHost()
{
return gitHost+"abc";
}
private GeneratorSettings(Builder builder) {
projectName = builder.projectName;
packageName = builder.packageName;
typeMappings = Collections.unmodifiableMap(builder.typeMappings);
gitHost = builder.gitHost;
gitUserId = builder.gitUserId;
gitRepoId = builder.gitRepoId;
releaseNote = builder.releaseNote;
httpUserAgent = builder.httpUserAgent;
Map<String, Object> additional = new HashMap<>(builder.additionalProperties);
additionalProperties = Collections.unmodifiableMap(additional);
}
public static Builder newBuilder(GeneratorSettings copy) {
Builder builder = new Builder();
builder.projectName = copy.projectName;
builder.packageName = copy.packageName;
builder.typeMappings = Collections.unmodifiableMap(copy.typeMappings);
builder.gitHost = copy.gitHost;
builder.gitUserId = copy.gitUserId;
builder.gitRepoId = copy.gitRepoId;
builder.releaseNote = copy.releaseNote;
builder.httpUserAgent = copy.httpUserAgent;
Map<String, Object> additional = new HashMap<>(copy.additionalProperties);
builder.additionalProperties = Collections.unmodifiableMap(additional);
return builder;
}
public static final class Builder {
private String projectName;
private String packageName;
private String gitHost;
private String gitUserId;
private String gitRepoId;
private String releaseNote;
private String httpUserAgent;
private Map<String, String> typeMappings;
private Map<String, Object> additionalProperties;
/**
* Instantiates a new Builder.
*/
public Builder() {
typeMappings = new HashMap<>();
additionalProperties = new HashMap<>();
gitHost = DEFAULT_GIT_HOST;
gitUserId = DEFAULT_GIT_USER_ID;
gitRepoId = DEFAULT_GIT_REPO_ID;
releaseNote = DEFAULT_RELEASE_NOTE;
}
public Builder withProjectName(String projectName) {
this.projectName = projectName;
return this;
}
/**
* Sets the {@code packageName} and returns a reference to this Builder so that the methods can be chained together.
*
* @param packageName the {@code packageName} to set
* @return a reference to this Builder
*/
public Builder withPackageName(String packageName) {
this.packageName = packageName;
return this;
}
/**
* Sets the {@code typeMappings} and returns a reference to this Builder so that the methods can be chained together.
*
* @param typeMappings the {@code typeMappings} to set
* @return a reference to this Builder
*/
public Builder withTypeMappings(Map<String, String> typeMappings) {
this.typeMappings = typeMappings;
return this;
}
public Builder withTypeMapping(String key, String value) {
if (this.typeMappings == null) {
this.typeMappings = new HashMap<>();
}
this.typeMappings.put(key, value);
return this;
}
/**
* Sets the {@code additionalProperties} and returns a reference to this Builder so that the methods can be chained together.
*
* @param additionalProperties the {@code additionalProperties} to set
* @return a reference to this Builder
*/
public Builder withAdditionalProperties(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
return this;
}
/**
* Sets the {@code additionalProperties} and returns a reference to this Builder so that the methods can be chained together.
*
* @param key A key for some additional property
* @param value The value of some additional property
* @return a reference to this Builder
*/
public Builder withAdditionalProperty(String key, Object value) {
if (this.additionalProperties == null) {
this.additionalProperties = new HashMap<>();
}
this.additionalProperties.put(key, value);
return this;
}
/**
* Sets the {@code gitHost} and returns a reference to this Builder so that the methods can be chained together.
*
* @param gitHost the {@code gitHost} to set
* @return a reference to this Builder
*/
public Builder withGitHost(String gitHost) {
this.gitHost = gitHost;
return this;
}
/**
* Sets the {@code gitUserId} and returns a reference to this Builder so that the methods can be chained together.
*
* @param gitUserId the {@code gitUserId} to set
* @return a reference to this Builder
*/
public Builder withGitUserId(String gitUserId) {
this.gitUserId = gitUserId;
return this;
}
/**
* Sets the {@code gitRepoId} and returns a reference to this Builder so that the methods can be chained together.
*
* @param gitRepoId the {@code gitRepoId} to set
* @return a reference to this Builder
*/
public Builder withGitRepoId(String gitRepoId) {
this.gitRepoId = gitRepoId;
return this;
}
/**
* Sets the {@code releaseNote} and returns a reference to this Builder so that the methods can be chained together.
*
* @param releaseNote the {@code releaseNote} to set
* @return a reference to this Builder
*/
public Builder withReleaseNote(String releaseNote) {
this.releaseNote = releaseNote;
return this;
}
/**
* Sets the {@code httpUserAgent} and returns a reference to this Builder so that the methods can be chained together.
*
* @param httpUserAgent the {@code httpUserAgent} to set
* @return a reference to this Builder
*/
public Builder withHttpUserAgent(String httpUserAgent) {
this.httpUserAgent = httpUserAgent;
return this;
}
/**
* Returns a {@code GeneratorSettings} built from the parameters previously set.
*
* @return a {@code GeneratorSettings} built with parameters of this {@code GeneratorSettings.Builder}
*/
public GeneratorSettings build() {
GeneratorSettings instance = new GeneratorSettings(this);
//noinspection PlaceholderCountMatchesArgumentCount
LOGGER.debug("GeneratorSettings#build: %s", instance.toString());
return instance;
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ibizlab-generator-project</artifactId>
<groupId>com.ibizlab</groupId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ibizlab-generator</name>
<dependencies>
<dependency>
<groupId>com.ibizlab</groupId>
<artifactId>ibizlab-generator-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import java.util.LinkedHashMap;
import java.util.Map;
public class CliOption {
private final String opt;
private String description;
private String type;
private String defaultValue;
private String optValue;
private Map<String, String> enumValues;
public CliOption(String opt, String description) {
this(opt, description, SchemaTypeUtil.STRING_TYPE);
}
public CliOption(String opt, String description, String type) {
this.opt = opt;
this.description = description;
this.type = type;
}
public String getOpt() {
return opt;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDefault() {
return defaultValue;
}
public void setDefault(String defaultValue) {
this.defaultValue = defaultValue;
}
public CliOption defaultValue(String defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public String getOptValue() {
return this.optValue;
}
public void setOptValue(String optValue) {
if (this.enumValues!=null && this.enumValues.containsKey(optValue)) {
this.optValue = optValue;
} else {
this.optValue = null;
}
}
public CliOption addEnum(String value, String description) {
if (this.enumValues == null) {
this.enumValues = new LinkedHashMap<String, String>();
}
if (!enumValues.containsKey(value)) {
enumValues.put(value, description);
}
return this;
}
public Map<String, String> getEnum() {
return enumValues;
}
public void setEnum(Map<String, String> enumValues) {
this.enumValues = enumValues;
}
/**
* Create new boolean command line option with a default of false
*
* @param opt Option name
* @param description Option description
* @return the CliOption created
*/
public static CliOption newBoolean(String opt, String description) {
return newBoolean(opt, description, false);
}
/**
* Create new boolean command line option with the provided value as default
*
* @param opt Option name
* @param description Option description
* @param defaultValue the default value to use if option not specified
* @return the CliOption created
*/
public static CliOption newBoolean(String opt, String description, boolean defaultValue) {
return new CliOption(opt, description, SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(String.valueOf(defaultValue));
}
public static CliOption newString(String opt, String description) {
return new CliOption(opt, description, SchemaTypeUtil.STRING_TYPE);
}
@JsonIgnore
public String getOptionHelp() {
StringBuilder sb = new StringBuilder(description);
if(defaultValue != null) {
sb.append(" (Default: ").append(defaultValue).append(")");
}
if (enumValues != null) {
for (Map.Entry<String, String> entry : enumValues.entrySet()) {
sb.append("\n ").append(entry.getKey()).append(" - ").append(entry.getValue());
}
}
return sb.toString();
}
}
package com.ibizlab.codegen;
import com.ibizlab.codegen.api.TemplateDefinition;
import io.swagger.v3.parser.core.models.AuthorizationValue;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class ClientOptInput {
private CodegenConfig config;
private List<TemplateDefinition> userDefinedTemplates;
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
import com.google.common.base.CaseFormat;
import com.google.common.collect.ImmutableMap;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import com.ibizlab.codegen.config.GeneratorSettings;
import com.ibizlab.codegen.config.GlobalSettings;
import com.ibizlab.codegen.templating.MustacheEngineAdapter;
import com.ibizlab.codegen.templating.mustache.*;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Mustache.Compiler;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.callbacks.Callback;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.*;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.servers.ServerVariable;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.ibizlab.codegen.utils.StringAdvUtils.*;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class CodegenConfig {
private final Logger LOGGER = LoggerFactory.getLogger(CodegenConfig.class);
private String inputSpec;
private String outputDir;
private String templateDir;
private String auth;
private Map<String, Object> additionalProperties = new HashMap<>();
private Map<String, String> typeMappings;
private TemplatingEngineAdapter templatingEngine;
@SuppressWarnings("static-method")
public String sanitizeName(String name) {
return sanitizeName(name, "\\W");
}
private static Cache<SanitizeNameOptions, String> sanitizedNameCache;
static {
int cacheSize = Integer.parseInt(GlobalSettings.getProperty(NAME_CACHE_SIZE_PROPERTY, "500"));
int cacheExpiry = Integer.parseInt(GlobalSettings.getProperty(NAME_CACHE_EXPIRY_PROPERTY, "10"));
sanitizedNameCache = Caffeine.newBuilder()
.maximumSize(cacheSize)
.expireAfterAccess(cacheExpiry, TimeUnit.SECONDS)
.ticker(Ticker.systemTicker())
.build();
}
/**
* Sanitize name (parameter, property, method, etc)
*
* @param name string to be sanitize
* @param removeCharRegEx a regex containing all char that will be removed
* @return sanitized string
*/
public String sanitizeName(String name, String removeCharRegEx) {
return sanitizeName(name, removeCharRegEx, new ArrayList<>());
}
/**
* Sanitize name (parameter, property, method, etc)
*
* @param name string to be sanitize
* @param removeCharRegEx a regex containing all char that will be removed
* @param exceptionList a list of matches which should not be sanitized (i.e exception)
* @return sanitized string
*/
@SuppressWarnings("static-method")
public String sanitizeName(final String name, String removeCharRegEx, ArrayList<String> exceptionList) {
// NOTE: performance wise, we should have written with 2 replaceAll to replace desired
// character with _ or empty character. Below aims to spell out different cases we've
// encountered so far and hopefully make it easier for others to add more special
// cases in the future.
// better error handling when map/array type is invalid
if (name == null) {
LOGGER.error("String to be sanitized is null. Default to ERROR_UNKNOWN");
return "ERROR_UNKNOWN";
}
// if the name is just '$', map it to 'value' for the time being.
if ("$".equals(name)) {
return "value";
}
SanitizeNameOptions opts = new SanitizeNameOptions(name, removeCharRegEx, exceptionList);
return sanitizedNameCache.get(opts, sanitizeNameOptions -> {
String modifiable = sanitizeNameOptions.getName();
List<String> exceptions = sanitizeNameOptions.getExceptions();
// input[] => input
modifiable = this.sanitizeValue(modifiable, "\\[\\]", "", exceptions);
// input[a][b] => input_a_b
modifiable = this.sanitizeValue(modifiable, "\\[", "_", exceptions);
modifiable = this.sanitizeValue(modifiable, "\\]", "", exceptions);
// input(a)(b) => input_a_b
modifiable = this.sanitizeValue(modifiable, "\\(", "_", exceptions);
modifiable = this.sanitizeValue(modifiable, "\\)", "", exceptions);
// input.name => input_name
modifiable = this.sanitizeValue(modifiable, "\\.", "_", exceptions);
// input-name => input_name
modifiable = this.sanitizeValue(modifiable, "-", "_", exceptions);
// a|b => a_b
modifiable = this.sanitizeValue(modifiable, "\\|", "_", exceptions);
// input name and age => input_name_and_age
modifiable = this.sanitizeValue(modifiable, " ", "_", exceptions);
// /api/films/get => _api_films_get
// \api\films\get => _api_films_get
modifiable = modifiable.replaceAll("/", "_");
modifiable = modifiable.replaceAll("\\\\", "_");
// remove everything else other than word, number and _
// $php_variable => php_variable
modifiable = modifiable.replaceAll(sanitizeNameOptions.getRemoveCharRegEx(), "");
return modifiable;
});
}
private String sanitizeValue(String value, String replaceMatch, String replaceValue, List<String> exceptionList) {
if (exceptionList.size() == 0 || !exceptionList.contains(replaceMatch)) {
return value.replaceAll(replaceMatch, replaceValue);
}
return value;
}
/**
* Sanitize tag
*
* @param tag Tag
* @return Sanitized tag
*/
public String sanitizeTag(String tag) {
tag = camelize(sanitizeName(tag));
// tag starts with numbers
if (tag.matches("^\\d.*")) {
tag = "Class" + tag;
}
return tag;
}
private static class SanitizeNameOptions {
public SanitizeNameOptions(String name, String removeCharRegEx, List<String> exceptions) {
this.name = name;
this.removeCharRegEx = removeCharRegEx;
if (exceptions != null) {
this.exceptions = Collections.unmodifiableList(exceptions);
} else {
this.exceptions = Collections.emptyList();
}
}
public String getName() {
return name;
}
public String getRemoveCharRegEx() {
return removeCharRegEx;
}
public List<String> getExceptions() {
return exceptions;
}
private String name;
private String removeCharRegEx;
private List<String> exceptions;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SanitizeNameOptions that = (SanitizeNameOptions) o;
return Objects.equals(getName(), that.getName()) &&
Objects.equals(getRemoveCharRegEx(), that.getRemoveCharRegEx()) &&
Objects.equals(getExceptions(), that.getExceptions());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getRemoveCharRegEx(), getExceptions());
}
}
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
public class CodegenConfigLoader {
/**
* 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
*/
public static CodegenConfig forName(String name) {
ServiceLoader<CodegenConfig> loader = ServiceLoader.load(CodegenConfig.class, CodegenConfig.class.getClassLoader());
StringBuilder availableConfigs = new StringBuilder();
for (CodegenConfig config : loader) {
if (config.getName().equals(name)) {
return config;
}
availableConfigs.append(config.getName()).append("\n");
}
// else try to load directly
try {
return (CodegenConfig) Class.forName(name).getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new GeneratorNotFoundException("Can't load config class with name '".concat(name) + "'\nAvailable:\n" + availableConfigs, e);
}
}
public static List<CodegenConfig> getAll() {
ServiceLoader<CodegenConfig> loader = ServiceLoader.load(CodegenConfig.class, CodegenConfig.class.getClassLoader());
List<CodegenConfig> output = new ArrayList<CodegenConfig>();
for (CodegenConfig aLoader : loader) {
output.add(aLoader);
}
return output;
}
}
package com.ibizlab.codegen;
import java.io.File;
import java.util.List;
public interface Generator {
Generator opts(ClientOptInput opts);
List<File> generate();
}
\ No newline at end of file
package com.ibizlab.codegen;
/**
* Typed exception exposing issues with loading generators (e.g. by name).
*/
@SuppressWarnings("unused")
public class GeneratorNotFoundException extends RuntimeException {
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public GeneratorNotFoundException() {
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public GeneratorNotFoundException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <code>null</code> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public GeneratorNotFoundException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of <code>(cause==null ? null : cause.toString())</code>
* (which typically contains the class and detail message of
* <code>cause</code>). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <code>null</code> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public GeneratorNotFoundException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
public GeneratorNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/*
* Copyright 2019 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import java.util.Locale;
import java.util.ServiceLoader;
public class TemplatingEngineLoader {
private TemplatingEngineLoader() {
throw new IllegalStateException("Utility class");
}
@SuppressWarnings("java:S112") // ignore java:S112 as generic RuntimeException is acceptable here
public static TemplatingEngineAdapter byIdentifier(String id) {
ServiceLoader<TemplatingEngineAdapter> loader = ServiceLoader.load(TemplatingEngineAdapter.class, TemplatingEngineLoader.class.getClassLoader());
StringBuilder sb = new StringBuilder();
for (TemplatingEngineAdapter templatingEngineAdapter : loader) {
if (id.equals(templatingEngineAdapter.getIdentifier())) {
return templatingEngineAdapter;
}
sb.append(templatingEngineAdapter.getIdentifier()).append("\n");
}
try {
// Attempt to load skipping SPI
return (TemplatingEngineAdapter) Class.forName(id).getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(String.format(Locale.ROOT, "Couldn't load template engine adapter %s. Available options: %n%s", id, sb), e);
}
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.config;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.ibizlab.codegen.*;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplatingEngineAdapter;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.oas.models.OpenAPI;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
/**
* A class which manages the contextual configuration for code generation.
* This includes configuring the generator, templating, and the workflow which orchestrates these.
*
* This helper also enables the deserialization of {@link GeneratorSettings} via application-specific Jackson JSON usage
* (see {@link DynamicSettings}.
*/
@SuppressWarnings("UnusedReturnValue")
public final class CodegenConfigurator {
public static final Logger LOGGER = LoggerFactory.getLogger(CodegenConfigurator.class);
private String inputSpec;
private String outputDir;
private String templateDir;
private String auth;
private String generatorName;
private String templatingEngineName;
private Map<String, String> globalProperties = new HashMap<>();
private Map<String, Object> additionalProperties = new HashMap<>();
private GeneratorSettings generatorSettings=new GeneratorSettings();
private List<TemplateDefinition> userDefinedTemplates = new ArrayList<>();
public CodegenConfigurator() {
}
@SuppressWarnings("DuplicatedCode")
public static CodegenConfigurator fromFile(String configFile, Module... modules) {
if (isNotEmpty(configFile)) {
DynamicSettings settings = readDynamicSettings(configFile, modules);
CodegenConfigurator configurator = new CodegenConfigurator();
GeneratorSettings generatorSettings = settings.getGeneratorSettings();
List<TemplateDefinition> userDefinedTemplateSettings = settings.getFiles();
if(generatorSettings.getAdditionalProperties() != null) {
configurator.additionalProperties.putAll(generatorSettings.getAdditionalProperties());
}
if (userDefinedTemplateSettings != null) {
configurator.userDefinedTemplates.addAll(userDefinedTemplateSettings);
}
return configurator;
}
return null;
}
private static DynamicSettings readDynamicSettings(String configFile, Module... modules) {
ObjectMapper mapper;
if (FilenameUtils.isExtension(configFile.toLowerCase(Locale.ROOT), new String[]{"yml", "yaml"})) {
mapper = Yaml.mapper().copy();
} else {
mapper = Json.mapper().copy();
}
if (modules != null && modules.length > 0) {
mapper.registerModules(modules);
}
mapper.registerModule(new GuavaModule());
try {
return mapper.readValue(new File(configFile), DynamicSettings.class);
} catch (IOException ex) {
LOGGER.error(ex.getMessage());
throw new RuntimeException("Unable to deserialize config file: " + configFile);
}
}
public CodegenConfigurator addAdditionalProperty(String key, Object value) {
this.additionalProperties.put(key, value);
generatorSettings.getAdditionalProperties().put(key, value);
return this;
}
public CodegenConfigurator addGlobalProperty(String key, String value) {
this.globalProperties.put(key, value);
return this;
}
public CodegenConfigurator setAdditionalProperties(Map<String, Object> additionalProperties) {
this.additionalProperties = additionalProperties;
generatorSettings.setAdditionalProperties(additionalProperties);
return this;
}
public CodegenConfigurator setProjectName(String projectName) {
if (StringUtils.isNotEmpty(projectName)) {
addAdditionalProperty(CodegenConstants.PROJECT_NAME, projectName);
}
generatorSettings.setProjectName(projectName);
return this;
}
public CodegenConfigurator setAuth(String auth) {
// do not cache this in additional properties.
this.auth = auth;
return this;
}
public CodegenConfigurator setGitRepoId(String gitRepoId) {
if (StringUtils.isNotEmpty(gitRepoId)) {
addAdditionalProperty(CodegenConstants.GIT_REPO_ID, gitRepoId);
}
generatorSettings.setGitRepoId(gitRepoId);
return this;
}
public CodegenConfigurator setGitHost(String gitHost) {
if (StringUtils.isNotEmpty(gitHost)) {
addAdditionalProperty(CodegenConstants.GIT_HOST, gitHost);
}
generatorSettings.setGitHost(gitHost);
return this;
}
public CodegenConfigurator setGitUserId(String gitUserId) {
if (StringUtils.isNotEmpty(gitUserId)) {
addAdditionalProperty(CodegenConstants.GIT_USER_ID, gitUserId);
}
generatorSettings.setGitUserId(gitUserId);
return this;
}
public CodegenConfigurator setReleaseNote(String releaseNote) {
if (StringUtils.isNotEmpty(releaseNote)) {
addAdditionalProperty(CodegenConstants.RELEASE_NOTE, releaseNote);
}
generatorSettings.setReleaseNote(releaseNote);
return this;
}
public CodegenConfigurator setHttpUserAgent(String httpUserAgent) {
if (StringUtils.isNotEmpty(httpUserAgent)) {
addAdditionalProperty(CodegenConstants.HTTP_USER_AGENT, httpUserAgent);
}
generatorSettings.setHttpUserAgent(httpUserAgent);
return this;
}
public CodegenConfigurator setInputSpec(String inputSpec) {
this.inputSpec = inputSpec;
return this;
}
public CodegenConfigurator setOutputDir(String outputDir) {
this.outputDir = outputDir;
return this;
}
public CodegenConfigurator setPackageName(String packageName) {
if (StringUtils.isNotEmpty(packageName)) {
addAdditionalProperty(CodegenConstants.PACKAGE_NAME, packageName);
}
generatorSettings.setPackageName(packageName);
return this;
}
public CodegenConfigurator setGlobalProperties(Map<String, String> globalProperties) {
this.globalProperties = globalProperties;
return this;
}
public CodegenConfigurator setTemplateDir(String templateDir) {
this.templateDir = templateDir;
return this;
}
public ClientOptInput toClientOptInput() {
// We load the config via generatorSettings.getGeneratorName() because this is guaranteed to be set
// regardless of entrypoint (CLI sets properties on this type, config deserialization sets on generatorSettings).
CodegenConfig config = new CodegenConfig();
// TODO: Work toward CodegenConfig having a "WorkflowSettings" property, or better a "Workflow" object which itself has a "WorkflowSettings" property.
TemplatingEngineAdapter templatingEngine = TemplatingEngineLoader.byIdentifier(this.templatingEngineName);
config.setTemplatingEngine(templatingEngine);
config.getAdditionalProperties().putAll(this.additionalProperties);
config.getAdditionalProperties().putAll(this.globalProperties);
config.setInputSpec(this.inputSpec);
config.setOutputDir(this.outputDir);
config.setTemplateDir(this.templateDir);
config.setAuth(this.auth);
ClientOptInput input = new ClientOptInput()
.setConfig(config)
.setUserDefinedTemplates(userDefinedTemplates);
return input;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.config;
import com.ibizlab.codegen.utils.OptionUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
/**
* Contains shared logic for applying key-value pairs and CSV strings
* to specific settings in CodegenConfigurator.
*
* <p>
* This class exists to facilitate testing. These methods could be applied
* to CodegenConfigurator, but this complicates things when mocking CodegenConfigurator.
* </p>
* <ul>
* <li>The methods named {@code apply...Kvp} take a string of comma-separated key-value pairs.</li>
* <li>The methods named {@code apply...KvpList} take a list of such strings.</li>
* <li>The method named {@code apply...Csv} takes a string of comma-separated values.</li>
* <li>The method named {@code apply...CsvList} takes a list of such strings.</li>
* </ul>
* <p>
* The corresponding {@code add...} method on the passed configurator is called for each key-value pair (or value).
* </p>
*/
public final class CodegenConfiguratorUtils {
public static void applyGlobalPropertiesKvpList(List<String> globalProperties, CodegenConfigurator configurator) {
for(String propString : globalProperties) {
applyGlobalPropertiesKvp(propString, configurator);
}
}
public static void applyGlobalPropertiesKvp(String globalProperties, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(globalProperties);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addGlobalProperty(entry.getKey(), entry.getValue().replace(":",","));
}
}
public static void applyAdditionalPropertiesKvpList(List<String> additionalProperties, CodegenConfigurator configurator) {
for(String propString : additionalProperties) {
applyAdditionalPropertiesKvp(propString, configurator);
}
}
public static void applyAdditionalPropertiesKvp(String additionalProperties, CodegenConfigurator configurator) {
final Map<String, String> map = createMapFromKeyValuePairs(additionalProperties);
for (Map.Entry<String, String> entry : map.entrySet()) {
configurator.addAdditionalProperty(entry.getKey(), entry.getValue());
}
}
private static Set<String> createSetFromCsvList(String csvProperty) {
final List<String> values = OptionUtils.splitCommaSeparatedList(csvProperty);
return new HashSet<String>(values);
}
private static Map<String, String> createMapFromKeyValuePairs(String commaSeparatedKVPairs) {
final List<Pair<String, String>> pairs = OptionUtils.parseCommaSeparatedTuples(commaSeparatedKVPairs);
Map<String, String> result = new HashMap<String, String>();
for (Pair<String, String> pair : pairs) {
result.put(pair.getLeft(), pair.getRight());
}
return result;
}
}
package com.ibizlab.codegen.config;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.ibizlab.codegen.api.TemplateDefinition;
import com.ibizlab.codegen.api.TemplateFileType;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;
public class DynamicSettings {
@JsonAnySetter
private Map<String, Object> dynamicProperties = new HashMap<>();
@JsonUnwrapped
@JsonDeserialize(builder = GeneratorSettings.Builder.class)
private GeneratorSettings generatorSettings;
/**
* Gets the list of template files allowing user redefinition and addition of templating files
*
* @return A list of template files
*/
public List<TemplateDefinition> getFiles() {
if (files == null) return new ArrayList<>();
return files.entrySet().stream().map(kvp -> {
TemplateDefinition file = kvp.getValue();
String templateFile = kvp.getKey();
String destination = file.getDestinationFilename();
if (TemplateFileType.SupportingFiles.equals(file.getTemplateType()) && StringUtils.isBlank(destination)) {
// this special case allows definitions such as LICENSE:{}
destination = templateFile;
}
TemplateDefinition definition = new TemplateDefinition(templateFile, file.getFolder(), destination);
definition.setTemplateType(file.getTemplateType());
return definition;
}).collect(Collectors.toList());
}
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
@JsonProperty("files")
private Map<String, TemplateDefinition> files;
public GeneratorSettings getGeneratorSettings() {
excludeSettingsFromDynamicProperties();
GeneratorSettings.Builder builder = GeneratorSettings.newBuilder(generatorSettings);
// This allows us to put any unknown top-level properties into additionalProperties of the generator object.
for (Map.Entry<String, Object> entry : dynamicProperties.entrySet()) {
builder.withAdditionalProperty(entry.getKey(), entry.getValue());
}
return builder.build();
}
/**
* <p>Constructor for DynamicSettings.</p>
*/
@JsonCreator
public DynamicSettings() { }
/**
* Gets all "custom" properties included in the config object.
*
* @return All user-specified custom properties.
*/
public Map<String, Object> getDynamicProperties() {
return dynamicProperties;
}
private void excludeSettingsFromDynamicProperties(){
Set<String> fieldNames = new HashSet<>();
for (Field field : GeneratorSettings.class.getDeclaredFields()) {
fieldNames.add(field.getName());
}
dynamicProperties.keySet().removeAll(fieldNames);
}
}
package com.ibizlab.codegen.config;
import java.util.Properties;
public class GlobalSettings {
private static ThreadLocal<Properties> properties = new InheritableThreadLocal<Properties>() {
@Override
protected Properties initialValue() {
// avoid using System.getProperties().clone() which is broken in Gradle - see https://github.com/gradle/gradle/issues/17344
Properties copy = new Properties();
copy.putAll(System.getProperties());
return copy;
};
};
public static String getProperty(String key, String defaultValue) {
return properties.get().getProperty(key, defaultValue);
}
public static String getProperty(String key) {
return properties.get().getProperty(key);
}
public static void setProperty(String key, String value) {
properties.get().setProperty(key, value);
}
public static void clearProperty(String key) {
properties.get().remove(key);
}
public static void reset() {
properties.remove();
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore;
import com.ibizlab.codegen.ignore.rules.DirectoryRule;
import com.ibizlab.codegen.ignore.rules.Rule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
* Presents a processing utility for parsing and evaluating files containing common ignore patterns. (.openapi-generator-ignore)
*/
public class CodegenIgnoreProcessor {
private final Logger LOGGER = LoggerFactory.getLogger(CodegenIgnoreProcessor.class);
private File ignoreFile = null;
private List<Rule> exclusionRules = new ArrayList<>();
private List<Rule> inclusionRules = new ArrayList<>();
/**
* Loads the default ignore file (.openapi-generator-ignore) from the specified path.
*
* @param baseDirectory The base directory of the files to be processed. This contains the ignore file.
*/
public CodegenIgnoreProcessor(final String baseDirectory) {
this(baseDirectory, ".openapi-generator-ignore");
}
/**
* Loads the specified ignore file by name ([ignoreFile]) from the specified path.
*
* @param baseDirectory The base directory of the files to be processed. This contains the ignore file.
* @param ignoreFile The file containing ignore patterns.
*/
@SuppressWarnings("WeakerAccess")
public CodegenIgnoreProcessor(final String baseDirectory, final String ignoreFile) {
final File directory = new File(baseDirectory);
final File targetIgnoreFile = new File(directory, ignoreFile);
if (directory.exists() && directory.isDirectory()) {
loadFromFile(targetIgnoreFile);
} else {
LOGGER.info("Output directory ({}) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.", baseDirectory);
}
}
/**
* Constructs an instance of {@link CodegenIgnoreProcessor} from an ignore file defined by {@code targetIgnoreFile}.
*
* @param targetIgnoreFile The ignore file location.
*/
public CodegenIgnoreProcessor(final File targetIgnoreFile) {
loadFromFile(targetIgnoreFile);
}
private void loadFromFile(File targetIgnoreFile) {
if (targetIgnoreFile.exists() && targetIgnoreFile.isFile()) {
try {
loadCodegenRules(targetIgnoreFile);
this.ignoreFile = targetIgnoreFile;
} catch (IOException e) {
LOGGER.error(String.format(Locale.ROOT, "Could not process %s.", targetIgnoreFile.getName()), e.getMessage());
}
} else if (!".swagger-codegen-ignore".equals(targetIgnoreFile.getName())) {
final File legacyIgnoreFile = new File(targetIgnoreFile.getParentFile(), ".swagger-codegen-ignore");
if (legacyIgnoreFile.exists() && legacyIgnoreFile.isFile()) {
LOGGER.info(String.format(Locale.ROOT, "Legacy support: '%s' file renamed to '%s'.", legacyIgnoreFile.getName(), targetIgnoreFile.getName()));
try {
Files.move(legacyIgnoreFile.toPath(), targetIgnoreFile.toPath(), REPLACE_EXISTING);
loadFromFile(targetIgnoreFile);
} catch (IOException e) {
LOGGER.error(String.format(Locale.ROOT, "Could not rename file: %s", e.getMessage()));
}
} else {
// log info message
LOGGER.info(String.format(Locale.ROOT, "No %s file found.", targetIgnoreFile.getName()));
}
} else {
// log info message
LOGGER.info(String.format(Locale.ROOT, "No %s file found.", targetIgnoreFile.getName()));
}
}
void loadCodegenRules(final File codegenIgnore) throws IOException {
try (FileInputStream fileInputStream = new FileInputStream(codegenIgnore);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(inputStreamReader)) {
String line;
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
while ((line = reader.readLine()) != null) {
if(
//: A blank line matches no files, so it can serve as a separator for readability.
line.length() == 0
) continue;
Rule rule = Rule.create(line);
// rule could be null here if it's a COMMENT, for example
if(rule != null) {
if (Boolean.TRUE.equals(rule.getNegated())) {
inclusionRules.add(rule);
} else {
exclusionRules.add(rule);
}
}
}
}
}
/**
* Determines whether or not a file defined by {@code toEvaluate} is allowed,
* under the exclusion rules from the ignore file being processed.
*
* @param targetFile The file to check against exclusion rules from the ignore file.
* @return {@code false} if file matches any pattern in the ignore file (disallowed), otherwise {@code true} (allowed).
*/
public boolean allowsFile(final File targetFile) {
if(this.ignoreFile == null) return true;
File file = new File(this.ignoreFile.getAbsoluteFile().getParentFile().toURI().relativize(targetFile.toURI()).getPath());
boolean directoryExcluded = false;
boolean exclude = false;
if(exclusionRules.size() == 0 && inclusionRules.size() == 0) {
return true;
}
// NOTE: We *must* process all exclusion rules
for (int i = 0; i < exclusionRules.size(); i++) {
Rule current = exclusionRules.get(i);
Rule.Operation op = current.evaluate(file.getPath());
switch (op){
case EXCLUDE:
exclude = true;
// Include rule can't override rules that exclude a file by some parent directory.
if(current instanceof DirectoryRule) {
directoryExcluded = true;
}
break;
case INCLUDE:
// This won't happen here.
break;
case NOOP:
break;
case EXCLUDE_AND_TERMINATE:
i = exclusionRules.size();
break;
}
}
if(exclude) {
// Only need to process inclusion rules if we've been excluded
for (int i = 0; exclude && i < inclusionRules.size(); i++) {
Rule current = inclusionRules.get(i);
Rule.Operation op = current.evaluate(file.getPath());
// At this point exclude=true means the file should be ignored.
// op == INCLUDE means we have to flip that flag.
if(op.equals(Rule.Operation.INCLUDE)) {
if(current instanceof DirectoryRule && directoryExcluded) {
// e.g
// baz/
// !foo/bar/baz/
// NOTE: Possibly surprising side effect:
// foo/bar/baz/
// !bar/
exclude = false;
} else if (!directoryExcluded) {
// e.g.
// **/*.log
// !ISSUE_1234.log
exclude = false;
}
}
}
}
return Boolean.FALSE.equals(exclude);
}
/**
* Allows a consumer to manually inspect explicit "inclusion rules". That is, patterns in the ignore file which have been negated.
*
* @return A {@link Collections#unmodifiableList(List)} of rules which possibly negate exclusion rules in the ignore file.
*/
public List<Rule> getInclusionRules() {
return Collections.unmodifiableList(inclusionRules);
}
/**
* Allows a consumer to manually inspect all "exclusion rules". That is, patterns in the ignore file which represent
* files and directories to be excluded, unless explicitly overridden by {@link CodegenIgnoreProcessor#getInclusionRules()} rules.
*
* NOTE: Existence in this list doesn't mean a file is excluded. The rule can be overridden by {@link CodegenIgnoreProcessor#getInclusionRules()} rules.
*
* @return A {@link Collections#unmodifiableList(List)} of rules which define exclusions by patterns in the ignore file.
*/
public List<Rule> getExclusionRules() {
return Collections.unmodifiableList((exclusionRules));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;
public class DirectoryRule extends FileRule {
private PathMatcher directoryMatcher = null;
private PathMatcher contentsMatcher = null;
DirectoryRule(List<Part> syntax, String definition) {
super(syntax, definition);
String pattern = this.getPattern();
StringBuilder sb = new StringBuilder();
sb.append("glob:");
sb.append(pattern);
if(!pattern.endsWith("/")) sb.append("/");
directoryMatcher = FileSystems.getDefault().getPathMatcher(sb.toString());
sb.append("**");
contentsMatcher = FileSystems.getDefault().getPathMatcher(sb.toString());
}
@Override
public Boolean matches(String relativePath) {
return contentsMatcher.matches(FileSystems.getDefault().getPath(relativePath)) || directoryMatcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
/**
* An ignore rule which matches everything.
*/
public class EverythingRule extends Rule {
EverythingRule(List<Part> syntax, String definition) {
super(syntax, definition);
}
@Override
public Boolean matches(String relativePath) {
return true;
}
@Override
protected Operation getExcludeOperation(){ return Operation.EXCLUDE_AND_TERMINATE; }
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.util.List;
public class FileRule extends Rule {
private PathMatcher matcher = null;
FileRule(List<Part> syntax, String definition) {
super(syntax, definition);
matcher = FileSystems.getDefault().getPathMatcher("glob:"+this.getPattern());
}
@Override
public Boolean matches(String relativePath) {
return matcher.matches(FileSystems.getDefault().getPath(relativePath));
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.util.ArrayList;
import java.util.List;
public class IgnoreLineParser {
enum Token {
MATCH_ALL("**"),
MATCH_ANY("*"),
ESCAPED_EXCLAMATION("\\!"),
ESCAPED_SPACE("\\ "),
PATH_DELIM("/"),
NEGATE("!"),
TEXT(null),
DIRECTORY_MARKER("/"),
ROOTED_MARKER("/"),
COMMENT(null);
private String pattern;
Token(String pattern) {
this.pattern = pattern;
}
public String getPattern() {
return pattern;
}
}
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
static List<Part> parse(String text) throws ParserException {
List<Part> parts = new ArrayList<>();
StringBuilder sb = new StringBuilder();
String current = null;
String next = null;
char[] characters = text.toCharArray();
for (int i = 0, totalLength = characters.length; i < totalLength; i++) {
char character = characters[i];
current = String.valueOf(character);
next = i < totalLength - 1 ? String.valueOf(characters[i + 1]) : null;
if (i == 0) {
if ("#".equals(current)) {
//: A line starting with # serves as a comment.
parts.add(new Part(Token.COMMENT, text));
i = totalLength; // rather than early return
continue;
} else if ("!".equals(current)) {
if (i == totalLength - 1) {
throw new ParserException("Negation with no negated pattern.");
} else {
parts.add(new Part(Token.NEGATE));
continue;
}
} else if ("\\".equals(current) && "#".equals(next)) {
//: Put a backslash ("`\`") in front of the first hash for patterns
//: that begin with a hash.
// NOTE: Just push forward and drop the escape character. Falls through to TEXT token.
current = next;
next = null;
i++;
}
}
if (Token.MATCH_ANY.pattern.equals(current)) {
if (Token.MATCH_ANY.pattern.equals(next)) {
// peek ahead for invalid pattern. Slightly inefficient, but acceptable.
if ((i+2 < totalLength - 1) &&
String.valueOf(characters[i+2]).equals(Token.MATCH_ANY.pattern)) {
// It doesn't matter where we are in the pattern, *** is invalid.
throw new ParserException("The pattern *** is invalid.");
}
parts.add(new Part(Token.MATCH_ALL));
i++;
continue;
} else {
if (sb.length() > 0) {
// A MATCH_ANY may commonly follow a filename or some other character. Dump that to results before the MATCH_ANY.
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
}
parts.add(new Part(Token.MATCH_ANY));
continue;
}
}
if (i == 0 && Token.ROOTED_MARKER.pattern.equals(current)) {
parts.add(new Part(Token.ROOTED_MARKER));
continue;
}
if ("\\".equals(current) && " ".equals(next)) {
parts.add(new Part(Token.ESCAPED_SPACE));
i++;
continue;
} else if ("\\".equals(current) && "!".equals(next)) {
parts.add(new Part(Token.ESCAPED_EXCLAMATION));
i++;
continue;
}
if (Token.PATH_DELIM.pattern.equals(current)) {
if (i != totalLength - 1) {
if (sb.length() > 0) {
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
}
parts.add(new Part(Token.PATH_DELIM));
if(Token.PATH_DELIM.pattern.equals(next)) {
// ignore doubled path delims. NOTE: doesn't do full lookahead, so /// will result in //
i++;
}
continue;
} else if (i == totalLength - 1) {
parts.add(new Part(Token.TEXT, sb.toString()));
sb.delete(0, sb.length());
parts.add(new Part(Token.DIRECTORY_MARKER));
continue;
}
}
sb.append(current);
}
if (sb.length() > 0) {
// NOTE: All spaces escaped spaces are a special token, ESCAPED_SPACE
//: Trailing spaces are ignored unless they are quoted with backslash ("`\`")
parts.add(new Part(Token.TEXT, sb.toString().trim()));
}
return parts;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
public class InvalidRule extends Rule {
private final String reason;
InvalidRule(List<Part> syntax, String definition, String reason) {
super(syntax, definition);
this.reason = reason;
}
@Override
public Boolean matches(String relativePath) {
return null;
}
@Override
public Operation evaluate(String relativePath) {
return Operation.NOOP;
}
public String getReason() {
return reason;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
public class ParserException extends Exception {
/**
* Constructs a new exception with the specified detail message. The
* cause is not initialized, and may subsequently be initialized by
* a call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public ParserException(String message) {
super(message);
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
class Part {
private final IgnoreLineParser.Token token;
private final String value;
public Part(IgnoreLineParser.Token token, String value) {
this.token = token;
this.value = value;
}
public Part(IgnoreLineParser.Token token) {
this.token = token;
this.value = token.getPattern();
}
public IgnoreLineParser.Token getToken() {
return token;
}
public String getValue() {
return value;
}
}
\ No newline at end of file
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
import java.util.regex.Pattern;
/**
* A special case rule which matches files only if they're located
* in the same directory as the .openapi-generator-ignore file.
*/
public class RootedFileRule extends Rule {
private String definedFilename = null;
private String definedExtension = null;
RootedFileRule(List<Part> syntax, String definition) {
super(syntax, definition);
int separatorIndex = definition.lastIndexOf(".");
definedFilename = getFilenamePart(definition, separatorIndex);
definedExtension = getExtensionPart(definition, separatorIndex);
}
private String getFilenamePart(final String input, int stopIndex){
return input.substring('/' == input.charAt(0) ? 1 : 0, stopIndex > 0 ? stopIndex : input.length());
}
private String getExtensionPart(final String input, int stopIndex) {
return input.substring(stopIndex > 0 ? stopIndex+1: input.length());
}
@Override
public Boolean matches(String relativePath) {
// NOTE: Windows-style separator isn't supported, so File.pathSeparator would be incorrect here.
// NOTE: lastIndexOf rather than contains because /file.txt is acceptable while path/file.txt is not.
// relativePath will be passed by CodegenIgnoreProcessor and is relative to .codegen-ignore.
boolean isSingleFile = relativePath.lastIndexOf("/") <= 0;
if(isSingleFile) {
int separatorIndex = relativePath.lastIndexOf(".");
final String filename = getFilenamePart(relativePath, separatorIndex);
final String extension = getExtensionPart(relativePath, separatorIndex);
boolean extensionMatches = definedExtension.equals(extension) || definedExtension.equals(IgnoreLineParser.Token.MATCH_ANY.getPattern());
if(extensionMatches && definedFilename.contains(IgnoreLineParser.Token.MATCH_ANY.getPattern())) {
// TODO: Evaluate any other escape requirements here.
Pattern regex = Pattern.compile(
definedFilename
.replaceAll(Pattern.quote("."), "\\\\Q.\\\\E")
.replaceAll(Pattern.quote("*"), ".*?") // non-greedy match on 0+ any character
);
return regex.matcher(filename).matches();
}
return extensionMatches && definedFilename.equals(filename);
}
return false;
}
}
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License 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 com.ibizlab.codegen.ignore.rules;
import java.util.List;
public abstract class Rule {
public enum Operation {EXCLUDE, INCLUDE, NOOP, EXCLUDE_AND_TERMINATE}
// The original rule
private final String definition;
private final List<Part> syntax;
Rule(List<Part> syntax, String definition) {
this.syntax = syntax;
this.definition = definition;
}
public abstract Boolean matches(String relativePath);
public String getDefinition() {
return this.definition;
}
protected String getPattern() {
if(syntax == null) return this.definition;
StringBuilder sb = new StringBuilder();
for (Part current : syntax) {
switch (current.getToken()) {
case MATCH_ALL:
case MATCH_ANY:
case ESCAPED_EXCLAMATION:
case ESCAPED_SPACE:
case PATH_DELIM:
case TEXT:
case DIRECTORY_MARKER:
sb.append(current.getValue());
break;
case NEGATE:
case ROOTED_MARKER:
case COMMENT:
break;
}
}
return sb.toString();
}
/**
* Whether or not the rule should be negated. !foo means foo should be removed from previous matches.
* Example: **\/*.bak excludes all backup. Adding !/test.bak will include test.bak in the project root.
* <p>
* NOTE: It is not possible to re-include a file if a parent directory of that file is excluded.
*
* @return {@code true} if the rule is negated (inverse), otherwise {@code false} (normal).
*/
public Boolean getNegated() {
return this.syntax != null && this.syntax.size() > 0 && this.syntax.get(0).getToken() == IgnoreLineParser.Token.NEGATE;
}
public Operation evaluate(String relativePath) {
if (Boolean.TRUE.equals(matches(relativePath))) {
if(Boolean.TRUE.equals(this.getNegated())) {
return this.getIncludeOperation();
}
return this.getExcludeOperation();
}
return Operation.NOOP;
}
protected Operation getIncludeOperation(){ return Operation.INCLUDE; }
protected Operation getExcludeOperation(){ return Operation.EXCLUDE; }
public static Rule create(String definition) {
// NOTE: Comments that start with a : (e.g. //:) are pulled from git documentation for .gitignore
// see: https://github.com/git/git/blob/90f7b16b3adc78d4bbabbd426fb69aa78c714f71/Documentation/gitignore.txt
Rule rule = null;
if (definition.equals(".")) {
return new InvalidRule(null, definition, "Pattern '.' is invalid.");
} else if (definition.equals("!.")) {
return new InvalidRule(null, definition, "Pattern '!.' is invalid.");
} else if (definition.startsWith("..")) {
return new InvalidRule(null, definition, "Pattern '..' is invalid.");
}
try {
List<Part> result = IgnoreLineParser.parse(definition);
Boolean directoryOnly = null;
if (result.size() == 0) {
return rule;
} else if (result.size() == 1) {
// single-character filename only
Part part = result.get(0);
if (IgnoreLineParser.Token.MATCH_ANY.equals(part.getToken())) {
rule = new RootedFileRule(result, definition);
} else {
rule = new FileRule(result, definition);
}
} else {
IgnoreLineParser.Token head = result.get(0).getToken();
//: An optional prefix "`!`" which negates the pattern; any
//: matching file excluded by a previous pattern will become
//: included again. It is not possible to re-include a file if a parent
//: directory of that file is excluded. Git doesn't list excluded
//: directories for performance reasons, so any patterns on contained
//: files have no effect, no matter where they are defined.
//: Put a backslash ("`\`") in front of the first "`!`" for patterns
//: that begin with a literal "`!`", for example, "`\!important!.txt`".
// see this.getNegated();
//: If the pattern ends with a slash, it is removed for the
//: purpose of the following description, but it would only find
//: a match with a directory. In other words, `foo/` will match a
//: directory `foo` and paths underneath it, but will not match a
//: regular file or a symbolic link `foo` (this is consistent
//: with the way how pathspec works in general in Git).
directoryOnly = IgnoreLineParser.Token.DIRECTORY_MARKER.equals(result.get(result.size() - 1).getToken());
if (directoryOnly) {
rule = new DirectoryRule(result, definition);
} else if (IgnoreLineParser.Token.PATH_DELIM.equals(head)) {
//: A leading slash matches the beginning of the pathname.
//: For example, "/{asterisk}.c" matches "cat-file.c" but not
//: "mozilla-sha1/sha1.c".
rule = new RootedFileRule(result, definition);
} else {
// case 1
//: If the pattern does not contain a slash '/', Git treats it as
//: a shell glob pattern and checks for a match against the
//: pathname relative to the location of the `.gitignore` file
//: (relative to the toplevel of the work tree if not from a
//: `.gitignore` file).
// case 2
//: Otherwise, Git treats the pattern as a shell glob suitable
//: for consumption by fnmatch(3) with the FNM_PATHNAME flag:
//: wildcards in the pattern will not match a / in the pathname.
//: For example, "Documentation/{asterisk}.html" matches
//: "Documentation/git.html" but not "Documentation/ppc/ppc.html"
//: or "tools/perf/Documentation/perf.html".
// case 3
//: Two consecutive asterisks ("`**`") in patterns matched against
//: full pathname may have special meaning:
//:
//: - A leading "`**`" followed by a slash means match in all
//: directories. For example, "`**/foo`" matches file or directory
//: "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
//: matches file or directory "`bar`" anywhere that is directly
//: under directory "`foo`".
//:
//: - A trailing "`/**`" matches everything inside. For example,
//: "`abc/**`" matches all files inside directory "`abc`", relative
//: to the location of the `.gitignore` file, with infinite depth.
//:
//: - A slash followed by two consecutive asterisks then a slash
//: matches zero or more directories. For example, "`a/**/b`"
//: matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
//:
//: - Other consecutive asterisks are considered invalid.
rule = new FileRule(result, definition);
}
}
} catch (ParserException e) {
return new InvalidRule(null, definition, e.getMessage());
}
return rule;
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class DstSystemModel {
/**
* 系统标识
*/
@JSONField(name = "pssystemid")
@JsonProperty("pssystemid")
private String pssystemid;
/**
* 系统名称
*/
@JSONField(name = "pssystemname")
@JsonProperty("pssystemname")
private String pssystemname;
/**
* 结构
*/
@JSONField(name = "sysstructure")
@JsonProperty("sysstructure")
private Map sysstructure;
/**
* 应用
*/
@JSONField(name = "apps")
@JsonProperty("apps")
private List<App> apps;
public DstSystemModel addApp(App app)
{
if(apps==null)
apps=new ArrayList<>();
apps.add(app.setSystemid(this.pssystemid));
return this;
}
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class App{
private String id;
private String label;
private String systemid;
private String fullname;
private String type;
private String group;
private String icon;
private Integer visabled;
private String addr;
}
/**
* 校验
*/
@JSONField(name = "md5check")
@JsonProperty("md5check")
private String md5check;
/**
* 排序
*/
@JSONField(name = "showorder")
@JsonProperty("showorder")
private Integer showorder;
private Map<String, Object> extensionparams;
public DstSystemModel setDynamicModelPath(String dynamic_model_path)
{
if(extensionparams==null)
extensionparams=new HashMap<String, Object>();
extensionparams.put("dynamic_model_path",dynamic_model_path);
return this;
}
@JSONField(serialize = false)
@JsonIgnore
public String getDynamicModelPath()
{
if(extensionparams!=null&&extensionparams.get("dynamic_model_path")!=null)
return extensionparams.get("dynamic_model_path").toString();
return null;
}
public DstSystemModel setLastModify(Long lastModify)
{
if(extensionparams==null)
extensionparams=new HashMap<String, Object>();
extensionparams.put("last_modify",lastModify);
return this;
}
@JSONField(serialize = false)
@JsonIgnore
public Long getLastModify()
{
if(extensionparams!=null&&extensionparams.get("last_modify")!=null)
return DataObject.getLongValue(extensionparams.get("last_modify"),0L);
return 0L;
}
public DstSystemModel fromPath(Path path)
{
try {
if(!Files.exists(path))
throw new IllegalArgumentException("读取文件失败DstSystem:"+path.toString());
JSONObject jo= JSON.parseObject(new String(Files.readAllBytes(path), StandardCharsets.UTF_8));
this.setPssystemid(jo.getString("codeName"));
this.setPssystemname(jo.getString("logicName"));
this.setLastModify(path.toFile().lastModified());
if(jo.containsKey("getAllPSApps"))
{
JSONArray array=jo.getJSONArray("getAllPSApps");
array.forEach(obj->{
JSONObject app=(JSONObject)obj;
String appPath=app.getString("path");
if(!StringUtils.isEmpty(appPath))
{
String[] args=appPath.split("/");
if(args.length==3)
{
String appId=args[1];
this.addApp(new App().setId(appId).setLabel(appId));
}
}
});
}
this.setDynamicModelPath(path.getParent().toAbsolutePath().toString());
} catch (IOException e) {
throw new IllegalArgumentException("读取文件失败DstSystem:"+path.toString());
}
return this;
}
}
package com.ibizlab.codegen.lite;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.ibizlab.codegen.utils.DataObject;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class FieldModel {
private String columnName;
private String codeName;
private String unionName;
private String showName;
private String comment;
private MetaFieldModel field;
private RelationshipModel reference;
@JsonIgnore
@JSONField(serialize = false)
public String getColumnExp()
{
if(field.getPhysicalField()!=null && 1==field.getPhysicalField())
{
return columnName+" as \""+columnName.toUpperCase()+"\"";
}
else if(!StringUtils.isEmpty(field.getExpression()))
{
return field.getExpression()+" as \""+columnName.toUpperCase()+"\"";
}
return "";
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isPhysicalField()
{
return this.getField().getPhysicalField()!=null && 1==this.getField().getPhysicalField();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isKeyField()
{
return this.getField().getKeyField()!=null && 1==this.getField().getKeyField();
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLogicValidField()
{
return "LOGICVALID".equals(this.getField().getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isLastModifyField()
{
return "UPDATEDATE".equals(this.getField().getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isCreateTimeField()
{
return "CREATEDATE".equals(this.getField().getPredefined());
}
@JsonIgnore
@JSONField(serialize = false)
public boolean isUnionKeyField()
{
return !StringUtils.isEmpty(this.getField().getUnionKey());
}
public String getPropType()
{
String dataType=this.getField().getDataType().toUpperCase();
if( dataType.indexOf("TEXT")>=0||dataType.indexOf("CHAR")>=0||dataType.indexOf("LOB")>=0)
return "string";
else if(dataType.indexOf("TIME")>=0)
return "date-time";
else if(dataType.indexOf("DATE")>=0)
return "date";
else if(dataType.indexOf("NUM")>=0||dataType.indexOf("FLOAT")>=0||dataType.indexOf("DOUBLE")>=0||dataType.indexOf("DECIMAL")>=0)
return "number";
else if(dataType.indexOf("INT")==0)
return "integer";
return "string";
}
public String getColumnName(String dsType)
{
return DataObject.getStringValue(field.get("column-"+dsType.toLowerCase()),getColumnName());
}
}
package com.ibizlab.codegen.lite;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonIgnoreProperties(value = "handler")
public class RelationshipModel {
private String codeName;
private String entityName;
private String entityCodeName;
private String entityLogicName;
private String systemId;
private String dataSourceName;
private String tableName;
private String entityId;
private MetaRelationshipModel relation;
}
package com.ibizlab.codegen;
\ No newline at end of file
此差异已折叠。
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册