Browse Source

Reimplemented project configuration management.

pull/32/merge
Daniel Grunwald 13 years ago
parent
commit
6e08cfe87e
  1. 2
      SharpDevelop.Tests.sln
  2. 3
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/WebProjectTests.cs
  3. 20
      src/AddIns/BackendBindings/WixBinding/Test/Project/CreateNewWixProjectObjectTestFixture.cs
  4. 2
      src/Main/Base/Project/ICSharpCode.SharpDevelop.addin
  5. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  6. 2
      src/Main/Base/Project/Project/Build/ProjectBuildOptions.cs
  7. 2
      src/Main/Base/Project/Project/Configuration/ConfigurationAndPlatform.cs
  8. 2
      src/Main/Base/Project/Src/Project/CompilableProject.cs
  9. 309
      src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
  10. 250
      src/Main/Base/Project/Src/Project/MSBuildConfigurationOrPlatformNameCollection.cs
  11. 5
      src/Main/Base/Project/Src/Project/MSBuildInternals.cs
  12. 2
      src/Main/SharpDevelop/Project/Configuration/EditAvailableConfigurationsDialog.cs

2
SharpDevelop.Tests.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 5.0
# SharpDevelop 4.3
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject
EndProjectSection

3
src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/WebProjectTests.cs

@ -55,7 +55,8 @@ namespace AspNet.Mvc.Tests @@ -55,7 +55,8 @@ namespace AspNet.Mvc.Tests
{
var fileContentsBuilder = new StringBuilder();
var stringWriter = new StringWriter(fileContentsBuilder);
msbuildProject.MSBuildProjectFile.Save(stringWriter);
lock (msbuildProject.SyncRoot)
msbuildProject.MSBuildProjectFile.Save(stringWriter);
return GetProjectExtensions(fileContentsBuilder.ToString());
}

20
src/AddIns/BackendBindings/WixBinding/Test/Project/CreateNewWixProjectObjectTestFixture.cs

@ -129,10 +129,12 @@ namespace WixBinding.Tests.Project @@ -129,10 +129,12 @@ namespace WixBinding.Tests.Project
/// </summary>
ProjectPropertyElement GetMSBuildProperty(string name)
{
foreach (ProjectPropertyGroupElement propertyGroup in project.MSBuildProjectFile.PropertyGroups) {
foreach (ProjectPropertyElement element in propertyGroup.Properties) {
if (element.Name == name) {
return element;
lock (project.SyncRoot) {
foreach (ProjectPropertyGroupElement propertyGroup in project.MSBuildProjectFile.PropertyGroups) {
foreach (ProjectPropertyElement element in propertyGroup.Properties) {
if (element.Name == name) {
return element;
}
}
}
}
@ -145,10 +147,12 @@ namespace WixBinding.Tests.Project @@ -145,10 +147,12 @@ namespace WixBinding.Tests.Project
ProjectPropertyElement GetLastMSBuildProperty(string name)
{
ProjectPropertyElement matchedElement = null;
foreach (ProjectPropertyGroupElement propertyGroup in project.MSBuildProjectFile.PropertyGroups) {
foreach (ProjectPropertyElement element in propertyGroup.Properties) {
if (element.Name == name) {
matchedElement = element;
lock (project.SyncRoot) {
foreach (ProjectPropertyGroupElement propertyGroup in project.MSBuildProjectFile.PropertyGroups) {
foreach (ProjectPropertyElement element in propertyGroup.Properties) {
if (element.Name == name) {
matchedElement = element;
}
}
}
}

2
src/Main/Base/Project/ICSharpCode.SharpDevelop.addin

@ -80,6 +80,8 @@ @@ -80,6 +80,8 @@
class="ICSharpCode.SharpDevelop.Project.MSBuildEngine"/>
<Service id="ICSharpCode.SharpDevelop.Editor.Bookmarks.IBookmarkManager"
class="ICSharpCode.SharpDevelop.Editor.Bookmarks.BookmarkManager"/>
<Service id="ICSharpCode.SharpDevelop.IUIService"
class="ICSharpCode.SharpDevelop.UIService"/>
<Service id="ICSharpCode.SharpDevelop.WinForms.IWinFormsService"
class="ICSharpCode.SharpDevelop.WinForms.WinFormsService"/>

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -233,6 +233,7 @@ @@ -233,6 +233,7 @@
<DependentUpon>OutputWindowOptionsPanel.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Src\Project\MSBuildConfigurationOrPlatformNameCollection.cs" />
<Compile Include="Util\AtomicBoolean.cs" />
<Compile Include="Util\ComparerExtensions.cs" />
<Compile Include="Util\CustomThreadPoolTaskScheduler.cs" />

2
src/Main/Base/Project/Project/Build/ProjectBuildOptions.cs

@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Project
public class ProjectBuildOptions
{
BuildTarget target;
IDictionary<string, string> properties = new SortedList<string, string>();
IDictionary<string, string> properties = new SortedList<string, string>(MSBuildInternals.PropertyNameComparer);
public BuildTarget Target {
get { return target; }

2
src/Main/Base/Project/Project/Configuration/ConfigurationAndPlatform.cs

@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -12,7 +12,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
public struct ConfigurationAndPlatform : IEquatable<ConfigurationAndPlatform>
{
public static readonly StringComparer ConfigurationNameComparer = StringComparer.Ordinal;
public static readonly StringComparer ConfigurationNameComparer = StringComparer.OrdinalIgnoreCase;
public static bool IsValidName(string name)
{

2
src/Main/Base/Project/Src/Project/CompilableProject.cs

@ -84,7 +84,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -84,7 +84,7 @@ namespace ICSharpCode.SharpDevelop.Project
PropertyStorageLocations.ConfigurationSpecific, true);
SetProperty("Release", null, "OutputPath", @"bin\Release\",
PropertyStorageLocations.ConfigurationSpecific, true);
InvalidateConfigurationPlatformNames();
LoadConfigurationPlatformNamesFromMSBuild();
SetProperty("Debug", null, "DebugSymbols", "True",
PropertyStorageLocations.ConfigurationSpecific, true);

309
src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs

@ -3,7 +3,6 @@ @@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@ -13,16 +12,14 @@ using System.Threading; @@ -13,16 +12,14 @@ using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using ICSharpCode.Core;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.SharpDevelop.Internal.Templates;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Exceptions;
using MSBuild = Microsoft.Build.Evaluation;
using StringPair = System.Tuple<string, string>;
namespace ICSharpCode.SharpDevelop.Project
{
@ -57,7 +54,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -57,7 +54,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// Use this for properties that could reference other properties, e.g.
/// PostBuildEvent references OutputPath.
/// </summary>
protected readonly ISet<string> saveAfterImportsProperties = new SortedSet<string> {
protected readonly ISet<string> saveAfterImportsProperties = new SortedSet<string>(MSBuildInternals.PropertyNameComparer) {
"PostBuildEvent",
"PreBuildEvent"
};
@ -85,6 +82,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -85,6 +82,7 @@ namespace ICSharpCode.SharpDevelop.Project
get {
if (projectFile == null)
throw new ObjectDisposedException("MSBuildBasedProject");
Debug.Assert(Monitor.IsEntered(SyncRoot));
return projectFile;
}
}
@ -98,6 +96,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -98,6 +96,7 @@ namespace ICSharpCode.SharpDevelop.Project
get {
if (projectFile == null)
throw new ObjectDisposedException("MSBuildBasedProject");
Debug.Assert(Monitor.IsEntered(SyncRoot));
return userProjectFile;
}
}
@ -161,6 +160,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -161,6 +160,8 @@ namespace ICSharpCode.SharpDevelop.Project
: base(information)
{
this.itemsCollection = new ProjectItemCollection(this);
this.configurationNames = new MSBuildConfigurationOrPlatformNameCollection(this, false);
this.platformNames = new MSBuildConfigurationOrPlatformNameCollection(this, true);
this.projectFile = ProjectRootElement.Create(MSBuildProjectCollection);
this.userProjectFile = ProjectRootElement.Create(MSBuildProjectCollection);
@ -174,10 +175,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -174,10 +175,11 @@ namespace ICSharpCode.SharpDevelop.Project
AddGuardedProperty("Platform", information.ActiveProjectConfiguration.Platform);
string platform = information.ActiveProjectConfiguration.Platform;
if (platform == "x86")
if (ConfigurationAndPlatform.ConfigurationNameComparer.Equals(platform, "x86"))
SetProperty(null, platform, "PlatformTarget", "x86", PropertyStorageLocations.PlatformSpecific, false);
else
SetProperty(null, platform, "PlatformTarget", "AnyCPU", PropertyStorageLocations.PlatformSpecific, false);
LoadConfigurationPlatformNamesFromMSBuild();
}
/// <summary>
@ -391,7 +393,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -391,7 +393,7 @@ namespace ICSharpCode.SharpDevelop.Project
if (platform == null)
platform = this.ActiveConfiguration.Platform;
bool openCurrentConfiguration = configuration == this.ActiveConfiguration.Configuration && platform == this.ActiveConfiguration.Platform;
bool openCurrentConfiguration = new ConfigurationAndPlatform(configuration, platform) == this.ActiveConfiguration;
if (currentlyOpenProject != null && openCurrentConfiguration) {
// use currently open project
@ -399,7 +401,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -399,7 +401,7 @@ namespace ICSharpCode.SharpDevelop.Project
return new ConfiguredProject(this, currentlyOpenProject, false);
}
Dictionary<string, string> globalProps = new Dictionary<string, string>();
Dictionary<string, string> globalProps = new Dictionary<string, string>(MSBuildInternals.PropertyNameComparer);
var msbuildEngine = SD.Services.GetService<IMSBuildEngine>();
if (msbuildEngine != null)
globalProps.AddRange(msbuildEngine.GlobalBuildProperties);
@ -534,8 +536,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -534,8 +536,9 @@ namespace ICSharpCode.SharpDevelop.Project
var configFromCondition = ConfigurationAndPlatform.FromCondition(g.Condition);
string gConfiguration = configFromCondition.Configuration;
string gPlatform = configFromCondition.Platform;
if ((configuration == null || configuration == gConfiguration || gConfiguration == null)
&& (platform == null || platform == gPlatform || gPlatform == null))
StringComparer comparer = ConfigurationAndPlatform.ConfigurationNameComparer;
if ((configuration == null || comparer.Equals(configuration, gConfiguration) || gConfiguration == null)
&& (platform == null || comparer.Equals(platform, gPlatform) || gPlatform == null))
{
if (gConfiguration == null && gPlatform == null) {
location = PropertyStorageLocations.Base;
@ -597,12 +600,12 @@ namespace ICSharpCode.SharpDevelop.Project @@ -597,12 +600,12 @@ namespace ICSharpCode.SharpDevelop.Project
PropertyStorageLocations FindExistingPropertyInAllConfigurations(string propertyName)
{
foreach (var g in projectFile.PropertyGroups) {
if (g.Properties.Any(p => MSBuildInternals.PropertyNameComparer.Equals(p.Name == propertyName))) {
if (g.Properties.Any(p => MSBuildInternals.PropertyNameComparer.Equals(p.Name, propertyName))) {
return MSBuildInternals.GetLocationFromCondition(g.Condition);
}
}
foreach (var g in userProjectFile.PropertyGroups) {
if (g.Properties.Any(p => MSBuildInternals.PropertyNameComparer.Equals(p.Name == propertyName))) {
if (g.Properties.Any(p => MSBuildInternals.PropertyNameComparer.Equals(p.Name, propertyName))) {
return MSBuildInternals.GetLocationFromCondition(g.Condition)
| PropertyStorageLocations.UserFile;
}
@ -713,7 +716,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -713,7 +716,7 @@ namespace ICSharpCode.SharpDevelop.Project
break;
case PropertyStorageLocations.ConfigurationSpecific:
// Get any value usable as existing property value (once per configuration)
Dictionary<string, string> oldValuesConf = new Dictionary<string, string>();
Dictionary<string, string> oldValuesConf = new Dictionary<string, string>(ConfigurationAndPlatform.ConfigurationNameComparer);
foreach (string conf in this.ConfigurationNames) {
oldValuesConf[conf] = GetAnyUnevaluatedPropertyValue(conf, null, propertyName);
}
@ -733,7 +736,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -733,7 +736,7 @@ namespace ICSharpCode.SharpDevelop.Project
break;
case PropertyStorageLocations.PlatformSpecific:
// Get any value usable as existing property value (once per platform)
Dictionary<string, string> oldValuesPlat = new Dictionary<string, string>();
Dictionary<string, string> oldValuesPlat = new Dictionary<string, string>(ConfigurationAndPlatform.ConfigurationNameComparer);
foreach (string plat in this.PlatformNames) {
oldValuesPlat[plat] = GetAnyUnevaluatedPropertyValue(null, plat, propertyName);
}
@ -753,10 +756,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -753,10 +756,10 @@ namespace ICSharpCode.SharpDevelop.Project
break;
case PropertyStorageLocations.ConfigurationAndPlatformSpecific:
// Get any value usable as existing property value (once per configuration+platform)
Dictionary<StringPair, string> oldValues = new Dictionary<StringPair, string>();
Dictionary<ConfigurationAndPlatform, string> oldValues = new Dictionary<ConfigurationAndPlatform, string>();
foreach (string conf in this.ConfigurationNames) {
foreach (string plat in this.PlatformNames) {
oldValues[new StringPair(conf, plat)] = GetAnyUnevaluatedPropertyValue(conf, plat, propertyName);
oldValues[new ConfigurationAndPlatform(conf, plat)] = GetAnyUnevaluatedPropertyValue(conf, plat, propertyName);
}
}
@ -764,10 +767,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -764,10 +767,10 @@ namespace ICSharpCode.SharpDevelop.Project
RemovePropertyCompletely(propertyName);
// Recreate the property using the saved value
foreach (KeyValuePair<StringPair, string> pair in oldValues) {
foreach (KeyValuePair<ConfigurationAndPlatform, string> pair in oldValues) {
if (pair.Value != null) {
MSBuildSetProperty(targetProject, propertyName, pair.Value,
ConfigurationAndPlatform.CreateCondition(pair.Key.Item1, pair.Key.Item2, location),
ConfigurationAndPlatform.CreateCondition(pair.Key.Configuration, pair.Key.Platform, location),
propertyInsertionPosition,
false);
}
@ -1087,7 +1090,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1087,7 +1090,7 @@ namespace ICSharpCode.SharpDevelop.Project
itemsReadOnly = null; // remove readonly variant of item list - will regenerate on next Items call
string newInclude = item.TreatIncludeAsLiteral ? MSBuildInternals.Escape(item.Include) : item.Include;
var newMetadata = new Dictionary<string, string>();
var newMetadata = new Dictionary<string, string>(MSBuildInternals.PropertyNameComparer);
foreach (string name in item.MetadataNames) {
newMetadata[name] = item.GetMetadata(name);
}
@ -1190,6 +1193,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1190,6 +1193,9 @@ namespace ICSharpCode.SharpDevelop.Project
: base(loadInformation)
{
this.itemsCollection = new ProjectItemCollection(this);
this.configurationNames = new MSBuildConfigurationOrPlatformNameCollection(this, false);
this.platformNames = new MSBuildConfigurationOrPlatformNameCollection(this, true);
isLoading = true;
bool success = false;
try {
@ -1311,61 +1317,44 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1311,61 +1317,44 @@ namespace ICSharpCode.SharpDevelop.Project
#endregion
#region GetConfigurationNames / GetPlatformNames
IReadOnlyCollection<string> configurationNames, platformNames;
readonly MSBuildConfigurationOrPlatformNameCollection configurationNames, platformNames;
#warning reimplement configuration management
/*public override IReadOnlyCollection<string> ConfigurationNames {
get {
lock (SyncRoot) {
if (configurationNames == null) {
LoadConfigurationPlatformNamesFromMSBuild();
}
return configurationNames;
}
}
public override IConfigurationOrPlatformNameCollection ConfigurationNames {
get { return configurationNames; }
}
public override IReadOnlyCollection<string> PlatformNames {
get {
lock (SyncRoot) {
if (platformNames == null) {
LoadConfigurationPlatformNamesFromMSBuild();
}
return platformNames;
}
}
}
*/
protected void InvalidateConfigurationPlatformNames()
{
lock (SyncRoot) {
configurationNames = null;
platformNames = null;
}
public override IConfigurationOrPlatformNameCollection PlatformNames {
get { return platformNames; }
}
/// <summary>
/// Load available configurations and platforms from the project file
/// by looking at which conditions are used.
/// </summary>
void LoadConfigurationPlatformNamesFromMSBuild()
protected internal void LoadConfigurationPlatformNamesFromMSBuild()
{
ISet<string> configurationNames = new SortedSet<string>();
ISet<string> platformNames = new SortedSet<string>();
LoadConfigurationPlatformNamesFromMSBuildInternal(projectFile, configurationNames, platformNames);
LoadConfigurationPlatformNamesFromMSBuildInternal(userProjectFile, configurationNames, platformNames);
if (configurationNames.Count == 0) {
configurationNames.Add("Debug");
configurationNames.Add("Release");
}
if (platformNames.Count == 0) {
platformNames.Add("AnyCPU");
lock (SyncRoot) {
ISet<string> configurationNames = new SortedSet<string>(ConfigurationAndPlatform.ConfigurationNameComparer);
ISet<string> platformNames = new SortedSet<string>(ConfigurationAndPlatform.ConfigurationNameComparer);
LoadConfigurationPlatformNamesFromMSBuildInternal(projectFile, configurationNames, platformNames);
LoadConfigurationPlatformNamesFromMSBuildInternal(userProjectFile, configurationNames, platformNames);
if (configurationNames.Count == 0) {
configurationNames.Add("Debug");
configurationNames.Add("Release");
}
if (platformNames.Count == 0) {
platformNames.Add("AnyCPU");
}
var oldConfigurationNames = this.configurationNames.CreateSnapshot();
var oldPlatformNames = this.platformNames.CreateSnapshot();
this.configurationNames.SetContents(configurationNames);
this.platformNames.SetContents(platformNames);
this.configurationNames.OnCollectionChanged(oldConfigurationNames, configurationNames.ToArray());
this.platformNames.OnCollectionChanged(oldPlatformNames, platformNames.ToArray());
}
this.configurationNames = configurationNames.ToArray();
this.platformNames = platformNames.ToArray();
}
static void LoadConfigurationPlatformNamesFromMSBuildInternal(
@ -1395,200 +1384,6 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1395,200 +1384,6 @@ namespace ICSharpCode.SharpDevelop.Project
}
#endregion
#region IProjectAllowChangeConfigurations interface implementation
/*
bool IProjectAllowChangeConfigurations.RenameProjectConfiguration(string oldName, string newName)
{
lock (SyncRoot) {
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.Concat(userProjectFile.PropertyGroups)) {
// Rename the default configuration setting
var prop = g.Properties.FirstOrDefault(p => p.Name == "Configuration");
if (prop != null && prop.Value == oldName) {
prop.Value = newName;
}
// Rename the configuration in conditions
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gConfiguration == oldName) {
g.Condition = CreateCondition(newName, gPlatform);
}
}
LoadConfigurationPlatformNamesFromMSBuild();
return true;
}
}
bool IProjectAllowChangeConfigurations.RenameProjectPlatform(string oldName, string newName)
{
lock (SyncRoot) {
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.Concat(userProjectFile.PropertyGroups)) {
// Rename the default platform setting
var prop = g.Properties.FirstOrDefault(p => p.Name == "Platform");
if (prop != null && prop.Value == oldName) {
prop.Value = newName;
}
// Rename the platform in conditions
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gPlatform == oldName) {
g.Condition = CreateCondition(gConfiguration, newName);
}
}
LoadConfigurationPlatformNamesFromMSBuild();
return true;
}
}
bool IProjectAllowChangeConfigurations.AddProjectConfiguration(string newName, string copyFrom)
{
lock (SyncRoot) {
bool copiedGroupInMainFile = false;
if (copyFrom != null) {
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.ToList()) {
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gConfiguration == copyFrom) {
CopyProperties(projectFile, g, newName, gPlatform);
copiedGroupInMainFile = true;
}
}
foreach (ProjectPropertyGroupElement g in userProjectFile.PropertyGroups.ToList()) {
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gConfiguration == copyFrom) {
CopyProperties(userProjectFile, g, newName, gPlatform);
}
}
}
if (!copiedGroupInMainFile) {
projectFile.AddPropertyGroup().Condition = CreateCondition(newName, null);
}
LoadConfigurationPlatformNamesFromMSBuild();
return true;
}
}
bool IProjectAllowChangeConfigurations.AddProjectPlatform(string newName, string copyFrom)
{
lock (SyncRoot) {
bool copiedGroupInMainFile = false;
if (copyFrom != null) {
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.ToList()) {
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gPlatform == copyFrom) {
CopyProperties(projectFile, g, gConfiguration, newName);
copiedGroupInMainFile = true;
}
}
foreach (ProjectPropertyGroupElement g in userProjectFile.PropertyGroups.ToList()) {
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gPlatform == copyFrom) {
CopyProperties(userProjectFile, g, gConfiguration, newName);
}
}
}
if (!copiedGroupInMainFile) {
projectFile.AddPropertyGroup().Condition = CreateCondition(null, newName);
}
LoadConfigurationPlatformNamesFromMSBuild();
return true;
}
}
/// <summary>
/// copy properties from g into a new property group for newConfiguration and newPlatform
/// </summary>
void CopyProperties(ProjectRootElement project, ProjectPropertyGroupElement g, string newConfiguration, string newPlatform)
{
ProjectPropertyGroupElement ng = project.AddPropertyGroup();
ng.Condition = CreateCondition(newConfiguration, newPlatform);
foreach (var p in g.Properties) {
ng.AddProperty(p.Name, p.Value).Condition = p.Condition;
}
}
bool IProjectAllowChangeConfigurations.RemoveProjectConfiguration(string name)
{
lock (SyncRoot) {
string otherConfigurationName = null;
foreach (string configName in this.ConfigurationNames) {
if (configName != name) {
otherConfigurationName = name;
break;
}
}
if (otherConfigurationName == null) {
throw new InvalidOperationException("cannot remove the last configuration");
}
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.Concat(userProjectFile.PropertyGroups).ToList()) {
ProjectPropertyElement prop = g.Properties.FirstOrDefault(p => p.Name == "Configuration");
if (prop != null && prop.Value == name) {
prop.Value = otherConfigurationName;
}
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gConfiguration == name) {
g.Parent.RemoveChild(g);
}
}
LoadConfigurationPlatformNamesFromMSBuild();
return true;
}
}
bool IProjectAllowChangeConfigurations.RemoveProjectPlatform(string name)
{
lock (SyncRoot) {
string otherPlatformName = null;
foreach (string platformName in this.PlatformNames) {
if (platformName != name) {
otherPlatformName = name;
break;
}
}
if (otherPlatformName == null) {
throw new InvalidOperationException("cannot remove the last platform");
}
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.Concat(userProjectFile.PropertyGroups).ToList()) {
ProjectPropertyElement prop = g.Properties.FirstOrDefault(p => p.Name == "Platform");
if (prop != null && prop.Value == name) {
prop.Value = otherPlatformName;
}
string gConfiguration, gPlatform;
MSBuildInternals.GetConfigurationAndPlatformFromCondition(g.Condition,
out gConfiguration,
out gPlatform);
if (gPlatform == name) {
g.Parent.RemoveChild(g);
}
}
LoadConfigurationPlatformNamesFromMSBuild();
return true;
}
}
*/
#endregion
#region ProjectExtensions
public override bool ContainsProjectExtension(string name)
{

250
src/Main/Base/Project/Src/Project/MSBuildConfigurationOrPlatformNameCollection.cs

@ -0,0 +1,250 @@ @@ -0,0 +1,250 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory;
using ICSharpCode.SharpDevelop.Dom;
using Microsoft.Build.Construction;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// The collection for <see cref="MSBuildBasedProject.ConfigurationNames"/> and <see cref="MSBuildBasedProject.PlatformNames"/>.
/// </summary>
class MSBuildConfigurationOrPlatformNameCollection : IConfigurationOrPlatformNameCollection
{
public event ModelCollectionChangedEventHandler<string> CollectionChanged;
volatile IReadOnlyList<string> listSnapshot = EmptyList<string>.Instance;
readonly MSBuildBasedProject project;
readonly bool isPlatform;
public MSBuildConfigurationOrPlatformNameCollection(MSBuildBasedProject project, bool isPlatform)
{
this.project = project;
this.isPlatform = isPlatform;
}
internal void SetContents(IEnumerable<string> updatedItems)
{
this.listSnapshot = updatedItems.ToArray();
}
internal void OnCollectionChanged(IReadOnlyCollection<string> oldItems, IReadOnlyCollection<string> newItems)
{
if (oldItems.SequenceEqual(newItems))
return;
var eh = CollectionChanged;
if (eh != null)
eh(oldItems, newItems);
}
#region IReadOnlyCollection implementation
public IReadOnlyCollection<string> CreateSnapshot()
{
return listSnapshot;
}
public int Count {
get {
return listSnapshot.Count;
}
}
public IEnumerator<string> GetEnumerator()
{
return listSnapshot.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return listSnapshot.GetEnumerator();
}
#endregion
public string ValidateName(string name)
{
if (name == null)
return null;
name = name.Trim();
if (!ConfigurationAndPlatform.IsValidName(name))
return null;
if (isPlatform)
return MSBuildInternals.FixPlatformNameForProject(name);
else
return name;
}
string GetName(ConfigurationAndPlatform config)
{
return isPlatform ? config.Platform : config.Configuration;
}
bool HasName(ConfigurationAndPlatform config, string name)
{
return ConfigurationAndPlatform.ConfigurationNameComparer.Equals(GetName(config), name);
}
ConfigurationAndPlatform SetName(ConfigurationAndPlatform config, string newName)
{
if (isPlatform)
return new ConfigurationAndPlatform(config.Configuration, newName);
else
return new ConfigurationAndPlatform(newName, config.Platform);
}
void IConfigurationOrPlatformNameCollection.Add(string newName, string copyFrom)
{
SD.MainThread.VerifyAccess();
newName = ValidateName(newName);
if (newName == null)
throw new ArgumentException();
lock (project.SyncRoot) {
var projectFile = project.MSBuildProjectFile;
var userProjectFile = project.MSBuildUserProjectFile;
bool copiedGroupInMainFile = false;
if (copyFrom != null) {
foreach (ProjectPropertyGroupElement g in projectFile.PropertyGroups.ToList()) {
var gConfig = ConfigurationAndPlatform.FromCondition(g.Condition);
if (HasName(gConfig, copyFrom)) {
CopyProperties(projectFile, g, SetName(gConfig, newName));
copiedGroupInMainFile = true;
}
}
foreach (ProjectPropertyGroupElement g in userProjectFile.PropertyGroups.ToList()) {
var gConfig = ConfigurationAndPlatform.FromCondition(g.Condition);
if (HasName(gConfig, copyFrom)) {
CopyProperties(userProjectFile, g, SetName(gConfig, newName));
}
}
}
if (!copiedGroupInMainFile) {
projectFile.AddPropertyGroup().Condition = (isPlatform ? new ConfigurationAndPlatform(null, newName) : new ConfigurationAndPlatform(newName, null)).ToCondition();
}
project.LoadConfigurationPlatformNamesFromMSBuild();
// Adjust mapping:
// If the new config/platform already exists in the solution and is mapped to some old project config/platform,
// re-map it to the new config/platform.
var mapping = project.ConfigurationMapping;
if (isPlatform) {
string newNameForSolution = MSBuildInternals.FixPlatformNameForSolution(newName);
if (project.ParentSolution.PlatformNames.Contains(newNameForSolution, ConfigurationAndPlatform.ConfigurationNameComparer)) {
foreach (string solutionConfiguration in project.ParentSolution.ConfigurationNames) {
var solutionConfig = new ConfigurationAndPlatform(solutionConfiguration, newNameForSolution);
var projectConfig = mapping.GetProjectConfiguration(solutionConfig);
mapping.SetProjectConfiguration(solutionConfig, SetName(projectConfig, newName));
}
}
} else {
if (project.ParentSolution.ConfigurationNames.Contains(newName, ConfigurationAndPlatform.ConfigurationNameComparer)) {
foreach (string solutionPlatform in project.ParentSolution.PlatformNames) {
var solutionConfig = new ConfigurationAndPlatform(newName, solutionPlatform);
var projectConfig = mapping.GetProjectConfiguration(solutionConfig);
mapping.SetProjectConfiguration(solutionConfig, SetName(projectConfig, newName));
}
}
}
project.ActiveConfiguration = mapping.GetProjectConfiguration(project.ParentSolution.ActiveConfiguration);
}
}
/// <summary>
/// copy properties from g into a new property group for newConfiguration and newPlatform
/// </summary>
void CopyProperties(ProjectRootElement project, ProjectPropertyGroupElement g, ConfigurationAndPlatform newConfig)
{
ProjectPropertyGroupElement ng = project.AddPropertyGroup();
ng.Condition = newConfig.ToCondition();
foreach (var p in g.Properties) {
ng.AddProperty(p.Name, p.Value).Condition = p.Condition;
}
}
/// <summary>
/// Finds the &lt;Configuration&gt; or &lt;Platform&gt; element in this property group.
/// </summary>
ProjectPropertyElement FindConfigElement(ProjectPropertyGroupElement g)
{
return g.Properties.FirstOrDefault(p => MSBuildInternals.PropertyNameComparer.Equals(p.Name, isPlatform ? "Platform" : "Configuration"));
}
void IConfigurationOrPlatformNameCollection.Remove(string name)
{
SD.MainThread.VerifyAccess();
lock (project.SyncRoot) {
string otherName = null;
foreach (string configName in this) {
if (!ConfigurationAndPlatform.ConfigurationNameComparer.Equals(configName, name)) {
otherName = name;
break;
}
}
if (otherName == null) {
throw new InvalidOperationException("cannot remove the last configuration/platform");
}
foreach (ProjectPropertyGroupElement g in project.MSBuildProjectFile.PropertyGroups.Concat(project.MSBuildUserProjectFile.PropertyGroups).ToList()) {
ProjectPropertyElement prop = FindConfigElement(g);
if (prop != null && ConfigurationAndPlatform.ConfigurationNameComparer.Equals(prop.Value, name)) {
prop.Value = otherName;
}
var gConfig = ConfigurationAndPlatform.FromCondition(g.Condition);
if (HasName(gConfig, name)) {
g.Parent.RemoveChild(g);
}
}
project.LoadConfigurationPlatformNamesFromMSBuild();
AdjustMapping(name, otherName);
}
}
void IConfigurationOrPlatformNameCollection.Rename(string oldName, string newName)
{
newName = ValidateName(newName);
if (newName == null)
throw new ArgumentException();
lock (project.SyncRoot) {
foreach (ProjectPropertyGroupElement g in project.MSBuildProjectFile.PropertyGroups.Concat(project.MSBuildUserProjectFile.PropertyGroups)) {
// Rename the default configuration setting
ProjectPropertyElement prop = FindConfigElement(g);
if (prop != null && ConfigurationAndPlatform.ConfigurationNameComparer.Equals(prop.Value, oldName)) {
prop.Value = newName;
}
// Rename the configuration in conditions
var gConfig = ConfigurationAndPlatform.FromCondition(g.Condition);
if (HasName(gConfig, oldName)) {
g.Condition = SetName(gConfig, newName).ToCondition();
}
}
project.LoadConfigurationPlatformNamesFromMSBuild();
AdjustMapping(oldName, newName);
}
}
void AdjustMapping(string oldName, string newName)
{
var mapping = project.ConfigurationMapping;
foreach (string solutionConfiguration in project.ParentSolution.ConfigurationNames) {
foreach (string solutionPlatform in project.ParentSolution.PlatformNames) {
var solutionConfig = new ConfigurationAndPlatform(solutionConfiguration, solutionPlatform);
var projectConfig = mapping.GetProjectConfiguration(solutionConfig);
if (HasName(projectConfig, oldName))
mapping.SetProjectConfiguration(solutionConfig, SetName(projectConfig, newName));
}
}
// Adjust active configuration:
if (HasName(project.ActiveConfiguration, oldName))
project.ActiveConfiguration = SetName(project.ActiveConfiguration, newName);
}
}
}

5
src/Main/Base/Project/Src/Project/MSBuildInternals.cs

@ -25,6 +25,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -25,6 +25,7 @@ namespace ICSharpCode.SharpDevelop.Project
// TODO: I think MSBuild actually uses OrdinalIgnoreCase. SharpDevelop 3.x just used string.operator ==, so I'm keeping
// that setting until all code is ported to use PropertyNameComparer and we've verified what MSBuild is actually using.
public readonly static StringComparer PropertyNameComparer = StringComparer.Ordinal;
public readonly static StringComparer ConfigurationNameComparer = ConfigurationAndPlatform.ConfigurationNameComparer;
internal static void UnloadProject(MSBuild.Evaluation.ProjectCollection projectCollection, MSBuild.Evaluation.Project project)
{
@ -123,9 +124,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -123,9 +124,9 @@ namespace ICSharpCode.SharpDevelop.Project
return PropertyStorageLocations.Base;
}
PropertyStorageLocations location = 0; // 0 is unknown
if (condition.Contains("$(Configuration)"))
if (condition.IndexOf("$(Configuration)", StringComparison.OrdinalIgnoreCase) >= 0)
location |= PropertyStorageLocations.ConfigurationSpecific;
if (condition.Contains("$(Platform)"))
if (condition.IndexOf("$(Platform)", StringComparison.OrdinalIgnoreCase) >= 0)
location |= PropertyStorageLocations.PlatformSpecific;
return location;
}

2
src/Main/SharpDevelop/Project/Configuration/EditAvailableConfigurationsDialog.cs

@ -106,7 +106,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -106,7 +106,7 @@ namespace ICSharpCode.SharpDevelop.Project
return false;
}
foreach (string item in listBox.Items) {
if (string.Equals(item, newName, StringComparison.OrdinalIgnoreCase)) {
if (ConfigurationAndPlatform.ConfigurationNameComparer.Equals(item, newName)) {
MessageService.ShowMessage("${res:Dialog.EditAvailableConfigurationsDialog.DuplicateName}");
return false;
}

Loading…
Cancel
Save