public async Task TestCheckForMissingPackages() { // Arrange var testSolutionManager = new TestSolutionManager(); var projectA = testSolutionManager.AddNewMSBuildProject(); var projectB = testSolutionManager.AddNewMSBuildProject(); var packageIdentity = new PackageIdentity("packageA", new NuGetVersion("1.0.0")); var randomPackageSourcePath = TestFilesystemUtility.CreateRandomTestFolder(); var packageFileInfo = TestPackages.GetLegacyTestPackage(randomPackageSourcePath, packageIdentity.Id, packageIdentity.Version.ToNormalizedString()); var testNuGetProjectContext = new TestNuGetProjectContext(); var token = CancellationToken.None; using (var packageStream = packageFileInfo.OpenRead()) { // Act await projectA.InstallPackageAsync(packageIdentity, packageStream, testNuGetProjectContext, token); await projectB.InstallPackageAsync(packageIdentity, packageStream, testNuGetProjectContext, token); } var sourceRepositoryProvider = TestSourceRepositoryUtility.CreateV3OnlySourceRepositoryProvider(); var testSettings = NullSettings.Instance; var packageRestoreManager = new PackageRestoreManager(sourceRepositoryProvider, testSettings, testSolutionManager); int packagesMissingEventCount = 0; bool packagesMissing = false; packageRestoreManager.PackagesMissingStatusChanged += delegate(object sender, PackagesMissingStatusEventArgs args) { packagesMissingEventCount++; packagesMissing = args.PackagesMissing; }; // Act await packageRestoreManager.RaisePackagesMissingEventForSolution(token); // Assert Assert.Equal(1, packagesMissingEventCount); Assert.False(packagesMissing); // Delete packages folder Directory.Delete(Path.Combine(testSolutionManager.SolutionDirectory, "packages"), recursive: true); // Act await packageRestoreManager.RaisePackagesMissingEventForSolution(token); // Assert Assert.Equal(2, packagesMissingEventCount); Assert.True(packagesMissing); }
private async System.Threading.Tasks.Task RestorePackagesOrCheckForMissingPackages(vsBuildScope scope) { _msBuildOutputVerbosity = GetMSBuildOutputVerbositySetting(_dte); var waitDialogFactory = ServiceLocator.GetGlobalService <SVsThreadedWaitDialogFactory, IVsThreadedWaitDialogFactory>(); waitDialogFactory.CreateInstance(out _waitDialog); var token = CancellationTokenSource.Token; try { if (IsConsentGranted()) { if (scope == vsBuildScope.vsBuildScopeSolution || scope == vsBuildScope.vsBuildScopeBatch || scope == vsBuildScope.vsBuildScopeProject) { TotalCount = (await PackageRestoreManager.GetMissingPackagesInSolution(token)).ToList().Count; if (TotalCount > 0) { if (_outputOptOutMessage) { _waitDialog.StartWaitDialog( Resources.DialogTitle, Resources.RestoringPackages, String.Empty, varStatusBmpAnim: null, szStatusBarText: null, iDelayToShowDialog: 0, fIsCancelable: true, fShowMarqueeProgress: true); WriteLine(VerbosityLevel.Quiet, Resources.PackageRestoreOptOutMessage); _outputOptOutMessage = false; } System.Threading.Tasks.Task waitDialogCanceledCheckTask = System.Threading.Tasks.Task.Run(() => { // Just create an extra task that can keep checking if the wait dialog was cancelled // If so, cancel the CancellationTokenSource bool canceled = false; try { while (!canceled && CancellationTokenSource != null && !CancellationTokenSource.IsCancellationRequested && _waitDialog != null) { _waitDialog.HasCanceled(out canceled); // Wait on the cancellation handle for 100ms to avoid checking on the wait dialog too frequently CancellationTokenSource.Token.WaitHandle.WaitOne(100); } CancellationTokenSource.Cancel(); } catch (Exception) { // Catch all and don't throw // There is a slight possibility that the _waitDialog was set to null by another thread right after the check for null // So, it could be null or disposed. Just ignore all errors } }); System.Threading.Tasks.Task whenAllTaskForRestorePackageTasks = System.Threading.Tasks.Task.WhenAll(SolutionManager.GetNuGetProjects().Select(nuGetProject => RestorePackagesInProject(nuGetProject, token))); await System.Threading.Tasks.Task.WhenAny(whenAllTaskForRestorePackageTasks, waitDialogCanceledCheckTask); // Once all the tasks are completed, just cancel the CancellationTokenSource // This will prevent the wait dialog from getting updated CancellationTokenSource.Cancel(); } } else { throw new NotImplementedException(); } } else { _waitDialog.StartWaitDialog( Resources.DialogTitle, Resources.RestoringPackages, String.Empty, varStatusBmpAnim: null, szStatusBarText: null, iDelayToShowDialog: 0, fIsCancelable: true, fShowMarqueeProgress: true); CheckForMissingPackages((await PackageRestoreManager.GetMissingPackagesInSolution(token)).ToList()); } } finally { int canceled; _waitDialog.EndWaitDialog(out canceled); _waitDialog = null; } await PackageRestoreManager.RaisePackagesMissingEventForSolution(CancellationToken.None); }