public void GivenALogMessageWithNoTargetGraphsVerifyAllGraphsAreReturned()
        {
            var assetsFile = new LockFile();

            assetsFile.Targets.Add(new LockFileTarget()
            {
                TargetFramework = NuGetFramework.Parse("net45"),
            });

            assetsFile.Targets.Add(new LockFileTarget()
            {
                TargetFramework   = NuGetFramework.Parse("net46"),
                RuntimeIdentifier = "win8"
            });

            assetsFile.Targets.Add(new LockFileTarget()
            {
                TargetFramework = NuGetFramework.Parse("netstandard2.0")
            });

            var expected1 = NuGetFramework.Parse("net45").DotNetFrameworkName;
            var expected2 = NuGetFramework.Parse("net46").DotNetFrameworkName + "/win8";
            var expected3 = NuGetFramework.Parse("netstandard2.0").DotNetFrameworkName;

            // Create a message with no target graphs
            var message = new AssetsLogMessage(LogLevel.Warning, NuGetLogCode.NU1103, "test");

            var graphs = message.GetTargetGraphs(assetsFile);

            graphs.Select(e => e.Name).ShouldBeEquivalentTo(new[] { expected1, expected2, expected3 });
        }
예제 #2
0
        public void WhenNoOpRestoreResult_LogMessagesAreSourcedFromTheCacheFile()
        {
            // Arrange
            var expectedLogLevel = NuGetLogCode.NU1500;
            var assetsLogMessage = new AssetsLogMessage(LogLevel.Error, NuGetLogCode.NU1501, "a");
            var cacheLogMessage  = new AssetsLogMessage(LogLevel.Error, expectedLogLevel, "a");

            var lockFile = new LockFile();

            lockFile.LogMessages.Add(assetsLogMessage);

            var cacheFile = new CacheFile("hash")
            {
                Success     = true,
                LogMessages = new List <IAssetsLogMessage>()
                {
                    cacheLogMessage
                },
            };

            // Act
            var result = new NoOpRestoreResult(
                success: true,
                lockFilePath: "project.assets.json",
                new Lazy <LockFile>(() => lockFile),
                cacheFile: cacheFile,
                cacheFilePath: "cachepath",
                projectStyle: ProjectStyle.PackageReference,
                elapsedTime: TimeSpan.MinValue);

            // Assert
            result.LogMessages.Should().NotBeNull();
            result.LogMessages.Should().HaveCount(1);
            result.LogMessages.Single().Code.Should().Be(expectedLogLevel);
        }
예제 #3
0
        public void GivenALogMessageWithMultipleGraphsVerifyTargetGraphsAreReturned()
        {
            var assetsFile = new LockFile();

            assetsFile.Targets.Add(new LockFileTarget()
            {
                TargetFramework = NuGetFramework.Parse("net45"),
            });

            assetsFile.Targets.Add(new LockFileTarget()
            {
                TargetFramework   = NuGetFramework.Parse("net46"),
                RuntimeIdentifier = "win8"
            });

            var expected1 = NuGetFramework.Parse("net45").DotNetFrameworkName;
            var expected2 = NuGetFramework.Parse("net46").DotNetFrameworkName + "/win8";
            var message   = new AssetsLogMessage(LogLevel.Warning, NuGetLogCode.NU1103, "test")
            {
                TargetGraphs = new[] { expected1, expected2 }
            };

            var graphs = message.GetTargetGraphs(assetsFile);

            graphs.Select(e => e.Name).Should().BeEquivalentTo(new[] { expected1, expected2 });
        }
예제 #4
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);
        }
예제 #5
0
        public void WhenRestoreResult_LogMessagesAreSourcedFromTheAssetsFile()
        {
            // Arrange
            var expectedLogLevel = NuGetLogCode.NU1500;
            var assetsLogMessage = new AssetsLogMessage(LogLevel.Error, expectedLogLevel, "a");
            var cacheLogMessage  = new AssetsLogMessage(LogLevel.Error, NuGetLogCode.NU1501, "a");

            var lockFile = new LockFile();

            lockFile.LogMessages.Add(assetsLogMessage);

            var cacheFile = new CacheFile("hash")
            {
                Success     = true,
                LogMessages = new List <IAssetsLogMessage>()
                {
                    cacheLogMessage
                },
            };

            // Act
            var result = new RestoreResult(
                success: true,
                restoreGraphs: null,
                compatibilityCheckResults: null,
                lockFile: lockFile,
                previousLockFile: null,
                lockFilePath: "project.assets.json",
                msbuildFiles: Enumerable.Empty <MSBuildOutputFile>(),
                cacheFile: cacheFile,
                cacheFilePath: null,
                packagesLockFilePath: null,
                packagesLockFile: null,
                dependencyGraphSpecFilePath: null,
                dependencyGraphSpec: null,
                projectStyle: ProjectStyle.PackageReference,
                elapsedTime: TimeSpan.MinValue);

            // Assert
            result.LogMessages.Should().NotBeNull();
            result.LogMessages.Should().HaveCount(1);
            result.LogMessages.Single().Code.Should().Be(expectedLogLevel);
        }
        public void GivenALogMessageVerifyTargetGraphIsReturned()
        {
            var assetsFile = new LockFile();

            assetsFile.Targets.Add(new LockFileTarget()
            {
                TargetFramework = NuGetFramework.Parse("net45"),
            });

            assetsFile.Targets.Single().Libraries.Add(new LockFileTargetLibrary()
            {
                Name    = "x",
                Version = NuGetVersion.Parse("1.0.0")
            });

            var expected = NuGetFramework.Parse("net45").DotNetFrameworkName;
            var message  = new AssetsLogMessage(LogLevel.Warning, NuGetLogCode.NU1103, "test", expected);

            var graphs = message.GetTargetGraphs(assetsFile);

            graphs.Select(e => e.Name).ShouldBeEquivalentTo(new[] { expected });
        }
예제 #7
0
        public async Task <RestoreResult> ExecuteAsync(CancellationToken token)
        {
            var restoreTime = Stopwatch.StartNew();

            // Local package folders (non-sources)
            var localRepositories = new List <NuGetv3LocalRepository>
            {
                _request.DependencyProviders.GlobalPackages
            };

            localRepositories.AddRange(_request.DependencyProviders.FallbackPackageFolders);

            var contextForProject = CreateRemoteWalkContext(_request, _logger);

            CacheFile cacheFile = null;

            if (NoOpRestoreUtilities.IsNoOpSupported(_request))
            {
                var cacheFileAndStatus = EvaluateCacheFile();
                cacheFile = cacheFileAndStatus.Key;
                if (cacheFileAndStatus.Value)
                {
                    if (NoOpRestoreUtilities.VerifyAssetsAndMSBuildFilesAndPackagesArePresent(_request))
                    {
                        // Replay Warnings and Errors from an existing lock file in case of a no-op.
                        ReplayWarningsAndErrors();

                        restoreTime.Stop();

                        return(new NoOpRestoreResult(
                                   _success,
                                   _request.ExistingLockFile,
                                   _request.ExistingLockFile,
                                   _request.ExistingLockFile.Path,
                                   cacheFile,
                                   _request.Project.RestoreMetadata.CacheFilePath,
                                   _request.ProjectStyle,
                                   restoreTime.Elapsed));
                    }
                }
            }

            // Validate, for noop this will be replayed from the assets file.
            _success &= await ValidateProjectAsync(_request.Project, _logger);

            // Restore
            var graphs = await ExecuteRestoreAsync(
                _request.DependencyProviders.GlobalPackages,
                _request.DependencyProviders.FallbackPackageFolders,
                contextForProject,
                token);

            // Create assets file
            var assetsFile = BuildAssetsFile(
                _request.ExistingLockFile,
                _request.Project,
                graphs,
                localRepositories,
                contextForProject);

            _success &= await ValidateRestoreGraphsAsync(graphs, _logger);

            // Check package compatibility
            var checkResults = await VerifyCompatibilityAsync(
                _request.Project,
                _includeFlagGraphs,
                localRepositories,
                assetsFile,
                graphs,
                _request.ValidateRuntimeAssets,
                _logger);


            if (checkResults.Any(r => !r.Success))
            {
                _success = false;
            }


            // Determine the lock file output path
            var assetsFilePath = GetAssetsFilePath(assetsFile);
            // Determine the cache file output path
            var cacheFilePath = NoOpRestoreUtilities.GetCacheFilePath(_request, assetsFile);

            // Tool restores are unique since the output path is not known until after restore
            if (_request.LockFilePath == null &&
                _request.ProjectStyle == ProjectStyle.DotnetCliTool)
            {
                _request.LockFilePath = assetsFilePath;
            }

            // Generate Targets/Props files
            var msbuildOutputFiles = Enumerable.Empty <MSBuildOutputFile>();

            if (contextForProject.IsMsBuildBased)
            {
                msbuildOutputFiles = BuildAssetsUtils.GetMSBuildOutputFiles(
                    _request.Project,
                    assetsFile,
                    graphs,
                    localRepositories,
                    _request,
                    assetsFilePath,
                    _success,
                    _logger);
            }

            // If the request is for a lower lock file version, downgrade it appropriately
            DowngradeLockFileIfNeeded(assetsFile);

            // Revert to the original case if needed
            await FixCaseForLegacyReaders(graphs, assetsFile, token);

            // Write the logs into the assets file
            var logs = _logger.Errors
                       .Select(l => AssetsLogMessage.Create(l))
                       .ToList();

            _success &= !logs.Any(l => l.Level == LogLevel.Error);

            assetsFile.LogMessages = logs;

            if (cacheFile != null)
            {
                cacheFile.Success = _success;
            }

            restoreTime.Stop();
            // Create result
            return(new RestoreResult(
                       _success,
                       graphs,
                       checkResults,
                       msbuildOutputFiles,
                       assetsFile,
                       _request.ExistingLockFile,
                       assetsFilePath,
                       cacheFile,
                       cacheFilePath,
                       _request.ProjectStyle,
                       restoreTime.Elapsed));
        }
        public async Task RestoreAsync_WithMinimalProjectAndAdditionalErrorMessage_WritesErrorsToAssetsFile()
        {
            // Arrange
            var projectName = "testproj";
            var logger      = new TestLogger();

            using (var rootFolder = TestDirectory.Create())
            {
                var projectFolder = new DirectoryInfo(Path.Combine(rootFolder, projectName));
                projectFolder.Create();
                var objFolder            = projectFolder.CreateSubdirectory("obj");
                var msbuildProjectPath   = new FileInfo(Path.Combine(projectFolder.FullName, $"{projectName}.csproj"));
                var globalPackagesFolder = Path.Combine(rootFolder, "gpf");

                var sources         = new SourceRepository[0];
                var restoreContext  = new DependencyGraphCacheContext(logger, NullSettings.Instance);
                var solutionManager = new Mock <ISolutionManager>();
                var restoreCommandProvidersCache = new RestoreCommandProvidersCache();

                // When a VS nomination results in an exception, we use this minimal DGSpec to do a restore.
                var dgSpec = DependencyGraphSpecTestUtilities.CreateMinimalDependencyGraphSpec(msbuildProjectPath.FullName, objFolder.FullName);
                dgSpec.AddRestore(dgSpec.Projects[0].FilePath);
                // CpsPackageReferenceProject sets some additional properties, from settings, in GetPackageSpecsAndAdditionalMessages(...)
                dgSpec.Projects[0].RestoreMetadata.PackagesPath = globalPackagesFolder;

                // Having an "additional" error message is also critical
                var restoreLogMessage = new RestoreLogMessage(LogLevel.Error, NuGetLogCode.NU1000, "Test error")
                {
                    FilePath    = msbuildProjectPath.FullName,
                    ProjectPath = msbuildProjectPath.FullName
                };
                var additionalMessages = new List <IAssetsLogMessage>()
                {
                    AssetsLogMessage.Create(restoreLogMessage)
                };

                // Act
                await DependencyGraphRestoreUtility.RestoreAsync(
                    dgSpec,
                    restoreContext,
                    restoreCommandProvidersCache,
                    cacheContextModifier : _ => { },
                    sources,
                    parentId : Guid.Empty,
                    forceRestore : false,
                    isRestoreOriginalAction : true,
                    additionalMessages,
                    progressReporter : null,
                    logger,
                    CancellationToken.None);

                // Assert
                var assetsFilePath = Path.Combine(objFolder.FullName, "project.assets.json");
                Assert.True(File.Exists(assetsFilePath), "Assets file does not exist");
                LockFile          assetsFile    = new LockFileFormat().Read(assetsFilePath);
                IAssetsLogMessage actualMessage = Assert.Single(assetsFile.LogMessages);
                Assert.Equal(restoreLogMessage.Level, actualMessage.Level);
                Assert.Equal(restoreLogMessage.Code, actualMessage.Code);
                Assert.Equal(restoreLogMessage.Message, actualMessage.Message);
            }
        }
예제 #9
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));
            }
        }
예제 #10
0
        public async Task <RestoreResult> ExecuteAsync(CancellationToken token)
        {
            using (var telemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(parentId: ParentId, eventName: ProjectRestoreInformation))
            {
                _operationId = telemetry.OperationId;
                var restoreTime = Stopwatch.StartNew();

                // Local package folders (non-sources)
                var localRepositories = new List <NuGetv3LocalRepository>
                {
                    _request.DependencyProviders.GlobalPackages
                };

                localRepositories.AddRange(_request.DependencyProviders.FallbackPackageFolders);

                var contextForProject = CreateRemoteWalkContext(_request, _logger);

                CacheFile cacheFile = null;
                using (var noOpTelemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(parentId: _operationId, eventName: RestoreNoOpInformation))
                {
                    if (NoOpRestoreUtilities.IsNoOpSupported(_request))
                    {
                        noOpTelemetry.StartIntervalMeasure();

                        var cacheFileAndStatus = EvaluateCacheFile();

                        noOpTelemetry.EndIntervalMeasure(CacheFileEvaluateDuration);

                        cacheFile = cacheFileAndStatus.Key;
                        if (cacheFileAndStatus.Value)
                        {
                            noOpTelemetry.StartIntervalMeasure();

                            var noOpSuccess = NoOpRestoreUtilities.VerifyAssetsAndMSBuildFilesAndPackagesArePresent(_request);

                            noOpTelemetry.EndIntervalMeasure(MsbuildAssetsVerificationDuration);
                            noOpTelemetry.TelemetryEvent[MsbuildAssetsVerificationResult] = noOpSuccess;

                            if (noOpSuccess)
                            {
                                noOpTelemetry.StartIntervalMeasure();

                                // Replay Warnings and Errors from an existing lock file in case of a no-op.
                                await MSBuildRestoreUtility.ReplayWarningsAndErrorsAsync(_request.ExistingLockFile, _logger);

                                noOpTelemetry.EndIntervalMeasure(ReplayLogsDuration);

                                restoreTime.Stop();

                                return(new NoOpRestoreResult(
                                           _success,
                                           _request.ExistingLockFile,
                                           _request.ExistingLockFile,
                                           _request.ExistingLockFile.Path,
                                           cacheFile,
                                           _request.Project.RestoreMetadata.CacheFilePath,
                                           _request.ProjectStyle,
                                           restoreTime.Elapsed));
                            }
                        }
                    }
                }

                IEnumerable <RestoreTargetGraph> graphs = null;
                using (var restoreGraphTelemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(parentId: _operationId, eventName: GenerateRestoreGraph))
                {
                    // Restore
                    graphs = await ExecuteRestoreAsync(
                        _request.DependencyProviders.GlobalPackages,
                        _request.DependencyProviders.FallbackPackageFolders,
                        contextForProject,
                        token,
                        restoreGraphTelemetry);
                }

                LockFile assetsFile = null;
                using (TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(parentId: _operationId, eventName: GenerateAssetsFile))
                {
                    // Create assets file
                    assetsFile = BuildAssetsFile(
                        _request.ExistingLockFile,
                        _request.Project,
                        graphs,
                        localRepositories,
                        contextForProject);
                }

                IList <CompatibilityCheckResult> checkResults = null;
                using (TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(parentId: _operationId, eventName: ValidateRestoreGraphs))
                {
                    _success &= await ValidateRestoreGraphsAsync(graphs, _logger);

                    // Check package compatibility
                    checkResults = await VerifyCompatibilityAsync(
                        _request.Project,
                        _includeFlagGraphs,
                        localRepositories,
                        assetsFile,
                        graphs,
                        _request.ValidateRuntimeAssets,
                        _logger);

                    if (checkResults.Any(r => !r.Success))
                    {
                        _success = false;
                    }
                }

                // Generate Targets/Props files
                var    msbuildOutputFiles = Enumerable.Empty <MSBuildOutputFile>();
                string assetsFilePath     = null;
                string cacheFilePath      = null;
                using (TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(parentId: _operationId, eventName: CreateRestoreResult))
                {
                    // Determine the lock file output path
                    assetsFilePath = GetAssetsFilePath(assetsFile);

                    // Determine the cache file output path
                    cacheFilePath = NoOpRestoreUtilities.GetCacheFilePath(_request, assetsFile);

                    // Tool restores are unique since the output path is not known until after restore
                    if (_request.LockFilePath == null &&
                        _request.ProjectStyle == ProjectStyle.DotnetCliTool)
                    {
                        _request.LockFilePath = assetsFilePath;
                    }

                    if (contextForProject.IsMsBuildBased)
                    {
                        msbuildOutputFiles = BuildAssetsUtils.GetMSBuildOutputFiles(
                            _request.Project,
                            assetsFile,
                            graphs,
                            localRepositories,
                            _request,
                            assetsFilePath,
                            _success,
                            _logger);
                    }

                    // If the request is for a lower lock file version, downgrade it appropriately
                    DowngradeLockFileIfNeeded(assetsFile);

                    // Revert to the original case if needed
                    await FixCaseForLegacyReaders(graphs, assetsFile, token);

                    // Write the logs into the assets file
                    var logs = _logger.Errors
                               .Select(l => AssetsLogMessage.Create(l))
                               .ToList();

                    _success &= !logs.Any(l => l.Level == LogLevel.Error);

                    assetsFile.LogMessages = logs;

                    if (cacheFile != null)
                    {
                        cacheFile.Success = _success;
                    }

                    var errorCodes   = ConcatAsString(new HashSet <NuGetLogCode>(logs.Where(l => l.Level == LogLevel.Error).Select(l => l.Code)));
                    var warningCodes = ConcatAsString(new HashSet <NuGetLogCode>(logs.Where(l => l.Level == LogLevel.Warning).Select(l => l.Code)));

                    if (!string.IsNullOrEmpty(errorCodes))
                    {
                        telemetry.TelemetryEvent[ErrorCodes] = errorCodes;
                    }

                    if (!string.IsNullOrEmpty(warningCodes))
                    {
                        telemetry.TelemetryEvent[WarningCodes] = warningCodes;
                    }

                    telemetry.TelemetryEvent[RestoreSuccess] = _success;
                }

                restoreTime.Stop();

                // Create result
                return(new RestoreResult(
                           _success,
                           graphs,
                           checkResults,
                           msbuildOutputFiles,
                           assetsFile,
                           _request.ExistingLockFile,
                           assetsFilePath,
                           cacheFile,
                           cacheFilePath,
                           _request.ProjectStyle,
                           restoreTime.Elapsed));
            }
        }