/******************************************************************************* * Copyright (c) 2008, 2011 Thomas Holland (thomas@innot.de) 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: * Thomas Holland - initial API and implementation *******************************************************************************/ package de.innot.avreclipse.mbs.scannerconfig; import java.util.HashMap; 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.internal.core.scannerconfig.CfgDiscoveredPathManager; import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigProfileManager; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.resources.ACBuilder; import org.eclipse.cdt.make.core.scannerconfig.IScannerConfigBuilderInfo2; import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollector; import org.eclipse.cdt.make.core.scannerconfig.IScannerInfoCollectorCleaner; import org.eclipse.cdt.make.core.scannerconfig.InfoContext; import org.eclipse.cdt.make.internal.core.scannerconfig.DiscoveredPathInfo; import org.eclipse.cdt.make.internal.core.scannerconfig.DiscoveredScannerInfoStore; import org.eclipse.cdt.make.internal.core.scannerconfig2.SCProfileInstance; import org.eclipse.cdt.make.internal.core.scannerconfig2.ScannerConfigProfileManager; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.runtime.jobs.Job; import de.innot.avreclipse.AVRPlugin; import de.innot.avreclipse.core.properties.ProjectPropertyManager; /** * Some utility methods for working with the discovery process. * * @author Thomas Holland * @since 2.5 * */ @SuppressWarnings("restriction") public class ScannerConfigUtil { /** * Clear all discovered symbols and paths for a configuration. * * @param cfg * The <code>IConfiguration</code> to be cleaned. * @throws CoreException */ public static void clearDiscovery(IConfiguration config) throws CoreException { // Get the/all CfgInfoContext objects for the given Configuration. // (Don't know when / if there are more than one CfgInfoContext objects for a single // Configuration) ICfgScannerConfigBuilderInfo2Set cbi = CfgScannerConfigProfileManager .getCfgScannerConfigBuildInfo(config); Map<CfgInfoContext, IScannerConfigBuilderInfo2> infoMap = cbi.getInfoMap(); for (CfgInfoContext cfgInfoContext : infoMap.keySet()) { // This is (mostly) copied from the DiscoveryTab class of the CDT UI project. // I don't really understand everything in here, but it seems to work... // @see // org.eclipse.cdt.managedbuilder.ui.properties.DiscoveryTab#clearDiscoveredEntries() // for no additional information :-) if (cfgInfoContext == null) { Status status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID, "Unexpected cfgInfoContext=null while trying to clear discovery entries"); //$NON-NLS-1$ throw new CoreException(status); } IConfiguration cfg = cfgInfoContext.getConfiguration(); if (cfg == null) { cfg = cfgInfoContext.getResourceInfo().getParent(); } if (cfg == null) { Status status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID, "Unexpected cfg=null while trying to clear discovery entries"); //$NON-NLS-1$ throw new CoreException(status); } IProject project = (IProject) cfg.getOwner(); DiscoveredPathInfo pathInfo = new DiscoveredPathInfo(project); InfoContext infoContext = cfgInfoContext.toInfoContext(); // 1. Remove scanner info from // .metadata/.plugins/org.eclipse.cdt.make.core/Project.sc DiscoveredScannerInfoStore dsiStore = DiscoveredScannerInfoStore.getInstance(); dsiStore.saveDiscoveredScannerInfoToState(project, infoContext, pathInfo); // 2. Remove scanner info from CfgDiscoveredPathManager cache and // from the Tool CfgDiscoveredPathManager cdpManager = CfgDiscoveredPathManager.getInstance(); cdpManager.removeDiscoveredInfo(project, cfgInfoContext); // 3. Remove scanner info from SI collector ICfgScannerConfigBuilderInfo2Set info2 = CfgScannerConfigProfileManager .getCfgScannerConfigBuildInfo(cfg); Map<CfgInfoContext, IScannerConfigBuilderInfo2> infoMap2 = info2.getInfoMap(); IScannerConfigBuilderInfo2 buildInfo2 = infoMap2.get(cfgInfoContext); if (buildInfo2 != null) { ScannerConfigProfileManager scpManager = ScannerConfigProfileManager.getInstance(); String selectedProfileId = buildInfo2.getSelectedProfileId(); SCProfileInstance profileInstance = scpManager.getSCProfileInstance(project, infoContext, selectedProfileId); IScannerInfoCollector collector = profileInstance.getScannerInfoCollector(); if (collector instanceof IScannerInfoCollectorCleaner) { ((IScannerInfoCollectorCleaner) collector).deleteAll(project); } buildInfo2 = null; } } } /** * Run the CDT Scanner Config Builder and the indexer for a project to discover the build in * paths/symbols and index them for the editor. * <p> * This method will check the perConfig flag of the AVR properties for the project and will run * the scanner builder either on * <ul> * <li>the active configuration ( perConfig <code>true</code>)</li> * <li>or all configurations ( perConfig <code>false</code>)</li> * </ul> * </p> * <p> * The actual build and the indexer is run in a background job and this method will return * immediately. Errors will be logged by the job. * * @param project * IProject with a <code>ScannerConfigNature</code> (normal CDT project) * @return The build job. Used for unit testing. */ public static Job runDiscovery(final IProject project) { Job buildJob = new Job("Running Scanner Config Builder") { @Override protected IStatus run(IProgressMonitor monitor) { // Check if the AVR properties apply to all configs. // If yes, then we want to run the ScannerConfigBuilder on all Configurations, while // by default it will only work on the active build configuration (unless changed by // the user in the preferences). // So we use a little "hack": Change the CDT Build preference property to // "Build all configurations" while we run the Scanner Config Builder and afterwards // restore the flag to the previous (user set) value. boolean isperconfig = ProjectPropertyManager.getPropertyManager(project) .isPerConfig(); boolean needallflag = ACBuilder.needAllConfigBuild(); if (!isperconfig) { // Set flag to build all configurations ACBuilder.setAllConfigBuild(true); } try { monitor.beginTask("Running scanner and indexer", 100); // // Run the Scanner Config Builder to re-discover paths and symbols // // Both parameters (kind and args) are unused by the ScannerConfigBuilder // We set them anyway for cleanness :-) int kind = IncrementalProjectBuilder.FULL_BUILD; Map<String, String> args = new HashMap<String, String>(); project.build(kind, "org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder", args, new SubProgressMonitor(monitor, 30)); monitor.worked(20); // // Now rebuild the index by the indexer, taking into account the new paths and // symbols. // // This may take some time, but as we are in a background job this is hopefully // not very noticeable to the user. // ICProject cproj = CoreModel.getDefault().create(project); CCorePlugin.getIndexManager().reindex(cproj); monitor.worked(100); } catch (CoreException e) { Status status = new Status(IStatus.ERROR, AVRPlugin.PLUGIN_ID, "Internal error while trying to run the ScannerConfigBuilder"); //$NON-NLS-1$ AVRPlugin.getDefault().log(status); return status; } finally { monitor.done(); if (!isperconfig) { // Restore the "Build all configurations" preference flag. ACBuilder.setAllConfigBuild(needallflag); } } return Status.OK_STATUS; } }; // now set the Job properties and start it buildJob.setPriority(Job.SHORT); // Could be Job.BUILD, but I think the Scanner builder is // quick enough to not affect the user experience. buildJob.setUser(true); buildJob.setSystem(true); buildJob.schedule(); return buildJob; } }