
org.nuiton.i18n.plugin.parser.I18nParseMojoSupport Maven / Gradle / Ivy
Show all versions of i18n-maven-plugin Show documentation
/*
* #%L
* I18n :: Maven Plugin
* %%
* Copyright (C) 2007 - 2024 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.i18n.plugin.parser;
import io.ultreia.java4all.i18n.spi.builder.I18nKeySet;
import io.ultreia.java4all.i18n.spi.builder.I18nModule;
import org.apache.maven.plugins.annotations.Parameter;
import org.nuiton.i18n.plugin.I18nMojoSupport;
import org.nuiton.io.FileUpdater;
import org.nuiton.plugin.PluginHelper;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
/**
* Abstract implementation for parsing goal.
*
* @author Tony Chemit - [email protected]
*/
public abstract class I18nParseMojoSupport extends I18nMojoSupport implements I18nParseMojoConfiguration {
/**
* Strict mode to only keep in user i18n detected i18n keys and remove obsolete keys.
*
* Note : By default not active. Use this with care since it can
* delete keys. Moreover if this flag is activated, then all files will be parsed.
*/
@Parameter(property = "i18n.strictMode", defaultValue = "false")
private boolean strictMode;
/** To treat default entry offered by the mojo. */
@Parameter(property = "i18n.treatDefaultEntry", defaultValue = "true")
private boolean treatDefaultEntry;
/** Source entries (src+includes+excludes) to process. */
@Parameter(property = "i18n.entries")
private I18nSourceEntry[] entries;
/**
* Flag to display touched files while parsing.
*
* Note: the value will be always {@code true} if {@link #verbose} is set at {@code true}.
*
* @since 0.9
*/
@Parameter(property = "i18n.showTouchedFiles", defaultValue = "${maven.verbose}")
private boolean showTouchedFiles;
/**
* To force scanning of all sources.
*
* @since 1.2
*/
@Parameter(property = "i18n.force", defaultValue = "false")
private boolean force;
/**
* A regex pattern to accept incoming keys.
*
* Only incoming keys which match the pattern will be kept.
*
* @since 2.5
*/
@Parameter(property = "i18n.acceptKeyFormat")
private String acceptKeyFormat;
private I18nKeySet i18nKeysFile;
private long t0;
private Pattern acceptPattern;
private I18nModule i18nModule;
/**
* Construit une chaine de log formatée.
*
* @param msg le prefix du message
* @param nbFiles le nombre de fichiers actuellement traités
* @param all le temps de traitement de tous les fichiers
* @return la chaine de log formatée
*/
private static String getLogEntry(String msg, int nbFiles, long all) {
long now = System.nanoTime();
String s = msg;
if (all > 0) {
s += String.format("(total time:%s)", PluginHelper.convertTime(now - all));
}
if (nbFiles > 0) {
s += String.format(" ( ~ %s / file)", PluginHelper.convertTime((now - all) / nbFiles));
}
return s;
}
/** @return the outGetter to use for the instance (java.getter,...) */
protected abstract String getOutGetter();
/** @return the default includes to add to directory scanner */
protected abstract String[] getDefaultIncludes();
/** @return the default excludes to add to directory scanner */
protected abstract String[] getDefaultExcludes();
/** @return the default src directory to use in directory scanner */
protected abstract File getDefaultBasedir();
/**
* @param basedir basedir of files to scan
* @param acceptPattern optional pattern to accept incoming keys
* @return a new file parser to be used in the parser consumer parserExecutor
* @since 1.2
*/
public abstract FileParser newFileParser(File basedir, Pattern acceptPattern);
/**
* @param entry the incoming source entry to attach to the file updater
* @return a new file updater to detects files to treate
*/
public abstract FileUpdater newFileUpdater(SourceEntry entry);
boolean isForce() {
return force;
}
@Override
public void init() throws Exception {
super.init();
t0 = System.nanoTime();
i18nModule = I18nModule.forGetter(getProject().getProperties());
i18nKeysFile = i18nModule.getModuleKeySet(getOutGetter());
// check there is something to treate
if ((entries == null || entries.length == 0) && !treatDefaultEntry) {
// nothing to do
throw new IllegalStateException(
"No entry defined and treatDefaultEntry is false, will skip the goal.");
}
if (isVerbose() && entries != null && entries.length > 0) {
if (getLog().isInfoEnabled()) {
getLog().info("detected entries : " + entries.length);
for (SourceEntry e : entries) {
getLog().info(String.format("%s, specific goal ? %s", e.toString(), e.getSpecificGoal()));
}
}
}
if (acceptKeyFormat != null) {
acceptPattern = Pattern.compile(acceptKeyFormat);
}
}
protected Charset getEncoding() {
return i18nModule.getConfiguration().getEncoding();
}
@Override
protected boolean checkSkip() {
boolean result = super.checkSkip();
if (result && !needInvoke(true, false, I18nMojoSupport.getProjectCacheKey(this))) {
getLog().info("Skip - already executed.");
result = false;
}
return result;
}
@Override
protected void doAction() throws IOException {
if (isNotSilent() && strictMode) {
getLog().info("config - strictMode is on (all files will be parsed).");
}
if (isNotSilent() && force) {
getLog().info("config - force is on (all files will be parsed).");
}
if (treatDefaultEntry) {
addDefaultEntry();
}
List treatedFiles = Collections.synchronizedList(new ArrayList<>());
List touchedFiles = Collections.synchronizedList(new ArrayList<>());
for (I18nSourceEntry entry : entries) {
boolean skip = entry.init(this);
if (skip) {
if (isNotSilent() && isVerbose()) {
getLog().info(String.format("skip [%s] - %s", entry, entry.getSkipMessage()));
}
continue;
}
// launch parser for found files
Set files = entry.getFiles();
if (isNotSilent()) {
getLog().info(String.format("start entry %s", entry.toString()));
getLog().info(String.format("%d file(s) to process (among %d files)", files.size(), entry.getFoudFiles()));
}
files.parallelStream().forEach(f -> {
ParserTask parserTask = new ParserTask(this, newFileParser(entry.getBasedir(), acceptPattern), f);
parserTask.run();
parserTask.registerResult(treatedFiles, touchedFiles, getGetterFile());
});
}
if (treatedFiles.isEmpty()) {
if (isNotSilent()) {
getLog().info("Nothing was parsed - all files are up to date.");
}
} else {
if (showTouchedFiles) {
for (File f : touchedFiles) {
getLog().info("touch " + f);
}
}
if (isNotSilent()) {
int i = touchedFiles.size();
int max = treatedFiles.size();
getLog().info(getLogEntry(String.format("Parsing is done. [treated file(s) : %d/%d]", i, max), max, t0));
}
i18nModule.storeModuleKeySet(i18nKeysFile);
}
}
@Override
public boolean isShowTouchedFiles() {
return showTouchedFiles;
}
@Override
public I18nKeySet getGetterFile() {
return i18nKeysFile;
}
boolean isStrictMode() {
return strictMode;
}
/**
* Add the default entry to entries given in configuration.
*
* This is a convinient method to simplify the configuration of the plugin.
*/
private void addDefaultEntry() {
if (isVerbose()) {
getLog().info("add default entry");
}
boolean hasEntries = entries != null && entries.length > 0;
I18nSourceEntry[] tmp =
new I18nSourceEntry[hasEntries ? entries.length + 1 : 1];
if (hasEntries) {
System.arraycopy(entries, 0, tmp, 0, entries.length);
}
tmp[tmp.length - 1] = new I18nSourceEntry();
entries = tmp;
}
public Pattern getAcceptPattern() {
return acceptPattern;
}
}