| File: PackagesConfigReader.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.IO; using System.Linq; using System.Xml.Linq; using NuGet.Frameworks; using NuGet.Packaging.Core; using NuGet.Versioning; namespace NuGet.Packaging { /// <summary> /// Reads packages.config /// </summary> public class PackagesConfigReader { private readonly XDocument _doc; private readonly IFrameworkNameProvider _frameworkMappings; /// <summary> /// Packages.config reader /// </summary> /// <param name="xml">Packages.config XML</param> public PackagesConfigReader(XDocument xml) : this(DefaultFrameworkNameProvider.Instance, xml) { } /// <summary> /// Packages.config reader /// </summary> /// <param name="frameworkMappings">Additional target framework mappings for parsing target frameworks</param> /// <param name="xml">Packages.config XML</param> public PackagesConfigReader(IFrameworkNameProvider frameworkMappings, XDocument xml) { if (xml == null) { throw new ArgumentNullException(nameof(xml)); } if (frameworkMappings == null) { throw new ArgumentNullException(nameof(frameworkMappings)); } _doc = xml; _frameworkMappings = frameworkMappings; } /// <summary> /// Packages.config reader /// </summary> /// <param name="stream">Stream containing packages.config</param> public PackagesConfigReader(Stream stream) : this(stream, false) { } /// <summary> /// Packages.config reader /// </summary> /// <param name="stream">Stream containing packages.config</param> /// <param name="leaveStreamOpen">True will leave the stream open</param> public PackagesConfigReader(Stream stream, bool leaveStreamOpen) : this(DefaultFrameworkNameProvider.Instance, stream, leaveStreamOpen) { } /// <summary> /// Packages.config reader /// </summary> /// <param name="stream">Stream containing packages.config</param> /// <param name="leaveStreamOpen">True will leave the stream open</param> /// <param name="frameworkMappings">Additional target framework mappings for parsing target frameworks</param> public PackagesConfigReader(IFrameworkNameProvider frameworkMappings, Stream stream, bool leaveStreamOpen) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (frameworkMappings == null) { throw new ArgumentNullException(nameof(frameworkMappings)); } _frameworkMappings = frameworkMappings; _doc = XDocument.Load(stream); if (!leaveStreamOpen) { stream.Dispose(); } } /// <summary> /// Reads the minimum client version from packages.config /// </summary> /// <returns>Minimum client version or the default of 2.5.0</returns> public NuGetVersion GetMinClientVersion() { NuGetVersion? version = null; var node = _doc.Root!.Attribute(XName.Get(PackagesConfig.MinClientAttributeName)); if (node == null) { version = new NuGetVersion(2, 5, 0); } else if (!NuGetVersion.TryParse(node.Value, out version)) { throw new PackagesConfigReaderException(string.Format( CultureInfo.CurrentCulture, Strings.ErrorInvalidMinClientVersion, node.Value)); } return version!; } /// <summary> /// Reads all package node entries in the config. /// If duplicate package ids exist an exception will be thrown. /// </summary> public IEnumerable<PackageReference> GetPackages() { return GetPackages(allowDuplicatePackageIds: false); } /// <summary> /// Reads all package node entries in the config. /// </summary> /// <param name="allowDuplicatePackageIds">If True validation will be performed to ensure that /// only one entry exists for each unique package id.</param> public IEnumerable<PackageReference> GetPackages(bool allowDuplicatePackageIds) { var packages = new List<PackageReference>(); foreach (var package in _doc.Root!.Elements(XName.Get(PackagesConfig.PackageNodeName))) { string? id = null; if (!PackagesConfig.TryGetAttribute(package, "id", out id) || String.IsNullOrEmpty(id)) { throw new PackagesConfigReaderException(string.Format( CultureInfo.CurrentCulture, Strings.ErrorNullOrEmptyPackageId)); } string? version = null; if (!PackagesConfig.TryGetAttribute(package, PackagesConfig.VersionAttributeName, out version) || String.IsNullOrEmpty(version)) { throw new PackagesConfigReaderException(string.Format( CultureInfo.CurrentCulture, Strings.ErrorInvalidPackageVersion, id, version)); } NuGetVersion? semver = null; if (!NuGetVersion.TryParse(version, out semver)) { throw new PackagesConfigReaderException(string.Format( CultureInfo.CurrentCulture, Strings.ErrorInvalidPackageVersion, id, version)); } string? attributeValue = null; VersionRange? allowedVersions = null; if (PackagesConfig.TryGetAttribute(package, PackagesConfig.allowedVersionsAttributeName, out attributeValue)) { if (!VersionRange.TryParse(attributeValue!, out allowedVersions)) { throw new PackagesConfigReaderException(string.Format( CultureInfo.CurrentCulture, Strings.ErrorInvalidAllowedVersions, id, attributeValue)); } } var targetFramework = NuGetFramework.UnsupportedFramework; if (PackagesConfig.TryGetAttribute(package, PackagesConfig.TargetFrameworkAttributeName, out attributeValue)) { targetFramework = NuGetFramework.Parse(attributeValue!, _frameworkMappings); } var developmentDependency = PackagesConfig.BoolAttribute(package, PackagesConfig.developmentDependencyAttributeName); var requireReinstallation = PackagesConfig.BoolAttribute(package, PackagesConfig.RequireInstallAttributeName); var userInstalled = PackagesConfig.BoolAttribute(package, PackagesConfig.UserInstalledAttributeName, true); var entry = new PackageReference(new PackageIdentity(id!, semver!), targetFramework, userInstalled, developmentDependency, requireReinstallation, allowedVersions); packages.Add(entry); } // check if there are duplicate entries var duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase); PackageIdentity? lastIdentity = null; var comparer = PackageIdentity.Comparer; // Sort the list of packages and check for duplicates foreach (var package in packages.OrderBy(p => p.PackageIdentity, comparer)) { if (lastIdentity != null) { if (allowDuplicatePackageIds) { // Full compare if (comparer.Equals(package.PackageIdentity, lastIdentity)) { duplicates.Add(lastIdentity.ToString()); } } else if (string.Equals( package.PackageIdentity.Id, lastIdentity.Id, StringComparison.OrdinalIgnoreCase)) { // Id only compare duplicates.Add(lastIdentity.Id); } } lastIdentity = package.PackageIdentity; } if (duplicates.Count > 0) { throw new PackagesConfigReaderException(string.Format( CultureInfo.CurrentCulture, Strings.ErrorDuplicatePackages, string.Join(", ", duplicates))); } return packages; } } }