/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs.optional; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import java.util.stream.Collectors; import java.util.stream.Stream; import netrexx.lang.Rexx; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.MatchingTask; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.util.FileUtils; // CheckStyle:InnerAssignmentCheck OFF - used too much in the file to be removed /** * Compiles NetRexx source files. * This task can take the following * arguments: * <ul> * <li>binary</li> * <li>classpath</li> * <li>comments</li> * <li>compile</li> * <li>console</li> * <li>crossref</li> * <li>decimal</li> * <li>destdir</li> * <li>diag</li> * <li>explicit</li> * <li>format</li> * <li>keep</li> * <li>logo</li> * <li>replace</li> * <li>savelog</li> * <li>srcdir</li> * <li>sourcedir</li> * <li>strictargs</li> * <li>strictassign</li> * <li>strictcase</li> * <li>strictimport</li> * <li>symbols</li> * <li>time</li> * <li>trace</li> * <li>utf8</li> * <li>verbose</li> * <li>suppressMethodArgumentNotUsed</li> * <li>suppressPrivatePropertyNotUsed</li> * <li>suppressVariableNotUsed</li> * <li>suppressExceptionNotSignalled</li> * <li>suppressDeprecation</li> * <li>removeKeepExtension</li> * </ul> * Of these arguments, the <b>srcdir</b> argument is required. * * <p>When this task executes, it will recursively scan the srcdir * looking for NetRexx source files to compile. This task makes its * compile decision based on timestamp. * <p>Before files are compiled they and any other file in the * srcdir will be copied to the destdir allowing support files to be * located properly in the classpath. The reason for copying the source files * before the compile is that NetRexxC has only two destinations for classfiles: * <ol> * <li>The current directory, and,</li> * <li>The directory the source is in (see sourcedir option) * </ol> * */ public class NetRexxC extends MatchingTask { // variables to hold arguments private boolean binary; private String classpath; private boolean comments; private boolean compact = true; // should be the default, as it integrates better in ant. private boolean compile = true; private boolean console; private boolean crossref; private boolean decimal = true; private File destDir; private boolean diag; private boolean explicit; private boolean format; private boolean keep; private boolean logo = true; private boolean replace; private boolean savelog; private File srcDir; private boolean sourcedir = true; // ?? Should this be the default for ant? private boolean strictargs; private boolean strictassign; private boolean strictcase; private boolean strictimport; private boolean strictprops; private boolean strictsignal; private boolean symbols; private boolean time; private String trace = "trace2"; private boolean utf8; private String verbose = "verbose3"; private boolean suppressMethodArgumentNotUsed = false; private boolean suppressPrivatePropertyNotUsed = false; private boolean suppressVariableNotUsed = false; private boolean suppressExceptionNotSignalled = false; private boolean suppressDeprecation = false; private boolean removeKeepExtension = false; // constants for the messages to suppress by flags and their corresponding properties static final String MSG_METHOD_ARGUMENT_NOT_USED = "Warning: Method argument is not used"; static final String MSG_PRIVATE_PROPERTY_NOT_USED = "Warning: Private property is defined but not used"; static final String MSG_VARIABLE_NOT_USED = "Warning: Variable is set but not used"; static final String MSG_EXCEPTION_NOT_SIGNALLED = "is in SIGNALS list but is not signalled within the method"; static final String MSG_DEPRECATION = "has been deprecated"; // other implementation variables private Vector<String> compileList = new Vector<>(); private Hashtable<String, String> filecopyList = new Hashtable<>(); /** * Set whether literals are treated as binary, rather than NetRexx types. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default is false. * @param binary a <code>boolean</code> value. */ public void setBinary(boolean binary) { this.binary = binary; } /** * Set the classpath used for NetRexx compilation. * @param classpath the classpath to use. */ public void setClasspath(String classpath) { this.classpath = classpath; } /** * Set whether comments are passed through to the generated java source. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param comments a <code>boolean</code> value. */ public void setComments(boolean comments) { this.comments = comments; } /** * Set whether error messages come out in compact or verbose format. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is true. * @param compact a <code>boolean</code> value. */ public void setCompact(boolean compact) { this.compact = compact; } /** * Set whether the NetRexx compiler should compile the generated java code. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is true. * Setting this flag to false, will automatically set the keep flag to true. * @param compile a <code>boolean</code> value. */ public void setCompile(boolean compile) { this.compile = compile; if (!this.compile && !this.keep) { this.keep = true; } } /** * Set whether or not compiler messages should be displayed on the 'console'. * Note that this task will rely on the default value for filtering compile messages. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param console a <code>boolean</code> value. */ public void setConsole(boolean console) { this.console = console; } /** * Whether variable cross references are generated. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param crossref a <code>boolean</code> value. */ public void setCrossref(boolean crossref) { this.crossref = crossref; } /** * Set whether decimal arithmetic should be used for the netrexx code. * Setting this to off will report decimal arithmetic as an error, for * performance critical applications. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is true. * @param decimal a <code>boolean</code> value. */ public void setDecimal(boolean decimal) { this.decimal = decimal; } /** * Set the destination directory into which the NetRexx source files * should be copied and then compiled. * @param destDirName the destination directory. */ public void setDestDir(File destDirName) { destDir = destDirName; } /** * Whether diagnostic information about the compile is generated * @param diag a <code>boolean</code> value. */ public void setDiag(boolean diag) { this.diag = diag; } /** * Sets whether variables must be declared explicitly before use. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param explicit a <code>boolean</code> value. */ public void setExplicit(boolean explicit) { this.explicit = explicit; } /** * Whether the generated java code is formatted nicely or left to match * NetRexx line numbers for call stack debugging. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value false. * @param format a <code>boolean</code> value. */ public void setFormat(boolean format) { this.format = format; } /** * Whether the generated java code is produced. * This is not implemented yet. * @param java a <code>boolean</code> value. */ public void setJava(boolean java) { log("The attribute java is currently unused.", Project.MSG_WARN); } /** * Sets whether the generated java source file should be kept after * compilation. The generated files will have an extension of .java.keep, * <b>not</b> .java. See setRemoveKeepExtension * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param keep a <code>boolean</code> value. * @see #setRemoveKeepExtension(boolean) */ public void setKeep(boolean keep) { this.keep = keep; } /** * Whether the compiler text logo is displayed when compiling. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param logo a <code>boolean</code> value. */ public void setLogo(boolean logo) { this.logo = logo; } /** * Whether the generated .java file should be replaced when compiling. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param replace a <code>boolean</code> value. */ public void setReplace(boolean replace) { this.replace = replace; } /** * Sets whether the compiler messages will be written to NetRexxC.log as * well as to the console. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param savelog a <code>boolean</code> value. */ public void setSavelog(boolean savelog) { this.savelog = savelog; } /** * Tells the NetRexx compiler to store the class files in the same * directory as the source files. The alternative is the working directory. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is true. * @param sourcedir a <code>boolean</code> value. */ public void setSourcedir(boolean sourcedir) { this.sourcedir = sourcedir; } /** * Set the source dir to find the source Java files. * @param srcDirName the source directory. */ public void setSrcDir(File srcDirName) { srcDir = srcDirName; } /** * Tells the NetRexx compiler that method calls always need parentheses, * even if no arguments are needed, e.g. <code>aStringVar.getBytes</code> * vs. <code>aStringVar.getBytes()</code>. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param strictargs a <code>boolean</code> value. */ public void setStrictargs(boolean strictargs) { this.strictargs = strictargs; } /** * Tells the NetRexx compile that assignments must match exactly on type. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param strictassign a <code>boolean</code> value. */ public void setStrictassign(boolean strictassign) { this.strictassign = strictassign; } /** * Specifies whether the NetRexx compiler should be case sensitive or not. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param strictcase a <code>boolean</code> value. */ public void setStrictcase(boolean strictcase) { this.strictcase = strictcase; } /** * Sets whether classes need to be imported explicitly using an <code>import</code> * statement. By default the NetRexx compiler will import certain packages * automatically. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param strictimport a <code>boolean</code> value. */ public void setStrictimport(boolean strictimport) { this.strictimport = strictimport; } /** * Sets whether local properties need to be qualified explicitly using * <code>this</code>. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param strictprops a <code>boolean</code> value. */ public void setStrictprops(boolean strictprops) { this.strictprops = strictprops; } /** * Whether the compiler should force catching of exceptions by explicitly * named types. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false * @param strictsignal a <code>boolean</code> value. */ public void setStrictsignal(boolean strictsignal) { this.strictsignal = strictsignal; } /** * Sets whether debug symbols should be generated into the class file. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param symbols a <code>boolean</code> value. */ public void setSymbols(boolean symbols) { this.symbols = symbols; } /** * Asks the NetRexx compiler to print compilation times to the console * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param time a <code>boolean</code> value. */ public void setTime(boolean time) { this.time = time; } /** * Turns on or off tracing and directs the resultant trace output Valid * values are: "trace", "trace1", "trace2" and "notrace". "trace" and * "trace2". * @param trace the value to set. */ public void setTrace(TraceAttr trace) { this.trace = trace.getValue(); } /** * Turns on or off tracing and directs the resultant trace output Valid * values are: "trace", "trace1", "trace2" and "notrace". "trace" and * "trace2". * @param trace the value to set. */ public void setTrace(String trace) { TraceAttr t = new TraceAttr(); t.setValue(trace); setTrace(t); } /** * Tells the NetRexx compiler that the source is in UTF8. * Valid true values are "yes", "on" or "true". Anything else sets the flag to false. * The default value is false. * @param utf8 a <code>boolean</code> value. */ public void setUtf8(boolean utf8) { this.utf8 = utf8; } /** * Whether lots of warnings and error messages should be generated * @param verbose the value to set - verbose<level> or noverbose. */ public void setVerbose(VerboseAttr verbose) { this.verbose = verbose.getValue(); } /** * Whether lots of warnings and error messages should be generated * @param verbose the value to set - verbose<level> or noverbose. */ public void setVerbose(String verbose) { VerboseAttr v = new VerboseAttr(); v.setValue(verbose); setVerbose(v); } /** * Whether the task should suppress the "Method argument is not used" in * strictargs-Mode, which can not be suppressed by the compiler itself. * The warning is logged as verbose message, though. * @param suppressMethodArgumentNotUsed a <code>boolean</code> value. */ public void setSuppressMethodArgumentNotUsed(boolean suppressMethodArgumentNotUsed) { this.suppressMethodArgumentNotUsed = suppressMethodArgumentNotUsed; } /** * Whether the task should suppress the "Private property is defined but * not used" in strictargs-Mode, which can be quite annoying while * developing. The warning is logged as verbose message, though. * @param suppressPrivatePropertyNotUsed a <code>boolean</code> value. */ public void setSuppressPrivatePropertyNotUsed(boolean suppressPrivatePropertyNotUsed) { this.suppressPrivatePropertyNotUsed = suppressPrivatePropertyNotUsed; } /** * Whether the task should suppress the "Variable is set but not used" in * strictargs-Mode. Be careful with this one! The warning is logged as * verbose message, though. * @param suppressVariableNotUsed a <code>boolean</code> value. */ public void setSuppressVariableNotUsed(boolean suppressVariableNotUsed) { this.suppressVariableNotUsed = suppressVariableNotUsed; } /** * Whether the task should suppress the "FooException is in SIGNALS list * but is not signalled within the method", which is sometimes rather * useless. The warning is logged as verbose message, though. * @param suppressExceptionNotSignalled a <code>boolean</code> value. */ public void setSuppressExceptionNotSignalled(boolean suppressExceptionNotSignalled) { this.suppressExceptionNotSignalled = suppressExceptionNotSignalled; } /** * Tells whether we should filter out any deprecation-messages * of the compiler out. * @param suppressDeprecation a <code>boolean</code> value. */ public void setSuppressDeprecation(boolean suppressDeprecation) { this.suppressDeprecation = suppressDeprecation; } /** * Tells whether the trailing .keep in nocompile-mode should be removed * so that the resulting java source really ends on .java. * This facilitates the use of the javadoc tool lateron. */ public void setRemoveKeepExtension(boolean removeKeepExtension) { this.removeKeepExtension = removeKeepExtension; } /** * init-Method sets defaults from Properties. That way, when ant is called * with arguments like -Dant.netrexxc.verbose=verbose5 one can easily take * control of all netrexxc-tasks. */ @Override public void init() { String p; if ((p = getProject().getProperty("ant.netrexxc.binary")) != null) { this.binary = Project.toBoolean(p); } // classpath makes no sense if ((p = getProject().getProperty("ant.netrexxc.comments")) != null) { this.comments = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.compact")) != null) { this.compact = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.compile")) != null) { this.compile = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.console")) != null) { this.console = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.crossref")) != null) { this.crossref = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.decimal")) != null) { this.decimal = Project.toBoolean(p); // destDir } if ((p = getProject().getProperty("ant.netrexxc.diag")) != null) { this.diag = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.explicit")) != null) { this.explicit = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.format")) != null) { this.format = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.keep")) != null) { this.keep = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.logo")) != null) { this.logo = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.replace")) != null) { this.replace = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.savelog")) != null) { this.savelog = Project.toBoolean(p); // srcDir } if ((p = getProject().getProperty("ant.netrexxc.sourcedir")) != null) { this.sourcedir = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.strictargs")) != null) { this.strictargs = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.strictassign")) != null) { this.strictassign = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.strictcase")) != null) { this.strictcase = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.strictimport")) != null) { this.strictimport = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.strictprops")) != null) { this.strictprops = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.strictsignal")) != null) { this.strictsignal = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.symbols")) != null) { this.symbols = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.time")) != null) { this.time = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.trace")) != null) { setTrace(p); } if ((p = getProject().getProperty("ant.netrexxc.utf8")) != null) { this.utf8 = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.verbose")) != null) { setVerbose(p); } if ((p = getProject().getProperty("ant.netrexxc.suppressMethodArgumentNotUsed")) != null) { this.suppressMethodArgumentNotUsed = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.suppressPrivatePropertyNotUsed")) != null) { this.suppressPrivatePropertyNotUsed = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.suppressVariableNotUsed")) != null) { this.suppressVariableNotUsed = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.suppressExceptionNotSignalled")) != null) { this.suppressExceptionNotSignalled = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.suppressDeprecation")) != null) { this.suppressDeprecation = Project.toBoolean(p); } if ((p = getProject().getProperty("ant.netrexxc.removeKeepExtension")) != null) { this.removeKeepExtension = Project.toBoolean(p); } } /** * Executes the task - performs the actual compiler call. * @throws BuildException on error. */ @Override public void execute() throws BuildException { // first off, make sure that we've got a srcdir and destdir if (srcDir == null || destDir == null) { throw new BuildException("srcDir and destDir attributes must be set!"); } // scan source and dest dirs to build up both copy lists and // compile lists DirectoryScanner ds = getDirectoryScanner(srcDir); String[] files = ds.getIncludedFiles(); scanDir(srcDir, destDir, files); // copy the source and support files copyFilesToDestination(); // compile the source files if (!compileList.isEmpty()) { log("Compiling " + compileList.size() + " source file" + (compileList.size() == 1 ? "" : "s") + " to " + destDir); doNetRexxCompile(); if (removeKeepExtension && (!compile || keep)) { removeKeepExtensions(); } } } /** * Scans the directory looking for source files to be compiled and support * files to be copied. */ private void scanDir(File srcDir, File destDir, String[] files) { for (String filename : files) { File srcFile = new File(srcDir, filename); File destFile = new File(destDir, filename); // if it's a non source file, copy it if a later date than the // dest // if it's a source file, see if the destination class file // needs to be recreated via compilation if (filename.toLowerCase().endsWith(".nrx")) { File classFile = new File(destDir, filename.substring(0, filename.lastIndexOf('.')) + ".class"); File javaFile = new File(destDir, filename.substring(0, filename.lastIndexOf('.')) + (removeKeepExtension ? ".java" : ".java.keep")); // nocompile case tests against .java[.keep] file if (!compile && srcFile.lastModified() > javaFile.lastModified()) { filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath()); compileList.addElement(destFile.getAbsolutePath()); } else if (compile && srcFile.lastModified() > classFile.lastModified()) { // compile case tests against .class file filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath()); compileList.addElement(destFile.getAbsolutePath()); } } else if (srcFile.lastModified() > destFile.lastModified()) { filecopyList.put(srcFile.getAbsolutePath(), destFile.getAbsolutePath()); } } } /** Copy eligible files from the srcDir to destDir */ private void copyFilesToDestination() { if (!filecopyList.isEmpty()) { log("Copying " + filecopyList.size() + " file" + (filecopyList.size() == 1 ? "" : "s") + " to " + destDir.getAbsolutePath()); filecopyList.forEach((fromFile, toFile) -> { try { FileUtils.getFileUtils().copyFile(fromFile, toFile); } catch (IOException ioe) { throw new BuildException("Failed to copy " + fromFile + " to " + toFile + " due to " + ioe.getMessage(), ioe); } }); } } /** * Rename .java.keep files (back) to .java. The netrexxc renames all * .java files to .java.keep if either -keep or -nocompile option is set. */ private void removeKeepExtensions() { if (!compileList.isEmpty()) { log("Removing .keep extension on " + compileList.size() + " file" + (compileList.size() == 1 ? "" : "s")); compileList.forEach(nrxName -> { String baseName = nrxName.substring(0, nrxName.lastIndexOf('.')); File fromFile = new File(baseName + ".java.keep"); File toFile = new File(baseName + ".java"); if (fromFile.renameTo(toFile)) { log("Successfully renamed " + fromFile + " to " + toFile, Project.MSG_VERBOSE); } else { log("Failed to rename " + fromFile + " to " + toFile); } }); } } /** Performs a compile using the NetRexx 1.1.x compiler */ private void doNetRexxCompile() throws BuildException { log("Using NetRexx compiler", Project.MSG_VERBOSE); String classpath = getCompileClasspath(); // create an array of strings for input to the compiler: one array // comes from the compile options, the other from the compileList String[] compileOptionsArray = getCompileOptionsAsArray(); // print nice output about what we are doing for the log log(Stream.of(compileOptionsArray) .collect(Collectors.joining(" ", "Compilation args: ", "")), Project.MSG_VERBOSE); log("Files to be compiled:", Project.MSG_VERBOSE); final String eol = System.getProperty("line.separator"); log( compileList.stream().map(s -> " " + s).collect(Collectors.joining(eol)) , Project.MSG_VERBOSE); // create a single array of arguments for the compiler String[] compileArgs = Stream.concat(Stream.of(compileOptionsArray), compileList.stream()) .toArray(String[]::new); // need to set java.class.path property and restore it later // since the NetRexx compiler has no option for the classpath String currentClassPath = System.getProperty("java.class.path"); Properties currentProperties = System.getProperties(); currentProperties.put("java.class.path", classpath); try { StringWriter out = new StringWriter(); PrintWriter w; int rc = COM.ibm.netrexx.process.NetRexxC.main(new Rexx(compileArgs), w = new PrintWriter(out)); //NOSONAR String sdir = srcDir.getAbsolutePath(); String ddir = destDir.getAbsolutePath(); boolean doReplace = !(sdir.equals(ddir)); int dlen = ddir.length(); BufferedReader in = new BufferedReader(new StringReader(out.toString())); log("replacing destdir '" + ddir + "' through sourcedir '" + sdir + "'", Project.MSG_VERBOSE); String l; while ((l = in.readLine()) != null) { int idx; while (doReplace && ((idx = l.indexOf(ddir)) != -1)) { // path is mentioned in the message l = new StringBuilder(l).replace(idx, idx + dlen, sdir).toString(); } // verbose level logging for suppressed messages if (suppressMethodArgumentNotUsed && l.indexOf(MSG_METHOD_ARGUMENT_NOT_USED) != -1) { log(l, Project.MSG_VERBOSE); } else if (suppressPrivatePropertyNotUsed && l.indexOf(MSG_PRIVATE_PROPERTY_NOT_USED) != -1) { log(l, Project.MSG_VERBOSE); } else if (suppressVariableNotUsed && l.indexOf(MSG_VARIABLE_NOT_USED) != -1) { log(l, Project.MSG_VERBOSE); } else if (suppressExceptionNotSignalled && l.indexOf(MSG_EXCEPTION_NOT_SIGNALLED) != -1) { log(l, Project.MSG_VERBOSE); } else if (suppressDeprecation && l.indexOf(MSG_DEPRECATION) != -1) { log(l, Project.MSG_VERBOSE); } else if (l.indexOf("Error:") != -1) { // error level logging for compiler errors log(l, Project.MSG_ERR); } else if (l.indexOf("Warning:") != -1) { // warning for all warning messages log(l, Project.MSG_WARN); } else { log(l, Project.MSG_INFO); // info level for the rest. } } if (rc > 1) { throw new BuildException( "Compile failed, messages should have been provided."); } if (w.checkError()) { throw new IOException("Encountered an error"); } } catch (IOException ioe) { throw new BuildException( "Unexpected IOException while playing with Strings", ioe); } finally { // need to reset java.class.path property // since the NetRexx compiler has no option for the classpath currentProperties = System.getProperties(); currentProperties.put("java.class.path", currentClassPath); } } /** Builds the compilation classpath. */ private String getCompileClasspath() { StringBuilder classpath = new StringBuilder(); // add dest dir to classpath so that previously compiled and // untouched classes are on classpath classpath.append(destDir.getAbsolutePath()); // add our classpath to the mix if (this.classpath != null) { addExistingToClasspath(classpath, this.classpath); } // add the system classpath return classpath.toString(); } /** This */ private String[] getCompileOptionsAsArray() { List<String> options = new ArrayList<>(); options.add(binary ? "-binary" : "-nobinary"); options.add(comments ? "-comments" : "-nocomments"); options.add(compile ? "-compile" : "-nocompile"); options.add(compact ? "-compact" : "-nocompact"); options.add(console ? "-console" : "-noconsole"); options.add(crossref ? "-crossref" : "-nocrossref"); options.add(decimal ? "-decimal" : "-nodecimal"); options.add(diag ? "-diag" : "-nodiag"); options.add(explicit ? "-explicit" : "-noexplicit"); options.add(format ? "-format" : "-noformat"); options.add(keep ? "-keep" : "-nokeep"); options.add(logo ? "-logo" : "-nologo"); options.add(replace ? "-replace" : "-noreplace"); options.add(savelog ? "-savelog" : "-nosavelog"); options.add(sourcedir ? "-sourcedir" : "-nosourcedir"); options.add(strictargs ? "-strictargs" : "-nostrictargs"); options.add(strictassign ? "-strictassign" : "-nostrictassign"); options.add(strictcase ? "-strictcase" : "-nostrictcase"); options.add(strictimport ? "-strictimport" : "-nostrictimport"); options.add(strictprops ? "-strictprops" : "-nostrictprops"); options.add(strictsignal ? "-strictsignal" : "-nostrictsignal"); options.add(symbols ? "-symbols" : "-nosymbols"); options.add(time ? "-time" : "-notime"); options.add("-" + trace); options.add(utf8 ? "-utf8" : "-noutf8"); options.add("-" + verbose); return options.toArray(new String[options.size()]); } /** * Takes a classpath-like string, and adds each element of this string to * a new classpath, if the components exist. Components that don't exist, * aren't added. We do this, because jikes issues warnings for * non-existent files/dirs in his classpath, and these warnings are pretty * annoying. * * @param target - target classpath * @param source - source classpath to get file objects. */ private void addExistingToClasspath(StringBuilder target, String source) { StringTokenizer tok = new StringTokenizer(source, System.getProperty("path.separator"), false); while (tok.hasMoreTokens()) { File f = getProject().resolveFile(tok.nextToken()); if (f.exists()) { target.append(File.pathSeparator); target.append(f.getAbsolutePath()); } else { log("Dropping from classpath: " + f.getAbsolutePath(), Project.MSG_VERBOSE); } } } /** * Enumerated class corresponding to the trace attribute. */ public static class TraceAttr extends EnumeratedAttribute { /** {@inheritDoc}. */ @Override public String[] getValues() { return new String[] { "trace", "trace1", "trace2", "notrace" }; } } /** * Enumerated class corresponding to the verbose attribute. */ public static class VerboseAttr extends EnumeratedAttribute { /** {@inheritDoc}. */ @Override public String[] getValues() { return new String[] { "verbose", "verbose0", "verbose1", "verbose2", "verbose3", "verbose4", "verbose5", "noverbose" }; } } }