public void ExecuteActions( IEnumerable<NewPackageAction> actions, IExecutionContext context, UserAction userAction = null) { // Capture actions we've already done so we can roll them back in case of an error var executedActions = new List<NewPackageAction>(); _userAction = userAction; ExceptionDispatchInfo capturedException = null; try { _readmeFilePath = null; foreach (var action in actions) { IActionHandler handler; if (!_actionHandlers.TryGetValue(action.ActionType, out handler)) { NuGetTraceSources.ActionExecutor.Error( "execute/unhandledaction", "[{0}] Skipping unknown action: {1}", action.PackageIdentity, action.ToString()); } else { NuGetTraceSources.ActionExecutor.Info( "execute/executing", "[{0}] Executing action: {1}", action.PackageIdentity, action.ToString()); handler.Execute(action, context, CancellationToken.None); executedActions.Add(action); } // Add binding redirects when neccessary. // Note that the current implementation is kind of inefficient. // AddBindingRedirects is run every time after an install or uninstall, // so it's called multiple times if multiple packages are installed/uninstalled. // But in fact, it's only needed to be called per project // once after all packages are installed uninstalled. var packageManager = action.Target.TryGetFeature<IPackageManager>(); var projectManager = action.Target.TryGetFeature<IProjectManager>(); if (packageManager != null && projectManager != null && packageManager.BindingRedirectEnabled && projectManager.Project.IsBindingRedirectSupported) { packageManager.AddBindingRedirects(projectManager); } UpdateReadmeFilePath(action); } if (_readmeFilePath != null) { context.OpenFile(_readmeFilePath); } } catch (Exception ex) { capturedException = ExceptionDispatchInfo.Capture(ex); } if (capturedException != null) { // Roll back the actions and rethrow Rollback(executedActions, context); capturedException.Throw(); } }
/// <summary> /// Resolve and execute actions for a single package for specified package action type. /// </summary> /// <param name="identity"></param> /// <param name="projects"></param> /// <param name="actionType"></param> protected void ExecuteSinglePackageAction(PackageIdentity identity, IEnumerable<VsProject> projects, PackageActionType actionType) { if (identity == null) { return; } try { // Resolve Actions List<VsProject> targetProjects = projects.ToList(); Task<IEnumerable<Client.Resolution.PackageAction>> resolverAction = PackageActionResolver.ResolveActionsAsync(identity, actionType, targetProjects, Solution); IEnumerable<Client.Resolution.PackageAction> actions = resolverAction.Result; if (WhatIf.IsPresent) { foreach (VsProject proj in targetProjects) { IEnumerable<PreviewResult> previewResults = PreviewResult.CreatePreview(actions, proj); if (previewResults.Count() == 0) { PowerShellPreviewResult prResult = new PowerShellPreviewResult(); prResult.Id = identity.Id; prResult.Action = Resources.Log_NoActionsWhatIf; prResult.ProjectName = proj.Name; WriteObject(prResult); } else { foreach (var p in previewResults) { LogPreviewResult(p, proj); } } } return; } // Execute Actions if (actions.Count() == 0 && actionType == PackageActionType.Install) { Log(MessageLevel.Info, NuGetResources.Log_PackageAlreadyInstalled, identity.Id); } else { var userAction = new UserAction(_actionType, identity); ActionExecutor executor = new ActionExecutor(); executor.ExecuteActions(actions, this, userAction); } } // TODO: Consider adding the rollback behavior if exception is thrown. catch (Exception ex) { if (ex.InnerException != null && !string.IsNullOrEmpty(ex.InnerException.Message)) { WriteError(ex.InnerException.Message); } else { WriteError(ex.Message); } } }