/******************************************************************************* * Copyright (c) 2007, 2008 Edgar Espina. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.deved.antlride.internal.core.builder; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import org.deved.antlride.core.AntlrConfiguration; import org.deved.antlride.core.AntlrConsole; import org.deved.antlride.core.AntlrCore; import org.deved.antlride.core.AntlrLanguageToolkit; import org.deved.antlride.core.build.AntlrBuildUnit; import org.deved.antlride.core.build.AntlrBuildUnitRepository; import org.deved.antlride.core.build.AntlrDeployer; import org.deved.antlride.core.build.AntlrDeployerRepository; import org.deved.antlride.core.build.AntlrProblem; import org.deved.antlride.core.build.AntlrProblemFactory; import org.deved.antlride.core.build.AntlrSourceParserRepository; import org.deved.antlride.core.env.JavaEnvironmentRepository; import org.deved.antlride.core.env.JavaEnvironmentRepositoryLookup; import org.deved.antlride.core.util.AntlrTextHelper; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.dltk.compiler.problem.DefaultProblem; import org.eclipse.dltk.compiler.problem.DefaultProblemFactory; import org.eclipse.dltk.compiler.problem.IProblemFactory; import org.eclipse.dltk.compiler.problem.IProblemReporter; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.builder.IBuildContext; import org.eclipse.dltk.core.builder.IBuildParticipant; import org.eclipse.dltk.core.builder.IBuildParticipantExtension; import org.eclipse.dltk.internal.core.builder.BuildProblemReporter; import org.eclipse.dltk.internal.core.builder.SourceModuleBuildContext; @SuppressWarnings("restriction") public class AntlrBuilder implements IBuildParticipant, IBuildParticipantExtension { private static final String PATTERN = "%32"; private static final String LINE_ESC_PROPERTY = "%0A"; private static final String CARRY_RET_ESC_PROPERTY = "%0D"; // private boolean depEnable = false; public AntlrBuilder() { } public boolean beginBuild(int buildType) { return buildType == INCREMENTAL_BUILD || buildType == FULL_BUILD; } public void build(IBuildContext context) throws CoreException { try { AntlrLanguageToolkit languageToolkit = AntlrLanguageToolkit .getDefault(); AntlrConsole console = languageToolkit.getConsole(); // create a build unit for the current resource AntlrBuildUnit unit = AntlrBuildUnitRepository.create(context); if (!unit.canBuild()) { // no package defined or can't get the grammar from context return; } IFile tokenVocabFile = unit.getTokenVocabFile(); if (tokenVocabFile != null) { ISourceModule tokenVocabModule = AntlrSourceParserRepository .getSourceModule(tokenVocabFile); SourceModuleBuildContext tokenVocabBuildContext = new SourceModuleBuildContext( new DefaultProblemFactory(), tokenVocabModule, INCREMENTAL_BUILD); build(tokenVocabBuildContext); BuildProblemReporter reporter = (BuildProblemReporter) tokenVocabBuildContext .getProblemReporter(); if (reporter != null) { reporter.flush(); } } // clean up errors for composite grammars IFile[] dependencies = unit.getDependencies(); for (IFile file : dependencies) { clearMarkers(file); } // pre-build phase preBuild(unit); // java virtual machine path JavaEnvironmentRepository javaEnvironmentRepository = JavaEnvironmentRepositoryLookup .lookup(); IPath java = javaEnvironmentRepository.getEnvironment( unit.getFile().getProject()).getJavaPath(); List<String> command = new ArrayList<String>(); command.add(java.toOSString()); String memory = unit.getConfiguration().getXmx(); if (!"0".equals(memory)) { command.add("-Xmx" + memory + "m"); } // system properties unit.addSystemProperty("gPATTERN", PATTERN); unit.addSystemProperty("gLINE_ESCAPE", LINE_ESC_PROPERTY); unit.addSystemProperty("gCREUTRNS_ESCAPE", CARRY_RET_ESC_PROPERTY); command.addAll(unit.getSystemProperties()); // build classpath AntlrDeployer deployer = AntlrDeployerRepository.createDeployer(); Set<String> hortogonalClasspath = new LinkedHashSet<String>(); for (IPath deployClasspath : deployer.deployRuntime()) hortogonalClasspath.add(deployClasspath.toOSString()); hortogonalClasspath.addAll(Arrays.asList(unit.getClasspath().split( File.pathSeparator))); StringBuilder classpath = new StringBuilder(); Iterator<String> classPathIterator = hortogonalClasspath.iterator(); classpath.append(classPathIterator.next()); while (classPathIterator.hasNext()) { classpath.append(File.pathSeparator); classpath.append(classPathIterator.next()); } command.add("-classpath"); command.add(classpath.toString()); // create the process command.add(unit.getBuildClassName()); List<String> appcmd = new ArrayList<String>(); appcmd.addAll(unit.getApplicationArgs()); appcmd.add("-lib"); appcmd.add(unit.getAbsoluteLibraryPath().toOSString()); appcmd.add("-o"); appcmd.add(unit.getOutputFolder().toOSString()); appcmd.add(unit.getAbsolutePath().toOSString()); command.addAll(appcmd); String fullpath = unit.getAbsolutePath().toOSString(); // console.info(command.toString()); console.info(unit.getDescription()); console.info("Grammar: " + fullpath); // StringBuilder options = new StringBuilder(); // for (int k = 0; k < appcmd.size() - 1; k++) { // options.append(appcmd.get(k)); // options.append(" "); // } // console.info("Options: " + options.append("\n").toString()); ProcessBuilder pb = new ProcessBuilder(command); pb.directory(unit.getAbsoluteFolderPath().toFile()); long startBuild = System.currentTimeMillis(); Process process = pb.start(); BufferedReader in = new BufferedReader(new InputStreamReader( process.getInputStream())); IProblemReporter problemReporter = context.getProblemReporter(); Set<String> problems = new HashSet<String>(); /** This map of problem reporters is used with composite grammars */ Map<IPath, IProblemReporter> reporters = new HashMap<IPath, IProblemReporter>() { private static final long serialVersionUID = 1L; private IProblemFactory problemFactory = new DefaultProblemFactory(); @Override public IProblemReporter get(Object key) { IProblemReporter problemReporter = super.get(key); if (problemReporter == null) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace() .getRoot(); IPath path = (IPath) key; IResource resource = root.getFile(path); problemReporter = new BuildProblemReporter(problemFactory, resource); put(path, problemReporter); } return problemReporter; } }; reporters.put(unit.getPath(), problemReporter); int errors = 0; int warnings = 0; String line = in.readLine(); while (line != null) { if (line.startsWith(PATTERN)) { line = AntlrTextHelper.unEscapeNewlines(line); // check for duplicated problems if (problems.add(line)) { String[] message = line.split(PATTERN); AntlrProblem problem = AntlrProblemFactory.create(unit, message); // report problems reporters.get(problem.getFilepath()).reportProblem( problem.toDLTKProblem()); if (problem.isError()) { errors++; } else { warnings++; } String desc = problem.getRawMessage(); console.error(desc); if (problem.getLineWithProblem().length() > 0) { console.error(" |---> " + problem.getLineWithProblem() + "\n"); } String key = desc.split("\n")[0]; console.setAttribute(key.trim(), problem); } } else { if (!fullpath.equals(line)) { // ANTLR 3.1.3 print the full path, don't let to print // it console.info(line); } } line = in.readLine(); } long endBuild = System.currentTimeMillis(); long buildTime = endBuild - startBuild; try { in.close(); process.destroy(); } catch (Exception ex) { ex.printStackTrace(); } long seconds = TimeUnit.MILLISECONDS.toSeconds(buildTime); if (warnings > 0) { console.error(String.format("\n%s warning%s\n", warnings, warnings == 1 ? "" : "s")); } if (errors == 0) { console.info("BUILD SUCCESSFUL"); } else { console.error(String.format("%s error%s\n", errors, errors == 1 ? "" : "s")); console.error("BUILD FAIL"); } long time = seconds; String timeunit = "second"; if (time <= 0) { time = buildTime; timeunit = "millisecond"; } console.info(String.format("Total time: %s %s%s\n", time, timeunit, time == 1 ? "" : "s")); postBuild(unit); } catch (CoreException ex) { throw ex; } catch (Exception ex) { IStatus status = new Status(IStatus.ERROR, AntlrCore.PLUGIN_ID, "Build fail", ex); throw new CoreException(status); } } private void preBuild(final AntlrBuildUnit unit) { AntlrConfiguration conf = unit.getConfiguration(); if (conf.isOutputFolderRelativeToWorkspace()) { // check for generated resources and deleted // this only works for compatibility for ANTLR IDE 1.3.0 IContainer outputContainer = unit.getOutputContainer(); if (outputContainer != null && outputContainer.exists()) { IResourceVisitor preBuildVisitor = new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (unit.isGeneratedResource(resource)) { try { resource.delete(true, unit.getMonitor()); } catch (CoreException ex) { AntlrCore.error(ex); } } else { unit.excludeResource(resource); } return true; } }; try { outputContainer.accept(preBuildVisitor, IResource.DEPTH_ONE, IContainer.INCLUDE_PHANTOMS); } catch (CoreException e) { AntlrCore.error(e); } } unit.cleanupResources(); } } private void postBuild(final AntlrBuildUnit unit) { AntlrConfiguration conf = unit.getConfiguration(); if (conf.isOutputFolderRelativeToWorkspace()) { IContainer outputContainer = unit.getOutputContainer(); IResourceVisitor postBuildVisitor = new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (unit.markAsGeneratedResource(resource)) { // move the *.tokens file String ext = resource.getLocation().getFileExtension(); if ("tokens".equals(ext)) { IPath outputFolder = unit.getOutputFolder(); IPath grammarFolder = unit.getAbsoluteFolderPath(); if (!grammarFolder.equals(outputFolder)) { try { IPath moveTo = unit.getFolderPath().append( resource.getName()); IWorkspaceRoot root = ResourcesPlugin .getWorkspace().getRoot(); IFile prevTokensFile = root.getFile(moveTo); if (prevTokensFile.exists()) { prevTokensFile.delete(true, unit .getMonitor()); } resource.move(moveTo, true, unit .getMonitor()); } catch (CoreException e) { AntlrCore.error(e); } } } } return true; } }; try { if (outputContainer != null) { outputContainer.refreshLocal(IResource.DEPTH_ONE, unit .getMonitor()); outputContainer.accept(postBuildVisitor, IResource.DEPTH_ONE, IResource.NONE); // after process all the generated resources the *.tokens // file // is moved to the same location of the grammar // refresh the output dir outputContainer.refreshLocal(IResource.DEPTH_ONE, unit .getMonitor()); } // refresh the grammar folder unit.getFolder().refreshLocal(IResource.DEPTH_ONE, unit.getMonitor()); } catch (CoreException e) { e.printStackTrace(); } } } public void endBuild(IProgressMonitor monitor) { } public void buildExternalModule(IBuildContext context) throws CoreException { } private static void clearMarkers(IResource resource) { if (resource != null) { try { if (resource.findMarkers(DefaultProblem.MARKER_TYPE_PROBLEM, true, IResource.DEPTH_INFINITE).length > 0) { resource.deleteMarkers(DefaultProblem.MARKER_TYPE_PROBLEM, true, IResource.DEPTH_INFINITE); } } catch (CoreException e) { e.printStackTrace(); } } } // @SuppressWarnings("rawtyps") // public DependencyResponse getDependencies(int buildType, Set localElements, // Set externalElements, Set oldExternalFolders, Set externalFolders) { // DependencyResponse response = null; // // enable this when the build order works as expected // if (depEnable) { // Set<ISourceModule> depmodules = new LinkedHashSet<ISourceModule>(); // for (Object object : localElements) { // ISourceModule sourceModule = (ISourceModule) object; // AntlrBuildUnit unit = AntlrBuildUnitRepository // .create(sourceModule); // if (unit.canBuild()) { // depmodules.addAll(getDependencies(unit)); // } // } // if (depmodules.size() > 0) { // System.out.println("DEPS=>" + depmodules); // response = DependencyResponse.createLocal(depmodules); // } // } // return response; // } // private Set<ISourceModule> getDependencies(AntlrBuildUnit unit) { // Set<ISourceModule> depmodules = new LinkedHashSet<ISourceModule>(); // IFile[] dependencies = unit.getDependencies(); // for (IFile depfile : dependencies) { // try { // if (depfile.exists()) { // ISourceModule depsm = AntlrSourceParserRepository // .getSourceModule(depfile); // if (depsm != null) { // depmodules.add(depsm); // } // } // } catch (FileNotFoundException e) { // e.printStackTrace(); // } // } // return depmodules; // } }