FREEMARKER-142 Support Transformation Of Directories (#13)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2846d0a..b610dbf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,8 +5,9 @@
## 0.1.0-SNAPSHOT
### Added
+* [FREEMARKER-142] Support Transformation Of Directories
* [FREEMARKER-139] freemarker-cli: Provide GsonTool to align with Maven plugin
-* An environment variable can bes passed as `DataSource`
+* Environment variables can bes passed as `DataSource`
* [FREEMARKER-135] Support user-supplied names for `DataSource` on the command line
* [FREEMARKER-129] Support `DataSource` exclude pattern in addition to include pattern
* [FREEMARKER-129] User-defined parameters are passed as `-Pkey=value` instead of using system properties
@@ -36,4 +37,5 @@
[FREEMARKER-135]: https://issues.apache.org/jira/browse/FREEMARKER-135
[FREEMARKER-136]: https://issues.apache.org/jira/browse/FREEMARKER-136
[FREEMARKER-138]: https://issues.apache.org/jira/browse/FREEMARKER-138
-[FREEMARKER-139]: https://issues.apache.org/jira/browse/FREEMARKER-139
\ No newline at end of file
+[FREEMARKER-139]: https://issues.apache.org/jira/browse/FREEMARKER-139
+[FREEMARKER-142]: https://issues.apache.org/jira/browse/FREEMARKER-142
\ No newline at end of file
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/ByteArrayDataSource.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/ByteArrayDataSource.java
index 196b254..c5c0a9d 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/ByteArrayDataSource.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/ByteArrayDataSource.java
@@ -14,7 +14,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.freemarker.generator.base.activation;
import javax.activation.DataSource;
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceFactory.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceFactory.java
index 016a394..df33351 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceFactory.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceFactory.java
@@ -49,7 +49,7 @@
/**
* Creates a FreeMarker data source from various sources.
*/
-public class DataSourceFactory {
+public abstract class DataSourceFactory {
private static final String NO_MIME_TYPE = null;
private static final Charset NO_CHARSET = null;
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java
index 097e17d..ef60fe7 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java
@@ -71,6 +71,7 @@
return sources.stream()
.map(this::resolve)
.flatMap(Collection::stream)
+ .sorted()
.collect(toList());
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
new file mode 100644
index 0000000..1e5cb50
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateOutput.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import org.apache.freemarker.generator.base.util.Validate;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Information about where to write the ouput of a template. Initially we
+ * wanted to use a <code>FileWriter</code> but it requires actually an
+ * existing output file (otherwise a FileNotFound exception is thrown).
+ */
+public class TemplateOutput {
+
+ private final Writer writer;
+ private final File file;
+
+ private TemplateOutput(File file) {
+ this.writer = null;
+ this.file = requireNonNull(file);
+ }
+
+ private TemplateOutput(Writer writer) {
+ this.writer = requireNonNull(writer);
+ this.file = null;
+ }
+
+ public static TemplateOutput fromWriter(Writer writer) {
+ return new TemplateOutput(writer);
+ }
+
+ public static TemplateOutput fromFile(File file) {
+ return new TemplateOutput(file);
+ }
+
+ public Writer getWriter() {
+ return writer;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ public boolean isWrittenToFile() {
+ return file != null;
+ }
+
+ public boolean isWrittenToSuppliedWriter() {
+ return writer != null;
+ }
+
+ public Writer writer() {
+ return writer != null ? writer : fileWriter();
+ }
+
+ private FileWriter fileWriter() {
+ Validate.notNull(file, "Output file is null");
+
+ try {
+ return new FileWriter(file);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to create FileWriter: " + file.getAbsolutePath(), e);
+ }
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java
new file mode 100644
index 0000000..42c36b6
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSource.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import org.apache.freemarker.generator.base.util.Validate;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Information how to load a template. The template is either
+ * provided as source code or as template path resolved
+ * by FreeMarker's template loader.
+ */
+public class TemplateSource {
+
+ public enum Origin {
+ PATH,
+ CODE
+ }
+
+ /** Name of template for diagnostics */
+ private final String name;
+
+ /** Origin of template, e.g. loaded via FreeMarker's template loader */
+ private final Origin origin;
+
+ /** Code of the template */
+ private final String code;
+
+ /** Template path */
+ private final String path;
+
+ /** Template encoding */
+ private final Charset encoding;
+
+ private TemplateSource(String name, String code) {
+ this.name = name;
+ this.origin = Origin.CODE;
+ this.code = code;
+ this.path = null;
+ this.encoding = StandardCharsets.UTF_8;
+ }
+
+ private TemplateSource(String name, String path, Charset encoding) {
+ this.name = name;
+ this.origin = Origin.PATH;
+ this.code = null;
+ this.path = path;
+ this.encoding = encoding;
+ }
+
+ public static TemplateSource fromPath(String path) {
+ Validate.notEmpty(path, "Template path is empty");
+ return new TemplateSource(path, path, StandardCharsets.UTF_8);
+ }
+
+ public static TemplateSource fromPath(String path, Charset encoding) {
+ Validate.notEmpty(path, "Template path is empty");
+ Validate.notNull(encoding, "Template encoding is null");
+ return new TemplateSource(path, path, encoding);
+ }
+
+ public static TemplateSource fromCode(String name, String code) {
+ Validate.notEmpty(name, "Template name is empty");
+ Validate.notEmpty(code, "Template code is empty");
+ return new TemplateSource(name, code);
+ }
+
+ public Origin getOrigin() {
+ return origin;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Charset getEncoding() {
+ return encoding;
+ }
+
+ @Override
+ public String toString() {
+ return "TemplateSource{" +
+ "name='" + name + '\'' +
+ ", origin=" + origin +
+ ", encoding=" + encoding +
+ '}';
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSourceFactory.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSourceFactory.java
new file mode 100644
index 0000000..ab53ee3
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateSourceFactory.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
+import org.apache.freemarker.generator.base.util.UriUtils;
+
+import java.io.File;
+
+public abstract class TemplateSourceFactory {
+
+ public static TemplateSource create(String str) {
+ if (isTemplatePath(str)) {
+ return TemplateSource.fromPath(str);
+ } else {
+ try (DataSource dataSource = DataSourceFactory.create(str)) {
+ return TemplateSource.fromCode(dataSource.getName(), dataSource.getText());
+ }
+ }
+ }
+
+ private static boolean isTemplatePath(String str) {
+ return !UriUtils.isUri(str) && !new File(str).exists();
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformation.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformation.java
new file mode 100644
index 0000000..b13a799
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformation.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Information about loading templates and writing their output.
+ */
+public class TemplateTransformation {
+
+ /** Source of template */
+ private final TemplateSource templateSource;
+
+ /** Output of template */
+ private final TemplateOutput templateOutput;
+
+ public TemplateTransformation(TemplateSource templateSource, TemplateOutput templateOutput) {
+ this.templateSource = requireNonNull(templateSource);
+ this.templateOutput = requireNonNull(templateOutput);
+ }
+
+ public TemplateSource getTemplateSource() {
+ return templateSource;
+ }
+
+ public TemplateOutput getTemplateOutput() {
+ return templateOutput;
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java
new file mode 100644
index 0000000..ed65111
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformations.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static java.util.Objects.requireNonNull;
+
+public class TemplateTransformations {
+
+ private final List<TemplateTransformation> templateTransformations;
+
+ public TemplateTransformations(Collection<? extends TemplateTransformation> templateTransformations) {
+ this.templateTransformations = new ArrayList<>(requireNonNull(templateTransformations));
+ }
+
+ public List<? extends TemplateTransformation> getList() {
+ return templateTransformations;
+ }
+
+ public TemplateTransformation get(int index) {
+ return templateTransformations.get(index);
+ }
+
+ public int size() {
+ return templateTransformations.size();
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
new file mode 100644
index 0000000..37100aa
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import org.apache.freemarker.generator.base.file.RecursiveFileSupplier;
+import org.apache.freemarker.generator.base.util.NonClosableWriterWrapper;
+import org.apache.freemarker.generator.base.util.StringUtils;
+import org.apache.freemarker.generator.base.util.Validate;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Collections.singletonList;
+
+/**
+ * Provide the logic to define multiple transformations from the user input.
+ */
+public class TemplateTransformationsBuilder {
+
+ /** Interactive template */
+ private TemplateSource template;
+
+ /** List of templates and/or template directories to be rendered */
+ private final List<String> sources;
+
+ /** Optional include patterns for resolving source templates or template directories */
+ private final List<String> includes;
+
+ /** Optional exclude patterns for resolving source templates or template directories */
+ private final List<String> excludes;
+
+ /** Optional output file or directory */
+ private final List<File> outputs;
+
+ /** Optional user-supplied writer */
+ private Writer writer;
+
+ private TemplateTransformationsBuilder() {
+ this.sources = new ArrayList<>();
+ this.includes = new ArrayList<>();
+ this.excludes = new ArrayList<>();
+ this.outputs = new ArrayList<>();
+ this.writer = null;
+ }
+
+ public static TemplateTransformationsBuilder builder() {
+ return new TemplateTransformationsBuilder();
+ }
+
+ public TemplateTransformations build() {
+ validate();
+
+ final List<TemplateTransformation> result = new ArrayList<>();
+
+ if (template != null) {
+ final File outputFile = outputs.isEmpty() ? null : outputs.get(0);
+ result.add(resolveInteractiveTemplate(outputFile));
+ } else {
+ for (int i = 0; i < sources.size(); i++) {
+ final String source = sources.get(i);
+ final File output = i < outputs.size() ? outputs.get(i) : null;
+ result.addAll(resolve(source, output));
+ }
+ }
+
+ return new TemplateTransformations(result);
+ }
+
+ public TemplateTransformationsBuilder setTemplate(String name, String code) {
+ if (StringUtils.isNotEmpty(code)) {
+ this.template = TemplateSource.fromCode(name, code);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addSource(String source) {
+ if (StringUtils.isNotEmpty(source)) {
+ this.sources.add(source);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addSources(Collection<String> sources) {
+ sources.forEach(this::addSource);
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addInclude(String include) {
+ if (StringUtils.isNotEmpty(include)) {
+ this.includes.add(include);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addIncludes(Collection<String> includes) {
+ if (includes != null) {
+ this.includes.addAll(includes);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addExclude(String exclude) {
+ if (StringUtils.isNotEmpty(exclude)) {
+ this.excludes.add(exclude);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addExcludes(Collection<String> excludes) {
+ if (excludes != null) {
+ this.excludes.addAll(excludes);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addOutput(String output) {
+ if (StringUtils.isNotEmpty(output)) {
+ this.outputs.add(new File(output));
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addOutput(File output) {
+ if (output != null) {
+ this.outputs.add(output);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder addOutputs(Collection<String> outputs) {
+ if (outputs != null) {
+ outputs.forEach(this::addOutput);
+ }
+ return this;
+ }
+
+ public TemplateTransformationsBuilder setWriter(Writer writer) {
+ this.writer = writer;
+ return this;
+ }
+
+ public TemplateTransformationsBuilder setStdOut() {
+ this.writer = new NonClosableWriterWrapper(new BufferedWriter(new OutputStreamWriter(System.out, UTF_8)));
+ return this;
+ }
+
+ private void validate() {
+ Validate.isTrue(template != null || !sources.isEmpty(), "No template was provided");
+ Validate.isTrue(template == null || sources.isEmpty(), "Interactive template does not support multiple sources");
+ }
+
+ /**
+ * Resolve a <code>source</code> to a list of <code>TemplateTransformation</code>.
+ *
+ * @param source the source being a file name, an URI or <code>NamedUri</code>
+ * @param output Optional output file or directory
+ * @return list of <code>TemplateTransformation</code>
+ */
+ private List<TemplateTransformation> resolve(String source, File output) {
+ if (isTemplateFile(source)) {
+ return resolveTemplateFile(source, output);
+ } else if (isTemplateDirectory(source)) {
+ return resolveTemplateDirectory(source, output);
+ } else if (isTemplatePath(source)) {
+ return resolveTemplatePath(source, output);
+ } else {
+ return resolveTemplateCode(source, output);
+ }
+ }
+
+ private List<TemplateTransformation> resolveTemplateFile(String source, File outputFile) {
+ final TemplateSource templateSource = templateSource(source);
+ final TemplateOutput templateOutput = templateOutput(outputFile);
+ return singletonList(new TemplateTransformation(templateSource, templateOutput));
+ }
+
+ private List<TemplateTransformation> resolveTemplateDirectory(String source, File outputDirectory) {
+ Validate.fileExists(new File(source), "Template directory does not exist: " + source);
+
+ final File templateDirectory = new File(source);
+ final List<File> templateFiles = templateFilesSupplier(source, getInclude(), getExclude()).get();
+ final List<TemplateTransformation> templateTransformations = new ArrayList<>();
+
+ for (File templateFile : templateFiles) {
+ final TemplateSource templateSource = templateSource(templateFile.getAbsolutePath());
+ final File outputFile = getTemplateOutputFile(templateDirectory, templateFile, outputDirectory);
+ final TemplateOutput templateOutput = templateOutput(outputFile);
+ templateTransformations.add(new TemplateTransformation(templateSource, templateOutput));
+ }
+
+ return templateTransformations;
+ }
+
+ private List<TemplateTransformation> resolveTemplatePath(String source, File out) {
+ final TemplateSource templateSource = templateSource(source);
+ final TemplateOutput templateOutput = templateOutput(out);
+ return singletonList(new TemplateTransformation(templateSource, templateOutput));
+ }
+
+ private TemplateTransformation resolveInteractiveTemplate(File out) {
+ final TemplateOutput templateOutput = templateOutput(out);
+ return new TemplateTransformation(template, templateOutput);
+ }
+
+ private List<TemplateTransformation> resolveTemplateCode(String source, File out) {
+ final TemplateSource templateSource = TemplateSource.fromCode("interactive", source);
+ final TemplateOutput templateOutput = templateOutput(out);
+ return singletonList(new TemplateTransformation(templateSource, templateOutput));
+ }
+
+ private TemplateOutput templateOutput(File templateOutputFile) {
+ if (writer == null && templateOutputFile != null) {
+ return TemplateOutput.fromFile(templateOutputFile);
+ } else {
+ return TemplateOutput.fromWriter(writer);
+ }
+ }
+
+ private TemplateSource templateSource(String source) {
+ return TemplateSourceFactory.create(source);
+ }
+
+ private String getInclude() {
+ return includes.isEmpty() ? null : includes.get(0);
+ }
+
+ private String getExclude() {
+ return excludes.isEmpty() ? null : excludes.get(0);
+ }
+
+ private Writer writer(String outputFile, String outputEncoding) {
+ try {
+ if (writer != null) {
+ return writer;
+ } else if (!StringUtils.isEmpty(outputFile)) {
+ return new BufferedWriter(new FileWriter(outputFile));
+ } else {
+ return new BufferedWriter(new OutputStreamWriter(System.out, outputEncoding));
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to create writer", e);
+ }
+ }
+
+ private static File getTemplateOutputFile(File templateDirectory, File templateFile, File outputDirectory) {
+ final String relativePath = relativePath(templateDirectory, templateFile);
+ final String relativeOutputFileName = mapExtension(relativePath);
+ return new File(outputDirectory, relativeOutputFileName);
+ }
+
+ private static boolean isTemplateFile(String source) {
+ final File file = new File(source);
+ return file.exists() && file.isFile();
+ }
+
+ private static boolean isTemplateDirectory(String source) {
+ final File file = new File(source);
+ return file.exists() && file.isDirectory();
+ }
+
+ private static boolean isTemplatePath(String source) {
+ return !isTemplateFile(source) && !isTemplateDirectory(source);
+ }
+
+ private static RecursiveFileSupplier templateFilesSupplier(String source, String include, String exclude) {
+ return new RecursiveFileSupplier(singletonList(source), singletonList(include), singletonList(exclude));
+ }
+
+ private static String relativePath(File directory, File file) {
+ return file.getAbsolutePath()
+ .substring(directory.getAbsolutePath().length())
+ .substring(1);
+ }
+
+ private static String mapExtension(String fileName) {
+ if (fileName.toLowerCase().endsWith(".ftl")) {
+ return fileName.substring(0, fileName.length() - 4);
+ } else {
+ return fileName;
+ }
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsSupplier.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsSupplier.java
new file mode 100644
index 0000000..ef06672
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsSupplier.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.template;
+
+import java.util.function.Supplier;
+
+public interface TemplateTransformationsSupplier extends Supplier<TemplateTransformations> {
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ClosableUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ClosableUtils.java
index dfefc01..0d04517 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ClosableUtils.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ClosableUtils.java
@@ -26,8 +26,8 @@
if (closeable != null) {
closeable.close();
}
- } catch (final IOException e) {
- // e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/MapFlattener.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/MapFlattener.java
index 3800add..80f5dd3 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/MapFlattener.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/MapFlattener.java
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.base.util;
import java.util.Iterator;
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java
index 71bd28a..af2b497 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java
@@ -16,6 +16,8 @@
*/
package org.apache.freemarker.generator.base.util;
+import java.io.File;
+
/**
* Simple validation methods designed for interal use.
*/
@@ -140,6 +142,18 @@
}
/**
+ * Validates that the file exists
+ *
+ * @param file the file to test
+ * @param msg message to output if validation fails
+ */
+ public static void fileExists(File file, String msg) {
+ if (file == null || !file.exists()) {
+ throw new IllegalArgumentException(msg);
+ }
+ }
+
+ /**
* Cause a failure.
*
* @param msg message to output.
@@ -147,4 +161,5 @@
public static void fail(String msg) {
throw new IllegalArgumentException(msg);
}
+
}
diff --git a/freemarker-generator-base/src/test/data/env/nginx.env b/freemarker-generator-base/src/test/data/env/nginx.env
new file mode 100644
index 0000000..111461e
--- /dev/null
+++ b/freemarker-generator-base/src/test/data/env/nginx.env
@@ -0,0 +1,19 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements. See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You 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
+##
+## http://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.
+## ---------------------------------------------------------------------------
+NGINX_HOSTNAME=localhost
+NGINX_WEBROOT=/var/www/project
+NGINX_LOGS=/var/log/nginx/
\ No newline at end of file
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesSupplierTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesSupplierTest.java
index 8089c48..aacfd75 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesSupplierTest.java
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DataSourcesSupplierTest.java
@@ -44,7 +44,8 @@
assertEquals(1, supplier("pom=./pom.xml", "*", NO_EXCLUDE).get().size());
assertEquals(1, supplier("pom=./pom.xml#mimetype=application/xml", "*", NO_EXCLUDE).get().size());
assertEquals(1, supplier("pom=" + PWD + "/pom.xml", "*", NO_EXCLUDE).get().size());
- assertEquals(1, supplier("pom=file:///" + PWD + "/pom.xml#mimetype=application/xml", "*", NO_EXCLUDE).get().size());
+ assertEquals(1, supplier("pom=file:///" + PWD + "/pom.xml#mimetype=application/xml", "*", NO_EXCLUDE).get()
+ .size());
}
@Test
@@ -62,10 +63,10 @@
@Test
public void shouldResolveDirectory() {
- assertEquals(4, supplier(DATA_DIRECTORY, null, null).get().size());
- assertEquals(4, supplier(DATA_DIRECTORY, "", null).get().size());
- assertEquals(4, supplier(DATA_DIRECTORY, "*", null).get().size());
- assertEquals(4, supplier(DATA_DIRECTORY, "*.*", null).get().size());
+ assertEquals(5, supplier(DATA_DIRECTORY, null, null).get().size());
+ assertEquals(5, supplier(DATA_DIRECTORY, "", null).get().size());
+ assertEquals(5, supplier(DATA_DIRECTORY, "*", null).get().size());
+ assertEquals(5, supplier(DATA_DIRECTORY, "*.*", null).get().size());
assertEquals(2, supplier(DATA_DIRECTORY, "*.csv", null).get().size());
assertEquals(1, supplier(DATA_DIRECTORY, "*.t*", null).get().size());
assertEquals(0, supplier(DATA_DIRECTORY, "*.bin", null).get().size());
@@ -75,10 +76,10 @@
public void shouldResolveFilesAndDirectory() {
final List<String> sources = Arrays.asList("pom.xml", "README.md", DATA_DIRECTORY);
- assertEquals(6, supplier(sources, null, null).get().size());
- assertEquals(6, supplier(sources, "", null).get().size());
- assertEquals(6, supplier(sources, "*", null).get().size());
- assertEquals(6, supplier(sources, "*.*", null).get().size());
+ assertEquals(7, supplier(sources, null, null).get().size());
+ assertEquals(7, supplier(sources, "", null).get().size());
+ assertEquals(7, supplier(sources, "*", null).get().size());
+ assertEquals(7, supplier(sources, "*.*", null).get().size());
assertEquals(2, supplier(sources, "*.csv", null).get().size());
assertEquals(1, supplier(sources, "*.t*", null).get().size());
assertEquals(1, supplier(sources, "*.xml", null).get().size());
@@ -87,8 +88,9 @@
assertEquals(0, supplier(sources, null, "*").get().size());
assertEquals(0, supplier(sources, null, "*.*").get().size());
assertEquals(0, supplier(sources, "*", "*").get().size());
- assertEquals(5, supplier(sources, "*", "*.md").get().size());
- assertEquals(3, supplier(sources, "*", "file*.*").get().size());
+
+ assertEquals(6, supplier(sources, "*", "*.md").get().size());
+ assertEquals(4, supplier(sources, "*", "file*.*").get().size());
}
@Test
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/file/RecursiveFileResolverTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/file/RecursiveFileSupplierTest.java
similarity index 72%
rename from freemarker-generator-base/src/test/java/org/apache/freemarker/generator/file/RecursiveFileResolverTest.java
rename to freemarker-generator-base/src/test/java/org/apache/freemarker/generator/file/RecursiveFileSupplierTest.java
index 7c20b49..06d5d17 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/file/RecursiveFileResolverTest.java
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/file/RecursiveFileSupplierTest.java
@@ -27,7 +27,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-public class RecursiveFileResolverTest {
+public class RecursiveFileSupplierTest {
private static final String ANY_DIRECTORY = "./src/test/data";
private static final String ANY_FILE_NAME = "file_01.csv";
@@ -35,13 +35,13 @@
@Test
public void shouldResolveAllFilesOfDirectory() {
- assertEquals(4, fileResolver(ANY_DIRECTORY, null, null).get().size());
- assertTrue(fileResolver(ANY_DIRECTORY, UNKNOWN_FILE_NAME, null).get().isEmpty());
+ assertEquals(5, fileSupplier(ANY_DIRECTORY, null, null).get().size());
+ assertTrue(fileSupplier(ANY_DIRECTORY, UNKNOWN_FILE_NAME, null).get().isEmpty());
}
@Test
public void shouldResolveSingleMatchingFile() {
- final List<File> files = fileResolver(ANY_DIRECTORY, ANY_FILE_NAME, null).get();
+ final List<File> files = fileSupplier(ANY_DIRECTORY, ANY_FILE_NAME, null).get();
assertEquals(1, files.size());
assertEquals(ANY_FILE_NAME, files.get(0).getName());
@@ -50,17 +50,17 @@
@Test
public void shouldResolveMultipleFiles() {
final List<String> sources = Arrays.asList("pom.xml", "README.md");
- final List<File> files = fileResolver(sources, "*", null).get();
+ final List<File> files = fileSupplier(sources, "*", null).get();
assertEquals(2, files.size());
- assertEquals("pom.xml", files.get(0).getName());
- assertEquals("README.md", files.get(1).getName());
+ assertEquals("README.md", files.get(0).getName());
+ assertEquals("pom.xml", files.get(1).getName());
}
@Test
public void shouldResolveMultipleFilesWithIncludeFilter() {
final List<String> sources = Arrays.asList("pom.xml", "README.md");
- final List<File> files = fileResolver(sources, "*.xml", null).get();
+ final List<File> files = fileSupplier(sources, "*.xml", null).get();
assertEquals(1, files.size());
assertEquals("pom.xml", files.get(0).getName());
@@ -68,23 +68,24 @@
@Test
public void shouldExcludeAllFiles() {
- final List<File> files = fileResolver(ANY_DIRECTORY, null, "*").get();
+ final List<File> files = fileSupplier(ANY_DIRECTORY, null, "*").get();
assertEquals(0, files.size());
}
@Test
public void shouldExcludeFiles() {
- final List<File> files = fileResolver(ANY_DIRECTORY, null, "*.csv").get();
+ final List<File> files = fileSupplier(ANY_DIRECTORY, null, "*.csv").get();
- assertEquals(2, files.size());
- assertEquals("file_01.txt", files.get(0).getName());
+ assertEquals(3, files.size());
+ assertEquals("nginx.env", files.get(0).getName());
assertEquals("test.properties", files.get(1).getName());
+ assertEquals("file_01.txt", files.get(2).getName());
}
@Test
public void shouldIncludeAndExcludeFiles() {
- final List<File> files = fileResolver(ANY_DIRECTORY, "file*.*", "*.csv").get();
+ final List<File> files = fileSupplier(ANY_DIRECTORY, "file*.*", "*.csv").get();
assertEquals(1, files.size());
assertEquals("file_01.txt", files.get(0).getName());
@@ -92,17 +93,16 @@
@Test
public void shouldResolveMultipleFilesRecursivelyWithIncludes() {
- final List<File> files = fileResolver(ANY_DIRECTORY, "*.csv", null).get();
+ final List<File> files = fileSupplier(ANY_DIRECTORY, "*.csv", null).get();
assertEquals(2, files.size());
}
- private static RecursiveFileSupplier fileResolver(String source, String include, String exclude) {
- return fileResolver(singletonList(source), include, exclude);
+ private static RecursiveFileSupplier fileSupplier(String source, String include, String exclude) {
+ return fileSupplier(singletonList(source), include, exclude);
}
- private static RecursiveFileSupplier fileResolver(List<String> sources, String include, String exclude) {
+ private static RecursiveFileSupplier fileSupplier(List<String> sources, String include, String exclude) {
return new RecursiveFileSupplier(sources, singletonList(include), singletonList(exclude));
}
-
}
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java
new file mode 100644
index 0000000..1d84c90
--- /dev/null
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateSourceFactoryTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.template;
+
+import org.apache.freemarker.generator.base.template.TemplateSource;
+import org.apache.freemarker.generator.base.template.TemplateSource.Origin;
+import org.apache.freemarker.generator.base.template.TemplateSourceFactory;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TemplateSourceFactoryTest {
+
+ private static final String ANY_TEMPLATE_PATH = "any/template/path.ftl";
+ private static final String ANY_FILE_NAME = "pom.xml";
+ private static final String ANY_URL = "https://jsonplaceholder.typicode.com/posts/2";
+ private static final String ANY_ENVIRONMENT_VARIABLE = "env:///PWD";
+ private static final String ANY_NAMED_URI = "content:www=https://www.google.com?foo=bar#contenttype=application/json";
+
+ @Test
+ public void shouldCreateFromTemplatePath() {
+ final TemplateSource templateSource = TemplateSourceFactory.create(ANY_TEMPLATE_PATH);
+
+ assertEquals(ANY_TEMPLATE_PATH, templateSource.getName());
+ assertEquals(Origin.PATH, templateSource.getOrigin());
+ assertEquals(ANY_TEMPLATE_PATH, templateSource.getPath());
+ assertNull(templateSource.getCode());
+ }
+
+ @Test
+ public void shouldCreateFromFile() {
+ final TemplateSource templateSource = TemplateSourceFactory.create(ANY_FILE_NAME);
+
+ assertEquals(ANY_FILE_NAME, templateSource.getName());
+ assertEquals(Origin.CODE, templateSource.getOrigin());
+ assertNull(templateSource.getPath());
+ assertFalse(templateSource.getCode().isEmpty());
+ }
+
+ @Test
+ public void shouldCreateFromEnvironmentVariable() {
+ final TemplateSource templateSource = TemplateSourceFactory.create(ANY_ENVIRONMENT_VARIABLE);
+
+ assertEquals("PWD", templateSource.getName());
+ assertEquals(Origin.CODE, templateSource.getOrigin());
+ assertNull(templateSource.getPath());
+ assertFalse(templateSource.getCode().isEmpty());
+ }
+
+ @Test
+ @Ignore("Requires internet access")
+ public void shouldCreateFromUrl() {
+ final TemplateSource templateSource = TemplateSourceFactory.create(ANY_URL);
+
+ assertNotNull(templateSource.getName());
+ assertEquals(Origin.CODE, templateSource.getOrigin());
+ assertNull(templateSource.getPath());
+ assertFalse(templateSource.getCode().isEmpty());
+ }
+
+ @Test
+ @Ignore("Requires internet access")
+ public void shouldCreateFromNamedUri() {
+ final TemplateSource templateSource = TemplateSourceFactory.create(ANY_NAMED_URI);
+
+ assertNotNull(templateSource.getName());
+ assertEquals(Origin.CODE, templateSource.getOrigin());
+ assertNull(templateSource.getPath());
+ assertFalse(templateSource.getCode().isEmpty());
+ }
+}
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
new file mode 100644
index 0000000..3cc0545
--- /dev/null
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.template;
+
+import org.apache.freemarker.generator.base.template.TemplateOutput;
+import org.apache.freemarker.generator.base.template.TemplateSource;
+import org.apache.freemarker.generator.base.template.TemplateSource.Origin;
+import org.apache.freemarker.generator.base.template.TemplateTransformations;
+import org.apache.freemarker.generator.base.template.TemplateTransformationsBuilder;
+import org.junit.Test;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class TemplateTransformationsBuilderTest {
+
+ private static final String ANY_TEMPLATE_FILE_NAME = "src/test/template/application.properties";
+ private static final String OTHER_TEMPLATE_FILE_NAME = "src/test/template/nginx/nginx.conf.ftl";
+ private static final String ANY_TEMPLATE_PATH = "template/info.ftl";
+ private static final String ANY_TEMPLATE_DIRECTORY_NAME = "src/test/template";
+
+ // === Interactive Template =============================================
+
+ @Test
+ public void shouldCreateFromInteractiveTemplate() {
+ final TemplateTransformations transformations = builder()
+ .setTemplate("interactive", "Hello World")
+ .setStdOut()
+ .build();
+
+ assertEquals(1, transformations.size());
+
+ final TemplateSource templateSource = transformations.get(0).getTemplateSource();
+ final TemplateOutput templateOutput = transformations.get(0).getTemplateOutput();
+
+ assertEquals("interactive", templateSource.getName());
+ assertEquals(Origin.CODE, templateSource.getOrigin());
+ assertEquals("Hello World", templateSource.getCode());
+ assertNull(templateSource.getPath());
+ assertEquals(StandardCharsets.UTF_8, templateSource.getEncoding());
+
+ assertNotNull(templateOutput.getWriter());
+ assertNull(templateOutput.getFile());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldThrowIllegalArgumentExceptionWheMixingInteractiveTemplateWithSources() {
+ builder()
+ .setTemplate("interactive", "Hello World")
+ .addSource(ANY_TEMPLATE_FILE_NAME)
+ .setStdOut()
+ .build();
+ }
+
+
+ // === Template File ====================================================
+
+ @Test
+ public void shouldCreateFromTemplateFile() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_FILE_NAME)
+ .setStdOut()
+ .build();
+
+ assertEquals(1, transformations.size());
+
+ final TemplateSource templateSource = transformations.get(0).getTemplateSource();
+ final TemplateOutput templateOutput = transformations.get(0).getTemplateOutput();
+
+ assertNotNull(templateSource.getName());
+ assertEquals(Origin.CODE, templateSource.getOrigin());
+ assertNotNull(templateSource.getCode());
+ assertNull(templateSource.getPath());
+ assertEquals(StandardCharsets.UTF_8, templateSource.getEncoding());
+
+ assertNotNull(templateOutput.getWriter());
+ assertNull(templateOutput.getFile());
+ }
+
+ @Test
+ public void shouldCreateFromMultipleTemplateFiles() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_FILE_NAME)
+ .addOutput("foo/first.out")
+ .addSource(OTHER_TEMPLATE_FILE_NAME)
+ .addOutput("foo/second.out")
+ .build();
+
+ assertEquals(2, transformations.size());
+ assertEquals(new File("foo/first.out"), transformations.get(0).getTemplateOutput().getFile());
+ assertEquals(new File("foo/second.out"), transformations.get(1).getTemplateOutput().getFile());
+ }
+
+ // === Template Path ====================================================
+
+ @Test
+ public void shouldCreateFromTemplatePath() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_PATH)
+ .setStdOut()
+ .build();
+
+ assertEquals(1, transformations.size());
+
+ final TemplateSource templateSource = transformations.get(0).getTemplateSource();
+ final TemplateOutput templateOutput = transformations.get(0).getTemplateOutput();
+
+ assertNotNull(templateSource.getName());
+ assertEquals(Origin.PATH, templateSource.getOrigin());
+ assertNull(templateSource.getCode());
+ assertNotNull(templateSource.getPath());
+ assertEquals(StandardCharsets.UTF_8, templateSource.getEncoding());
+
+ assertNotNull(templateOutput.getWriter());
+ assertNull(templateOutput.getFile());
+ }
+
+ // === Template Directory ===============================================
+
+ @Test
+ public void shouldCreateFromTemplateDirectory() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_DIRECTORY_NAME)
+ .setStdOut()
+ .build();
+
+ assertEquals(2, transformations.size());
+ assertEquals("application.properties", transformations.get(0).getTemplateSource().getName());
+ assertEquals("nginx.conf.ftl", transformations.get(1).getTemplateSource().getName());
+ }
+
+ @Test
+ public void shouldCreateFromTemplateDirectoryWithOutputDirectory() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_DIRECTORY_NAME)
+ .addOutput("/foo")
+ .build();
+
+ assertEquals(2, transformations.size());
+ assertEquals("application.properties", transformations.get(0).getTemplateSource().getName());
+ assertEquals("nginx.conf.ftl", transformations.get(1).getTemplateSource().getName());
+ }
+
+ @Test
+ public void shouldCreateFromTemplateDirectoryWithInclude() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_DIRECTORY_NAME)
+ .addInclude("*.properties")
+ .setStdOut()
+ .build();
+
+ assertEquals(1, transformations.size());
+ assertEquals("application.properties", transformations.get(0).getTemplateSource().getName());
+ }
+
+ @Test
+ public void shouldCreateFromTemplateDirectoryWithExclude() {
+ final TemplateTransformations transformations = builder()
+ .addSource(ANY_TEMPLATE_DIRECTORY_NAME)
+ .addExclude("*.ftl")
+ .setStdOut()
+ .build();
+
+ assertEquals(1, transformations.size());
+ assertEquals("application.properties", transformations.get(0).getTemplateSource().getName());
+ }
+
+ private TemplateTransformationsBuilder builder() {
+ return TemplateTransformationsBuilder
+ .builder();
+ }
+}
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/MapFlattenerTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/MapFlattenerTest.java
index 882ffe5..92bd90c 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/MapFlattenerTest.java
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/MapFlattenerTest.java
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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 org.apache.freemarker.generator.util;
import org.apache.freemarker.generator.base.util.MapFlattener;
diff --git a/freemarker-generator-base/src/test/template/application.properties b/freemarker-generator-base/src/test/template/application.properties
new file mode 100644
index 0000000..0488360
--- /dev/null
+++ b/freemarker-generator-base/src/test/template/application.properties
@@ -0,0 +1,19 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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
+ http://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.
+-->
+# == application.properties ==================================================
+server.name=${NGINX_HOSTNAME!"somehost"}
+server.logs=${NGINX_LOGS!"/var/log/nginx"}
diff --git a/freemarker-generator-base/src/test/template/nginx/nginx.conf.ftl b/freemarker-generator-base/src/test/template/nginx/nginx.conf.ftl
new file mode 100644
index 0000000..ac57019
--- /dev/null
+++ b/freemarker-generator-base/src/test/template/nginx/nginx.conf.ftl
@@ -0,0 +1,24 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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
+ http://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.
+-->
+# == nginx-conf =============================================================
+server {
+ listen ${NGINX_PORT!"80"};
+ server_name ${NGINX_HOSTNAME!"somehost"};
+
+ root ${NGINX_WEBROOT!"/usr/share/nginx/www"};
+ index index.htm;
+}
diff --git a/freemarker-generator-cli/run-samples.sh b/freemarker-generator-cli/run-samples.sh
index 01e5085..d760145 100755
--- a/freemarker-generator-cli/run-samples.sh
+++ b/freemarker-generator-cli/run-samples.sh
@@ -155,6 +155,13 @@
$FREEMARKER_CMD -t templates/properties/csv/locker-test-users.ftl site/sample/properties > target/out/locker-test-users.csv || { echo >&2 "Test failed. Aborting."; exit 1; }
#############################################################################
+# Template Directory
+#############################################################################
+
+echo "site/template"
+$FREEMARKER_CMD -t site/template -PNGINX_HOSTNAME=localhost -o target/out/template || { echo >&2 "Test failed. Aborting."; exit 1; }
+
+#############################################################################
# YAML
#############################################################################
diff --git a/freemarker-generator-cli/site/template/application.properties b/freemarker-generator-cli/site/template/application.properties
new file mode 100644
index 0000000..d5f2114
--- /dev/null
+++ b/freemarker-generator-cli/site/template/application.properties
@@ -0,0 +1,19 @@
+<#--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you 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
+http://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.
+-->
+# == application.properties ==================================================
+server.name=${NGINX_HOSTNAME!"somehost"}
+server.logs=${NGINX_LOGS!"/var/log/nginx"}
diff --git a/freemarker-generator-cli/site/template/nginx/nginx.conf.ftl b/freemarker-generator-cli/site/template/nginx/nginx.conf.ftl
new file mode 100644
index 0000000..ac57019
--- /dev/null
+++ b/freemarker-generator-cli/site/template/nginx/nginx.conf.ftl
@@ -0,0 +1,24 @@
+<#--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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
+ http://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.
+-->
+# == nginx-conf =============================================================
+server {
+ listen ${NGINX_PORT!"80"};
+ server_name ${NGINX_HOSTNAME!"somehost"};
+
+ root ${NGINX_WEBROOT!"/usr/share/nginx/www"};
+ index index.htm;
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
index c3c319a..6315aa0 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java
@@ -33,7 +33,6 @@
import java.io.BufferedWriter;
import java.io.File;
-import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
@@ -60,56 +59,56 @@
TemplateSourceOptions templateSourceOptions;
public static final class TemplateSourceOptions {
- @Option(names = { "-t", "--template" }, description = "FreeMarker template to render")
- public String template;
+ @Option(names = { "-t", "--template" }, description = "template to process")
+ public List<String> templates;
- @Option(names = { "-i", "--interactive" }, description = "Interactive FreeMarker template")
+ @Option(names = { "-i", "--interactive" }, description = "interactive template to process")
public String interactiveTemplate;
}
- @Option(names = { "-b", "--basedir" }, description = "Optional template base directory")
+ @Option(names = { "-b", "--basedir" }, description = "optional template base directory")
String baseDir;
- @Option(names = { "-D", "--system-property" }, description = "Set system property")
+ @Option(names = { "-D", "--system-property" }, description = "set system property")
Properties systemProperties;
- @Option(names = { "-e", "--input-encoding" }, description = "Encoding of data source", defaultValue = "UTF-8")
+ @Option(names = { "-e", "--input-encoding" }, description = "encoding of data source", defaultValue = "UTF-8")
String inputEncoding;
- @Option(names = { "-l", "--locale" }, description = "Locale being used for the output, e.g. 'en_US'")
+ @Option(names = { "-l", "--locale" }, description = "locale being used for the output, e.g. 'en_US'")
String locale;
- @Option(names = { "-m", "--data-model" }, description = "Data model used for rendering")
+ @Option(names = { "-m", "--data-model" }, description = "data model used for rendering")
List<String> dataModels;
- @Option(names = { "-o", "--output" }, description = "Output file")
+ @Option(names = { "-o", "--output" }, description = "output file or directory")
String outputFile;
- @Option(names = { "-P", "--param" }, description = "Set parameter")
+ @Option(names = { "-P", "--param" }, description = "set parameter")
Map<String, String> parameters;
- @Option(names = { "-s", "--data-source" }, description = "Data source used for rendering")
+ @Option(names = { "-s", "--data-source" }, description = "data source used for redering")
List<String> dataSources;
@Option(names = { "--config" }, defaultValue = FREEMARKER_CLI_PROPERTY_FILE, description = "FreeMarker CLI configuration file")
String configFile;
- @Option(names = { "--include" }, description = "File pattern for data source input directory")
+ @Option(names = { "--data-source-include" }, description = "file include pattern for data sources")
String include;
- @Option(names = { "--exclude" }, description = "File pattern for data source input directory")
+ @Option(names = { "--data-source-exclude" }, description = "file exclude pattern for data sources")
String exclude;
- @Option(names = { "--output-encoding" }, description = "Encoding of output, e.g. UTF-8", defaultValue = "UTF-8")
+ @Option(names = { "--output-encoding" }, description = "encoding of output, e.g. UTF-8", defaultValue = "UTF-8")
String outputEncoding;
- @Option(names = { "--stdin" }, description = "Read data source from stdin")
+ @Option(names = { "--stdin" }, description = "read data source from stdin")
boolean readFromStdin;
- @Option(names = { "--times" }, defaultValue = "1", description = "Re-run X times for profiling")
+ @Option(names = { "--times" }, defaultValue = "1", description = "re-run X times for profiling")
int times;
- @Parameters(description = "List of input files and/or input directories")
+ @Parameters(description = "data source files and/or directories")
List<String> sources;
/** User-supplied command line parameters */
@@ -118,7 +117,7 @@
/** User-supplied writer (used mainly for unit testing) */
Writer userSuppliedWriter;
- /** Injected by Picolci */
+ /** Injected by Picocli */
@Spec private CommandSpec spec;
Main() {
@@ -190,14 +189,6 @@
}
}
}
-
- // "-t" or "--template" parameter shall not contain wildcard characters
- if (StringUtils.isNotEmpty(templateSourceOptions.template)) {
- final String source = templateSourceOptions.template;
- if (isFileSource(source) && (source.contains("*") || source.contains("?"))) {
- throw new ParameterException(spec.commandLine(), "No wildcards supported for template: " + source);
- }
- }
}
private Settings settings(Properties configuration, List<File> templateDirectories) {
@@ -207,31 +198,31 @@
.isReadFromStdin(readFromStdin)
.setArgs(args)
.setConfiguration(configuration)
- .setInclude(include)
- .setExclude(exclude)
+ .setDataSourceIncludePattern(include)
+ .setDataSourceExcludePattern(exclude)
.setInputEncoding(inputEncoding)
.setInteractiveTemplate(templateSourceOptions.interactiveTemplate)
.setLocale(locale)
.setOutputEncoding(outputEncoding)
.setOutputFile(outputFile)
.setParameters(parameterModelSupplier.get())
- .setDataSources(getCombindedDataSources())
+ .setDataSources(getCombinedDataSources())
.setDataModels(dataModels)
.setSystemProperties(systemProperties != null ? systemProperties : new Properties())
.setTemplateDirectories(templateDirectories)
- .setTemplateName(templateSourceOptions.template)
+ .setTemplateNames(templateSourceOptions.templates)
.setWriter(writer(outputFile, outputEncoding))
.build();
}
- private Writer writer(String outputFile, String ouputEncoding) {
+ private Writer writer(String outputFile, String outputEncoding) {
try {
if (userSuppliedWriter != null) {
return userSuppliedWriter;
- } else if (!StringUtils.isEmpty(outputFile)) {
- return new BufferedWriter(new FileWriter(outputFile));
+ } else if (StringUtils.isEmpty(outputFile)) {
+ return new BufferedWriter(new OutputStreamWriter(System.out, outputEncoding));
} else {
- return new BufferedWriter(new OutputStreamWriter(System.out, ouputEncoding));
+ return null;
}
} catch (IOException e) {
throw new RuntimeException("Unable to create writer", e);
@@ -250,7 +241,7 @@
*
* @return List of data sources
*/
- private List<String> getCombindedDataSources() {
+ private List<String> getCombinedDataSources() {
return Stream.of(dataSources, sources)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java
index 3b53e71..89e48bf 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java
@@ -23,6 +23,7 @@
import java.io.File;
import java.io.Writer;
import java.nio.charset.Charset;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -52,12 +53,18 @@
/** List of FreeMarker template directories to be passed to FreeMarker <code>TemplateLoader</code> */
private final List<File> templateDirectories;
- /** Name of the template to be loaded and rendered */
- private final String templateName;
+ /** List of template to be loaded and rendered */
+ private final List<String> templates;
- /** Template provided by the user interactivly */
+ /** Template provided by the user interactively */
private final String interactiveTemplate;
+ /** Optional include pattern for recursive directly search of template files */
+ private final String templateFileIncludePattern;
+
+ /** Optional exclude pattern for recursive directly search of data source files */
+ private final String templateFileExcludePattern;
+
/** Encoding of input files */
private final Charset inputEncoding;
@@ -67,14 +74,14 @@
/** Enable verbose mode (currently not used) **/
private final boolean verbose;
- /** Optional output file if not written to stdout */
- private final File outputFile;
+ /** Optional output file or directory if not written to stdout */
+ private final File output;
- /** Optional include pattern for recursice directly search of source files */
- private final String include;
+ /** Optional include pattern for recursive directly search of data source files */
+ private final String dataSourceIncludePattern;
- /** Optional exclude pattern for recursice directly search of source files */
- private final String exclude;
+ /** Optional exclude pattern for recursive directly search of data source files */
+ private final String dataSourceExcludePattern;
/** The locale used for rendering the template */
private final Locale locale;
@@ -92,7 +99,7 @@
private final Map<String, Object> parameters;
/** User-supplied system properties */
- private final Properties sytemProperties;
+ private final Properties systemProperties;
/** The writer used for rendering templates, e.g. stdout or a file writer */
private final Writer writer;
@@ -101,43 +108,47 @@
Properties configuration,
List<String> args,
List<File> templateDirectories,
- String template,
+ List<String> templates,
String interactiveTemplate,
+ String templateFileIncludePattern,
+ String templateFileExcludePattern,
Charset inputEncoding,
Charset outputEncoding,
boolean verbose,
- File outputFile,
- String include,
- String exclude,
+ File output,
+ String dataSourceIncludePattern,
+ String dataSourceExcludePattern,
Locale locale,
boolean isReadFromStdin,
List<String> dataSources,
List<String> dataModels,
Map<String, Object> parameters,
- Properties sytemProperties,
+ Properties systemProperties,
Writer writer) {
- if (isEmpty(template) && isEmpty(interactiveTemplate)) {
+ if ((templates == null || templates.isEmpty()) && isEmpty(interactiveTemplate)) {
throw new IllegalArgumentException("Either 'template' or 'interactiveTemplate' must be provided");
}
this.args = requireNonNull(args);
this.templateDirectories = requireNonNull(templateDirectories);
- this.templateName = template;
+ this.templates = requireNonNull(templates);
this.interactiveTemplate = interactiveTemplate;
+ this.templateFileIncludePattern = templateFileIncludePattern;
+ this.templateFileExcludePattern = templateFileExcludePattern;
this.inputEncoding = inputEncoding;
this.outputEncoding = outputEncoding;
this.verbose = verbose;
- this.outputFile = outputFile;
- this.include = include;
- this.exclude = exclude;
+ this.output = output;
+ this.dataSourceIncludePattern = dataSourceIncludePattern;
+ this.dataSourceExcludePattern = dataSourceExcludePattern;
this.locale = requireNonNull(locale);
this.isReadFromStdin = isReadFromStdin;
this.dataSources = requireNonNull(dataSources);
this.dataModels = requireNonNull(dataModels);
this.parameters = requireNonNull(parameters);
- this.sytemProperties = requireNonNull(sytemProperties);
+ this.systemProperties = requireNonNull(systemProperties);
this.configuration = requireNonNull(configuration);
- this.writer = new NonClosableWriterWrapper(requireNonNull(writer));
+ this.writer = writer != null ? new NonClosableWriterWrapper(writer) : null;
}
public static SettingsBuilder builder() {
@@ -156,14 +167,22 @@
return templateDirectories;
}
- public String getTemplateName() {
- return templateName;
+ public List<String> getTemplates() {
+ return templates;
}
-
+
public String getInteractiveTemplate() {
return interactiveTemplate;
}
+ public String getTemplateFileIncludePattern() {
+ return templateFileIncludePattern;
+ }
+
+ public String getTemplateFileExcludePattern() {
+ return templateFileExcludePattern;
+ }
+
public Charset getInputEncoding() {
return inputEncoding;
}
@@ -180,16 +199,16 @@
return verbose;
}
- public File getOutputFile() {
- return outputFile;
+ public File getOutput() {
+ return output;
}
- public String getInclude() {
- return include;
+ public String getDataSourceIncludePattern() {
+ return dataSourceIncludePattern;
}
- public String getExclude() {
- return exclude;
+ public String getDataSourceExcludePattern() {
+ return dataSourceExcludePattern;
}
public Locale getLocale() {
@@ -212,12 +231,12 @@
return parameters;
}
- public Properties getSytemProperties() {
- return sytemProperties;
+ public Properties getSystemProperties() {
+ return systemProperties;
}
public boolean hasOutputFile() {
- return outputFile != null;
+ return output != null;
}
public Writer getWriter() {
@@ -236,7 +255,7 @@
result.put(Model.FREEMARKER_LOCALE, getLocale());
result.put(Model.FREEMARKER_TEMPLATE_DIRECTORIES, getTemplateDirectories());
result.put(Model.FREEMARKER_USER_PARAMETERS, getParameters());
- result.put(Model.FREEMARKER_USER_SYSTEM_PROPERTIES, getSytemProperties());
+ result.put(Model.FREEMARKER_USER_SYSTEM_PROPERTIES, getSystemProperties());
result.put(Model.FREEMARKER_WRITER, getWriter());
return result;
}
@@ -251,33 +270,37 @@
"configuration=" + configuration +
", args=" + args +
", templateDirectories=" + templateDirectories +
- ", templateName='" + templateName + '\'' +
+ ", templateName=s'" + templates + '\'' +
", interactiveTemplate='" + interactiveTemplate + '\'' +
+ ", templateFileIncludePattern='" + templateFileIncludePattern + '\'' +
+ ", templateFileExcludePattern='" + templateFileExcludePattern + '\'' +
", inputEncoding=" + inputEncoding +
", outputEncoding=" + outputEncoding +
", verbose=" + verbose +
- ", outputFile=" + outputFile +
- ", include='" + include + '\'' +
- ", exclude='" + include + '\'' +
+ ", outputFile=" + output +
+ ", include='" + dataSourceIncludePattern + '\'' +
+ ", exclude='" + dataSourceExcludePattern + '\'' +
", locale=" + locale +
", isReadFromStdin=" + isReadFromStdin +
", dataSources=" + dataSources +
", properties=" + parameters +
- ", sytemProperties=" + sytemProperties +
+ ", systemProperties=" + systemProperties +
'}';
}
public static class SettingsBuilder {
private List<String> args;
private List<File> templateDirectories;
- private String templateName;
+ private List<String> templateNames;
private String interactiveTemplate;
+ private String templateFileIncludePattern;
+ private String templateFileExcludePattern;
private String inputEncoding;
private String outputEncoding;
private boolean verbose;
private String outputFile;
- private String include;
- private String exclude;
+ private String dataSourceIncludePattern;
+ private String dataSourceExcludePattern;
private String locale;
private boolean isReadFromStdin;
private List<String> dataSources;
@@ -295,6 +318,7 @@
this.systemProperties = new Properties();
this.setInputEncoding(DEFAULT_CHARSET.name());
this.setOutputEncoding(DEFAULT_CHARSET.name());
+ this.templateNames = new ArrayList<>();
this.dataSources = emptyList();
this.dataModels = emptyList();
this.templateDirectories = emptyList();
@@ -315,8 +339,10 @@
return this;
}
- public SettingsBuilder setTemplateName(String templateName) {
- this.templateName = templateName;
+ public SettingsBuilder setTemplateNames(List<String> templateNames) {
+ if (templateNames != null) {
+ this.templateNames = templateNames;
+ }
return this;
}
@@ -325,6 +351,16 @@
return this;
}
+ public SettingsBuilder setTemplateFileIncludePattern(String templateFileIncludePattern) {
+ this.templateFileIncludePattern = templateFileIncludePattern;
+ return this;
+ }
+
+ public SettingsBuilder setTemplateFileExcludePattern(String templateFileExcludePattern) {
+ this.templateFileExcludePattern = templateFileExcludePattern;
+ return this;
+ }
+
public SettingsBuilder setInputEncoding(String inputEncoding) {
if (inputEncoding != null) {
this.inputEncoding = inputEncoding;
@@ -349,13 +385,13 @@
return this;
}
- public SettingsBuilder setInclude(String include) {
- this.include = include;
+ public SettingsBuilder setDataSourceIncludePattern(String dataSourceIncludePattern) {
+ this.dataSourceIncludePattern = dataSourceIncludePattern;
return this;
}
- public SettingsBuilder setExclude(String exclude) {
- this.exclude = exclude;
+ public SettingsBuilder setDataSourceExcludePattern(String dataSourceExcludePattern) {
+ this.dataSourceExcludePattern = dataSourceExcludePattern;
return this;
}
@@ -419,14 +455,16 @@
configuration,
args,
templateDirectories,
- templateName,
+ templateNames,
interactiveTemplate,
+ templateFileIncludePattern,
+ templateFileExcludePattern,
inputEncoding,
outputEncoding,
verbose,
currOutputFile,
- include,
- exclude,
+ dataSourceIncludePattern,
+ dataSourceExcludePattern,
LocaleUtils.parseLocale(currLocale),
isReadFromStdin,
dataSources,
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java
index 6a57e59..2c220b2 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java
@@ -21,6 +21,8 @@
import org.apache.freemarker.generator.base.file.PropertiesClassPathSupplier;
import org.apache.freemarker.generator.base.file.PropertiesFileSystemSupplier;
import org.apache.freemarker.generator.base.file.PropertiesSupplier;
+import org.apache.freemarker.generator.base.template.TemplateTransformationsBuilder;
+import org.apache.freemarker.generator.base.template.TemplateTransformationsSupplier;
import java.util.Map;
import java.util.function.Supplier;
@@ -52,8 +54,8 @@
public static DataSourcesSupplier dataSourcesSupplier(Settings settings) {
return new DataSourcesSupplier(settings.getDataSources(),
- settings.getInclude(),
- settings.getExclude(),
+ settings.getDataSourceIncludePattern(),
+ settings.getDataSourceExcludePattern(),
settings.getInputEncoding());
}
@@ -65,6 +67,17 @@
return settings::getParameters;
}
+ public static TemplateTransformationsSupplier templateTransformationsSupplier(Settings settings) {
+ return (() -> TemplateTransformationsBuilder.builder()
+ .setTemplate("interactive", settings.getInteractiveTemplate())
+ .addSources(settings.getTemplates())
+ .addInclude(settings.getTemplateFileIncludePattern())
+ .addExclude(settings.getTemplateFileExcludePattern())
+ .addOutput(settings.getOutput())
+ .setWriter(settings.getWriter())
+ .build());
+ }
+
public static PropertiesSupplier propertiesSupplier(String fileName) {
return new PropertiesSupplier(
new PropertiesFileSystemSupplier(fileName),
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java
index 618fef9..7813a4e 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java
@@ -18,15 +18,22 @@
import freemarker.template.Configuration;
import freemarker.template.Template;
+import freemarker.template.TemplateException;
import org.apache.commons.io.FileUtils;
import org.apache.freemarker.generator.base.FreeMarkerConstants.Location;
import org.apache.freemarker.generator.base.datasource.DataSource;
import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
import org.apache.freemarker.generator.base.datasource.DataSources;
+import org.apache.freemarker.generator.base.template.TemplateOutput;
+import org.apache.freemarker.generator.base.template.TemplateSource;
+import org.apache.freemarker.generator.base.template.TemplateTransformation;
+import org.apache.freemarker.generator.base.template.TemplateTransformations;
import org.apache.freemarker.generator.base.util.UriUtils;
import org.apache.freemarker.generator.cli.config.Settings;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URI;
@@ -47,6 +54,7 @@
import static org.apache.freemarker.generator.cli.config.Suppliers.dataModelSupplier;
import static org.apache.freemarker.generator.cli.config.Suppliers.dataSourcesSupplier;
import static org.apache.freemarker.generator.cli.config.Suppliers.parameterSupplier;
+import static org.apache.freemarker.generator.cli.config.Suppliers.templateTransformationsSupplier;
import static org.apache.freemarker.generator.cli.config.Suppliers.toolsSupplier;
/**
@@ -62,41 +70,60 @@
private final Supplier<Map<String, Object>> dataModelsSupplier;
private final Supplier<Map<String, Object>> parameterModelSupplier;
private final Supplier<Configuration> configurationSupplier;
+ private final Supplier<TemplateTransformations> templateTransformationsSupplier;
+
public FreeMarkerTask(Settings settings) {
this(settings,
- toolsSupplier(settings),
+ configurationSupplier(settings),
+ templateTransformationsSupplier(settings),
dataSourcesSupplier(settings),
dataModelSupplier(settings),
parameterSupplier(settings),
- configurationSupplier(settings));
+ toolsSupplier(settings)
+ );
}
public FreeMarkerTask(Settings settings,
- Supplier<Map<String, Object>> toolsSupplier,
+ Supplier<Configuration> configurationSupplier,
+ Supplier<TemplateTransformations> templateTransformationsSupplier,
Supplier<List<DataSource>> dataSourcesSupplier,
Supplier<Map<String, Object>> dataModelsSupplier,
Supplier<Map<String, Object>> parameterModelSupplier,
- Supplier<Configuration> configurationSupplier) {
+ Supplier<Map<String, Object>> toolsSupplier) {
this.settings = requireNonNull(settings);
this.toolsSupplier = requireNonNull(toolsSupplier);
this.dataSourcesSupplier = requireNonNull(dataSourcesSupplier);
this.dataModelsSupplier = requireNonNull(dataModelsSupplier);
this.parameterModelSupplier = requireNonNull(parameterModelSupplier);
this.configurationSupplier = requireNonNull(configurationSupplier);
+ this.templateTransformationsSupplier = requireNonNull(templateTransformationsSupplier);
}
@Override
public Integer call() {
- final Template template = template(settings, configurationSupplier);
- try (Writer writer = settings.getWriter(); DataSources dataSources = dataSources(settings, dataSourcesSupplier)) {
+ try {
+ final Configuration configuration = configurationSupplier.get();
+ final TemplateTransformations templateTransformations = templateTransformationsSupplier.get();
+ final DataSources dataSources = dataSources(settings, dataSourcesSupplier);
final Map<String, Object> dataModel = dataModel(dataSources, parameterModelSupplier, dataModelsSupplier, toolsSupplier);
- template.process(dataModel, writer);
+ templateTransformations.getList().forEach(t -> process(configuration, t, dataModel));
return SUCCESS;
} catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException("Failed to render FreeMarker template: " + template.getName(), e);
+ throw new RuntimeException("Failed to process templates", e);
+ }
+ }
+
+ private void process(Configuration configuration,
+ TemplateTransformation templateTransformation,
+ Map<String, Object> dataModel) {
+ final TemplateSource templateSource = templateTransformation.getTemplateSource();
+ final TemplateOutput templateOutput = templateTransformation.getTemplateOutput();
+ try (Writer writer = writer(templateOutput)) {
+ final Template template = template(configuration, templateSource);
+ template.process(dataModel, writer);
+ } catch (TemplateException | IOException e) {
+ throw new RuntimeException("Failed to process template: " + templateSource.getName(), e);
}
}
@@ -113,33 +140,6 @@
return new DataSources(dataSources);
}
- /**
- * Loading FreeMarker templates from absolute paths is not encouraged due to security
- * concern (see https://freemarker.apache.org/docs/pgui_config_templateloading.html#autoid_42)
- * which are mostly irrelevant when running on the command line. So we resolve the absolute file
- * instead of relying on existing template loaders.
- *
- * @param settings Settings
- * @param configurationSupplier Supplies FreeMarker configuration
- * @return FreeMarker template
- */
- private static Template template(Settings settings, Supplier<Configuration> configurationSupplier) {
- final String templateName = settings.getTemplateName();
- final Configuration configuration = configurationSupplier.get();
-
- try {
- if (settings.isInteractiveTemplate()) {
- return interactiveTemplate(settings, configuration);
- } else if (isAbsoluteTemplateFile(settings)) {
- return fileTemplate(settings, configuration);
- } else {
- return configuration.getTemplate(templateName);
- }
- } catch (IOException e) {
- throw new RuntimeException("Failed to load template: " + templateName, e);
- }
- }
-
private static Map<String, Object> dataModel(
DataSources dataSources,
Supplier<Map<String, Object>> parameterModelSupplier,
@@ -153,27 +153,55 @@
return result;
}
- private static boolean isAbsoluteTemplateFile(Settings settings) {
- final File file = new File(settings.getTemplateName());
- return file.isAbsolute() && file.exists() & !file.isDirectory();
+ // ==============================================================
+
+ private static Writer writer(TemplateOutput templateOutput) throws IOException {
+ if (templateOutput.getWriter() != null) {
+ return templateOutput.getWriter();
+ }
+
+ final File file = templateOutput.getFile();
+ FileUtils.forceMkdirParent(file);
+ return new BufferedWriter(new FileWriter(file));
}
- private static Template fileTemplate(Settings settings, Configuration configuration) {
- final String templateName = settings.getTemplateName();
- final File templateFile = new File(templateName);
- try {
- final String content = FileUtils.readFileToString(templateFile, settings.getTemplateEncoding());
- return new Template(templateName, content, configuration);
- } catch (IOException e) {
- throw new RuntimeException("Failed to load template: " + templateName, e);
+ /**
+ * Loading FreeMarker templates from absolute paths is not encouraged due to security
+ * concern (see https://freemarker.apache.org/docs/pgui_config_templateloading.html#autoid_42)
+ * which are mostly irrelevant when running on the command line. So we resolve the absolute file
+ * instead of relying on existing template loaders.
+ *
+ * @param configuration FreeMarker configuration
+ * @param templateSource source template to load
+ * @return FreeMarker template
+ */
+ private static Template template(Configuration configuration, TemplateSource templateSource) {
+ switch (templateSource.getOrigin()) {
+ case PATH:
+ return fromTemplatePath(configuration, templateSource);
+ case CODE:
+ return fromTemplateCode(configuration, templateSource);
+ default:
+ throw new IllegalArgumentException("Don't know how to handle: " + templateSource.getOrigin());
}
}
- private static Template interactiveTemplate(Settings settings, Configuration configuration) {
+ private static Template fromTemplatePath(Configuration configuration, TemplateSource templateSource) {
+ final String path = templateSource.getPath();
try {
- return new Template(Location.INTERACTIVE, settings.getInteractiveTemplate(), configuration);
+ return configuration.getTemplate(path);
} catch (IOException e) {
- throw new RuntimeException("Failed to load interactive template", e);
+ throw new RuntimeException("Failed to load template from path: " + path, e);
+ }
+ }
+
+ private static Template fromTemplateCode(Configuration configuration, TemplateSource templateSource) {
+ final String name = templateSource.getName();
+
+ try {
+ return new Template(name, templateSource.getCode(), configuration);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to load template code: " + name, e);
}
}
}
diff --git a/freemarker-generator-cli/src/main/scripts/run-samples.sh b/freemarker-generator-cli/src/main/scripts/run-samples.sh
index c9f335e..c005f09 100755
--- a/freemarker-generator-cli/src/main/scripts/run-samples.sh
+++ b/freemarker-generator-cli/src/main/scripts/run-samples.sh
@@ -155,6 +155,13 @@
$FREEMARKER_CMD -t templates/properties/csv/locker-test-users.ftl site/sample/properties > target/out/locker-test-users.csv || { echo >&2 "Test failed. Aborting."; exit 1; }
#############################################################################
+# Template Directory
+#############################################################################
+
+echo "site/template"
+$FREEMARKER_CMD -t site/template -PNGINX_HOSTNAME=localhost -o target/out/template || { echo >&2 "Test failed. Aborting."; exit 1; }
+
+#############################################################################
# YAML
#############################################################################
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts.md b/freemarker-generator-cli/src/site/markdown/cli/concepts.md
deleted file mode 100644
index dc95664..0000000
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts.md
+++ /dev/null
@@ -1,124 +0,0 @@
-## The Mental Model
-
-* A command line invocation requires 1..n `templates` and 0..n `datasources`
-* A command line invocation is mapped to a series of `transformations`
-* The mapping strategy is either
- * `aggregating`: each `template` yields one output file based on 0..n `datasources`
- * `generating`: each `datasources` yields one output per `template`
-* The `transformation` consists of exactly one `template`, 0..n `datasources` and an `output`
-* An `output` is either written to
- * `stdout`
- * an output file
- * an output directory
-* When the output is written to a directory
- * the structure of the input directory is preserved
- * the file names can be customized using an output mapping
-
-## Aggregation Versus Generation
-
-This distiniction is only relevant if you have more than one `datasource` for a given `template`
-
-* aggregation will invoke the `template` once with all `datasources`
-* generation will invoke the `template` multiple times with only one `datasources`
-
-### Aggregation
-
-A nice example for `aggregation` is the generation of test user documentation with the following directory layout
-
-```text
-.
-|-- data
-| |-- user-products.csv
-| |-- user-transactions.csv
-| `-- users.csv
-`-- templates
- |-- test-user-documentation.html.ftl
- `-- test-user-documentation.md.ftl
-```
-
-We want to transform those three CSV input files into a `Markdown` and `HTML` document copied into an `out` directory
-
-```text
-# Using short options
-> freemarker-cli -t templates -d data -output-dir out
-
-# Using long options
-> freemarker-cli -m aggregate -t templates -d data -output-dir out
-> freemarker-cli --mode aggregate --template templates --datasource data -output-dir out
-```
-
-The invocation would generate the following files
-
-```text
-.
-`-- out
- |-- test-user-documentation.html
- `-- test-user-documentation.md
-```
-
-### Generation
-
-#### Source Code Generation
-
-A good example for `generation` is the creation of souce code, e.g. as provided by the `maven-generator-plugin`
-
-```text
-.
-|-- data
-| |-- ProductDao.java.json
-| |-- TransactionDao.java.json
-| `-- UserDao.java.json
-`-- templates
- `-- generate-dao.ftl
-```
-
-We want to generate three Java files based on JSON files and a single template
-
-```text
-# Using short options
-> freemarker-cli -m generate -t templates -d data -output-dir out
-
-# Using long options
-> freemarker-cli --mode generate --template templates --datasource data -output-dir out
-```
-
-The invocation would generate the following files
-
-```text
-.
-`-- out
- |-- ProductDao.java
- |-- TransactionDao.java
- `-- UserDao.java
-```
-
-#### Configuration File Generations
-
-Another example for `generation` comes from cloud computing, i.e. the generation of configuration files using the following directory layout
-
-```text
-.
-|-- config
-| |-- application.yml
-| `-- nginx.conf
-`-- config.json
-```
-
-We want to generate a set of expanded configuration files
-
-```text
-# Using short options
-> freemarker-cli -m generate -t config -d config.json -output-dir out
-
-# Using long options
-> freemarker-cli --mode generate --template templates --datasource data -output-dir out
-```
-
-which results in the following directory structure
-
-```text
-.
-`-- out
-| |-- application.yml
-| `-- nginx.conf
-```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
new file mode 100644
index 0000000..84647e0
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
@@ -0,0 +1,86 @@
+## DataSources
+
+A `DataSource` consists of lazy-loaded data available in Apache FreeMarker's model (context) - it provides
+
+* a `charset` for reading textual content
+* a `content type`
+* a `name` and a `group`
+* access to textual content directly or using a line iterator
+* access to the data input stream
+
+### Loading A DataSource
+
+A `DataSource` can be loaded from the file system, e.g. as positional command line argument
+
+```
+bin/freemarker-cli -t templates/info.ftl README.md
+
+FreeMarker CLI DataSources
+------------------------------------------------------------------------------
+ [#1], name=README.md, group=default, contentType=text/markdown, charset=UTF-8, length=57,188 Bytes
+ URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/README.md
+```
+
+from an URL
+
+```
+bin/freemarker-cli --data-source xkcd=https://xkcd.com/info.0.json -t templates/info.ftl
+
+FreeMarker CLI DataSources
+------------------------------------------------------------------------------
+ [#1], name=xkcd, group=default, contentType=application/json, charset=UTF-8, length=-1 Bytes
+ URI : https://xkcd.com/info.0.json
+```
+
+or from an environment variable, e.g. `NGINX_CONF` having a JSON payload
+
+```
+export NGINX_CONF='{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}'
+bin/freemarker-cli -t templates/info.ftl -s conf=env:///NGINX_CONF#mimetype=application/json
+
+FreeMarker CLI DataSources
+------------------------------------------------------------------------------
+ [#1], name=conf, group=default, contentType=application/json, charset=UTF-8, length=50 Bytes
+ URI : env:///NGINX_CONF
+```
+
+Of course you can load multiple `DataSources` directly
+
+```
+bin/freemarker-cli -t templates/info.ftl README.md xkcd=https://xkcd.com/info.0.json
+
+FreeMarker CLI DataSources
+------------------------------------------------------------------------------
+ [#1], name=README.md, group=default, contentType=text/markdown, charset=UTF-8, length=57,188 Bytes
+ URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/README.md
+ [#2], name=xkcd, group=default, contentType=application/json, charset=UTF-8, length=-1 Bytes
+ URI : https://xkcd.com/info.0.json
+```
+
+or load them from a directory
+
+```
+bin/freemarker-cli -t templates/info.ftl -s site/sample/
+FreeMarker CLI DataSources
+------------------------------------------------------------------------------
+ [#1], name=combined-access.log, group=default, contentType=text/plain, charset=UTF-8, length=2,068 Bytes
+ URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/site/sample/accesslog/combined-access.log
+ ...
+ [#22], name=swagger-spec.yaml, group=default, contentType=text/yaml, charset=UTF-8, length=17,555 Bytes
+ URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/site/sample/yaml/swagger-spec.yaml
+
+```
+
+which can be combined with `include` and `exclude` filters
+
+```
+bin/freemarker-cli -t templates/info.ftl -s site/sample --data-source-include=*.json
+
+FreeMarker CLI DataSources
+------------------------------------------------------------------------------
+ [#1], name=github-users.json, group=default, contentType=application/json, charset=UTF-8, length=7,168 Bytes
+ URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/site/sample/json/github-users.json
+ [#2], name=swagger-spec.json, group=default, contentType=application/json, charset=UTF-8, length=24,948 Bytes
+ URI : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/site/sample/json/swagger-spec.json
+
+```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
new file mode 100644
index 0000000..966743b
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
@@ -0,0 +1,12 @@
+## Transformation
+
+* A command line invocation requires 1..n `templates` and 0..n `data sources` / `data models`
+* A command line invocation is mapped to a series of `transformations`
+* The `transformation` consists of exactly one `template`, 0..n `data sources` / `data models` and an `output`
+* An `output` is either written to
+ * `stdout`
+ * an output file
+ * an output directory
+* When the output is written to a directory
+ * the structure of the input directory is preserved
+ * a "ftl" file externsion is removed
diff --git a/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md b/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md
new file mode 100644
index 0000000..3181907
--- /dev/null
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/transforming-directories.md
@@ -0,0 +1,126 @@
+## Transforming Directories
+
+FreeMarker CLI supports the transformation of directories
+
+* Transform an input directory recursively into an output directory
+* If a template has a ".ftl" extension this extension will be removed after processing
+* Only a single directory is support
+* Currently no inclusion / exclusion pattern for templates are supported
+
+### Transform Template Directory To STDOUT
+
+```
+bin/freemarker-cli -t site/template/
+# == application.properties ==================================================
+server.name=localhost
+server.logs=/var/log/nginx
+# == nginx-conf =============================================================
+server {
+ listen 80;
+ server_name 127.0.0.1;
+
+ root /usr/share/nginx/www;
+ index index.htm;
+}
+```
+
+### Transform Template Directory To Output Directory
+
+```
+bin/freemarker-cli -t site/template/ -o out; ls -l out
+total 8
+-rw-r--r-- 1 sgoeschl staff 128 May 30 20:02 application.properties
+drwxr-xr-x 3 sgoeschl staff 96 May 30 20:02 nginx
+```
+
+### Pass Parameter On The Command Line
+
+```
+bin/freemarker-cli -t site/template/ -P NGINX_HOSTNAME=localhost
+# == application.properties ==================================================
+server.name=localhost
+server.logs=/var/log/nginx
+# == nginx-conf =============================================================
+server {
+ listen 80;
+ server_name localhost;
+
+ root /usr/share/nginx/www;
+ index index.htm;
+}
+```
+
+### Use Environment Variables
+
+```
+export NGINX_PORT=8080
+bin/freemarker-cli -t site/template/ -m env:///
+# == application.properties ==================================================
+server.name=localhost
+server.logs=/var/log/nginx
+# == nginx-conf =============================================================
+server {
+ listen 8080;
+ server_name 127.0.0.1;
+
+ root /usr/share/nginx/www;
+ index index.htm;
+}
+```
+
+### Use Environment File
+
+```
+echo "NGINX_PORT=8080" > nginx.env
+bin/freemarker-cli -t site/template/ -m nginx.env
+# == application.properties ==================================================
+server.name=localhost
+server.logs=/var/log/nginx
+# == nginx-conf =============================================================
+server {
+ listen 8080;
+ server_name 127.0.0.1;
+
+ root /usr/share/nginx/www;
+ index index.htm;
+}
+```
+
+### Use JSON File
+
+```
+echo '{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}' > nginx.json
+bin/freemarker-cli -t site/template/ -m nginx.json
+# == application.properties ==================================================
+server.name=localhost
+server.logs=/var/log/nginx
+# == nginx-conf =============================================================
+server {
+ listen 8443;
+ server_name localhost;
+
+ root /usr/share/nginx/www;
+ index index.htm;
+}
+
+```
+
+### Use Environment Variable With JSON Payload
+
+```
+export NGINX_CONF='{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}'
+echo $NGINX_CONF
+{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}
+bin/freemarker-cli -t site/template/ -m env:///NGINX_CONF#mimetype=application/json
+# == application.properties ==================================================
+server.name=localhost
+server.logs=/var/log/nginx
+# == nginx-conf =============================================================
+server {
+ listen 8443;
+ server_name localhost;
+
+ root /usr/share/nginx/www;
+ index index.htm;
+}
+```
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/site/markdown/index.md b/freemarker-generator-cli/src/site/markdown/index.md
index 791ab12..b8d50e1 100644
--- a/freemarker-generator-cli/src/site/markdown/index.md
+++ b/freemarker-generator-cli/src/site/markdown/index.md
@@ -2,6 +2,12 @@
### Concepts
-* [User-Supplied Parameters](cli/concepts/user-parameters.html)
* [Named URIs](cli/concepts/named-uris.html)
-* [Data Models](cli/concepts/data-models.html)
\ No newline at end of file
+* [Data Sources](cli/concepts/data-sources.html)
+* [Data Models](cli/concepts/data-models.html)
+* [User-Supplied Parameters](cli/concepts/user-parameters.html)
+* [Transformation](cli/concepts/transformation.html)
+
+### Usage
+
+* [Transforming Directories](cli/usage/transforming-directories.html)
diff --git a/freemarker-generator-cli/src/site/site.xml b/freemarker-generator-cli/src/site/site.xml
index a2157bf..0c6d789 100644
--- a/freemarker-generator-cli/src/site/site.xml
+++ b/freemarker-generator-cli/src/site/site.xml
@@ -18,7 +18,6 @@
<body>
<menu name="Overview">
<item name="Introduction" href="index.html" />
- <item name="Concepts" href="cli/concepts.html" />
</menu>
</body>
</project>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java
index fedc66c..9b2727b 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java
@@ -114,9 +114,15 @@
}
@Test
+ public void shouldTransformTemplateDirectory() throws IOException {
+ assertTrue(execute("-t site/template").contains("server.name=somehost"));
+ assertTrue(execute("-t site/template -PNGINX_HOSTNAME=localhost").contains("server.name=localhost"));
+ }
+
+ @Test
@Ignore("Manual test to check memory consumption and resource handling")
public void shouldCloseAllResources() throws IOException {
- for (int i = 0; i < 5000; i++) {
+ for (int i = 0; i < 500; i++) {
shouldRunInfo();
shouldRunDemoExamples();
shouldRunCsvExamples();
@@ -128,6 +134,7 @@
shouldRunXmlExamples();
shouldRunGrokExamples();
shouldRunInteractiveTemplateExamples();
+ shouldTransformTemplateDirectory();
shouldRunWithExposedEnvironmentVariableExamples();
}
}
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java
index 210f32f..2dbaf2c 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java
@@ -48,7 +48,8 @@
// private static final String CMD = "-b ./src/test -t templates/demo.ftl -m env=./site/sample/properties/user_0001/user.properties";
// private static final String CMD = "-b ./src/test -t templates/demo.ftl -m ./site/sample/properties/user_0001/user.properties";
// private static final String CMD = "-b ./src/test --data-model post=https://jsonplaceholder.typicode.com/posts/2 -t templates/info.ftl";
- private static final String CMD = "-b ./src/test -t templates/info.ftl -P name=value";
+ // private static final String CMD = "-b ./src/test -t templates/info.ftl -P name=value";
+ private static final String CMD = "-P NGINX_PORT=8080 -t ../freemarker-generator-base/src/test/template -t templates/info.ftl";
public static void main(String[] args) {
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java
index 57f2844..800e8be 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java
@@ -101,7 +101,7 @@
public void shouldParseSingleTemplate() {
final Main main = parse("-t", ANY_TEMPLATE);
- assertEquals(ANY_TEMPLATE, main.templateSourceOptions.template);
+ assertEquals(ANY_TEMPLATE, main.templateSourceOptions.templates.get(0));
}
@Test
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
index ad24631..baae451 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
@@ -59,6 +59,8 @@
}
private SettingsBuilder settingsBuilder() {
- return Settings.builder().setTemplateName(ANY_TEMPLATE_NAME).setWriter(new StringWriter());
+ return Settings.builder()
+ .setTemplateNames(singletonList(ANY_TEMPLATE_NAME))
+ .setWriter(new StringWriter());
}
}
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java
index 16032e4..5aa6681 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java
@@ -51,14 +51,14 @@
assertEquals(1, settings.getArgs().size());
assertNotNull(settings.getConfiguration());
- assertEquals(ANY_INCLUDE, settings.getInclude());
+ assertEquals(ANY_INCLUDE, settings.getDataSourceIncludePattern());
assertEquals(ANY_INPUT_ENCODING, settings.getInputEncoding().name());
assertEquals(ANY_OUTPUT_ENCODING, settings.getOutputEncoding().name());
- assertEquals(ANY_OUTPUT_FILE, settings.getOutputFile().getName());
- assertEquals(ANY_TEMPLATE_NAME, settings.getTemplateName());
+ assertEquals(ANY_OUTPUT_FILE, settings.getOutput().getName());
+ assertEquals(ANY_TEMPLATE_NAME, settings.getTemplates().get(0));
assertNotNull(settings.getDataSources());
assertNotNull(settings.getParameters());
- assertNotNull(settings.getSytemProperties());
+ assertNotNull(settings.getSystemProperties());
assertTrue(settings.isReadFromStdin());
assertTrue(settings.isInteractiveTemplate());
assertTrue(settings.isVerbose());
@@ -69,7 +69,7 @@
.isReadFromStdin(true)
.setArgs(ANY_ARGS)
.setConfiguration(ANY_CONFIGURATION)
- .setInclude(ANY_INCLUDE)
+ .setDataSourceIncludePattern(ANY_INCLUDE)
.setInputEncoding(ANY_INPUT_ENCODING)
.setInteractiveTemplate(ANY_INTERACTIVE_TEMPLATE)
.setLocale(ANY_LOCALE)
@@ -78,7 +78,7 @@
.setParameters(ANY_USER_PARAMETERS)
.setDataSources(ANY_SOURCES)
.setSystemProperties(ANY_SYSTEM_PROPERTIES)
- .setTemplateName(ANY_TEMPLATE_NAME)
+ .setTemplateNames(singletonList(ANY_TEMPLATE_NAME))
.setWriter(new StringWriter())
.setVerbose(true);
}
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index f530805..455ebb0 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -1,8 +1,8 @@
The Apache FreeMarker Generator projects provides additional tools to generate textual ouptut using [Apache FreeMarker](https://freemarker.apache.org).
-| Name | Description |
-| --------------------- | ----------------------------------------------------------------- |
-| Base | Common functionality independent from Apache FreeMarker |
-| Tools | Data source processing tools for Apache FreeMarker Generator |
-| CLI | Command-line client for Apache FreeMarker |
-| Maven Plugin | Maven plugin for Apache FreeMarker |
\ No newline at end of file
+| Name | Description |
+| ------------------------------------------------------------- | ----------------------------------------------------------------- |
+| [Base](freemarker-generator-base/index.html) | Common functionality independent from Apache FreeMarker |
+| [Tools](freemarker-generator-tools/index.html) | Data source processing tools for Apache FreeMarker Generator |
+| [CLI](freemarker-generator-cli/index.html) | Command-line client for Apache FreeMarker |
+| [Maven Plugin](freemarker-generator-maven-plugin/index.html) | Maven plugin for Apache FreeMarker |
\ No newline at end of file
diff --git a/travis.sh b/travis.sh
new file mode 100755
index 0000000..e9c3f62
--- /dev/null
+++ b/travis.sh
@@ -0,0 +1,5 @@
+mvn clean install
+cd ./freemarker-generator-cli
+sh ./run-samples.sh
+cd ../freemarker-generator-maven-plugin-sample
+mvn clean package
\ No newline at end of file