org.nuiton.i18n.plugin.parser.AbstractI18nParserMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of i18n-maven-plugin Show documentation
Show all versions of i18n-maven-plugin Show documentation
Maven plugin to deal with i18n stuff in a project, mainly base on the
nuiton-i18n api (but not only).
/*
* #%L
* I18n :: Maven Plugin
*
* $Id$
* $HeadURL$
* %%
* Copyright (C) 2007 - 2010 CodeLutin, Tony Chemit
* %%
* 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 org.apache.maven.plugins.annotations.Parameter;
import org.nuiton.i18n.plugin.AbstractI18nGenerateMojo;
import org.nuiton.i18n.plugin.I18nUtil;
import org.nuiton.io.FileUpdater;
import org.nuiton.io.SortedProperties;
import org.nuiton.plugin.PluginHelper;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.regex.Pattern;
/**
* Abstract implementation for parsing goal.
*
* @author Tony Chemit - [email protected]
*/
public abstract class AbstractI18nParserMojo extends AbstractI18nGenerateMojo implements I18nParserConfiguration {
/** @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 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(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);
/** Directory where to find project i18n files. */
@Parameter(property = "i18n.src", defaultValue = "${basedir}/src/main/resources/i18n", required = true)
protected File src;
/**
* 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")
protected boolean strictMode;
/** Build directory (used to know if files in sources are up-to-date). */
@Parameter(property = "i18n.cp", defaultValue = "${basedir}/target/classes")
protected File cp;
/** To treat default entry offered by the mojo. */
@Parameter(property = "i18n.treateDefaultEntry", defaultValue = "true")
protected boolean treateDefaultEntry;
/** Source entries (src+includes+excludes) to process. */
@Parameter(property = "i18n.entries")
protected 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}")
protected boolean showTouchedFiles;
/**
* Flag to save previous getter in a backup before doing parsing.
*
* Note: by default, do not perform backup (but it was here originaly so let
* it possible...)
*
* @since 1.0.2
*/
@Parameter(property = "i18n.backupGetter", defaultValue = "false")
protected boolean backupGetter;
/**
* To force reparse of all sources.
*
* @since 1.2
*/
@Parameter(property = "i18n.force", defaultValue = "false")
protected 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")
protected String acceptKeyFormat;
protected Pattern acceptPattern;
private SortedProperties result;
protected SortedProperties oldParser;
protected SortedProperties oldLanguage;
protected long t0;
ParserExecutor parserExecutor;
// @Override
// public boolean isStrictMode() {
// return strictMode;
// }
public boolean isForce() {
return force;
}
@Override
public void init() throws Exception {
super.init();
t0 = System.nanoTime();
result = new SortedProperties(encoding);
oldParser = new SortedProperties(encoding);
oldLanguage = new SortedProperties(encoding);
createDirectoryIfNecessary(out);
// // evenements
// if (keysModifier) {
// addParserEvent(KeysModifier.getInstance(
// getKeyModifierStart(), getKeyModifierEnd(), encoding));
// }
// check there is something to treate
if ((entries == null || entries.length == 0) && !treateDefaultEntry) {
// nothing to do
throw new IllegalStateException(
"No entry defined and treateDefaultEntry is false, " +
"will skip the goal.");
}
if (verbose && entries != null && entries.length > 0) {
if (getLog().isInfoEnabled()) {
getLog().info("detected entries : " + entries.length);
for (SourceEntry e : entries) {
getLog().info(e.toString() + ", specific goal ? " +
e.getSpecificGoal());
}
}
}
if (acceptKeyFormat != null) {
acceptPattern = Pattern.compile(acceptKeyFormat);
}
parserExecutor = new ParserExecutor(this);
}
protected boolean onEnterEntry(I18nSourceEntry entry) {
boolean skip = entry.init(this);
return skip;
}
@Override
protected void doAction() throws Exception {
if (!silent && strictMode) {
getLog().info("config - strictMode is on (all files will be" +
" parsed).");
}
if (!silent && force) {
getLog().info("config - force is on (all files will be" +
" parsed).");
}
// Reprise sur un ancien parsing
File oldParserFile = getGetterFile(out, getOutGetter(), true);
File saveFile = getBackupFile(oldParserFile);
oldParser.load(oldParserFile);
if (backupGetter) {
backupFile(oldParserFile);
}
// Anciennes cles disponnibles
//fixme : pourquoi on utilise un bundle precis ? le premier ici,
// je ne comprends pas
File oldLanguageFile = I18nUtil.getI18nFile(src, artifactId, locales[0], true);
oldLanguage.load(oldLanguageFile);
// Parsing
if (treateDefaultEntry) {
addDefaultEntry();
}
for (I18nSourceEntry entry : entries) {
boolean skip = onEnterEntry(entry);
if (skip) {
if (!silent && verbose) {
getLog().info("skip [" + entry + "] - " + entry.getSkipMessage());
}
continue;
}
// launch parser for found files
String[] files = entry.getFiles();
if (!silent) {
getLog().info("start entry " + entry.toString());
getLog().info(files.length + " file(s) to process (among " +
entry.getFoudFiles() + " files)");
}
for (String file1 : files) {
String fileName = entry.getBasedir().getAbsolutePath() +
File.separator + file1;
File file = new File(fileName);
parserExecutor.addFile(newFileParser(acceptPattern), file);
}
}
if (getLog().isDebugEnabled()) {
getLog().debug("ask to terminate " + parserExecutor);
}
// all files are send to parserExecutor, we ask termination of parserExecutor.
// this termination treat all sending file before really stop
parserExecutor.terminatesAndWaits();
List treadedFiles = parserExecutor.getTreatedFiles();
List touchedFiles = parserExecutor.getTouchedFiles();
// Suppression du fichier sauvegarder
if (!backupGetter) {
deleteFile(saveFile);
}
if (treadedFiles.isEmpty()) {
if (!silent) {
getLog().info("Nothing was parsed - all files are up to date.");
}
} else {
if (showTouchedFiles) {
for (File f : touchedFiles) {
getLog().info("touch " + f);
}
}
if (!silent) {
int i = touchedFiles.size();
int max = treadedFiles.size();
getLog().info(getLogEntry(
"Parsing is done. [treated file(s) : " + i + '/' +
max + "]", max, 0, t0));
}
// save getter
saveGetterFile();
// add getter
addGetter();
}
parserExecutor.clear();
}
@Override
public boolean isShowTouchedFiles() {
return showTouchedFiles;
}
@Override
public SortedProperties getResult() {
return result;
}
public 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.
*/
protected void addDefaultEntry() {
if (verbose) {
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;
}
/**
* Save the result in the getter file.
*
* @throws IOException if any io pb
*/
protected void saveGetterFile() throws IOException {
File getterFile = getGetterFile(out, getOutGetter(), false);
result.store(getterFile);
}
/**
* Construit une chaine de log formatée.
*
* @param msg le prefix du message
* @param nbFiles le nombre de fichiers actuellement traités
* @param time le time de traitement de ce fichier
* @param all le temps de traitement de tous les fichiers
* @return la chaine de log formatée
*/
public static String getLogEntry(String msg,
int nbFiles,
long time,
long all) {
long now = System.nanoTime();
long delta = now - time;
String s = msg;
if (time > 0 && all == 0) {
s += " (" + PluginHelper.convertTime(delta) + ")";
}
if (all > 0) {
s += "(total time:" + PluginHelper.convertTime(now - all) + ")";
}
if (nbFiles > 0) {
s += " ( ~ " +
PluginHelper.convertTime((now - all) / nbFiles) + " / file)";
}
return s;
}
}