001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs.optional;
019:
020: import java.io.BufferedReader;
021: import java.io.File;
022: import java.io.IOException;
023: import java.io.PrintWriter;
024: import java.io.StringReader;
025: import java.io.StringWriter;
026: import java.util.Enumeration;
027: import java.util.Hashtable;
028: import java.util.Properties;
029: import java.util.StringTokenizer;
030: import java.util.Vector;
031: import netrexx.lang.Rexx;
032: import org.apache.tools.ant.BuildException;
033: import org.apache.tools.ant.DirectoryScanner;
034: import org.apache.tools.ant.Project;
035: import org.apache.tools.ant.taskdefs.MatchingTask;
036: import org.apache.tools.ant.types.EnumeratedAttribute;
037: import org.apache.tools.ant.util.FileUtils;
038:
039: /**
040: * Compiles NetRexx source files.
041: * This task can take the following
042: * arguments:
043: * <ul>
044: * <li>binary</li>
045: * <li>classpath</li>
046: * <li>comments</li>
047: * <li>compile</li>
048: * <li>console</li>
049: * <li>crossref</li>
050: * <li>decimal</li>
051: * <li>destdir</li>
052: * <li>diag</li>
053: * <li>explicit</li>
054: * <li>format</li>
055: * <li>keep</li>
056: * <li>logo</li>
057: * <li>replace</li>
058: * <li>savelog</li>
059: * <li>srcdir</li>
060: * <li>sourcedir</li>
061: * <li>strictargs</li>
062: * <li>strictassign</li>
063: * <li>strictcase</li>
064: * <li>strictimport</li>
065: * <li>symbols</li>
066: * <li>time</li>
067: * <li>trace</li>
068: * <li>utf8</li>
069: * <li>verbose</li>
070: * <li>suppressMethodArgumentNotUsed</li>
071: * <li>suppressPrivatePropertyNotUsed</li>
072: * <li>suppressVariableNotUsed</li>
073: * <li>suppressExceptionNotSignalled</li>
074: * <li>suppressDeprecation</li>
075: * </ul>
076: * Of these arguments, the <b>srcdir</b> argument is required.
077: *
078: * <p>When this task executes, it will recursively scan the srcdir
079: * looking for NetRexx source files to compile. This task makes its
080: * compile decision based on timestamp.
081: * <p>Before files are compiled they and any other file in the
082: * srcdir will be copied to the destdir allowing support files to be
083: * located properly in the classpath. The reason for copying the source files
084: * before the compile is that NetRexxC has only two destinations for classfiles:
085: * <ol>
086: * <li>The current directory, and,</li>
087: * <li>The directory the source is in (see sourcedir option)
088: * </ol>
089: *
090: */
091: public class NetRexxC extends MatchingTask {
092:
093: // variables to hold arguments
094: private boolean binary;
095: private String classpath;
096: private boolean comments;
097: private boolean compact = true; // should be the default, as it integrates better in ant.
098: private boolean compile = true;
099: private boolean console;
100: private boolean crossref;
101: private boolean decimal = true;
102: private File destDir;
103: private boolean diag;
104: private boolean explicit;
105: private boolean format;
106: private boolean keep;
107: private boolean logo = true;
108: private boolean replace;
109: private boolean savelog;
110: private File srcDir;
111: private boolean sourcedir = true; // ?? Should this be the default for ant?
112: private boolean strictargs;
113: private boolean strictassign;
114: private boolean strictcase;
115: private boolean strictimport;
116: private boolean strictprops;
117: private boolean strictsignal;
118: private boolean symbols;
119: private boolean time;
120: private String trace = "trace2";
121: private boolean utf8;
122: private String verbose = "verbose3";
123: private boolean suppressMethodArgumentNotUsed = false;
124: private boolean suppressPrivatePropertyNotUsed = false;
125: private boolean suppressVariableNotUsed = false;
126: private boolean suppressExceptionNotSignalled = false;
127: private boolean suppressDeprecation = false;
128:
129: // constants for the messages to suppress by flags and their corresponding properties
130: static final String MSG_METHOD_ARGUMENT_NOT_USED = "Warning: Method argument is not used";
131: static final String MSG_PRIVATE_PROPERTY_NOT_USED = "Warning: Private property is defined but not used";
132: static final String MSG_VARIABLE_NOT_USED = "Warning: Variable is set but not used";
133: static final String MSG_EXCEPTION_NOT_SIGNALLED = "is in SIGNALS list but is not signalled within the method";
134: static final String MSG_DEPRECATION = "has been deprecated";
135:
136: // other implementation variables
137: private Vector compileList = new Vector();
138: private Hashtable filecopyList = new Hashtable();
139:
140: /**
141: * Set whether literals are treated as binary, rather than NetRexx types.
142: * @param binary a <code>boolean</code> value.
143: */
144: public void setBinary(boolean binary) {
145: this .binary = binary;
146: }
147:
148: /**
149: * Set the classpath used for NetRexx compilation.
150: * @param classpath the classpath to use.
151: */
152: public void setClasspath(String classpath) {
153: this .classpath = classpath;
154: }
155:
156: /**
157: * Set whether comments are passed through to the generated java source.
158: * Valid true values are "on" or "true". Anything else sets the flag to
159: * false. The default value is false
160: * @param comments a <code>boolean</code> value.
161: */
162: public void setComments(boolean comments) {
163: this .comments = comments;
164: }
165:
166: /**
167: * Set whether error messages come out in compact or verbose format. Valid
168: * true values are "on" or "true". Anything else sets the flag to false.
169: * The default value is false
170: * @param compact a <code>boolean</code> value.
171: */
172: public void setCompact(boolean compact) {
173: this .compact = compact;
174: }
175:
176: /**
177: * Set whether the NetRexx compiler should compile the generated java code
178: * Valid true values are "on" or "true". Anything else sets the flag to
179: * false. The default value is true. Setting this flag to false, will
180: * automatically set the keep flag to true.
181: * @param compile a <code>boolean</code> value.
182: */
183: public void setCompile(boolean compile) {
184: this .compile = compile;
185: if (!this .compile && !this .keep) {
186: this .keep = true;
187: }
188: }
189:
190: /**
191: * Set whether or not messages should be displayed on the 'console' Valid
192: * true values are "on" or "true". Anything else sets the flag to false.
193: * The default value is true.
194: * @param console a <code>boolean</code> value.
195: */
196: public void setConsole(boolean console) {
197: this .console = console;
198: }
199:
200: /**
201: * Whether variable cross references are generated.
202: * @param crossref a <code>boolean</code> value.
203: */
204: public void setCrossref(boolean crossref) {
205: this .crossref = crossref;
206: }
207:
208: /**
209: * Set whether decimal arithmetic should be used for the netrexx code.
210: * Binary arithmetic is used when this flag is turned off. Valid true
211: * values are "on" or "true". Anything else sets the flag to false. The
212: * default value is true.
213: * @param decimal a <code>boolean</code> value.
214: */
215: public void setDecimal(boolean decimal) {
216: this .decimal = decimal;
217: }
218:
219: /**
220: * Set the destination directory into which the NetRexx source files
221: * should be copied and then compiled.
222: * @param destDirName the destination directory.
223: */
224: public void setDestDir(File destDirName) {
225: destDir = destDirName;
226: }
227:
228: /**
229: * Whether diagnostic information about the compile is generated
230: * @param diag a <code>boolean</code> value.
231: */
232: public void setDiag(boolean diag) {
233: this .diag = diag;
234: }
235:
236: /**
237: * Sets whether variables must be declared explicitly before use. Valid
238: * true values are "on" or "true". Anything else sets the flag to false.
239: * The default value is false.
240: * @param explicit a <code>boolean</code> value.
241: */
242: public void setExplicit(boolean explicit) {
243: this .explicit = explicit;
244: }
245:
246: /**
247: * Whether the generated java code is formatted nicely or left to match
248: * NetRexx line numbers for call stack debugging.
249: * @param format a <code>boolean</code> value.
250: */
251: public void setFormat(boolean format) {
252: this .format = format;
253: }
254:
255: /**
256: * Whether the generated java code is produced Valid true values are "on"
257: * or "true". Anything else sets the flag to false. The default value is
258: * false.
259: * @param java a <code>boolean</code> value.
260: */
261: public void setJava(boolean java) {
262: log("The attribute java is currently unused.", Project.MSG_WARN);
263: }
264:
265: /**
266: * Sets whether the generated java source file should be kept after
267: * compilation. The generated files will have an extension of .java.keep,
268: * <b>not</b> .java Valid true values are "on" or "true". Anything else
269: * sets the flag to false. The default value is false.
270: * @param keep a <code>boolean</code> value.
271: */
272: public void setKeep(boolean keep) {
273: this .keep = keep;
274: }
275:
276: /**
277: * Whether the compiler text logo is displayed when compiling.
278: * @param logo a <code>boolean</code> value.
279: */
280: public void setLogo(boolean logo) {
281: this .logo = logo;
282: }
283:
284: /**
285: * Whether the generated .java file should be replaced when compiling
286: * Valid true values are "on" or "true". Anything else sets the flag to
287: * false. The default value is false.
288: * @param replace a <code>boolean</code> value.
289: */
290: public void setReplace(boolean replace) {
291: this .replace = replace;
292: }
293:
294: /**
295: * Sets whether the compiler messages will be written to NetRexxC.log as
296: * well as to the console Valid true values are "on" or "true". Anything
297: * else sets the flag to false. The default value is false.
298: * @param savelog a <code>boolean</code> value.
299: */
300: public void setSavelog(boolean savelog) {
301: this .savelog = savelog;
302: }
303:
304: /**
305: * Tells the NetRexx compiler to store the class files in the same
306: * directory as the source files. The alternative is the working directory
307: * Valid true values are "on" or "true". Anything else sets the flag to
308: * false. The default value is true.
309: * @param sourcedir a <code>boolean</code> value.
310: */
311: public void setSourcedir(boolean sourcedir) {
312: this .sourcedir = sourcedir;
313: }
314:
315: /**
316: * Set the source dir to find the source Java files.
317: * @param srcDirName the source directory.
318: */
319: public void setSrcDir(File srcDirName) {
320: srcDir = srcDirName;
321: }
322:
323: /**
324: * Tells the NetRexx compiler that method calls always need parentheses,
325: * even if no arguments are needed, e.g. <code>aStringVar.getBytes</code>
326: * vs. <code>aStringVar.getBytes()</code> Valid true values are "on" or
327: * "true". Anything else sets the flag to false. The default value is
328: * false.
329: * @param strictargs a <code>boolean</code> value.
330: */
331: public void setStrictargs(boolean strictargs) {
332: this .strictargs = strictargs;
333: }
334:
335: /**
336: * Tells the NetRexx compile that assignments must match exactly on type.
337: * @param strictassign a <code>boolean</code> value.
338: */
339: public void setStrictassign(boolean strictassign) {
340: this .strictassign = strictassign;
341: }
342:
343: /**
344: * Specifies whether the NetRexx compiler should be case sensitive or not.
345: * @param strictcase a <code>boolean</code> value.
346: */
347: public void setStrictcase(boolean strictcase) {
348: this .strictcase = strictcase;
349: }
350:
351: /**
352: * Sets whether classes need to be imported explicitly using an <code>import</code>
353: * statement. By default the NetRexx compiler will import certain packages
354: * automatically Valid true values are "on" or "true". Anything else sets
355: * the flag to false. The default value is false.
356: * @param strictimport a <code>boolean</code> value.
357: */
358: public void setStrictimport(boolean strictimport) {
359: this .strictimport = strictimport;
360: }
361:
362: /**
363: * Sets whether local properties need to be qualified explicitly using
364: * <code>this</code> Valid true values are "on" or "true". Anything else
365: * sets the flag to false. The default value is false.
366: * @param strictprops a <code>boolean</code> value.
367: */
368: public void setStrictprops(boolean strictprops) {
369: this .strictprops = strictprops;
370: }
371:
372: /**
373: * Whether the compiler should force catching of exceptions by explicitly
374: * named types.
375: * @param strictsignal a <code>boolean</code> value.
376: */
377: public void setStrictsignal(boolean strictsignal) {
378: this .strictsignal = strictsignal;
379: }
380:
381: /**
382: * Sets whether debug symbols should be generated into the class file
383: * Valid true values are "on" or "true". Anything else sets the flag to
384: * false. The default value is false.
385: * @param symbols a <code>boolean</code> value.
386: */
387: public void setSymbols(boolean symbols) {
388: this .symbols = symbols;
389: }
390:
391: /**
392: * Asks the NetRexx compiler to print compilation times to the console
393: * Valid true values are "on" or "true". Anything else sets the flag to
394: * false. The default value is false.
395: * @param time a <code>boolean</code> value.
396: */
397: public void setTime(boolean time) {
398: this .time = time;
399: }
400:
401: /**
402: * Turns on or off tracing and directs the resultant trace output Valid
403: * values are: "trace", "trace1", "trace2" and "notrace". "trace" and
404: * "trace2".
405: * @param trace the value to set.
406: */
407: public void setTrace(TraceAttr trace) {
408: this .trace = trace.getValue();
409: }
410:
411: /**
412: * Turns on or off tracing and directs the resultant trace output Valid
413: * values are: "trace", "trace1", "trace2" and "notrace". "trace" and
414: * "trace2".
415: * @param trace the value to set.
416: */
417: public void setTrace(String trace) {
418: TraceAttr t = new TraceAttr();
419:
420: t.setValue(trace);
421: setTrace(t);
422: }
423:
424: /**
425: * Tells the NetRexx compiler that the source is in UTF8 Valid true values
426: * are "on" or "true". Anything else sets the flag to false. The default
427: * value is false.
428: * @param utf8 a <code>boolean</code> value.
429: */
430: public void setUtf8(boolean utf8) {
431: this .utf8 = utf8;
432: }
433:
434: /**
435: * Whether lots of warnings and error messages should be generated
436: * @param verbose the value to set - verbose<level> or noverbose.
437: */
438: public void setVerbose(VerboseAttr verbose) {
439: this .verbose = verbose.getValue();
440: }
441:
442: /**
443: * Whether lots of warnings and error messages should be generated
444: * @param verbose the value to set - verbose<level> or noverbose.
445: */
446: public void setVerbose(String verbose) {
447: VerboseAttr v = new VerboseAttr();
448:
449: v.setValue(verbose);
450: setVerbose(v);
451: }
452:
453: /**
454: * Whether the task should suppress the "Method argument is not used" in
455: * strictargs-Mode, which can not be suppressed by the compiler itself.
456: * The warning is logged as verbose message, though.
457: * @param suppressMethodArgumentNotUsed a <code>boolean</code> value.
458: */
459: public void setSuppressMethodArgumentNotUsed(
460: boolean suppressMethodArgumentNotUsed) {
461: this .suppressMethodArgumentNotUsed = suppressMethodArgumentNotUsed;
462: }
463:
464: /**
465: * Whether the task should suppress the "Private property is defined but
466: * not used" in strictargs-Mode, which can be quite annoying while
467: * developing. The warning is logged as verbose message, though.
468: * @param suppressPrivatePropertyNotUsed a <code>boolean</code> value.
469: */
470: public void setSuppressPrivatePropertyNotUsed(
471: boolean suppressPrivatePropertyNotUsed) {
472: this .suppressPrivatePropertyNotUsed = suppressPrivatePropertyNotUsed;
473: }
474:
475: /**
476: * Whether the task should suppress the "Variable is set but not used" in
477: * strictargs-Mode. Be careful with this one! The warning is logged as
478: * verbose message, though.
479: * @param suppressVariableNotUsed a <code>boolean</code> value.
480: */
481: public void setSuppressVariableNotUsed(
482: boolean suppressVariableNotUsed) {
483: this .suppressVariableNotUsed = suppressVariableNotUsed;
484: }
485:
486: /**
487: * Whether the task should suppress the "FooException is in SIGNALS list
488: * but is not signalled within the method", which is sometimes rather
489: * useless. The warning is logged as verbose message, though.
490: * @param suppressExceptionNotSignalled a <code>boolean</code> value.
491: */
492: public void setSuppressExceptionNotSignalled(
493: boolean suppressExceptionNotSignalled) {
494: this .suppressExceptionNotSignalled = suppressExceptionNotSignalled;
495: }
496:
497: /**
498: * Tells whether we should filter out any deprecation-messages
499: * of the compiler out.
500: * @param suppressDeprecation a <code>boolean</code> value.
501: */
502: public void setSuppressDeprecation(boolean suppressDeprecation) {
503: this .suppressDeprecation = suppressDeprecation;
504: }
505:
506: /**
507: * init-Method sets defaults from Properties. That way, when ant is called
508: * with arguments like -Dant.netrexxc.verbose=verbose5 one can easily take
509: * control of all netrexxc-tasks.
510: */
511: public void init() {
512: String p;
513:
514: if ((p = getProject().getProperty("ant.netrexxc.binary")) != null) {
515: this .binary = Project.toBoolean(p);
516: }
517: // classpath makes no sense
518: if ((p = getProject().getProperty("ant.netrexxc.comments")) != null) {
519: this .comments = Project.toBoolean(p);
520: }
521: if ((p = getProject().getProperty("ant.netrexxc.compact")) != null) {
522: this .compact = Project.toBoolean(p);
523: }
524: if ((p = getProject().getProperty("ant.netrexxc.compile")) != null) {
525: this .compile = Project.toBoolean(p);
526: }
527: if ((p = getProject().getProperty("ant.netrexxc.console")) != null) {
528: this .console = Project.toBoolean(p);
529: }
530: if ((p = getProject().getProperty("ant.netrexxc.crossref")) != null) {
531: this .crossref = Project.toBoolean(p);
532: }
533: if ((p = getProject().getProperty("ant.netrexxc.decimal")) != null) {
534: this .decimal = Project.toBoolean(p);
535: // destDir
536: }
537: if ((p = getProject().getProperty("ant.netrexxc.diag")) != null) {
538: this .diag = Project.toBoolean(p);
539: }
540: if ((p = getProject().getProperty("ant.netrexxc.explicit")) != null) {
541: this .explicit = Project.toBoolean(p);
542: }
543: if ((p = getProject().getProperty("ant.netrexxc.format")) != null) {
544: this .format = Project.toBoolean(p);
545: }
546: if ((p = getProject().getProperty("ant.netrexxc.keep")) != null) {
547: this .keep = Project.toBoolean(p);
548: }
549: if ((p = getProject().getProperty("ant.netrexxc.logo")) != null) {
550: this .logo = Project.toBoolean(p);
551: }
552: if ((p = getProject().getProperty("ant.netrexxc.replace")) != null) {
553: this .replace = Project.toBoolean(p);
554: }
555: if ((p = getProject().getProperty("ant.netrexxc.savelog")) != null) {
556: this .savelog = Project.toBoolean(p);
557: // srcDir
558: }
559: if ((p = getProject().getProperty("ant.netrexxc.sourcedir")) != null) {
560: this .sourcedir = Project.toBoolean(p);
561: }
562: if ((p = getProject().getProperty("ant.netrexxc.strictargs")) != null) {
563: this .strictargs = Project.toBoolean(p);
564: }
565: if ((p = getProject().getProperty("ant.netrexxc.strictassign")) != null) {
566: this .strictassign = Project.toBoolean(p);
567: }
568: if ((p = getProject().getProperty("ant.netrexxc.strictcase")) != null) {
569: this .strictcase = Project.toBoolean(p);
570: }
571: if ((p = getProject().getProperty("ant.netrexxc.strictimport")) != null) {
572: this .strictimport = Project.toBoolean(p);
573: }
574: if ((p = getProject().getProperty("ant.netrexxc.strictprops")) != null) {
575: this .strictprops = Project.toBoolean(p);
576: }
577: if ((p = getProject().getProperty("ant.netrexxc.strictsignal")) != null) {
578: this .strictsignal = Project.toBoolean(p);
579: }
580: if ((p = getProject().getProperty("ant.netrexxc.symbols")) != null) {
581: this .symbols = Project.toBoolean(p);
582: }
583: if ((p = getProject().getProperty("ant.netrexxc.time")) != null) {
584: this .time = Project.toBoolean(p);
585: }
586: if ((p = getProject().getProperty("ant.netrexxc.trace")) != null) {
587: setTrace(p);
588: }
589: if ((p = getProject().getProperty("ant.netrexxc.utf8")) != null) {
590: this .utf8 = Project.toBoolean(p);
591: }
592: if ((p = getProject().getProperty("ant.netrexxc.verbose")) != null) {
593: setVerbose(p);
594: }
595: if ((p = getProject().getProperty(
596: "ant.netrexxc.suppressMethodArgumentNotUsed")) != null) {
597: this .suppressMethodArgumentNotUsed = Project.toBoolean(p);
598: }
599: if ((p = getProject().getProperty(
600: "ant.netrexxc.suppressPrivatePropertyNotUsed")) != null) {
601: this .suppressPrivatePropertyNotUsed = Project.toBoolean(p);
602: }
603: if ((p = getProject().getProperty(
604: "ant.netrexxc.suppressVariableNotUsed")) != null) {
605: this .suppressVariableNotUsed = Project.toBoolean(p);
606: }
607: if ((p = getProject().getProperty(
608: "ant.netrexxc.suppressExceptionNotSignalled")) != null) {
609: this .suppressExceptionNotSignalled = Project.toBoolean(p);
610: }
611: if ((p = getProject().getProperty(
612: "ant.netrexxc.suppressDeprecation")) != null) {
613: this .suppressDeprecation = Project.toBoolean(p);
614: }
615: }
616:
617: /**
618: * Executes the task - performs the actual compiler call.
619: * @throws BuildException on error.
620: */
621: public void execute() throws BuildException {
622:
623: // first off, make sure that we've got a srcdir and destdir
624: if (srcDir == null || destDir == null) {
625: throw new BuildException(
626: "srcDir and destDir attributes must be set!");
627: }
628:
629: // scan source and dest dirs to build up both copy lists and
630: // compile lists
631: // scanDir(srcDir, destDir);
632: DirectoryScanner ds = getDirectoryScanner(srcDir);
633:
634: String[] files = ds.getIncludedFiles();
635:
636: scanDir(srcDir, destDir, files);
637:
638: // copy the source and support files
639: copyFilesToDestination();
640:
641: // compile the source files
642: if (compileList.size() > 0) {
643: log("Compiling " + compileList.size() + " source file"
644: + (compileList.size() == 1 ? "" : "s") + " to "
645: + destDir);
646: doNetRexxCompile();
647: }
648: }
649:
650: /**
651: * Scans the directory looking for source files to be compiled and support
652: * files to be copied.
653: */
654: private void scanDir(File srcDir, File destDir, String[] files) {
655: for (int i = 0; i < files.length; i++) {
656: File srcFile = new File(srcDir, files[i]);
657: File destFile = new File(destDir, files[i]);
658: String filename = files[i];
659: // if it's a non source file, copy it if a later date than the
660: // dest
661: // if it's a source file, see if the destination class file
662: // needs to be recreated via compilation
663: if (filename.toLowerCase().endsWith(".nrx")) {
664: File classFile = new File(destDir, filename.substring(
665: 0, filename.lastIndexOf('.'))
666: + ".class");
667:
668: if (!compile
669: || srcFile.lastModified() > classFile
670: .lastModified()) {
671: filecopyList.put(srcFile.getAbsolutePath(),
672: destFile.getAbsolutePath());
673: compileList.addElement(destFile.getAbsolutePath());
674: }
675: } else {
676: if (srcFile.lastModified() > destFile.lastModified()) {
677: filecopyList.put(srcFile.getAbsolutePath(),
678: destFile.getAbsolutePath());
679: }
680: }
681: }
682: }
683:
684: /** Copy eligible files from the srcDir to destDir */
685: private void copyFilesToDestination() {
686: if (filecopyList.size() > 0) {
687: log("Copying " + filecopyList.size() + " file"
688: + (filecopyList.size() == 1 ? "" : "s") + " to "
689: + destDir.getAbsolutePath());
690:
691: Enumeration e = filecopyList.keys();
692:
693: while (e.hasMoreElements()) {
694: String fromFile = (String) e.nextElement();
695: String toFile = (String) filecopyList.get(fromFile);
696:
697: try {
698: FileUtils.getFileUtils().copyFile(fromFile, toFile);
699: } catch (IOException ioe) {
700: String msg = "Failed to copy " + fromFile + " to "
701: + toFile + " due to " + ioe.getMessage();
702:
703: throw new BuildException(msg, ioe);
704: }
705: }
706: }
707: }
708:
709: /** Performs a compile using the NetRexx 1.1.x compiler */
710: private void doNetRexxCompile() throws BuildException {
711: log("Using NetRexx compiler", Project.MSG_VERBOSE);
712:
713: String classpath = getCompileClasspath();
714: StringBuffer compileOptions = new StringBuffer();
715:
716: // create an array of strings for input to the compiler: one array
717: // comes from the compile options, the other from the compileList
718: String[] compileOptionsArray = getCompileOptionsAsArray();
719: String[] fileListArray = new String[compileList.size()];
720: Enumeration e = compileList.elements();
721: int j = 0;
722:
723: while (e.hasMoreElements()) {
724: fileListArray[j] = (String) e.nextElement();
725: j++;
726: }
727: // create a single array of arguments for the compiler
728: String[] compileArgs = new String[compileOptionsArray.length
729: + fileListArray.length];
730:
731: for (int i = 0; i < compileOptionsArray.length; i++) {
732: compileArgs[i] = compileOptionsArray[i];
733: }
734: for (int i = 0; i < fileListArray.length; i++) {
735: compileArgs[i + compileOptionsArray.length] = fileListArray[i];
736: }
737:
738: // print nice output about what we are doing for the log
739: compileOptions.append("Compilation args: ");
740: for (int i = 0; i < compileOptionsArray.length; i++) {
741: compileOptions.append(compileOptionsArray[i]);
742: compileOptions.append(" ");
743: }
744: log(compileOptions.toString(), Project.MSG_VERBOSE);
745:
746: String eol = System.getProperty("line.separator");
747: StringBuffer niceSourceList = new StringBuffer(
748: "Files to be compiled:" + eol);
749:
750: for (int i = 0; i < compileList.size(); i++) {
751: niceSourceList.append(" ");
752: niceSourceList.append(compileList.elementAt(i).toString());
753: niceSourceList.append(eol);
754: }
755:
756: log(niceSourceList.toString(), Project.MSG_VERBOSE);
757:
758: // need to set java.class.path property and restore it later
759: // since the NetRexx compiler has no option for the classpath
760: String currentClassPath = System.getProperty("java.class.path");
761: Properties currentProperties = System.getProperties();
762:
763: currentProperties.put("java.class.path", classpath);
764:
765: try {
766: StringWriter out = new StringWriter();
767: int rc = COM.ibm.netrexx.process.NetRexxC.main(new Rexx(
768: compileArgs), new PrintWriter(out));
769: String sdir = srcDir.getAbsolutePath();
770: String ddir = destDir.getAbsolutePath();
771: boolean doReplace = !(sdir.equals(ddir));
772: int dlen = ddir.length();
773: String l;
774: BufferedReader in = new BufferedReader(new StringReader(out
775: .toString()));
776:
777: log("replacing destdir '" + ddir + "' through sourcedir '"
778: + sdir + "'", Project.MSG_VERBOSE);
779: while ((l = in.readLine()) != null) {
780: int idx;
781:
782: while (doReplace && ((idx = l.indexOf(ddir)) != -1)) {
783: // path is mentioned in the message
784: l = (new StringBuffer(l)).replace(idx, idx + dlen,
785: sdir).toString();
786: }
787: // verbose level logging for suppressed messages
788: if (suppressMethodArgumentNotUsed
789: && l.indexOf(MSG_METHOD_ARGUMENT_NOT_USED) != -1) {
790: log(l, Project.MSG_VERBOSE);
791: } else if (suppressPrivatePropertyNotUsed
792: && l.indexOf(MSG_PRIVATE_PROPERTY_NOT_USED) != -1) {
793: log(l, Project.MSG_VERBOSE);
794: } else if (suppressVariableNotUsed
795: && l.indexOf(MSG_VARIABLE_NOT_USED) != -1) {
796: log(l, Project.MSG_VERBOSE);
797: } else if (suppressExceptionNotSignalled
798: && l.indexOf(MSG_EXCEPTION_NOT_SIGNALLED) != -1) {
799: log(l, Project.MSG_VERBOSE);
800: } else if (suppressDeprecation
801: && l.indexOf(MSG_DEPRECATION) != -1) {
802: log(l, Project.MSG_VERBOSE);
803: } else if (l.indexOf("Error:") != -1) {
804: // error level logging for compiler errors
805: log(l, Project.MSG_ERR);
806: } else if (l.indexOf("Warning:") != -1) {
807: // warning for all warning messages
808: log(l, Project.MSG_WARN);
809: } else {
810: log(l, Project.MSG_INFO); // info level for the rest.
811: }
812: }
813: if (rc > 1) {
814: throw new BuildException(
815: "Compile failed, messages should "
816: + "have been provided.");
817: }
818: } catch (IOException ioe) {
819: throw new BuildException("Unexpected IOException while "
820: + "playing with Strings", ioe);
821: } finally {
822: // need to reset java.class.path property
823: // since the NetRexx compiler has no option for the classpath
824: currentProperties = System.getProperties();
825: currentProperties.put("java.class.path", currentClassPath);
826: }
827:
828: }
829:
830: /** Builds the compilation classpath. */
831: private String getCompileClasspath() {
832: StringBuffer classpath = new StringBuffer();
833:
834: // add dest dir to classpath so that previously compiled and
835: // untouched classes are on classpath
836: classpath.append(destDir.getAbsolutePath());
837:
838: // add our classpath to the mix
839: if (this .classpath != null) {
840: addExistingToClasspath(classpath, this .classpath);
841: }
842:
843: // add the system classpath
844: // addExistingToClasspath(classpath,System.getProperty("java.class.path"));
845: return classpath.toString();
846: }
847:
848: /** This */
849: private String[] getCompileOptionsAsArray() {
850: Vector options = new Vector();
851:
852: options.addElement(binary ? "-binary" : "-nobinary");
853: options.addElement(comments ? "-comments" : "-nocomments");
854: options.addElement(compile ? "-compile" : "-nocompile");
855: options.addElement(compact ? "-compact" : "-nocompact");
856: options.addElement(console ? "-console" : "-noconsole");
857: options.addElement(crossref ? "-crossref" : "-nocrossref");
858: options.addElement(decimal ? "-decimal" : "-nodecimal");
859: options.addElement(diag ? "-diag" : "-nodiag");
860: options.addElement(explicit ? "-explicit" : "-noexplicit");
861: options.addElement(format ? "-format" : "-noformat");
862: options.addElement(keep ? "-keep" : "-nokeep");
863: options.addElement(logo ? "-logo" : "-nologo");
864: options.addElement(replace ? "-replace" : "-noreplace");
865: options.addElement(savelog ? "-savelog" : "-nosavelog");
866: options.addElement(sourcedir ? "-sourcedir" : "-nosourcedir");
867: options
868: .addElement(strictargs ? "-strictargs"
869: : "-nostrictargs");
870: options.addElement(strictassign ? "-strictassign"
871: : "-nostrictassign");
872: options
873: .addElement(strictcase ? "-strictcase"
874: : "-nostrictcase");
875: options.addElement(strictimport ? "-strictimport"
876: : "-nostrictimport");
877: options.addElement(strictprops ? "-strictprops"
878: : "-nostrictprops");
879: options.addElement(strictsignal ? "-strictsignal"
880: : "-nostrictsignal");
881: options.addElement(symbols ? "-symbols" : "-nosymbols");
882: options.addElement(time ? "-time" : "-notime");
883: options.addElement("-" + trace);
884: options.addElement(utf8 ? "-utf8" : "-noutf8");
885: options.addElement("-" + verbose);
886:
887: String[] results = new String[options.size()];
888:
889: options.copyInto(results);
890: return results;
891: }
892:
893: /**
894: * Takes a classpath-like string, and adds each element of this string to
895: * a new classpath, if the components exist. Components that don't exist,
896: * aren't added. We do this, because jikes issues warnings for
897: * non-existant files/dirs in his classpath, and these warnings are pretty
898: * annoying.
899: *
900: * @param target - target classpath
901: * @param source - source classpath to get file objects.
902: */
903: private void addExistingToClasspath(StringBuffer target,
904: String source) {
905: StringTokenizer tok = new StringTokenizer(source, System
906: .getProperty("path.separator"), false);
907:
908: while (tok.hasMoreTokens()) {
909: File f = getProject().resolveFile(tok.nextToken());
910:
911: if (f.exists()) {
912: target.append(File.pathSeparator);
913: target.append(f.getAbsolutePath());
914: } else {
915: log("Dropping from classpath: " + f.getAbsolutePath(),
916: Project.MSG_VERBOSE);
917: }
918: }
919:
920: }
921:
922: /**
923: * Enumerated class corresponding to the trace attribute.
924: */
925: public static class TraceAttr extends EnumeratedAttribute {
926: /** {@inheritDoc}. */
927: public String[] getValues() {
928: return new String[] { "trace", "trace1", "trace2",
929: "notrace" };
930: }
931: }
932:
933: /**
934: * Enumerated class corresponding to the verbose attribute.
935: */
936: public static class VerboseAttr extends EnumeratedAttribute {
937: /** {@inheritDoc}. */
938: public String[] getValues() {
939: return new String[] { "verbose", "verbose0", "verbose1",
940: "verbose2", "verbose3", "verbose4", "verbose5",
941: "noverbose" };
942: }
943: }
944: }
|