public async Task UpdateCapabilitiesAsync(ImmutableHashSet <string> capabilities, CancellationToken cancellationToken) { if (capabilities == null) { throw new ArgumentNullException(nameof(capabilities)); } await ProjectLockService.WriteLockAsync((releaser) => { _capabilities = capabilities; Refresh(); }, cancellationToken); }
public override async void UpdateProjectAsync(ProjectUpdateAction update) { using (var access = await ProjectLockService.WriteLockAsync()) { var configuredProject = await UnconfiguredProject.GetSuggestedConfiguredProjectAsync(); var project = await access.GetProjectAsync(configuredProject); // // Check out the project from SCC before aply any changes // await access.CheckoutAsync(configuredProject.UnconfiguredProject.FullPath); if (update(project)) { project.Save(); } } }
TResult ExecuteLockAction <TResult>(Func <Microsoft.Build.Evaluation.Project, TResult> callback, LockType lockType = LockType.Read, TResult defaultValue = default(TResult)) { var context = ContainingProject as IVsBrowseObjectContext; if (context == null) { context = ContainingProject.Object as IVsBrowseObjectContext; } if (context != null) { return(AsyncManager.Run(async() => { if (lockType == LockType.Read) { using (var access = await ProjectLockService.ReadLockAsync()) { var configuredProject = await context.UnconfiguredProject.GetSuggestedConfiguredProjectAsync(); var project = await access.GetProjectAsync(configuredProject); return callback(project); } } else { using (var access = await ProjectLockService.WriteLockAsync()) { var configuredProject = await context.UnconfiguredProject.GetSuggestedConfiguredProjectAsync(); var project = await access.GetProjectAsync(configuredProject); return callback(project); } } })); } return(defaultValue); }
/// <summary> /// Deletes items from the project, and optionally from disk. /// Note: Delete and Remove commands are handled via IVsHierarchyDeleteHandler3, not by /// IAsyncCommandGroupHandler and first asks us we CanRemove nodes. If yes then RemoveAsync is called. /// We can remove only nodes that are standard and based on project items, i.e. nodes that /// are created by default IProjectDependenciesSubTreeProvider implementations and have /// DependencyNode.GenericDependencyFlags flags and IRule with Context != null, in order to obtain /// node's itemSpec. ItemSpec then used to remove a project item having same Include. /// </summary> /// <param name="nodes">The nodes that should be deleted.</param> /// <param name="deleteOptions">A value indicating whether the items should be deleted from disk as well as /// from the project file. /// </param> /// <exception cref="InvalidOperationException">Thrown when <see cref="IProjectTreeProvider.CanRemove"/> /// would return <c>false</c> for this operation.</exception> public override async Task RemoveAsync(IImmutableSet <IProjectTree> nodes, DeleteOptions deleteOptions = DeleteOptions.None) { if (deleteOptions.HasFlag(DeleteOptions.DeleteFromStorage)) { throw new NotSupportedException(); } // Get the list of shared import nodes. IEnumerable <IProjectTree> sharedImportNodes = nodes.Where(node => node.Flags.Contains(ProjectTreeFlags.Common.SharedProjectImportReference)); // Get the list of normal reference Item Nodes (this excludes any shared import nodes). IEnumerable <IProjectTree> referenceItemNodes = nodes.Except(sharedImportNodes); using (var access = await ProjectLockService.WriteLockAsync()) { var project = await access.GetProjectAsync(ActiveConfiguredProject).ConfigureAwait(true); // Handle the removal of normal reference Item Nodes (this excludes any shared import nodes). foreach (var node in referenceItemNodes) { if (node.BrowseObjectProperties == null || node.BrowseObjectProperties.Context == null) { // if node does not have an IRule with valid ProjectPropertiesContext we can not // get it's itemsSpec. If nodes provided by custom IProjectDependenciesSubTreeProvider // implementation, and have some custom IRule without context, it is not a problem, // since they wouldnot have DependencyNode.GenericDependencyFlags and we would not // end up here, since CanRemove would return false and Remove command would not show // up for those nodes. continue; } var nodeItemContext = node.BrowseObjectProperties.Context; var unresolvedReferenceItem = project.GetItemsByEvaluatedInclude(nodeItemContext.ItemName) .FirstOrDefault(item => string.Equals(item.ItemType, nodeItemContext.ItemType, StringComparison.OrdinalIgnoreCase)); Report.IfNot(unresolvedReferenceItem != null, "Cannot find reference to remove."); if (unresolvedReferenceItem != null) { await access.CheckoutAsync(unresolvedReferenceItem.Xml.ContainingProject.FullPath) .ConfigureAwait(true); project.RemoveItem(unresolvedReferenceItem); } } // Handle the removal of shared import nodes. var projectXml = await access.GetProjectXmlAsync(UnconfiguredProject.FullPath) .ConfigureAwait(true); foreach (var sharedImportNode in sharedImportNodes) { // Find the import that is included in the evaluation of the specified ConfiguredProject that // imports the project file whose full path matches the specified one. var matchingImports = from import in project.Imports where import.ImportingElement.ContainingProject == projectXml where PathHelper.IsSamePath(import.ImportedProject.FullPath, sharedImportNode.FilePath) select import; foreach (var importToRemove in matchingImports) { var importingElementToRemove = importToRemove.ImportingElement; Report.IfNot(importingElementToRemove != null, "Cannot find shared project reference to remove."); if (importingElementToRemove != null) { await access.CheckoutAsync(importingElementToRemove.ContainingProject.FullPath) .ConfigureAwait(true); importingElementToRemove.Parent.RemoveChild(importingElementToRemove); } } } } }
/// <summary> /// Deletes items from the project, and optionally from disk. /// Note: Delete and Remove commands are handled via IVsHierarchyDeleteHandler3, not by /// IAsyncCommandGroupHandler and first asks us we CanRemove nodes. If yes then RemoveAsync is called. /// We can remove only nodes that are standard and based on project items, i.e. nodes that /// are created by default IProjectDependenciesSubTreeProvider implementations and have /// DependencyNode.GenericDependencyFlags flags and IRule with Context != null, in order to obtain /// node's itemSpec. ItemSpec then used to remove a project item having same Include. /// </summary> /// <param name="nodes">The nodes that should be deleted.</param> /// <param name="deleteOptions">A value indicating whether the items should be deleted from disk as well as /// from the project file. /// </param> /// <exception cref="InvalidOperationException">Thrown when <see cref="IProjectTreeProvider.CanRemove"/> /// would return <c>false</c> for this operation.</exception> public override async Task RemoveAsync(IImmutableSet <IProjectTree> nodes, DeleteOptions deleteOptions = DeleteOptions.None) { if (deleteOptions.HasFlag(DeleteOptions.DeleteFromStorage)) { throw new NotSupportedException(); } // Get the list of shared import nodes. IEnumerable <IProjectTree> sharedImportNodes = nodes.Where(node => node.Flags.Contains(DependencyTreeFlags.SharedProjectFlags)); // Get the list of normal reference Item Nodes (this excludes any shared import nodes). IEnumerable <IProjectTree> referenceItemNodes = nodes.Except(sharedImportNodes); await ProjectLockService.WriteLockAsync(async access => { Project project = await access.GetProjectAsync(ActiveConfiguredProject); // Handle the removal of normal reference Item Nodes (this excludes any shared import nodes). foreach (IProjectTree node in referenceItemNodes) { if (node.BrowseObjectProperties?.Context == null) { // if node does not have an IRule with valid ProjectPropertiesContext we can not // get its itemsSpec. If nodes provided by custom IProjectDependenciesSubTreeProvider // implementation, and have some custom IRule without context, it is not a problem, // since they would not have DependencyNode.GenericDependencyFlags and we would not // end up here, since CanRemove would return false and Remove command would not show // up for those nodes. continue; } IProjectPropertiesContext nodeItemContext = node.BrowseObjectProperties.Context; ProjectItem unresolvedReferenceItem = project.GetItemsByEvaluatedInclude(nodeItemContext.ItemName) .FirstOrDefault(item => string.Equals(item.ItemType, nodeItemContext.ItemType, StringComparisons.ItemTypes)); Report.IfNot(unresolvedReferenceItem != null, "Cannot find reference to remove."); if (unresolvedReferenceItem != null) { await access.CheckoutAsync(unresolvedReferenceItem.Xml.ContainingProject.FullPath); project.RemoveItem(unresolvedReferenceItem); } } IDependenciesSnapshot snapshot = _dependenciesSnapshotProvider.CurrentSnapshot; Requires.NotNull(snapshot, nameof(snapshot)); if (snapshot == null) { return; } // Handle the removal of shared import nodes. ProjectRootElement projectXml = await access.GetProjectXmlAsync(UnconfiguredProject.FullPath); foreach (IProjectTree sharedImportNode in sharedImportNodes) { string sharedFilePath = UnconfiguredProject.GetRelativePath(sharedImportNode.FilePath); if (string.IsNullOrEmpty(sharedFilePath)) { continue; } IDependency sharedProjectDependency = snapshot.FindDependency(sharedFilePath, topLevel: true); if (sharedProjectDependency != null) { sharedFilePath = sharedProjectDependency.Path; } // Find the import that is included in the evaluation of the specified ConfiguredProject that // imports the project file whose full path matches the specified one. IEnumerable <ResolvedImport> matchingImports = from import in project.Imports where import.ImportingElement.ContainingProject == projectXml && PathHelper.IsSamePath(import.ImportedProject.FullPath, sharedFilePath) select import; foreach (ResolvedImport importToRemove in matchingImports) { ProjectImportElement importingElementToRemove = importToRemove.ImportingElement; Report.IfNot(importingElementToRemove != null, "Cannot find shared project reference to remove."); if (importingElementToRemove != null) { await access.CheckoutAsync(importingElementToRemove.ContainingProject.FullPath); importingElementToRemove.Parent.RemoveChild(importingElementToRemove); } } } }); }