You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by sg...@apache.org on 2020/07/01 06:18:12 UTC
[freemarker-generator] branch master updated: FREEMARKER-149
Support multiple template transformation on the command line (#17)
This is an automated email from the ASF dual-hosted git repository.
sgoeschl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/freemarker-generator.git
The following commit(s) were added to refs/heads/master by this push:
new b27c6ba FREEMARKER-149 Support multiple template transformation on the command line (#17)
b27c6ba is described below
commit b27c6ba7ceefbaafed91182fbb0fd32223149303
Author: Siegfried Goeschl <si...@gmail.com>
AuthorDate: Wed Jul 1 08:18:05 2020 +0200
FREEMARKER-149 Support multiple template transformation on the command line (#17)
---
.../generator/base/datasource/DataSources.java | 2 +-
.../generator/base/file/RecursiveFileSupplier.java | 6 +-
.../generator/base/template/TemplateOutput.java | 8 +++
.../base/template/TemplateTransformation.java | 8 +++
.../template/TemplateTransformationsBuilder.java | 34 ++++++----
.../freemarker/generator/base/uri/NamedUri.java | 2 +-
.../freemarker/generator/base/util/ListUtils.java | 4 ++
freemarker-generator-cli/CHANGELOG.md | 8 ++-
freemarker-generator-cli/README.md | 29 ++++----
freemarker-generator-cli/pom.xml | 2 +
.../org/apache/freemarker/generator/cli/Main.java | 42 +++++++-----
.../freemarker/generator/cli/config/Settings.java | 30 ++++----
.../freemarker/generator/cli/config/Suppliers.java | 2 +-
.../markdown/cli/advanced/cli-configuration.md | 2 +-
.../site/markdown/cli/concepts/template-loading.md | 2 +-
.../site/markdown/cli/concepts/transformation.md | 74 ++++++++++++++++++--
.../markdown/cli/introduction/getting-started.md | 79 +++++++++++-----------
.../freemarker/generator/cli/ExamplesTest.java | 17 ++++-
.../freemarker/generator/cli/ManualTest.java | 3 +-
.../freemarker/generator/cli/PicocliTest.java | 8 +++
.../generator/cli/config/SettingsTest.java | 5 +-
.../generator/tools/excel/ExcelTool.java | 2 +-
22 files changed, 247 insertions(+), 122 deletions(-)
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java
index 9db5552..62838a1 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSources.java
@@ -124,7 +124,7 @@ public class DataSources implements Closeable {
* Find data sources based on their group and and globbing pattern.
*
* @param wildcard the wildcard string to match against
- * @return list of mathching data sources
+ * @return list of matching data sources
*/
public List<DataSource> findByGroup(String wildcard) {
return dataSources.stream()
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 ef60fe7..d532df8 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
@@ -53,7 +53,7 @@ public class RecursiveFileSupplier implements Supplier<List<File>> {
/** File filter to apply */
private final IOFileFilter fileFilter;
- /** Diectory filter to apply */
+ /** Directory filter to apply */
private final IOFileFilter directoryFilter;
public RecursiveFileSupplier(Collection<String> sources, Collection<String> includes, Collection<String> excludes) {
@@ -119,10 +119,10 @@ public class RecursiveFileSupplier implements Supplier<List<File>> {
return emptyList();
}
- return excludes.stream().map(RecursiveFileSupplier::exludeFilter).collect(toList());
+ return excludes.stream().map(RecursiveFileSupplier::excludeFilter).collect(toList());
}
- private static IOFileFilter exludeFilter(String exclude) {
+ private static IOFileFilter excludeFilter(String exclude) {
return isEmpty(exclude) ?
VISIBLE :
new NotFileFilter(new OrFileFilter(new WildcardFileFilter(exclude), HIDDEN));
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
index 426c0f1..818d66d 100644
--- 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
@@ -75,6 +75,14 @@ public class TemplateOutput {
return writer != null ? writer : fileWriter();
}
+ @Override
+ public String toString() {
+ return "TemplateOutput{" +
+ "writer=" + writer +
+ ", file=" + file +
+ '}';
+ }
+
private FileWriter fileWriter() {
Validate.notNull(file, "Output file is null");
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
index b13a799..8c19478 100644
--- 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
@@ -41,4 +41,12 @@ public class TemplateTransformation {
public TemplateOutput getTemplateOutput() {
return templateOutput;
}
+
+ @Override
+ public String toString() {
+ return "TemplateTransformation{" +
+ "templateSource=" + templateSource +
+ ", templateOutput=" + templateOutput +
+ '}';
+ }
}
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
index fe62017..c738670 100644
--- 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
@@ -28,6 +28,7 @@ import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonList;
@@ -50,7 +51,7 @@ public class TemplateTransformationsBuilder {
private final List<String> excludes;
/** Optional output file or directory */
- private final List<File> outputs;
+ private final List<String> outputs;
/** Optional user-supplied writer */
private Writer writer;
@@ -73,12 +74,12 @@ public class TemplateTransformationsBuilder {
final List<TemplateTransformation> result = new ArrayList<>();
if (hasInteractiveTemplate()) {
- final File outputFile = outputs.isEmpty() ? null : outputs.get(0);
+ final File outputFile = getOutputFile(0).orElse(null);
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;
+ final File output = getOutputFile(i).orElse(null);
result.addAll(resolve(source, output));
}
}
@@ -133,27 +134,20 @@ public class TemplateTransformationsBuilder {
return this;
}
- public TemplateTransformationsBuilder addOutput(String output) {
- if (StringUtils.isNotEmpty(output)) {
- this.outputs.add(new File(output));
+ public TemplateTransformationsBuilder addOutputs(Collection<String> outputs) {
+ if (outputs != null) {
+ this.outputs.addAll(outputs);
}
return this;
}
- public TemplateTransformationsBuilder addOutput(File output) {
- if (output != null) {
+ public TemplateTransformationsBuilder addOutput(String output) {
+ if (StringUtils.isNotEmpty(output)) {
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;
@@ -252,6 +246,16 @@ public class TemplateTransformationsBuilder {
return template != null;
}
+ private Optional<File> getOutputFile(int i) {
+ if (outputs.isEmpty()) {
+ return Optional.empty();
+ } else if (i < outputs.size()) {
+ return Optional.of(new File(outputs.get(i)));
+ } else {
+ return Optional.of(new File(outputs.get(0)));
+ }
+ }
+
private static File getTemplateOutputFile(File templateDirectory, File templateFile, File outputDirectory) {
final String relativePath = relativePath(templateDirectory, templateFile);
final String relativeOutputFileName = mapExtension(relativePath);
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java
index 45fb595..1b1c63e 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java
@@ -25,7 +25,7 @@ import static org.apache.freemarker.generator.base.util.StringUtils.emptyToNull;
import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty;
/**
- * Caputeres the information of a user-supplied "named URI".
+ * Captures the information of a user-supplied "named URI".
*/
public class NamedUri {
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
index 369bf90..613b3e1 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
@@ -26,6 +26,10 @@ public class ListUtils {
return list == null || list.isEmpty();
}
+ public static <T> boolean isNotEmpty(final List<T> list) {
+ return !isNullOrEmpty(list);
+ }
+
/**
* Transposes the given tabular data, swapping rows with columns.
*
diff --git a/freemarker-generator-cli/CHANGELOG.md b/freemarker-generator-cli/CHANGELOG.md
index 32ab747..70d43a1 100644
--- a/freemarker-generator-cli/CHANGELOG.md
+++ b/freemarker-generator-cli/CHANGELOG.md
@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. We try to a
## 0.1.0-SNAPSHOT
### Added
+* [FREEMARKER-149] Support multiple template transformations on the command line
* [FREEMARKER-144] Proof Of Concept for providing DataFrames
* [FREEMARKER-142] Support Transformation Of Directories
* [FREEMARKER-139] freemarker-cli: Provide GsonTool to align with Maven plugin
@@ -21,11 +22,11 @@ All notable changes to this project will be documented in this file. We try to a
* [FREEMARKER-136] Fix broken `site:stage` build
* [FREEMARKER-134] Rename `Document` to `Datasource` which also changes `--document` to `--datasource`
* [FREEMARKER-129] Use `freemarker.configuration.setting` in `freemarker-cli.properties` to configure FreeMarker
-* [FREEMARKER-129] Provide a `toString()` metheod for all tools
+* [FREEMARKER-129] Provide a `toString()` method for all tools
* [FREEMARKER-129] Use version "0.X.Y" to cater for API changes according to [Semantic Versioning](https://semver.org)
### Fixed
-* [FREEMARKER-147] Complete Maven site documenation
+* [FREEMARKER-147] Complete Maven site documentation
* [FREEMARKER-127] Site build fails with missing "org/apache/maven/doxia/siterenderer/DocumentContent"
[FREEMARKER-127]: https://issues.apache.org/jira/browse/FREEMARKER-127
@@ -39,4 +40,5 @@ All notable changes to this project will be documented in this file. We try to a
[FREEMARKER-142]: https://issues.apache.org/jira/browse/FREEMARKER-142
[FREEMARKER-144]: https://issues.apache.org/jira/browse/FREEMARKER-144
[FREEMARKER-146]: https://issues.apache.org/jira/browse/FREEMARKER-146
-[FREEMARKER-147]: https://issues.apache.org/jira/browse/FREEMARKER-147
\ No newline at end of file
+[FREEMARKER-147]: https://issues.apache.org/jira/browse/FREEMARKER-147
+[FREEMARKER-149]: https://issues.apache.org/jira/browse/FREEMARKER-149
\ No newline at end of file
diff --git a/freemarker-generator-cli/README.md b/freemarker-generator-cli/README.md
index 097a4b5..acfcc67 100644
--- a/freemarker-generator-cli/README.md
+++ b/freemarker-generator-cli/README.md
@@ -8,26 +8,27 @@ This module provides provides the CLI for `Apache FreeMarker`.
Now you can have a look at the command line options
-```
+```text
freemarker-cli -h
Usage: freemarker-cli (-t=<templates> [-t=<templates>]... |
-i=<interactiveTemplate>) [-hV] [--stdin] [-b=<baseDir>]
- [--config=<configFile>] [--data-source-exclude=<exclude>]
- [--data-source-include=<include>] [-e=<inputEncoding>]
- [-l=<locale>] [-o=<outputFile>]
+ [--config=<configFile>]
+ [--data-source-exclude=<dataSourceExcludePattern>]
+ [--data-source-include=<dataSourceIncludePattern>]
+ [-e=<inputEncoding>] [-l=<locale>]
[--output-encoding=<outputEncoding>] [--times=<times>]
[-D=<String=String>]... [-m=<dataModels>]...
- [-P=<String=String>]... [-s=<dataSources>]...
- [<sources>...]
+ [-o=<outputs>]... [-P=<String=String>]...
+ [-s=<dataSources>]... [<sources>...]
Apache FreeMarker CLI
[<sources>...] data source files and/or directories
- -b, --basedir=<baseDir> optional template base directory
+ -b, --basedir=<baseDir> additional template base directory
--config=<configFile> FreeMarker CLI configuration file
-D, --system-property=<String=String>
set system property
- --data-source-exclude=<exclude>
+ --data-source-exclude=<dataSourceExcludePattern>
file exclude pattern for data sources
- --data-source-include=<include>
+ --data-source-include=<dataSourceIncludePattern>
file include pattern for data sources
-e, --input-encoding=<inputEncoding>
encoding of data source
@@ -37,30 +38,30 @@ Apache FreeMarker CLI
-l, --locale=<locale> locale being used for the output, e.g. 'en_US'
-m, --data-model=<dataModels>
data model used for rendering
- -o, --output=<outputFile> output file or directory
+ -o, --output=<outputs> output files or directories
--output-encoding=<outputEncoding>
encoding of output, e.g. UTF-8
-P, --param=<String=String>
set parameter
-s, --data-source=<dataSources>
- data source used for redering
+ data source used for rendering
--stdin read data source from stdin
-t, --template=<templates>
- template to process
+ templates to process
--times=<times> re-run X times for profiling
-V, --version Print version information and exit.
```
Check the version of the `Apache FreeMarker CLI`
-```
+```text
freemarker-cli -V
version=0.1.0-SNAPSHOT, time=2020-06-25T21:48:02+0200, commit=b320d00094be8789086ad6153d9d3fcaf4b8c75f
```
Or run the examples
-```
+```text
./run-examples.sh
templates/info.ftl
examples/templates/demo.ftl
diff --git a/freemarker-generator-cli/pom.xml b/freemarker-generator-cli/pom.xml
index 81ee0ac..20d7ce2 100644
--- a/freemarker-generator-cli/pom.xml
+++ b/freemarker-generator-cli/pom.xml
@@ -73,6 +73,8 @@
<target>
<copy file="CHANGELOG.md" todir="./target/appassembler" />
<copy file="README.md" todir="./target/appassembler" />
+ <copy file="LICENSE" todir="./target/appassembler" />
+ <copy file="NOTICE" todir="./target/appassembler" />
<copy file="./src/main/scripts/run-examples.sh" todir="./target/appassembler" />
<copy todir="./target/appassembler/templates">
<fileset dir="templates" />
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 7e86f85..8b3b853 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
@@ -18,7 +18,7 @@ package org.apache.freemarker.generator.cli;
import org.apache.freemarker.generator.base.parameter.ParameterModelSupplier;
import org.apache.freemarker.generator.base.util.ClosableUtils;
-import org.apache.freemarker.generator.base.util.StringUtils;
+import org.apache.freemarker.generator.base.util.ListUtils;
import org.apache.freemarker.generator.cli.config.Settings;
import org.apache.freemarker.generator.cli.picocli.GitVersionProvider;
import org.apache.freemarker.generator.cli.task.FreeMarkerTask;
@@ -59,7 +59,7 @@ public class Main implements Callable<Integer> {
TemplateSourceOptions templateSourceOptions;
public static final class TemplateSourceOptions {
- @Option(names = { "-t", "--template" }, description = "template to process")
+ @Option(names = { "-t", "--template" }, description = "templates to process")
public List<String> templates;
@Option(names = { "-i", "--interactive" }, description = "interactive template to process")
@@ -81,8 +81,8 @@ public class Main implements Callable<Integer> {
@Option(names = { "-m", "--data-model" }, description = "data model used for rendering")
List<String> dataModels;
- @Option(names = { "-o", "--output" }, description = "output file or directory")
- String outputFile;
+ @Option(names = { "-o", "--output" }, description = "output files or directories")
+ List<String> outputs;
@Option(names = { "-P", "--param" }, description = "set parameter")
Map<String, String> parameters;
@@ -94,10 +94,10 @@ public class Main implements Callable<Integer> {
String configFile;
@Option(names = { "--data-source-include" }, description = "file include pattern for data sources")
- String include;
+ String dataSourceIncludePattern;
@Option(names = { "--data-source-exclude" }, description = "file exclude pattern for data sources")
- String exclude;
+ String dataSourceExcludePattern;
@Option(names = { "--output-encoding" }, description = "encoding of output, e.g. UTF-8", defaultValue = "UTF-8")
String outputEncoding;
@@ -174,13 +174,13 @@ public class Main implements Callable<Integer> {
final FreeMarkerTask freeMarkerTask = new FreeMarkerTask(settings);
return freeMarkerTask.call();
} finally {
- if (settings.hasOutputFile()) {
+ if (settings.hasOutputs()) {
ClosableUtils.closeQuietly(settings.getWriter());
}
}
}
- private void validate() {
+ void validate() {
// "-d" or "--data-source" parameter shall not contain wildcard characters
if (dataSources != null) {
for (String source : dataSources) {
@@ -189,6 +189,16 @@ public class Main implements Callable<Integer> {
}
}
}
+
+ // does the templates match the expected outputs?!
+ // -) no output means it goes to stdout
+ // -) for each template there should be an output
+ final List<String> templates = templateSourceOptions.templates;
+ if (templates != null && templates.size() > 1) {
+ if (outputs != null && outputs.size() != templates.size()) {
+ throw new ParameterException(spec.commandLine(), "Template output does not match specified templates");
+ }
+ }
}
private Settings settings(Properties configuration, List<File> templateDirectories) {
@@ -198,28 +208,28 @@ public class Main implements Callable<Integer> {
.isReadFromStdin(readFromStdin)
.setArgs(args)
.setConfiguration(configuration)
- .setDataSourceIncludePattern(include)
- .setDataSourceExcludePattern(exclude)
+ .setDataModels(dataModels)
+ .setDataSources(getCombinedDataSources())
+ .setDataSourceIncludePattern(dataSourceIncludePattern)
+ .setDataSourceExcludePattern(dataSourceExcludePattern)
.setInputEncoding(inputEncoding)
.setInteractiveTemplate(templateSourceOptions.interactiveTemplate)
.setLocale(locale)
.setOutputEncoding(outputEncoding)
- .setOutputFile(outputFile)
+ .setOutputs(outputs)
.setParameters(parameterModelSupplier.get())
- .setDataSources(getCombinedDataSources())
- .setDataModels(dataModels)
.setSystemProperties(systemProperties != null ? systemProperties : new Properties())
.setTemplateDirectories(templateDirectories)
.setTemplateNames(templateSourceOptions.templates)
- .setWriter(writer(outputFile, outputEncoding))
+ .setWriter(writer(outputs, outputEncoding))
.build();
}
- private Writer writer(String outputFile, String outputEncoding) {
+ private Writer writer(List<String> outputFiles, String outputEncoding) {
try {
if (userSuppliedWriter != null) {
return userSuppliedWriter;
- } else if (StringUtils.isEmpty(outputFile)) {
+ } else if (ListUtils.isNullOrEmpty(outputFiles)) {
return new BufferedWriter(new OutputStreamWriter(System.out, outputEncoding));
} else {
return null;
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 16dc76f..245a2a8 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
@@ -17,6 +17,7 @@
package org.apache.freemarker.generator.cli.config;
import org.apache.freemarker.generator.base.FreeMarkerConstants.Model;
+import org.apache.freemarker.generator.base.util.ListUtils;
import org.apache.freemarker.generator.base.util.LocaleUtils;
import org.apache.freemarker.generator.base.util.NonClosableWriterWrapper;
@@ -74,8 +75,8 @@ public class Settings {
/** Enable verbose mode (currently not used) **/
private final boolean verbose;
- /** Optional output file or directory if not written to stdout */
- private final File output;
+ /** Optional output files or directories if not written to stdout */
+ private final List<String> outputs;
/** Optional include pattern for recursive directly search of data source files */
private final String dataSourceIncludePattern;
@@ -115,7 +116,7 @@ public class Settings {
Charset inputEncoding,
Charset outputEncoding,
boolean verbose,
- File output,
+ List<String> outputs,
String dataSourceIncludePattern,
String dataSourceExcludePattern,
Locale locale,
@@ -138,7 +139,7 @@ public class Settings {
this.inputEncoding = inputEncoding;
this.outputEncoding = outputEncoding;
this.verbose = verbose;
- this.output = output;
+ this.outputs = outputs;
this.dataSourceIncludePattern = dataSourceIncludePattern;
this.dataSourceExcludePattern = dataSourceExcludePattern;
this.locale = requireNonNull(locale);
@@ -199,8 +200,8 @@ public class Settings {
return verbose;
}
- public File getOutput() {
- return output;
+ public List<String> getOutputs() {
+ return outputs;
}
public String getDataSourceIncludePattern() {
@@ -235,8 +236,8 @@ public class Settings {
return userSystemProperties;
}
- public boolean hasOutputFile() {
- return output != null;
+ public boolean hasOutputs() {
+ return ListUtils.isNotEmpty(outputs);
}
public Writer getWriter() {
@@ -277,7 +278,7 @@ public class Settings {
", inputEncoding=" + inputEncoding +
", outputEncoding=" + outputEncoding +
", verbose=" + verbose +
- ", outputFile=" + output +
+ ", outputs=" + outputs +
", include='" + dataSourceIncludePattern + '\'' +
", exclude='" + dataSourceExcludePattern + '\'' +
", locale=" + locale +
@@ -298,7 +299,7 @@ public class Settings {
private String inputEncoding;
private String outputEncoding;
private boolean verbose;
- private String outputFile;
+ private List<String> outputs;
private String dataSourceIncludePattern;
private String dataSourceExcludePattern;
private String locale;
@@ -380,8 +381,10 @@ public class Settings {
return this;
}
- public SettingsBuilder setOutputFile(String outputFile) {
- this.outputFile = outputFile;
+ public SettingsBuilder setOutputs(List<String> outputs) {
+ if (outputs != null) {
+ this.outputs = outputs;
+ }
return this;
}
@@ -449,7 +452,6 @@ public class Settings {
final Charset inputEncoding = Charset.forName(this.inputEncoding);
final Charset outputEncoding = Charset.forName(this.outputEncoding);
final String currLocale = locale != null ? locale : getDefaultLocale();
- final File currOutputFile = outputFile != null ? new File(outputFile) : null;
return new Settings(
configuration,
@@ -462,7 +464,7 @@ public class Settings {
inputEncoding,
outputEncoding,
verbose,
- currOutputFile,
+ outputs,
dataSourceIncludePattern,
dataSourceExcludePattern,
LocaleUtils.parseLocale(currLocale),
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 54e0758..6412b4d 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
@@ -73,7 +73,7 @@ public class Suppliers {
.addSources(settings.getTemplates())
.addInclude(settings.getTemplateFileIncludePattern())
.addExclude(settings.getTemplateFileExcludePattern())
- .addOutput(settings.getOutput())
+ .addOutputs(settings.getOutputs())
.setWriter(settings.getWriter())
.build();
}
diff --git a/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md b/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md
index cde2cd1..0c3e842 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/advanced/cli-configuration.md
@@ -40,7 +40,7 @@ Changing this file allows to tweak the underlying `Apache FreeMarker Configurati
### Storing User-Specific Templates
-Over the time you will accumalate more and more `Apache FreeMarker` templates - some of them are stored within a project but some of the more general might be free-floating and you don't want to store them in the installation directory.
+Over the time you will accumulate more and more `Apache FreeMarker` templates - some of them are stored within a project but some of the more general might be free-floating and you don't want to store them in the installation directory.
To give those free-floating templates a home `Apache FreeMarker CLI` tries to read templates from `~/freemarker-cli`, e.g.
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md
index f54228e..c512d5c 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/template-loading.md
@@ -40,7 +40,7 @@ and [Template Includes](https://freemarker.apache.org/docs/ref_directive_include
### Free-Style Template Loading
-The previosly described `Template Loaders` do not support absolute template files or arbitraRY URLS - this behaviour
+The previosly described `Template Loaders` do not support absolute template files or arbitrary URLS - this behaviour
stems from security aspects when running `Apache FreeMarker` on the server side. For a command-line tool this is mostly
irrelevant therefore any template file outside of the template loader directories can be loaded
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
index 388a681..73477eb 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
@@ -1,14 +1,74 @@
## Transformation
-The `freemarker-cli` generates text output based on FreeMarker templates and data
+The `freemarker-cli` generates text output based on processing FreeMarker templates and data
* 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
+* A command line invocation is mapped to a series of `template transformations`
+* The `transformation` consists of exactly one `template`, 0..n `data sources` / `data models` written to an `output`
+* The `output` is either written to
* `stdout`
- * an output file
- * an output directory
+ * one or more output files
+ * one or output directories
* When the output is written to a directory
* the structure of the input directory is preserved
- * a `ftl` file externsion is removed
+ * a `ftl` file extension is removed
+
+### Examples
+
+Transforming a single template to a single output file
+
+```
+freemarker-cli \
+-t templates/csv/md/transform.ftl examples/data/csv/contract.csv \
+-o target/contract.md
+```
+
+Transforming multiple templates to multiple output files (1:1 mapping between templates and outputs)
+
+```
+> freemarker-cli \
+-t templates/csv/md/transform.ftl -o target/contract.md \
+-t templates/csv/html/transform.ftl -o target/contract.html \
+examples/data/csv/contract.csv
+
+> tree target
+target
+|-- contract.html
+`-- contract.md
+```
+
+Transforming single template directory to single output directory
+
+```
+> freemarker-cli \
+-t examples/data/template -o target/template1
+
+> tree target
+target
+`-- template1
+ |-- application.properties
+ `-- nginx
+ `-- nginx.conf
+
+
+```
+
+Transforming multiple template directories to multiple output directories
+
+```
+freemarker-cli \
+-t examples/data/template -o target/template1 \
+-t examples/data/template -o target/template2
+
+> tree target
+target
+|-- template1
+| |-- application.properties
+| `-- nginx
+| `-- nginx.conf
+`-- template2
+ |-- application.properties
+ `-- nginx
+ `-- nginx.conf
+
+```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md b/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md
index a288348..e2f0de4 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/introduction/getting-started.md
@@ -36,45 +36,46 @@ version=0.1.0-SNAPSHOT, time=2020-06-25T21:48:02+0200, commit=b320d00094be878908
```
> freemarker-cli -h
-Usage: freemarker-cli (-t=<templates> [-t=<templates>]... |
- -i=<interactiveTemplate>) [-hV] [--stdin] [-b=<baseDir>]
- [--config=<configFile>] [--data-source-exclude=<exclude>]
- [--data-source-include=<include>] [-e=<inputEncoding>]
- [-l=<locale>] [-o=<outputFile>]
- [--output-encoding=<outputEncoding>] [--times=<times>]
- [-D=<String=String>]... [-m=<dataModels>]...
- [-P=<String=String>]... [-s=<dataSources>]...
- [<sources>...]
-Apache FreeMarker CLI
- [<sources>...] data source files and/or directories
- -b, --basedir=<baseDir> optional template base directory
- --config=<configFile> FreeMarker CLI configuration file
- -D, --system-property=<String=String>
- set system property
- --data-source-exclude=<exclude>
- file exclude pattern for data sources
- --data-source-include=<include>
- file include pattern for data sources
- -e, --input-encoding=<inputEncoding>
- encoding of data source
- -h, --help Show this help message and exit.
- -i, --interactive=<interactiveTemplate>
- interactive template to process
- -l, --locale=<locale> locale being used for the output, e.g. 'en_US'
- -m, --data-model=<dataModels>
- data model used for rendering
- -o, --output=<outputFile> output file or directory
- --output-encoding=<outputEncoding>
- encoding of output, e.g. UTF-8
- -P, --param=<String=String>
- set parameter
- -s, --data-source=<dataSources>
- data source used for redering
- --stdin read data source from stdin
- -t, --template=<templates>
- template to process
- --times=<times> re-run X times for profiling
- -V, --version Print version information and exit.
+ Usage: freemarker-cli (-t=<templates> [-t=<templates>]... |
+ -i=<interactiveTemplate>) [-hV] [--stdin] [-b=<baseDir>]
+ [--config=<configFile>]
+ [--data-source-exclude=<dataSourceExcludePattern>]
+ [--data-source-include=<dataSourceIncludePattern>]
+ [-e=<inputEncoding>] [-l=<locale>]
+ [--output-encoding=<outputEncoding>] [--times=<times>]
+ [-D=<String=String>]... [-m=<dataModels>]...
+ [-o=<outputs>]... [-P=<String=String>]...
+ [-s=<dataSources>]... [<sources>...]
+ Apache FreeMarker CLI
+ [<sources>...] data source files and/or directories
+ -b, --basedir=<baseDir> additional template base directory
+ --config=<configFile> FreeMarker CLI configuration file
+ -D, --system-property=<String=String>
+ set system property
+ --data-source-exclude=<dataSourceExcludePattern>
+ file exclude pattern for data sources
+ --data-source-include=<dataSourceIncludePattern>
+ file include pattern for data sources
+ -e, --input-encoding=<inputEncoding>
+ encoding of data source
+ -h, --help Show this help message and exit.
+ -i, --interactive=<interactiveTemplate>
+ interactive template to process
+ -l, --locale=<locale> locale being used for the output, e.g. 'en_US'
+ -m, --data-model=<dataModels>
+ data model used for rendering
+ -o, --output=<outputs> output files or directories
+ --output-encoding=<outputEncoding>
+ encoding of output, e.g. UTF-8
+ -P, --param=<String=String>
+ set parameter
+ -s, --data-source=<dataSources>
+ data source used for rendering
+ --stdin read data source from stdin
+ -t, --template=<templates>
+ templates to process
+ --times=<times> re-run X times for profiling
+ -V, --version Print version information and exit.
```
### The Info Template
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 0c3820c..e66d457 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
@@ -121,12 +121,24 @@ public class ExamplesTest extends AbstractMainTest {
}
@Test
- public void shouldTransformTemplateDirectory() throws IOException {
+ public void shouldTransformSingleTemplateDirectory() throws IOException {
assertTrue(execute("-t examples/data/template").contains("server.name=127.0.0.1"));
assertTrue(execute("-t examples/data/template -PNGINX_HOSTNAME=my.domain.com").contains("server.name=my.domain.com"));
}
@Test
+ public void shouldTransformMultipleTemplateDirectories() throws IOException {
+ assertValid(execute("-t examples/data/template -t examples/data/template"));
+ assertValid(execute("-t examples/data/template -o target/out/template1 -t examples/data/template -o target/out/template2"));
+ }
+
+ @Test
+ public void shouldTransformMultipleTemplates() throws IOException {
+ assertValid(execute("-t templates/csv/md/transform.ftl -t templates/csv/html/transform.ftl examples/data/csv/contract.csv"));
+ assertValid(execute("-t templates/csv/md/transform.ftl -o target/contract.md -t templates/csv/html/transform.ftl -o target/contract.html examples/data/csv/contract.csv"));
+ }
+
+ @Test
@Ignore("Manual test to check memory consumption and resource handling")
public void shouldCloseAllResources() throws IOException {
for (int i = 0; i < 500; i++) {
@@ -141,7 +153,8 @@ public class ExamplesTest extends AbstractMainTest {
shouldRunXmlExamples();
shouldRunGrokExamples();
shouldRunInteractiveTemplateExamples();
- shouldTransformTemplateDirectory();
+ shouldTransformSingleTemplateDirectory();
+ shouldTransformMultipleTemplates();
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 2b7f456..ab10101 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
@@ -24,10 +24,11 @@ import java.util.Arrays;
public class ManualTest {
private static final String SPACE = " ";
- private static final String CMD = "-V";
+ // private static final String CMD = "-V";
// private static final String CMD = "-PCSV_SOURCE_FORMAT=DATAFRAME -t examples/templates/dataframe/example.ftl https://raw.githubusercontent.com/nRo/DataFrame/master/src/test/resources/users.csv";
// private static final String CMD = "-PCSV_SOURCE_WITH_HEADER=false -PCSV_SOURCE_FORMAT=DEFAULT -PCSV_TARGET_FORMAT=EXCEL -PCSV_TARGET_WITH_HEADER=true -t templates/csv/csv/transform.ftl examples/data/csv/contract.csv";
// private static final String CMD = "-t examples/templates/json/dataframe/github-users.ftl examples/data/json/github-users.json";
+ private static final String CMD = "-t templates/csv/md/transform.ftl -o target/contract.md -t templates/csv/html/transform.ftl examples/data/csv/contract.csv";
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 800e8be..34077d5 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
@@ -18,6 +18,7 @@ package org.apache.freemarker.generator.cli;
import org.junit.Test;
import picocli.CommandLine;
+import picocli.CommandLine.ParameterException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -111,6 +112,13 @@ public class PicocliTest {
assertEquals(INTERACTIVE_TEMPLATE, main.templateSourceOptions.interactiveTemplate);
}
+ @Test(expected = ParameterException.class)
+ public void shouldThrowParameterExceptionForMismatchedTemplateOutput() {
+ final Main main = parse("-t", "foo.ftl", "-t", "bar.ftl", "-o", "foo.out");
+
+ main.validate();
+ }
+
private static Main parse(String... args) {
final Main main = new Main();
new CommandLine(main).parseArgs(args);
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 90c7696..cbd838a 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
@@ -20,6 +20,7 @@ import org.apache.freemarker.generator.cli.config.Settings.SettingsBuilder;
import org.junit.Test;
import java.io.StringWriter;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -54,7 +55,7 @@ public class SettingsTest {
assertEquals(ANY_INCLUDE, settings.getDataSourceIncludePattern());
assertEquals(ANY_INPUT_ENCODING, settings.getInputEncoding().name());
assertEquals(ANY_OUTPUT_ENCODING, settings.getOutputEncoding().name());
- assertEquals(ANY_OUTPUT_FILE, settings.getOutput().getName());
+ assertEquals(ANY_OUTPUT_FILE, settings.getOutputs().get(0));
assertEquals(ANY_TEMPLATE_NAME, settings.getTemplates().get(0));
assertNotNull(settings.getDataSources());
assertNotNull(settings.getUserParameters());
@@ -74,7 +75,7 @@ public class SettingsTest {
.setInteractiveTemplate(ANY_INTERACTIVE_TEMPLATE)
.setLocale(ANY_LOCALE)
.setOutputEncoding(ANY_OUTPUT_ENCODING)
- .setOutputFile(ANY_OUTPUT_FILE)
+ .setOutputs(Collections.singletonList(ANY_OUTPUT_FILE))
.setParameters(ANY_USER_PARAMETERS)
.setDataSources(ANY_SOURCES)
.setSystemProperties(ANY_SYSTEM_PROPERTIES)
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
index d9bb473..406a927 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
@@ -154,7 +154,7 @@ public class ExcelTool {
* See https://stackoverflow.com/questions/15710888/reading-time-values-from-spreadsheet-using-poi-api.
*
* @param cell Cell containing some sort of date or time
- * @return The corresponding Java istance
+ * @return The corresponding Java instance
*/
private static synchronized Object toDateCellValue(Cell cell) {
final Date date = cell.getDateCellValue();