org.kohsuke.stapler.LocalizerMojo Maven / Gradle / Ivy
package org.kohsuke.stapler;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.model.Resource;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/**
* Alias for stapler:l10n mojo. Left for compatibility.
*
* @author Kohsuke Kawaguchi
* @goal i18n
*/
public class LocalizerMojo extends AbstractMojo {
/**
* The locale to generate properties for.
*
* @parameter expression="${locale}"
* @required
*/
protected String locale;
/**
* The maven project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
protected MavenProject project;
public void execute() throws MojoExecutionException, MojoFailureException {
// create parser
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
parser = spf.newSAXParser();
} catch (SAXException e) {
throw new Error(e); // impossible
} catch (ParserConfigurationException e) {
throw new Error(e); // impossible
}
for( Resource res : (List)project.getResources() ) {
File dir = new File(res.getDirectory());
processDirectory(dir);
}
}
private void process(File file) throws MojoExecutionException {
if(file.isDirectory())
processDirectory(file);
else
if(file.getName().endsWith(".jelly"))
processJelly(file);
}
private void processDirectory(File dir) throws MojoExecutionException {
File[] children = dir.listFiles();
if(children==null) return;
for (File child : children)
process(child);
}
private void processJelly(File file) throws MojoExecutionException {
Set props = findAllProperties(file);
if(props.isEmpty())
return; // nothing to generate here.
String fileName = file.getName();
fileName=fileName.substring(0,fileName.length()-".jelly".length());
fileName+='_'+locale+".properties";
File resourceFile = new File(file.getParentFile(),fileName);
if(resourceFile.exists()) {
Properties resource;
try {
resource = new Properties(resourceFile);
} catch (IOException e) {
throw new MojoExecutionException("Failed to read "+resourceFile,e);
}
// find unnecessary properties = those which are present in the resource file but not in Jelly
HashSet unnecessaries = new HashSet((Set) resource.keySet());
unnecessaries.removeAll(props);
for (String s : unnecessaries)
getLog().warn("Unused property "+s+" in "+resourceFile);
// figure out missing properties
props.removeAll(resource.keySet());
// add NL to the end if necessary
try {
// then add them to the end
RandomAccessFile f = new RandomAccessFile(resourceFile,"rw");
if(f.length()>0) {
// add the terminating line end if needed
f.seek(f.length()-1);
int ch = f.read();
if(!(ch=='\r' || ch=='\n'))
f.write(System.getProperty("line.separator").getBytes());
}
f.close();
} catch (IOException e) {
throw new MojoExecutionException("Failed to write "+resourceFile,e);
}
}
if(props.isEmpty())
return; // no change to make
getLog().info("Updating "+resourceFile);
try {
// then add them to the end
RandomAccessFile f = new RandomAccessFile(resourceFile,"rw");
if(f.length()>0) {
// add the terminating line end if needed
f.seek(f.length()-1);
int ch = f.read();
if(!(ch=='\r' || ch=='\n'))
f.write(System.getProperty("line.separator").getBytes());
}
f.close();
PrintWriter w = new PrintWriter(new FileWriter(resourceFile,true));
for (String p : props) {
w.println(escape(p)+"=");
}
w.close();
} catch (IOException e) {
throw new MojoExecutionException("Failed to write "+resourceFile,e);
}
}
/**
* Escapes the property key in the proper format.
*/
private String escape(String key) {
StringBuilder buf = new StringBuilder(key.length());
for( int i=0; i findAllProperties(File file) throws MojoExecutionException {
getLog().debug("Parsing "+file);
try {
// we'd like to preserve order, but don't want duplicates
final Set properties = new LinkedHashSet();
parser.parse(file,new DefaultHandler() {
private final StringBuilder buf = new StringBuilder();
private Locator locator;
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
findExpressions();
for( int i=0; i=0) exp=exp.substring(0,op);
properties.add(exp);
} else {
Matcher m = RESOURCE_LITERAL_STRING.matcher(exp);
while(m.find()) {
String literal = m.group();
getLog().debug("Found "+literal);
literal = literal.substring(2,literal.length()-1); // unquote and remove '%'
// if parameters follow, remove them
int op = literal.indexOf('(');
if(op>=0) literal=literal.substring(0,op);
properties.add(literal);
}
}
}
});
return properties;
} catch (SAXException e) {
throw new MojoExecutionException("Failed to parse "+file, e);
} catch (IOException e) {
throw new MojoExecutionException("Failed to parse "+file, e);
}
}
SAXParser parser;
// "%...." string literal that starts with '%'
private static final Pattern RESOURCE_LITERAL_STRING = Pattern.compile("(\"%[^\"]+\")|('%[^']+')");
}