/******************************************************************************* * Copyright (c) 2007, 2010 Intel Corporation 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: * Intel Corporation - Initial API and implementation * IBM Corporation *******************************************************************************/ package org.eclipse.cdt.build.internal.core.scannerconfig; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.eclipse.cdt.build.core.scannerconfig.CfgInfoContext; import org.eclipse.cdt.build.core.scannerconfig.ICfgScannerConfigBuilderInfo2Set; import org.eclipse.cdt.build.core.scannerconfig.ScannerConfigBuilder; import org.eclipse.cdt.build.internal.core.scannerconfig.PerFileSettingsCalculator.ILangSettingInfo; import org.eclipse.cdt.build.internal.core.scannerconfig.PerFileSettingsCalculator.IRcSettingInfo; import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.settings.model.ICSettingBase; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.core.settings.model.extension.CFolderData; import org.eclipse.cdt.core.settings.model.extension.CResourceData; import org.eclipse.cdt.make.core.MakeCorePlugin; import org.eclipse.cdt.make.core.scannerconfig.IDiscoveredPathManager; import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2; import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector; import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector2; import org.eclipse.cdt.make.core.scannerconfig.PathInfo; import org.eclipse.cdt.make.internal.core.scannerconfig.DiscoveredScannerInfoStore; import org.eclipse.cdt.make.internal.core.scannerconfig2.PerFileSICollector; import org.eclipse.cdt.make.internal.core.scannerconfig2.SCProfileInstance; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IFileInfo; import org.eclipse.cdt.managedbuilder.core.IFolderInfo; import org.eclipse.cdt.managedbuilder.core.IInputType; import org.eclipse.cdt.managedbuilder.core.IResourceInfo; import org.eclipse.cdt.managedbuilder.core.ITool; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin; import org.eclipse.cdt.managedbuilder.internal.core.Configuration; import org.eclipse.cdt.managedbuilder.internal.core.FolderInfo; import org.eclipse.cdt.managedbuilder.internal.core.Tool; import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildFileData; import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildFolderData; import org.eclipse.cdt.managedbuilder.internal.dataprovider.BuildLanguageData; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRunnable; 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.NullProgressMonitor; import org.eclipse.core.runtime.jobs.ILock; import org.eclipse.core.runtime.jobs.Job; public class CfgDiscoveredPathManager implements IResourceChangeListener { public static CfgDiscoveredPathManager fInstance; private IDiscoveredPathManager fBaseMngr; /** Deadlock-safe mutex lock */ private ILock lock = Job.getJobManager().newLock(); private static class ContextInfo { public ContextInfo() { } CfgInfoContext fInitialContext; CfgInfoContext fCacheContext; CfgInfoContext fLoadContext; ICfgScannerConfigBuilderInfo2Set fCfgInfo; IScannerConfigBuilderInfo2 fInfo; boolean fIsPerFileCache; } public static class PathInfoCache{ private PathInfo fPathInfo; private String fProfileId; public PathInfo getPathInfo(){ return fPathInfo; } private PathInfoCache(String profileId, PathInfo pathInfo){ this.fProfileId = profileId; this.fPathInfo = pathInfo; } } private CfgDiscoveredPathManager() { fBaseMngr = MakeCorePlugin.getDefault().getDiscoveryManager(); } public static CfgDiscoveredPathManager getInstance(){ if(fInstance == null){ fInstance = new CfgDiscoveredPathManager(); fInstance.startup(); } return fInstance; } public static void stop(){ if(fInstance != null) fInstance.shutdown(); } public void startup() { ResourcesPlugin.getWorkspace().addResourceChangeListener(this); } public void shutdown() { ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); } /* (non-Javadoc) * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) */ public void resourceChanged(IResourceChangeEvent event) { if (event.getSource() instanceof IWorkspace) { IResource resource = event.getResource(); switch (event.getType()) { case IResourceChangeEvent.POST_CHANGE : // DiscoveredScannerInfoStore.getInstance().updateScannerConfigStore(event.getDelta()); break; case IResourceChangeEvent.PRE_DELETE : case IResourceChangeEvent.PRE_CLOSE : if (resource.getType() == IResource.PROJECT) { // fDiscoveredMap.remove(resource); } break; } } } public void updateCoreSettings(final IProject project, final IConfiguration cfgs[]) { try { IWorkspaceRunnable runnable = new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { ManagedBuildManager.updateCoreSettings(project, cfgs, true); } }; CoreModel.run(runnable, null); } catch (CoreException e) { ManagedBuilderCorePlugin.log(e); } } public PathInfo getDiscoveredInfo(IProject project, CfgInfoContext context) throws CoreException { ContextInfo cInfo = getContextInfo(context); PathInfo info = getCachedPathInfo(cInfo); if (info == null) { try { lock.acquire(); info = getCachedPathInfo(cInfo); if(info == null){ IDiscoveredPathManager.IDiscoveredPathInfo baseInfo = loadPathInfo(project, context.getConfiguration(), cInfo); info = resolveCacheBaseDiscoveredInfo(cInfo, baseInfo); } } finally { lock.release(); } } return info; } // private void adjustPerRcContextInfo(ContextInfo cInfo){ // cInfo.fIsFerFileCache = true; // cInfo.fCacheContext = cInfo.fInitialContext; // cInfo.fLoadContext = new CfgInfoContext(cInfo.fInitialContext.getConfiguration()); // } private PathInfo resolveCacheBaseDiscoveredInfo(ContextInfo cInfo, IDiscoveredPathManager.IDiscoveredPathInfo baseInfo){ if(cInfo.fIsPerFileCache){ if(baseInfo instanceof IDiscoveredPathManager.IPerFileDiscoveredPathInfo2){ resolveCachePerFileInfo(cInfo, (IDiscoveredPathManager.IPerFileDiscoveredPathInfo2)baseInfo); } return getCachedPathInfo(cInfo); } ((FolderInfo)cInfo.fLoadContext.getConfiguration().getRootFolderInfo()).setContainsDiscoveredScannerInfo(true); Map<String, String> map = baseInfo.getSymbols(); IPath paths[] = baseInfo.getIncludePaths(); PathInfo info = new PathInfo(paths, null, map, null, null); setCachedPathInfo(cInfo, info); return info; } private void resolveCachePerFileInfo(ContextInfo cInfo, IDiscoveredPathManager.IPerFileDiscoveredPathInfo2 info){ CConfigurationData data = cInfo.fLoadContext.getConfiguration().getConfigurationData(); if(data == null) return; PerFileSettingsCalculator calculator = new PerFileSettingsCalculator(); IRcSettingInfo[] rcInfos = calculator.getSettingInfos(cInfo.fLoadContext.getConfiguration().getOwner().getProject(), data, info, true); CResourceData rcDatas[] = data.getResourceDatas(); Map<IPath, CResourceData> rcDataMap = new HashMap<IPath, CResourceData>(); CResourceData rcData; for(int i = 0; i < rcDatas.length; i++){ rcData = rcDatas[i]; rcDataMap.put(rcData.getPath(), rcData); } IRcSettingInfo rcInfo; IPath path; boolean rootSettingFound = false; boolean fileSettingFound = false; for(int i = 0; i < rcInfos.length; i++){ rcInfo = rcInfos[i]; rcData = rcInfo.getResourceData(); path = rcData.getPath(); if(path.segmentCount() != 0) fileSettingFound = true; else rootSettingFound = true; rcDataMap.remove(path); cache(cInfo, rcInfo); } if(rootSettingFound && fileSettingFound) ((BuildFolderData)data.getRootFolderData()).setContainsDiscoveredScannerInfo(false); if(!rcDataMap.isEmpty()){ CResourceData tmpRcData; for(Iterator<CResourceData> iter = rcDataMap.values().iterator(); iter.hasNext();){ tmpRcData = iter.next(); if(tmpRcData.getPath().segmentCount() == 0 && tmpRcData.getType() == ICSettingBase.SETTING_FOLDER){ cache(cInfo, PerFileSettingsCalculator.createEmptyRcSettingInfo((CFolderData)tmpRcData)); } else { clearCache(tmpRcData); } } } } private void cache(ContextInfo cInfo, IRcSettingInfo rcSetting){ CResourceData rcData = rcSetting.getResourceData(); clearCache(rcData); ILangSettingInfo lInfos[] = rcSetting.getLangInfos(); for(int i = 0; i < lInfos.length; i++){ cache(cInfo, lInfos[i]); } } private void cache(ContextInfo cInfo, ILangSettingInfo lInfo){ BuildLanguageData bld = (BuildLanguageData)lInfo.getLanguageData(); setCachedPathInfo(cInfo, (Configuration)bld.getConfiguration(), (Tool)bld.getTool(), bld.getInputType(), lInfo.getFilePathInfo()); } private void clearCache(CResourceData rcData){ if(rcData.getType() == ICSettingBase.SETTING_FILE){ IFileInfo fiInfo = ((BuildFileData)rcData).getFileInfo(); ITool tools[] = fiInfo.getTools(); clearCache(tools); } else { IFolderInfo foInfo = ((BuildFolderData)rcData).getFolderInfo(); ITool[] tools = foInfo.getTools(); clearCache(tools); } } private void clearCache(ITool[] tools){ for(int i = 0; i < tools.length; i++){ ((Tool)tools[i]).clearAllDiscoveredInfo(); } } private IDiscoveredPathManager.IDiscoveredPathInfo loadPathInfo(IProject project, IConfiguration cfg, ContextInfo cInfo) throws CoreException{ IDiscoveredPathManager.IDiscoveredPathInfo info = fBaseMngr.getDiscoveredInfo(cfg.getOwner().getProject(), cInfo.fLoadContext.toInfoContext(), false); if(!DiscoveredScannerInfoStore.getInstance().hasInfo(project, cInfo.fLoadContext.toInfoContext(), info.getSerializable())){ // setCachedPathInfo(context, info); ICfgScannerConfigBuilderInfo2Set container = cInfo.fCfgInfo; IScannerConfigBuilderInfo2 buildInfo = container.getInfo(cInfo.fLoadContext); if(buildInfo != null){ SCProfileInstance instance = ScannerConfigBuilder.build(cInfo.fLoadContext, buildInfo, 0, null, new NullProgressMonitor()); if(instance != null){ IScannerInfoCollector newC = instance.getScannerInfoCollector(); if(newC instanceof IScannerInfoCollector2 && !(newC instanceof PerFileSICollector)){ info = ((IScannerInfoCollector2)newC).createPathInfoObject(); // setCachedPathInfo(context, info); } } } } return info; } private PathInfo getCachedPathInfo(ContextInfo cInfo){ PathInfo info = getCachedPathInfo(cInfo, true, true, false); return info; } private void removeCachedPathInfo(ContextInfo cInfo){ // ICfgScannerConfigBuilderInfo2Set cfgInfo = cInfo.fCfgInfo; if(cInfo.fIsPerFileCache){ Configuration cfg = (Configuration)cInfo.fInitialContext.getConfiguration(); cfg.clearDiscoveredPathInfo(); IResourceInfo[] infos = cfg.getResourceInfos(); for(int i = 0; i < infos.length; i++){ IResourceInfo rcInfo = infos[i]; ITool[] tools = rcInfo.getTools(); for(int k = 0; k < tools.length; k++){ Tool tool = (Tool)tools[k]; tool.clearAllDiscoveredPathInfo(); } } } else { setCachedPathInfo(cInfo, null); } // PathInfo info = getCachedPathInfo(cInfo, true, true, true); } private PathInfo getCachedPathInfo(ContextInfo cInfo, boolean queryParent, boolean clearIfInvalid, boolean clear){ return getCachedPathInfo(cInfo, (Configuration)cInfo.fCacheContext.getConfiguration(), (Tool)cInfo.fCacheContext.getTool(), cInfo.fCacheContext.getInputType(), queryParent, clearIfInvalid, clear); } private PathInfo getCachedPathInfo(ContextInfo cInfo, Configuration cfg, Tool tool, IInputType inType, boolean queryParent, boolean clearIfInvalid, boolean clear){ PathInfoCache infoCache = getPathInfoCache(cInfo, cfg, tool, inType, queryParent, clearIfInvalid, clear); if(infoCache != null && isCacheValid(cInfo, infoCache)) return infoCache.fPathInfo; return null; } private PathInfoCache getPathInfoCache(ContextInfo cInfo, Configuration cfg, Tool tool, IInputType inType, boolean queryParent, boolean clearIfInvalid, boolean clear){ PathInfoCache info = null; // boolean queryCfg = false; if(tool != null){ info = tool.getDiscoveredPathInfo(inType); if(info != null){ if(clear || (clearIfInvalid && !isCacheValid(cInfo, info))){ tool.clearDiscoveredPathInfo(inType); // fBaseMngr.removeDiscoveredInfo(cfg.getOwner().getProject(), cInfo.fLoadContext.toInfoContext()); } } else if(queryParent){ // IResourceInfo rcInfo = tool.getParentResourceInfo(); ITool superTool = tool.getSuperClass(); if(superTool!=null && !superTool.isExtensionElement()){ if(inType != null){ IInputType superInType = null; String exts[] = inType.getSourceExtensions(tool); for(int i = 0; i < exts.length; i++){ superInType = superTool.getInputType(exts[i]); if(superInType != null) break; } if(superInType != null){ info = getPathInfoCache(cInfo, cfg, (Tool)superTool, superInType, true, clearIfInvalid, clear); } } else { info = getPathInfoCache(cInfo, cfg, (Tool)superTool, null, true, clearIfInvalid, clear); } } else { info = getPathInfoCache(cInfo, cfg, null, null, true, clearIfInvalid, clear); } } } else { info = cfg.getDiscoveredPathInfo(); if(clear || (clearIfInvalid && !isCacheValid(cInfo, info))){ cfg.clearDiscoveredPathInfo(); // fBaseMngr.removeDiscoveredInfo(cfg.getOwner().getProject(), cInfo.fLoadContext.toInfoContext()); } } return info; } private boolean isCacheValid(ContextInfo cInfo, PathInfoCache cache){ if(cache == null) return true; if(cInfo.fInfo != null){ String id = cInfo.fInfo.getSelectedProfileId(); return id.equals(cache.fProfileId); } return false; } private ContextInfo getContextInfo(CfgInfoContext context){ return getContextInfo(context, null); } private ContextInfo getContextInfo(CfgInfoContext context, ICfgScannerConfigBuilderInfo2Set cfgInfo){ if(cfgInfo == null) cfgInfo = CfgScannerConfigProfileManager.getCfgScannerConfigBuildInfo(context.getConfiguration()); boolean isPerRcType = cfgInfo.isPerRcTypeDiscovery(); ContextInfo contextInfo = new ContextInfo(); contextInfo.fInitialContext = context; contextInfo.fCfgInfo = cfgInfo; if(isPerRcType){ contextInfo.fLoadContext = CfgScannerConfigUtil.adjustPerRcTypeContext(contextInfo.fInitialContext); contextInfo.fCacheContext = contextInfo.fLoadContext; contextInfo.fIsPerFileCache = false; contextInfo.fInfo = cfgInfo.getInfo(contextInfo.fLoadContext); } else { contextInfo.fLoadContext = new CfgInfoContext(context.getConfiguration()); contextInfo.fInfo = cfgInfo.getInfo(contextInfo.fLoadContext); contextInfo.fIsPerFileCache = CfgScannerConfigProfileManager.isPerFileProfile(contextInfo.fInfo.getSelectedProfileId()); contextInfo.fCacheContext = contextInfo.fIsPerFileCache ? contextInfo.fInitialContext : contextInfo.fLoadContext; } return contextInfo; } private PathInfo setCachedPathInfo(ContextInfo cInfo, PathInfo info){ CfgInfoContext cacheContext = cInfo.fCacheContext; return setCachedPathInfo(cInfo, (Configuration)cacheContext.getConfiguration(), (Tool)cacheContext.getTool(), cacheContext.getInputType(), info); } private PathInfo setCachedPathInfo(ContextInfo cInfo, Configuration cfg, Tool tool, IInputType inType, PathInfo info){ PathInfoCache oldInfo; PathInfoCache cache; if(info != null){ String id = cInfo.fInfo != null ? cInfo.fInfo.getSelectedProfileId() : null; cache = new PathInfoCache(id, info); } else { cache = null; } if(tool != null){ if(info != null) oldInfo = tool.setDiscoveredPathInfo(inType, cache); else oldInfo = tool.clearDiscoveredPathInfo(inType); } else { if(info != null) oldInfo = cfg.setDiscoveredPathInfo(cache); else oldInfo = cfg.clearDiscoveredPathInfo(); } return oldInfo != null ? oldInfo.fPathInfo : null; } public void removeDiscoveredInfo(IProject project, CfgInfoContext context) { removeDiscoveredInfo(project, context, true); } public void removeDiscoveredInfo(IProject project, CfgInfoContext context, boolean removeBaseCache) { // if(context == null) // context = ScannerConfigUtil.createContextForProject(project); ContextInfo cInfo = getContextInfo(context); removeCachedPathInfo(cInfo); if(removeBaseCache) fBaseMngr.removeDiscoveredInfo(project, cInfo.fLoadContext.toInfoContext()); } }