package ca.coglinc.gradle.plugins.javacc.compiler; import java.io.File; import org.apache.commons.io.FileUtils; import org.gradle.api.file.FileTree; import org.gradle.api.file.FileVisitor; import org.gradle.api.file.RelativePath; import org.gradle.api.logging.Logger; import ca.coglinc.gradle.plugins.javacc.JavaccTaskException; import ca.coglinc.gradle.plugins.javacc.compilationresults.CompiledJavaccFile; import ca.coglinc.gradle.plugins.javacc.compilationresults.CompiledJavaccFilesDirectory; import ca.coglinc.gradle.plugins.javacc.compilationresults.CompiledJavaccFilesDirectoryFactory; import ca.coglinc.gradle.plugins.javacc.programexecution.ProgramArguments; import ca.coglinc.gradle.plugins.javacc.programexecution.ProgramInvoker; /** * This {@link SourceFileCompiler} implementation invokes JavaCC programs to compile supported files to Java or JavaCC files. * <p></p> * It supports the following programs: * <ul> * <li>JavaCC</li> * <li>JJTree</li> * <li>JJDoc</li> * </ul> */ public class JavaccSourceFileCompiler implements SourceFileCompiler { private final ProgramInvoker programInvoker; private final ProgramArguments argumentsProvidedByTask; private final CompilerInputOutputConfiguration configuration; private CompiledJavaccFilesDirectoryFactory compiledJavaccFilesDirectoryFactory = new CompiledJavaccFilesDirectoryFactory(); private final Logger logger; public JavaccSourceFileCompiler(ProgramInvoker programInvoker, ProgramArguments argumentsProvidedByTask, CompilerInputOutputConfiguration configuration, Logger logger) { this.programInvoker = programInvoker; this.argumentsProvidedByTask = argumentsProvidedByTask; this.configuration = configuration; this.logger = logger; } @Override public void compileSourceFilesToTempOutputDirectory() { configuration.getSource().visit(getJavaccSourceFileVisitor()); } private FileVisitor getJavaccSourceFileVisitor() { return new JavaccSourceFileVisitor(this); } @Override public void copyNonJavaccFilesToOutputDirectory() { configuration.getSource().visit(getNonJavaccSourceFileVisitor()); } private FileVisitor getNonJavaccSourceFileVisitor() { return new NonJavaccSourceFileVisitor(this); } @Override public void compile(File inputDirectory, RelativePath inputRelativePath) { logger.debug("Compiling {} file [{}] from [{}] into [{}]", programInvoker.getProgramName(), inputRelativePath, inputDirectory, getOutputDirectory()); ProgramArguments arguments = buildProgramArguments(inputDirectory, inputRelativePath); logger.debug("Invoking {} with arguments [{}]", programInvoker.getProgramName(), arguments); try { programInvoker.invokeCompiler(arguments); } catch (Exception exception) { final String errorMessage = String.format("Unable to compile '%s' from '%s' into '%s'", inputRelativePath, inputDirectory, getOutputDirectory()); throw new JavaccTaskException(errorMessage, exception); } } private ProgramArguments buildProgramArguments(File inputDirectory, RelativePath inputRelativePath) { ProgramArguments commandLineArguments = new ProgramArguments(argumentsProvidedByTask); commandLineArguments.addFilename(inputRelativePath.getFile(inputDirectory).getAbsolutePath()); return programInvoker.augmentArguments(inputDirectory, inputRelativePath, commandLineArguments); } @Override public void copyCompiledFilesFromTempOutputDirectoryToOutputDirectory() { CompiledJavaccFilesDirectory compiledJavaccFilesDirectory = compiledJavaccFilesDirectoryFactory.getCompiledJavaccFilesDirectory( configuration.getTempOutputDirectory(), configuration.getCompleteSourceTree(), getOutputDirectory(), getLogger()); for (CompiledJavaccFile compiledJavaccFile : compiledJavaccFilesDirectory.listFiles()) { FileTree javaSourceTree = configuration.getJavaSourceTree(); if (compiledJavaccFile.customAstClassExists(javaSourceTree)) { compiledJavaccFile.ignoreCompiledFileAndUseCustomAstClassFromJavaSourceTree(javaSourceTree); } else if (compiledJavaccFile.customAstClassExists()) { compiledJavaccFile.copyCustomAstClassToTargetDirectory(configuration.getCompleteSourceTree()); } else { compiledJavaccFile.copyCompiledFileToTargetDirectory(); } } } @Override public String supportedSuffix() { return programInvoker.supportedSuffix(); } @Override public String getProgramName() { return programInvoker.getProgramName(); } @Override public File getOutputDirectory() { return configuration.getOutputDirectory(); } @Override public File getInputDirectory() { return configuration.getInputDirectory(); } @Override public void createTempOutputDirectory() { configuration.getTempOutputDirectory().mkdirs(); } @Override public void cleanTempOutputDirectory() { FileUtils.deleteQuietly(configuration.getTempOutputDirectory()); } @Override public Logger getLogger() { return logger; } void setCompiledJavaccFilesDirectoryFactoryForTest(CompiledJavaccFilesDirectoryFactory factory) { compiledJavaccFilesDirectoryFactory = factory; } }