| /******************************************************************************* |
| * Copyright (c) 2008, 2012 Obeo. |
| * 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 |
| * |
| * Contributors: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.acceleo.internal.ide.ui.builders; |
| |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Sets; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.acceleo.common.IAcceleoConstants; |
| import org.eclipse.acceleo.common.internal.utils.AcceleoDynamicMetamodelResourceSetImpl; |
| import org.eclipse.acceleo.common.internal.utils.AcceleoPackageRegistry; |
| import org.eclipse.acceleo.common.internal.utils.workspace.AcceleoModelManager; |
| import org.eclipse.acceleo.common.internal.utils.workspace.AcceleoProjectState; |
| import org.eclipse.acceleo.ide.ui.AcceleoUIActivator; |
| import org.eclipse.acceleo.ide.ui.resources.AcceleoProject; |
| import org.eclipse.acceleo.internal.ide.ui.AcceleoUIMessages; |
| import org.eclipse.acceleo.internal.ide.ui.acceleowizardmodel.AcceleowizardmodelFactory; |
| import org.eclipse.acceleo.internal.ide.ui.builders.runner.CreateRunnableAcceleoOperation; |
| import org.eclipse.acceleo.internal.ide.ui.editors.template.utils.JavaServicesUtils; |
| import org.eclipse.acceleo.internal.ide.ui.generators.AcceleoUIGenerator; |
| import org.eclipse.acceleo.internal.parser.compiler.AcceleoProjectClasspathEntry; |
| import org.eclipse.acceleo.internal.parser.cst.utils.FileContent; |
| import org.eclipse.acceleo.internal.parser.cst.utils.Sequence; |
| import org.eclipse.acceleo.parser.AcceleoParserInfo; |
| import org.eclipse.acceleo.parser.AcceleoParserProblem; |
| import org.eclipse.acceleo.parser.AcceleoParserWarning; |
| import org.eclipse.core.resources.IContainer; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceDelta; |
| 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.NullProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.util.BasicMonitor; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| |
| /** |
| * The builder compiles the Acceleo templates in a background task. Compilation errors are put in the problems |
| * view when it is necessary. |
| * |
| * @author <a href="mailto:jonathan.musset@obeo.fr">Jonathan Musset</a> |
| */ |
| public class AcceleoBuilder extends IncrementalProjectBuilder { |
| |
| /** |
| * The builder ID. |
| */ |
| public static final String BUILDER_ID = "org.eclipse.acceleo.ide.ui.acceleoBuilder"; //$NON-NLS-1$ |
| |
| /** |
| * The output folders to ignore. |
| */ |
| private Set<File> outputFolders = new LinkedHashSet<File>(); |
| |
| /** |
| * The projects mapped by the builder. |
| */ |
| private Map<IJavaProject, org.eclipse.acceleo.internal.parser.compiler.AcceleoProject> mappedProjects = new HashMap<IJavaProject, org.eclipse.acceleo.internal.parser.compiler.AcceleoProject>(); |
| |
| /** |
| * The state of the current Acceleo project. |
| */ |
| private AcceleoProjectState lastState; |
| |
| /** |
| * Constructor. |
| */ |
| public AcceleoBuilder() { |
| super(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.core.resources.IncrementalProjectBuilder#build(int, java.util.Map, |
| * org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| @Override |
| @SuppressWarnings("rawtypes") |
| protected IProject[] build(int kind, Map arguments, IProgressMonitor monitor) throws CoreException { |
| IProject project = getProject(); |
| if (project == null || !project.isAccessible()) { |
| return new IProject[] {}; |
| } |
| this.mappedProjects.clear(); |
| |
| monitor.subTask(AcceleoUIMessages.getString( |
| "AcceleoBuilder.StartingBuild", project.getName(), Integer.valueOf(0))); //$NON-NLS-1$ |
| long currentTimeMillis = System.currentTimeMillis(); |
| |
| // Generate all Acceleo Java Services modules |
| List<IFile> javaFiles = this.members(getProject(), "java"); //$NON-NLS-1$ |
| for (IFile iFile : javaFiles) { |
| IJavaElement iJavaElement = JavaCore.create(iFile); |
| if (iJavaElement instanceof ICompilationUnit) { |
| ICompilationUnit iCompilationUnit = (ICompilationUnit)iJavaElement; |
| if (JavaServicesUtils.isAcceleoJavaServicesClass(iCompilationUnit)) { |
| JavaServicesUtils.generateAcceleoServicesModule(iCompilationUnit, monitor); |
| } |
| } |
| } |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.ComputeAccessibleEcores", Long //$NON-NLS-1$ |
| .valueOf(System.currentTimeMillis() - currentTimeMillis))); |
| IJavaProject javaProject = JavaCore.create(project); |
| Set<AcceleoProjectClasspathEntry> entries = this.computeProjectClassPath(javaProject); |
| |
| File projectRoot = project.getLocation().toFile(); |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject acceleoProject = new org.eclipse.acceleo.internal.parser.compiler.AcceleoProject( |
| projectRoot, entries); |
| |
| acceleoProject = this.computeProjectDependencies(acceleoProject, javaProject); |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.LoadAccessibleEcores", Long //$NON-NLS-1$ |
| .valueOf(System.currentTimeMillis() - currentTimeMillis))); |
| // Check that all ".ecore" models in accessible projects have been loaded. |
| AcceleoProject aProject = new AcceleoProject(project); |
| List<IProject> accessibleProjects = new ArrayList<IProject>(); |
| accessibleProjects = aProject.getRecursivelyAccessibleProjects(); |
| for (IProject iProject : Lists.reverse(accessibleProjects)) { |
| List<IFile> members = this.members(iProject, IAcceleoConstants.ECORE_FILE_EXTENSION); |
| for (IFile iFile : members) { |
| URI uri = URI.createPlatformResourceURI(iFile.getFullPath().toString(), true); |
| AcceleoPackageRegistry.INSTANCE.registerEcorePackages(uri.toString(), |
| AcceleoDynamicMetamodelResourceSetImpl.DYNAMIC_METAMODEL_RESOURCE_SET); |
| } |
| } |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.ComputeAccessibleAcceleoModules", Long //$NON-NLS-1$ |
| .valueOf(System.currentTimeMillis() - currentTimeMillis))); |
| List<URI> accessibleOutputFiles = AcceleoProject.computeAcceleoModuleInRequiredPlugins(project); |
| acceleoProject.addDependencies(Sets.newHashSet(accessibleOutputFiles)); |
| AcceleoBuilderSettings settings = new AcceleoBuilderSettings(project); |
| String resourceKind = settings.getResourceKind(); |
| boolean useBinaryResources = !AcceleoBuilderSettings.BUILD_XMI_RESOURCE.equals(resourceKind); |
| boolean usePlatformResourcePath = AcceleoBuilderSettings.COMPILATION_PLATFORM_RESOURCE |
| .equals(settings.getCompilationKind()); |
| |
| Set<File> mainFiles = new LinkedHashSet<File>(); |
| |
| this.lastState = this.getLastState(this.getProject()); |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.CompilationStart", Long.valueOf(System //$NON-NLS-1$ |
| .currentTimeMillis() - currentTimeMillis))); |
| |
| if (kind == IncrementalProjectBuilder.FULL_BUILD) { |
| // Full build -> build all |
| mainFiles.addAll(buildAll(acceleoProject, project, useBinaryResources, usePlatformResourcePath, |
| monitor)); |
| } else { |
| if (this.lastState == null) { |
| // No state -> build all |
| mainFiles.addAll(buildAll(acceleoProject, project, useBinaryResources, |
| usePlatformResourcePath, monitor)); |
| } else if (kind == IncrementalProjectBuilder.INCREMENTAL_BUILD |
| || kind == IncrementalProjectBuilder.AUTO_BUILD) { |
| mainFiles.addAll(this.incrementalBuild(acceleoProject, project, useBinaryResources, |
| usePlatformResourcePath, monitor)); |
| } else if (kind == IncrementalProjectBuilder.CLEAN_BUILD) { |
| acceleoProject.clean(); |
| this.cleanAcceleoMarkers(project); |
| } |
| } |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.BuildFileNotCompiled", Long //$NON-NLS-1$ |
| .valueOf(System.currentTimeMillis() - currentTimeMillis))); |
| // Ensure that we didn't forget to build a file out of the dependency graph of the file(s) |
| // currently |
| // built, this can occur if two files are not related at all and we force the build of only one of |
| // those files. |
| Set<File> fileNotCompiled = acceleoProject.getFileNotCompiled(); |
| for (File fileToBuild : fileNotCompiled) { |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoParser acceleoParser = new org.eclipse.acceleo.internal.parser.compiler.AcceleoParser( |
| acceleoProject, useBinaryResources, usePlatformResourcePath); |
| Set<File> builtFiles = acceleoParser.buildFile(fileToBuild, BasicMonitor.toMonitor(monitor)); |
| this.addAcceleoMarkers(builtFiles, acceleoParser); |
| mainFiles.addAll(acceleoParser.getMainFiles()); |
| } |
| |
| // Launch the build of the MANIFEST.MF, Java launcher, build.acceleo etc. |
| List<IFile> filesWithMainTag = new ArrayList<IFile>(); |
| for (File mainFile : mainFiles) { |
| IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( |
| new Path(mainFile.getAbsolutePath())); |
| filesWithMainTag.add(workspaceFile); |
| } |
| if (filesWithMainTag.size() > 0) { |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.GeneratingAcceleoFiles", Long //$NON-NLS-1$ |
| .valueOf(System.currentTimeMillis() - currentTimeMillis))); |
| CreateRunnableAcceleoOperation createRunnableAcceleoOperation = new CreateRunnableAcceleoOperation( |
| new AcceleoProject(project), filesWithMainTag); |
| createRunnableAcceleoOperation.run(monitor); |
| } |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.RefreshingProjects", Long.valueOf(System //$NON-NLS-1$ |
| .currentTimeMillis() - currentTimeMillis))); |
| // Refresh all the projects potentially containing files. |
| Set<org.eclipse.acceleo.internal.parser.compiler.AcceleoProject> projectsToRefresh = Sets |
| .newHashSet(acceleoProject); |
| projectsToRefresh.addAll(acceleoProject.getProjectDependencies()); |
| projectsToRefresh.addAll(acceleoProject.getDependentProjects()); |
| for (org.eclipse.acceleo.internal.parser.compiler.AcceleoProject projectToRefresh : projectsToRefresh) { |
| IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); |
| for (IProject iProject : projects) { |
| if (iProject.isAccessible() |
| && projectToRefresh.getProjectRoot().equals(iProject.getLocation().toFile())) { |
| iProject.refreshLocal(IResource.DEPTH_INFINITE, monitor); |
| } |
| } |
| } |
| |
| monitor.subTask(AcceleoUIMessages.getString("AcceleoBuilder.GenerateBuildFiles", Long.valueOf(System //$NON-NLS-1$ |
| .currentTimeMillis() - currentTimeMillis))); |
| generateAcceleoBuildFile(monitor); |
| monitor.done(); |
| |
| return accessibleProjects.toArray(new IProject[accessibleProjects.size()]); |
| } |
| |
| /** |
| * Build all the files in the project. |
| * |
| * @param acceleoProject |
| * The Acceleo project |
| * @param project |
| * The Eclipse IProject |
| * @param useBinaryResources |
| * Indicates if we should use the binary resources serialization |
| * @param usePlatformResourcePath |
| * Indicates if we should use platform:/resource paths |
| * @param monitor |
| * The progress monitor |
| * @return The files built |
| */ |
| private Set<File> buildAll(org.eclipse.acceleo.internal.parser.compiler.AcceleoProject acceleoProject, |
| IProject project, boolean useBinaryResources, boolean usePlatformResourcePath, |
| IProgressMonitor monitor) { |
| Set<File> filesBuilt = new LinkedHashSet<File>(); |
| |
| this.clearLastState(); |
| |
| // acceleoProject.clean(); |
| this.cleanAcceleoMarkers(project); |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoParser acceleoParser = new org.eclipse.acceleo.internal.parser.compiler.AcceleoParser( |
| acceleoProject, useBinaryResources, usePlatformResourcePath); |
| Set<File> builtFiles = acceleoParser.buildAll(BasicMonitor.toMonitor(monitor)); |
| for (File builtFile : builtFiles) { |
| IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( |
| new Path(builtFile.getAbsolutePath())); |
| this.cleanAcceleoMarkers(workspaceFile); |
| } |
| this.addAcceleoMarkers(builtFiles, acceleoParser); |
| filesBuilt.addAll(acceleoParser.getMainFiles()); |
| |
| AcceleoProjectState state = new AcceleoProjectState(); |
| state.setProjectName(this.getProject().getName()); |
| state.setLastStructuralBuildTime(System.currentTimeMillis()); |
| this.recordNewState(state); |
| |
| return filesBuilt; |
| } |
| |
| /** |
| * Launches an incremental build of the given project. |
| * |
| * @param acceleoProject |
| * The Acceleo project |
| * @param project |
| * The Eclipse IProject |
| * @param useBinaryResources |
| * Indicates if we should use binary resources serialization |
| * @param usePlatformResourcePath |
| * Indicates if we should use platform:/resources paths |
| * @param monitor |
| * The progress monitor |
| * @return The list of the files built |
| * @throws CoreException |
| * In case of problems during the serialization |
| */ |
| private Set<File> incrementalBuild( |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject acceleoProject, IProject project, |
| boolean useBinaryResources, boolean usePlatformResourcePath, IProgressMonitor monitor) |
| throws CoreException { |
| Set<File> filesBuilt = new LinkedHashSet<File>(); |
| |
| this.clearLastState(); |
| |
| List<IFile> deltaMembers = this.deltaMembers(getDelta(project), monitor); |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoParser acceleoParser = new org.eclipse.acceleo.internal.parser.compiler.AcceleoParser( |
| acceleoProject, useBinaryResources, usePlatformResourcePath); |
| Iterator<IFile> it = deltaMembers.iterator(); |
| while (it.hasNext() && !monitor.isCanceled()) { |
| File fileToBuild = it.next().getLocation().toFile(); |
| Set<File> builtFiles = acceleoParser.buildFile(fileToBuild, BasicMonitor.toMonitor(monitor)); |
| for (File builtFile : builtFiles) { |
| IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( |
| new Path(builtFile.getAbsolutePath())); |
| this.cleanAcceleoMarkers(workspaceFile); |
| } |
| this.addAcceleoMarkers(builtFiles, acceleoParser); |
| filesBuilt.addAll(acceleoParser.getMainFiles()); |
| } |
| |
| AcceleoProjectState state = new AcceleoProjectState(); |
| state.setProjectName(this.getProject().getName()); |
| state.setLastStructuralBuildTime(System.currentTimeMillis()); |
| this.recordNewState(state); |
| |
| return filesBuilt; |
| } |
| |
| /** |
| * Adds the necessary markers on the given built files. |
| * |
| * @param builtFiles |
| * The files built by the parser. |
| * @param parser |
| * The parser. |
| */ |
| private void addAcceleoMarkers(Set<File> builtFiles, |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoParser parser) { |
| for (File builtFile : builtFiles) { |
| try { |
| IFile workspaceFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( |
| new Path(builtFile.getAbsolutePath())); |
| Collection<AcceleoParserInfo> infos = parser.getInfos(builtFile); |
| for (AcceleoParserInfo info : infos) { |
| AcceleoMarkerUtils.createMarkerOnFile(AcceleoMarkerUtils.INFO_MARKER_ID, workspaceFile, |
| info.getLine(), info.getPosBegin(), info.getPosEnd(), info.getMessage()); |
| } |
| Collection<AcceleoParserWarning> warnings = parser.getWarnings(builtFile); |
| for (AcceleoParserWarning warning : warnings) { |
| AcceleoMarkerUtils.createMarkerOnFile(AcceleoMarkerUtils.WARNING_MARKER_ID, |
| workspaceFile, warning.getLine(), warning.getPosBegin(), warning.getPosEnd(), |
| warning.getMessage()); |
| } |
| Collection<AcceleoParserProblem> problems = parser.getProblems(builtFile); |
| for (AcceleoParserProblem problem : problems) { |
| AcceleoMarkerUtils.createMarkerOnFile(AcceleoMarkerUtils.PROBLEM_MARKER_ID, |
| workspaceFile, problem.getLine(), problem.getPosBegin(), problem.getPosEnd(), |
| problem.getMessage()); |
| } |
| } catch (CoreException e) { |
| AcceleoUIActivator.log(e, true); |
| } |
| |
| } |
| } |
| |
| /** |
| * Cleans the Acceleo marker from the given resource. |
| * |
| * @param resource |
| * The resource. |
| */ |
| private void cleanAcceleoMarkers(IResource resource) { |
| try { |
| if (resource.exists() && resource.isAccessible()) { |
| resource.deleteMarkers(AcceleoMarkerUtils.PROBLEM_MARKER_ID, true, IResource.DEPTH_INFINITE); |
| resource.deleteMarkers(AcceleoMarkerUtils.WARNING_MARKER_ID, true, IResource.DEPTH_INFINITE); |
| resource.deleteMarkers(AcceleoMarkerUtils.INFO_MARKER_ID, true, IResource.DEPTH_INFINITE); |
| resource.deleteMarkers(AcceleoMarkerUtils.OVERRIDE_MARKER_ID, true, IResource.DEPTH_INFINITE); |
| resource.deleteMarkers(AcceleoMarkerUtils.TASK_MARKER_ID, true, IResource.DEPTH_INFINITE); |
| } |
| } catch (CoreException e) { |
| AcceleoUIActivator.log(e, true); |
| } |
| |
| } |
| |
| /** |
| * Computes the project dependencies of the given Acceleo project matching the given Java project. |
| * |
| * @param acceleoProject |
| * The Acceleo project. |
| * @param javaProject |
| * The Java project. |
| * @return The Acceleo project with its dependencies resolved. |
| */ |
| private org.eclipse.acceleo.internal.parser.compiler.AcceleoProject computeProjectDependencies( |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject acceleoProject, |
| IJavaProject javaProject) { |
| this.mappedProjects.put(javaProject, acceleoProject); |
| try { |
| // Required projects |
| String[] requiredProjectNames = javaProject.getRequiredProjectNames(); |
| for (String requiredProjectName : requiredProjectNames) { |
| IProject requiredProject = ResourcesPlugin.getWorkspace().getRoot().getProject( |
| requiredProjectName); |
| try { |
| if (requiredProject.isAccessible() && requiredProject.hasNature(JavaCore.NATURE_ID) |
| && requiredProject.hasNature(IAcceleoConstants.ACCELEO_NATURE_ID)) { |
| IJavaProject requiredJavaProject = JavaCore.create(requiredProject); |
| File projectRoot = requiredProject.getLocation().toFile(); |
| |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject mappedProject = this.mappedProjects |
| .get(requiredJavaProject); |
| if (mappedProject != null) { |
| acceleoProject.addProjectDependencies(Sets.newHashSet(mappedProject)); |
| } else { |
| Set<AcceleoProjectClasspathEntry> entries = this |
| .computeProjectClassPath(requiredJavaProject); |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject requiredAcceleoProject = new org.eclipse.acceleo.internal.parser.compiler.AcceleoProject( |
| projectRoot, entries); |
| if (!acceleoProject.getProjectDependencies().contains(requiredAcceleoProject)) { |
| acceleoProject |
| .addProjectDependencies(Sets.newHashSet(requiredAcceleoProject)); |
| requiredAcceleoProject = this.computeProjectDependencies( |
| requiredAcceleoProject, requiredJavaProject); |
| } |
| } |
| |
| } |
| } catch (CoreException e) { |
| AcceleoUIActivator.log(e, true); |
| } |
| } |
| |
| // Requiring projects |
| IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); |
| for (IProject iProject : projects) { |
| try { |
| if (iProject.isAccessible() && iProject.hasNature(JavaCore.NATURE_ID) |
| && iProject.hasNature(IAcceleoConstants.ACCELEO_NATURE_ID)) { |
| IJavaProject iJavaProject = JavaCore.create(iProject); |
| boolean requiring = false; |
| |
| String[] projectNames = iJavaProject.getRequiredProjectNames(); |
| for (String projectName : projectNames) { |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject( |
| projectName); |
| if (acceleoProject.getProjectRoot().equals(project.getLocation().toFile())) { |
| requiring = true; |
| } |
| } |
| |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject mappedProject = this.mappedProjects |
| .get(iJavaProject); |
| if (requiring && mappedProject != null) { |
| acceleoProject.addDependentProjects(Sets.newHashSet(mappedProject)); |
| } else if (requiring && mappedProject == null) { |
| Set<AcceleoProjectClasspathEntry> entries = this |
| .computeProjectClassPath(iJavaProject); |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject requiringAcceleoProject = new org.eclipse.acceleo.internal.parser.compiler.AcceleoProject( |
| iProject.getLocation().toFile(), entries); |
| if (!acceleoProject.getDependentProjects().contains(requiringAcceleoProject)) { |
| acceleoProject.addDependentProjects(Sets.newHashSet(requiringAcceleoProject)); |
| requiringAcceleoProject = this.computeProjectDependencies( |
| requiringAcceleoProject, iJavaProject); |
| } |
| } |
| |
| } |
| } catch (CoreException e) { |
| AcceleoUIActivator.log(e, true); |
| } |
| } |
| } catch (JavaModelException e) { |
| AcceleoUIActivator.log(e, true); |
| } |
| return acceleoProject; |
| } |
| |
| /** |
| * Computes the classpath for the given java project. |
| * |
| * @param javaProject |
| * The Java project |
| * @return The classpath entries |
| */ |
| private Set<AcceleoProjectClasspathEntry> computeProjectClassPath(IJavaProject javaProject) { |
| Set<AcceleoProjectClasspathEntry> classpathEntries = new LinkedHashSet<AcceleoProjectClasspathEntry>(); |
| |
| // Compute the classpath of the acceleo project |
| IClasspathEntry[] rawClasspath; |
| try { |
| rawClasspath = javaProject.getRawClasspath(); |
| for (IClasspathEntry iClasspathEntry : rawClasspath) { |
| int entryKind = iClasspathEntry.getEntryKind(); |
| if (IClasspathEntry.CPE_SOURCE == entryKind) { |
| // We have the source folders of the project. |
| IPath inputFolderPath = iClasspathEntry.getPath(); |
| IPath outputFolderPath = iClasspathEntry.getOutputLocation(); |
| |
| if (outputFolderPath == null) { |
| outputFolderPath = javaProject.getOutputLocation(); |
| } |
| |
| IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject( |
| inputFolderPath.lastSegment()); |
| if (!(project != null && project.exists() && project.equals(javaProject.getProject()))) { |
| IContainer inputContainer = ResourcesPlugin.getWorkspace().getRoot().getFolder( |
| inputFolderPath); |
| IContainer outputContainer = ResourcesPlugin.getWorkspace().getRoot().getFolder( |
| outputFolderPath); |
| |
| if (inputContainer != null && outputContainer != null) { |
| File inputDirectory = inputContainer.getLocation().toFile(); |
| File outputDirectory = outputContainer.getLocation().toFile(); |
| AcceleoProjectClasspathEntry entry = new AcceleoProjectClasspathEntry( |
| inputDirectory, outputDirectory); |
| classpathEntries.add(entry); |
| |
| this.outputFolders.add(outputDirectory); |
| } |
| } |
| } |
| } |
| } catch (JavaModelException e) { |
| AcceleoUIActivator.log(e, true); |
| } |
| return classpathEntries; |
| } |
| |
| /** |
| * It does a full build. |
| * |
| * @param monitor |
| * is the progress monitor |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| protected void fullBuild(IProgressMonitor monitor) throws CoreException { |
| List<IFile> filesOutput = new ArrayList<IFile>(); |
| for (File outputFolder : this.outputFolders) { |
| IPath path = new Path(outputFolder.getAbsolutePath()); |
| AcceleoBuilderUtils |
| .members(filesOutput, getProject(), IAcceleoConstants.MTL_FILE_EXTENSION, path); |
| if (filesOutput.size() > 0) { |
| Collections.sort(filesOutput, new Comparator<IFile>() { |
| public int compare(IFile arg0, IFile arg1) { |
| long m0 = arg0.getLocation().toFile().lastModified(); |
| long m1 = arg1.getLocation().toFile().lastModified(); |
| if (m0 < m1) { |
| return 1; |
| } |
| return -1; |
| } |
| }); |
| registerAccessibleEcoreFiles(); |
| IFile[] files = filesOutput.toArray(new IFile[filesOutput.size()]); |
| AcceleoCompileOperation compileOperation = new AcceleoCompileOperation(getProject(), files, |
| false); |
| compileOperation.run(monitor); |
| generateAcceleoBuildFile(monitor); |
| } |
| } |
| } |
| |
| /** |
| * Register the accessible workspace ecore files. |
| * |
| * @throws CoreException |
| * when an issue occurs |
| */ |
| private void registerAccessibleEcoreFiles() throws CoreException { |
| List<IFile> ecoreFiles = new ArrayList<IFile>(); |
| AcceleoProject acceleoProject = new AcceleoProject(getProject()); |
| for (IProject project : acceleoProject.getRecursivelyAccessibleProjects()) { |
| if (project.isAccessible()) { |
| for (File outputFolder : this.outputFolders) { |
| IPath path = new Path(outputFolder.getAbsolutePath()); |
| AcceleoBuilderUtils.members(ecoreFiles, project, "ecore", path); //$NON-NLS-1$ |
| } |
| } |
| } |
| for (IFile ecoreFile : Lists.reverse(ecoreFiles)) { |
| URI uri = URI.createPlatformResourceURI(ecoreFile.getFullPath().toString(), true); |
| AcceleoPackageRegistry.INSTANCE.registerEcorePackages(uri.toString(), |
| AcceleoDynamicMetamodelResourceSetImpl.DYNAMIC_METAMODEL_RESOURCE_SET); |
| } |
| } |
| |
| /** |
| * It checks the build configuration of the Acceleo module. It creates the build.acceleo file, the |
| * build.xml file and the pom.xm file if they don't exist. |
| * |
| * @param monitor |
| * is the monitor |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| private void generateAcceleoBuildFile(IProgressMonitor monitor) throws CoreException { |
| IFile buildProperties = getProject().getFile("build.properties"); //$NON-NLS-1$ |
| for (File outputFolder : this.outputFolders) { |
| IPath path = new Path(outputFolder.getAbsolutePath()); |
| if (path.segmentCount() >= 1) { |
| IFile buildAcceleo = getProject().getFile("build.acceleo"); //$NON-NLS-1$ |
| AcceleoProject project = new AcceleoProject(getProject()); |
| List<IProject> dependencies = project.getRecursivelyAccessibleProjects(); |
| dependencies.remove(getProject()); |
| org.eclipse.acceleo.internal.ide.ui.acceleowizardmodel.AcceleoProject acceleoProject = AcceleowizardmodelFactory.eINSTANCE |
| .createAcceleoProject(); |
| List<String> pluginDependencies = acceleoProject.getPluginDependencies(); |
| for (IProject iProject : dependencies) { |
| pluginDependencies.add(iProject.getName()); |
| } |
| |
| AcceleoUIGenerator.getDefault() |
| .generateBuildAcceleo(acceleoProject, buildAcceleo.getParent()); |
| |
| if (buildProperties.exists() |
| && FileContent.getFileContent(buildProperties.getLocation().toFile()).indexOf( |
| buildAcceleo.getName()) == -1) { |
| AcceleoUIActivator.getDefault().getLog().log( |
| new Status(IStatus.ERROR, AcceleoUIActivator.PLUGIN_ID, AcceleoUIMessages |
| .getString("AcceleoBuilder.AcceleoBuildFileIssue", //$NON-NLS-1$ |
| new Object[] {getProject().getName(), }))); |
| } |
| } |
| } |
| } |
| |
| /** |
| * It does an incremental build. |
| * |
| * @param delta |
| * is the resource delta |
| * @param monitor |
| * is the progress monitor |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { |
| List<IFile> deltaFilesOutput = deltaMembers(delta, monitor); |
| if (deltaFilesOutput.size() > 0) { |
| boolean containsManifest = false; |
| for (int i = 0; !containsManifest && i < deltaFilesOutput.size(); i++) { |
| containsManifest = "MANIFEST.MF".equals(deltaFilesOutput.get(i).getName()); //$NON-NLS-1$ |
| } |
| if (containsManifest) { |
| deltaFilesOutput.clear(); |
| for (File outputFolder : this.outputFolders) { |
| IPath path = new Path(outputFolder.getAbsolutePath()); |
| AcceleoBuilderUtils.members(deltaFilesOutput, getProject(), |
| IAcceleoConstants.MTL_FILE_EXTENSION, path); |
| } |
| } else { |
| computeOtherFilesToBuild(deltaFilesOutput); |
| } |
| } |
| if (deltaFilesOutput.size() > 0) { |
| Collections.sort(deltaFilesOutput, new Comparator<IFile>() { |
| public int compare(IFile arg0, IFile arg1) { |
| long m0 = arg0.getLocation().toFile().lastModified(); |
| long m1 = arg1.getLocation().toFile().lastModified(); |
| if (m0 < m1) { |
| return 1; |
| } |
| return -1; |
| } |
| }); |
| registerAccessibleEcoreFiles(); |
| IFile[] files = deltaFilesOutput.toArray(new IFile[deltaFilesOutput.size()]); |
| AcceleoCompileOperation compileOperation = new AcceleoCompileOperation(getProject(), files, false); |
| compileOperation.run(monitor); |
| generateAcceleoBuildFile(monitor); |
| } else { |
| List<IFile> deltaRemovedFilesOutput = new ArrayList<IFile>(); |
| deltaRemovedMembers(deltaRemovedFilesOutput, delta, monitor); |
| if (deltaRemovedFilesOutput.size() > 0) { |
| for (IFile removedFile : deltaRemovedFilesOutput) { |
| if ("java".equals(removedFile.getFileExtension())) { //$NON-NLS-1$ |
| this.fullBuild(monitor); |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Gets also the files that depend of the templates to build. |
| * |
| * @param deltaFiles |
| * is an output parameter to get all the templates to build |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| private void computeOtherFilesToBuild(List<IFile> deltaFiles) throws CoreException { |
| AcceleoProject acceleoProject = new AcceleoProject(getProject()); |
| List<IFile> otherTemplates = new ArrayList<IFile>(); |
| for (File outputFolder : this.outputFolders) { |
| IPath path = new Path(outputFolder.getAbsolutePath()); |
| AcceleoBuilderUtils.members(otherTemplates, getProject(), IAcceleoConstants.MTL_FILE_EXTENSION, |
| path); |
| } |
| List<Sequence> importSequencesToSearch = new ArrayList<Sequence>(); |
| for (int i = 0; i < deltaFiles.size(); i++) { |
| IFile deltaFile = deltaFiles.get(i); |
| if (IAcceleoConstants.MTL_FILE_EXTENSION.equals(deltaFile.getFileExtension())) { |
| importSequencesToSearch.addAll(AcceleoBuilderUtils.getImportSequencesToSearch(acceleoProject, |
| deltaFile)); |
| otherTemplates.remove(deltaFile); |
| } |
| } |
| List<IFile> otherTemplatesToBuild = getOtherTemplatesToBuild(acceleoProject, otherTemplates, |
| importSequencesToSearch); |
| while (otherTemplatesToBuild.size() > 0) { |
| for (int i = 0; i < otherTemplatesToBuild.size(); i++) { |
| IFile otherTemplateToBuild = otherTemplatesToBuild.get(i); |
| otherTemplates.remove(otherTemplateToBuild); |
| if (!deltaFiles.contains(otherTemplateToBuild)) { |
| deltaFiles.add(otherTemplateToBuild); |
| importSequencesToSearch.addAll(AcceleoBuilderUtils.getImportSequencesToSearch( |
| acceleoProject, otherTemplateToBuild)); |
| } |
| } |
| otherTemplatesToBuild = getOtherTemplatesToBuild(acceleoProject, otherTemplates, |
| importSequencesToSearch); |
| } |
| } |
| |
| /** |
| * Gets the files that import the given dependencies. |
| * |
| * @param acceleoProject |
| * is the project |
| * @param otherTemplates |
| * are the other templates that we can decide to build |
| * @param importSequencesToSearch |
| * are the dependencies to detect in the "import" section of the other templates |
| * @return the other templates to build |
| */ |
| private List<IFile> getOtherTemplatesToBuild(AcceleoProject acceleoProject, List<IFile> otherTemplates, |
| List<Sequence> importSequencesToSearch) { |
| List<IFile> result = new ArrayList<IFile>(); |
| for (int i = 0; i < otherTemplates.size(); i++) { |
| IFile otherTemplate = otherTemplates.get(i); |
| IPath outputPath = acceleoProject.getOutputFilePath(otherTemplate); |
| if (outputPath != null && !getProject().getFile(outputPath.removeFirstSegments(1)).exists()) { |
| result.add(otherTemplate); |
| } else { |
| StringBuffer otherTemplateContent = FileContent.getFileContent(otherTemplate.getLocation() |
| .toFile()); |
| for (int j = 0; j < importSequencesToSearch.size(); j++) { |
| Sequence importSequence = importSequencesToSearch.get(j); |
| if (importSequence.search(otherTemplateContent).b() > -1) { |
| result.add(otherTemplate); |
| } |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * @see org.eclipse.core.resources.IncrementalProjectBuilder#clean(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| @Override |
| protected void clean(IProgressMonitor monitor) throws CoreException { |
| super.clean(monitor); |
| IProject project = getProject(); |
| IJavaProject javaProject = JavaCore.create(project); |
| File projectRoot = project.getLocation().toFile(); |
| Set<AcceleoProjectClasspathEntry> entries = this.computeProjectClassPath(javaProject); |
| org.eclipse.acceleo.internal.parser.compiler.AcceleoProject acceleoProject = new org.eclipse.acceleo.internal.parser.compiler.AcceleoProject( |
| projectRoot, entries); |
| |
| acceleoProject = this.computeProjectDependencies(acceleoProject, javaProject); |
| acceleoProject.clean(); |
| this.cleanAcceleoMarkers(project); |
| } |
| |
| /** |
| * Computes a list of all the modified files (Acceleo files only). |
| * |
| * @param delta |
| * the resource delta represents changes in the state of a resource tree |
| * @param monitor |
| * is the monitor |
| * @return The list of files involved in the resource delta. |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| private List<IFile> deltaMembers(IResourceDelta delta, IProgressMonitor monitor) throws CoreException { |
| List<IFile> deltaFilesOutput = new ArrayList<IFile>(); |
| if (delta != null) { |
| IResource resource = delta.getResource(); |
| if (resource instanceof IFile) { |
| if (delta.getKind() == IResourceDelta.REMOVED |
| && IAcceleoConstants.MTL_FILE_EXTENSION.equals(resource.getFileExtension())) { |
| removeOutputFile((IFile)resource, monitor); |
| } |
| if (contentChanged(delta) |
| && (IAcceleoConstants.MTL_FILE_EXTENSION.equals(resource.getFileExtension()) || "MANIFEST.MF" //$NON-NLS-1$ |
| .equals(resource.getName())) || "plugin.xml".equals(resource.getName())) { //$NON-NLS-1$ |
| deltaFilesOutput.add((IFile)resource); |
| } |
| } else { |
| boolean shouldConsider = true; |
| for (File outputFolder : this.outputFolders) { |
| if (outputFolder == null |
| || new Path(outputFolder.getAbsolutePath()).isPrefixOf(resource.getLocation())) { |
| shouldConsider = false; |
| } |
| } |
| if (shouldConsider) { |
| IResourceDelta[] children = delta.getAffectedChildren(); |
| for (int i = 0; i < children.length; i++) { |
| deltaFilesOutput.addAll(deltaMembers(children[i], monitor)); |
| } |
| } |
| } |
| } |
| |
| return deltaFilesOutput; |
| } |
| |
| /** |
| * return true if the delta indicates a change of file content. |
| * |
| * @param delta |
| * a resource delta. |
| * @return true if the delta indicates a change of file content. |
| */ |
| private boolean contentChanged(IResourceDelta delta) { |
| if (delta.getKind() != IResourceDelta.REMOVED) { |
| return (delta.getFlags() & IResourceDelta.CONTENT) != 0 |
| || (delta.getFlags() & IResourceDelta.REPLACED) != 0; |
| } |
| return false; |
| } |
| |
| /** |
| * Computes a list of all the removed files. |
| * |
| * @param deltaFilesOutput |
| * an output parameter to get all the modified files |
| * @param delta |
| * the resource delta represents changes in the state of a resource tree |
| * @param monitor |
| * is the monitor |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| private void deltaRemovedMembers(List<IFile> deltaFilesOutput, IResourceDelta delta, |
| IProgressMonitor monitor) throws CoreException { |
| if (delta != null) { |
| IResource resource = delta.getResource(); |
| if (resource instanceof IFile) { |
| if (delta.getKind() == IResourceDelta.REMOVED) { |
| deltaFilesOutput.add((IFile)resource); |
| } |
| } else { |
| for (File outputFolder : this.outputFolders) { |
| if (outputFolder == null |
| || !new Path(outputFolder.getAbsolutePath()).isPrefixOf(resource.getLocation())) { |
| IResourceDelta[] children = delta.getAffectedChildren(); |
| for (int i = 0; i < children.length; i++) { |
| deltaRemovedMembers(deltaFilesOutput, children[i], monitor); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Removes the output file that corresponding to the input file. |
| * |
| * @param inputFile |
| * is the input file ('.acceleo') |
| * @param monitor |
| * is the monitor |
| * @throws CoreException |
| * contains a status object describing the cause of the exception |
| */ |
| private void removeOutputFile(IFile inputFile, IProgressMonitor monitor) throws CoreException { |
| AcceleoProject acceleoProject = new AcceleoProject(getProject()); |
| IPath outputPath = acceleoProject.getOutputFilePath(inputFile); |
| IResource outputFile = ResourcesPlugin.getWorkspace().getRoot().findMember(outputPath); |
| if (outputFile instanceof IFile && outputFile.isAccessible()) { |
| outputFile.delete(true, monitor); |
| } |
| } |
| |
| /** |
| * Returns a list of existing member files (that validate the file extension) in this resource. |
| * |
| * @param container |
| * The container to browse for files with the given extension. |
| * @param extension |
| * The file extension to browse for. |
| * @return The List of files of the given extension contained by <code>container</code>. |
| * @throws CoreException |
| * Thrown if we couldn't retrieve the children of <code>container</code>. |
| */ |
| private List<IFile> members(IContainer container, String extension) throws CoreException { |
| List<IFile> output = new ArrayList<IFile>(); |
| if (container != null) { |
| IResource[] children = container.members(); |
| if (children != null) { |
| for (int i = 0; i < children.length; ++i) { |
| IResource resource = children[i]; |
| if (resource instanceof IFile && extension.equals(((IFile)resource).getFileExtension())) { |
| output.add((IFile)resource); |
| } else if (resource instanceof IContainer) { |
| output.addAll(members((IContainer)resource, extension)); |
| } |
| } |
| } |
| } |
| return output; |
| } |
| |
| /** |
| * Record a new state for the current project. |
| * |
| * @param state |
| * The state to record |
| */ |
| private void recordNewState(AcceleoProjectState state) { |
| AcceleoModelManager.getManager().setProjectState(this.getProject(), state); |
| } |
| |
| /** |
| * Clears the last recorded state. |
| */ |
| private void clearLastState() { |
| AcceleoModelManager.getManager().setProjectState(this.getProject(), null); |
| } |
| |
| /** |
| * Returns the last saved state for the given project. |
| * |
| * @param project |
| * The given project |
| * @return The last saved state for the given project |
| */ |
| private AcceleoProjectState getLastState(IProject project) { |
| return AcceleoModelManager.getManager().getLastBuiltState(project, new NullProgressMonitor()); |
| } |
| } |