/******************************************************************************* * Copyright (c) 2015 ARM Ltd. and others * 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: * ARM Ltd and ARM Germany GmbH - Initial API and implementation *******************************************************************************/ package com.arm.cmsis.pack.project.utils; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.Iterator; import java.util.List; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.settings.model.ICSourceEntry; import org.eclipse.cdt.core.settings.model.util.CDataUtil; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import com.arm.cmsis.pack.common.CmsisConstants; import com.arm.cmsis.pack.info.ICpFileInfo; import com.arm.cmsis.pack.project.CpProjectPlugIn; import com.arm.cmsis.pack.project.IRteProject; import com.arm.cmsis.pack.project.Messages; import com.arm.cmsis.pack.project.RteProjectManager; import com.arm.cmsis.pack.project.RteProjectNature; /** * Helper class with useful static methods */ public class ProjectUtils { /** * Returns ICpProject for given IProject if such exists * @param project IProject * @return */ public static ICProject getCProject(IProject project) { if (project == null) { return null; } try { ICProject[] cProjects = CoreModel.getDefault().getCModel().getCProjects(); if (cProjects != null) { for (ICProject cProject : cProjects) { if (project.equals(cProject.getProject())) { return cProject; } } } } catch (CModelException e) { e.printStackTrace(); } return null; } /** * Return IProject of a project * @param projectName name of the project * @return instance of IProject */ public static IProject getProject(String projectName) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); return project; } /** * Return IProject of a project * @param projectName name of the project * @return instance of IProject */ public static IProject getValidProject(String projectName) throws CoreException { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); if (project == null || !project.exists()) { String msg = Messages.ProjectUtils_Project + projectName + Messages.ProjectUtils_DoesNotExistsOrNotAccessible; Status status = new Status(IStatus.ERROR, CpProjectPlugIn.PLUGIN_ID, msg); throw new CoreException(status); } return project; } /** * Creates an empty file if it does not exist * Folder is automatically created if not existing. * @param project parent IProject * @param dstFile project file name, e.g. src/package1/file.c * @param monitor IProgressMonitor * @return created or existing IFile * @throws CoreException */ public static IFile createFile(IProject project, String dstFile, IProgressMonitor monitor) throws CoreException { // create folder if not existing String folder = removeLastPathSegment(dstFile); createProjectFolder(project, folder, monitor); IFile file = project.getFile(dstFile); if(file.isLinked()) { file.delete(true, null); file = project.getFile(dstFile); } if (file.exists()) { return file; // file already exists } file.create(null, true, monitor); return file; } /** * Copy a local file to a local project folder. * Destination file name can be different than the source one. * Folder is automatically created if not existing. * @param projectName name of the project * @param srcFile source file name, e.g. C:/work/file.c * @param dstFile project file name, e.g. src/package1/file.c * @param index file index: >=0 for headers/sources of multi-instance project components -1 for others * @param monitor IProgressMonitor * @param forceOverwrite set to true when updating component file * @return 1 if the file has been copied, -1 if file already exists or 0 if there is an error * @throws CoreException */ public static int copyFile(String projectName, String srcFile, String dstFile, int index, IProgressMonitor monitor, boolean forceOverwrite) throws Exception { IProject project = getValidProject(projectName); return copyFile(project, srcFile, dstFile, index, monitor, forceOverwrite); } /** * Copy a local file to a local project folder. * Destination file name can be different than the source one. * Folder is automatically created if not existing. * @param project parent IProject * @param srcFile source file name, e.g. C:/work/file.c * @param dstFile destination file name, e.g. RTE/class/file.c * @param index file index: >=0 for headers/sources of multi-instance project components -1 for others * @param monitor IProgressMonitor * @param forceOverwrite set to true when updating component file * @return 1 if the file has been copied, -1 if file already exists or 0 if there is an error * @throws CoreException */ public static int copyFile(IProject project, String srcFile, String dstFile, int index, IProgressMonitor monitor, boolean forceOverwrite) throws CoreException { IFile file = createFile(project, dstFile, monitor); if(srcFile == null) { return 0; // only create resource, do not copy the content } IPath loc = file.getLocation(); File f = loc.toFile(); if(f != null && f.exists() && !forceOverwrite) { return -1; // destination file already exists } File inputfile = new File(srcFile); if (!inputfile.exists()) { String msg = Messages.ProjectUtils_TheFile + srcFile + Messages.ProjectUtils_DoesNotExistsOrNotAccessible; Status status = new Status(IStatus.ERROR, CpProjectPlugIn.PLUGIN_ID, msg); throw new CoreException(status); } try { if(index < 0) { FileInputStream fileStream = new FileInputStream(inputfile); if(file.exists()) { file.delete(true, true, null); } file.create(fileStream, true, null); fileStream.close(); } else { FileReader fr = new FileReader(inputfile); IPath p = file.getLocation(); PrintWriter pw = new PrintWriter(p.toOSString()); String instance = String.valueOf(index); BufferedReader br = new BufferedReader(fr); String s; while ((s = br.readLine()) != null) { s = s.replaceAll(CmsisConstants.pINSTANCEp, instance); pw.println(s); } fr.close(); pw.close(); file.refreshLocal(IResource.DEPTH_INFINITE, null); } } catch ( IOException e) { e.printStackTrace(); String msg = Messages.ProjectUtils_CannotCopyFile + srcFile + Messages.ProjectUtils_to + dstFile; Status status = new Status(IStatus.ERROR, CpProjectPlugIn.PLUGIN_ID, msg, e); throw new CoreException(status); } return 1; } /** * Create a link in a local (if folder exists) or virtual folder if folder has to be created. * @param projectName name of project * @param srcFile source file which is to be linked, may not be relative. * @param dstFile destination file in a virtual project folder. Folder(s) are created if not existing. * @param monitor IProgressMonitor * @throws CoreException */ public static void createLink(String projectName, String srcFile, String dstFile, IProgressMonitor monitor) throws CoreException { IProject project = getValidProject(projectName); createLink(project, srcFile, dstFile, monitor); } /** * Create a link in a local (if folder exists) or virtual folder if folder has to be created. * @param srcFile source file which is to be linked, may not be relative. * @param project parent IProject * @param dstFile destination file in a virtual project folder. Folder(s) are created if not existing. * @param monitor IProgressMonitor * @throws CoreException */ public static void createLink(IProject project, String srcFile, String dstFile, IProgressMonitor monitor ) throws CoreException { // create folder if not existing String folder = removeLastPathSegment(dstFile); // retrieve only folder name createProjectFolder(project, folder, monitor); // create link IFile file = project.getFile(dstFile); IPath path = new Path(srcFile); file.createLink(path, IResource.REPLACE, monitor); } /** * Create folder (and sub-folders). Folder (and sub-folders) can be local or virtual. * @param projectName name of project * @param projectFolder project folder. E.g. src/package1/package2 * @param monitor IProgressMonitor * @throws CoreException */ public static void createProjectFolder(String projectName, String projectFolder, IProgressMonitor monitor) throws CoreException { IProject project = getValidProject(projectName); createProjectFolder(project, projectFolder, monitor); } /** * Create folder (and sub-folders). Folder (and sub-folders) can be local or virtual. * @param project instance of IProject * @param projectFolder project folder. E.g. src/package1/package2 * @param virtual true if folder (and sub-folders) are virtual * @param monitor IProgressMonitor * @throws CoreException */ public static void createProjectFolder(IProject project, String projectFolder, IProgressMonitor monitor) throws CoreException { if(projectFolder.isEmpty()) { return; } IPath path = new Path(projectFolder); if (path.isAbsolute()) { String msg = Messages.ProjectUtils_ProjectfolderMustBeRelative; Status status = new Status(IStatus.ERROR, CpProjectPlugIn.PLUGIN_ID, msg); throw new CoreException(status); } // create non-existing folders for (int i=1;i<=path.segmentCount();i++) { IFolder subfolder = project.getFolder(path.uptoSegment(i)); if (!subfolder.exists()) { subfolder.create(true, true, monitor); } } } /** * Remove the last segment of a path specification which can be a file or a sub-folder. * @param filePath fully specified file/path name, e.g. src/package/file.c * @return path without last path segment, e.g. src/package */ public static String removeLastPathSegment(String filePath) { IPath path = new Path(filePath); path = path.removeLastSegments(1); // remove file return path.toString(); } /** * Set a configuration as active one. * @param projectName IProject owning configuration * @param configName configuration name to set * @return true if active configuration has changed */ public static boolean setDefaultConfiguration(String projectName, String configName) { IProject project = getProject(projectName); IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); if(buildInfo == null) { return false; } IConfiguration activeConfig = buildInfo.getDefaultConfiguration(); if (activeConfig != null && configName.equals(activeConfig.getName())) { return true; } return buildInfo.setDefaultConfiguration(configName); } /** * Returns IConfiguration for given name * @param project owning IProject * @name configuration name to retrieve * @return IConfiguration */ public static IConfiguration getConfiguration(IProject project, String name) { if(project == null) { return null; } try{ IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); IConfiguration[] configs = buildInfo.getManagedProject().getConfigurations(); for(IConfiguration c : configs) { if(c.getName().equals(name)) { return c; } } } catch (Exception e) { e.printStackTrace(); return null; } return null; } /** * Returns active configuration * @param project owning IProject * @return active IConfiguration */ public static IConfiguration getDefaultConfiguration(IProject project) { if(project == null) { return null; } IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); if(buildInfo != null) { return buildInfo.getDefaultConfiguration(); } return null; } /** * Returns active configuration * @param projectName owning project name * @return active configuration */ public static IConfiguration getDefaultConfiguration(String projectName) { IProject project = getProject(projectName); return getDefaultConfiguration(project); } /** * Returns active configuration name * @param projectName owning project name * @return active configuration name */ public static String getDefaultConfigurationName(String projectName) { IConfiguration activeConfig = getDefaultConfiguration(projectName); if(activeConfig != null) { return activeConfig.getName(); } return null; } /** * Removes all entries beginning with RTE or ${cmsis_pack_root} paths from supplied list * @param paths list of paths/files to process * @return updated list */ static public List<String> removeRtePathEntries(List<String> paths) { for (Iterator<String> iterator = paths.iterator(); iterator.hasNext();) { String s = iterator.next(); if(s.startsWith(CmsisConstants.PROJECT_RTE_PATH) || s.startsWith(CmsisConstants.CMSIS_PACK_ROOT_VAR) || s.startsWith(CmsisConstants.CMSIS_RTE_VAR)) { iterator.remove(); } } return paths; } /** * Returns IResource for the given object if any * @param obj an object that is derived from IResource or adapts IResource * @return IResource if can be resolved or null */ static public IResource getResource(Object obj) { if(obj instanceof IResource) { return (IResource)obj; } if(obj instanceof IAdaptable) { IAdaptable a = (IAdaptable)obj; Object o = a.getAdapter(IResource.class); if(o != null) { return (IResource) o; } } return null; } /** * Returns IReource object if it represents an RTE file or folder * @param obj an object that is derived from IResource or adapts IResource * @return IReource if it is an RTE resource or null */ static public IResource getRteResource(Object obj) { IResource r = getResource(obj); if(r == null) { return null; } IProject project = r.getProject(); if(!RteProjectNature.hasRteNature(project)) { return null; } if(r.getType() == IResource.PROJECT) { return r; } IPath path = r.getProjectRelativePath(); if(path == null || path.isEmpty()) { return null; } if(r.getType() == IResource.FILE && path.segmentCount() == 1) { if(CmsisConstants.RTECONFIG.equals(r.getFileExtension())) { return r; } } if(!path.segment(0).startsWith(CmsisConstants.RTE)) { return null; } return r; } /** * Returns IFile object if it represents an RTE file * @param obj an object that is derived from IResource or adapts IResource * @return IFile if it is an RTE file or null */ static public IFile getRteFileResource(Object obj) { IResource r = getRteResource(obj); if(r instanceof IFile) { return (IFile)r; } return null; } static public ICpFileInfo getCpFileInfo(IResource resource) { if(resource == null || resource.getType() != IResource.FILE) { return null; } IProject project = resource.getProject(); RteProjectManager rteProjectManager = CpProjectPlugIn.getRteProjectManager(); IRteProject rteProject = rteProjectManager.getRteProject(project); if(rteProject != null) { IPath path = resource.getProjectRelativePath(); return rteProject.getProjectFileInfo(path.toString()); } return null; } /** * Exclude the file with project relative path of "path" from build if bExclude is * set to true * @param project the project * @param path the resource's relative path to the project * @param bExclude set to true to exclude the resource from build * @throws CoreException */ static public void setExcludeFromBuild(IProject project, String path, boolean bExclude) throws CoreException { IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); IConfiguration activeConfig = buildInfo.getDefaultConfiguration(); ICSourceEntry[] sourceEntries = activeConfig.getSourceEntries(); sourceEntries = CDataUtil.setExcluded(new Path(path), false, bExclude, sourceEntries); activeConfig.setSourceEntries(sourceEntries); } /** * Check if a folder or file is excluded from build * @param project the project * @param path the resource's relative path to the project * @return true if the folder or file is excluded from build */ static public boolean isExcludedFromBuild(IProject project, String path) { IManagedBuildInfo buildInfo = ManagedBuildManager.getBuildInfo(project); IConfiguration activeConfig = buildInfo.getDefaultConfiguration(); ICSourceEntry[] sourceEntries = activeConfig.getSourceEntries(); return CDataUtil.isExcluded(new Path(path), sourceEntries); } }