コード例 #1
0
 // Gets the runtime graph specified in the path.
 // returns null if an error is hit. A valid runtime graph otherwise.
 private RuntimeGraph GetRuntimeGraph(string runtimeGraphPath)
 {
     if (File.Exists(runtimeGraphPath))
     {
         try
         {
             using (var stream = File.OpenRead(runtimeGraphPath))
             {
                 var runtimeGraph = JsonRuntimeFormat.ReadRuntimeGraph(stream);
                 return(runtimeGraph);
             }
         }
         catch (Exception e)
         {
             _logger.Log(
                 RestoreLogMessage.CreateError(
                     NuGetLogCode.NU1007,
                     string.Format(CultureInfo.CurrentCulture,
                                   Strings.Error_ProjectRuntimeJsonIsUnreadable,
                                   runtimeGraphPath,
                                   e.Message)));
         }
     }
     else
     {
         _logger.Log(
             RestoreLogMessage.CreateError(
                 NuGetLogCode.NU1007,
                 string.Format(CultureInfo.CurrentCulture,
                               Strings.Error_ProjectRuntimeJsonNotFound,
                               runtimeGraphPath)));
     }
     return(null);
 }
コード例 #2
0
        public void GetMessagesForProject_WithMultipleMessages_SelectedMessagesForCorrectProject()
        {
            // Arrange
            var project1 = @"z:\src\solution\project1\project1.csproj";
            var project2 = @"z:\src\solution\project2\project2.csproj";

            var project1Error = RestoreLogMessage.CreateError(NuGetLogCode.NU1001, "project1 error");

            project1Error.ProjectPath = project1;

            var project2Error = RestoreLogMessage.CreateError(NuGetLogCode.NU1002, "project2 error");

            project2Error.ProjectPath = project2;

            var solutionMessages = new List <IAssetsLogMessage>()
            {
                AssetsLogMessage.Create(project1Error),
                AssetsLogMessage.Create(project2Error)
            };

            // Act
            IReadOnlyList <IAssetsLogMessage> actual = DependencyGraphSpecRequestProvider.GetMessagesForProject(solutionMessages, project1);

            // Assert
            var actualError = Assert.Single(actual);

            Assert.Equal(NuGetLogCode.NU1001, actualError.Code);
        }
コード例 #3
0
        public static RestoreLogMessage GetInvalidFallbackCombinationMessage(string path)
        {
            var error = RestoreLogMessage.CreateError(NuGetLogCode.NU1003, Strings.Error_InvalidATF);

            error.ProjectPath = path;
            error.FilePath    = path;

            return(error);
        }
コード例 #4
0
ファイル: RestoreCommand.cs プロジェクト: zyonet/NuGet.Client
        /// <summary>
        /// Logs an error and returns false if any cycles exist.
        /// </summary>
        private static async Task<bool> ValidateCyclesAsync(IEnumerable<RestoreTargetGraph> graphs, ILogger logger)
        {
            foreach (var graph in graphs)
            {
                foreach (var cycle in graph.AnalyzeResult.Cycles)
                {
                    var text = Strings.Log_CycleDetected + $" {Environment.NewLine}  {cycle.GetPath()}.";
                    await logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1606, text, cycle.Key?.Name, graph.TargetGraphName));
                    return false;
                }
            }

            return true;
        }
コード例 #5
0
        public void RestoreLogMessage_TestCreateError(NuGetLogCode code, string message, string libraryId, string[] targetGraphs)
        {
            // Arrange & Act
            var logMessage = RestoreLogMessage.CreateError(code, message, libraryId, targetGraphs);

            // Assert
            Assert.Equal(LogLevel.Error, logMessage.Level);
            Assert.Equal(code, logMessage.Code);
            Assert.Equal(message, logMessage.Message);
            Assert.Equal(0, logMessage.StartLineNumber);
            Assert.Equal(0, logMessage.EndLineNumber);
            Assert.Equal(0, logMessage.StartColumnNumber);
            Assert.Equal(0, logMessage.EndColumnNumber);
            targetGraphs.SequenceEqual(logMessage.TargetGraphs);
        }
 private async Task LogErrorAsync(ILogger logger, string id, FatalProtocolException e)
 {
     if (!_ignoreWarning)
     {
         // Sometimes, there's a better root cause for a source failures we log that instead of NU1301.
         // We only do this for errors, and not warnings.
         var unwrappedLogMessage = UnwrapToLogMessage(e);
         if (unwrappedLogMessage != null)
         {
             await logger.LogAsync(unwrappedLogMessage);
         }
         else
         {
             await logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1301, e.Message, id));
         }
     }
コード例 #7
0
        private async Task <bool> ResolutionSucceeded(IEnumerable <RestoreTargetGraph> graphs, IList <DownloadDependencyResolutionResult> downloadDependencyResults, RemoteWalkContext context, CancellationToken token)
        {
            var graphSuccess = true;

            foreach (var graph in graphs)
            {
                if (graph.Conflicts.Any())
                {
                    graphSuccess = false;

                    foreach (var conflict in graph.Conflicts)
                    {
                        var graphName = DiagnosticUtility.FormatGraphName(graph);

                        var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolverConflict,
                                                    conflict.Name,
                                                    string.Join(", ", conflict.Requests),
                                                    graphName);

                        _logger.Log(RestoreLogMessage.CreateError(NuGetLogCode.NU1106, message, conflict.Name, graph.TargetGraphName));
                    }
                }

                if (graph.Unresolved.Count > 0)
                {
                    graphSuccess = false;
                }
            }

            if (!graphSuccess)
            {
                // Log message for any unresolved dependencies
                await UnresolvedMessages.LogAsync(graphs, context, context.Logger, token);
            }

            var ddSuccess = downloadDependencyResults.All(e => e.Unresolved.Count == 0);

            if (!ddSuccess)
            {
                await UnresolvedMessages.LogAsync(downloadDependencyResults, context.RemoteLibraryProviders, context.CacheContext, context.Logger, token);
            }

            return(graphSuccess && ddSuccess);
        }
コード例 #8
0
ファイル: RestoreCommand.cs プロジェクト: zyonet/NuGet.Client
        /// <summary>
        /// Logs an error and returns false if any conflicts exist.
        /// </summary>
        private static async Task<bool> ValidateConflictsAsync(IEnumerable<RestoreTargetGraph> graphs, ILogger logger)
        {
            foreach (var graph in graphs)
            {
                foreach (var versionConflict in graph.AnalyzeResult.VersionConflicts)
                {
                    var message = string.Format(
                            CultureInfo.CurrentCulture,
                            Strings.Log_VersionConflict,
                            versionConflict.Selected.Key.Name)
                        + $" {Environment.NewLine} {versionConflict.Selected.GetPath()} {Environment.NewLine} {versionConflict.Conflicting.GetPath()}.";

                    await logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1607, message, versionConflict.Selected.Key.Name, graph.TargetGraphName));
                    return false;
                }
            }

            return true;
        }
コード例 #9
0
        private async Task <bool> ResolutionSucceeded(IEnumerable <RestoreTargetGraph> graphs, RemoteWalkContext context, CancellationToken token)
        {
            var success = true;

            foreach (var graph in graphs)
            {
                if (graph.Conflicts.Any())
                {
                    success = false;

                    foreach (var conflict in graph.Conflicts)
                    {
                        var graphName = DiagnosticUtility.FormatGraphName(graph);

                        var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ResolverConflict,
                                                    conflict.Name,
                                                    string.Join(", ", conflict.Requests),
                                                    graphName);

                        _logger.Log(RestoreLogMessage.CreateError(NuGetLogCode.NU1106, message));
                    }
                }

                if (graph.Unresolved.Count > 0)
                {
                    success = false;
                }
            }

            if (!success)
            {
                // Log message for any unresolved dependencies
                await UnresolvedMessages.LogAsync(graphs, context, context.Logger, token);
            }

            return(success);
        }
コード例 #10
0
        private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync(
            NuGetv3LocalRepository userPackageFolder,
            IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders,
            RemoteWalkContext context,
            CancellationToken token)
        {
            if (_request.Project.TargetFrameworks.Count == 0)
            {
                var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath);
                await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1001, message));

                _success = false;
                return(Enumerable.Empty <RestoreTargetGraph>());
            }

            _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath));

            // Get external project references
            // If the top level project already exists, update the package spec provided
            // with the RestoreRequest spec.
            var updatedExternalProjects = GetProjectReferences(context);

            // Determine if the targets and props files should be written out.
            context.IsMsBuildBased = _request.ProjectStyle != ProjectStyle.DotnetCliTool;

            // Load repositories
            // the external project provider is specific to the current restore project
            context.ProjectLibraryProviders.Add(
                new PackageSpecReferenceDependencyProvider(updatedExternalProjects, _logger));

            var remoteWalker = new RemoteDependencyWalker(context);

            var projectRange = new LibraryRange()
            {
                Name           = _request.Project.Name,
                VersionRange   = new VersionRange(_request.Project.Version),
                TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject
            };

            // Resolve dependency graphs
            var allInstalledPackages         = new HashSet <LibraryIdentity>();
            var allGraphs                    = new List <RestoreTargetGraph>();
            var runtimeIds                   = RequestRuntimeUtility.GetRestoreRuntimes(_request);
            var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds);
            var hasSupports                  = _request.Project.RuntimeGraph.Supports.Count > 0;

            var projectRestoreRequest = new ProjectRestoreRequest(
                _request,
                _request.Project,
                _request.ExistingLockFile,
                _runtimeGraphCache,
                _runtimeGraphCacheByPackage,
                _logger);

            var projectRestoreCommand = new ProjectRestoreCommand(projectRestoreRequest);

            var result = await projectRestoreCommand.TryRestore(
                projectRange,
                projectFrameworkRuntimePairs,
                allInstalledPackages,
                userPackageFolder,
                fallbackPackageFolders,
                remoteWalker,
                context,
                forceRuntimeGraphCreation : hasSupports,
                token : token);

            var success = result.Item1;

            allGraphs.AddRange(result.Item2);

            _success = success;

            // Calculate compatibility profiles to check by merging those defined in the project with any from the command line
            foreach (var profile in _request.Project.RuntimeGraph.Supports)
            {
                var runtimes = result.Item3;

                CompatibilityProfile compatProfile;
                if (profile.Value.RestoreContexts.Any())
                {
                    // Just use the contexts from the project definition
                    compatProfile = profile.Value;
                }
                else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile))
                {
                    // No definition of this profile found, so just continue to the next one
                    var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key);

                    await _logger.LogAsync(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1502, message));

                    continue;
                }

                foreach (var pair in compatProfile.RestoreContexts)
                {
                    _logger.LogDebug($" {profile.Value.Name} -> +{pair}");
                    _request.CompatibilityProfiles.Add(pair);
                }
            }

            // Walk additional runtime graphs for supports checks
            if (_success && _request.CompatibilityProfiles.Any())
            {
                var compatibilityResult = await projectRestoreCommand.TryRestore(
                    projectRange,
                    _request.CompatibilityProfiles,
                    allInstalledPackages,
                    userPackageFolder,
                    fallbackPackageFolders,
                    remoteWalker,
                    context,
                    forceRuntimeGraphCreation : true,
                    token : token);

                _success = compatibilityResult.Item1;

                // TryRestore may contain graphs that are already in allGraphs if the
                // supports section contains the same TxM as the project framework.
                var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >(
                    allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>(
                                         graph.Framework,
                                         graph.RuntimeIdentifier))
                    );

                foreach (var graph in compatibilityResult.Item2)
                {
                    var key = new KeyValuePair <NuGetFramework, string>(
                        graph.Framework,
                        graph.RuntimeIdentifier);

                    if (currentGraphs.Add(key))
                    {
                        allGraphs.Add(graph);
                    }
                }
            }


            return(allGraphs);
        }
コード例 #11
0
        /// <summary>
        /// Create a specific error message for the unresolved dependency.
        /// </summary>
        public static async Task <RestoreLogMessage> GetMessageAsync(string targetGraphName,
                                                                     LibraryRange unresolved,
                                                                     IList <IRemoteDependencyProvider> remoteLibraryProviders,
                                                                     SourceCacheContext sourceCacheContext,
                                                                     ILogger logger,
                                                                     CancellationToken token)
        {
            // Default to using the generic unresolved error code, this will be overridden later.
            var code    = NuGetLogCode.NU1100;
            var message = string.Empty;

            if (unresolved.TypeConstraintAllows(LibraryDependencyTarget.ExternalProject) &&
                !unresolved.TypeConstraintAllows(LibraryDependencyTarget.Package))
            {
                // Project
                // Check if the name is a path and if it exists. All project paths should have been normalized and converted to full paths before this.
                if (unresolved.Name.IndexOf(Path.DirectorySeparatorChar) > -1 && File.Exists(unresolved.Name))
                {
                    // File exists but the dg spec did not contain the spec
                    code    = NuGetLogCode.NU1105;
                    message = string.Format(CultureInfo.CurrentCulture, Strings.Error_UnableToFindProjectInfo, unresolved.Name);
                }
                else
                {
                    // Generic missing project error
                    code    = NuGetLogCode.NU1104;
                    message = string.Format(CultureInfo.CurrentCulture, Strings.Error_ProjectDoesNotExist, unresolved.Name);
                }
            }
            else if (unresolved.TypeConstraintAllows(LibraryDependencyTarget.Package) && remoteLibraryProviders.Count > 0)
            {
                // Package
                var range      = unresolved.VersionRange ?? VersionRange.All;
                var sourceInfo = await GetSourceInfosForIdAsync(unresolved.Name, range, remoteLibraryProviders, sourceCacheContext, logger, token);

                var allVersions = new SortedSet <NuGetVersion>(sourceInfo.SelectMany(e => e.Value));

                if (allVersions.Count == 0)
                {
                    // No versions found
                    code = NuGetLogCode.NU1101;
                    var sourceList = string.Join(", ",
                                                 sourceInfo.Select(e => e.Key.Name)
                                                 .OrderBy(e => e, StringComparer.OrdinalIgnoreCase));

                    message = string.Format(CultureInfo.CurrentCulture, Strings.Error_NoPackageVersionsExist, unresolved.Name, sourceList);
                }
                else
                {
                    // At least one version found
                    var firstLine   = string.Empty;
                    var rangeString = range.ToNonSnapshotRange().PrettyPrint();

                    if (!IsPrereleaseAllowed(range) && HasPrereleaseVersionsOnly(range, allVersions))
                    {
                        code      = NuGetLogCode.NU1103;
                        firstLine = string.Format(CultureInfo.CurrentCulture, Strings.Error_NoStablePackageVersionsExist, unresolved.Name, rangeString);
                    }
                    else
                    {
                        code      = NuGetLogCode.NU1102;
                        firstLine = string.Format(CultureInfo.CurrentCulture, Strings.Error_NoPackageVersionsExistInRange, unresolved.Name, rangeString);
                    }

                    var lines = new List <string>()
                    {
                        firstLine
                    };

                    lines.AddRange(sourceInfo.Select(e => FormatSourceInfo(e, range)));

                    message = DiagnosticUtility.GetMultiLineMessage(lines);
                }
            }
            else
            {
                // Unknown or non-specific.
                // Also shown when no sources exist.
                message = string.Format(CultureInfo.CurrentCulture,
                                        Strings.Log_UnresolvedDependency,
                                        unresolved.ToString(),
                                        targetGraphName);

                // Set again for clarity
                code = NuGetLogCode.NU1100;
            }

            return(RestoreLogMessage.CreateError(code, message, unresolved.Name, targetGraphName));
        }
コード例 #12
0
 /// <summary>
 /// Create an error message for the given issue.
 /// </summary>
 private static RestoreLogMessage GetErrorMessage(NuGetLogCode logCode, CompatibilityIssue issue, RestoreTargetGraph graph)
 {
     return(RestoreLogMessage.CreateError(logCode, issue.Format(), issue.Package.Id, graph.TargetGraphName));
 }
コード例 #13
0
        /// <summary>
        /// This is where the nominate calls for the IVs1 and IVS3 APIs combine. The reason for this method is to avoid duplication and potential issues
        /// The issue with this method is that it has some weird custom logging to ensure backward compatibility. It's on the implementer to ensure these calls are correct.
        /// <param name="projectUniqueName">projectUniqueName</param>
        /// <param name="projectRestoreInfo">projectRestoreInfo. Can be null</param>
        /// <param name="projectRestoreInfo2">proectRestoreInfo2. Can be null</param>
        /// <param name="token"></param>
        /// <remarks>Exactly one of projectRestoreInfos has to null.</remarks>
        /// <returns>The task that scheduled restore</returns>
        private Task <bool> NominateProjectAsync(string projectUniqueName, IVsProjectRestoreInfo projectRestoreInfo, IVsProjectRestoreInfo2 projectRestoreInfo2, CancellationToken token)
        {
            if (string.IsNullOrEmpty(projectUniqueName))
            {
                throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(projectUniqueName));
            }

            if (projectRestoreInfo == null && projectRestoreInfo2 == null)
            {
                throw new ArgumentNullException(nameof(projectRestoreInfo));
            }

            if (projectRestoreInfo != null && projectRestoreInfo2 != null)
            {
                throw new ArgumentException($"Internal error: Both {nameof(projectRestoreInfo)} and {nameof(projectRestoreInfo2)} cannot have values. Please file an issue at NuGet/Home if you see this exception.");
            }

            if (projectRestoreInfo != null)
            {
                if (projectRestoreInfo.TargetFrameworks == null)
                {
                    throw new InvalidOperationException("TargetFrameworks cannot be null.");
                }
            }
            else
            {
                if (projectRestoreInfo2.TargetFrameworks == null)
                {
                    throw new InvalidOperationException("TargetFrameworks cannot be null.");
                }
            }

            try
            {
                _logger.LogInformation(
                    $"The nominate API is called for '{projectUniqueName}'.");

                var projectNames = ProjectNames.FromFullProjectPath(projectUniqueName);
                DependencyGraphSpec dgSpec;
                IReadOnlyList <IAssetsLogMessage> nominationErrors = null;
                try
                {
                    dgSpec = ToDependencyGraphSpec(projectNames, projectRestoreInfo, projectRestoreInfo2);
                }
                catch (Exception e)
                {
                    var restoreLogMessage = RestoreLogMessage.CreateError(NuGetLogCode.NU1105, string.Format(Resources.NU1105, projectNames.ShortName, e.Message));
                    restoreLogMessage.LibraryId = projectUniqueName;

                    nominationErrors = new List <IAssetsLogMessage>()
                    {
                        AssetsLogMessage.Create(restoreLogMessage)
                    };

                    var    projectDirectory        = Path.GetDirectoryName(projectUniqueName);
                    string projectIntermediatePath = projectRestoreInfo == null
                        ? projectRestoreInfo2.BaseIntermediatePath
                        : projectRestoreInfo.BaseIntermediatePath;
                    var dgSpecOutputPath = GetProjectOutputPath(projectDirectory, projectIntermediatePath);
                    dgSpec = CreateMinimalDependencyGraphSpec(projectUniqueName, dgSpecOutputPath);
                }

                _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec, nominationErrors);

                // returned task completes when scheduled restore operation completes.
                var restoreTask = _restoreWorker.ScheduleRestoreAsync(
                    SolutionRestoreRequest.OnUpdate(),
                    token);

                return(restoreTask);
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
                TelemetryUtility.EmitException(nameof(VsSolutionRestoreService), nameof(NominateProjectAsync), e);
                return(Task.FromResult(false));
            }
        }
コード例 #14
0
        public static IReadOnlyList <IRestoreLogMessage> ValidatePackagesConfigLockFiles(
            string projectFile,
            string packagesConfigFile,
            string projectName,
            string nuGetLockFilePath,
            string restorePackagesWithLockFile,
            NuGetFramework projectTfm,
            string packagesFolderPath,
            bool restoreLockedMode,
            CancellationToken token)
        {
            var lockFilePath   = GetPackagesLockFilePath(Path.GetDirectoryName(packagesConfigFile), nuGetLockFilePath, projectName);
            var lockFileExists = File.Exists(lockFilePath);
            var lockFileOptIn  = MSBuildStringUtility.GetBooleanOrNull(restorePackagesWithLockFile);
            var useLockFile    = lockFileOptIn == true || lockFileExists;

            if (lockFileOptIn == false && lockFileExists)
            {
                var message = string.Format(CultureInfo.CurrentCulture, Strings.Error_InvalidLockFileInput, lockFilePath);
                var errors  = new List <IRestoreLogMessage>();
                var log     = RestoreLogMessage.CreateError(NuGetLogCode.NU1005, message, packagesConfigFile);
                log.ProjectPath = projectFile ?? packagesConfigFile;
                errors.Add(log);
                return(errors);
            }

            if (useLockFile)
            {
                PackagesLockFile projectLockFileEquivalent = PackagesConfigLockFileUtility.FromPackagesConfigFile(packagesConfigFile,
                                                                                                                  projectTfm,
                                                                                                                  packagesFolderPath,
                                                                                                                  token);

                if (!lockFileExists)
                {
                    PackagesLockFileFormat.Write(lockFilePath, projectLockFileEquivalent);
                    return(null);
                }
                else
                {
                    PackagesLockFile lockFile = PackagesLockFileFormat.Read(lockFilePath);
                    PackagesLockFileUtilities.LockFileValidityWithMatchedResults comparisonResult = PackagesLockFileUtilities.IsLockFileStillValid(projectLockFileEquivalent, lockFile);
                    if (comparisonResult.IsValid)
                    {
                        // check sha hashes
                        bool allContentHashesMatch = comparisonResult.MatchedDependencies.All(pair => pair.Key.ContentHash == pair.Value.ContentHash);
                        if (allContentHashesMatch)
                        {
                            return(null);
                        }
                        else
                        {
                            var errors = new List <IRestoreLogMessage>();
                            foreach (var difference in comparisonResult.MatchedDependencies.Where(kvp => kvp.Key.ContentHash != kvp.Value.ContentHash))
                            {
                                var message = string.Format(CultureInfo.CurrentCulture, Strings.Error_PackageValidationFailed, difference.Key.Id + "." + difference.Key.ResolvedVersion);
                                var log     = RestoreLogMessage.CreateError(NuGetLogCode.NU1403, message, packagesConfigFile);
                                log.ProjectPath = projectFile ?? packagesConfigFile;
                                errors.Add(log);
                            }
                            return(errors);
                        }
                    }
                    else
                    {
                        if (restoreLockedMode)
                        {
                            var errors = new List <IRestoreLogMessage>();
                            var log    = RestoreLogMessage.CreateError(NuGetLogCode.NU1004, Strings.Error_RestoreInLockedModePackagesConfig, packagesConfigFile);
                            log.ProjectPath = projectFile ?? packagesConfigFile;
                            errors.Add(log);
                            return(errors);
                        }
                        else
                        {
                            PackagesLockFileFormat.Write(lockFilePath, projectLockFileEquivalent);
                            return(null);
                        }
                    }
                }
            }
            else
            {
                return(null);
            }
        }
コード例 #15
0
        internal CompatibilityCheckResult Check(
            RestoreTargetGraph graph,
            Dictionary <string, LibraryIncludeFlags> includeFlags)
        {
            // The Compatibility Check is designed to alert the user to cases where packages are not behaving as they would
            // expect, due to compatibility issues.
            //
            // During this check, we scan all packages for a given restore graph and check the following conditions
            // (using an example TxM 'foo' and an example Runtime ID 'bar'):
            //
            // * If any package provides a "ref/foo/Thingy.dll", there MUST be a matching "lib/foo/Thingy.dll" or
            //   "runtimes/bar/lib/foo/Thingy.dll" provided by a package in the graph.
            // * All packages that contain Managed Assemblies must provide assemblies for 'foo'. If a package
            //   contains any of 'ref/' folders, 'lib/' folders, or framework assemblies, it must provide at least
            //   one of those for the 'foo' framework. Otherwise, the package is intending to provide managed assemblies
            //   but it does not support the target platform. If a package contains only 'content/', 'build/', 'tools/' or
            //   other NuGet convention folders, it is exempt from this check. Thus, content-only packages are always considered
            //   compatible, regardless of if they actually provide useful content.
            //
            // It is up to callers to invoke the compatibility check on the graphs they wish to check, but the general behavior in
            // the restore command is to invoke a compatibility check for each of:
            //
            // * The Targets (TxMs) defined in the project.json, with no Runtimes
            // * All combinations of TxMs and Runtimes defined in the project.json
            // * Additional (TxMs, Runtime) pairs defined by the "supports" mechanism in project.json

            var runtimeAssemblies = new HashSet <string>(StringComparer.OrdinalIgnoreCase);
            var compileAssemblies = new Dictionary <string, LibraryIdentity>(StringComparer.OrdinalIgnoreCase);
            var issues            = new List <CompatibilityIssue>();

            // Verify framework assets also as part of runtime assets validation.
            foreach (var node in graph.Flattened)
            {
                _log.LogDebug(string.Format(CultureInfo.CurrentCulture, Strings.Log_CheckingPackageCompatibility, node.Key.Name, node.Key.Version, graph.Name));

                // Check project compatibility
                if (node.Key.Type == LibraryType.Project)
                {
                    // Get the full library
                    var localMatch = node.Data?.Match as LocalMatch;
                    if (localMatch == null || !IsProjectCompatible(localMatch.LocalLibrary))
                    {
                        var available = new List <NuGetFramework>();

                        // If the project info is available find all available frameworks
                        if (localMatch?.LocalLibrary != null)
                        {
                            available = GetProjectFrameworks(localMatch.LocalLibrary);
                        }

                        // Create issue
                        var issue = CompatibilityIssue.IncompatibleProject(
                            new PackageIdentity(node.Key.Name, node.Key.Version),
                            graph.Framework,
                            graph.RuntimeIdentifier,
                            available);

                        issues.Add(issue);

                        _log.Log(RestoreLogMessage.CreateError(NuGetLogCode.NU1201, issue.Format()));
                    }

                    // Skip further checks on projects
                    continue;
                }

                // Find the include/exclude flags for this package
                LibraryIncludeFlags packageIncludeFlags;
                if (!includeFlags.TryGetValue(node.Key.Name, out packageIncludeFlags))
                {
                    packageIncludeFlags = LibraryIncludeFlags.All;
                }

                // If the package has compile and runtime assets excluded the compatibility check
                // is not needed. Packages with no ref or lib entries are considered
                // compatible in IsCompatible.
                if ((packageIncludeFlags &
                     (LibraryIncludeFlags.Compile
                      | LibraryIncludeFlags.Runtime)) == LibraryIncludeFlags.None)
                {
                    continue;
                }

                var compatibilityData = GetCompatibilityData(graph, node.Key);
                if (compatibilityData == null)
                {
                    continue;
                }

                if (!IsCompatible(compatibilityData))
                {
                    var available = GetPackageFrameworks(compatibilityData, graph);

                    var issue = CompatibilityIssue.IncompatiblePackage(
                        new PackageIdentity(node.Key.Name, node.Key.Version),
                        graph.Framework,
                        graph.RuntimeIdentifier,
                        available);

                    issues.Add(issue);

                    _log.Log(RestoreLogMessage.CreateError(NuGetLogCode.NU1202, issue.Format()));
                }

                // Check for matching ref/libs if we're checking a runtime-specific graph
                var targetLibrary = compatibilityData.TargetLibrary;
                if (_validateRuntimeAssets && !string.IsNullOrEmpty(graph.RuntimeIdentifier))
                {
                    // Skip runtime checks for packages that have runtime references excluded,
                    // this allows compile only packages that do not have runtimes for the
                    // graph RID to be used.
                    if ((packageIncludeFlags & LibraryIncludeFlags.Runtime) == LibraryIncludeFlags.Runtime)
                    {
                        // Scan the package for ref assemblies
                        foreach (var compile in targetLibrary.CompileTimeAssemblies
                                 .Where(p => Path.GetExtension(p.Path)
                                        .Equals(".dll", StringComparison.OrdinalIgnoreCase)))
                        {
                            var name = Path.GetFileNameWithoutExtension(compile.Path);

                            // If we haven't already started tracking this compile-time assembly, AND there isn't already a runtime-loadable version
                            if (!compileAssemblies.ContainsKey(name) && !runtimeAssemblies.Contains(name))
                            {
                                // Track this assembly as potentially compile-time-only
                                compileAssemblies.Add(name, node.Key);
                            }
                        }

                        // Match up runtime assemblies
                        foreach (var runtime in targetLibrary.RuntimeAssemblies
                                 .Where(p => Path.GetExtension(p.Path)
                                        .Equals(".dll", StringComparison.OrdinalIgnoreCase)))
                        {
                            var name = Path.GetFileNameWithoutExtension(runtime.Path);

                            // If there was a compile-time-only assembly under this name...
                            if (compileAssemblies.ContainsKey(name))
                            {
                                // Remove it, we've found a matching runtime ref
                                compileAssemblies.Remove(name);
                            }

                            // Track this assembly as having a runtime assembly
                            runtimeAssemblies.Add(name);

                            // Fix for NuGet/Home#752 - Consider ".ni.dll" (native image/ngen) files matches for ref/ assemblies
                            if (name.EndsWith(".ni", StringComparison.OrdinalIgnoreCase))
                            {
                                var withoutNi = name.Substring(0, name.Length - 3);

                                if (compileAssemblies.ContainsKey(withoutNi))
                                {
                                    compileAssemblies.Remove(withoutNi);
                                }

                                runtimeAssemblies.Add(withoutNi);
                            }
                        }
                    }
                }
            }

            // Generate errors for un-matched reference assemblies, if we're checking a runtime-specific graph
            if (_validateRuntimeAssets && !string.IsNullOrEmpty(graph.RuntimeIdentifier))
            {
                foreach (var compile in compileAssemblies)
                {
                    var issue = CompatibilityIssue.ReferenceAssemblyNotImplemented(
                        compile.Key,
                        new PackageIdentity(compile.Value.Name, compile.Value.Version),
                        graph.Framework,
                        graph.RuntimeIdentifier);

                    issues.Add(issue);

                    _log.Log(RestoreLogMessage.CreateError(NuGetLogCode.NU1203, issue.Format()));
                }
            }

            return(new CompatibilityCheckResult(graph, issues));
        }