コード例 #1
0
        public async Task <bool> NominateProjectAsync(string projectUniqueName, CancellationToken token)
        {
            Assumes.NotNullOrEmpty(projectUniqueName);

            if (!_projectSystemCache.TryGetProjectNames(projectUniqueName, out ProjectNames projectNames))
            {
                IVsSolution2 vsSolution2 = await _vsSolution2.GetValueAsync(token);

                projectNames = await ProjectNames.FromIVsSolution2(projectUniqueName, vsSolution2, token);
            }
            var dgSpec      = new DependencyGraphSpec();
            var packageSpec = new PackageSpec()
            {
                Name = projectUniqueName
            };

            dgSpec.AddProject(packageSpec);
            dgSpec.AddRestore(packageSpec.Name);
            _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec, new List <IAssetsLogMessage>());

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

            return(await restoreTask);
        }
コード例 #2
0
        public async Task <bool> RestoreAsync(SolutionRestoreRequest request, CancellationToken token)
        {
            // Signal that restore is running
            _isCompleteEvent.Reset();

            try
            {
                using (_joinableCollection.Join())
                {
                    await StartInitializationAsync();

                    using (var restoreOperation = new BackgroundRestoreOperation())
                    {
                        await PromoteTaskToActiveAsync(restoreOperation, token);

                        var result = await ProcessRestoreRequestAsync(restoreOperation, request, token);

                        return(result);
                    }
                }
            }
            finally
            {
                // Signal that restore has been completed.
                _isCompleteEvent.Set();
            }
        }
コード例 #3
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);

                var dgSpec = ToDependencyGraphSpec(projectNames, projectRestoreInfo, projectRestoreInfo2);

                _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec);

                // 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());
                return(Task.FromResult(false));
            }
        }
コード例 #4
0
        private async Task <bool> StartRestoreJobAsync(
            SolutionRestoreRequest request, CancellationToken token)
        {
            await TaskScheduler.Default;

            using (var jobCts = CancellationTokenSource.CreateLinkedTokenSource(token))
            {
                return(await _lockService.Value.ExecuteNuGetOperationAsync(async() =>
                {
                    var componentModel = await _componentModel.GetValueAsync(jobCts.Token);

                    using (var logger = componentModel.GetService <RestoreOperationLogger>())
                    {
                        try
                        {
                            // Start logging
                            await logger.StartAsync(
                                request.RestoreSource,
                                _errorListTableDataSource,
                                _joinableFactory,
                                jobCts);

                            // Run restore
                            var job = componentModel.GetService <ISolutionRestoreJob>();
                            return await job.ExecuteAsync(request, _restoreJobContext, logger, jobCts.Token);
                        }
                        finally
                        {
                            // Complete all logging
                            await logger.StopAsync();
                        }
                    }
                }, jobCts.Token));
            }
        }
コード例 #5
0
        public async Task RestoreSolutionAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            await _initializer.InitializeAsync(cancellationToken);

            await SolutionRestoreWorker.Value.ScheduleRestoreAsync(SolutionRestoreRequest.ByUserCommand(ExplicitRestoreReason.RestoreSolutionPackages), cancellationToken);
        }
コード例 #6
0
        public async Task RestoreSolutionAsync(CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            await _initializer.InitializeAsync(cancellationToken);

            await SolutionRestoreWorker.Value.ScheduleRestoreAsync(SolutionRestoreRequest.ByMenu(), cancellationToken);
        }
コード例 #7
0
        private async Task <bool> RestoreProjectAsync(CancellationToken token)
        {
            await ShowProgressUIAsync();

            OperationId = Guid.NewGuid();

            return(await _solutionRestoreWorker.ScheduleRestoreAsync(
                       SolutionRestoreRequest.ByMenu(),
                       token));
        }
コード例 #8
0
        private async Task <bool> RestoreProjectAsync(CancellationToken token)
        {
            await ShowProgressUIAsync();

            OperationId = Guid.NewGuid();

            return(await _solutionRestoreWorker.ScheduleRestoreAsync(
                       SolutionRestoreRequest.ByUserCommand(ExplicitRestoreReason.MissingPackagesBanner),
                       token));
        }
コード例 #9
0
 /// <summary>
 /// This function is the callback used to execute the command when the menu item is clicked.
 /// See the constructor to see how the menu item is associated with this function using
 /// OleMenuCommandService service and MenuCommand class.
 /// </summary>
 /// <param name="sender">Event sender.</param>
 /// <param name="e">Event args.</param>
 private void OnRestorePackages(object sender, EventArgs args)
 {
     if (_restoreTask.IsCompleted)
     {
         _restoreTask = NuGetUIThreadHelper.JoinableTaskFactory
                        .RunAsync(() => SolutionRestoreWorker.Value.ScheduleRestoreAsync(
                                      SolutionRestoreRequest.ByMenu(),
                                      CancellationToken.None))
                        .Task;
     }
 }
コード例 #10
0
        public Task <bool> NominateProjectAsync(string projectUniqueName, CancellationToken token)
        {
            Assumes.NotNullOrEmpty(projectUniqueName);

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

            return(restoreTask);
        }
コード例 #11
0
        public async Task Simple_WhenCancelled_Reports_Cancelled_Async()
        {
            var restoreMan = Mock.Of <IPackageRestoreManager>();

            _globalProvider.AddService(typeof(IPackageRestoreManager), restoreMan);
            var slnMan = Mock.Of <IVsSolutionManager>();

            _globalProvider.AddService(typeof(IVsSolutionManager), slnMan);
            ISourceRepositoryProvider sourceRepositoryProvider = TestSourceRepositoryUtility.CreateV3OnlySourceRepositoryProvider();

            _globalProvider.AddService(typeof(ISourceRepositoryProvider), sourceRepositoryProvider);

            var restoreChecker        = Mock.Of <ISolutionRestoreChecker>();
            var eventsPublisher       = Mock.Of <IRestoreEventsPublisher>();
            var settings              = Mock.Of <ISettings>();
            var nuGetProgressReporter = Mock.Of <IVsNuGetProgressReporter>();

            Mock.Get(settings)
            .Setup(x => x.GetSection("packageRestore"))
            .Returns(() => new VirtualSettingSection("packageRestore",
                                                     new AddItem("automatic", bool.TrueString)));

            var consoleProvider = Mock.Of <IOutputConsoleProvider>();
            var logger          = new RestoreOperationLogger(new Lazy <IOutputConsoleProvider>(() => consoleProvider));

            var job = new SolutionRestoreJob(
                asyncServiceProvider: AsyncServiceProvider.GlobalProvider,
                packageRestoreManager: restoreMan,
                solutionManager: slnMan,
                sourceRepositoryProvider: sourceRepositoryProvider,
                restoreEventsPublisher: eventsPublisher,
                settings: settings,
                solutionRestoreChecker: restoreChecker,
                nuGetProgressReporter: nuGetProgressReporter);

            var restoreRequest = new SolutionRestoreRequest(
                forceRestore: true,
                RestoreOperationSource.OnBuild);
            var restoreJobContext = new SolutionRestoreJobContext();

            var cts = new CancellationTokenSource();

            cts.Cancel();

            await job.ExecuteAsync(
                request : restoreRequest,
                jobContext : restoreJobContext,
                logger : logger,
                trackingData : new Dictionary <string, object>(),
                token : cts.Token);

            Assert.Equal(NuGetOperationStatus.Cancelled, job.Status);
        }
コード例 #12
0
        /// <summary>
        /// Restore job entry point. Not re-entrant.
        /// </summary>
        public async Task <bool> ExecuteAsync(
            SolutionRestoreRequest request,
            SolutionRestoreJobContext jobContext,
            RestoreOperationLogger logger,
            CancellationToken token)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (jobContext == null)
            {
                throw new ArgumentNullException(nameof(jobContext));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            _logger = logger;

            // update instance attributes with the shared context values
            _dependencyGraphProjectCacheHash = jobContext.DependencyGraphProjectCacheHash;
            _nuGetProjectContext             = jobContext.NuGetProjectContext;

            using (var ctr1 = token.Register(() => _status = NuGetOperationStatus.Cancelled))
            {
                try
                {
                    await RestoreAsync(request.ForceRestore, request.RestoreSource, token);
                }
                catch (OperationCanceledException) when(token.IsCancellationRequested)
                {
                }
                catch (Exception e)
                {
                    // Log the exception to the console and activity log
                    await _logger.LogExceptionAsync(e);
                }
                finally
                {
                    // update shared context values with instance attributes
                    jobContext.DependencyGraphProjectCacheHash = _dependencyGraphProjectCacheHash;
                }
            }

            return(_status == NuGetOperationStatus.NoOp || _status == NuGetOperationStatus.Succeeded);
        }
コード例 #13
0
        public Task <bool> NominateProjectAsync(string projectUniqueName, IVsProjectRestoreInfo projectRestoreInfo, CancellationToken token)
        {
            if (string.IsNullOrEmpty(projectUniqueName))
            {
                throw new ArgumentException(Resources.Argument_Cannot_Be_Null_Or_Empty, nameof(projectUniqueName));
            }

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

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

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

                var projectNames = ProjectNames.FromFullProjectPath(projectUniqueName);

                var dgSpec = ToDependencyGraphSpec(projectNames, projectRestoreInfo);
#if DEBUG
                DumpProjectRestoreInfo(projectUniqueName, dgSpec);
#endif
                _projectSystemCache.AddProjectRestoreInfo(projectNames, dgSpec);

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

                return(restoreTask);
            }
            catch (Exception e)
                when(e is InvalidOperationException || e is ArgumentException || e is FormatException)
                {
                    _logger.LogError(e.ToString());
                    return(Task.FromResult(false));
                }
            catch (Exception e)
            {
                _logger.LogError(e.ToString());
                throw;
            }
        }
コード例 #14
0
        private async Task <bool> ProcessRestoreRequestAsync(
            BackgroundRestoreOperation restoreOperation,
            SolutionRestoreRequest request,
            CancellationToken token)
        {
            // Start the restore job in a separate task on a background thread
            // it will switch into main thread when necessary.
            var joinableTask = _joinableFactory.RunAsync(
                () => StartRestoreJobAsync(request, token));

            var continuation = joinableTask
                               .Task
                               .ContinueWith(t => restoreOperation.ContinuationAction(t));

            return(await joinableTask);
        }
コード例 #15
0
            public static RestoreTask Start(ISolutionRestoreWorker worker, bool forceRestore)
            {
                var cts  = new CancellationTokenSource();
                var task = worker
                           .JoinableTaskFactory
                           .RunAsync(() => worker.ScheduleRestoreAsync(
                                         SolutionRestoreRequest.OnBuild(forceRestore),
                                         cts.Token))
                           .Task;

                return(new RestoreTask
                {
                    _cts = cts,
                    _task = task
                });
            }
コード例 #16
0
        public async Task <bool> RestoreAsync(SolutionRestoreRequest request, CancellationToken token)
        {
            using (_joinableCollection.Join())
            {
                // Initialize if not already done.
                await InitializeAsync();

                using (var restoreOperation = new BackgroundRestoreOperation())
                {
                    await PromoteTaskToActiveAsync(restoreOperation, token);

                    var result = await ProcessRestoreRequestAsync(restoreOperation, request, token);

                    return(result);
                }
            }
        }
コード例 #17
0
        /// <summary>
        /// Restore job entry point. Not re-entrant.
        /// </summary>
        public async Task <bool> ExecuteAsync(
            SolutionRestoreRequest request,
            SolutionRestoreJobContext jobContext,
            RestoreOperationLogger logger,
            bool isSolutionLoadRestore,
            CancellationToken token)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (jobContext == null)
            {
                throw new ArgumentNullException(nameof(jobContext));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            _logger = logger;

            // update instance attributes with the shared context values
            _nuGetProjectContext             = jobContext.NuGetProjectContext;
            _nuGetProjectContext.OperationId = request.OperationId;
            _isSolutionLoadRestore           = isSolutionLoadRestore;

            try
            {
                await RestoreAsync(request.ForceRestore, request.RestoreSource, token);
            }
            catch (OperationCanceledException)
            {
            }
            catch (Exception e)
            {
                // Log the exception to the console and activity log
                await _logger.LogExceptionAsync(e);
            }

            return(_status == NuGetOperationStatus.NoOp || _status == NuGetOperationStatus.Succeeded);
        }
コード例 #18
0
        public async Task <bool> ScheduleRestoreAsync(
            SolutionRestoreRequest request, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return(false);
            }

            // Initialize if not already done.
            await InitializeAsync();

            var pendingRestore = _pendingRestore;

            // on-board request onto pending restore operation
            _pendingRequests.Value.TryAdd(request);

            try
            {
                using (_joinableCollection.Join())
                {
                    // Await completion of the requested restore operation or
                    // preliminary termination of the job runner.
                    // The caller will be unblocked immediately upon
                    // cancellation request via provided token.
                    return(await await Task
                           .WhenAny(
                               pendingRestore.Task,
                               _backgroundJobRunner.GetValueAsync())
                           .WithCancellation(token));
                }
            }
            catch (OperationCanceledException) when(token.IsCancellationRequested)
            {
                return(false);
            }
            catch (Exception e)
            {
                Logger.LogError(e.ToString());
                return(false);
            }
        }
コード例 #19
0
        /// <summary>
        /// This function is the callback used to execute the command when the menu item is clicked.
        /// See the constructor to see how the menu item is associated with this function using
        /// OleMenuCommandService service and MenuCommand class.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event args.</param>
        private void OnRestorePackages(object sender, EventArgs args)
        {
            if (!_isMEFInitialized)
            {
                NuGetUIThreadHelper.JoinableTaskFactory.Run(async() =>
                {
                    await InitializeMEFAsync();
                });

                _isMEFInitialized = true;
            }

            if (_restoreTask.IsCompleted)
            {
                _restoreTask = NuGetUIThreadHelper.JoinableTaskFactory
                               .RunAsync(() => SolutionRestoreWorker.Value.ScheduleRestoreAsync(
                                             SolutionRestoreRequest.ByUserCommand(ExplicitRestoreReason.RestoreSolutionPackages),
                                             CancellationToken.None))
                               .Task;
            }
        }
コード例 #20
0
        private void BuildEvents_OnBuildBegin(
            EnvDTE.vsBuildScope scope, EnvDTE.vsBuildAction Action)
        {
            if (Action == EnvDTE.vsBuildAction.vsBuildActionClean)
            {
                // Clear the project.json restore cache on clean to ensure that the next build restores again
                SolutionRestoreWorker.CleanCache();

                return;
            }

            if (!ShouldRestoreOnBuild)
            {
                return;
            }

            var forceRestore = Action == EnvDTE.vsBuildAction.vsBuildActionRebuildAll;

            // Execute
            SolutionRestoreWorker.Restore(SolutionRestoreRequest.OnBuild(forceRestore));
        }
コード例 #21
0
        private async Task <bool> ProcessRestoreRequestAsync(
            BackgroundRestoreOperation restoreOperation,
            SolutionRestoreRequest request,
            CancellationToken token)
        {
            // if the request is implicit & this is the first restore, assume we are restoring due to a solution load.
            var isSolutionLoadRestore = _isFirstRestore &&
                                        request.RestoreSource == RestoreOperationSource.Implicit;

            _isFirstRestore = false;

            // Start the restore job in a separate task on a background thread
            // it will switch into main thread when necessary.
            var joinableTask = JoinableTaskFactory.RunAsync(
                () => StartRestoreJobAsync(request, isSolutionLoadRestore, token));

            var continuation = joinableTask
                               .Task
                               .ContinueWith(t => restoreOperation.ContinuationAction(t, JoinableTaskFactory));

            return(await joinableTask);
        }
コード例 #22
0
        public bool Restore(SolutionRestoreRequest request)
        {
            return(_joinableFactory.Run(
                       async() =>
            {
                using (_joinableCollection.Join())
                {
                    // Initialize if not already done.
                    await InitializeAsync();

                    using (var restoreOperation = new BackgroundRestoreOperation())
                    {
                        await PromoteTaskToActiveAsync(restoreOperation, _workerCts.Token);

                        var result = await ProcessRestoreRequestAsync(restoreOperation, request, _workerCts.Token);

                        return result;
                    }
                }
            },
                       JoinableTaskCreationOptions.LongRunning));
        }
コード例 #23
0
        public async Task <bool> RestoreAsync(uint buildAction, CancellationToken token)
        {
            // move to bg thread to continue with restore
            await TaskScheduler.Default;

            if ((buildAction & (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_CLEAN) != 0 &&
                (buildAction & (uint)VSSOLNBUILDUPDATEFLAGS3.SBF_FLAGS_UPTODATE_CHECK) == 0)
            {
                // Clear the project.json restore cache on clean to ensure that the next build restores again
                await SolutionRestoreWorker.Value.CleanCacheAsync();
            }
            else if ((buildAction & (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD) != 0 &&
                     (buildAction & (uint)VSSOLNBUILDUPDATEFLAGS3.SBF_FLAGS_UPTODATE_CHECK) == 0 &&
                     ShouldRestoreOnBuild)
            {
                // start a restore task
                var forceRestore = (buildAction & (uint)VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_FORCE_UPDATE) != 0;

                var restoreTask = SolutionRestoreWorker.Value.JoinableTaskFactory.RunAsync(() =>
                                                                                           SolutionRestoreWorker.Value.RestoreAsync(
                                                                                               SolutionRestoreRequest.OnBuild(forceRestore),
                                                                                               token));

                // wait until restore is done which will block build without blocking UI thread
                return(await restoreTask);
            }

            return(true);
        }
コード例 #24
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));
            }
        }
コード例 #25
0
        private async Task <bool> StartBackgroundJobRunnerAsync(CancellationToken token)
        {
            // Hops onto a background pool thread
            await TaskScheduler.Default;

            var status = false;

            // Check if the solution is fully loaded
            while (!_solutionLoadedEvent.IsSet)
            {
                // Needed when OnAfterBackgroundSolutionLoadComplete fires before
                // Advise has been called.
                if (await IsSolutionFullyLoadedAsync())
                {
                    _solutionLoadedEvent.Set();
                    break;
                }
                else
                {
                    // Waits for 100ms to let solution fully load or canceled
                    await _solutionLoadedEvent.WaitAsync()
                    .WithTimeout(TimeSpan.FromMilliseconds(DelaySolutionLoadRetry))
                    .WithCancellation(token);
                }
            }

            // Loops until there are pending restore requests or it's get cancelled
            while (!token.IsCancellationRequested)
            {
                lock (_lockPendingRequestsObj)
                {
                    // if no pending restore requests then shut down the restore job runner.
                    if (_pendingRequests.Value.Count == 0)
                    {
                        break;
                    }
                }

                // Grabs a local copy of pending restore operation
                using (var restoreOperation = _pendingRestore)
                {
                    try
                    {
                        // Blocks the execution until first request is scheduled
                        // Monitors the cancelllation token as well.
                        var request = _pendingRequests.Value.Take(token);

                        token.ThrowIfCancellationRequested();

                        // Claims the ownership over the active task
                        // Awaits for currently running restore to complete
                        await PromoteTaskToActiveAsync(restoreOperation, token);

                        token.ThrowIfCancellationRequested();
                        DateTime lastNominationReceived = DateTime.UtcNow;

                        // Drains the queue
                        while (!_pendingRequests.Value.IsCompleted &&
                               !token.IsCancellationRequested)
                        {
                            SolutionRestoreRequest next;

                            // check if there are pending nominations
                            var isAllProjectsNominated = await _solutionManager.Value.IsAllProjectsNominatedAsync();

                            // Try to get a request without a timeout. We don't want to *block* the threadpool thread.
                            if (!_pendingRequests.Value.TryTake(out next, millisecondsTimeout: 0, token))
                            {
                                if (isAllProjectsNominated)
                                {
                                    // if we've got all the nominations then continue with the auto restore
                                    break;
                                }
                                else
                                {
                                    // Break if we've waited for more than 10s without an actual nomination.
                                    if (lastNominationReceived.AddMilliseconds(MaxIdleWaitTimeMs) < DateTime.UtcNow)
                                    {
                                        break;
                                    }
                                    await Task.Delay(IdleTimeoutMs, token);
                                }
                            }
                            else
                            {
                                lastNominationReceived = DateTime.UtcNow;
                                // Upgrade request if necessary
                                if (next != null && next.RestoreSource != request.RestoreSource)
                                {
                                    // there could be requests of two types: Auto-Restore or Explicit
                                    // Explicit is always preferred.
                                    request = new SolutionRestoreRequest(
                                        next.ForceRestore || request.ForceRestore,
                                        RestoreOperationSource.Explicit);

                                    // we don't want to delay explicit solution restore request so just break at this time.
                                    break;
                                }
                            }
                        }

                        token.ThrowIfCancellationRequested();

                        // Replaces pending restore operation with a new one.
                        // Older value is ignored.
                        var ignore = Interlocked.CompareExchange(
                            ref _pendingRestore, new BackgroundRestoreOperation(), restoreOperation);

                        token.ThrowIfCancellationRequested();

                        // Runs restore job with scheduled request params
                        status = await ProcessRestoreRequestAsync(restoreOperation, request, token);

                        // Repeats...
                    }
                    catch (OperationCanceledException) when(token.IsCancellationRequested)
                    {
                        // Ignores
                    }
                    catch (Exception e)
                    {
                        // Writes stack to activity log
                        Logger.LogError(e.ToString());
                        // Do not die just yet
                    }
                }
            }

            return(status);
        }
コード例 #26
0
        private async Task <bool> StartBackgroundJobRunnerAsync(CancellationToken token)
        {
            // Hops onto a background pool thread
            await TaskScheduler.Default;

            // Waits until the solution is fully loaded or canceled
            await _solutionLoadedEvent.WaitAsync().WithCancellation(token);

            // Loops forever until it's get cancelled
            while (!token.IsCancellationRequested)
            {
                // Grabs a local copy of pending restore operation
                using (var restoreOperation = _pendingRestore)
                {
                    try
                    {
                        // Blocks the execution until first request is scheduled
                        // Monitors the cancelllation token as well.
                        var request = _pendingRequests.Value.Take(token);

                        token.ThrowIfCancellationRequested();

                        // Claims the ownership over the active task
                        // Awaits for currently running restore to complete
                        await PromoteTaskToActiveAsync(restoreOperation, token);

                        token.ThrowIfCancellationRequested();

                        var retries = 0;

                        // Drains the queue
                        while (!_pendingRequests.Value.IsCompleted &&
                               !token.IsCancellationRequested)
                        {
                            SolutionRestoreRequest next;

                            // check if there are pending nominations
                            var isAllProjectsNominated = _solutionManager.Value.IsAllProjectsNominated();

                            if (!_pendingRequests.Value.TryTake(out next, IdleTimeoutMs, token))
                            {
                                if (isAllProjectsNominated)
                                {
                                    // if we've got all the nominations then continue with the auto restore
                                    break;
                                }
                            }

                            // Upgrade request if necessary
                            if (next.RestoreSource != request.RestoreSource)
                            {
                                // there could be requests of two types: Auto-Restore or Explicit
                                // Explicit is always preferred.
                                request = new SolutionRestoreRequest(
                                    next.ForceRestore || request.ForceRestore,
                                    RestoreOperationSource.Explicit);

                                // we don't want to delay explicit solution restore request so just break at this time.
                                break;
                            }

                            if (!isAllProjectsNominated)
                            {
                                if (retries >= DelayAutoRestoreRetries)
                                {
                                    // we're still missing some nominations but don't delay it indefinitely and let auto restore fail.
                                    // we wait until 20 secs for all the projects to be nominated at solution load.
                                    break;
                                }

                                // if we're still expecting some nominations and also haven't reached our max timeout
                                // then increase the retries count.
                                retries++;
                            }
                        }

                        token.ThrowIfCancellationRequested();

                        // Replaces pending restore operation with a new one.
                        // Older value is ignored.
                        var ignore = Interlocked.CompareExchange(
                            ref _pendingRestore, new BackgroundRestoreOperation(), restoreOperation);

                        token.ThrowIfCancellationRequested();

                        // Runs restore job with scheduled request params
                        await ProcessRestoreRequestAsync(restoreOperation, request, token);

                        // Repeats...
                    }
                    catch (OperationCanceledException) when(token.IsCancellationRequested)
                    {
                        // Ignores
                    }
                    catch (Exception e)
                    {
                        // Writes stack to activity log
                        Logger.LogError(e.ToString());
                        // Do not die just yet
                    }
                }
            }

            // returns false on preliminary exit (cancellation)
            return(false);
        }
コード例 #27
0
        private async Task <bool> StartBackgroundJobRunnerAsync(CancellationToken token)
        {
            // Hops onto a background pool thread
            await TaskScheduler.Default;

            // Waits until the solution is fully loaded or canceled
            await _solutionLoadedEvent.WaitAsync().WithCancellation(token);

            // Loops forever until it's get cancelled
            while (!token.IsCancellationRequested)
            {
                // Grabs a local copy of pending restore operation
                using (var restoreOperation = _pendingRestore)
                {
                    try
                    {
                        // Blocks the execution until first request is scheduled
                        // Monitors the cancelllation token as well.
                        var request = _pendingRequests.Value.Take(token);

                        token.ThrowIfCancellationRequested();

                        // Claims the ownership over the active task
                        // Awaits for currently running restore to complete
                        await PromoteTaskToActiveAsync(restoreOperation, token);

                        token.ThrowIfCancellationRequested();

                        // Drains the queue
                        while (!_pendingRequests.Value.IsCompleted &&
                               !token.IsCancellationRequested)
                        {
                            SolutionRestoreRequest next;
                            if (!_pendingRequests.Value.TryTake(out next, IdleTimeoutMs, token))
                            {
                                break;
                            }

                            // Upgrade request if necessary
                            if (next.RestoreSource != request.RestoreSource)
                            {
                                // there could be requests of two types: Auto-Restore or Explicit
                                // Explicit is always preferred.
                                request = new SolutionRestoreRequest(
                                    next.ForceRestore || request.ForceRestore,
                                    RestoreOperationSource.Explicit);
                            }
                        }

                        token.ThrowIfCancellationRequested();

                        // Replaces pending restore operation with a new one.
                        // Older value is ignored.
                        var ignore = Interlocked.CompareExchange(
                            ref _pendingRestore, new BackgroundRestoreOperation(), restoreOperation);

                        token.ThrowIfCancellationRequested();

                        // Runs restore job with scheduled request params
                        await ProcessRestoreRequestAsync(restoreOperation, request, token);

                        // Repeats...
                    }
                    catch (OperationCanceledException) when(token.IsCancellationRequested)
                    {
                        // Ignores
                    }
                    catch (Exception e)
                    {
                        // Writes stack to activity log
                        Logger.LogError(e.ToString());
                        // Do not die just yet
                    }
                }
            }

            // returns false on preliminary exit (cancellation)
            return(false);
        }
コード例 #28
0
        public async Task <bool> ScheduleRestoreAsync(
            SolutionRestoreRequest request, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return(false);
            }

            // Reset to signal that a restore is in progress.
            // This sets IsBusy to true
            _isCompleteEvent.Reset();

            try
            {
                // Initialize if not already done.
                await InitializeAsync();

                var pendingRestore            = _pendingRestore;
                var shouldStartNewBGJobRunner = true;

                // lock _pendingRequests to figure out if we need to start a new background job for restore
                // or if there is already one running which will also take care of current request.
                lock (_lockPendingRequestsObj)
                {
                    // check if there are already pending restore request or active restore task
                    // then don't initiate a new background job runner.
                    if (_pendingRequests.Value.Count > 0 || IsBusy)
                    {
                        shouldStartNewBGJobRunner = false;
                    }
                    else if (_lockService.Value.IsLockHeld && _lockService.Value.LockCount > 0)
                    {
                        // when restore is not running but NuGet lock is still held for the current async operation,
                        // then it means other NuGet operation like Install or Update are in progress which will
                        // take care of running restore for appropriate projects so skipping auto restore in that case.
                        return(true);
                    }

                    // on-board request onto pending restore operation
                    _pendingRequests.Value.TryAdd(request);
                }

                try
                {
                    using (_joinableCollection.Join())
                    {
                        // when there is no current background restore job running, then it will start a new one.
                        // else, current requrest will also await the existing job to be completed.
                        if (shouldStartNewBGJobRunner)
                        {
                            _backgroundJobRunner = new AsyncLazy <bool>(
                                () => StartBackgroundJobRunnerAsync(_workerCts.Token),
                                _joinableFactory);
                        }

                        // Await completion of the requested restore operation or
                        // completion of the current job runner.
                        // The caller will be unblocked immediately upon
                        // cancellation request via provided token.
                        return(await await Task
                               .WhenAny(
                                   pendingRestore.Task,
                                   _backgroundJobRunner.GetValueAsync())
                               .WithCancellation(token));
                    }
                }
                catch (OperationCanceledException) when(token.IsCancellationRequested)
                {
                    return(false);
                }
                catch (Exception e)
                {
                    Logger.LogError(e.ToString());
                    return(false);
                }
            }
            finally
            {
                // Signal that all pending operations are complete.
                _isCompleteEvent.Set();
            }
        }
コード例 #29
0
        int IVsTrackBatchRetargetingEvents.OnBatchRetargetingEnd()
        {
            NuGetProject nuGetProject = null;

            NuGetUIThreadHelper.JoinableTaskFactory.Run(async delegate
            {
                await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                _errorListProvider.Tasks.Clear();
                if (_platformRetargetingProject != null)
                {
                    try
                    {
                        var project = _dte.Solution.Item(_platformRetargetingProject);

                        if (project != null)
                        {
                            nuGetProject = EnvDTEProjectUtility.GetNuGetProject(project, _solutionManager);

                            if (ProjectRetargetingUtility.IsProjectRetargetable(nuGetProject))
                            {
                                var frameworkName = EnvDTEProjectUtility.GetTargetFrameworkString(project);
                                if (NETCore451.Equals(frameworkName, StringComparison.OrdinalIgnoreCase) || Windows81.Equals(frameworkName, StringComparison.OrdinalIgnoreCase))
                                {
                                    IList <PackageIdentity> packagesToBeReinstalled = await ProjectRetargetingUtility.GetPackagesToBeReinstalled(nuGetProject);
                                    if (packagesToBeReinstalled.Count > 0)
                                    {
                                        // By asserting that NuGet is in use, we are also asserting that NuGet.VisualStudio.dll is already loaded
                                        // Hence, it is okay to call project.ToVsHierarchy()
                                        Debug.Assert(ProjectRetargetingUtility.IsNuGetInUse(project));
                                        IVsHierarchy projectHierarchy = VsHierarchyUtility.ToVsHierarchy(project);
                                        ShowRetargetingErrorTask(packagesToBeReinstalled.Select(p => p.Id), projectHierarchy, TaskErrorCategory.Error, TaskPriority.High);
                                    }
                                    ProjectRetargetingUtility.MarkPackagesForReinstallation(nuGetProject, packagesToBeReinstalled);
                                }
                            }
                        }
                    }
                    catch (ArgumentException)
                    {
                        // If the solution does not contain a project named '_platformRetargetingProject', it will throw ArgumentException
                    }
                    _platformRetargetingProject = null;
                }
            });
#if !VS14
            if (nuGetProject != null && nuGetProject is LegacyCSProjPackageReferenceProject)
            {
                // trigger solution restore and don't wait for it to be complete and hold the UI thread
                System.Threading.Tasks.Task.Run(() => _solutionRestoreWorker.Value.ScheduleRestoreAsync(SolutionRestoreRequest.ByMenu(), CancellationToken.None));
            }
#endif
            return(VSConstants.S_OK);
        }
コード例 #30
0
        int IVsTrackProjectRetargetingEvents.OnRetargetingAfterChange(string projRef, IVsHierarchy pAfterChangeHier, string fromTargetFramework, string toTargetFramework)
        {
            NuGetProject retargetedProject = null;

            NuGetUIThreadHelper.JoinableTaskFactory.Run(async delegate
            {
                await NuGetUIThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                _errorListProvider.Tasks.Clear();
                var project       = VsHierarchyUtility.GetProjectFromHierarchy(pAfterChangeHier);
                retargetedProject = EnvDTEProjectUtility.GetNuGetProject(project, _solutionManager);

                if (ProjectRetargetingUtility.IsProjectRetargetable(retargetedProject))
                {
                    var packagesToBeReinstalled = await ProjectRetargetingUtility.GetPackagesToBeReinstalled(retargetedProject);
                    if (packagesToBeReinstalled.Any())
                    {
                        ShowRetargetingErrorTask(packagesToBeReinstalled.Select(p => p.Id), pAfterChangeHier, TaskErrorCategory.Error, TaskPriority.High);
                    }
                    ProjectRetargetingUtility.MarkPackagesForReinstallation(retargetedProject, packagesToBeReinstalled);
                }
            });
#if !VS14
            if (retargetedProject != null && retargetedProject is LegacyCSProjPackageReferenceProject)
            {
                // trigger solution restore and don't wait for it to be complete and hold the UI thread
                System.Threading.Tasks.Task.Run(() => _solutionRestoreWorker.Value.ScheduleRestoreAsync(SolutionRestoreRequest.ByMenu(), CancellationToken.None));
            }
#endif
            return(VSConstants.S_OK);
        }