diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs
index 9c750eeb079..b50bcaf7138 100644
--- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs
+++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs
@@ -903,6 +903,175 @@ await TestUpdateForProject("Newtonsoft.Json", "7.0.1", "13.0.1",
""");
}
+ [Fact]
+ public async Task PackagesConfigUpdateIsNotThwartedBy_VSToolsPath_PropertyBeingSetInUserCode()
+ {
+ await TestUpdateForProject("Newtonsoft.Json", "7.0.1", "13.0.1",
+ projectContents: """
+
+
+ Debug
+ AnyCPU
+
+
+ 2.0
+ 68ed3303-52a0-47b8-a687-3abbb07530da
+ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
+ Library
+ Properties
+ TestProject
+ TestProject
+ v4.5
+
+
+ true
+ full
+ false
+ bin\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C:\some\path\that\does\not\exist
+
+
+
+
+
+ """,
+ packagesConfigContents: """
+
+
+
+ """,
+ expectedProjectContents: """
+
+
+ Debug
+ AnyCPU
+
+
+ 2.0
+ 68ed3303-52a0-47b8-a687-3abbb07530da
+ {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
+ Library
+ Properties
+ TestProject
+ TestProject
+ v4.5
+
+
+ true
+ full
+ false
+ bin\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ C:\some\path\that\does\not\exist
+
+
+
+
+
+ """,
+ expectedPackagesConfigContents: """
+
+
+
+
+ """);
+ }
+
protected static async Task TestUpdateForProject(
string dependencyName,
string oldVersion,
diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs
index 428cc3451d5..acdb37c3940 100644
--- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs
+++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs
@@ -7,6 +7,7 @@
using System.Xml.Linq;
using Microsoft.Language.Xml;
+using NuGetUpdater.Core.Updater;
namespace NuGetUpdater.Core;
@@ -56,7 +57,10 @@ public static async Task UpdateDependencyAsync(string repoRootPath, string proje
args.Add(msbuildDirectory); // e.g., /usr/share/dotnet/sdk/7.0.203
}
- RunNuget(args, packagesDirectory, logger);
+ using (new WebApplicationTargetsConditionPatcher(projectPath))
+ {
+ RunNuget(args, packagesDirectory, logger);
+ }
projectBuildFile = ProjectBuildFile.Open(repoRootPath, projectPath);
projectBuildFile.NormalizeDirectorySeparatorsInProject();
diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs
new file mode 100644
index 00000000000..a04746567ef
--- /dev/null
+++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/WebApplicationTargetsConditionPatcher.cs
@@ -0,0 +1,47 @@
+using System;
+using System.IO;
+using System.Linq;
+
+using Microsoft.Language.Xml;
+
+namespace NuGetUpdater.Core.Updater
+{
+ internal class WebApplicationTargetsConditionPatcher : IDisposable
+ {
+ private string? _capturedCondition;
+ private readonly XmlFilePreAndPostProcessor _processor;
+
+ public WebApplicationTargetsConditionPatcher(string projectFilePath)
+ {
+ _processor = new XmlFilePreAndPostProcessor(
+ getContent: () => File.ReadAllText(projectFilePath),
+ setContent: s => File.WriteAllText(projectFilePath, s),
+ nodeFinder: doc => doc.Descendants()
+ .FirstOrDefault(e => e.Name == "Import" && e.GetAttributeValue("Project") == @"$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets")
+ as XmlNodeSyntax,
+ preProcessor: n =>
+ {
+ var element = (IXmlElementSyntax)n;
+ _capturedCondition = element.GetAttributeValue("Condition");
+ return (XmlNodeSyntax)element.RemoveAttributeByName("Condition").WithAttribute("Condition", "false");
+ },
+ postProcessor: n =>
+ {
+ var element = (IXmlElementSyntax)n;
+ var newElement = element.RemoveAttributeByName("Condition");
+ if (_capturedCondition is not null)
+ {
+ newElement = newElement.WithAttribute("Condition", _capturedCondition);
+ }
+
+ return (XmlNodeSyntax)newElement;
+ }
+ );
+ }
+
+ public void Dispose()
+ {
+ _processor.Dispose();
+ }
+ }
+}
diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/XmlFilePreAndPostProcessor.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/XmlFilePreAndPostProcessor.cs
new file mode 100644
index 00000000000..a728a919a53
--- /dev/null
+++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/XmlFilePreAndPostProcessor.cs
@@ -0,0 +1,55 @@
+using System;
+
+using Microsoft.Language.Xml;
+
+namespace NuGetUpdater.Core.Updater
+{
+ internal class XmlFilePreAndPostProcessor : IDisposable
+ {
+ public Func GetContent { get; }
+ public Action SetContent { get; }
+ public Func NodeFinder { get; }
+ public Func PreProcessor { get; }
+ public Func PostProcessor { get; }
+
+ public XmlFilePreAndPostProcessor(Func getContent, Action setContent, Func nodeFinder, Func preProcessor, Func postProcessor)
+ {
+ GetContent = getContent;
+ SetContent = setContent;
+ NodeFinder = nodeFinder;
+ PreProcessor = preProcessor;
+ PostProcessor = postProcessor;
+ PreProcess();
+ }
+
+ public void Dispose()
+ {
+ PostProcess();
+ }
+
+ private void PreProcess() => RunProcessor(PreProcessor);
+
+ private void PostProcess() => RunProcessor(PostProcessor);
+
+ private void RunProcessor(Func processor)
+ {
+ var content = GetContent();
+ var xml = Parser.ParseText(content);
+ if (xml is null)
+ {
+ return;
+ }
+
+ var node = NodeFinder(xml);
+ if (node is null)
+ {
+ return;
+ }
+
+ var replacementElement = processor(node);
+ var replacementXml = xml.ReplaceNode(node, replacementElement);
+ var replacementString = replacementXml.ToFullString();
+ SetContent(replacementString);
+ }
+ }
+}
diff --git a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs
index e31bb65b943..1a38affa7d7 100644
--- a/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs
+++ b/nuget/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/XmlExtensions.cs
@@ -30,6 +30,17 @@ public static IEnumerable GetElements(this IXmlElementSyntax
return element.Attributes.FirstOrDefault(a => a.Name.Equals(name, comparisonType));
}
+ public static IXmlElementSyntax RemoveAttributeByName(this IXmlElementSyntax element, string attributeName, StringComparison comparisonType = StringComparison.Ordinal)
+ {
+ var attribute = element.GetAttribute(attributeName, comparisonType);
+ if (attribute is null)
+ {
+ return element;
+ }
+
+ return element.RemoveAttribute(attribute);
+ }
+
public static string GetAttributeValue(this IXmlElementSyntax element, string name, StringComparison comparisonType)
{
return element.Attributes.First(a => a.Name.Equals(name, comparisonType)).Value;