private static string GetNameString(NuGetFramework framework, string runtime)
        {
            string frameworkString;

            // We already shipped net5.0 being listed as .NETCoreApp,Version=5.0, so it would be a breaking change
            // to change it. Similarly for all earlier framework identifiers.
            // Since net5.0-windows didn't work properly, we can use the "friendly" (folder name) for net5 with a platform.
            // For net6 and higher, always use friendly folder format, since this is the preferred customer-facing
            // format (from dotnet/design's net5 spec).
            // Packages lock files are checked into source control, hence customers will see it in their diffs.
            if (string.Equals(framework.Framework, FrameworkConstants.FrameworkIdentifiers.NetCoreApp, StringComparison.OrdinalIgnoreCase) &&
                (
                    (framework.Version.Major >= 6) ||
                    (framework.Version.Major == 5 && framework.HasPlatform)
                )
                )
            {
                frameworkString = framework.ToString();
            }
            else
            {
                frameworkString = framework.DotNetFrameworkName;
            }

            if (!string.IsNullOrEmpty(runtime))
            {
                return($"{frameworkString}/{runtime}");
            }

            return(frameworkString);
        }
Ejemplo n.º 2
0
    private static bool IsKnownUnsupportedPlatform(NuGetFramework target)
    {
        var platforms = new[] {
            ".NETCore,Version=v5.0",
            ".NETFramework,Version=v4.6.3",
            ".NETPlatform,Version=v5.0",
            ".NETPlatform,Version=v5.4",
            ".NETPortable,Version=v0.0,Profile=aspnetcore50+net45+win8+wp8+wpa81",
            ".NETPortable,Version=v0.0,Profile=net40+sl4+win8",
            ".NETPortable,Version=v0.0,Profile=net40+sl4+win8+wp71+wpa81",
            ".NETPortable,Version=v0.0,Profile=net40+sl4+win8+wp8+wpa81",
            ".NETPortable,Version=v0.0,Profile=net40+win8+wp8+wpa81",
            ".NETPortable,Version=v0.0,Profile=net45+netcore45+wp8+wp81+wpa81",
            ".NETPortable,Version=v0.0,Profile=net45+wp8+wpa81",
            ".NETPortable,Version=v0.0,Profile=net451+win8+wp8+wpa81",
            ".NETPortable,Version=v0.0,Profile=win8+wp8+wpa81",
            ".NETPortable,Version=v0.0,Profile=win8+wpa81",
            "Any,Version=v0.0",
            "ASP.NETCore,Version=v5.0",
            "DNX,Version=v4.5.1",
            "DNXCore,Version=v5.0",
            "native,Version=v0.0",
            "Silverlight,Version=v4.0",
            "Silverlight,Version=v4.0,Profile=WindowsPhone71",
            "Silverlight,Version=v5.0",
            "WindowsPhone,Version=v8.0",
            "WindowsPhoneApp,Version=v8.1",
        };

        var targetString = target.ToString();

        return(platforms.Any(p => string.Equals(p, targetString, StringComparison.OrdinalIgnoreCase)));
    }
Ejemplo n.º 3
0
        private void EnsureToolJsonDepsFileExists(
            LibraryRange toolLibrary,
            LockFile toolLockFile,
            string depsPath)
        {
            if (!File.Exists(depsPath))
            {
                var projectContext = new ProjectContextBuilder()
                                     .WithLockFile(toolLockFile)
                                     .WithTargetFramework(s_toolPackageFramework.ToString())
                                     .Build();

                var exporter = projectContext.CreateExporter(Constants.DefaultConfiguration);

                var dependencyContext = new DependencyContextBuilder()
                                        .Build(null,
                                               null,
                                               exporter.GetAllExports(),
                                               true,
                                               s_toolPackageFramework,
                                               string.Empty);

                using (var fileStream = File.Create(depsPath))
                {
                    var dependencyContextWriter = new DependencyContextWriter();

                    dependencyContextWriter.Write(dependencyContext, fileStream);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Get project's target frameworks
        /// </summary>
        /// <param name="project"></param>
        /// <returns></returns>
        public static IEnumerable <string> GetProjectTargetFrameworks(NuGetProject project)
        {
            List <string>  frameworks     = new List <string>();
            NuGetFramework nugetFramework = project.GetMetadata <NuGetFramework>(NuGetProjectMetadataKeys.TargetFramework);

            if (nugetFramework != null)
            {
                string framework = nugetFramework.ToString();
                frameworks.Add(framework);
            }
            return(frameworks);
        }
Ejemplo n.º 5
0
        private IEnumerable <PackageAsset> GetTestAssets(NuGetFramework fx, string runtimeId)
        {
            var targetKey = string.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";

            Target target = null;

            if (!_report.Targets.TryGetValue(targetKey, out target))
            {
                Log.LogError($"Could not find target {targetKey} in {ReportFile}.");
                return(Enumerable.Empty <PackageAsset>());
            }

            return(string.IsNullOrEmpty(Runtime) ? target.CompileAssets : target.RuntimeAssets);
        }
Ejemplo n.º 6
0
        // Need to unit test this, so public
        public void GenerateDepsJsonFile(
            LockFile toolLockFile,
            string depsPath)
        {
            Reporter.Verbose.WriteLine($"Generating deps.json at: {depsPath}");

            var projectContext = new ProjectContextBuilder()
                                 .WithLockFile(toolLockFile)
                                 .WithTargetFramework(s_toolPackageFramework.ToString())
                                 .Build();

            var exporter = projectContext.CreateExporter(Constants.DefaultConfiguration);

            var dependencyContext = new DependencyContextBuilder()
                                    .Build(null,
                                           null,
                                           exporter.GetAllExports(),
                                           true,
                                           s_toolPackageFramework,
                                           string.Empty);

            var tempDepsFile = Path.GetTempFileName();

            using (var fileStream = File.Open(tempDepsFile, FileMode.Open, FileAccess.Write))
            {
                var dependencyContextWriter = new DependencyContextWriter();

                dependencyContextWriter.Write(dependencyContext, fileStream);
            }

            try
            {
                File.Copy(tempDepsFile, depsPath);
            }
            catch (Exception e)
            {
                Reporter.Verbose.WriteLine($"unable to generate deps.json, it may have been already generated: {e.Message}");
            }
            finally
            {
                try
                {
                    File.Delete(tempDepsFile);
                }
                catch (Exception e2)
                {
                    Reporter.Verbose.WriteLine($"unable to delete temporary deps.json file: {e2.Message}");
                }
            }
        }
        public CentralTransitiveDependencyGroup(NuGetFramework framework, IEnumerable <LibraryDependency> transitiveDependencies)
        {
            if (framework == null)
            {
                throw new ArgumentNullException(nameof(framework));
            }
            if (transitiveDependencies == null)
            {
                throw new ArgumentNullException(nameof(transitiveDependencies));
            }

            FrameworkName          = framework.ToString();
            TransitiveDependencies = transitiveDependencies;
        }
        /// <summary>
        /// Generates a table in markdown that lists the API version supported by
        /// various packages at all levels of NETStandard.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            if (PackageReports == null || PackageReports.Length == 0)
            {
                Log.LogError("PackageReports argument must be specified");
                return(false);
            }

            if (TargetMoniker == null || TargetMoniker.Length == 0)
            {
                Log.LogError("TargetMoniker argument must be specified");
                return(false);
            }

            NuGetFramework fx = NuGetFramework.Parse(TargetMoniker);

            string targetString = String.IsNullOrEmpty(TargetRuntime) ? fx.ToString() : $"{fx}/{TargetRuntime}";

            var compileAssets = new List <ITaskItem>();
            var runtimeAssets = new List <ITaskItem>();
            var nativeAssets  = new List <ITaskItem>();
            var buildProjects = new List <BuildProject>();

            foreach (var reportPath in PackageReports)
            {
                var report = PackageReport.Load(reportPath);

                Target target = null;
                if (report.Targets.TryGetValue(targetString, out target))
                {
                    compileAssets.AddRange(target.CompileAssets.Select(c => ItemFromApplicableAsset(c, report.Id, report.Version)));
                    buildProjects.AddRange(target.CompileAssets.Select(c => c.SourceProject).Where(bp => bp != null));
                    runtimeAssets.AddRange(target.RuntimeAssets.Select(r => ItemFromApplicableAsset(r, report.Id, report.Version)));
                    buildProjects.AddRange(target.RuntimeAssets.Select(r => r.SourceProject).Where(bp => bp != null));
                    nativeAssets.AddRange(target.NativeAssets.Select(r => ItemFromApplicableAsset(r, report.Id, report.Version)));
                    buildProjects.AddRange(target.NativeAssets.Select(r => r.SourceProject).Where(bp => bp != null));
                }
                else
                {
                    Log.LogMessage($"No assets found for '{report.Id}' applicable to '{targetString}'.");
                }
            }

            CompileAssets = compileAssets.ToArray();
            RuntimeAssets = runtimeAssets.ToArray();
            NativeAssets  = nativeAssets.ToArray();
            BuildProjects = buildProjects.Distinct().Select(bp => bp.ToItem()).ToArray();

            return(!Log.HasLoggedErrors);
        }
        /// <summary>
        /// Takes a NuGet framework folder name and returns the .NET FrameworkName
        /// </summary>
        public static FrameworkName GetFrameworkName(string nugetFramework)
        {
            // TODO: Call a non-portable version of Frameworks to do this work instead.

            FrameworkName framework = null;

            NuGetFramework nf = NuGetFramework.Parse(nugetFramework);

            if (nf.IsSpecificFramework)
            {
                framework = new FrameworkName(nf.ToString());
            }

            return(framework);
        }
Ejemplo n.º 10
0
        private async Task <SourcePackageDependencyInfo> CacheResolvePackage(NuGetFactory factory, PackageIdentity package, NuGetFramework fx)
        {
            string key = String.Format(@"{0}-{1}", package.ToString(), fx.ToString());

            if (base.IsInCache <SourcePackageDependencyInfo>("CacheResolvePackage", key))
            {
                return(Get <SourcePackageDependencyInfo>("CacheResolvePackage", key));
            }
            else
            {
                var depResource = await factory.GetDependency();

                var output = await depResource.ResolvePackage(package, fx, CancellationToken.None);

                return(Get <SourcePackageDependencyInfo>("CacheResolvePackage", key, () => { return output; }));
            }
        }
Ejemplo n.º 11
0
        private static string SynthesizeFrameworkFriendlyName(NuGetFramework targetFramework)
        {
            // Names are not present in the RedistList.xml file for older frameworks or on Mono
            // We do some custom version string rendering to match how net40 is rendered (.NET Framework 4)
            if (targetFramework.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.Net))
            {
                string versionString = targetFramework.Version.Minor == 0 ?
                                       targetFramework.Version.Major.ToString() :
                                       GetDisplayVersion(targetFramework).ToString();

                string profileString = string.IsNullOrEmpty(targetFramework.Profile) ?
                                       string.Empty :
                                       $" {targetFramework.Profile} Profile";
                return(".NET Framework " + versionString + profileString);
            }
            return(targetFramework.ToString());
        }
Ejemplo n.º 12
0
        private bool ValidateTools(PackageSpec spec)
        {
            // Skip this check if there are no tools at all.
            if (ProjectFileToolGroups.Count == 0 && spec.Tools.Count == 0)
            {
                return(true);
            }

            // The lock file should only contain tools for a single framework
            if (ProjectFileToolGroups.Count != 1)
            {
                return(false);
            }

            var group = ProjectFileToolGroups.First();

            if (!StringComparer.OrdinalIgnoreCase.Equals(
                    group.FrameworkName,
                    ToolFramework.ToString()))
            {
                return(false);
            }

            var lockDependencies = group
                                   .Dependencies
                                   .OrderBy(x => x, StringComparer.Ordinal);

            var specDependencies = spec.Tools
                                   .Select(x => x.LibraryRange.ToLockFileDependencyGroupString())
                                   .OrderBy(x => x, StringComparer.Ordinal);

            if (!specDependencies.SequenceEqual(lockDependencies))
            {
                return(false);
            }

            return(true);
        }
Ejemplo n.º 13
0
        public string GetFriendlyNuGetFramework(NuGetFramework targetFramework)
        {
            // We don't have a friendly name for this anywhere on the machine so hard code it
            string friendlyName = targetFramework.Framework;

            if (Equals(targetFramework.Framework, FrameworkConstants.CommonFrameworks.DnxCore))
            {
                return("DNX Core " + targetFramework.Version.ToString());
            }
            else if (Equals(targetFramework.Framework, FrameworkConstants.CommonFrameworks.Dnx))
            {
                return("DNX " + targetFramework.Version.ToString());
            }

            var information = _cache.GetOrAdd(targetFramework, GetFrameworkInformation);

            if (information == null)
            {
                return(targetFramework.ToString());
            }

            return(information.Name);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Validates the latest nuget package doesnot drop any target framework/rid and does not introduce any breaking changes.
        /// </summary>
        /// <param name="package">Nuget Package that needs to be validated.</param>
        public void Validate(Package package)
        {
            if (_runApiCompat)
            {
                _apiCompatRunner.InitializePaths(_baselinePackage.PackagePath, package.PackagePath);
            }

            foreach (ContentItem baselineCompileTimeAsset in _baselinePackage.RefAssets)
            {
                NuGetFramework baselineTargetFramework = (NuGetFramework)baselineCompileTimeAsset.Properties["tfm"];
                ContentItem    latestCompileTimeAsset  = package.FindBestCompileAssetForFramework(baselineTargetFramework);
                if (latestCompileTimeAsset == null)
                {
                    _log.LogError(
                        new Suppression {
                        DiagnosticId = DiagnosticIds.TargetFrameworkDropped, Target = baselineTargetFramework.ToString()
                    },
                        DiagnosticIds.TargetFrameworkDropped,
                        Resources.MissingTargetFramework,
                        baselineTargetFramework.ToString());
                }
                else if (_runApiCompat)
                {
                    string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineCompileTimeAsset.Path, latestCompileTimeAsset.Path, _baselinePackage.Version, package.Version);
                    _apiCompatRunner.QueueApiCompatFromContentItem(package.PackageId, baselineCompileTimeAsset, latestCompileTimeAsset, header, isBaseline: true);
                }
            }

            foreach (ContentItem baselineRuntimeAsset in _baselinePackage.RuntimeAssets)
            {
                NuGetFramework baselineTargetFramework = (NuGetFramework)baselineRuntimeAsset.Properties["tfm"];
                ContentItem    latestRuntimeAsset      = package.FindBestRuntimeAssetForFramework(baselineTargetFramework);
                if (latestRuntimeAsset == null)
                {
                    _log.LogError(
                        new Suppression {
                        DiagnosticId = DiagnosticIds.TargetFrameworkDropped, Target = baselineTargetFramework.ToString()
                    },
                        DiagnosticIds.TargetFrameworkDropped,
                        Resources.MissingTargetFramework,
                        baselineTargetFramework.ToString());
                }
                else
                {
                    if (_runApiCompat)
                    {
                        string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineRuntimeAsset.Path, latestRuntimeAsset.Path, _baselinePackage.Version, package.Version);
                        _apiCompatRunner.QueueApiCompatFromContentItem(package.PackageId, baselineRuntimeAsset, latestRuntimeAsset, header, isBaseline: true);
                    }
                }
            }

            foreach (ContentItem baselineRuntimeSpecificAsset in _baselinePackage.RuntimeSpecificAssets)
            {
                NuGetFramework baselineTargetFramework    = (NuGetFramework)baselineRuntimeSpecificAsset.Properties["tfm"];
                string         baselineRid                = (string)baselineRuntimeSpecificAsset.Properties["rid"];
                ContentItem    latestRuntimeSpecificAsset = package.FindBestRuntimeAssetForFrameworkAndRuntime(baselineTargetFramework, baselineRid);
                if (latestRuntimeSpecificAsset == null)
                {
                    _log.LogError(
                        new Suppression {
                        DiagnosticId = DiagnosticIds.TargetFrameworkAndRidPairDropped, Target = baselineTargetFramework.ToString() + "-" + baselineRid
                    },
                        DiagnosticIds.TargetFrameworkAndRidPairDropped,
                        Resources.MissingTargetFrameworkAndRid,
                        baselineTargetFramework.ToString(),
                        baselineRid);
                }
                else
                {
                    if (_runApiCompat)
                    {
                        string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineRuntimeSpecificAsset.Path, latestRuntimeSpecificAsset.Path, _baselinePackage.Version, package.Version);
                        _apiCompatRunner.QueueApiCompatFromContentItem(package.PackageId, baselineRuntimeSpecificAsset, latestRuntimeSpecificAsset, header, isBaseline: true);
                    }
                }
            }

            _apiCompatRunner.RunApiCompat();
        }
        public static string ToFriendlyName(this NuGetFramework frameworkName, bool allowRecurseProfile = true)
        {
            if (frameworkName == null)
            {
                throw new ArgumentNullException(nameof(frameworkName));
            }

            // Defer to the NuGet client logic for displaying .NET 5 frameworks. This aligns with Visual Studio package
            // management UI.
            var isNet5Era = frameworkName.Version.Major >= 5 &&
                            StringComparer.OrdinalIgnoreCase.Equals(FrameworkConstants.FrameworkIdentifiers.NetCoreApp, frameworkName.Framework);

            if (isNet5Era)
            {
                return(frameworkName.ToString());
            }

            var sb = new StringBuilder();

            if (String.Equals(frameworkName.Framework, ".NETPortable", StringComparison.OrdinalIgnoreCase))
            {
                sb.Append("Portable Class Library");

                // Recursively parse the profile
                if (allowRecurseProfile)
                {
                    sb.Append(" (");

                    var profiles = frameworkName.GetShortFolderName()
                                   .Replace("portable-", string.Empty)
                                   .Replace("portable40-", string.Empty)
                                   .Replace("portable45-", string.Empty)
                                   .Split('+');

                    sb.Append(String.Join(", ",
                                          profiles.Select(s => NuGetFramework.Parse(s).ToFriendlyName(allowRecurseProfile: false))));

                    sb.Append(")");
                }
            }
            else
            {
                string version = null;
                if (frameworkName.Version.Build == 0)
                {
                    version = frameworkName.Version.ToString(2);
                }
                else if (frameworkName.Version.Revision == 0)
                {
                    version = frameworkName.Version.ToString(3);
                }
                else
                {
                    version = frameworkName.Version.ToString();
                }

                sb.AppendFormat("{0} {1}", frameworkName.Framework, version);
                if (!String.IsNullOrEmpty(frameworkName.Profile))
                {
                    sb.AppendFormat(" {0}", frameworkName.Profile);
                }
            }
            return(sb.ToString());
        }
        /// <summary>
        /// Target framework versions returned from ResolvePackageDependenciesDesignTime use four part version numbers
        /// so we cannot use TargetFrameworkMoniker as the dictionary key since this will not always match the
        /// project's target framework. Instead generate a NuGetFramework and use that as the key since it will
        /// normalize the version numbers.
        /// </summary>
        static string GetMappingKey(TargetFrameworkMoniker framework)
        {
            NuGetFramework nugetFramework = NuGetFramework.ParseFrameworkName(framework.ToString(), DefaultFrameworkNameProvider.Instance);

            return(nugetFramework.ToString());
        }
Ejemplo n.º 17
0
        private void ValidateSupport()
        {
            var runtimeFxSuppression = GetSuppressionValues(Suppression.PermitRuntimeTargetMonikerMismatch) ?? new HashSet <string>();
            ValidationReport report  = null;

            if (ValidationReport != null)
            {
                report = CreateValidationReport();
            }

            // validate support for each TxM:RID
            foreach (var validateFramework in _frameworks.Values)
            {
                NuGetFramework fx = validateFramework.Framework;
                Version        supportedVersion = validateFramework.SupportedVersion;

                var  compileAssetPaths = _resolver.ResolveCompileAssets(fx, PackageId);
                bool hasCompileAsset, hasCompilePlaceHolder;
                NuGetAssetResolver.ExamineAssets(Log, "Compile", ContractName, fx.ToString(), compileAssetPaths, out hasCompileAsset, out hasCompilePlaceHolder);

                if (report != null && validateFramework.RuntimeIds.All(rid => !String.IsNullOrEmpty(rid)))
                {
                    // Add Framework only (compile) target if all RIDs are non-empty.
                    // This acts as a compile target for a framework that requires a RID for runtime.
                    var reportTarget = new Target()
                    {
                        Framework     = fx.ToString(),
                        RuntimeID     = null,
                        CompileAssets = compileAssetPaths.Where(c => !NuGetAssetResolver.IsPlaceholder(c)).Select(c => GetPackageAssetFromTargetPath(c)).ToArray()
                    };
                    report.Targets.Add(fx.ToString(), reportTarget);
                }

                // resolve/test for each RID associated with this framework.
                foreach (string runtimeId in validateFramework.RuntimeIds)
                {
                    string target            = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";
                    var    runtimeAssetPaths = _resolver.ResolveRuntimeAssets(fx, runtimeId);

                    bool hasRuntimeAsset, hasRuntimePlaceHolder;
                    NuGetAssetResolver.ExamineAssets(Log, "Runtime", ContractName, target, runtimeAssetPaths, out hasRuntimeAsset, out hasRuntimePlaceHolder);

                    if (null == supportedVersion)
                    {
                        // Contract should not be supported on this platform.
                        bool permitImplementation = HasSuppression(Suppression.PermitImplementation, target);

                        if (hasCompileAsset && (hasRuntimeAsset & !permitImplementation))
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has both compile and runtime assets.");
                        }
                        else if (hasRuntimeAsset & !permitImplementation)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has runtime assets.");
                        }

                        if (hasRuntimePlaceHolder && hasCompilePlaceHolder)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has placeholders for both compile and runtime which will permit the package to install.");
                        }
                    }
                    else
                    {
                        if (report != null)
                        {
                            var reportTarget = new Target()
                            {
                                Framework     = fx.ToString(),
                                RuntimeID     = runtimeId,
                                CompileAssets = compileAssetPaths.Where(c => !NuGetAssetResolver.IsPlaceholder(c)).Select(c => GetPackageAssetFromTargetPath(c)).ToArray(),
                                RuntimeAssets = runtimeAssetPaths.Where(r => !NuGetAssetResolver.IsPlaceholder(r)).Select(r => GetPackageAssetFromTargetPath(r)).ToArray()
                            };
                            report.Targets.Add(target, reportTarget);
                        }

                        if (validateFramework.IsInbox)
                        {
                            if (!hasCompileAsset && !hasCompilePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for compile-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasCompileAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a reference assemblies: {String.Join(", ", compileAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }

                            if (!hasRuntimeAsset && !hasRuntimePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for run-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasRuntimeAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a implementation assemblies: {String.Join(", ", runtimeAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                        }
                        else
                        {
                            Version referenceAssemblyVersion = null;
                            if (!hasCompileAsset)
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no compile assets.");
                            }
                            else
                            {
                                var referenceAssemblies = compileAssetPaths.Where(IsDll);

                                if (referenceAssemblies.Count() > 1)
                                {
                                    Log.LogError($"{ContractName} should only contain a single compile asset for {target}.");
                                }

                                foreach (var referenceAssembly in referenceAssemblies)
                                {
                                    referenceAssemblyVersion = _targetPathToPackageItem[referenceAssembly].Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, referenceAssemblyVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {referenceAssembly} was found to support {referenceAssemblyVersion?.ToString() ?? "<unknown version>"}.");
                                    }
                                }
                            }

                            if (!hasRuntimeAsset && !FrameworkUtilities.IsGenerationMoniker(validateFramework.Framework))
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no runtime assets.");
                            }
                            else
                            {
                                var implementationAssemblies = runtimeAssetPaths.Where(IsDll);

                                Dictionary <string, string> implementationFiles = new Dictionary <string, string>();
                                foreach (var implementationAssembly in implementationAssemblies)
                                {
                                    var     packageItem           = _targetPathToPackageItem[implementationAssembly];
                                    Version implementationVersion = packageItem.Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {implementationAssembly} was found to support {implementationVersion?.ToString() ?? "<unknown version>"}.");
                                    }

                                    // Previously we only permitted compatible mismatch if Suppression.PermitHigherCompatibleImplementationVersion was specified
                                    // this is a permitted thing on every framework but desktop (which requires exact match to ensure bindingRedirects exist)
                                    // Now make this the default, we'll check desktop, where it matters, more strictly
                                    if (referenceAssemblyVersion != null &&
                                        !VersionUtility.IsCompatibleApiVersion(referenceAssemblyVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} has mismatched compile ({referenceAssemblyVersion}) and runtime ({implementationVersion}) versions on {target}.");
                                    }

                                    if (fx.Framework == FrameworkConstants.FrameworkIdentifiers.Net &&
                                        !referenceAssemblyVersion.Equals(implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} has a higher runtime version ({implementationVersion}) than compile version ({referenceAssemblyVersion}) on .NET Desktop framework {target}.  This will break bindingRedirects.");
                                    }

                                    string fileName = Path.GetFileName(implementationAssembly);

                                    if (implementationFiles.ContainsKey(fileName))
                                    {
                                        Log.LogError($"{ContractName} includes both {implementationAssembly} and {implementationFiles[fileName]} an on {target} which have the same name and will clash when both packages are used.");
                                    }
                                    else
                                    {
                                        implementationFiles[fileName] = implementationAssembly;
                                    }

                                    if (packageItem.TargetFramework != fx && !runtimeFxSuppression.Contains(fx.ToString()))
                                    {
                                        // the selected asset wasn't an exact framework match, let's see if we have an exact match in any other runtime asset.
                                        var matchingFxAssets = _targetPathToPackageItem.Values.Where(i => i.TargetFramework == fx && // exact framework
                                                                                                                                     // Same file
                                                                                                     Path.GetFileName(i.TargetPath).Equals(fileName, StringComparison.OrdinalIgnoreCase) &&
                                                                                                                                     // Is implementation
                                                                                                     (i.TargetPath.StartsWith("lib") || i.TargetPath.StartsWith("runtimes")) &&
                                                                                                                                     // is not the same source file as was already selected
                                                                                                     i.SourcePath != packageItem.SourcePath);

                                        if (matchingFxAssets.Any())
                                        {
                                            Log.LogError($"When targeting {target} {ContractName} will use {implementationAssembly} which targets {packageItem.TargetFramework.GetShortFolderName()}  but {String.Join(";", matchingFxAssets.Select(i => i.TargetPath))} targets {fx.GetShortFolderName()} specifically.");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // Set output items
            AllSupportedFrameworks = _frameworks.Values.Where(fx => fx.SupportedVersion != null).Select(fx => fx.ToItem()).OrderBy(i => i.ItemSpec).ToArray();

            if (!String.IsNullOrEmpty(ValidationReport))
            {
                report.Save(ValidationReport);
            }
        }
Ejemplo n.º 18
0
 private static JToken WriteFrameworkName(NuGetFramework item)
 {
     return(item != null ? new JValue(item.ToString()) : JValue.CreateNull());
 }
Ejemplo n.º 19
0
        private void ValidateSupport()
        {
            // validate support for each TxM:RID
            foreach (var validateFramework in _frameworks.Values)
            {
                NuGetFramework fx = validateFramework.Framework;
                Version        supportedVersion = validateFramework.SupportedVersion;

                var  compileAssetPaths = _resolver.ResolveCompileAssets(fx, PackageId);
                bool hasCompileAsset, hasCompilePlaceHolder;
                ExamineAssets("Compile", ContractName, fx.ToString(), compileAssetPaths, out hasCompileAsset, out hasCompilePlaceHolder);

                // resolve/test for each RID associated with this framework.
                foreach (string runtimeId in validateFramework.RuntimeIds)
                {
                    string target            = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";
                    var    runtimeAssetPaths = _resolver.ResolveRuntimeAssets(fx, runtimeId);

                    bool hasRuntimeAsset, hasRuntimePlaceHolder;
                    ExamineAssets("Runtime", ContractName, target, runtimeAssetPaths, out hasRuntimeAsset, out hasRuntimePlaceHolder);

                    if (null == supportedVersion)
                    {
                        // Contract should not be supported on this platform.
                        bool permitImplementation = HasSuppression(Suppression.PermitImplementation, target);

                        if (hasCompileAsset && (hasRuntimeAsset & !permitImplementation))
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has both compile and runtime assets.");
                        }
                        else if (hasRuntimeAsset & !permitImplementation)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has runtime assets.");
                        }

                        if (hasRuntimePlaceHolder && hasCompilePlaceHolder)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has placeholders for both compile and runtime which will permit the package to install.");
                        }
                    }
                    else
                    {
                        if (validateFramework.IsInbox)
                        {
                            if (!hasCompileAsset && !hasCompilePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for compile-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasCompileAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a reference assemblies: {String.Join(", ", compileAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }

                            if (!hasRuntimeAsset && !hasRuntimePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for run-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasRuntimeAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a implementation assemblies: {String.Join(", ", runtimeAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                        }
                        else
                        {
                            Version referenceAssemblyVersion = null;
                            if (!hasCompileAsset)
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no compile assets.");
                            }
                            else
                            {
                                var referenceAssemblies = compileAssetPaths.Where(IsDll);

                                if (referenceAssemblies.Count() > 1)
                                {
                                    Log.LogError($"{ContractName} should only contain a single compile asset for {target}.");
                                }

                                foreach (var referenceAssembly in referenceAssemblies)
                                {
                                    referenceAssemblyVersion = _targetPathToPackageItem[referenceAssembly].Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, referenceAssemblyVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {referenceAssembly} was found to support {referenceAssemblyVersion?.ToString() ?? "<unknown version>"}.");
                                    }
                                }
                            }

                            if (!hasRuntimeAsset && !FrameworkUtilities.IsGenerationMoniker(validateFramework.Framework))
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no runtime assets.");
                            }
                            else
                            {
                                var implementationAssemblies = runtimeAssetPaths.Where(IsDll);

                                Dictionary <string, string> implementationFiles = new Dictionary <string, string>();
                                foreach (var implementationAssembly in implementationAssemblies)
                                {
                                    Version implementationVersion = _targetPathToPackageItem[implementationAssembly].Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {implementationAssembly} was found to support {implementationVersion?.ToString() ?? "<unknown version>"}.");
                                    }

                                    if (referenceAssemblyVersion != null &&
                                        HasSuppression(Suppression.PermitHigherCompatibleImplementationVersion) ?
                                        !VersionUtility.IsCompatibleApiVersion(referenceAssemblyVersion, implementationVersion) :
                                        (implementationVersion != referenceAssemblyVersion))
                                    {
                                        Log.LogError($"{ContractName} has mismatched compile ({referenceAssemblyVersion}) and runtime ({implementationVersion}) versions on {target}.");
                                    }

                                    string fileName = Path.GetFileName(implementationAssembly);

                                    if (implementationFiles.ContainsKey(fileName))
                                    {
                                        Log.LogError($"{ContractName} includes both {implementationAssembly} and {implementationFiles[fileName]} an on {target} which have the same name and will clash when both packages are used.");
                                    }
                                    else
                                    {
                                        implementationFiles[fileName] = implementationAssembly;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // Set output items
            AllSupportedFrameworks = _frameworks.Values.Where(fx => fx.SupportedVersion != null).Select(fx => fx.ToItem()).OrderBy(i => i.ItemSpec).ToArray();

            if (!String.IsNullOrEmpty(ValidationReport))
            {
                WriteValidationReport(ValidationReport, _frameworks.Values);
            }
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Validates the latest nuget package doesnot drop any target framework/rid and does not introduce any breaking changes.
        /// </summary>
        /// <param name="package">Nuget Package that needs to be validated.</param>
        public void Validate(PackageValidatorOption option)
        {
            if (option.BaselinePackage is null)
            {
                throw new ArgumentNullException(nameof(option.BaselinePackage));
            }

            ApiCompatRunner apiCompatRunner = new(_log,
                                                  option.EnableStrictMode,
                                                  option.FrameworkReferences,
                                                  option.BaselinePackage.PackagePath,
                                                  option.Package.PackagePath);

            // Iterate over all available baseline assets
            foreach (ContentItem baselineCompileTimeAsset in option.BaselinePackage.RefAssets)
            {
                // Search for a compatible compile time asset in the latest package
                NuGetFramework baselineTargetFramework = (NuGetFramework)baselineCompileTimeAsset.Properties["tfm"];
                ContentItem?   latestCompileTimeAsset  = option.Package.FindBestCompileAssetForFramework(baselineTargetFramework);
                if (latestCompileTimeAsset == null)
                {
                    _log.LogError(
                        new Suppression(DiagnosticIds.TargetFrameworkDropped)
                    {
                        Target = baselineTargetFramework.ToString()
                    },
                        DiagnosticIds.TargetFrameworkDropped,
                        Resources.MissingTargetFramework,
                        baselineTargetFramework.ToString());
                }
                else if (option.RunApiCompat)
                {
                    string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineCompileTimeAsset.Path, latestCompileTimeAsset.Path, option.BaselinePackage.Version, option.Package.Version);
                    apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, baselineCompileTimeAsset, latestCompileTimeAsset, header, isBaseline: true);
                }
            }

            // Iterates over both runtime and runtime specific baseline assets and searches for a compatible non runtime
            // specific asset in the latest package.
            foreach (ContentItem baselineRuntimeAsset in option.BaselinePackage.RuntimeAssets)
            {
                // Search for a compatible runtime asset in the latest package
                NuGetFramework baselineTargetFramework = (NuGetFramework)baselineRuntimeAsset.Properties["tfm"];
                ContentItem?   latestRuntimeAsset      = option.Package.FindBestRuntimeAssetForFramework(baselineTargetFramework);
                if (latestRuntimeAsset == null)
                {
                    _log.LogError(
                        new Suppression(DiagnosticIds.TargetFrameworkDropped)
                    {
                        Target = baselineTargetFramework.ToString()
                    },
                        DiagnosticIds.TargetFrameworkDropped,
                        Resources.MissingTargetFramework,
                        baselineTargetFramework.ToString());
                }
                else if (option.RunApiCompat)
                {
                    string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineRuntimeAsset.Path, latestRuntimeAsset.Path, option.BaselinePackage.Version, option.Package.Version);
                    apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, baselineRuntimeAsset, latestRuntimeAsset, header, isBaseline: true);
                }
            }

            // Compares runtime specific baseline assets against runtime specific latest assets.
            foreach (ContentItem baselineRuntimeSpecificAsset in option.BaselinePackage.RuntimeSpecificAssets)
            {
                NuGetFramework baselineTargetFramework    = (NuGetFramework)baselineRuntimeSpecificAsset.Properties["tfm"];
                string         baselineRid                = (string)baselineRuntimeSpecificAsset.Properties["rid"];
                ContentItem?   latestRuntimeSpecificAsset = option.Package.FindBestRuntimeAssetForFrameworkAndRuntime(baselineTargetFramework, baselineRid);
                if (latestRuntimeSpecificAsset == null)
                {
                    _log.LogError(
                        new Suppression(DiagnosticIds.TargetFrameworkAndRidPairDropped)
                    {
                        Target = baselineTargetFramework.ToString() + "-" + baselineRid
                    },
                        DiagnosticIds.TargetFrameworkAndRidPairDropped,
                        Resources.MissingTargetFrameworkAndRid,
                        baselineTargetFramework.ToString(),
                        baselineRid);
                }
                else if (option.RunApiCompat)
                {
                    string header = string.Format(Resources.ApiCompatibilityBaselineHeader, baselineRuntimeSpecificAsset.Path, latestRuntimeSpecificAsset.Path, option.BaselinePackage.Version, option.Package.Version);
                    apiCompatRunner.QueueApiCompatFromContentItem(option.Package.PackageId, baselineRuntimeSpecificAsset, latestRuntimeSpecificAsset, header, isBaseline: true);
                }
            }

            if (option.RunApiCompat)
            {
                apiCompatRunner.RunApiCompat();
            }
        }
Ejemplo n.º 21
0
        private void ValidateSupport()
        {
            var runtimeFxSuppression = GetSuppressionValues(Suppression.PermitRuntimeTargetMonikerMismatch) ?? new HashSet <string>();

            // validate support for each TxM:RID
            foreach (var validateFramework in _frameworks.Values)
            {
                NuGetFramework fx = validateFramework.Framework;
                Version        supportedVersion = validateFramework.SupportedVersion;

                Target compileTarget;
                if (!_report.Targets.TryGetValue(fx.ToString(), out compileTarget))
                {
                    Log.LogError($"Missing target {fx.ToString()} from validation report {ReportFile}");
                    continue;
                }

                var  compileAssetPaths = compileTarget.CompileAssets.Select(ca => ca.PackagePath);
                bool hasCompileAsset, hasCompilePlaceHolder;
                NuGetAssetResolver.ExamineAssets(Log, "Compile", ContractName, fx.ToString(), compileAssetPaths, out hasCompileAsset, out hasCompilePlaceHolder);

                // resolve/test for each RID associated with this framework.
                foreach (string runtimeId in validateFramework.RuntimeIds)
                {
                    string target = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";

                    Target runtimeTarget;
                    if (!_report.Targets.TryGetValue(target, out runtimeTarget))
                    {
                        Log.LogError($"Missing target {target} from validation report {ReportFile}");
                        continue;
                    }

                    var runtimeAssetPaths = runtimeTarget.RuntimeAssets.Select(ra => ra.PackagePath);

                    bool hasRuntimeAsset, hasRuntimePlaceHolder;
                    NuGetAssetResolver.ExamineAssets(Log, "Runtime", ContractName, target, runtimeAssetPaths, out hasRuntimeAsset, out hasRuntimePlaceHolder);

                    if (null == supportedVersion)
                    {
                        // Contract should not be supported on this platform.
                        bool permitImplementation = HasSuppression(Suppression.PermitImplementation, target);

                        if (hasCompileAsset && (hasRuntimeAsset & !permitImplementation))
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has both compile and runtime assets.");
                        }
                        else if (hasRuntimeAsset & !permitImplementation)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has runtime assets.");
                        }

                        if (hasRuntimePlaceHolder && hasCompilePlaceHolder)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has placeholders for both compile and runtime which will permit the package to install.");
                        }
                    }
                    else
                    {
                        if (validateFramework.IsInbox)
                        {
                            if (!hasCompileAsset && !hasCompilePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for compile-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasCompileAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a reference assemblies: {String.Join(", ", compileAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }

                            if (!hasRuntimeAsset && !hasRuntimePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for run-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasRuntimeAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a implementation assemblies: {String.Join(", ", runtimeAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                        }
                        else
                        {
                            Version referenceAssemblyVersion = null;
                            if (!hasCompileAsset)
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no compile assets.");
                            }
                            else
                            {
                                var referenceAssemblies = compileTarget.CompileAssets.Where(ca => IsDll(ca.PackagePath));

                                if (referenceAssemblies.Count() > 1)
                                {
                                    Log.LogError($"{ContractName} should only contain a single compile asset for {target}.");
                                }

                                foreach (var referenceAssembly in referenceAssemblies)
                                {
                                    referenceAssemblyVersion = referenceAssembly.Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, referenceAssemblyVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {referenceAssembly.LocalPath} was found to support {referenceAssemblyVersion?.ToString() ?? "<unknown version>"}.");
                                    }
                                }
                            }


                            if (!hasRuntimeAsset)
                            {
                                if (HasSuppression(Suppression.PermitMissingImplementation, target))
                                {
                                    Log.LogMessage($"Suppressed: {ContractName} should be supported on {target} but has no runtime assets.");
                                }
                                else
                                {
                                    // Contract should not be supported on this platform.
                                    Log.LogError($"{ContractName} should be supported on {target} but has no runtime assets.");
                                }
                            }
                            else
                            {
                                var implementationAssemblies = runtimeTarget.RuntimeAssets.Where(ra => IsDll(ra.PackagePath));

                                Dictionary <string, PackageAsset> implementationFiles = new Dictionary <string, PackageAsset>();
                                foreach (var implementationAssembly in implementationAssemblies)
                                {
                                    Version implementationVersion = implementationAssembly.Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {implementationAssembly.LocalPath} was found to support {implementationVersion?.ToString() ?? "<unknown version>"}.");
                                    }

                                    // Previously we only permitted compatible mismatch if Suppression.PermitHigherCompatibleImplementationVersion was specified
                                    // this is a permitted thing on every framework but desktop (which requires exact match to ensure bindingRedirects exist)
                                    // Now make this the default, we'll check desktop, where it matters, more strictly
                                    if (referenceAssemblyVersion != null &&
                                        !VersionUtility.IsCompatibleApiVersion(referenceAssemblyVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} has mismatched compile ({referenceAssemblyVersion}) and runtime ({implementationVersion}) versions on {target}.");
                                    }

                                    if (fx.Framework == FrameworkConstants.FrameworkIdentifiers.Net &&
                                        referenceAssemblyVersion != null &&
                                        !referenceAssemblyVersion.Equals(implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} has a higher runtime version ({implementationVersion}) than compile version ({referenceAssemblyVersion}) on .NET Desktop framework {target}.  This will break bindingRedirects.  If the live reference was replaced with a harvested reference you may need to set <Preserve>true</Preserve> on your reference assembly ProjectReference.");
                                    }

                                    string fileName = Path.GetFileName(implementationAssembly.PackagePath);

                                    if (implementationFiles.ContainsKey(fileName))
                                    {
                                        Log.LogError($"{ContractName} includes both {implementationAssembly.LocalPath} and {implementationFiles[fileName].LocalPath} an on {target} which have the same name and will clash when both packages are used.");
                                    }
                                    else
                                    {
                                        implementationFiles[fileName] = implementationAssembly;
                                    }

                                    if (!implementationAssembly.TargetFramework.Equals(fx) && !runtimeFxSuppression.Contains(fx.ToString()))
                                    {
                                        // the selected asset wasn't an exact framework match, let's see if we have an exact match in any other runtime asset.
                                        var matchingFxAssets = _report.UnusedAssets.Where(i => i.TargetFramework != null && i.TargetFramework.Equals(fx) && // exact framework
                                                                                                                                                            // Same file
                                                                                          Path.GetFileName(i.PackagePath).Equals(fileName, StringComparison.OrdinalIgnoreCase) &&
                                                                                                                                                            // Is implementation
                                                                                          (i.PackagePath.StartsWith("lib") || i.PackagePath.StartsWith("runtimes")) &&
                                                                                                                                                            // is not the same source file as was already selected
                                                                                          i.LocalPath != implementationAssembly.LocalPath);

                                        if (matchingFxAssets.Any())
                                        {
                                            Log.LogError($"When targeting {target} {ContractName} will use {implementationAssembly.LocalPath} which targets {implementationAssembly.TargetFramework.GetShortFolderName()}  but {String.Join(";", matchingFxAssets.Select(i => i.PackagePath))} targets {fx.GetShortFolderName()} specifically.");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // Set output items
            AllSupportedFrameworks = _frameworks.Values.Where(fx => fx.SupportedVersion != null).Select(fx => fx.ToItem()).OrderBy(i => i.ItemSpec).ToArray();
        }
Ejemplo n.º 22
0
 public static Task <PackagesLock> FetchModules(NuGetFramework framework, IRestClient client)
 {
     return(CreateRequest().AddQueryParam("framework", framework.ToString()).Execute(client).Return <PackagesLock>());
 }