org.nuiton.eugene.plugin.GenerateMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eugene-maven-plugin Show documentation
Show all versions of eugene-maven-plugin Show documentation
Maven plugin to use the eugene library
/*
* #%L
* EUGene :: Maven plugin
* %%
* Copyright (C) 2006 - 2017 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.eugene.plugin;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.settings.Settings;
import org.nuiton.eugene.DefaultTemplateConfiguration;
import org.nuiton.eugene.LogProxy;
import org.nuiton.eugene.ModelHelper;
import org.nuiton.eugene.ModelReader;
import org.nuiton.eugene.Template;
import org.nuiton.eugene.models.Model;
import org.nuiton.eugene.models.object.reader.InvalidModelPropertiesException;
import org.nuiton.eugene.plugin.writer.BaseChainedFileWriter;
import org.nuiton.eugene.plugin.writer.BaseChainedFileWriterToMemoryModel;
import org.nuiton.eugene.plugin.writer.XmiChainedFileWriter;
import org.nuiton.eugene.writer.ChainedFileWriter;
import org.nuiton.eugene.writer.ChainedFileWriterConfiguration;
import org.nuiton.eugene.writer.ChainedFileWriterData;
import org.nuiton.eugene.writer.ChainedFileWriterEntry;
import org.nuiton.eugene.writer.ChainedFileWriterToMemoryModel;
import org.nuiton.eugene.writer.ChainedWriterEngine;
import org.nuiton.eugene.writer.WriterReport;
import org.nuiton.plugin.AbstractPlugin;
import org.nuiton.plugin.PluginWithEncoding;
import org.nuiton.util.StringUtil;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Eugene generator plugin (a.k.a generate mojo)
*
* Fill inputs and mojo will chained needed writer.
*
* @author Tony Chemit - [email protected]
* @since 2.5
*/
@Mojo(name = "generate", requiresDependencyResolution = ResolutionScope.COMPILE)
public class GenerateMojo extends AbstractPlugin implements ChainedFileWriterConfiguration, PluginWithEncoding, LogProxy {
/**
* Inputs files to used to generate the required model files.
*
* An include has the following pattern :
*
* writer:
*
* when you want to use a specific writer with his default io values.
*
* Can also write :
*
* [writer:]directory:includes
*
* where {@code includes} is the pattern to find files from the directory
* given and must be terminated by the extension of files.
*
* Specifying the {@code writer} can be usefull when you want to use a
* writer for an unknown extension by any writer.
*
* Example :
*
* <inputs>
* <input>zargo:</input>
* <input>src/main/xmi2:**\/*.zargo</input>
* <input>zargo:src/main/xmi:**\/*.zargo2</input>
* </inputs>
*
*
* Note: If your using a single input, you can just write :
*
* <inputs>zargo</inputs>
*
*
* @since 2.0.0
*/
@Parameter(property = "eugene.inputs", required = true)
protected String[] inputs;
/**
* List of input (protocol) not to treate separated by comma.
*
* Example :
*
* <skipInputs>xmi</skipInputs>
* <skipInputs>xmi,model</skipInputs>
*
*
* @since 2.0.0
*/
@Parameter(property = "eugene.skipInputs")
protected String skipInputs;
/**
* Where to generate files.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.outputDirectory", defaultValue = "target/generated-sources", required = true)
protected File outputDirectory;
/**
* Where to copy extracted files (when using class-path data).
*
* @since 2.1.3
*/
@Parameter(property = "eugene.extractDirectory", defaultValue = "target/extracted-sources", required = true)
protected File extractDirectory;
/**
* Ecrase les fichiers générés.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.overwrite", defaultValue = "false")
protected boolean overwrite;
/**
* Pour activer le mode verbeux.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.verbose", defaultValue = "${maven.verbose}")
protected boolean verbose;
/**
* Encoding to be used for generation of files.
*
* Note: If nothing is filled here, we will use the system
* property {@code file.encoding}.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.encoding", defaultValue = "${project.build.sourceEncoding}")
protected String encoding;
/**
* A flag to mark the mojo to be used in a test phase. This will permits
* to add generated sources in test compile roots.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.testPhase", defaultValue = "false")
protected boolean testPhase;
/**
* The type of model to be used.
*
* By default, use an {@code objectmodel}.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.modelType", defaultValue = "objectmodel", required = true)
protected String modelType;
/**
* Properties to pass to writer.
*
* @since 2.0.0
*/
@Parameter
protected Map properties;
/**
* Ne génère rien, analyse juste la configuration.
*
* @since 2.0.0
*/
@Parameter(property = "eugene.dryRun", defaultValue = "false")
protected boolean dryRun;
/**
* Nom du paquetage pour les fichiers générés (xmi input sepcific).
*
* @since 2.0.0
*/
@Parameter(property = "generator.fullPackagePath", defaultValue = "${project.groupId}.${project.artifactId}")
protected String fullPackagePath;
/**
* Nom du resolver a utiliser pour les transformations xmi vers model
* (xmi input sepcific).
*
* @since 2.0.0
*/
@Parameter(property = "generator.resolver", defaultValue = "org.nuiton.util.ResourceResolver")
protected String resolver;
/**
* Templates à utiliser, séparés par des virgules pour les transformations
* depuis les models (model input sepcific).
*
* @since 0.50
*/
@Parameter(property = "eugene.templates")
protected String templates;
/**
* Templates à ne pas utiliser lors de la transformations des models
* (model input sepcific).
*
* @since 0.63
*/
@Parameter(property = "eugene.excludeTemplates")
protected String[] excludeTemplates;
/**
* Nom par défaut du paquetage généré (model input specific).
*
* @since 0.50
*/
@Parameter(property = "eugene.defaultPackage", defaultValue = "${project.groupId}.${project.artifactId}")
protected String defaultPackage;
/**
* List of packages to generate (comma separated). (model input specific).
*
* If the parameter is not filled, will generate all packages.
*
* @since 1.0.0-rc-8
*/
@Parameter(property = "eugene.generatedPackages")
protected String generatedPackages;
/**
* List of package to extract from xmi to models. (model input specific).
*
* If the parameter is not filled, will extract all packages.
*
* @since 1.0.0-rc-8
*/
@Parameter(property = "eugene.extractedPackages", defaultValue = "${project.groupId}.${project.artifactId}")
protected String extractedPackages;
/**
* A flag to fail if model properties is not safe (means some tagValues or stereotypes are not correct).
*
* Note: since version 3.0, the default value is {@code true}.
*
* @since 2.9
*/
@Parameter(property = "eugene.failIfUnsafe", defaultValue = "true")
protected boolean failIfUnsafe;
/**
* To use a new object model extension file.
*
* @since 3.0
*/
@Parameter(property = "eugene.modelExtensionFile")
protected File modelExtensionFile;
/**
* Maven project.
*
* @since 2.0.0
*/
@Parameter(defaultValue = "${project}", readonly = true)
protected MavenProject project;
/**
* Le settings (pour obtenir le mode offline).
*
* @since 2.0.0
*/
@Parameter(defaultValue = "${settings}", readonly = true)
protected Settings settings;
/**
* All available models (obtain by plexus, keys are plexus roles,
* values are a instance of corresponding model).
*/
@Component(role = Model.class)
protected Map _models;
/** All available writers introspects via plexus. */
@Component(role = ChainedFileWriter.class)
protected Map writers;
/** All available writers introspects via plexus. */
@Component(role = ModelReader.class)
protected Map> modelReaders;
/** All available templates introspects via plexus. */
@Component(role = Template.class)
protected Map> modelTemplates;
/** The engine to compute {@link ChainedFileWriter} from inputs entries. */
@Component(role = ChainedWriterEngine.class)
protected ChainedWriterEngine engine;
protected ModelHelper modelHelper;
/** fixed classloader */
protected ClassLoader fixedClassLoader;
protected List> templateList;
protected WriterReport newWriterReport() {
return new WriterReport() {
@Override
public void addFile(String entry, File file, boolean b) {
super.addFile(entry, file, b);
if (b || isVerbose()) {
getLog().info("Will generate " + file);
}
if (getLog().isDebugEnabled()) {
getLog().debug(String.format("[%1$s] Will generate %2$s", entry, file));
}
}
@Override
public void addResource(String entry, File file, boolean b) {
super.addResource(entry, file, b);
if (b || isVerbose()) {
getLog().info("Will copy resource " + file);
}
if (getLog().isDebugEnabled()) {
getLog().debug(String.format("[%1$s] Will copy resource %2$s", entry, file));
}
}
};
}
@Override
protected void init() throws Exception {
if (getLog().isDebugEnabled()) {
verbose = true;
}
modelHelper = new ModelHelper(_models, modelReaders);
modelType = modelType.trim().toLowerCase();
// Check model type is accepted
// pouvoir associé un nom à un type de service).
Model model = modelHelper.getModel(modelType);
// Model model = _models.get(modelType);
if (model == null) {
throw new MojoExecutionException(
"No modelType named '" + modelType + "', use one of " +
_models.keySet()
);
}
if (inputs.length == 0) {
throw new MojoExecutionException(
"Must specify something to include using the includes " +
"property"
);
}
//FIXME-TC20091217 use a configurator in plexus ?
// Actually we obtain a different instance of the mojo conflit with mojo and plexus :)
engine.init(this);
Set availableWriters = engine.getAvailableWriters();
if (availableWriters.isEmpty()) {
throw new MojoExecutionException(
"Could not find any writer in class-path.");
}
for (ChainedFileWriter writer : availableWriters) {
if (writer instanceof BaseChainedFileWriter) {
// add log support
((BaseChainedFileWriter) writer).setLog(getLog());
}
writer.setWriterReport(newWriterReport());
}
// detect top level writers
for (String include : inputs) {
if (isVerbose()) {
getLog().info("Register include : " + include);
}
engine.registerInclude(include);
}
if (engine.getSelectedWriters().isEmpty()) {
return;
}
if (properties == null) {
properties = new LinkedHashMap<>();
}
if (engine.containsWriter("xmi")) {
// add xmi writer support
properties.put(XmiChainedFileWriter.PROP_FULL_PACKAGE_PATH, fullPackagePath);
properties.put(XmiChainedFileWriter.PROP_EXTRACTED_PACKAGES, extractedPackages);
properties.put(XmiChainedFileWriter.PROP_RESOLVER, resolver);
}
if (engine.containsWriter("model")) {
// add model writer support
properties.put(BaseChainedFileWriterToMemoryModel.PROP_FAIL_IF_UNSAFE, failIfUnsafe);
}
// init templates
templateList = initTemplates();
}
@Override
protected boolean checkSkip() {
if (engine.getSelectedWriters().isEmpty()) {
getLog().warn("No phase was detected, skip the goal.");
return false;
}
return true;
}
@Override
protected void doAction() throws Exception {
if (dryRun) {
getLog().warn("dryRun property is set, no file will be generated.");
}
if (isVerbose()) {
if (isTestPhase()) {
getLog().info(" using testPhase");
}
}
try {
List skipInputList = new ArrayList<>();
if (!StringUtils.isEmpty(skipInputs)) {
for (String s : skipInputs.split(",")) {
skipInputList.add(s.trim());
}
}
// launch writers in incoming order of dicovering of them
Set models = new HashSet<>();
for (ChainedFileWriter writer : engine.getSelectedWriters()) {
if (skipInputList.contains(writer.getInputProtocol())) {
getLog().info("Skip phase [" + writer.getInputProtocol() +
"] as required in skipInputs configuration.");
continue;
}
long t0 = System.nanoTime();
getLog().info("Process phase [" + writer.getInputProtocol() + "]");
if (dryRun || isVerbose()) {
for (ChainedFileWriterEntry entry : writer.getEntries()) {
getLog().info(" entry : " + entry);
}
if (dryRun) {
continue;
}
}
if (getLog().isDebugEnabled()) {
getLog().debug("Generating files and copying resources...");
}
// obtains data to react for this writer
ChainedFileWriterData data = engine.getData(writer);
try {
// launch generation
writer.generate(this, data);
} catch (InvalidModelPropertiesException e) {
throw new MojoFailureException("failIfUnsafe flag is on, and some errors occurs while loading model.", e);
}
if (writer instanceof ChainedFileWriterToMemoryModel) {
// keep result
ChainedFileWriterToMemoryModel writerToMemoryModel = (ChainedFileWriterToMemoryModel) writer;
models.add(writerToMemoryModel);
} else {
WriterReport writerReport = writer.getWriterReport();
String messageResources = reportCopiedResources(writerReport);
getLog().info(messageResources);
String message = reportGeneratedFiles(writerReport, t0);
getLog().info(message);
}
}
if (!models.isEmpty()) {
// apply templates
//TODO merge all models in a unique one ? or apply templates on each model ?
long t0 = System.nanoTime();
WriterReport writerReport = newWriterReport();
getLog().info("Process phase [generator]");
for (ChainedFileWriterToMemoryModel entry : models) {
Model model = entry.getModel();
Long lastModified = entry.getLastModifiedSource();
File outputDir = entry.getOutputDirectory();
applyTemplates(model,
lastModified,
outputDir,
templateList,
writerReport);
// must fix source compile roots
fixCompileSourceRoots(outputDir);
}
String message = reportGeneratedFiles(writerReport, t0);
getLog().info(message);
}
} finally {
// always clear everything to avoid side-effects in goal is
// invoked more than once
properties.clear();
engine.clear();
}
}
protected void applyTemplates(Model model,
Long lastModifiedSource,
File outputDirectory,
List> templateList,
WriterReport writerReport) throws IOException {
for (Template template : templateList) {
getLog().info("Apply generator " + template.getClass().getSimpleName());
// set the lastModified source property
template.setProperty(Template.PROP_LAST_MODIFIED_SOURCE, lastModifiedSource);
template.setProperty(Template.PROP_WRITER_REPORT, writerReport);
template.setLog(this);
template.setProperty(Template.PROP_OUTPUT_DIRECTORY, outputDirectory);
if (isVerbose()) {
getLog().info(" overwrite = " + template.isOverwrite());
getLog().info(" encoding = " + template.getEncoding());
getLog().info(" lastModifiedSource = " + template.getLastModifiedSource());
getLog().info(" exclude = " + template.getExcludeTemplates());
getLog().info(" output directory = " + outputDirectory);
}
// apply template
template.applyTemplate(model, outputDirectory);
}
}
/**
* Add a single input to the {@link #inputs} property.
*
* Note: This is a convinient way to allow in pom to write
*
* <inputs>zargo</inputs>
*
* in stead of array notation :
*
* <inputs>
* <input>zargo:</input>
* </inputs>
*
*
* @param inputs unique input to add
*/
public void setInputs(String inputs) {
this.inputs = new String[]{inputs};
}
@Override
public File getOutputDirectory() {
return outputDirectory;
}
@Override
public File getExtractDirectory() {
return extractDirectory;
}
@Override
public Map getProperties() {
return properties;
}
@Override
public ClassLoader getClassLoader() {
try {
return getFixedClassLoader();
} catch (MojoExecutionException e) {
throw new IllegalStateException("could not obtain classLoader", e);
}
}
@Override
public MavenProject getProject() {
return project;
}
@Override
public void setProject(MavenProject project) {
this.project = project;
}
@Override
public boolean isVerbose() {
return verbose;
}
@Override
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
@Override
public String getEncoding() {
return encoding;
}
@Override
public void setEncoding(String encoding) {
this.encoding = encoding;
}
@Override
public boolean isOverwrite() {
return overwrite;
}
@Override
public boolean isOffline() {
return settings.isOffline();
}
@Override
public boolean isTestPhase() {
return testPhase;
}
@Override
public String getModelType() {
return modelType;
}
@Override
public Map getWriters() {
return writers;
}
@Override
public ModelHelper getModelHelper() {
return modelHelper;
}
@Override
public File getBasedir() {
return getProject().getBasedir();
}
@Override
public File getModelExtensionFile() {
return modelExtensionFile;
}
/**
* @return the string representation of excludesTemplates
* (separated by comma)
*/
protected String getExcludeTemplatesAsString() {
String result = "";
for (int i = 0; i < excludeTemplates.length; i++) {
result += excludeTemplates[i];
if (i != excludeTemplates.length - 1) {
result += ",";
}
}
return result;
}
/**
* Prepare le classLoader a utiliser dans le generateur.
*
* Si le mojo est en phase de test {@link #testPhase} a été renseigné,
* target/selectedClasses est rajouté.
*
* Si des références à des sibling modules, ils seront rajoutés aussi.
*
* @return le class loader modifie
* @throws MojoExecutionException if any pb
*/
public ClassLoader getFixedClassLoader() throws MojoExecutionException {
if (fixedClassLoader == null) {
Set urlsAsString = new HashSet<>();
List urls = new ArrayList<>();
try {
ClassLoader loader;
if (testPhase) {
File extraClassPathDirectory = new File(
getProject().getBuild().getOutputDirectory());
if (verbose) {
getLog().info("Add in generator's classLoader : " +
extraClassPathDirectory);
}
addDirectoryToUrlsList(
extraClassPathDirectory,
urls,
urlsAsString
);
addDirectoryToUrlsList(
new File(getProject().getBuild().getTestSourceDirectory()),
urls,
urlsAsString
);
} else {
addDirectoryToUrlsList(
new File(getProject().getBuild().getSourceDirectory()),
urls,
urlsAsString
);
}
if (project.getProjectReferences() != null) {
// this case is for multi-module when calling from a
// parent module
for (Object o :
project.getProjectReferences().entrySet()) {
Map.Entry, ?> entry = (Map.Entry, ?>) o;
MavenProject relatedProject =
(MavenProject) entry.getValue();
if (verbose) {
getLog().info("Add project reference in " +
"generator's classLoader : '" +
relatedProject.getArtifact() + "'");
}
//TODO il faudrait peut-etre aussi ajouter les
//TODO dependances ?
if (relatedProject.getArtifact().getFile() != null) {
addDirectoryToUrlsList(
relatedProject.getArtifact().getFile(),
urls,
urlsAsString
);
}
}
}
if (!project.getArtifacts().isEmpty()) {
// this is a special case when artifacts were resolved
// (for example in site phase)
if (isVerbose()) {
getLog().info(
"Use resolved artifacts to build class-path");
}
for (Object o : project.getArtifacts()) {
Artifact a = (Artifact) o;
if (!a.getScope().equals("provided")) {
addDirectoryToUrlsList(
a.getFile(),
urls,
urlsAsString
);
}
}
}
// we ask to add the directory in classloader
loader = getClass().getClassLoader();
if (isVerbose()) {
getLog().info("original classloader " + loader);
}
if (loader instanceof URLClassLoader) {
// on reinjecte les urls de loader de base
// car sinon on risque de ne pas retrouver les resources...
for (URL u : ((URLClassLoader) loader).getURLs()) {
addUrlToUrlsList(u, urls, urlsAsString);
if (isVerbose()) {
getLog().debug("original cp entry: " + u);
}
}
// et on force l'utilisation du classloader parent
// s'il existe
if (loader.getParent() != null) {
loader = loader.getParent();
}
}
if (!urls.isEmpty()) {
loader = new URLClassLoader(
urls.toArray(new URL[urls.size()]),
loader);
}
if (isVerbose()) {
for (URL u : urls) {
getLog().info("cp entry: " + u);
}
}
fixedClassLoader = loader;
} catch (MalformedURLException e) {
throw new MojoExecutionException(e.getMessage());
} finally {
urls.clear();
urlsAsString.clear();
}
}
return fixedClassLoader;
}
/**
* permet d'ajout le répertoire de génération des fichiers java dans
* les répertoires de compilation du projet Maven.
*
* @param destDirGen le repertoire a traiter
*/
protected void fixCompileSourceRoots(File destDirGen) {
//FIXME-TC20091215 : should never have a null project, this is not
//FIXME-TC20091215 : normal
if (project == null) {
// no project defined, can not fix anything
// this case could appears if we wanted to do some tests of the
// plugin
return;
}
//TODO-TC20091016 should use AbstractPlugin api
if (isTestPhase()) {
if (!project.getTestCompileSourceRoots().contains(
destDirGen.getPath())) {
if (isVerbose()) {
getLog().info("Add test compile source root : " + destDirGen);
}
project.addTestCompileSourceRoot(destDirGen.getPath());
Resource resources = new Resource();
resources.setDirectory(destDirGen.getAbsolutePath());
resources.setExcludes(Collections.singletonList("**/*.java"));
if (isVerbose()) {
getLog().info("Add test resource root :" + resources);
}
project.addTestResource(resources);
}
} else {
if (!project.getCompileSourceRoots().contains(
destDirGen.getPath())) {
if (isVerbose()) {
getLog().info("Add compile source root : " + destDirGen);
}
project.addCompileSourceRoot(destDirGen.getPath());
Resource resources = new Resource();
resources.setDirectory(destDirGen.getAbsolutePath());
resources.setExcludes(Collections.singletonList("**/*.java"));
if (isVerbose()) {
getLog().info("Add resource root :" + resources);
}
project.addResource(resources);
}
}
}
protected List> initTemplates() {
ClassLoader loader = getClassLoader();
Properties templateProperties = new Properties();
templateProperties.put(Template.PROP_DEFAULT_PACKAGE, defaultPackage);
templateProperties.put(Template.PROP_ENCODING, getEncoding());
templateProperties.put(Template.PROP_VERBOSE, verbose);
templateProperties.put(Template.PROP_OVERWRITE, isOverwrite());
templateProperties.put(Template.PROP_CLASS_LOADER, loader);
templateProperties.put(Template.PROP_EXCLUDE_TEMPLATES, getExcludeTemplatesAsString());
if (StringUtils.isEmpty(generatedPackages)) {
if (verbose) {
getLog().info("generating all packages");
}
} else {
templateProperties.put(Template.PROP_GENERATED_PACKAGES,
generatedPackages);
if (verbose) {
getLog().info("generating only for packages " + generatedPackages);
}
}
// init templates
List> templatesList = new ArrayList<>();
if (StringUtils.isNotEmpty(templates)) {
String[] templatesNames = templates.split(",");
for (String templateName : templatesNames) {
// remove trailing spaces
templateName = templateName.trim();
Template template =
(Template) modelTemplates.get(templateName);
if (template == null) {
getLog().warn("template [" + templateName + "] is not " +
"registred via plexus, try to read it directly");
try {
template = (Template) Class.forName(
templateName, true, loader).newInstance();
} catch (Exception e) {
throw new IllegalStateException(
"Can't obtain template [" + templateName +
"] for reason " + e.getMessage(), e
);
}
}
if (verbose) {
getLog().info("will use the template [" + templateName + "]");
}
// will use this template
templatesList.add(template);
// set the properties of the template
template.setConfiguration(
new DefaultTemplateConfiguration(templateProperties));
}
}
return templatesList;
}
protected String reportGeneratedFiles(WriterReport writerReport, long t0) {
String result;
int nbFiles = writerReport.getFilesCount();
if (nbFiles == 0) {
result = "No file generated.";
} else {
long delay = System.nanoTime() - t0;
if (nbFiles == 1) {
result = "Generate one file in " + StringUtil.convertTime(delay) + ".";
} else {
result = "Generate " + nbFiles + " files in " + StringUtil.convertTime(delay) + ".";
}
}
return result;
}
protected String reportCopiedResources(WriterReport writerReport) {
String result;
int nbResources = writerReport.getResourcesCount();
if (nbResources == 0) {
result = "No resources copied.";
} else {
if (nbResources == 1) {
result = "One resource copied.";
} else {
result = nbResources + " resources copied.";
}
// int nbFiles = writerReport.getFilesCount();
// if (nbFiles == 0) {
// result += " (will regenerate all files).";
// }
}
return result;
}
@Override
public void info(String message) {
getLog().info(message);
}
@Override
public void debug(String message) {
getLog().debug(message);
}
@Override
public void warn(String message) {
getLog().warn(message);
}
@Override
public void error(String message) {
getLog().error(message);
}
}