All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gosu.tools.ant.Gosuc Maven / Gradle / Ivy

The newest version!
package gosu.tools.ant;

import gosu.tools.ant.util.AntLoggingHelper;
import gw.lang.gosuc.GosucUtil;
import gw.lang.gosuc.simple.ICompilerDriver;
import gw.lang.gosuc.simple.IGosuCompiler;
import gw.lang.gosuc.simple.SoutCompilerDriver;
import manifold.util.JreUtil;
import manifold.util.NecessaryEvilUtil;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.GlobPatternMapper;
import org.apache.tools.ant.util.SourceFileScanner;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Ant task for compiling Gosu files to disk.
 * 

The following parameters are available: *

    *
  • "srcdir" : A Path containing one or more source directories
  • *
  • "destdir" : A File representing the output destination of the compilation
  • *
  • "checkedarithmetic" : Compile with checked arithmetic if true. Defaults to {@code false}.
  • *
  • "failonerror" : Ignore compile errors and continue if true. Defaults to {@code true}.
  • *
  • "projectname" : Outputs this value in the compilation complete message. Defaults to the empty string.
  • *
  • "additionalscriptextensions" : Comma-separated list of additional file extensions to compile. Normally not required.
  • *
*/ public class Gosuc extends GosuMatchingTask { private final AntLoggingHelper log = new AntLoggingHelper(this); private Path _src; private File _destDir; private Path _compileClasspath; private boolean _failOnError = true; private boolean _checkedArithmetic = false; private boolean _force = true; private String _projectName = ""; private Set _scriptExtensions = new HashSet<>(Arrays.asList("gs", "gsx", "gst", "gsp")); protected List compileList = new ArrayList<>(); /** * Adds a path for source compilation. * * @return a nested src element. */ public Path createSrc() { if (_src == null) { _src = new Path(getProject()); } return _src.createPath(); } /** * Recreate src. * * @return a nested src element. */ protected Path recreateSrc() { _src = null; return createSrc(); } /** * Set the source directories to find the source Gosu files. * * @param srcDir the source directories as a path */ public void setSrcdir(Path srcDir) { if (_src == null) { _src = srcDir; } else { _src.append(srcDir); } } /** * Gets the source dirs to find the source Gosu files. * * @return the source directories as a path */ public Path getSrcdir() { return _src; } /** * Set the destination directory into which the Gosu source * files should be compiled. * * @param destDir the destination directory */ public void setDestdir(File destDir) { _destDir = destDir; } /** * Gets the destination directory into which the Gosu source files * should be compiled. * * @return the destination directory */ public File getDestdir() { return _destDir; } /** * Adds a path to the classpath. * * @return a classpath to be configured */ public Path createClasspath() { if (_compileClasspath == null) { _compileClasspath = new Path(getProject()); } return _compileClasspath.createPath(); } /** * Adds a reference to a classpath defined elsewhere. * * @param ref a reference to a classpath */ public void setClasspathRef(Reference ref) { createClasspath().setRefid(ref); } private Set getScriptExtensions() { return _scriptExtensions; } /** * * @param extensions Additional extensions to compile; for example "grs, gr" */ public void setAdditionalScriptExtensions(String extensions) { _scriptExtensions.addAll( Arrays.asList( extensions.split( ",\\s*" ) ) ); } /** * Indicates whether the build will continue * even if there are compilation errors; defaults to true. * * @param fail if true halt the build on failure */ public void setFailOnError(boolean fail) { _failOnError = fail; } /** * Gets the FailOnError flag. * * @return the FailOnError flag */ public boolean getFailOnError() { return _failOnError; } public boolean isCheckedArithmetic() { return _checkedArithmetic; } public void setCheckedArithmetic( boolean checkedArithmetic ) { _checkedArithmetic = checkedArithmetic; } /** * Gets the Force flag.
* ant's directory scanner is timestamp based. Without proper tasks, this could result in successful, but incomplete compilation.
* Therefore we default 'force' to true, which causes compilation of all matching source files, regardless of the timestamp comparison between source and target. * * @return */ public boolean isForce() { return _force; } public void setForce( boolean force ) { _force = force; } /** * Gets the optional Project Name.
* This has no impact on the compilation; simply outputs this value in the compilation complete message. * Useful in large, multimodule builds with parallelization. * * @return ProjectName property; defaults to empty string. */ public String getProjectName() { return _projectName; } public void setProjectName( String projectName ) { _projectName = projectName; } /** * Scans the directory looking for source files to be compiled. * The results are returned in the class variable compileList * * @param srcDir The source directory * @param destDir The destination directory * @param files An array of filenames */ protected void scanDir(File srcDir, File destDir, String[] files) { GlobPatternMapper m = new GlobPatternMapper(); SourceFileScanner sfs = new SourceFileScanner(this); List newFiles; if(!isForce()) { log.warn("Relying on ant's SourceFileScanner, which only looks at timestamps. If broken references result, try setting option 'force' to true."); } for (String extension : getScriptExtensions()) { m.setFrom("*." + extension); m.setTo("*.class"); log.debug("Scanning for *." + extension + " files..."); if(isForce()) { newFiles = asFiles(srcDir, files, m); } else { newFiles = Arrays.asList(sfs.restrictAsFiles(files, srcDir, destDir, m)); } log.debug("Found these files:"); for(File newFile : newFiles) { log.debug('\t' + newFile.getAbsolutePath()); } compileList.addAll(newFiles); } } /** * Converts an array of relative String filenames to a {@code List} * @param srcDir The root directory of all files * @param files All files are relative to srcDir * @return a List of Files by joining srcDir to each file */ private List asFiles(File srcDir, String[] files, FileNameMapper m) { List newFiles = new ArrayList<>(); for(String file : files) { boolean hasMatchingExtension = m.mapFileName(file) != null; //use mapFileName as a check to validate if the source file extension is recognized by the mapper or not if(hasMatchingExtension) { newFiles.add(new File(srcDir, file)); } } return newFiles; } /** * Gets the list of files to be compiled. * * @return the list of files */ public List getFileList() { return compileList; } /** * Executes the task. * * @throws BuildException if an error occurs */ public void execute() throws BuildException { log.debug("projectname=" + getProjectName()); log.debug("src/srcdir=" + getSrcdir()); log.debug("destdir=" + getDestdir()); log.debug("failOnError=" + getFailOnError()); log.debug("checkedArithmetic=" + isCheckedArithmetic()); log.debug("scriptExtensions=" + getScriptExtensions()); log.debug("_compileClasspath=" + _compileClasspath); NecessaryEvilUtil.bypassJava9Security(); if(isCheckedArithmetic()) { System.setProperty("checkedArithmetic", "true"); } ICompilerDriver driver = new SoutCompilerDriver(); IGosuCompiler gosuc = new gw.lang.gosuc.simple.GosuCompiler(); List classpath = new ArrayList<>( Arrays.asList( _compileClasspath.list() ) ); classpath.add( GosucUtil.getClassLocation( "manifold.api.host.IManifoldHost" ) ); // manifold core classpath.add( GosucUtil.getClassLocation( "manifold.rt.api.Bindings" ) ); // manifold-rt // classpath.add( GosucUtil.getClassLocation( "manifold.ext.ExtensionMethod" ) ); // manifold-ext classpath.add( GosucUtil.getClassLocation( "manifold.util.ReflectUtil" ) ); // manifold-util if( JreUtil.isJava8() ) { classpath.addAll( GosucUtil.getJreJars()); } String startupMsg = "Initializing Gosu compiler"; if(!getProjectName().isEmpty()) { startupMsg += " for " + getProjectName(); } log.info(startupMsg); log.debug("\tsourceFolders:" + Arrays.asList(getSrcdir().list())); log.debug("\tclasspath:" + classpath); log.debug("\toutputPath:" + getDestdir().getAbsolutePath()); List sourceRoots = Arrays.asList(getSrcdir().list()); for (String sourceRootName : sourceRoots) { File sourceRoot = getProject().resolveFile(sourceRootName); if (!sourceRoot.exists()) { throw new BuildException("srcdir \"" + sourceRoot.getPath() + "\" does not exist!", getLocation()); } DirectoryScanner ds = this.getDirectoryScanner(sourceRoot); String[] files = ds.getIncludedFiles(); if( hasSelectors() ) { // we have explicit includes/excludes criteria nested in a element; no need to call scanDir // this is the typical use case when ant is invoked dynamically by gradle for( String relativeFilename : files ) { compileList.add( new File( sourceRoot, relativeFilename ) ); } } else { // element was not used - instead we have an explicit list of srcDir elements // and optionally additionalscriptextensions specified in addition to the defaults scanDir(sourceRoot, _destDir != null ? _destDir : sourceRoot, files); } } gosuc.initializeGosu( sourceRoots, classpath, getDestdir().getAbsolutePath() ); log.debug("About to compile these files:"); for(File file : compileList) { log.debug("\t" + file.getAbsolutePath()); } for(File file : compileList) { try { gosuc.compile(file, driver); } catch (Exception e) { log.error(e.getMessage()); throw new BuildException(e); } } gosuc.uninitializeGosu(); List warnings = ((SoutCompilerDriver) driver).getWarnings(); boolean errorsInCompilation = ((SoutCompilerDriver) driver).hasErrors(); List errors = ((SoutCompilerDriver) driver).getErrors(); List warningMessages = new ArrayList<>(); List errorMessages = new ArrayList<>(); warnings.forEach(warning -> warningMessages.add("[WARNING] " + warning)); int numWarnings = warningMessages.size(); int numErrors = 0; if(errorsInCompilation) { errors.forEach(error -> errorMessages.add("[ERROR] " + error)); numErrors = errorMessages.size(); } boolean hasWarningsOrErrors = numWarnings > 0 || errorsInCompilation; StringBuilder sb; sb = new StringBuilder(); sb.append(getProjectName().isEmpty() ? "Gosu compilation" : getProjectName()); sb.append(" completed"); if(hasWarningsOrErrors) { sb.append(" with "); if(numWarnings > 0) { sb.append(numWarnings).append(" warning").append(numWarnings == 1 ? "" : 's'); } if(errorsInCompilation) { sb.append(numWarnings > 0 ? " and " : ""); sb.append(numErrors).append(" error").append(numErrors == 1 ? "" : 's'); } } else { sb.append(" successfully."); } if(hasWarningsOrErrors) { log.warn(sb.toString()); } else { log.info(sb.toString()); } //log at most 100 warnings or errors warningMessages.subList(0, Math.min(warningMessages.size(), 100)).forEach(log::info); errorMessages.subList(0, Math.min(errorMessages.size(), 100)).forEach(log::error); if(errorsInCompilation) { if(getFailOnError()) { buildError("Gosu compilation failed with errors; see compiler output for details."); } else { log.warn("Gosu Compiler: Ignoring compilation failure(s) as 'failOnError' was set to false"); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy