From 876cf6f4c24433be3c22441379ebe70cf875b10a Mon Sep 17 00:00:00 2001 From: James Blackburn Date: Tue, 16 Feb 2010 12:56:18 +0000 Subject: [PATCH] Bug 302881 Referenced settings are lost on project import --- .../cdt/core/model/tests/AllCoreTests.java | 1 - .../model/AllCProjectDescriptionTests.java | 1 + ...onfigurationDescriptionExportSettings.java | 203 ++++++++++++++++++ .../model/CExternalSettingsManager.java | 16 +- .../CfgExportSettingContainerFactory.java | 41 ++-- 5 files changed, 239 insertions(+), 23 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CConfigurationDescriptionExportSettings.java diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java index f4c36c309be..256939bad12 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/model/tests/AllCoreTests.java @@ -51,7 +51,6 @@ public class AllCoreTests { suite.addTest(MacroTests.suite()); // suite.addTest(FailedMacroTests.suite()); suite.addTest(CPathEntryTest.suite()); -// suite.addTest(CConfigurationDescriptionReferenceTests.suite()); //the CProjectDescriptionTests now groups all New Project Model related tests //which includes the CConfigurationDescriptionReferenceTests suite.addTest(AllCProjectDescriptionTests.suite()); diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java index 14835d9cd96..0d28078b1bf 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/AllCProjectDescriptionTests.java @@ -24,6 +24,7 @@ public class AllCProjectDescriptionTests { // Just add more test cases here as you create them for // each class being tested suite.addTest(CConfigurationDescriptionReferenceTests.suite()); + suite.addTest(CConfigurationDescriptionExportSettings.suite()); suite.addTest(ExternalSettingsProviderTests.suite()); suite.addTest(CfgSettingsTests.suite()); suite.addTest(CProjectDescriptionDeltaTests.suite()); diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CConfigurationDescriptionExportSettings.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CConfigurationDescriptionExportSettings.java new file mode 100644 index 00000000000..49633cd5612 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/settings/model/CConfigurationDescriptionExportSettings.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2010 Broadcom 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: + * James Blackburn (Broadcom Corp.) + *******************************************************************************/ + +package org.eclipse.cdt.core.settings.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestSuite; + +import org.eclipse.cdt.core.internal.errorparsers.tests.ResourceHelper; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.core.resources.IProject; + +/** + * Class for testing exported settings and project references + */ +public class CConfigurationDescriptionExportSettings extends BaseTestCase { + + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + ResourceHelper.cleanUp(); + } + + public static TestSuite suite() { + return suite(CConfigurationDescriptionExportSettings.class, "_"); + } + + /** + * This tests for simple reference propagation. + * It used to live in the Managedbuild testsuite in ProjectModelTests.java + * but is moved here as it doesn't test any managedbuilder specific functionality + */ + public void testReferences() throws Exception { + final String projectName4 = "test4"; + final String projectName5 = "test5"; + CoreModel coreModel = CoreModel.getDefault(); + + IProject project4 = ResourceHelper.createCDTProjectWithConfig(projectName4); + IProject project5 = ResourceHelper.createCDTProjectWithConfig(projectName5); + + ICProjectDescription des4 = coreModel.getProjectDescription(project4); + ICProjectDescription des5 = coreModel.getProjectDescription(project5); + ICConfigurationDescription dess[] = des5.getConfigurations(); + + ICLanguageSettingEntry entries[] = new ICLanguageSettingEntry[]{ + new CMacroEntry("a", "b", 0), + new CMacroEntry("c", "d", 0), + new CIncludePathEntry("a/b/c", 0), + new CIncludePathEntry("d/e/f", 0), + }; + dess[0].createExternalSetting(null, null, null, entries); + dess[0].setActive(); + + ICExternalSetting extSettings[] = dess[0].getExternalSettings(); + assertEquals(extSettings.length, 1); + + checkEquivContents(extSettings[0].getEntries(), entries); + List list = new ArrayList(Arrays.asList(entries)); + list.remove(3); + list.remove(2); + checkEquivContents(extSettings[0].getEntries(ICSettingEntry.MACRO), list.toArray()); + list = new ArrayList(Arrays.asList(entries)); + list.remove(0); + list.remove(0); + checkEquivContents(extSettings[0].getEntries(ICSettingEntry.INCLUDE_PATH), list.toArray()); + coreModel.setProjectDescription(project5, des5); + + extSettings = coreModel.getProjectDescription(project5).getActiveConfiguration().getExternalSettings(); + assertEquals(extSettings.length, 1); + + checkEquivContents(extSettings[0].getEntries(), entries); + list = new ArrayList(Arrays.asList(entries)); + list.remove(3); + list.remove(2); + checkEquivContents(extSettings[0].getEntries(ICSettingEntry.MACRO), list.toArray()); + list = new ArrayList(Arrays.asList(entries)); + list.remove(0); + list.remove(0); + checkEquivContents(extSettings[0].getEntries(ICSettingEntry.INCLUDE_PATH), list.toArray()); + + dess = des4.getConfigurations(); + ICLanguageSetting ls = dess[0].getRootFolderDescription().getLanguageSettingForFile("a.c"); + ICLanguageSettingEntry macros[] = ls.getSettingEntries(ICSettingEntry.MACRO); + ICLanguageSettingEntry includes[] = ls.getSettingEntries(ICSettingEntry.INCLUDE_PATH); + assertFalse(Arrays.asList(macros).contains(entries[0])); + assertFalse(Arrays.asList(macros).contains(entries[1])); + assertFalse(Arrays.asList(includes).contains(entries[2])); + assertFalse(Arrays.asList(includes).contains(entries[3])); + Map map = new HashMap(); + map.put(projectName5, ""); + dess[0].setReferenceInfo(map); + ICLanguageSettingEntry updatedMacros[] = ls.getSettingEntries(ICSettingEntry.MACRO); + ICLanguageSettingEntry udatedIncludes[] = ls.getSettingEntries(ICSettingEntry.INCLUDE_PATH); + assertTrue(Arrays.asList(updatedMacros).contains(entries[0])); + assertTrue(Arrays.asList(updatedMacros).contains(entries[1])); + assertTrue(Arrays.asList(udatedIncludes).contains(entries[2])); + assertTrue(Arrays.asList(udatedIncludes).contains(entries[3])); + } + + /** + * This tests importing projects with references works even if the projects are + * imported in opposite order + * @throws Exception + */ + public void testProjectImport() throws Exception { + CoreModel coreModel = CoreModel.getDefault(); + final IProject libProj = ResourceHelper.createCDTProjectWithConfig("libProj"); + final IProject mainProj = ResourceHelper.createCDTProjectWithConfig("mainProj"); + + // Settings to set on the lib project + final ICLanguageSettingEntry entries[] = new ICLanguageSettingEntry[]{ + new CMacroEntry("a", "b", 0), + new CMacroEntry("c", "d", 0), + new CIncludePathEntry("a/b/c", 0), + new CIncludePathEntry("d/e/f", 0), + }; + + // set the settings on the lib config; reference it from the main config + { + ICProjectDescription desLib = coreModel.getProjectDescription(libProj); + ICProjectDescription desMain = coreModel.getProjectDescription(mainProj); + ICConfigurationDescription cfgLib = desLib.getActiveConfiguration(); + ICConfigurationDescription cfgMain = desMain.getActiveConfiguration(); + + cfgLib.createExternalSetting(null, null, null, entries); + coreModel.setProjectDescription(libProj, desLib); + + // Main Project references lib project + cfgMain.setReferenceInfo(new HashMap() {{ put(libProj.getName(), ""); }}); + coreModel.setProjectDescription(mainProj, desMain); + + // Referenced settings have been picked up + for (ICLanguageSettingEntry e : entries) { + assertTrue(cfgMain.getRootFolderDescription().getLanguageSettingForFile("a.c"). + getSettingEntriesList(e.getKind()).contains(e)); + } + } + + // Now delete the two projects, import main first + // then lib and check we're A-Ok + libProj.delete(false, false, null); + mainProj.delete(false, false, null); + + // project description obviously no longer eixsts + assertNull(coreModel.getProjectDescription(mainProj)); + assertNull(coreModel.getProjectDescription(libProj)); + + // Re-import the main project first + mainProj.create(null); + mainProj.open(null); + + // Now re-open the lib project + assertFalse(libProj.exists()); + libProj.create(null); + libProj.open(null); + + // Referenced settings should still exist + ICConfigurationDescription cfgMain = coreModel.getProjectDescription(mainProj).getActiveConfiguration(); + ICConfigurationDescription cfgLib = coreModel.getProjectDescription(libProj).getActiveConfiguration(); + + checkEquivContents(cfgLib.getExternalSettings()[0].getEntries(), entries); + for (ICLanguageSettingEntry e : entries) { + assertTrue(cfgMain.getRootFolderDescription().getLanguageSettingForFile("a.c"). + getSettingEntriesList(e.getKind()).contains(e)); + } + } + + private void checkEquivContents(Object[] a1, Object[] a2) { + if(a1 == null){ + assertTrue(a2 == null); + return; + } + assertTrue(a2 != null); + assertEquals(a1.length, a2.length); + + Set s1 = new HashSet(Arrays.asList(a1)); + Set s2 = new HashSet(Arrays.asList(a2)); + assertEquals(a1.length, s1.size()); + assertEquals(s1, s2); + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CExternalSettingsManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CExternalSettingsManager.java index 7b38a02b68a..96dc8ed3c3e 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CExternalSettingsManager.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CExternalSettingsManager.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Intel Corporation and others. + * 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 @@ -156,6 +156,7 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP try { fContainer = fFactoryDr.getFactory().createContainer(containerId, project, cfgDes, previousSettings); } catch (CoreException e) { + CCorePlugin.log(e); } if(fContainer == null) fContainer = NullContainer.INSTANCE; @@ -183,7 +184,10 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP // return fContainer; // } } - + + /** + * A dummy SettingsContainer with 0 CExternalSettings + */ static class NullContainer extends CExternalSettingsContainer { static final NullContainer INSTANCE = new NullContainer(); @@ -515,7 +519,7 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP }; - CProjectDescriptionManager.getInstance().runWspModification(r, new NullProgressMonitor()); + CProjectDescriptionManager.runWspModification(r, new NullProgressMonitor()); } } @@ -696,7 +700,7 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP } }; - CProjectDescriptionManager.getInstance().runWspModification(r, null); + CProjectDescriptionManager.runWspModification(r, null); } break; } @@ -786,12 +790,12 @@ public class CExternalSettingsManager implements ICExternalSettingsListener, ICP return deltas; } - private ExtSettingsDelta[] reconsile(IProject proj, ICConfigurationDescription cfgDes, boolean add, HolderContainer hCr, CContainerRef cr){ + private ExtSettingsDelta[] reconsile(IProject proj, ICConfigurationDescription cfgDes, boolean addOrChange, HolderContainer hCr, CContainerRef cr){ // if(holder.isReconsiled()) // return; CExternalSetting[] newSettings = null; CExternalSetting[] oldSettings = hCr.getHolder(false).getExternalSettings(); - if(add){ + if (addOrChange) { ContainerDescriptor cdr = createDescriptor(cr.getFactoryId(), cr.getContainerId(), proj, cfgDes, oldSettings); newSettings = cdr.getExternalSettings(); } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgExportSettingContainerFactory.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgExportSettingContainerFactory.java index 5331fd8fabc..a41b589951c 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgExportSettingContainerFactory.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/settings/model/CfgExportSettingContainerFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Intel Corporation and others. + * 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 @@ -27,7 +27,6 @@ import org.eclipse.cdt.core.settings.model.ICExternalSetting; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener; import org.eclipse.cdt.internal.core.settings.model.CExternalSettingsManager.CContainerRef; -import org.eclipse.cdt.internal.core.settings.model.CExternalSettingsManager.NullContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -67,18 +66,24 @@ public class CfgExportSettingContainerFactory extends CProjectDescriptionManager.getInstance().removeCProjectDescriptionListener(this); } + /** + * An ExternalSettingsContainer which returns the settings as + * exported by a referenced configuration in another project. + */ private static class CfgRefContainer extends CExternalSettingsContainer { - private String fProjName, fCfgId; + final private String fProjName, fCfgId; + final private CExternalSetting[] prevSettings; - CfgRefContainer(String projName, String cfgId){ + CfgRefContainer(String projName, String cfgId, CExternalSetting[] previousSettings){ fProjName = projName; fCfgId = cfgId; + prevSettings = previousSettings; } @Override public CExternalSetting[] getExternalSettings() { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(fProjName); - if(project.exists() && project.isOpen()){ + if (project.isAccessible()) { ICProjectDescription des = CProjectDescriptionManager.getInstance().getProjectDescription(project, false); if(des != null){ ICConfigurationDescription cfg = fCfgId.length() != 0 ? @@ -93,24 +98,22 @@ public class CfgExportSettingContainerFactory extends return es; } } + } else { + // If project doesn't not open in this workspace, just return the previous settings + // for the moment. We'll update again when the referenced project reappears + return prevSettings; } return new CExternalSetting[0]; } - } - + @Override public CExternalSettingsContainer createContainer(String id, - IProject project, ICConfigurationDescription cfgDes, CExternalSetting[] previousSettings) { - try { - String[] r = parseId(id); - return new CfgRefContainer(r[0], r[1]); - } catch (CoreException e) { - CCorePlugin.log(e); - } - return new NullContainer(); + IProject project, ICConfigurationDescription cfgDes, CExternalSetting[] previousSettings) throws CoreException { + String[] r = parseId(id); + return new CfgRefContainer(r[0], r[1], previousSettings); } - + private static void createReference(ICConfigurationDescription cfg, String projName, String cfgId){ CContainerRef cr = createContainerRef(projName, cfgId); CExternalSettingsManager.getInstance().addContainer(cfg, cr); @@ -178,6 +181,12 @@ public class CfgExportSettingContainerFactory extends private static String createId(String projName, String cfgId){ return projName + DELIMITER + cfgId; } + /** + * Return a 2-element array String[]{projName, cfgId} + * @param id id to parse, must not be null + * @return String[]{projName, cfgId} + * @throws CoreException if prjName not valid + */ private static String[] parseId(String id) throws CoreException { if(id == null) throw new NullPointerException();