001: package org.tigris.scarab.util.build;
002:
003: /* ================================================================
004: * Copyright (c) 2005 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: import java.io.BufferedWriter;
050: import java.io.File;
051: import java.io.FileWriter;
052: import java.io.IOException;
053: import java.util.Iterator;
054: import java.util.Vector;
055:
056: import org.apache.tools.ant.BuildException;
057: import org.apache.tools.ant.DirectoryScanner;
058: import org.apache.tools.ant.Task;
059: import org.apache.tools.ant.types.FileSet;
060:
061: import org.tigris.scarab.util.build.l10nchecker.L10nInspector;
062: import org.tigris.scarab.util.build.l10nchecker.L10nIssue;
063: import org.tigris.scarab.util.build.l10nchecker.L10nIssueTemplates;
064: import org.tigris.scarab.util.build.l10nchecker.L10nMessage;
065:
066: /**
067: *
068: * Ant task to check for localisation problems.
069: *
070: * <p>Ant parameters:
071: *
072: * <ul>
073: * <li>FileSet: Files to check
074: * <li>messageSet: Set the severity for a particular message.
075: * This is done by setting the attributes <code>error</code> to the
076: * issue that has to be used (e.g. <code>error="CantParseIssue"</code>)
077: * and <code>severity</code> to one of the defined severity levels:
078: * <ul>
079: * <li><strong>ERROR</strong>: This issue will be marked as error
080: * <li><strong>WARNING</strong>: This issue will be marked as error
081: * <li><strong>INFORMATION</strong>: This issue will be marked as error
082: * <li><strong>IGNORED</strong>: This issue will be marked to be
083: * ignored. By default all issues are marked as "IGNORED".
084: * </ul>
085: * <li>reffile: Reference file
086: * <li>verbose: Verbosity:
087: * <ul>
088: * <li>0: Errors only
089: * <li>1: Errors and warnings
090: * <li>2: Errors, warnings and information.
091: * </ul>
092: * <li>outfile: IF given, all output is written to this file
093: * <li>failonerr: Stop after first checked file in case of errors.
094: * </ul>
095: *
096: * In case the output is redirected to a file, summary information is displayed
097: * on the ant output.
098: *
099: * @author sreindl
100: *
101: */
102: public class AntL10AnalysisTask extends Task {
103: /* intput files */
104: private Vector filesets = new Vector();
105:
106: /* message set settings */
107: private Vector messages = new Vector();
108:
109: /* verbosity */
110: private int verbose = 0;
111:
112: private String refFile;
113:
114: private boolean failonerr = false;
115:
116: private String outFileName = null;
117:
118: private BufferedWriter outFile = null;
119:
120: /*
121: * Read all parameters and execute
122: *
123: * @see org.apache.tools.ant.Task#execute()
124: */
125: public void execute() throws BuildException {
126: L10nInspector ins = null;
127: DirectoryScanner ds;
128: if (outFileName != null) {
129: try {
130: outFile = new BufferedWriter(
131: new FileWriter(outFileName));
132: } catch (IOException eIO) {
133: throw new BuildException(eIO);
134: }
135: }
136: output("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>");
137: output("<document>");
138: output("<properties><title>L10N status report</title></properties>");
139: output("<body>");
140: try {
141: ins = new L10nInspector();
142: // set severities
143: Iterator it = messages.iterator();
144: while (it.hasNext()) {
145: Message msg = (Message) it.next();
146: try {
147: Class _clazz = Class
148: .forName("org.tigris.scarab.util.build.l10nchecker.issues."
149: + msg.id + "Issue");
150: L10nIssueTemplates.setMessageType(_clazz,
151: msg.severity);
152: } catch (ClassNotFoundException ex_cnf) {
153: throw new BuildException("Cannot locate issue "
154: + msg.id);
155: }
156: }
157: output("<section name=\"Reference file "
158: + refFile.substring(refFile.lastIndexOf("/") + 1)
159: + "\"><pre>");
160: output("Loading reference file " + refFile, true);
161: int refCount = ins.setReference(refFile);
162: output("Loaded properties: " + refCount);
163: if (ins.hasErrors()) {
164: output("Errors: " + ins.getErrors().size());
165: it = ins.getErrors().iterator();
166: while (it.hasNext()) {
167: L10nMessage err = (L10nMessage) it.next();
168: output("Error at line " + err.getLineNumber()
169: + ": " + err.getMessageText());
170: }
171: }
172: output("</pre></section>");
173: output(""); // empty line for readability
174: it = filesets.iterator();
175: while (it.hasNext()) {
176: FileSet fs = (FileSet) it.next();
177: ds = fs.getDirectoryScanner(this .getProject());
178: ds.scan();
179: File srcDir = fs.getDir(getProject());
180: String[] files = ds.getIncludedFiles();
181: for (int i = 0; i < files.length; i++) {
182: File f = new File(files[i]);
183: output("");
184: output("<section name=\"Checking bundle "
185: + files[i] + "\"><pre>", true);
186: int transcount = ins.checkFile(srcDir
187: .getAbsolutePath()
188: + "/" + files[i]);
189: output("Translations found: " + transcount, true);
190: if (ins.getErrors().size() > 0) {
191: output("Errors: "
192: + ins.getErrors().size(), true);
193: }
194: if (verbose > 0 && ins.getWarnings().size() > 0) {
195: output("Warnings: "
196: + ins.getWarnings().size());
197: }
198: if (verbose > 1 && ins.getInfos().size() > 0) {
199: output("Information: "
200: + ins.getInfos().size());
201: }
202: output(""); // empty line for readability
203: if (ins.hasErrors()) {
204: it = ins.getErrors().iterator();
205: while (it.hasNext()) {
206: L10nMessage err = (L10nMessage) it.next();
207: output("Error at line "
208: + err.getLineNumber() + ": "
209: + err.getMessageText());
210: }
211: if (failonerr) {
212: throw new BuildException(
213: "Failed due to errors in reference bundle");
214: }
215: }
216: if (verbose > 0 && ins.getWarnings().size() > 0) {
217: it = ins.getWarnings().iterator();
218: while (it.hasNext()) {
219: L10nMessage err = (L10nMessage) it.next();
220: output("Warning at line "
221: + err.getLineNumber() + ": "
222: + err.getMessageText());
223: }
224: }
225: if (verbose > 1 && ins.getInfos().size() > 0) {
226: it = ins.getInfos().iterator();
227: while (it.hasNext()) {
228: L10nMessage err = (L10nMessage) it.next();
229:
230: if (err.getLineNumber() < 0) {
231: output("Information: "
232: + err.getMessageText());
233: } else {
234: output("Information for line "
235: + err.getLineNumber() + ": "
236: + err.getMessageText());
237: }
238: }
239: }
240: output("</pre></section>");
241: }
242: }
243: output("</body>");
244: output("</document>");
245: } catch (Exception e) {
246: log("Exception " + e + " raised");
247: throw new BuildException(e);
248: }
249: }
250:
251: /**
252: * Set the output file
253: *
254: * @param filename the file to write
255: */
256: public void setOutfile(String filename) {
257: this .outFileName = filename;
258: }
259:
260: /**
261: * Handle the attribute "refFile"
262: * @param aFile The reference file to be used
263: */
264: public void setRefFile(String aFile) {
265: refFile = aFile;
266: }
267:
268: /**
269: * Handle the attribute "verbose".
270: *
271: * @param verbose The verbosity to be set
272: */
273: public void setVerbose(int verbose) {
274: this .verbose = verbose;
275: }
276:
277: /**
278: * Handle the attribute fileonerr
279: *
280: * @param failonerr The failonerr to set.
281: */
282: public void setFailonerr(boolean failonerr) {
283: this .failonerr = failonerr;
284: }
285:
286: /**
287: * Files to load
288: *
289: * @return A new {@link org.apache.tools.ant.types.FileSet} that
290: * represents a list of files to be read.
291: */
292: public FileSet createFileset() {
293: FileSet set = new FileSet();
294: filesets.add(set);
295: return set;
296: }
297:
298: /* output routines */
299: private void output(String what) {
300: output(what, false);
301: }
302:
303: /* print output. In case dumpToConsole is true and output is redirected
304: * the line is printed to the console also
305: */
306: private void output(String what, boolean dumpToConsole) {
307: if (outFile != null) {
308: try {
309: outFile.write(what);
310: outFile.newLine();
311: outFile.flush();
312: } catch (IOException eIO) {
313: log("Cannot write " + what + " to " + outFileName
314: + " (" + eIO.getMessage() + ")");
315: }
316: }
317: if (null == outFile || dumpToConsole) {
318: log(what);
319: }
320: }
321:
322: /**
323: * ant handler for the messageSet token
324: *
325: * @return a new allocated message
326: */
327: public Message createMessageSet() {
328: Message msg = new Message();
329: messages.add(msg);
330: return msg;
331: }
332:
333: /**
334: * sub Class that represents a severity setting message
335: *
336: */
337: public class Message {
338: private String id;
339: private int severity;
340:
341: /** bean constructor */
342: public Message() {
343: }
344:
345: /** ant entrypoint to set the error name */
346: public void setError(String _id) {
347: this .id = _id;
348: }
349:
350: /** ant entrypoint to set the severity */
351: public void setSeverity(String severity) {
352: if (severity.equals("ERROR")) {
353: this .severity = L10nIssue.MESSAGE_ERROR;
354: } else if (severity.equals("WARNING")) {
355: this .severity = L10nIssue.MESSAGE_WARNING;
356: } else if (severity.equals("INFORMATION")) {
357: this.severity = L10nIssue.MESSAGE_INFO;
358: } else {
359: this.severity = L10nIssue.MESSAGE_IGNORE;
360: }
361: }
362: }
363: }
|