Browse Source

Fix project build error after installing Fody NuGet package.

The Fody NuGet package has an install PowerShell script that
directly updates the MSBuild project from the
Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection
to set a FodyPath property that defines where the Fody.targets
file should find the main Fody assembly.

Extended the support added for the Microsoft.Bcl.Build NuGet package
so project properties added by directly updating the MSBuild project
from the GlobalProjectCollection are added/updated in the actual
project file.

No support for updating properties that exist multiple times inside
a project (e.g. OutputPath).
pull/79/head
Matt Ward 12 years ago
parent
commit
5a4cac8dae
  1. 2
      src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj
  2. 24
      src/AddIns/Misc/PackageManagement/Project/Src/Scripting/GlobalMSBuildProjectCollection.cs
  3. 55
      src/AddIns/Misc/PackageManagement/Project/Src/Scripting/MSBuildProjectPropertiesMergeResult.cs
  4. 93
      src/AddIns/Misc/PackageManagement/Project/Src/Scripting/MSBuildProjectPropertiesMerger.cs
  5. 1
      src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj
  6. 248
      src/AddIns/Misc/PackageManagement/Test/Src/Scripting/MSBuildProjectPropertiesMergerTests.cs

2
src/AddIns/Misc/PackageManagement/Project/PackageManagement.csproj

@ -255,6 +255,8 @@ @@ -255,6 +255,8 @@
<Compile Include="Src\Scripting\IGlobalMSBuildProjectCollection.cs" />
<Compile Include="Src\Scripting\MSBuildProjectImportsMerger.cs" />
<Compile Include="Src\Scripting\MSBuildProjectImportsMergeResult.cs" />
<Compile Include="Src\Scripting\MSBuildProjectPropertiesMerger.cs" />
<Compile Include="Src\Scripting\MSBuildProjectPropertiesMergeResult.cs" />
<Compile Include="Src\Scripting\NullGlobalMSBuildProjectCollection.cs" />
<Compile Include="Src\Scripting\RunAllProjectPackageScriptsAction.cs" />
<Compile Include="Src\ServiceWithWorkbenchOwner.cs" />

24
src/AddIns/Misc/PackageManagement/Project/Src/Scripting/GlobalMSBuildProjectCollection.cs

@ -55,6 +55,7 @@ namespace ICSharpCode.PackageManagement.Scripting @@ -55,6 +55,7 @@ namespace ICSharpCode.PackageManagement.Scripting
{
foreach (GlobalAndInternalProject msbuildProjects in projects) {
UpdateImports(msbuildProjects);
UpdateProperties(msbuildProjects);
GetGlobalProjectCollection().UnloadProject(msbuildProjects.GlobalMSBuildProject);
}
}
@ -92,5 +93,28 @@ namespace ICSharpCode.PackageManagement.Scripting @@ -92,5 +93,28 @@ namespace ICSharpCode.PackageManagement.Scripting
project.Name,
result);
}
void UpdateProperties(GlobalAndInternalProject msbuildProjects)
{
var propertiesMerger = new MSBuildProjectPropertiesMerger(
msbuildProjects.GlobalMSBuildProject,
msbuildProjects.SharpDevelopMSBuildProject);
propertiesMerger.Merge();
if (propertiesMerger.Result.AnyPropertiesChanged())
{
LogProjectPropertiesMergeResult(msbuildProjects.SharpDevelopMSBuildProject, propertiesMerger.Result);
}
}
void LogProjectPropertiesMergeResult(MSBuildBasedProject project, MSBuildProjectPropertiesMergeResult result)
{
logger.Log(
MessageLevel.Info,
"Project properties merge result for project '{0}':\r\n{1}",
project.Name,
result);
}
}
}

55
src/AddIns/Misc/PackageManagement/Project/Src/Scripting/MSBuildProjectPropertiesMergeResult.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// 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;
namespace ICSharpCode.PackageManagement.Scripting
{
public class MSBuildProjectPropertiesMergeResult
{
List<string> propertiesAdded = new List<string>();
List<string> propertiesUpdated = new List<string>();
public IEnumerable<string> PropertiesAdded {
get { return propertiesAdded; }
}
public IEnumerable<string> PropertiesUpdated {
get { return propertiesUpdated; }
}
public override string ToString()
{
return String.Format(
"Properties added: {0}\r\nProperties updated: {1}",
PropertiesToString(propertiesAdded),
PropertiesToString(propertiesUpdated));
}
static string PropertiesToString(IEnumerable<string> properties)
{
if (!properties.Any()) {
return String.Empty;
}
return String.Join(",\r\n", properties.Select(property => property));
}
public void AddPropertyAdded(string propertyName)
{
propertiesAdded.Add(propertyName);
}
public void AddPropertyUpdated(string propertyName)
{
propertiesUpdated.Add(propertyName);
}
public bool AnyPropertiesChanged()
{
return propertiesUpdated.Any() || propertiesAdded.Any();
}
}
}

93
src/AddIns/Misc/PackageManagement/Project/Src/Scripting/MSBuildProjectPropertiesMerger.cs

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
// 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.SharpDevelop.Project;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
namespace ICSharpCode.PackageManagement.Scripting
{
public class MSBuildProjectPropertiesMerger
{
IPackageManagementProjectService projectService;
Project msbuildProject;
MSBuildBasedProject sharpDevelopProject;
MSBuildProjectPropertiesMergeResult result = new MSBuildProjectPropertiesMergeResult();
public MSBuildProjectPropertiesMerger(Project msbuildProject, MSBuildBasedProject sharpDevelopProject)
: this(msbuildProject, sharpDevelopProject, new PackageManagementProjectService())
{
}
public MSBuildProjectPropertiesMerger(
Project msbuildProject,
MSBuildBasedProject sharpDevelopProject,
IPackageManagementProjectService projectService)
{
this.msbuildProject = msbuildProject;
this.sharpDevelopProject = sharpDevelopProject;
this.projectService = projectService;
}
public MSBuildProjectPropertiesMergeResult Result {
get { return result; }
}
public void Merge()
{
foreach (ProjectPropertyElement property in msbuildProject.Xml.Properties) {
UpdateProperty(property);
}
projectService.Save(sharpDevelopProject);
}
void UpdateProperty(ProjectPropertyElement msbuildProjectProperty)
{
List<ProjectPropertyElement> sharpDevelopProjectProperties = FindSharpDevelopProjectProperties(msbuildProjectProperty);
if (sharpDevelopProjectProperties.Count > 1) {
// Ignore. Currently do not handle properties defined inside
// property groups with conditions (e.g. OutputPath)
} else if (!sharpDevelopProjectProperties.Any()) {
AddPropertyToSharpDevelopProject(msbuildProjectProperty);
} else if (HasMSBuildProjectPropertyBeenUpdated(msbuildProjectProperty, sharpDevelopProjectProperties.First())) {
UpdatePropertyInSharpDevelopProject(msbuildProjectProperty);
}
}
List<ProjectPropertyElement> FindSharpDevelopProjectProperties(ProjectPropertyElement msbuildProjectProperty)
{
return sharpDevelopProject
.MSBuildProjectFile
.Properties
.Where(property => String.Equals(property.Name, msbuildProjectProperty.Name, StringComparison.OrdinalIgnoreCase))
.ToList();
}
void AddPropertyToSharpDevelopProject(ProjectPropertyElement msbuildProjectProperty)
{
SetPropertyInSharpDevelopProject(msbuildProjectProperty);
result.AddPropertyAdded(msbuildProjectProperty.Name);
}
void SetPropertyInSharpDevelopProject(ProjectPropertyElement msbuildProjectProperty)
{
sharpDevelopProject.SetProperty(msbuildProjectProperty.Name, msbuildProjectProperty.Value);
}
bool HasMSBuildProjectPropertyBeenUpdated(ProjectPropertyElement msbuildProjectProperty, ProjectPropertyElement sharpDevelopProjectProperty)
{
return msbuildProjectProperty.Value != sharpDevelopProjectProperty.Value;
}
void UpdatePropertyInSharpDevelopProject(ProjectPropertyElement msbuildProjectProperty)
{
SetPropertyInSharpDevelopProject(msbuildProjectProperty);
result.AddPropertyUpdated(msbuildProjectProperty.Name);
}
}
}

1
src/AddIns/Misc/PackageManagement/Test/PackageManagement.Tests.csproj

@ -207,6 +207,7 @@ @@ -207,6 +207,7 @@
<Compile Include="Src\RunAllProjectPackageScriptsActionTests.cs" />
<Compile Include="Src\Scripting\ConsoleHostFileConflictResolverTests.cs" />
<Compile Include="Src\Scripting\MSBuildProjectImportsMergerTests.cs" />
<Compile Include="Src\Scripting\MSBuildProjectPropertiesMergerTests.cs" />
<Compile Include="Src\UpdatedPackagesTests.cs" />
<Compile Include="Src\UpdatePackagesActionTests.cs" />
<Compile Include="Src\UpdateSolutionPackagesActionTests.cs" />

248
src/AddIns/Misc/PackageManagement/Test/Src/Scripting/MSBuildProjectPropertiesMergerTests.cs

@ -0,0 +1,248 @@ @@ -0,0 +1,248 @@
// 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.Linq;
using ICSharpCode.PackageManagement;
using ICSharpCode.PackageManagement.Scripting;
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using NUnit.Framework;
using PackageManagement.Tests.Helpers;
using Rhino.Mocks;
namespace PackageManagement.Tests.Scripting
{
[TestFixture]
public class MSBuildProjectPropertiesMergerTests
{
MSBuildProjectPropertiesMerger propertiesMerger;
IPackageManagementProjectService projectService;
TestableProject sharpDevelopProject;
Project msbuildProject;
[SetUp]
public void Init()
{
CreateMSBuildProject();
CreateSharpDevelopProject();
CreateProjectPropertiesMerger();
}
void CreateMSBuildProject()
{
msbuildProject = new Project();
}
void CreateSharpDevelopProject()
{
sharpDevelopProject = ProjectHelper.CreateTestProject();
}
void CreateProjectPropertiesMerger()
{
projectService = MockRepository.GenerateStub<IPackageManagementProjectService>();
propertiesMerger = new MSBuildProjectPropertiesMerger(msbuildProject, sharpDevelopProject, projectService);
}
void Merge()
{
propertiesMerger.Merge();
}
void AddPropertyToSharpDevelopProject(string name, string value)
{
sharpDevelopProject.SetProperty(name, value);
}
void AddPropertyToSharpDevelopProjectWithCondition(string name, string value, string condition)
{
AddPropertyWithCondition(sharpDevelopProject.MSBuildProjectFile, name, value, condition);
}
void AddPropertyWithCondition(ProjectRootElement projectRoot, string name, string value, string condition)
{
ProjectPropertyGroupElement groupProperty = projectRoot.CreatePropertyGroupElement();
groupProperty.Condition = condition;
projectRoot.AppendChild(groupProperty);
ProjectPropertyElement property = projectRoot.CreatePropertyElement(name);
groupProperty.AppendChild(property);
property.Value = value;
property.Condition = condition;
}
void AddPropertyToMSBuildProject(string name, string value)
{
msbuildProject.SetProperty(name, value);
}
void AddPropertyToMSBuildProjectWithCondition(string name, string value, string condition)
{
AddPropertyWithCondition(msbuildProject.Xml, name, value, condition);
}
void AssertSharpDevelopProjectContainsProperty(string propertyName, string expectedValue)
{
string actualValue = sharpDevelopProject.GetEvaluatedProperty(propertyName);
Assert.AreEqual(expectedValue, actualValue);
}
[Test]
public void Merge_MSBuildProjectHasNewPropertyAdded_PropertyAddedToSharpDevelopProject()
{
AddPropertyToMSBuildProject("Test", "test-value");
Merge();
AssertSharpDevelopProjectContainsProperty("Test", "test-value");
}
[Test]
public void Merge_MSBuildProjectHasNewPropertyAdded_SharpDevelopProjectIsSaved()
{
AddPropertyToMSBuildProject("Test", "test-value");
Merge();
projectService.AssertWasCalled(service => service.Save(sharpDevelopProject));
}
[Test]
public void Merge_MSBuildProjectHasTwoNewPropertiesAdded_BothPropertiesAddedToSharpDevelopProject()
{
AddPropertyToMSBuildProject("Test1", "test-value1");
AddPropertyToMSBuildProject("Test2", "test-value2");
Merge();
AssertSharpDevelopProjectContainsProperty("Test1", "test-value1");
AssertSharpDevelopProjectContainsProperty("Test2", "test-value2");
}
[Test]
public void Merge_MSBuildProjectHasTwoNewPropertiesAdded_MergeResultHasBothPropertiesAdded()
{
AddPropertyToMSBuildProject("Test1", "test-value2");
AddPropertyToMSBuildProject("Test2", "test-value2");
Merge();
var expected = new string[] { "Test1", "Test2" };
string expectedToString = "Properties added: Test1,\r\nTest2\r\nProperties updated: ";
CollectionAssert.AreEqual(expected, propertiesMerger.Result.PropertiesAdded);
Assert.AreEqual(expectedToString, propertiesMerger.Result.ToString());
}
[Test]
public void Merge_MSBuildProjectPropertyUpdated_SharpDevelopProjectPropertyIsUpdated()
{
AddPropertyToSharpDevelopProject("Test", "old-value");
AddPropertyToMSBuildProject("Test", "new-value");
Merge();
AssertSharpDevelopProjectContainsProperty("Test", "new-value");
}
[Test]
public void Merge_TwoMSBuildProjectsPropertiesUpdated_BothPropertiesUpdatedInSharpDevelopProject()
{
AddPropertyToSharpDevelopProject("Test1", "old-value");
AddPropertyToSharpDevelopProject("Test2", "old-value");
AddPropertyToMSBuildProject("Test1", "new-value1");
AddPropertyToMSBuildProject("Test2", "new-value2");
Merge();
AssertSharpDevelopProjectContainsProperty("Test1", "new-value1");
AssertSharpDevelopProjectContainsProperty("Test2", "new-value2");
}
[Test]
public void Merge_TwoMSBuildProjectsPropertiesUpdated_MergeResultShowsUpdatedProperty()
{
AddPropertyToSharpDevelopProject("Test1", "old-value");
AddPropertyToSharpDevelopProject("Test2", "old-value");
AddPropertyToMSBuildProject("Test1", "new-value");
AddPropertyToMSBuildProject("Test2", "new-value");
Merge();
var expected = new string[] { "Test1", "Test2" };
string expectedToString = "Properties added: \r\nProperties updated: Test1,\r\nTest2";
CollectionAssert.AreEqual(expected, propertiesMerger.Result.PropertiesUpdated);
Assert.AreEqual(expectedToString, propertiesMerger.Result.ToString());
}
[Test]
public void Merge_TwoMSBuildProjectsNotChanged_MergeResultShowNoUpdatedProperties()
{
AddPropertyToSharpDevelopProject("Test1", "old-value");
AddPropertyToSharpDevelopProject("Test2", "old-value");
AddPropertyToMSBuildProject("Test1", "old-value");
AddPropertyToMSBuildProject("Test2", "old-value");
Merge();
var expected = new string[0];
CollectionAssert.AreEqual(expected, propertiesMerger.Result.PropertiesUpdated);
CollectionAssert.AreEqual(expected, propertiesMerger.Result.PropertiesAdded);
Assert.IsFalse(propertiesMerger.Result.AnyPropertiesChanged());
}
[Test]
public void SetProperty_UseDifferentCaseForMSBuildPropertyName_WhatHappens()
{
AddPropertyToMSBuildProject("test", "value");
string propertyValue = msbuildProject.GetPropertyValue("TEST");
Assert.AreEqual("value", propertyValue);
}
[Test]
public void Merge_MSBuildProjectPropertyUpdatedButDifferentCaseUsedForName_SharpDevelopProjectPropertyIsStillUpdated()
{
AddPropertyToSharpDevelopProject("TEST", "old-value");
AddPropertyToMSBuildProject("Test", "new-value");
Merge();
AssertSharpDevelopProjectContainsProperty("TEST", "new-value");
}
[Test]
public void Merge_MSBuildProjectPropertyUpdatedButDifferentCaseUsedForName_MergeResultShowsPropertyHasBeenUpdated()
{
AddPropertyToSharpDevelopProject("TEST", "old-value");
AddPropertyToMSBuildProject("Test", "new-value");
Merge();
var expected = new string[] { "Test" };
CollectionAssert.AreEqual(expected, propertiesMerger.Result.PropertiesUpdated);
Assert.AreEqual(0, propertiesMerger.Result.PropertiesAdded.Count());
}
/// <summary>
/// Ignore any properties that are duplicated in the project file, such as
/// OutputPath which exists twice due to Debug and Release configurations.
/// </summary>
[Test]
public void Merge_OutputPathPropertyInDebugAndReleaseConfigurations_SharpDevelopProjectPropertiesNotChanged()
{
string debugConfiguration = "'$(Configuration)' == 'Debug'";
string releaseConfiguration = "'$(Configuration)' == 'Release'";
AddPropertyToSharpDevelopProjectWithCondition("OutputPath", @"bin\Release", releaseConfiguration);
AddPropertyToSharpDevelopProjectWithCondition("OutputPath", @"bin\Debug", debugConfiguration);
AddPropertyToMSBuildProjectWithCondition("OutputPath", @"bin\Release", releaseConfiguration);
AddPropertyToMSBuildProjectWithCondition("OutputPath", @"bin\Debug", debugConfiguration);
Merge();
Assert.IsFalse(propertiesMerger.Result.AnyPropertiesChanged());
}
}
}
Loading…
Cancel
Save