| File: PackageCreation\Authoring\ManifestMetadata.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 NuGet.Packaging.Core; using NuGet.Packaging.PackageCreation.Resources; using NuGet.Versioning; namespace NuGet.Packaging { /// <summary> /// Manifest (user created .nuspec) file metadata model /// </summary> public class ManifestMetadata : IPackageMetadata { private string? _minClientVersionString; private IEnumerable<string> _authors = Enumerable.Empty<string>(); private IEnumerable<string> _owners = Enumerable.Empty<string>(); private string? _iconUrl; private string? _licenseUrl; private string? _projectUrl; public ManifestMetadata() { } /// <summary> /// Constructs a ManifestMetadata instance from an IPackageMetadata instance /// </summary> public ManifestMetadata(IPackageMetadata copy) { Id = copy.Id?.Trim(); Version = copy.Version; Title = copy.Title?.Trim(); Authors = copy.Authors; Owners = copy.Owners; Tags = string.IsNullOrEmpty(copy.Tags) ? null : copy.Tags!.Trim(); Serviceable = copy.Serviceable; _licenseUrl = copy.LicenseUrl?.OriginalString; _projectUrl = copy.ProjectUrl?.OriginalString; _iconUrl = copy.IconUrl?.OriginalString; RequireLicenseAcceptance = copy.RequireLicenseAcceptance; EmitRequireLicenseAcceptance = (copy as PackageBuilder)?.EmitRequireLicenseAcceptance ?? true; Description = copy.Description?.Trim(); Copyright = copy.Copyright?.Trim(); Summary = copy.Summary?.Trim(); ReleaseNotes = copy.ReleaseNotes?.Trim(); Language = copy.Language?.Trim(); DependencyGroups = copy.DependencyGroups; FrameworkReferences = copy.FrameworkReferences; FrameworkReferenceGroups = copy.FrameworkReferenceGroups; PackageAssemblyReferences = copy.PackageAssemblyReferences; PackageTypes = copy.PackageTypes; MinClientVersionString = copy.MinClientVersion?.ToString(); ContentFiles = copy.ContentFiles; DevelopmentDependency = copy.DevelopmentDependency; Repository = copy.Repository; LicenseMetadata = copy.LicenseMetadata; Icon = copy.Icon; Readme = copy.Readme; } public string? MinClientVersionString { get { return _minClientVersionString; } set { Version? version = null; if (!String.IsNullOrEmpty(value) && !System.Version.TryParse(value, out version)) { throw new InvalidDataException(NuGetResources.Manifest_InvalidMinClientVersion); } _minClientVersionString = value; MinClientVersion = version; } } public Version? MinClientVersion { get; private set; } public string? Id { get; set; } public NuGetVersion? Version { get; set; } public string? Title { get; set; } public IEnumerable<string> Authors { get { return _authors; } set { _authors = value ?? Enumerable.Empty<string>(); } } public IEnumerable<string> Owners { get { return _owners; } set { _owners = value ?? Enumerable.Empty<string>(); } } // The (Icon/License/Project)Url properties have backing strings as we need to be able to differentiate // between the property not being set (valid) and set to an empty value (invalid). public void SetIconUrl(string? iconUrl) { _iconUrl = iconUrl; } public Uri? IconUrl { get { if (_iconUrl == null) { return null; } return new Uri(_iconUrl); } } public string? Icon { get; set; } public void SetLicenseUrl(string? licenseUrl) { _licenseUrl = licenseUrl; } public Uri? LicenseUrl { get { if (_licenseUrl == null) { return null; } return new Uri(_licenseUrl); } } public void SetProjectUrl(string? projectUrl) { _projectUrl = projectUrl; } public Uri? ProjectUrl { get { if (_projectUrl == null) { return null; } return new Uri(_projectUrl); } } public bool RequireLicenseAcceptance { get; set; } public bool EmitRequireLicenseAcceptance { get; set; } = true; public bool DevelopmentDependency { get; set; } public string? Description { get; set; } public string? Summary { get; set; } public string? ReleaseNotes { get; set; } public string? Copyright { get; set; } public string? Language { get; set; } public string? Tags { get; set; } public string? Readme { get; set; } public bool Serviceable { get; set; } public RepositoryMetadata? Repository { get; set; } private IEnumerable<PackageDependencyGroup> _dependencyGroups = []; public IEnumerable<PackageDependencyGroup> DependencyGroups { get { return _dependencyGroups; } set { _dependencyGroups = MergeDependencyGroups(value); } } public IEnumerable<FrameworkReferenceGroup> FrameworkReferenceGroups { get; set; } = []; public IEnumerable<FrameworkAssemblyReference> FrameworkReferences { get; set; } = []; private IEnumerable<PackageReferenceSet> _packageAssemblyReferences = []; public IEnumerable<PackageReferenceSet> PackageAssemblyReferences { get { return _packageAssemblyReferences; } set { _packageAssemblyReferences = MergePackageAssemblyReferences(value); } } private static IEnumerable<PackageReferenceSet> MergePackageAssemblyReferences(IEnumerable<PackageReferenceSet> referenceSets) { if (referenceSets == null) { return Enumerable.Empty<PackageReferenceSet>(); } var referenceSetGroups = referenceSets.GroupBy(set => set.TargetFramework); var groupedReferenceSets = referenceSetGroups.Select(group => new PackageReferenceSet(group.Key, group.SelectMany(g => g.References))) .ToList(); int nullTargetFrameworkIndex = groupedReferenceSets.FindIndex(set => set.TargetFramework == null); if (nullTargetFrameworkIndex > -1) { var nullFxReferenceSet = groupedReferenceSets[nullTargetFrameworkIndex]; groupedReferenceSets.RemoveAt(nullTargetFrameworkIndex); groupedReferenceSets.Insert(0, nullFxReferenceSet); } return groupedReferenceSets; } public IEnumerable<ManifestContentFiles> ContentFiles { get; set; } = new List<ManifestContentFiles>(); public IEnumerable<PackageType> PackageTypes { get; set; } = new List<PackageType>(); public LicenseMetadata? LicenseMetadata { get; set; } = null; private static IEnumerable<PackageDependencyGroup> MergeDependencyGroups(IEnumerable<PackageDependencyGroup> actualDependencyGroups) { if (actualDependencyGroups == null) { return Enumerable.Empty<PackageDependencyGroup>(); } var dependencyGroups = actualDependencyGroups.Select(CreatePackageDependencyGroup); // group the dependency sets with the same target framework together. var dependencySetGroups = dependencyGroups.GroupBy(set => set.TargetFramework); var groupedDependencySets = dependencySetGroups.Select(group => new PackageDependencyGroup(group.Key, new HashSet<PackageDependency>(group.SelectMany(g => g.Packages)))) .ToList(); // move the group with the any target framework (if any) to the front just for nicer display in UI int anyTargetFrameworkIndex = groupedDependencySets.FindIndex(set => set.TargetFramework.IsAny); if (anyTargetFrameworkIndex > -1) { var anyFxDependencySet = groupedDependencySets[anyTargetFrameworkIndex]; groupedDependencySets.RemoveAt(anyTargetFrameworkIndex); groupedDependencySets.Insert(0, anyFxDependencySet); } return groupedDependencySets; } private static PackageDependencyGroup CreatePackageDependencyGroup(PackageDependencyGroup dependencyGroup) { ISet<PackageDependency> dependencies; if (dependencyGroup.Packages == null) { dependencies = new HashSet<PackageDependency>(); } else { var dependenciesList = dependencyGroup.Packages.Select(dependency => new PackageDependency( dependency.Id.Trim(), dependency.VersionRange, dependency.Include, dependency.Exclude)).ToList(); dependencies = new HashSet<PackageDependency>(dependenciesList); } return new PackageDependencyGroup(dependencyGroup.TargetFramework, dependencies); } /// <summary> /// Checks that the metadata in the nuspec is enough to create a package /// </summary> /// <returns>A iterable collection with the validation error messages</returns> /// <remarks>Error codes are not associated with the validation error messages returned</remarks> public IEnumerable<string> Validate() { if (String.IsNullOrEmpty(Id)) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_RequiredMetadataMissing, "Id"); } else { if (Id!.Length > PackageIdValidator.MaxPackageIdLength) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_IdMaxLengthExceeded); } else if (!PackageIdValidator.IsValidPackageId(Id)) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidPackageId, Id); } } if (Version == null) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_RequiredMetadataMissing, "Version"); } if ((Authors == null || !Authors.Any(author => !String.IsNullOrEmpty(author))) && !PackageTypes.Contains(PackageType.SymbolsPackage)) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_RequiredMetadataMissing, "Authors"); } if (String.IsNullOrEmpty(Description)) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_RequiredMetadataMissing, "Description"); } if (_licenseUrl == String.Empty) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_UriCannotBeEmpty, "LicenseUrl"); } if (_iconUrl == String.Empty) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_UriCannotBeEmpty, "IconUrl"); } if (_projectUrl == String.Empty) { yield return String.Format(CultureInfo.CurrentCulture, NuGetResources.Manifest_UriCannotBeEmpty, "ProjectUrl"); } if (Icon == string.Empty) { yield return NuGetResources.IconMissingRequiredValue; } if (Readme == string.Empty) { yield return NuGetResources.ReadmeMissingRequiredValue; } if (RequireLicenseAcceptance) { if ((string.IsNullOrWhiteSpace(_licenseUrl) && LicenseMetadata == null)) { yield return NuGetResources.Manifest_RequireLicenseAcceptanceRequiresLicenseUrl; } if (!EmitRequireLicenseAcceptance) { yield return NuGetResources.Manifest_RequireLicenseAcceptanceRequiresEmit; } } if (_licenseUrl != null && LicenseMetadata != null && (string.IsNullOrWhiteSpace(_licenseUrl) || !LicenseUrl!.Equals(LicenseMetadata.LicenseUrl))) { yield return NuGetResources.Manifest_LicenseUrlCannotBeUsedWithLicenseMetadata; } } } }