| /* |
| * 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 |
| * |
| * https://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> |
| * <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:</p> |
| * <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 later on. |
| * @param removeKeepExtension boolean |
| */ |
| 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); |
| |
| scanDir(srcDir, destDir, ds.getIncludedFiles()); |
| |
| // 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); |
| |
| log(compileList.stream().map(s -> String.format(" %s%n", s)) |
| .collect(Collectors.joining("")), 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.contains(MSG_METHOD_ARGUMENT_NOT_USED)) { |
| log(l, Project.MSG_VERBOSE); |
| } else if (suppressPrivatePropertyNotUsed |
| && l.contains(MSG_PRIVATE_PROPERTY_NOT_USED)) { |
| log(l, Project.MSG_VERBOSE); |
| } else if (suppressVariableNotUsed |
| && l.contains(MSG_VARIABLE_NOT_USED)) { |
| log(l, Project.MSG_VERBOSE); |
| } else if (suppressExceptionNotSignalled |
| && l.contains(MSG_EXCEPTION_NOT_SIGNALLED)) { |
| log(l, Project.MSG_VERBOSE); |
| } else if (suppressDeprecation |
| && l.contains(MSG_DEPRECATION)) { |
| log(l, Project.MSG_VERBOSE); |
| } else if (l.contains("Error:")) { |
| // error level logging for compiler errors |
| log(l, Project.MSG_ERR); |
| } else if (l.contains("Warning:")) { |
| // 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, |
| File.pathSeparator, 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"}; |
| } |
| } |
| } |