From db652a87ec7017e4c5fe2a8c200c0c77e9124473 Mon Sep 17 00:00:00 2001 From: Matt Kotsenas Date: Fri, 15 Mar 2024 10:37:46 -0700 Subject: [PATCH] Support any namespace in NuspecReader (#278) The NuspecReader was hardcoded to always assume the nuspec v6 schema. However, the NuGet client will use the _oldest_ schema it can when creating a package. Update the reader so it uses whatever the provided XML schema is. --- .../NuspecReaderTests.cs | 24 +++++++++++++++++++ .../NuspecReader.cs | 22 +++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Build.Utilities.ProjectCreation.UnitTests/NuspecReaderTests.cs b/src/Microsoft.Build.Utilities.ProjectCreation.UnitTests/NuspecReaderTests.cs index 7029c20..fde770e 100644 --- a/src/Microsoft.Build.Utilities.ProjectCreation.UnitTests/NuspecReaderTests.cs +++ b/src/Microsoft.Build.Utilities.ProjectCreation.UnitTests/NuspecReaderTests.cs @@ -34,5 +34,29 @@ public void LicenseExpressionIsNullForFileLicenses() nuspec.LicenseVersion.ShouldBeNull(); nuspec.LicenseUrl.ShouldBeNull(); } + + // List of namespaces from https://github.com/NuGet/NuGet.Client/blob/6917e6c883d45f45672e20d4b1c45758dad2fa84/src/NuGet.Core/NuGet.Packaging/PackageCreation/Authoring/ManifestSchemaUtility.cs#L23-L50 + [Theory] + [InlineData("http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd")] + [InlineData("http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd")] + [InlineData("http://schemas.microsoft.com/packaging/2011/10/nuspec.xsd")] + [InlineData("http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd")] + [InlineData("http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd")] + [InlineData("http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd")] + public void ReaderCanParseKnownXmlNamespaces(string xmlns) + { + string contents = +$@" + + PackageL + 16.4.60 + +"; + + NuspecReader nuspec = new NuspecReader(contents); + + nuspec.Id.ShouldBe("PackageL"); + nuspec.Version.ShouldBe("16.4.60"); + } } } \ No newline at end of file diff --git a/src/Microsoft.Build.Utilities.ProjectCreation/NuspecReader.cs b/src/Microsoft.Build.Utilities.ProjectCreation/NuspecReader.cs index 67e0a84..0184d1a 100644 --- a/src/Microsoft.Build.Utilities.ProjectCreation/NuspecReader.cs +++ b/src/Microsoft.Build.Utilities.ProjectCreation/NuspecReader.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Xml; using System.Xml.Linq; using System.Xml.XPath; @@ -13,17 +14,15 @@ namespace Microsoft.Build.Utilities.ProjectCreation { internal class NuspecReader { - private static readonly XNamespace NuspecNamespace = "http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"; - private readonly XDocument _document; - private readonly XmlNamespaceManager _namespaceManager = new XmlNamespaceManager(new NameTable()); public NuspecReader(string contents) { _document = XDocument.Parse(contents); - _namespaceManager.AddNamespace("ns", NuspecNamespace.NamespaceName); + string ns = GetNamespace(_document); + _namespaceManager.AddNamespace("ns", ns); } public NuspecReader(FileInfo fileInfo) @@ -125,6 +124,21 @@ public IEnumerable PackageTypes public string? Version => GetElement("version"); + private static string GetNamespace(XDocument document) + { + XPathNavigator navigator = document.CreateNavigator(); + navigator.MoveToFollowing(XPathNodeType.Element); + + IDictionary namespaces = navigator.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml); + + if (namespaces.Count != 1) + { + throw new XmlException($"Unabled to determine nuspec XML namespace. Namespaces in scope: '{string.Join(",", new Dictionary(namespaces))}'."); + } + + return namespaces.Values.Single(); + } + private IEnumerable GetContentFiles() { foreach (XElement file in _document.XPathSelectElements("//ns:package/ns:metadata/ns:contentFiles/ns:files", _namespaceManager))