mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-01 06:05:24 +02:00
Bug 312575 Updating a .cproject doesn't update settings in referencing projects. Patch 3 + JavaDoc
This commit is contained in:
parent
36e5cb1427
commit
ba5001ebc1
7 changed files with 156 additions and 66 deletions
|
@ -299,7 +299,7 @@ public class CConfigurationDescriptionExportSettings extends BaseTestCase {
|
|||
* causes referencing projects to correctly pick up changes to the project exports.
|
||||
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=312575
|
||||
*/
|
||||
public void _testExportedSettingsExternalUpdate() throws Exception {
|
||||
public void testExportedSettingsExternalUpdate() throws Exception {
|
||||
final IProject libProj = ResourceHelper.createCDTProjectWithConfig("libProj312575");
|
||||
final IProject mainProj = ResourceHelper.createCDTProjectWithConfig("mainProj312575");
|
||||
|
||||
|
|
|
@ -22,7 +22,11 @@ import org.eclipse.cdt.core.settings.model.ICSettingEntry;
|
|||
import org.eclipse.cdt.core.settings.model.ICStorageElement;
|
||||
import org.eclipse.cdt.internal.core.settings.model.CExternalSettinsDeltaCalculator.ExtSettingMapKey;
|
||||
|
||||
/**
|
||||
* The raw external settings as exported by a project configuration.
|
||||
*/
|
||||
public class CExternalSettingsHolder extends CExternalSettingsContainer {
|
||||
|
||||
private Map<ExtSettingMapKey, CExternalSetting> fSettingsMap;
|
||||
static final String ELEMENT_EXT_SETTINGS_CONTAINER = "externalSettings"; //$NON-NLS-1$
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.settings.model.CExternalSetting;
|
||||
import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent;
|
||||
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
|
||||
|
@ -73,9 +74,14 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP
|
|||
return fInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class representing an external settings container.
|
||||
* These are uniquely identifiable by the factoryId + factory
|
||||
* specific container id
|
||||
*/
|
||||
public final static class CContainerRef {
|
||||
private String fFactoryId;
|
||||
private String fContainerId;
|
||||
private final String fFactoryId;
|
||||
private final String fContainerId;
|
||||
|
||||
public CContainerRef(String factoryId, String containerId){
|
||||
fFactoryId = factoryId;
|
||||
|
@ -351,16 +357,25 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP
|
|||
return dr.getFactory();
|
||||
}
|
||||
|
||||
public void settingsChanged(IProject project, String cfgId,
|
||||
CExternalSettingChangeEvent event) {
|
||||
/**
|
||||
* External settings call-back from the setting container factories
|
||||
* to notify that settings have changed in a container.
|
||||
*
|
||||
* Schedules a runnable to update any referencing projects
|
||||
*/
|
||||
public void settingsChanged(final IProject project, final String cfgId, final CExternalSettingChangeEvent event) {
|
||||
// Modifying the project description in an asynchronous runnable is likely bad...
|
||||
// Unfortunately there's nothing else we can do as it's not safe to modify the referencing configurations in place
|
||||
IWorkspaceRunnable r = new IWorkspaceRunnable() {
|
||||
public void run(IProgressMonitor monitor) throws CoreException {
|
||||
ProjDesCfgList[] lists = null;
|
||||
CExternalSettingsContainerChangeInfo[] infos = event.getChangeInfos();
|
||||
for (CExternalSettingsContainerChangeInfo info : infos) {
|
||||
for (CExternalSettingsContainerChangeInfo info : event.getChangeInfos()) {
|
||||
switch(info.getEventType()){
|
||||
case CExternalSettingsContainerChangeInfo.CHANGED:
|
||||
int flags = info.getChangeFlags();
|
||||
if((flags & CExternalSettingsContainerChangeInfo.CONTAINER_CONTENTS) != 0){
|
||||
if(lists == null)
|
||||
// Potentially all configuration in all projects need to be considered for be
|
||||
lists = createCfgListsForEvent(project, cfgId);
|
||||
for (ProjDesCfgList list : lists) {
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
|
@ -372,24 +387,19 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO modifying the project description in an asynchronous runnable is likely bad...
|
||||
if(lists != null) {
|
||||
if (lists != null) {
|
||||
final List<ICProjectDescription> list = getModifiedProjDesList(lists);
|
||||
if(list.size() != 0){
|
||||
IWorkspaceRunnable r = new IWorkspaceRunnable(){
|
||||
|
||||
public void run(IProgressMonitor monitor) throws CoreException {
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
if(list.size() != 0) {
|
||||
for(int i = 0; i < list.size(); i++) {
|
||||
ICProjectDescription des = list.get(i);
|
||||
CProjectDescriptionManager.getInstance().setProjectDescription(des.getProject(), des, false, monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
CProjectDescriptionManager.runWspModification(r, new NullProgressMonitor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<ICProjectDescription> getModifiedProjDesList(ProjDesCfgList[] lists){
|
||||
List<ICProjectDescription> list = new ArrayList<ICProjectDescription>();
|
||||
|
@ -507,6 +517,12 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to Project Description events.
|
||||
* - DATA_APPLIED: Data has been applied, and the description is still
|
||||
* writable, store cached external settings into the configuration
|
||||
* - LOADED: Check whether a reconcile is needed and update the settings atomically
|
||||
*/
|
||||
public void handleEvent(CProjectDescriptionEvent event) {
|
||||
switch(event.getEventType()){
|
||||
case CProjectDescriptionEvent.DATA_APPLIED: {
|
||||
|
@ -522,11 +538,18 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP
|
|||
store(cfg, cr.fRefInfo);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CProjectDescriptionEvent.LOADED:
|
||||
ProjDesCfgList list = new ProjDesCfgList(event.getNewCProjectDescription(), null);
|
||||
// Note using an asynchronous get / set here is bad.
|
||||
// Unfortunately there's no other way to make this work without re-writing the project model to allow
|
||||
// us to reconcile / update the cached configuration during load
|
||||
final IProject project = event.getProject();
|
||||
IWorkspaceRunnable r = new IWorkspaceRunnable(){
|
||||
public void run(IProgressMonitor monitor) throws CoreException {
|
||||
if (!project.isAccessible())
|
||||
return;
|
||||
ProjDesCfgList list = new ProjDesCfgList(CoreModel.getDefault().getProjectDescription(project), null);
|
||||
boolean changed = false;
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
CfgListCfgContainer cfgCr = new CfgListCfgContainer(list, i);
|
||||
|
@ -537,18 +560,11 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
// TODO firing an asynchronous setProjectDescription here is likely to lead to trouble...
|
||||
final ICProjectDescription prjDesc = list.fProjDes;
|
||||
if(changed){
|
||||
IWorkspaceRunnable r = new IWorkspaceRunnable(){
|
||||
|
||||
public void run(IProgressMonitor monitor) throws CoreException {
|
||||
CProjectDescriptionManager.getInstance().setProjectDescription(prjDesc.getProject(), prjDesc);
|
||||
if (changed)
|
||||
CProjectDescriptionManager.getInstance().setProjectDescription(project, list.fProjDes);
|
||||
}
|
||||
|
||||
};
|
||||
CProjectDescriptionManager.runWspModification(r, null);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,15 +13,61 @@ package org.eclipse.cdt.internal.core.settings.model;
|
|||
import org.eclipse.cdt.core.settings.model.ICStorageElement;
|
||||
import org.eclipse.cdt.internal.core.settings.model.CExternalSettingsManager.CContainerRef;
|
||||
|
||||
/**
|
||||
* This class, derived from CExternalSettingsHolder, is used to cache the
|
||||
* external settings exported by some container.
|
||||
*
|
||||
* <p> External settings have two sides. The external settings exporter (represented
|
||||
* by a pure CExternalSettingsHolder) and the settings referencer referenced by this class.
|
||||
* The CRefSettingsHolder holds a cache of the settings exports by the settings holder
|
||||
*
|
||||
* <p>Concretely, in the .cproject you might have:
|
||||
*
|
||||
* <p> In the exporting config:
|
||||
* <code>
|
||||
* <br/><cconfiguration ...
|
||||
* <br/> <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="..." moduleId="org.eclipse.cdt.core.settings" name="Debug">
|
||||
* <br/> <externalSettings>
|
||||
* <br/> <externalSetting>
|
||||
* <br/> <entry flags="" kind="includePath" name="libProj"/>
|
||||
* <br/> </externalSetting>
|
||||
* <br/> </externalSettings>
|
||||
*
|
||||
* </code>
|
||||
*
|
||||
* <p>In the referencing project:
|
||||
*
|
||||
* <code>
|
||||
* <br/><configuration ... >
|
||||
* <br/><storageModule moduleId="org.eclipse.cdt.core.externalSettings">
|
||||
* <br/> <externalSettings containerId="libProj;" factoryId="org.eclipse.cdt.core.cfg.export.settings.sipplier">
|
||||
* <br/> <externalSetting>
|
||||
* <br/> <entry flags="" kind="includePath" name="libProj"/>
|
||||
* <br/> </externalSetting>
|
||||
* <br/> </externalSettings>
|
||||
* <br/></storageModule>
|
||||
* </code>
|
||||
*/
|
||||
public class CRefSettingsHolder extends CExternalSettingsHolder {
|
||||
|
||||
/**
|
||||
* The factory responsible for the setting.
|
||||
* One of
|
||||
* <ul>
|
||||
* <li> {@link CfgExportSettingContainerFactory#FACTORY_ID} </li>
|
||||
* <li> {@link ExtensionContainerFactory#FACTORY_ID} </lid
|
||||
* </ul>
|
||||
*/
|
||||
private static final String ATTR_FACTORY_ID = "factoryId"; //$NON-NLS-1$
|
||||
/** Factory specific containerId used to resolve the settings container */
|
||||
private static final String ATTR_CONTAINER_ID = "containerId"; //$NON-NLS-1$
|
||||
private CContainerRef fContainerRef;
|
||||
|
||||
/** The container we get settings from */
|
||||
private final CContainerRef fContainerRef;
|
||||
private boolean fIsReconsiled;
|
||||
|
||||
public CRefSettingsHolder(CContainerRef ref) {
|
||||
super();
|
||||
|
||||
fContainerRef = ref;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,9 @@ import org.eclipse.cdt.core.settings.model.util.EntryNameKey;
|
|||
import org.eclipse.cdt.internal.core.settings.model.CExternalSettingsManager.CContainerRef;
|
||||
|
||||
class CSettingsRefInfo {
|
||||
final static String ELEMENT_REFERENCE_INFO = "referenceInfo"; //$NON-NLS-1$
|
||||
/** External Settings Holder Map */
|
||||
|
||||
/** External Settings Holder Map
|
||||
* From references container -> to concrete held settings */
|
||||
private HashMap<CContainerRef, CRefSettingsHolder> fESHolderMap = new LinkedHashMap<CContainerRef, CRefSettingsHolder>();
|
||||
|
||||
CSettingsRefInfo(){
|
||||
|
|
|
@ -212,12 +212,31 @@ public class CfgExportSettingContainerFactory extends
|
|||
}
|
||||
|
||||
/**
|
||||
* Notify the ExternalSettingManager that there's been a change in the configurations mapped by this external settings provider
|
||||
* (as a result of a proejct configuration change)
|
||||
* Notify the ExternalSettingManager that there's been a change in the configuration which may require referencing configs to update
|
||||
* their cache of the external settings
|
||||
*/
|
||||
public void handleEvent(CProjectDescriptionEvent event) {
|
||||
switch(event.getEventType()){
|
||||
case CProjectDescriptionEvent.LOADED:
|
||||
case CProjectDescriptionEvent.LOADED: {
|
||||
// Bug 312575 on Project load, event.getProjectDelta() == null => report all configs as potentially changed
|
||||
// Referencing projects should be reconciled and potentially updated.
|
||||
String projName = event.getProject().getName();
|
||||
ICConfigurationDescription[] descs = event.getNewCProjectDescription().getConfigurations();
|
||||
CExternalSettingsContainerChangeInfo[] changeInfos = new CExternalSettingsContainerChangeInfo[descs.length + 1];
|
||||
int i = 0;
|
||||
for (ICConfigurationDescription desc : event.getNewCProjectDescription().getConfigurations())
|
||||
changeInfos[i++] = new CExternalSettingsContainerChangeInfo(
|
||||
CExternalSettingsContainerChangeInfo.CONTAINER_CONTENTS,
|
||||
new CContainerRef(FACTORY_ID, createId(projName, desc.getId())),
|
||||
null);
|
||||
// Active configuration too
|
||||
changeInfos[i] = new CExternalSettingsContainerChangeInfo(
|
||||
CExternalSettingsContainerChangeInfo.CONTAINER_CONTENTS,
|
||||
new CContainerRef(FACTORY_ID, createId(projName, ACTIVE_CONFIG_ID)),
|
||||
null);
|
||||
notifySettingsChange(null, null, changeInfos);
|
||||
break;
|
||||
}
|
||||
case CProjectDescriptionEvent.APPLIED:
|
||||
String[] ids = getContainerIds(event.getProjectDelta());
|
||||
if(ids.length != 0){
|
||||
|
|
|
@ -18,8 +18,12 @@ import org.eclipse.core.resources.IProject;
|
|||
public interface ICExternalSettingsListener {
|
||||
|
||||
/**
|
||||
* Notifies the listener that the configuration with id cfgId has changed in the project
|
||||
* project.
|
||||
* Notifies the listener that external settings in a particular container have changed.
|
||||
* The CExternalSettingsManager will try to reconcile changes into the project + config
|
||||
* specified by the call-back. If these are null (which they currently always are)
|
||||
* the external settings manager will check all projects and configurations to see
|
||||
* if there are any referencing configs which need reconciling.
|
||||
*
|
||||
* @param project or null indicating all projects should be considered
|
||||
* @param cfgId or null indicating all configurations should be considered
|
||||
* @param event CExternalSettingsChangeEvent
|
||||
|
|
Loading…
Add table
Reference in a new issue