Skip to content

Commit

Permalink
[handlebars] Honor supporting files when applying bundles (#5364)
Browse files Browse the repository at this point in the history
* [handlebars] Honor supporting files when applying bundles
  • Loading branch information
jimschubert authored Feb 23, 2020
1 parent 3f0c163 commit ef00854
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,88 @@

package org.openapitools.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();

/**
* Compiles a template into a string
*
* @param generator 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 ocurred in the template processing
*/
String compileTemplate(TemplatingGenerator generator, Map<String, Object> bundle,
String templateFile) throws IOException;

/**
* 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();
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();

/**
* Compiles a template into a string
*
* @param generator 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 ocurred in the template processing
*/
String compileTemplate(TemplatingGenerator generator, Map<String, Object> bundle,
String templateFile) throws IOException;

/**
* 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();

/**
* 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
*/
default boolean templateExists(TemplatingGenerator 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;
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,24 @@

/**
* interface to the full template content
* implementers might take into account the -t cli option,
* look in the resources for a language specific template, etc
* implementers might take into account the -t cli option,
* look in the resources for a language specific template, etc
*/
public interface TemplatingGenerator {

/**
* 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 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);
/**
* 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,9 @@ private void generateSupportingFiles(List<File> files, Map<String, Object> bundl
}

if (ignoreProcessor.allowsFile(new File(outputFilename))) {
if (Arrays.stream(templatingEngine.getFileExtensions()).anyMatch(templateFile::endsWith)) {
// support.templateFile is the unmodified/original supporting file name (e.g. build.sh.mustache)
// templatingEngine.templateExists dispatches resolution to this, performing template-engine specific inspect of support file extensions.
if (templatingEngine.templateExists(this, support.templateFile)) {
String templateContent = templatingEngine.compileTemplate(this, bundle, support.templateFile);
writeToFile(outputFilename, templateContent);
File written = new File(outputFilename);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public TemplateSource findTemplate(TemplatingGenerator generator, String templat
} catch (Exception ignored) {
}
}
throw new RuntimeException("couldnt find a subtemplate " + templateFile);
throw new TemplateNotFoundException(templateFile);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public Reader findTemplate(TemplatingGenerator generator, String name) {
} catch (Exception ignored) {
}
}
throw new RuntimeException("couldnt find a subtemplate " + name);
throw new TemplateNotFoundException(name);
}

public Mustache.Compiler getCompiler() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.openapitools.codegen.templating;

public class TemplateNotFoundException 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 TemplateNotFoundException() {
}

/**
* 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 TemplateNotFoundException(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 TemplateNotFoundException(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 TemplateNotFoundException(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 TemplateNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

0 comments on commit ef00854

Please sign in to comment.