Java tutorial
/******************************************************************************* * Copyright (c) 2009 IBM Corporation. * * 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 x10dt.ui.launch.core.builder; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.IncrementalProjectBuilder; 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.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.core.runtime.jobs.MultiRule; import org.eclipse.imp.java.hosted.BuildPathUtils; import org.eclipse.imp.preferences.IPreferencesService; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.console.MessageConsole; import org.eclipse.ui.console.MessageConsoleStream; import polyglot.frontend.Compiler; import polyglot.frontend.Globals; import polyglot.frontend.Job; import polyglot.main.Options; import polyglot.util.InternalCompilerError; import x10.ExtensionInfo; import x10.X10CompilerOptions; import x10dt.core.X10DTCorePlugin; import x10dt.core.preferences.generated.X10Constants; import x10dt.core.utils.AlwaysTrueFilter; import x10dt.core.utils.CompilerOptionsFactory; import x10dt.core.utils.CountableIterableFactory; import x10dt.core.utils.IFilter; import x10dt.core.utils.URIUtils; import x10dt.ui.launch.core.Constants; import x10dt.ui.launch.core.LaunchCore; import x10dt.ui.launch.core.Messages; import x10dt.ui.launch.core.builder.target_op.IX10BuilderFileOp; import x10dt.ui.launch.core.utils.CollectionUtils; import x10dt.ui.launch.core.utils.CoreResourceUtils; import x10dt.ui.launch.core.utils.IdentityFunctor; import x10dt.ui.launch.core.utils.ProjectUtils; import x10dt.ui.launch.core.utils.UIUtils; import x10dt.ui.launch.core.utils.X10BuilderUtils; /** * X10 builder base class for all the different back-ends. * * @author egeay */ public abstract class AbstractX10Builder extends IncrementalProjectBuilder { // --- Abstract methods definition /** * Creates the Polyglot extension information that controls the compiler options for the particular back-end. * * @param classPath The class path to consider for compilation. * @param sourcePath The source path to use. * @param localOutputDir The directory where the generated files will be created. * @param withMainMethod True if the main method should be generated, false otherwise. * @param monitor The monitor to use for reporting progress and/or cancel the operation. * @return A non-null object. */ public abstract ExtensionInfo createExtensionInfo(final String classPath, final List<File> sourcePath, final String localOutputDir, final boolean withMainMethod, final IProgressMonitor monitor); /** * Creates a filter for all the native files that may be present in the projects for the current back-end. * * @return A non-null filter instance. */ public abstract IFilter<IFile> createNativeFilesFilter(); /** * Creates the instance of {@link IX10BuilderFileOp} depending of the connection type, local or remote. * * @return A non-null object. * @throws CoreException Occurs if we could not load the X10 platform configuration associated with the project. */ public abstract IX10BuilderFileOp createX10BuilderFileOp() throws CoreException; /** * Returns the file extension corresponding to each back-end (e.g., ".java" for Java back-end). * * @return A non-null string in all cases. */ public abstract String getFileExtension(); // --- Abstract methods implementation static Map<Integer, String> BUILD_TYPE_NAME = new HashMap<Integer, String>(); static { BUILD_TYPE_NAME.put(IncrementalProjectBuilder.AUTO_BUILD, "auto"); BUILD_TYPE_NAME.put(IncrementalProjectBuilder.CLEAN_BUILD, "clean"); BUILD_TYPE_NAME.put(IncrementalProjectBuilder.FULL_BUILD, "full"); BUILD_TYPE_NAME.put(IncrementalProjectBuilder.INCREMENTAL_BUILD, "incremental"); } private void logBuildTypeToConsole(final int kind, PrintStream ps) { IResourceDelta delta = this.getDelta(getProject()); ps.println("Build initiated: type = " + BUILD_TYPE_NAME.get(kind) + "; delta = " + (delta != null ? delta.toString() : "<none>")); } @SuppressWarnings("rawtypes") protected final IProject[] build(final int kind, final Map args, final IProgressMonitor monitor) throws CoreException { final MessageConsole messageConsole = UIUtils.findOrCreateX10Console(); messageConsole.clearConsole(); logBuildTypeToConsole(kind, new PrintStream(messageConsole.newMessageStream())); if (!getProject().isAccessible()) { return null; } try { CoreResourceUtils.deleteBuildMarkers(getProject(), IResource.DEPTH_ZERO); if (this.fProjectWrapper == null) { return new IProject[0]; } final SubMonitor subMonitor = SubMonitor.convert(monitor, 100); final Collection<IFile> sourcesToCompile = new HashSet<IFile>(); final Collection<IFile> deletedSources = new HashSet<IFile>(); final Collection<IFile> nativeFiles = new HashSet<IFile>(); IX10BuilderFileOp x10BuilderOp = null; try { x10BuilderOp = createX10BuilderFileOp(); } catch (CoreException except) { CoreResourceUtils.addBuildMarkerTo(getProject(), except.getMessage(), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_NORMAL); } if (x10BuilderOp == null) { return new IProject[0]; } if (!x10BuilderOp.hasAllPrerequisites()) { CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.AXB_IncompleteConfMsg, getProject().getName()), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); UIUtils.showProblemsView(); return null; } if (!x10BuilderOp.hasValidCompilationCommands()) { CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.AXB_InvalidCommands, getProject().getName()), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); UIUtils.showProblemsView(); return null; } checkForCancelation(subMonitor); final Set<IProject> dependentProjects = cleanFiles(kind, subMonitor.newChild(10), sourcesToCompile, deletedSources, nativeFiles, x10BuilderOp); if (dependentProjects == null) { return null; } final String localOutputDir = getLocalOutputDir(); x10BuilderOp.copyToOutputDir(nativeFiles, subMonitor.newChild(5)); checkForCancelation(subMonitor); if (!sourcesToCompile.isEmpty()) { compile(localOutputDir, sourcesToCompile, x10BuilderOp, subMonitor); } this.fProjectWrapper.getProject().refreshLocal(IResource.DEPTH_INFINITE, subMonitor); dependentProjects.addAll(ProjectUtils.getDependentProjects(fProjectWrapper)); return dependentProjects.toArray(new IProject[dependentProjects.size()]); } catch (Exception except) { if (!(except instanceof OperationCanceledException)) { LaunchCore.log(IStatus.ERROR, Messages.AXB_BuildException, except); CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.XEQ_InternalCompilerErrorMsg, getProject().getName()), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); } else { // --- cancelation super.forgetLastBuiltState(); throw new OperationCanceledException(); } } finally { info(); if (monitor.isCanceled()) { super.forgetLastBuiltState(); throw new OperationCanceledException(); } monitor.done(); } return new IProject[0]; } protected String getLocalOutputDir() throws CoreException { return ProjectUtils.getProjectOutputDirPath(getProject()); } abstract protected void deleteX10GeneratedFiles() throws CoreException; private Set<IProject> cleanFiles(final int kind, final SubMonitor subMonitor, final Collection<IFile> sourcesToCompile, final Collection<IFile> deletedSources, final Collection<IFile> nativeFiles, final IX10BuilderFileOp x10BuilderFileOp) throws CoreException { subMonitor.beginTask(null, 10); try { final boolean shouldBuildAll; if (kind == FULL_BUILD || kind == CLEAN_BUILD) { this.fDependencyInfo.clearAllDependencies(); shouldBuildAll = true; deleteX10GeneratedFiles(); } else { shouldBuildAll = this.fDependencyInfo.getDependencies().isEmpty(); } final Set<IProject> dependentProjects = new HashSet<IProject>(); collectSourceFilesToCompile(sourcesToCompile, nativeFiles, deletedSources, this.fProjectWrapper, dependentProjects, createNativeFilesFilter(), shouldBuildAll, subMonitor.newChild(5)); CoreResourceUtils.deleteBuildMarkers(getProject(), IResource.DEPTH_ZERO); clearDependencyInfoAsNeeded(sourcesToCompile, deletedSources); clearMarkers(sourcesToCompile); // --- This needs to happen before filter because we need to clear markers on files that have been recently excluded from the class path. filter(sourcesToCompile); if (subMonitor.isCanceled()) { return null; } final ISchedulingRule rule = MultiRule.combine(getSchedulingRule(sourcesToCompile), MultiRule.combine(getSchedulingRule(nativeFiles), getSchedulingRule(deletedSources))); final IWorkspace workspace = ResourcesPlugin.getWorkspace(); final IWorkspaceRunnable runnable = new IWorkspaceRunnable() { public void run(final IProgressMonitor monitor) throws CoreException { x10BuilderFileOp.cleanFiles( CountableIterableFactory.create(sourcesToCompile, nativeFiles, deletedSources), subMonitor.newChild(5)); } }; checkForCancelation(subMonitor); workspace.run(runnable, rule, IWorkspace.AVOID_UPDATE, subMonitor); return dependentProjects; } finally { subMonitor.done(); } } // --- Overridden methods protected void clean(final IProgressMonitor monitor) throws CoreException { if (getProject().isAccessible()) { if (this.fProjectWrapper == null) { this.fProjectWrapper = JavaCore.create(getProject()); } this.fDependencyInfo.clearAllDependencies(); IX10BuilderFileOp x10BuilderOp = null; try { x10BuilderOp = createX10BuilderFileOp(); } catch (CoreException except) { CoreResourceUtils.addBuildMarkerTo(getProject(), except.getMessage(), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_NORMAL); return; } if (!x10BuilderOp.hasAllPrerequisites()) { CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.AXB_IncompleteConfMsg, getProject().getName()), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); UIUtils.showProblemsView(); } cleanFiles(CLEAN_BUILD, SubMonitor.convert(monitor), new HashSet<IFile>(), new HashSet<IFile>(), new HashSet<IFile>(), x10BuilderOp); } } protected void startupOnInitialize() { if (getProject().isAccessible()) { if (this.fProjectWrapper == null) { this.fProjectWrapper = JavaCore.create(getProject()); } if (this.fDependencyInfo == null) { this.fDependencyInfo = new PolyglotDependencyInfo(fProjectWrapper); } } } public IJavaProject getJavaProject() { return fProjectWrapper; } /** * Returns the main generated file for the X10 file provided, i.e. for C++ back-end this should return the C++ file * corresponding to the X10 file in question. * * @param project * The project containing the X10 file in question. * @param x10File * The x10 file to consider. * @return A non-null file if we found one, otherwise <b>null</b>. * @throws CoreException * Occurs if we could not access some project information or get the local file for the location identified. */ public File getMainGeneratedFile(final IJavaProject project, final IFile x10File) throws CoreException { final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (final IClasspathEntry cpEntry : project.getRawClasspath()) { if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE && cpEntry.getPath().isPrefixOf(x10File.getFullPath()) && !BuildPathUtils.isExcluded(x10File.getFullPath(), cpEntry)) { final IPath outputLocation; if (cpEntry.getOutputLocation() == null) { outputLocation = project.getOutputLocation(); } else { outputLocation = cpEntry.getOutputLocation(); } final StringBuilder sb = new StringBuilder(); sb.append(File.separatorChar) .append(x10File.getProjectRelativePath().removeFileExtension().toString()) .append(getFileExtension()); final IPath projectRelativeFilePath = new Path(sb.toString()); final int srcPathCount = cpEntry.getPath().removeFirstSegments(1).segmentCount(); final IPath generatedFilePath = outputLocation .append(projectRelativeFilePath.removeFirstSegments(srcPathCount)); final IFileStore fileStore = EFS.getLocalFileSystem() .getStore(URIUtils.getExpectedURI(root.getFile(generatedFilePath).getLocationURI())); if (fileStore.fetchInfo().exists()) { return fileStore.toLocalFile(EFS.NONE, null); } } } return null; } // --- Code for descendants protected void buildOptions(final String classPath, final List<File> sourcePath, final String localOutputDir, final Options options, final boolean withMainMethod) { options.assertions = true; options.classpath = classPath; options.output_classpath = options.classpath; options.output_directory = new File(localOutputDir); options.source_path = sourcePath; options.compile_command_line_only = true; final IPreferencesService prefService = X10DTCorePlugin.getInstance().getPreferencesService(); options.assertions = prefService.getBooleanPreference(X10Constants.P_PERMITASSERT); CompilerOptionsFactory.setOptions(prefService, (X10CompilerOptions) options); } // --- Private code private void filter(Collection<IFile> files) { Collection<IFile> filesToRemove = new ArrayList<IFile>(); for (IFile file : files) { if (BuildPathUtils.isExcluded(file.getFullPath(), this.fProjectWrapper)) { filesToRemove.add(file); } } files.removeAll(filesToRemove); } private ISchedulingRule getSchedulingRule(Collection<IFile> files) { Collection<ISchedulingRule> rules = new ArrayList<ISchedulingRule>(); for (IFile file : files) { rules.add(file); } return MultiRule.combine(rules.toArray(new ISchedulingRule[0])); } private void clearMarkers(final Collection<IFile> sourcesToCompile) { for (final IFile file : sourcesToCompile) { CoreResourceUtils.deleteBuildMarkers(file); } } private void collectSourceFilesToCompile(final Collection<IFile> sourcesToCompile, final Collection<IFile> nativeFiles, final Collection<IFile> deletedSources, final IJavaProject javaProject, final Set<IProject> dependentProjects, final IFilter<IFile> nativeFilesFilter, final boolean fullBuild, final SubMonitor monitor) throws CoreException { try { monitor.beginTask(Messages.CPPB_CollectingSourcesTaskName, 1); final Set<Object> fullBuildSet = new HashSet<Object>(); Collection<IProject> projects = new ArrayList<IProject>(); projects.add(javaProject.getProject()); projects.addAll(ProjectUtils.getDependentProjects(javaProject)); for (IProject project : projects) { final IResourceDelta resourceDelta = getDelta(project); if (resourceDelta != null) { resourceDelta.accept(new IResourceDeltaVisitor() { public boolean visit(final IResourceDelta delta) throws CoreException { if (delta.getResource().getType() == IResource.FOLDER) { final IFolder folder = (IFolder) delta.getResource(); if (delta.getKind() == IResourceDelta.REMOVED || delta.getKind() == IResourceDelta.ADDED) { sourcesToCompile.addAll(getChangeDependents(folder)); } } if (delta.getResource().getType() == IResource.FILE) { final IFile file = (IFile) delta.getResource(); if (isClassPathFile(file)) { fullBuildSet.add(new Object()); // --- If the classpath has been changed, then we need to do a full build. } if (isX10File(file) || isClassFile(file)) { if (delta.getKind() == IResourceDelta.REMOVED) { if (!isClassFile(file) && file.getProject().equals(fProjectWrapper.getProject())) { deletedSources.add(file); } sourcesToCompile.addAll(getChangeDependents(file)); } else if (delta.getKind() == IResourceDelta.ADDED || delta.getKind() == IResourceDelta.CHANGED) { if (!isClassFile(file) && file.getProject().equals(fProjectWrapper.getProject())) { sourcesToCompile.add(file); } sourcesToCompile.addAll(getChangeDependents(file)); } } } return true; } }); } } final boolean buildAll = !fullBuildSet.isEmpty() || fullBuild; final IPreferencesService prefService = X10DTCorePlugin.getInstance().getPreferencesService(); final boolean conservativeBuild = prefService.getBooleanPreference(X10Constants.P_CONSERVATIVEBUILD); final IResourceVisitor visitor = new IResourceVisitor() { // --- Interface methods implementation public boolean visit(final IResource resource) throws CoreException { if ((resource.getType() == IResource.FILE) && !resource.isDerived()) { final IFile file = (IFile) resource; if (isX10File(file)) { final File generatedFile = getMainGeneratedFile(AbstractX10Builder.this.fProjectWrapper, file); boolean unprocessed = ((generatedFile == null) && !CoreResourceUtils.hasBuildErrorMarkers(file)); if (buildAll || (conservativeBuild && unprocessed)) { sourcesToCompile.add(file); /*if (!resource.getProject().equals(javaProject.getProject())) { dependentProjects.add(resource.getProject()); }*/ } } else if (nativeFilesFilter.accepts(file)) { nativeFiles.add(file); } } return true; } }; if (buildAll || conservativeBuild) { final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (final IClasspathEntry cpEntry : javaProject.getRawClasspath()) { if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (cpEntry.getPath().segmentCount() > 1) { final IFolder folder = root.getFolder(cpEntry.getPath()); if (folder.exists()) { folder.accept(visitor); } } } } } } finally { monitor.done(); } } private void clearDependencyInfoAsNeeded(Collection<IFile> sourcesToCompile, Collection<IFile> deletedSources) { for (IFile srcFile : sourcesToCompile) { fDependencyInfo.clearDependenciesOf(srcFile.getFullPath().toOSString()); } for (IFile srcFile : deletedSources) { fDependencyInfo.clearDependenciesOf(srcFile.getFullPath().toOSString()); } } private void info() throws CoreException { final IResourceVisitor visitor = new IResourceVisitor() { public boolean first = true; // --- Interface methods implementation public boolean visit(final IResource resource) throws CoreException { if ((resource.getType() == IResource.FILE) && !resource.isDerived()) { final IFile file = (IFile) resource; if (isX10File(file)) { final File generatedFile = getMainGeneratedFile(AbstractX10Builder.this.fProjectWrapper, file); boolean unprocessed = ((generatedFile == null) && !CoreResourceUtils.hasBuildErrorMarkers(file)); if (unprocessed && !BuildPathUtils.isExcluded(file.getFullPath(), AbstractX10Builder.this.fProjectWrapper)) { if (first) { first = false; CoreResourceUtils.addBuildMarkerTo(getProject(), Messages.AXB_Unprocessed, IMarker.SEVERITY_ERROR, IMarker.PRIORITY_NORMAL); } LaunchCore.log(IStatus.ERROR, NLS.bind(Messages.AXB_UnprocessedFile, file.getFullPath().toOSString())); } } } return true; } }; final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); for (final IClasspathEntry cpEntry : fProjectWrapper.getRawClasspath()) { if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (cpEntry.getPath().segmentCount() > 1) { final IFolder folder = root.getFolder(cpEntry.getPath()); if (folder.exists()) { folder.accept(visitor); } } } } } private void compile(final String localOutputDir, final Collection<IFile> sourcesToCompile, final IX10BuilderFileOp builderOp, final SubMonitor subMonitor) throws CoreException { final IWorkspace workspace = ResourcesPlugin.getWorkspace(); final ISchedulingRule rule = getSchedulingRule(sourcesToCompile); final IWorkspaceRunnable runnable = new IWorkspaceRunnable() { public void run(final IProgressMonitor monitor) throws CoreException { Map<String, Collection<String>> generatedFiles = compileX10Files(localOutputDir, sourcesToCompile, subMonitor.newChild(20)); compileGeneratedFiles(builderOp, generatedFiles, sourcesToCompile, subMonitor.newChild(65)); } }; checkForCancelation(subMonitor); workspace.run(runnable, rule, IWorkspace.AVOID_UPDATE, subMonitor); } private void compileGeneratedFiles(final IX10BuilderFileOp builderOp, final Map<String, Collection<String>> generatedFiles, final Collection<IFile> sourcesToCompile, final SubMonitor monitor) throws CoreException { checkForCancelation(monitor); if (!generatedFiles.isEmpty()) { monitor.beginTask(null, 80); final Map<IPath, Collection<File>> sourcesToPostCompile = new HashMap<IPath, Collection<File>>(); for (IFile srcFile : sourcesToCompile) { final String name = BuildPathUtils.getBareName(srcFile, this.fProjectWrapper); final IPath packagePath = getPackagePath(srcFile); if (generatedFiles.containsKey(name)) { // --- Code was generated for srcFile during this build. if (checkPostCompilationCondition(srcFile.getFullPath().toString())) { addGeneratedFile(sourcesToPostCompile, packagePath, getLocalFiles(generatedFiles.get(name))); } addGeneratedFile(sourcesToPostCompile, packagePath, getFilesBlockedForPostCompilation(name)); } } checkForCancelation(monitor); builderOp.transfer(sourcesToPostCompile, monitor.newChild(10)); checkForCancelation(monitor); builderOp.compile(monitor.newChild(70)); } checkForCancelation(monitor); builderOp.archive(monitor); } private void checkForCancelation(IProgressMonitor monitor) { if (monitor.isCanceled()) { throw new OperationCanceledException(); } } private void addGeneratedFile(final Map<IPath, Collection<File>> map, final IPath pkgPath, final Collection<File> files) { final Collection<File> values = map.get(pkgPath); if (values == null) { map.put(pkgPath, files); } else { values.addAll(files); } } private IPath getPackagePath(final IFile file) { final IPath projectRelativePath = file.getProjectRelativePath().removeLastSegments(1); final String src = projectRelativePath.segment(0); if (src == null) { return projectRelativePath; } else { final IJavaProject javaProject = JavaCore.create(file.getProject()); final IPath srcPath = file.getProject().getFolder(src).getFullPath(); try { for (final IClasspathEntry cpEntry : javaProject.getRawClasspath()) { if (cpEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (srcPath.equals(cpEntry.getPath())) { return projectRelativePath.removeFirstSegments(1); } } } } catch (JavaModelException except) { // Let's forget and try with the current relative path given from Core Resources. } return projectRelativePath; } } private Collection<File> getFilesBlockedForPostCompilation(String name) throws CoreException { Collection<File> result = new ArrayList<File>(); Collection<String> paths = fBlockingPostCompilation.get(name); Collection<String> pathsToRemove = new ArrayList<String>(); if (paths != null) { for (String path : paths) { if (checkPostCompilationCondition(path)) { Collection<String> gens = fGeneratedFiles .get(BuildPathUtils.getBareName(path, fProjectWrapper)); result.addAll(getLocalFiles(gens)); pathsToRemove.add(path); } } paths.removeAll(pathsToRemove); } return result; } protected boolean checkPostCompilationCondition(final String srcPath) throws CoreException { Set<String> dependencies = this.fDependencyInfo.getDependencies().get(srcPath); final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); if (dependencies != null) { for (String path : dependencies) { IFile dep = wsRoot.getFile(new Path(path)); if (!dep.exists()) { // --- Some dependencies are to folders continue; } IJavaProject project = JavaCore.create(dep.getProject()); if (isX10File(dep)) { File f = getMainGeneratedFile(project, dep); if (f == null) { addToBlockingPostCompilation(BuildPathUtils.getBareName(path, fProjectWrapper), srcPath); return false; } } } } return true; } private void addToBlockingPostCompilation(String name, String path) { Collection<String> blocked = fBlockingPostCompilation.get(name); if (blocked == null) { blocked = new HashSet<String>(); fBlockingPostCompilation.put(name, blocked); } blocked.add(path); } public Collection<File> getLocalFiles(final Collection<String> generatedStrings) throws JavaModelException { Collection<File> result = new ArrayList<File>(); final IPath root = ResourcesPlugin.getWorkspace().getRoot().getLocation(); final File wsRoot = root.toFile(); final File outputLocation = new File(wsRoot, this.fProjectWrapper.getOutputLocation().toString().substring(1)); for (String name : generatedStrings) { if (name.startsWith(root.toOSString())) { result.add(new File(name)); } else { result.add(new File(outputLocation, name)); } } return result; } //protected abstract String getSrcClassPath(List<File> sourcePath) throws CoreException; protected String getSrcClassPath(List<File> sourcePath) throws CoreException { StringBuffer bufferPath = new StringBuffer(); final Set<IPath> srcPaths = ProjectUtils.getFilteredCpEntries(this.fProjectWrapper, new IdentityFunctor<IPath>(), new AlwaysTrueFilter<IPath>(), bufferPath); // removeSrcJava(srcPaths); // TODO: I should have threaded a list around sourcePath.addAll(CollectionUtils.transform(srcPaths, new IPathToFileFunc())); return bufferPath.toString(); } private Map<String, Collection<String>> compileX10Files(final String localOutputDir, final Collection<IFile> sourcesToCompile, final IProgressMonitor monitor) throws CoreException { checkSrcFolders(); List<File> sourcePath = new ArrayList<File>(); String classPath = getSrcClassPath(sourcePath); ExtensionInfo extInfo = createExtensionInfo(classPath, sourcePath, localOutputDir, false /* withMainMethod */, monitor); echoCommandLineToConsole(sourcesToCompile, extInfo); final Compiler compiler = new Compiler(extInfo, new X10ErrorQueue(this.fProjectWrapper, 1000000, extInfo.compilerName(), sourcesToCompile)); Globals.initialize(compiler); try { final Collection<String> files = new ArrayList<String>(); for (final IFile f : sourcesToCompile) { files.add(f.getLocation().toOSString()); } checkForCancelation(monitor); compiler.compileFiles(files); // compiler.compile(toSources(sourcesToCompile)); // --- This way of calling the compiler causes a bad behavior // (duplicate class error), // --- when there is a file that imports another one file a bad syntactic error. final Map<String, Collection<String>> outputFiles = compiler.outputFiles(); updateGeneratedFiles(outputFiles, sourcesToCompile); return outputFiles; } catch (InternalCompilerError except) { LaunchCore.log(IStatus.ERROR, Messages.AXB_CompilerInternalError, except); // The exception is also pushed on the error queue... A marker will be created accordingly for it. sourcesToCompile.clear(); // To prevent post-compilation step. return Collections.emptyMap(); } finally { if (!monitor.isCanceled()) analyze(extInfo.scheduler().commandLineJobs()); Globals.initialize(null); } } // Constants that describe the role of each slot in the 2D array that Configuration.options() returns. private static final int OPTION_NAME = 0; private static final int OPTION_TYPE = 1; private static final int OPTION_DESCRIPTION = 2; private static final int OPTION_VALUE = 3; private void echoCommandLineToConsole(final Collection<IFile> sourcesToCompile, final ExtensionInfo extInfo) { final IPreferencesService prefService = X10DTCorePlugin.getInstance().getPreferencesService(); if (prefService.getBooleanPreference(X10Constants.P_ECHOCOMPILEARGUMENTSTOCONSOLE)) { final MessageConsole console = UIUtils.findOrCreateX10Console(); final MessageConsoleStream consoleStream = console.newMessageStream(); try { X10CompilerOptions options = extInfo.getOptions(); String[][] opts = options.x10_config.options(); // --- The shape of this data structure is an array of: // --- (option,type,description,value) for each field in Configuration. consoleStream.write(getOptions(options)); String result = ""; for (int j = 0; j < opts.length; j++) { if (opts[j][OPTION_TYPE].equals("boolean")) { if (opts[j][OPTION_VALUE].equals("true")) { result += " -" + opts[j][OPTION_NAME] + " "; } } if (opts[j][OPTION_TYPE].equals("String")) { if (!opts[j][OPTION_VALUE].equals("null") && !opts[j][OPTION_VALUE].equals("")) { result += " -" + opts[j][OPTION_NAME] + "=" + opts[j][OPTION_VALUE] + " "; } } } consoleStream.write(result); for (IFile f : sourcesToCompile) { consoleStream.write("\""); consoleStream.write(X10BuilderUtils.getTargetSystemPath(f.getLocation().toPortableString())); consoleStream.write("\" "); } consoleStream.write("\n"); console.activate(); } catch (IOException except) { LaunchCore.log(IStatus.ERROR, Messages.AXB_EchoIOException, except); } } } private void checkSrcFolders() throws CoreException { try { final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); boolean hasNoSourceTypeEntries = true; IClasspathEntry[] entries = this.fProjectWrapper.getResolvedClasspath(true); for (int i = 0; i < entries.length; i++) { if (entries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) { hasNoSourceTypeEntries = false; final IPath path = entries[i].getPath(); if (path.segmentCount() > 1) { final IFileStore fileStore = EFS.getLocalFileSystem() .getStore(URIUtils.getExpectedURI(root.getFile(path).getLocationURI())); if (!fileStore.fetchInfo().exists()) { // --- Non existent source entry CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.AXB_NonExistentSRCFolder, path.lastSegment()), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); } if (fileStore.childNames(EFS.NONE, null).length == 0) { // --- Empty source directory CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.AXB_EmptySRCFolder, path.lastSegment()), IMarker.SEVERITY_WARNING, IMarker.PRIORITY_HIGH); } } } } if (hasNoSourceTypeEntries) { // --- Project has no source entry CoreResourceUtils.addBuildMarkerTo(getProject(), NLS.bind(Messages.AXB_NoSRCFolder, getProject().getName()), IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH); } } catch (JavaModelException e) { LaunchCore.log(IStatus.ERROR, Messages.AXB_BuilderProblem, e); } } private void analyze(final Collection<Job> jobs) { computeDependencies(jobs); collectBookmarks(jobs); } private void collectBookmarks(final Collection<Job> jobs) { for (final Job job : jobs) { final CollectBookmarks cb = new CollectBookmarks(job, this); cb.perform(); } } private void computeDependencies(final Collection<Job> jobs) { for (final Job job : jobs) { final ComputeDependenciesVisitor visitor = new ComputeDependenciesVisitor(this.fProjectWrapper, job, job.extensionInfo().typeSystem(), this.fDependencyInfo); if (job.ast() != null) { job.ast().visit(visitor.begin()); } } } private Collection<IFile> getChangeDependents(final IResource srcFile) { final Collection<IFile> result = new ArrayList<IFile>(); final Set<String> fileDependents = this.fDependencyInfo.getDependentsOf(srcFile.getFullPath().toOSString()); final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); if (fileDependents != null) { for (final String dependent : fileDependents) { result.add(wsRoot.getFile(new Path(dependent))); } } return result; } private void updateGeneratedFiles(Map<String, Collection<String>> generatedFiles, Collection<IFile> sourceFiles) { for (IFile srcFile : sourceFiles) { try { String name = BuildPathUtils.getBareName(srcFile, fProjectWrapper); if (generatedFiles.containsKey(name)) { fGeneratedFiles.put(name, generatedFiles.get(name)); } else { fGeneratedFiles.remove(name); } } catch (JavaModelException e) { LaunchCore.log(IStatus.ERROR, Messages.AXB_BuilderProblem, e); } } } private boolean isX10File(final IFile file) { return Constants.X10_EXT.equals('.' + file.getFileExtension()); } private boolean isClassFile(final IFile file) { if (file.getFileExtension() != null) { return file.getFileExtension().equals("class"); } return false; } private boolean isClassPathFile(final IFile file) { return file.getName().equals(".classpath"); } private String getOptions(Options options) { String result = ""; if (options.classpath != null && !options.classpath.equals("")) { result += "-classpath \""; for (String token : options.classpath.split(File.pathSeparator)) { result += X10BuilderUtils.getTargetSystemPath(token); result += File.pathSeparator; } result += "\""; } if (options.output_directory != null) { result += " -d \"" + X10BuilderUtils.getTargetSystemPath(options.output_directory.getAbsolutePath()); result += "\""; } if (options.assertions) { result += " -assert"; } if (options.source_path != null && !options.source_path.isEmpty()) { result += " -sourcepath \""; for (int i = 0; i < options.source_path.size(); i++) { result += ((i > 0) ? ":" : "") + X10BuilderUtils.getTargetSystemPath(options.source_path.get(i).getAbsolutePath()); } result += "\""; } if (options.bootclasspath != null && !options.bootclasspath.equals("")) { result += " -bootclasspath " + options.bootclasspath; } if (options.compile_command_line_only) { result += " -commandlineonly"; } if (options.fully_qualified_names) { result += " -fqcn"; } if (options.source_ext != null) { for (int i = 0; i < options.source_ext.length; i++) { result += " -sx " + options.source_ext[i]; } } if (options.output_ext != null && !options.output_ext.equals("")) { result += " -ox " + options.output_ext; } result += " -errors " + options.error_count; result += " -w " + options.output_width; for (String s : options.dump_ast) { result += " -dump " + s; } for (String s : options.print_ast) { result += " -print " + s; } for (String s : options.disable_passes) { result += " -disable " + s; } if (!options.serialize_type_info) { result += " -noserial"; } if (!options.keep_output_files) { result += " -nooutput"; } if (options.post_compiler != null && !options.post_compiler.equals("")) { result += " -post " + options.post_compiler; } if (options.precise_compiler_generated_positions) { result += " -debugpositions"; } if (options.use_simple_code_writer) { result += " -simpleoutput"; } return result; } public static Collection<IPath> getProjectDependencies(IJavaProject project) throws JavaModelException { Collection<IPath> ret = new ArrayList<IPath>(); if (project == null) return ret; for (final IClasspathEntry cpEntry : project.getRawClasspath()) { if (cpEntry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); IJavaProject javaProject = JavaCore.create(wsRoot.getProject(cpEntry.getPath().toOSString())); ret.add(wsRoot.getLocation().append(javaProject.getOutputLocation())); for (final IClasspathEntry pEntry : javaProject.getRawClasspath()) { if (pEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (pEntry.getOutputLocation() != null) { ret.add(wsRoot.getLocation().append(pEntry.getOutputLocation())); } } } } } return ret; } public static Collection<String> getProjectDependenciesNames(IJavaProject project) throws JavaModelException { Collection<String> ret = new ArrayList<String>(); for (final IClasspathEntry cpEntry : project.getRawClasspath()) { if (cpEntry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { final IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); ret.add(wsRoot.getProject(cpEntry.getPath().toOSString()).getName()); } } return ret; } // --- Fields private PolyglotDependencyInfo fDependencyInfo; protected IJavaProject fProjectWrapper; protected Map<String, Collection<String>> fGeneratedFiles = new HashMap<String, Collection<String>>(); protected Map<String, Collection<String>> fBlockingPostCompilation = new HashMap<String, Collection<String>>(); // --- X10 sources. }