public async Task ExecuteNuGetProjectActionsAsync()

in src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs [2498:2822]


        public async Task ExecuteNuGetProjectActionsAsync(NuGetProject nuGetProject,
            IEnumerable<NuGetProjectAction> nuGetProjectActions,
            INuGetProjectContext nuGetProjectContext,
            PackageDownloadContext downloadContext,
            CancellationToken token)
        {
            if (nuGetProject == null)
            {
                throw new ArgumentNullException(nameof(nuGetProject));
            }

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

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

            var stopWatch = Stopwatch.StartNew();

            ExceptionDispatchInfo exceptionInfo = null;

            // DNU: Find the closure before executing the actions
            var buildIntegratedProject = nuGetProject as BuildIntegratedNuGetProject;
            if (buildIntegratedProject != null)
            {
                await ExecuteBuildIntegratedProjectActionsAsync(buildIntegratedProject,
                    nuGetProjectActions,
                    nuGetProjectContext,
                    token);
            }
            else
            {
                // Set the original packages config if it exists
                var msbuildProject = nuGetProject as MSBuildNuGetProject;
                if (msbuildProject != null)
                {
                    nuGetProjectContext.OriginalPackagesConfig =
                        msbuildProject.PackagesConfigNuGetProject?.GetPackagesConfig();
                }

                var executedNuGetProjectActions = new Stack<NuGetProjectAction>();
                var packageWithDirectoriesToBeDeleted = new HashSet<PackageIdentity>(PackageIdentity.Comparer);
                var ideExecutionContext = nuGetProjectContext.ExecutionContext as IDEExecutionContext;
                if (ideExecutionContext != null)
                {
                    await ideExecutionContext.SaveExpandedNodeStates(SolutionManager);
                }

                var logger = new ProjectContextLogger(nuGetProjectContext);
                Dictionary<PackageIdentity, PackagePreFetcherResult> downloadTasks = null;
                CancellationTokenSource downloadTokenSource = null;

                // batch events argument object
                PackageProjectEventArgs packageProjectEventArgs = null;

                try
                {
                    // PreProcess projects
                    await nuGetProject.PreProcessAsync(nuGetProjectContext, token);

                    var actionsList = nuGetProjectActions.ToList();

                    var hasInstalls = actionsList.Any(action =>
                        action.NuGetProjectActionType == NuGetProjectActionType.Install);

                    if (hasInstalls)
                    {
                        // Make this independently cancelable.
                        downloadTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);

                        // Download all packages up front in parallel
                        downloadTasks = await PackagePreFetcher.GetPackagesAsync(
                            actionsList,
                            PackagesFolderNuGetProject,
                            downloadContext,
                            SettingsUtility.GetGlobalPackagesFolder(Settings),
                            logger,
                            downloadTokenSource.Token);

                        // Log download information
                        PackagePreFetcher.LogFetchMessages(
                            downloadTasks.Values,
                            PackagesFolderNuGetProject.Root,
                            logger);
                    }

                    // raise Nuget batch start event
                    var batchId = Guid.NewGuid().ToString();
                    string name;
                    nuGetProject.TryGetMetadata(NuGetProjectMetadataKeys.Name, out name);
                    var projectPath = msbuildProject?.MSBuildProjectPath;
                    packageProjectEventArgs = new PackageProjectEventArgs(batchId, name, projectPath);
                    BatchStart?.Invoke(this, packageProjectEventArgs);
                    PackageProjectEventsProvider.Instance.NotifyBatchStart(packageProjectEventArgs);

                    try
                    {
                        if (msbuildProject != null)
                        {
                            //start batch processing for msbuild
                            await msbuildProject.ProjectSystem.BeginProcessingAsync();
                        }

                        foreach (var nuGetProjectAction in actionsList)
                        {
                            if (nuGetProjectAction.NuGetProjectActionType == NuGetProjectActionType.Uninstall)
                            {
                                executedNuGetProjectActions.Push(nuGetProjectAction);

                                await ExecuteUninstallAsync(nuGetProject,
                                    nuGetProjectAction.PackageIdentity,
                                    packageWithDirectoriesToBeDeleted,
                                    nuGetProjectContext, token);

                                nuGetProjectContext.Log(
                                    ProjectManagement.MessageLevel.Info,
                                    Strings.SuccessfullyUninstalled,
                                    nuGetProjectAction.PackageIdentity,
                                    nuGetProject.GetMetadata<string>(NuGetProjectMetadataKeys.Name));
                            }
                        }
                    }
                    finally
                    {
                        if (msbuildProject != null)
                        {
                            // end batch for msbuild and let it save everything.
                            // always calls it before PostProcessAsync or binding redirects
                            await msbuildProject.ProjectSystem.EndProcessingAsync();
                        }
                    }

                    try
                    {
                        if (msbuildProject != null)
                        {
                            //start batch processing for msbuild
                            await msbuildProject.ProjectSystem.BeginProcessingAsync();
                        }

                        foreach (var nuGetProjectAction in actionsList)
                        {
                            if (nuGetProjectAction.NuGetProjectActionType == NuGetProjectActionType.Install)
                            {
                                executedNuGetProjectActions.Push(nuGetProjectAction);

                                // Retrieve the downloaded package
                                // This will wait on the package if it is still downloading
                                var preFetchResult = downloadTasks[nuGetProjectAction.PackageIdentity];
                                using (var downloadPackageResult = await preFetchResult.GetResultAsync())
                                {
                                    // use the version exactly as specified in the nuspec file
                                    var packageIdentity = await downloadPackageResult.PackageReader.GetIdentityAsync(token);

                                    await ExecuteInstallAsync(
                                        nuGetProject,
                                        packageIdentity,
                                        downloadPackageResult,
                                        packageWithDirectoriesToBeDeleted,
                                        nuGetProjectContext,
                                        token);
                                }

                                var identityString = string.Format(CultureInfo.InvariantCulture, "{0} {1}",
                                    nuGetProjectAction.PackageIdentity.Id,
                                    nuGetProjectAction.PackageIdentity.Version.ToNormalizedString());

                                preFetchResult.EmitTelemetryEvent(nuGetProjectContext.OperationId);

                                nuGetProjectContext.Log(
                                    ProjectManagement.MessageLevel.Info,
                                    Strings.SuccessfullyInstalled,
                                    identityString,
                                    nuGetProject.GetMetadata<string>(NuGetProjectMetadataKeys.Name));
                            }
                        }
                    }
                    finally
                    {
                        if (msbuildProject != null)
                        {
                            // end batch for msbuild and let it save everything.
                            // always calls it before PostProcessAsync or binding redirects
                            await msbuildProject.ProjectSystem.EndProcessingAsync();
                        }
                    }

                    PackagesConfigLockFileUtility.UpdateLockFile(msbuildProject,
                        actionsList,
                        token);

                    // Post process
                    await nuGetProject.PostProcessAsync(nuGetProjectContext, token);

                    // Open readme file
                    await OpenReadmeFile(nuGetProject, nuGetProjectContext, token);
                }
                catch (SignatureException ex)
                {
                    var errors = ex.Results.SelectMany(r => r.GetErrorIssues());
                    var warnings = ex.Results.SelectMany(r => r.GetWarningIssues());
                    SignatureException unwrappedException = null;

                    if (errors.Count() == 1)
                    {
                        // In case of one error, throw it as the exception
                        var error = errors.First();
                        unwrappedException = new SignatureException(error.Code, error.Message, ex.PackageIdentity);
                    }
                    else
                    {
                        // In case of multiple errors, wrap them in a general NU3000 error
                        var errorMessage = string.Format(CultureInfo.CurrentCulture,
                            Strings.SignatureVerificationMultiple,
                            $"{Environment.NewLine}{string.Join(Environment.NewLine, errors.Select(e => e.FormatWithCode()))}");

                        unwrappedException = new SignatureException(NuGetLogCode.NU3000, errorMessage, ex.PackageIdentity);
                    }

                    foreach (var warning in warnings)
                    {
                        nuGetProjectContext.Log(warning);
                    }

                    exceptionInfo = ExceptionDispatchInfo.Capture(unwrappedException);
                }
                catch (Exception ex)
                {
                    exceptionInfo = ExceptionDispatchInfo.Capture(ex);
                }
                finally
                {
                    if (downloadTasks != null)
                    {
                        // Wait for all downloads to cancel and dispose
                        downloadTokenSource.Cancel();

                        foreach (var result in downloadTasks.Values)
                        {
                            await result.EnsureResultAsync();
                            result.Dispose();
                        }
                    }

                    downloadTokenSource?.Dispose();

                    if (msbuildProject != null)
                    {
                        // raise nuget batch end event
                        if (packageProjectEventArgs != null)
                        {
                            BatchEnd?.Invoke(this, packageProjectEventArgs);
                            PackageProjectEventsProvider.Instance.NotifyBatchEnd(packageProjectEventArgs);
                        }
                    }
                }

                if (exceptionInfo != null)
                {
                    await RollbackAsync(nuGetProject, executedNuGetProjectActions, packageWithDirectoriesToBeDeleted, nuGetProjectContext, token);
                }

                if (ideExecutionContext != null)
                {
                    await ideExecutionContext.CollapseAllNodes(SolutionManager);
                }

                // Delete the package directories as the last step, so that, if an uninstall had to be rolled back, we can just use the package file on the directory
                // Also, always perform deletion of package directories, even in a rollback, so that there are no stale package directories
                foreach (var packageWithDirectoryToBeDeleted in packageWithDirectoriesToBeDeleted)
                {
                    var packageFolderPath = PackagesFolderNuGetProject.GetInstalledPath(packageWithDirectoryToBeDeleted);
                    try
                    {
                        await DeletePackageAsync(packageWithDirectoryToBeDeleted, nuGetProjectContext, token);
                    }
                    finally
                    {
                        if (DeleteOnRestartManager != null)
                        {
                            if (Directory.Exists(packageFolderPath))
                            {
                                DeleteOnRestartManager.MarkPackageDirectoryForDeletion(
                                    packageWithDirectoryToBeDeleted,
                                    packageFolderPath,
                                    nuGetProjectContext);

                                // Raise the event to notify listners to update the UI etc.
                                DeleteOnRestartManager.CheckAndRaisePackageDirectoriesMarkedForDeletion();
                            }
                        }
                    }
                }

                // Save project
                await nuGetProject.SaveAsync(token);

                // Clear direct install
                SetDirectInstall(null, nuGetProjectContext);
            }


            // calculate total time taken to execute all nuget actions
            stopWatch.Stop();
            nuGetProjectContext.Log(
                MessageLevel.Info, Strings.NugetActionsTotalTime,
                DatetimeUtility.ToReadableTimeFormat(stopWatch.Elapsed));

            // emit resolve actions telemetry event
            var actionTelemetryEvent = new ActionTelemetryStepEvent(
                nuGetProjectContext.OperationId.ToString(),
                TelemetryConstants.ExecuteActionStepName, stopWatch.Elapsed.TotalSeconds);

            NuGetTelemetryService?.EmitTelemetryEvent(actionTelemetryEvent);

            if (exceptionInfo != null)
            {
                exceptionInfo.Throw();
            }

        }