| File: Core\NuspecUtility.cs | Web Access |
| Project: src\nuget-client\src\NuGet.Core\NuGet.Packaging\NuGet.Packaging.csproj (NuGet.Packaging) |
// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Xml.Linq; using NuGet.Common; using NuGet.Frameworks; namespace NuGet.Packaging.Core { /// <summary> /// Until NuspecReader and Manifest are unified, this is a place to share implementations of /// reading and parsing specific elements out of the .nuspec XML. /// </summary> public static class NuspecUtility { public static readonly string PackageTypes = "packageTypes"; public static readonly string PackageType = "packageType"; public static readonly string Name = "name"; public static readonly string Version = "version"; public static readonly string Serviceable = "serviceable"; public static readonly string Repository = "repository"; public static readonly string Type = "type"; public static readonly string RepositoryUrl = "url"; public static readonly string RepositoryBranch = "branch"; public static readonly string RepositoryCommit = "commit"; public static readonly string License = "license"; public static readonly string Group = "group"; public static readonly string FrameworkReferences = "frameworkReferences"; public static readonly string FrameworkReference = "frameworkReference"; public static readonly string TargetFramework = "targetFramework"; /// <summary> /// Gets the package types from a .nuspec metadata XML element. /// </summary> /// <param name="metadataNode">The metadata XML element.</param> /// <param name="useMetadataNamespace"> /// Whether or not to use the metadata element's namespace when finding the package type /// nodes. If false is specified, only the local names of the package type nodes are used /// for comparison. If true is specified, the package type nodes must have the same /// namespace as the metadata node. /// </param> /// <returns> /// A list of package types. If no package types are found in the metadata node, an empty /// list is returned. /// </returns> public static IReadOnlyList<PackageType> GetPackageTypes(XElement metadataNode, bool useMetadataNamespace) { IEnumerable<XElement> nodes; if (useMetadataNamespace) { var metadataNamespace = metadataNode.GetDefaultNamespace().NamespaceName; nodes = metadataNode .Elements(XName.Get(PackageTypes, metadataNamespace)) .SelectMany(x => x.Elements(XName.Get(PackageType, metadataNamespace))); } else { nodes = metadataNode .Elements() .Where(x => x.Name.LocalName == PackageTypes) .SelectMany(x => x.Elements()) .Where(x => x.Name.LocalName == PackageType); } var packageTypes = new List<PackageType>(); foreach (var node in nodes) { // Get the required package type name. var nameAttribute = node.Attribute(XName.Get(Name)); if (nameAttribute == null || string.IsNullOrWhiteSpace(nameAttribute.Value)) { throw new PackagingException(Strings.MissingPackageTypeName); } var name = nameAttribute.Value.Trim(); // Get the optional package type version. var versionAttribute = node.Attribute(XName.Get(Version)); Version? version; if (versionAttribute != null) { if (!System.Version.TryParse(versionAttribute.Value, out version)) { throw new PackagingException(string.Format( CultureInfo.CurrentCulture, Strings.InvalidPackageTypeVersion, versionAttribute.Value)); } } else { version = Core.PackageType.EmptyVersion; } packageTypes.Add(new PackageType(name, version)); } return packageTypes; } /// <summary> /// Gets the value of serviceable element from a .nuspec metadata XML element. /// </summary> /// <param name="metadataNode">The metadata XML element.</param> /// <returns> /// true if the serviceable element is set in the .nuspec file as true, else false. /// </returns> public static bool IsServiceable(XElement metadataNode) { var metadataNamespace = metadataNode.GetDefaultNamespace().NamespaceName; var element = metadataNode.Elements(XName.Get(Serviceable, metadataNamespace)).FirstOrDefault(); if (element == null) { return false; } if (element.Value == null) { return false; } var value = element.Value.Trim(); return System.Xml.XmlConvert.ToBoolean(value); } /// <summary> /// Gets the FrameworkReference groups. This refers to the FrameworkReference concept added in .NET Core 3.0 /// </summary> /// <param name="metadataNode">The metadata node</param> /// <param name="frameworkProvider">A FrameworkNameProvider</param> /// <param name="useMetadataNamespace">Whether or not to use the metadata element's namespace when getting the framework reference nodes. /// If false is specified, only the local names of the FrameworkReference nodes are used /// for comparison. If true is specified, the fremeworkreference nodes must have the same /// namespace as the metadata node.</param> /// <returns></returns> internal static IEnumerable<FrameworkReferenceGroup> GetFrameworkReferenceGroups(XElement metadataNode, IFrameworkNameProvider frameworkProvider, bool useMetadataNamespace) { var ns = useMetadataNamespace ? metadataNode.GetDefaultNamespace().NamespaceName : null; IEnumerable<XElement> frameworkReferenceGroups; if (useMetadataNamespace) { var frameworkReferencesNode = metadataNode .Elements(XName.Get(FrameworkReferences, ns!)); frameworkReferenceGroups = frameworkReferencesNode .Elements(XName.Get(Group, ns!)); } else { frameworkReferenceGroups = metadataNode .Elements() .Where(x => x.Name.LocalName == Group); } foreach (var frameworkRefGroup in frameworkReferenceGroups) { var groupFramework = GetAttributeValue(frameworkRefGroup, TargetFramework); var frameworkReferences = useMetadataNamespace ? frameworkRefGroup.Elements(XName.Get(FrameworkReference, ns!)) : frameworkRefGroup.Elements().Where(x => x.Name.LocalName == FrameworkReference); var framework = NuGetFramework.Parse(groupFramework!, frameworkProvider); var frameworkRefs = GetFrameworkReferences(frameworkReferences); yield return new FrameworkReferenceGroup(framework, frameworkRefs.Select(e => new FrameworkReference(e))); } } private static IEnumerable<string> GetFrameworkReferences(IEnumerable<XElement> nodes) { return new HashSet<string>(nodes.Select(e => GetAttributeValue(e, Name)!), ComparisonUtility.FrameworkReferenceNameComparer); } private static string? GetAttributeValue(XElement element, string attributeName) { var attribute = element.Attribute(XName.Get(attributeName)); return attribute == null ? null : attribute.Value; } } }