/* * #%~ * org.overture.ide.core * %% * Copyright (C) 2008 - 2014 Overture * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #~% */ package org.overture.ide.internal.core.resources; import java.io.File; import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import org.eclipse.core.resources.ICommand; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.core.runtime.content.IContentTypeManager; import org.eclipse.core.runtime.jobs.Job; import org.overture.ast.lex.Dialect; import org.overture.config.Release; import org.overture.ide.core.ICoreConstants; import org.overture.ide.core.IVdmModel; import org.overture.ide.core.VdmCore; import org.overture.ide.core.ast.NotAllowedException; import org.overture.ide.core.builder.SafeBuilder; import org.overture.ide.core.resources.IVdmProject; import org.overture.ide.core.resources.IVdmSourceUnit; import org.overture.ide.core.resources.ModelBuildPath; import org.overture.ide.core.resources.Options; import org.overture.ide.core.utility.ILanguage; import org.overture.ide.core.utility.LanguageManager; import org.overture.ide.internal.core.ResourceManager; import org.overture.ide.internal.core.ast.VdmModelManager; public class VdmProject implements IVdmProject { private static final String LANGUAGE_VERSION_ARGUMENT_KEY = "LANGUAGE_VERSION"; // private static final String DYNAMIC_TYPE_CHECKS_ARGUMENT_KEY = "DYNAMIC_TYPE_CHECKS"; // private static final String INV_CHECKS_ARGUMENT_KEY = "INV_CHECKS"; // private static final String POST_CHECKS_ARGUMENT_KEY = "POST_CHECKS"; // private static final String PRE_CHECKS_ARGUMENT_KEY = "PRE_CHECKS"; private static final String SUPRESS_WARNINGS_ARGUMENT_KEY = "SUPPRESS_WARNINGS"; // private static final String MEASURE_CHECKS_ARGUMENT_KEY = "MEASURE_CHECKS"; public final IProject project; private ILanguage language = null; private final ModelBuildPath modelpath; private Options options = null; private VdmProject(IProject project) throws CoreException, NotAllowedException { this.project = project; for (ILanguage language : LanguageManager.getInstance().getLanguages()) { if (project.hasNature(language.getNature())) { this.language = language; break; } } if (this.language == null) throw new NotAllowedException(); this.modelpath = new ModelBuildPath(this); // Fix for old projects with Script Builder // this.setBuilder(this.getLanguageVersion()); } public static boolean isVdmProject(IProject project) { try { for (ILanguage language : LanguageManager.getInstance().getLanguages()) { if (project.hasNature(language.getNature())) { return true; } } } catch (CoreException e) { } return false; } public synchronized static IVdmProject createProject(IProject project) { if (ResourceManager.getInstance().hasProject(project)) return ResourceManager.getInstance().getProject(project); else { try { IVdmProject vdmProject = new VdmProject(project); return ResourceManager.getInstance().addProject(vdmProject); } catch (Exception e) { if (VdmCore.DEBUG) { VdmCore.log("VdmModelManager createProject", e); } return null; } } } @SuppressWarnings("unchecked") public static void addBuilder(IProject project, String name, String argumentKey, String argumentValue) throws CoreException { Vector<ICommand> buildCommands = new Vector<ICommand>(); boolean found = false; IProjectDescription description = project.getDescription(); for (ICommand command : description.getBuildSpec()) { buildCommands.add(command); if (command.getBuilderName().equals(name)) { found = true; if (argumentKey != null && argumentValue != null) { @SuppressWarnings("rawtypes") Map arguments = command.getArguments(); if (arguments == null) arguments = new HashMap<String, String>(); if (arguments.containsKey(argumentKey)) arguments.remove(argumentKey); arguments.put(argumentKey, argumentValue); command.setArguments(arguments); } } } if (!found) { ICommand newCommand = description.newCommand(); newCommand.setBuilderName(name); if (argumentKey != null && argumentValue != null) { @SuppressWarnings("rawtypes") Map arguments = new HashMap<String, String>(); arguments.put(argumentKey, argumentValue); newCommand.setArguments(arguments); } buildCommands.add(newCommand); } ICommand[] commands = new ICommand[buildCommands.size()]; commands = buildCommands.toArray(commands); description.setBuildSpec(commands); project.setDescription(description, null); } /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject#setBuilder(org.overture.vdmj .Release) */ /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject1#setBuilder(org.overture.vdmj .Release) */ public void setBuilder(Release languageVersion) throws CoreException { addBuilder(getProject(), ICoreConstants.BUILDER_ID, LANGUAGE_VERSION_ARGUMENT_KEY, languageVersion.toString()); } private IProject getProject() { return this.project; } /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject#hasBuilder() */ /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject1#hasBuilder() */ public boolean hasBuilder() throws CoreException { Vector<ICommand> buildCommands = new Vector<ICommand>(); IProjectDescription description = project.getDescription(); for (ICommand command : description.getBuildSpec()) { buildCommands.add(command); if (command.getBuilderName().equals(ICoreConstants.BUILDER_ID)) return true; } return false; } /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject#getLanguageVersion() */ /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject1#getLanguageVersion() */ public Release getLanguageVersion() throws CoreException { if (!hasBuilder()) return Release.DEFAULT; else { Object languageVersion = getBuilderArguemnt(LANGUAGE_VERSION_ARGUMENT_KEY); if (languageVersion != null && Release.lookup(languageVersion.toString()) != null) return Release.lookup(languageVersion.toString()); } return Release.DEFAULT; } public String getLanguageVersionName() throws CoreException { return getLanguageVersion().toString(); } // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#hasDynamictypechecks() // */ // public boolean hasDynamictypechecks() // { // return hasArgument(DYNAMIC_TYPE_CHECKS_ARGUMENT_KEY, true); // } // // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#hasInvchecks() // */ // public boolean hasInvchecks() // { // return hasArgument(INV_CHECKS_ARGUMENT_KEY, true); // } // // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#hasPostchecks() // */ // public boolean hasPostchecks() // { // return hasArgument(POST_CHECKS_ARGUMENT_KEY, true); // } // // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#hasPrechecks() // */ // public boolean hasPrechecks() // { // return hasArgument(PRE_CHECKS_ARGUMENT_KEY, true); // } // // public boolean hasMeasurechecks() // { // return hasArgument(MEASURE_CHECKS_ARGUMENT_KEY, true); // } /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject1#hasSuppressWarnings() */ public boolean hasSuppressWarnings() { return hasArgument(SUPRESS_WARNINGS_ARGUMENT_KEY, false); } // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#setDynamictypechecks(java.lang. Boolean) // */ // public void setDynamictypechecks(Boolean value) throws CoreException // { // addBuilder(getProject(), ICoreConstants.BUILDER_ID, DYNAMIC_TYPE_CHECKS_ARGUMENT_KEY, value.toString()); // } // // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#setInvchecks(java.lang.Boolean) // */ // public void setInvchecks(Boolean value) throws CoreException // { // addBuilder(getProject(), ICoreConstants.BUILDER_ID, INV_CHECKS_ARGUMENT_KEY, value.toString()); // } // // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#setPostchecks(java.lang.Boolean) // */ // public void setPostchecks(Boolean value) throws CoreException // { // addBuilder(getProject(), ICoreConstants.BUILDER_ID, POST_CHECKS_ARGUMENT_KEY, value.toString()); // } // // /* // * (non-Javadoc) // * @see org.overture.ide.utility.IVdmProject1#setPrechecks(java.lang.Boolean) // */ // public void setPrechecks(Boolean value) throws CoreException // { // addBuilder(getProject(), ICoreConstants.BUILDER_ID, PRE_CHECKS_ARGUMENT_KEY, value.toString()); // } // // public void setMeasurechecks(Boolean value) throws CoreException // { // addBuilder(getProject(), ICoreConstants.BUILDER_ID,MEASURE_CHECKS_ARGUMENT_KEY, value.toString()); // } /* * (non-Javadoc) * @see org.overture.ide.utility.IVdmProject1#setSuppressWarnings(java.lang.Boolean ) */ public void setSuppressWarnings(Boolean value) throws CoreException { addBuilder(getProject(), ICoreConstants.BUILDER_ID, SUPRESS_WARNINGS_ARGUMENT_KEY, value.toString()); } private boolean hasArgument(String argumentKey, boolean defaultValue) { Object argument; try { argument = getBuilderArguemnt(argumentKey); if (argument != null) { return Boolean.parseBoolean(argument.toString()); } } catch (CoreException e) { // Could not retrieve value so return default } return defaultValue; } private Object getBuilderArguemnt(String argumentKey) throws CoreException { if (hasBuilder()) return getBuilderArgument(project, ICoreConstants.BUILDER_ID, argumentKey); return null; } public static Object getBuilderArgument(IProject project, String builderId, String argumentKey) throws CoreException { Vector<ICommand> buildCommands = new Vector<ICommand>(); IProjectDescription description = project.getDescription(); for (ICommand command : description.getBuildSpec()) { buildCommands.add(command); if (command.getBuilderName().equals(builderId)) { if (command.getArguments().containsKey(argumentKey)) { Object argumentValue = command.getArguments().get(argumentKey); if (argumentValue != null) return argumentValue; } } } return null; } /** * For this marvelous project we need to: - create the default Eclipse project - add the custom project nature - * create the folder structure * * @param projectName * @param location * @param natureId * @return * @throws NotAllowedException * @throws CoreException */ public static IVdmProject createProject(String projectName, URI location, String nature) throws CoreException, NotAllowedException { Assert.isNotNull(projectName); Assert.isTrue(projectName.trim().length() > 0); IProject project = createBaseProject(projectName, location); try { addNature(project, nature); //String[] paths = { };//"parent/child1-1/child2", "parent/child1-2/child2/child3" }; //$NON-NLS-1$ //$NON-NLS-2$ // addToProjectStructure(project, paths); } catch (CoreException e) { VdmCore.log("VdmProject createProject", e); project = null; } return new VdmProject(project); } /** * Just do the basics: create a basic project. * * @param location * @param projectName */ private static IProject createBaseProject(String projectName, URI location) { // it is acceptable to use the ResourcesPlugin class IProject newProject = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); if (!newProject.exists()) { URI projectLocation = location; IProjectDescription desc = newProject.getWorkspace().newProjectDescription(newProject.getName()); if (location != null || ResourcesPlugin.getWorkspace().getRoot().getLocationURI().equals(location)) { projectLocation = null; } desc.setLocationURI(projectLocation); try { newProject.create(desc, null); if (!newProject.isOpen()) { newProject.open(null); } } catch (CoreException e) { VdmCore.log("VdmModelManager createBaseProject", e); } } return newProject; } public static void addNature(IProject project, String nature) throws CoreException { if (!project.hasNature(nature)) { IProjectDescription description = project.getDescription(); String[] prevNatures = description.getNatureIds(); String[] newNatures = new String[prevNatures.length + 1]; System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length); newNatures[prevNatures.length] = nature; description.setNatureIds(newNatures); IProgressMonitor monitor = null; project.setDescription(description, monitor); } } public boolean typeCheck(IProgressMonitor monitor) throws CoreException { // getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); IVdmModel model = getModel(); if (model.isTypeCorrect()) { return true; // no need to do any work } else { final IVdmProject currentProject = this; final IProgressMonitor mon = monitor; ISafeRunnable runnable = new ISafeRunnable() { public void handleException(Throwable e) { VdmCore.log("VdmProject typeCheck ISafeRunnable", e); } @SuppressWarnings("deprecation") public void run() throws Exception { final SafeBuilder builder = new SafeBuilder(currentProject, mon); builder.start(); while (builder.isAlive()) { Thread.sleep(100); if (mon.isCanceled()) { builder.stop(); } } } }; SafeRunner.run(runnable); return model.isTypeCorrect(); } } public void typeCheck(boolean clean, IProgressMonitor monitor) throws CoreException { if (clean) getProject().build(IncrementalProjectBuilder.FULL_BUILD, monitor); else getProject().build(IncrementalProjectBuilder.AUTO_BUILD, monitor); } public static void waitForBuidCompletion() { while (true) { Job[] jobs = Job.getJobManager().find(null); boolean builderFound = false; for (Job job : jobs) { if (job.getName().contains("org.overture.ide.builders.vdmj")) builderFound = true; } if (!builderFound) return; else { try { Thread.sleep(200); } catch (InterruptedException e) { } } } } /*** * This method removed all problem markers and its sub-types from the project. It is called before an instance of * the AbstractBuilder is created * * @param project * The project which should be build. */ public void clearProblemMarkers() { try { this.project.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_INFINITE); } catch (CoreException e) { if (VdmCore.DEBUG) { VdmCore.log("VdmProject clearProblemMarkers", e); } } } public File getFile(IFile file) { Path path = new Path(file.getProject().getFullPath().addTrailingSeparator().toString() + file.getProjectRelativePath().toString()); return getSystemFile(path); } public File getSystemFile(IPath path) { return project.getFile(path.removeFirstSegments(1)).getLocation().toFile(); } public File getFile(IWorkspaceRoot wroot, IPath path) { return wroot.getFile(path.removeFirstSegments(1)).getLocation().toFile(); } /*** * Get files from a eclipse project * * @param project * the project to scan * @param contentTypeId * of the type of files that should be returned * @return a list of IFile * @throws CoreException */ public List<IVdmSourceUnit> getSpecFiles() throws CoreException { List<IVdmSourceUnit> list = new Vector<IVdmSourceUnit>(); IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); for (String contentTypeId : language.getContentTypes()) { for (IVdmSourceUnit iVdmSourceUnit : getFiles(contentTypeManager.getContentType(contentTypeId))) { if(!list.contains(iVdmSourceUnit)) { list.add(iVdmSourceUnit); } } } return list; } public String getVdmNature() { return language.getNature(); } /*** * Get files from a eclipse project * * @param project * the project to scan * @param iContentType * of the type of files that should be returned * @return a list of IFile * @throws CoreException */ public List<IVdmSourceUnit> getFiles(IContentType iContentType) throws CoreException { List<IVdmSourceUnit> list = new Vector<IVdmSourceUnit>(); for (IContainer container : modelpath.getModelSrcPaths()) { if (!container.exists() || !container.isAccessible()) { continue; } for (IResource res : container.members(IContainer.INCLUDE_PHANTOMS | IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS)) { list.addAll(ResourceManager.getInstance().getFiles(this, res, iContentType)); } } return list; } public boolean isModelFile(IFile file) throws CoreException { for (IContainer src : modelpath.getModelSrcPaths()) { // Check model path if (src.getFullPath().isPrefixOf(file.getFullPath())&& !modelpath.getOutput().getFullPath().isPrefixOf(file.getFullPath()))//TODO check this, does it break something? not using the actual location. This was changed to do linked files. { //Check content type for (IContentType contentType : getContentTypeIds()) { if(contentType.isAssociatedWith(file.getName())&& !file.getName().startsWith("~$")) { return true; } } // if (file.getContentDescription() != null && getContentTypeIds().contains(file.getContentDescription().getContentType().getId())) // { // return true; // } } } return false; } /*** * Gets the IFile from the Eclipse filesystem from a normal file placed in a project * * @param project * the project which holds the file * @param file * the File to look up * @return a new IFile representing the file in the eclipse filesystem */ public IFile findIFile(File file) { IPath location = Path.fromOSString(file.getAbsolutePath()); IFile ifile = project.getFile(location); if (ifile == null || !ifile.exists()) { IPath absolutePath = new Path(file.getAbsolutePath()); // check if the project contains a IFile which maps to the same // file system location try { for (IVdmSourceUnit f : getSpecFiles()) { if (f.getFile().getLocation().equals(absolutePath)) return f.getFile(); } } catch (CoreException e1) { } // project does not contain this file, this means that the file has // been include elsewhere and a link will be created to the file // instead. try { linkFileToProject(file); } catch (CoreException e) { } } return ifile; } public void linkFileToProject(File file) throws CoreException { final IPath absolutePath = new Path(file.getAbsolutePath()); final IFile ifile = project.getFile(absolutePath.lastSegment()); Job j = new Job("Link file") { @Override protected IStatus run(IProgressMonitor monitor) { try { ifile.createLink(absolutePath, IResource.REPLACE, null); } catch (CoreException e) { VdmCore.log("VdmProject linkFileToProject", e); return Status.CANCEL_STATUS; } return Status.OK_STATUS; } }; j.setPriority(Job.BUILD); j.schedule(); } public IVdmModel getModel() { return VdmModelManager.getInstance().getModel(this); } @Override public String toString() { return getName(); } public Dialect getDialect() { return this.language.getDialect(); } public IVdmSourceUnit findSourceUnit(IFile file) throws CoreException { for (IVdmSourceUnit source : getSpecFiles()) { if(source.getFile().equals(file)) { return source; } } return null; } public List<IContentType> getContentTypeIds() { IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); List<IContentType> types = new Vector<IContentType>(); for (String type : language.getContentTypes()) { types.add(contentTypeManager.getContentType(type)); } return types; } public String getName() { return this.project.getName(); } public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { return Platform.getAdapterManager().getAdapter(this, adapter); } public ModelBuildPath getModelBuildPath() { return this.modelpath; } public Options getOptions() { if (options == null) { options = Options.load(this); } return options; } // @Override // public boolean equals(Object obj) // { // return project.equals(obj); // } // @Override // public int hashCode() // { // return project.hashCode(); // } }