public async Task ExecuteBuildIntegratedProjectActionsAsync()

in src/NuGet.Core/NuGet.PackageManagement/NuGetPackageManager.cs [3261:3504]


        public async Task ExecuteBuildIntegratedProjectActionsAsync(
            BuildIntegratedNuGetProject buildIntegratedProject,
            IEnumerable<NuGetProjectAction> nuGetProjectActions,
            INuGetProjectContext nuGetProjectContext,
            CancellationToken token)
        {
            if (buildIntegratedProject == null)
            {
                throw new ArgumentNullException(nameof(buildIntegratedProject));
            }

            BuildIntegratedProjectAction projectAction = null;

            if (nuGetProjectActions.Count() == 1
                && nuGetProjectActions.All(action => action is BuildIntegratedProjectAction))
            {
                projectAction = nuGetProjectActions.Single() as BuildIntegratedProjectAction;
            }
            else if (nuGetProjectActions.Any())
            {
                projectAction = await PreviewBuildIntegratedProjectActionsAsync(
                    buildIntegratedProject,
                    nuGetProjectActions,
                    nuGetProjectContext,
                    token);
            }
            else
            {
                // There are no actions, this is a no-op
                return;
            }

            var actions = projectAction.GetProjectActions();

            // Check if all actions are uninstalls
            var uninstallOnly = projectAction.NuGetProjectActionType == NuGetProjectActionType.Uninstall
                && actions.All(action => action.NuGetProjectActionType == NuGetProjectActionType.Uninstall);

            var restoreResult = projectAction.RestoreResult;

            // Avoid committing the changes if the restore did not succeed
            // For uninstalls continue even if the restore failed to avoid blocking the user
            if (restoreResult.Success || uninstallOnly)
            {
                // Get all install actions
                var ignoreActions = new HashSet<NuGetProjectAction>();
                var installedIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

                foreach ((var action, _) in projectAction.ActionAndContextList.Reverse())
                {
                    if (action.NuGetProjectActionType == NuGetProjectActionType.Install)
                    {
                        installedIds.Add(action.PackageIdentity.Id);
                    }
                    else if (installedIds.Contains(action.PackageIdentity.Id))
                    {
                        ignoreActions.Add(action);
                    }
                }

                var pathResolver = new FallbackPackagePathResolver(
                    projectAction.RestoreResult.LockFile.PackageSpec.RestoreMetadata.PackagesPath,
                    projectAction.RestoreResult.LockFile.PackageSpec.RestoreMetadata.FallbackFolders);

                foreach ((var originalAction, var installationContext) in projectAction.ActionAndContextList.Where(e => !ignoreActions.Contains(e.Item1)))
                {
                    // This is where we calculate what goes into CPSPackageReferenceProject
                    if (originalAction.NuGetProjectActionType == NuGetProjectActionType.Install)
                    {
                        if (buildIntegratedProject.ProjectStyle == ProjectStyle.PackageReference)
                        {
                            BuildIntegratedRestoreUtility.UpdatePackageReferenceMetadata(
                                projectAction.RestoreResult.LockFile,
                                pathResolver,
                                originalAction.PackageIdentity);

                            var framework = installationContext.SuccessfulFrameworks.First();
                            var resolvedAction = projectAction.RestoreResult.LockFile.PackageSpec.TargetFrameworks.FirstOrDefault(fm => fm.FrameworkName.Equals(framework))
                                .Dependencies.First(dependency => dependency.Name.Equals(originalAction.PackageIdentity.Id, StringComparison.OrdinalIgnoreCase));

                            installationContext.SuppressParent = resolvedAction.SuppressParent;
                            installationContext.IncludeType = resolvedAction.IncludeType;
                        }

                        // Install the package to the project
                        await buildIntegratedProject.InstallPackageAsync(
                            originalAction.PackageIdentity.Id,
                            originalAction.VersionRange ?? new VersionRange(originalAction.PackageIdentity.Version),
                            nuGetProjectContext,
                            installationContext,
                            token: token);
                    }
                    else if (originalAction.NuGetProjectActionType == NuGetProjectActionType.Uninstall)
                    {
                        await buildIntegratedProject.UninstallPackageAsync(
                            originalAction.PackageIdentity.Id,
                            installationContext,
                            token: token);
                    }
                }

                var logger = new ProjectContextLogger(nuGetProjectContext);
                var referenceContext = new DependencyGraphCacheContext(logger, Settings);

                var now = DateTime.UtcNow;
                void cacheContextModifier(SourceCacheContext c) => c.MaxAge = now;

                // Write out the lock file, now no need bubbling re-evaluating of parent projects when you restore from PM UI.
                // We already taken account of that concern in PreviewBuildIntegratedProjectsActionsAsync method.

                bool isNoOp = projectAction.RestoreResultPair.Result is NoOpRestoreResult;
                IReadOnlyList<string> filesToBeUpdated = isNoOp ? null : GetFilesToBeUpdated(projectAction.RestoreResultPair);
                if (!isNoOp)
                {
                    RestoreProgressReporter?.StartProjectUpdate(projectAction.RestoreResultPair.SummaryRequest.Request.Project.FilePath, filesToBeUpdated);
                }
                try
                {
                    await RestoreRunner.CommitAsync(projectAction.RestoreResultPair, token);
                }
                finally
                {
                    if (!isNoOp)
                    {
                        RestoreProgressReporter?.EndProjectUpdate(projectAction.RestoreResultPair.SummaryRequest.Request.Project.FilePath, filesToBeUpdated);
                    }
                }

                // add packages lock file into project
                if (PackagesLockFileUtilities.IsNuGetLockFileEnabled(projectAction.RestoreResult.LockFile.PackageSpec))
                {
                    var lockFilePath = PackagesLockFileUtilities.GetNuGetLockFilePath(projectAction.RestoreResult.LockFile.PackageSpec);

                    await buildIntegratedProject.AddFileToProjectAsync(lockFilePath);
                }

                // Write out a message for each action
                foreach (var action in actions)
                {
                    var identityString = string.Format(CultureInfo.InvariantCulture, "{0} {1}",
                        action.PackageIdentity.Id,
                        action.PackageIdentity.Version.ToNormalizedString());

                    if (action.NuGetProjectActionType == NuGetProjectActionType.Install)
                    {
                        nuGetProjectContext.Log(
                            MessageLevel.Info,
                            Strings.SuccessfullyInstalled,
                            identityString,
                            buildIntegratedProject.GetMetadata<string>(NuGetProjectMetadataKeys.Name));
                    }
                    else
                    {
                        // uninstall
                        nuGetProjectContext.Log(
                            MessageLevel.Info,
                            Strings.SuccessfullyUninstalled,
                            identityString,
                            buildIntegratedProject.GetMetadata<string>(NuGetProjectMetadataKeys.Name));
                    }
                }

                // Run init.ps1 scripts
                var addedPackages = BuildIntegratedRestoreUtility.GetAddedPackages(
                    projectAction.OriginalLockFile,
                    restoreResult.LockFile);
                await BuildIntegratedRestoreUtility.ExecuteInitPs1ScriptsAsync(
                    buildIntegratedProject,
                    addedPackages,
                    pathResolver,
                    nuGetProjectContext,
                    token);

                // find list of buildintegrated projects
                var projects = (await SolutionManager.GetNuGetProjectsAsync()).OfType<BuildIntegratedNuGetProject>().ToList();

                // build reference cache if not done already
                if (_buildIntegratedProjectsCache == null)
                {
                    _buildIntegratedProjectsCache = await
                        DependencyGraphRestoreUtility.GetSolutionRestoreSpec(SolutionManager, referenceContext);
                }

                // Restore parent projects. These will be updated to include the transitive changes.
                var parents = BuildIntegratedRestoreUtility.GetParentProjectsInClosure(
                    projects,
                    buildIntegratedProject,
                    _buildIntegratedProjectsCache);
                // The settings contained in the context are applied to the dg spec.
                var dgSpecForParents = await DependencyGraphRestoreUtility.GetSolutionRestoreSpec(SolutionManager, referenceContext);
                dgSpecForParents = dgSpecForParents.WithoutRestores();

                foreach (var parent in parents)
                {
                    // We only evaluate unseen parents.
                    if (_buildIntegratedProjectsUpdateSet == null ||
                        !_buildIntegratedProjectsUpdateSet.Contains(parent.MSBuildProjectPath))
                    {
                        // Mark project for restore
                        dgSpecForParents.AddRestore(parent.MSBuildProjectPath);
                        _buildIntegratedProjectsUpdateSet?.Add(parent.MSBuildProjectPath);
                    }
                }

                if (dgSpecForParents.Restore.Count > 0)
                {
                    // Restore and commit the lock file to disk regardless of the result
                    // This will restore all parents in a single restore
                    await DependencyGraphRestoreUtility.RestoreAsync(
                        dgSpecForParents,
                        referenceContext,
                        GetRestoreProviderCache(),
                        cacheContextModifier,
                        projectAction.Sources,
                        nuGetProjectContext.OperationId,
                        forceRestore: false, // No need to force restore as the inputs would've changed here anyways
                        isRestoreOriginalAction: false, // not an explicit restore request instead being done as part of install or update
                        additionalMessages: null,
                        progressReporter: RestoreProgressReporter,
                        log: logger,
                        token: token);
                }
            }
            else
            {
                // Fail and display a rollback message to let the user know they have returned to the original state
                var message = string.Format(
                        CultureInfo.InvariantCulture,
                        Strings.RestoreFailedRollingBack,
                        buildIntegratedProject.ProjectName);

                // Read additional errors from the lock file if one exists
                var logMessages = restoreResult.LockFile?
                    .LogMessages
                    .Where(e => e.Level == LogLevel.Error || e.Level == LogLevel.Warning)
                    .Select(e => e.AsRestoreLogMessage())
                  ?? Enumerable.Empty<ILogMessage>();

                // Throw an exception containing all errors, these will be displayed in the error list
                throw new PackageReferenceRollbackException(message, logMessages);
            }

            await OpenReadmeFile(buildIntegratedProject, nuGetProjectContext, token);
        }