blob: 84991efc3aafaee95bd77e9da9685595b56df483 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 QNX Software Systems 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
*******************************************************************************/
package org.eclipse.cdt.internal.core.build;
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.cdt.core.build.ICBuildConfiguration;
import org.eclipse.cdt.core.build.ICBuildConfigurationManager;
import org.eclipse.cdt.core.build.ICBuildConfigurationProvider;
import org.eclipse.cdt.internal.core.model.CModelManager;
import org.eclipse.core.resources.IBuildConfiguration;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
public class CBuildConfigurationManager implements ICBuildConfigurationManager, IResourceChangeListener {
private static class Provider {
private String id;
private String natureId;
private IConfigurationElement element;
private ICBuildConfigurationProvider provider;
public Provider(IConfigurationElement element) {
this.id = element.getAttribute("id"); //$NON-NLS-1$
this.natureId = element.getAttribute("natureId"); //$NON-NLS-1$
this.element = element;
}
public String getId() {
return id;
}
public ICBuildConfigurationProvider getProvider() {
if (provider == null) {
try {
provider = (ICBuildConfigurationProvider) element.createExecutableExtension("class"); //$NON-NLS-1$
} catch (CoreException e) {
CCorePlugin.log(e.getStatus());
}
}
return provider;
}
public boolean supports(IProject project) {
try {
if (natureId != null) {
return project.hasNature(natureId);
}
} catch (CoreException e) {
CCorePlugin.log(e.getStatus());
}
return false;
}
}
private Map<String, Provider> providers;
private Map<IBuildConfiguration, ICBuildConfiguration> configs = new HashMap<>();
private Set<IBuildConfiguration> noConfigs = new HashSet<>();
public CBuildConfigurationManager() {
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
}
public void dispose() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
}
private void initProviders() {
if (providers == null) {
providers = new HashMap<>();
IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(CCorePlugin.PLUGIN_ID,
"buildConfigProvider"); //$NON-NLS-1$
for (IConfigurationElement element : point.getConfigurationElements()) {
Provider provider = new Provider(element);
providers.put(provider.getId(), provider);
}
}
}
private Provider getProviderDelegate(String id) {
return providers.get(id);
}
@Override
public ICBuildConfigurationProvider getProvider(String id) {
initProviders();
Provider provider = providers.get(id);
return provider != null ? provider.getProvider() : null;
}
public ICBuildConfigurationProvider getProvider(String id, IProject project) {
initProviders();
Provider provider = getProviderDelegate(id);
if (provider != null && provider.supports(project)) {
return provider.getProvider();
}
return null;
}
public ICBuildConfigurationProvider getProvider(IProject project) throws CoreException {
initProviders();
for (Provider provider : providers.values()) {
if (provider.supports(project)) {
return provider.getProvider();
}
}
return null;
}
@Override
public IBuildConfiguration createBuildConfiguration(ICBuildConfigurationProvider provider,
IProject project, String configName, IProgressMonitor monitor) throws CoreException {
String name = provider.getId() + '/' + configName;
Set<String> names = new HashSet<>();
for (IBuildConfiguration config : project.getBuildConfigs()) {
names.add(config.getName());
}
IProjectDescription desc = project.getDescription();
names.add(name);
desc.setBuildConfigs(names.toArray(new String[names.size()]));
project.setDescription(desc, monitor);
return project.getBuildConfig(name);
}
@Override
public void addBuildConfiguration(IBuildConfiguration buildConfig, ICBuildConfiguration cConfig) {
synchronized (configs) {
configs.put(buildConfig, cConfig);
}
}
@Override
public ICBuildConfiguration getBuildConfiguration(IBuildConfiguration buildConfig) throws CoreException {
initProviders();
synchronized (configs) {
if (noConfigs.contains(buildConfig)) {
return null;
} else {
ICBuildConfiguration config = configs.get(buildConfig);
if (config != null) {
return config;
} else {
String configName;
ICBuildConfigurationProvider provider;
if (IBuildConfiguration.DEFAULT_CONFIG_NAME.equals(buildConfig.getName())) {
configName = ICBuildConfiguration.DEFAULT_NAME;
provider = getProvider(buildConfig.getProject());
} else {
String[] segments = buildConfig.getName().split("/"); //$NON-NLS-1$
if (segments.length == 2) {
String providerId = segments[0];
configName = segments[1];
Provider delegate = getProviderDelegate(providerId);
if (delegate != null && delegate.supports(buildConfig.getProject())) {
provider = delegate.getProvider();
} else {
return null;
}
} else {
// Not ours
return null;
}
}
if (provider != null) {
config = provider.getCBuildConfiguration(buildConfig, configName);
if (config != null) {
configs.put(buildConfig, config);
// Also make sure we reset the binary parser cache for the new config
CModelManager.getDefault().resetBinaryParser(buildConfig.getProject());
return config;
}
}
noConfigs.add(buildConfig);
return null;
}
}
}
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
if (event.getType() == IResourceChangeEvent.PRE_CLOSE
|| event.getType() == IResourceChangeEvent.PRE_DELETE) {
if (event.getResource().getType() == IResource.PROJECT) {
IProject project = event.getResource().getProject();
try {
if (!project.isOpen() || !project.hasNature(CProjectNature.C_NATURE_ID))
return;
} catch (CoreException e) {
CCorePlugin.log(e.getStatus());
return;
}
// Clean up the configMap
try {
for (IBuildConfiguration buildConfig : project.getBuildConfigs()) {
configs.remove(buildConfig);
}
} catch (CoreException e) {
CCorePlugin.log(e);
}
// Clean up the config settings
Preferences parentNode = InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID).node("config"); //$NON-NLS-1$
if (parentNode != null) {
Preferences projectNode = parentNode.node(project.getName());
if (projectNode != null) {
try {
projectNode.removeNode();
parentNode.flush();
} catch (BackingStoreException e) {
CCorePlugin.log(e);
}
}
}
// Clean up the scanner info data
IPath stateLoc = CCorePlugin.getDefault().getStateLocation();
IPath scannerInfoPath = stateLoc.append(project.getName());
Path directory = scannerInfoPath.toFile().toPath();
if (!Files.exists(directory)) {
return;
}
try {
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
CCorePlugin.log(e);
}
}
}
}
}