예제 #1
0
 /// <summary>
 /// Gets package metadata from a the provided <see cref="NuspecReader"/> instance.
 /// </summary>
 /// <param name="nuspecReader">The </param>
 public static PackageMetadata FromNuspecReader(NuspecReader nuspecReader)
 {
     return(new PackageMetadata(
                nuspecReader.GetMetadata().ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
                nuspecReader.GetDependencyGroups(true),
                nuspecReader.GetFrameworkReferenceGroups(),
                nuspecReader.GetPackageTypes(),
                nuspecReader.GetMinClientVersion()
                ));
 }
예제 #2
0
        /// <summary>
        /// Gets package metadata from a the provided <see cref="NuspecReader"/> instance.
        /// </summary>
        /// <param name="nuspecReader">The <see cref="NuspecReader"/> instance used to read the <see cref="PackageMetadata"/></param>
        /// <param name="strict">
        /// Whether or not to be strict when reading the <see cref="NuspecReader"/>. This should be <code>true</code>
        /// on initial ingestion but false when a package that has already been accepted is being processed.</param>
        /// <exception cref="PackagingException">
        /// We default to use a strict version-check on dependency groups.
        /// When an invalid dependency version range is detected, a <see cref="PackagingException"/> will be thrown.
        /// </exception>
        public static PackageMetadata FromNuspecReader(NuspecReader nuspecReader, bool strict)
        {
            var strictNuspecReader = new StrictNuspecReader(nuspecReader.Xml);
            var metadataLookup     = strictNuspecReader.GetMetadataLookup();

            if (strict)
            {
                var duplicates = metadataLookup
                                 .Where(g => g.Count() > 1)
                                 .Select(g => g.Key)
                                 .ToList();

                if (duplicates.Any())
                {
                    throw new PackagingException(string.Format(
                                                     CoreStrings.Manifest_DuplicateMetadataElements,
                                                     string.Join("', '", duplicates)));
                }
            }

            // Reject invalid metadata element names. Today this only rejects element names that collide with
            // properties generated downstream.
            var metadataKeys = new HashSet <string>(metadataLookup.Select(g => g.Key));

            metadataKeys.IntersectWith(RestrictedMetadataElements);
            if (metadataKeys.Any())
            {
                throw new PackagingException(string.Format(
                                                 CoreStrings.Manifest_InvalidMetadataElements,
                                                 string.Join("', '", metadataKeys.OrderBy(x => x))));
            }

            // Reject non-boolean values for boolean metadata.
            foreach (var booleanName in BooleanMetadataElements)
            {
                foreach (var unparsedBoolean in metadataLookup[booleanName])
                {
                    if (!bool.TryParse(unparsedBoolean, out var parsedBoolean))
                    {
                        throw new PackagingException(string.Format(
                                                         CoreStrings.Manifest_InvalidBooleanMetadata,
                                                         booleanName));
                    }
                }
            }

            return(new PackageMetadata(
                       nuspecReader.GetMetadata().ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
                       nuspecReader.GetDependencyGroups(useStrictVersionCheck: strict),
                       nuspecReader.GetFrameworkReferenceGroups(),
                       nuspecReader.GetPackageTypes(),
                       nuspecReader.GetMinClientVersion(),
                       nuspecReader.GetRepositoryMetadata(),
                       nuspecReader.GetLicenseMetadata()));
        }
        private static void EnsurePackageCompatibility(
            NuGetProject nuGetProject,
            PackageIdentity packageIdentity,
            NuspecReader nuspecReader)
        {
            // Validate that the current version of NuGet satisfies the minVersion attribute specified in the .nuspec
            MinClientVersionUtility.VerifyMinClientVersion(nuspecReader);

            // Validate the package type. There must be zero package types or exactly one package
            // type that is one of the recognized package types.
            var packageTypes   = nuspecReader.GetPackageTypes();
            var identityString = $"{packageIdentity.Id} {packageIdentity.Version.ToNormalizedString()}";

            if (packageTypes.Count > 1)
            {
                throw new PackagingException(string.Format(
                                                 CultureInfo.CurrentCulture,
                                                 Strings.MultiplePackageTypesNotSupported,
                                                 identityString));
            }
            else if (packageTypes.Count == 1)
            {
                var packageType       = packageTypes[0];
                var packageTypeString = packageType.Name;
                if (packageType.Version != PackageType.EmptyVersion)
                {
                    packageTypeString += " " + packageType.Version;
                }

                var projectName = NuGetProject.GetUniqueNameOrName(nuGetProject);

                if (packageType == PackageType.Legacy ||   // Added for "quirks mode", but not yet fully implemented.
                    packageType == PackageType.Dependency) // A package explicitly stated as a dependency.
                {
                    // These types are always acceptable.
                }
                else if (nuGetProject is ProjectKNuGetProjectBase &&
                         packageType == PackageType.DotnetCliTool)
                {
                    // ProjectKNuGetProjectBase projects are .NET Core (both "dotnet" and "dnx").
                    // .NET CLI tools are support for "dotnet" projects. The projects eventually
                    // call into INuGetPackageManager, which is not implemented by NuGet. This code
                    // will make the decision of how to install the .NET CLI tool package.
                }
                else
                {
                    throw new PackagingException(string.Format(
                                                     CultureInfo.CurrentCulture,
                                                     Strings.UnsupportedPackageType,
                                                     identityString,
                                                     packageTypeString,
                                                     projectName));
                }
            }
        }
예제 #4
0
        private static void EnsurePackageCompatibility(
            NuGetProject nuGetProject,
            PackageIdentity packageIdentity,
            NuspecReader nuspecReader)
        {
            // Validate that the current version of NuGet satisfies the minVersion attribute specified in the .nuspec
            MinClientVersionUtility.VerifyMinClientVersion(nuspecReader);

            // Validate the package type. There must be zero package types or exactly one package
            // type that is one of the recognized package types.
            var packageTypes   = nuspecReader.GetPackageTypes();
            var identityString = $"{packageIdentity.Id} {packageIdentity.Version.ToNormalizedString()}";

            if (packageTypes.Count > 1)
            {
                throw new PackagingException(string.Format(
                                                 CultureInfo.CurrentCulture,
                                                 Strings.MultiplePackageTypesNotSupported,
                                                 identityString));
            }
            else if (packageTypes.Count == 1)
            {
                var packageType       = packageTypes[0];
                var packageTypeString = packageType.Name;
                if (packageType.Version != PackageType.EmptyVersion)
                {
                    packageTypeString += " " + packageType.Version;
                }

                var projectName = NuGetProject.GetUniqueNameOrName(nuGetProject);

                if (packageType == PackageType.Legacy ||   // Added for "quirks mode", but not yet fully implemented.
                    packageType == PackageType.Dependency) // A package explicitly stated as a dependency.
                {
                    // These types are always acceptable.
                }
                else
                {
                    throw new PackagingException(string.Format(
                                                     CultureInfo.CurrentCulture,
                                                     Strings.UnsupportedPackageType,
                                                     identityString,
                                                     packageTypeString,
                                                     projectName));
                }
            }
        }
        private static List <PackageType> GetPackageTypes(NuspecReader nuspec)
        {
            var packageTypes = nuspec
                               .GetPackageTypes()
                               .Select(t => new PackageType
            {
                Name    = t.Name,
                Version = t.Version.ToString()
            })
                               .ToList();

            // Default to the standard "dependency" package type if no types were found.
            if (packageTypes.Count == 0)
            {
                packageTypes.Add(new PackageType
                {
                    Name    = NuGetPackageType.Dependency.Name,
                    Version = NuGetPackageType.Dependency.Version.ToString(),
                });
            }

            return(packageTypes);
        }
        /// <summary>
        /// This method combines the logic used in restore operations to make a determination about the TFM supported by the package.
        /// We have curated a set of compatibility requirements for our needs in NuGet.org. The client logic can be found here:
        /// https://github.com/NuGet/NuGet.Client/blob/63255047fe7052cc33b763356ff995d9166f719e/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L252-L294
        /// https://github.com/NuGet/NuGet.Client/blob/63255047fe7052cc33b763356ff995d9166f719e/src/NuGet.Core/NuGet.Commands/RestoreCommand/CompatibilityChecker.cs#L439-L442
        /// ...and our combination of these elements is below.
        /// The logic is essentially this:
        /// - Determine whether we're looking at a tools package. In this case we will use tools "pattern sets" (collections of file patterns
        ///   defined in <see cref="ManagedCodeConventions" />) to assess which frameworks are targeted by the package.
        /// - If this isn't a tools package, we look for build-time, runtime, content and resource file patterns
        /// For added details on the various cases, see unit tests targeting this method.
        /// </summary>
        public virtual IEnumerable <NuGetFramework> GetSupportedFrameworks(NuspecReader nuspecReader, IList <string> packageFiles)
        {
            var supportedTFMs = Enumerable.Empty <NuGetFramework>();

            if (packageFiles != null && packageFiles.Any() && nuspecReader != null)
            {
                // Setup content items for analysis
                var items = new ContentItemCollection();
                items.Load(packageFiles);
                var runtimeGraph = new RuntimeGraph();
                var conventions  = new ManagedCodeConventions(runtimeGraph);

                // Let's test for tools packages first--they're a special case
                var groups       = Enumerable.Empty <ContentItemGroup>();
                var packageTypes = nuspecReader.GetPackageTypes();
                if (packageTypes.Count == 1 && (packageTypes[0] == PackageType.DotnetTool ||
                                                packageTypes[0] == PackageType.DotnetCliTool))
                {
                    // Only a package that is a tool package (and nothing else) will be matched against tools pattern set
                    groups = items.FindItemGroups(conventions.Patterns.ToolsAssemblies);
                }
                else
                {
                    // Gather together a list of pattern sets indicating the kinds of packages we wish to evaluate
                    var patterns = new[]
                    {
                        conventions.Patterns.CompileRefAssemblies,
                        conventions.Patterns.CompileLibAssemblies,
                        conventions.Patterns.RuntimeAssemblies,
                        conventions.Patterns.ContentFiles,
                        conventions.Patterns.ResourceAssemblies,
                    };

                    // Add MSBuild to this list, but we need to ensure we have package assets before they make the cut.
                    // A series of files in the right places won't matter if there's no {id}.props|targets.
                    var msbuildPatterns = new[]
                    {
                        conventions.Patterns.MSBuildFiles,
                        conventions.Patterns.MSBuildMultiTargetingFiles,
                    };

                    // We'll create a set of "groups" --these are content items which satisfy file pattern sets
                    var standardGroups = patterns
                                         .SelectMany(p => items.FindItemGroups(p));

                    // Filter out MSBuild assets that don't match the package ID and append to groups we already have
                    var packageId     = nuspecReader.GetId();
                    var msbuildGroups = msbuildPatterns
                                        .SelectMany(p => items.FindItemGroups(p))
                                        .Where(g => HasBuildItemsForPackageId(g.Items, packageId));
                    groups = standardGroups.Concat(msbuildGroups);
                }

                // Now that we have a collection of groups which have made it through the pattern set filter, let's transform them into TFMs
                supportedTFMs = groups
                                .SelectMany(p => p.Properties)
                                .Where(pair => pair.Key == ManagedCodeConventions.PropertyNames.TargetFrameworkMoniker)
                                .Select(pair => pair.Value)
                                .Cast <NuGetFramework>()
                                .Distinct();
            }

            return(supportedTFMs);
        }