private static async ATask SetVCProjectsConfigurationProperties12(DTEProject project, string configurationName, string platformName) { // Inspired from Nuget: https://github.com/Haacked/NuGet/blob/master/src/VisualStudio12/ProjectHelper.cs IVsBrowseObjectContext context = project.Object as IVsBrowseObjectContext; UnconfiguredProject unconfiguredProject = context.UnconfiguredProject; IProjectLockService service = unconfiguredProject.ProjectService.Services.ProjectLockService; using (ProjectWriteLockReleaser releaser = await service.WriteLockAsync()) { ProjectCollection collection = releaser.ProjectCollection; ConfigureCollection(collection, configurationName, platformName); _VCProjectCollectionLoaded = true; // The following was present in the NuGet code: it seesms unecessary, // as the lock it's release anyway after the using block (check // service.IsAnyLockHeld). Also it seemed to cause a deadlock sometimes // when switching solution configuration //await releaser.ReleaseAsync(); } }
private Task RemoveFiles(HashSet <string> filesToRemove, ProjectWriteLockReleaser access) { return(RemoveItems(_filesItemGroup, _fileItems, filesToRemove, access)); }
private async Task ReevaluateLoadedConfiguredProjects(CancellationToken cancellationToken, ProjectWriteLockReleaser access) { foreach (var configuredProject in _unconfiguredProject.LoadedConfiguredProjects) { try { var jsproj = await access.GetProjectAsync(configuredProject, cancellationToken); jsproj.ReevaluateIfNecessary(); } catch (Exception ex) { System.Diagnostics.Debug.Fail("We were unable to mark a configuration as dirty" + ex.Message, ex.StackTrace); } } }
public Task UpdateFullPathAsync(ProjectWriteLockReleaser access, CancellationToken cancellationToken = default(CancellationToken)) { _inMemoryImportFullPath = _unconfiguredProject.GetInMemoryTargetsFileFullPath(); _inMemoryImport.FullPath = _inMemoryImportFullPath; return ReevaluateLoadedConfiguredProjects(cancellationToken, access); }
async Task <bool> BuildProjectAsync(ProjectWriteLockReleaser writeAccess) { var msBuildProject = await writeAccess.GetProjectAsync(ConfiguredProject); var solutionPath = QtProjectTracker.SolutionPath; var configProps = new Dictionary <string, string>( ConfiguredProject.ProjectConfiguration.Dimensions.ToImmutableDictionary()) { { "SolutionPath", solutionPath }, { "SolutionFileName", Path.GetFileName(solutionPath) }, { "SolutionName", Path.GetFileNameWithoutExtension(solutionPath) }, { "SolutionExt", Path.GetExtension(solutionPath) }, { "SolutionDir", Path.GetDirectoryName(solutionPath).TrimEnd('\\') + '\\' } }; foreach (var property in Properties) { configProps[property.Key] = property.Value; } var projectInstance = new ProjectInstance(msBuildProject.Xml, configProps, null, new ProjectCollection()); var loggerVerbosity = LoggerVerbosity; if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) { loggerVerbosity = QtVsToolsPackage.Instance.Options.BuildLoggerVerbosity; } var buildParams = new BuildParameters() { Loggers = (loggerVerbosity != LoggerVerbosity.Quiet) ? new[] { new QtProjectLogger() { Verbosity = loggerVerbosity } } : null }; var buildRequest = new BuildRequestData(projectInstance, Targets.ToArray(), hostServices: null, flags: BuildRequestDataFlags.ProvideProjectStateAfterBuild); if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) { Messages.Print(string.Format( "{0:HH:mm:ss.FFF} QtProjectBuild({1}): Build [{2}] {3}", DateTime.Now, Thread.CurrentThread.ManagedThreadId, ConfiguredProject.ProjectConfiguration.Name, UnconfiguredProject.FullPath)); Messages.Print("=== Targets"); foreach (var target in buildRequest.TargetNames) { Messages.Print(string.Format(" {0}", target)); } Messages.Print("=== Properties"); foreach (var property in Properties) { Messages.Print(string.Format(" {0}={1}", property.Key, property.Value)); } } BuildResult result = null; while (result == null) { try { result = BuildManager.DefaultBuildManager.Build( buildParams, buildRequest); } catch (InvalidOperationException) { if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) { Messages.Print(string.Format( "{0:HH:mm:ss.FFF} QtProjectBuild({1}): [{2}] " + "Warning: Another build is in progress; waiting...", DateTime.Now, Thread.CurrentThread.ManagedThreadId, ConfiguredProject.ProjectConfiguration.Name)); } await Task.Delay(3000); } } if (QtVsToolsPackage.Instance.Options.BuildDebugInformation) { string resMsg; StringBuilder resInfo = new StringBuilder(); if (result?.OverallResult == BuildResultCode.Success) { resMsg = "Build ok"; } else { resMsg = "Build FAIL"; if (result == null) { resInfo.AppendLine("####### Build returned 'null'"); } else { resInfo.AppendLine("####### Build returned 'Failure' code"); if (result.ResultsByTarget != null) { foreach (var tr in result.ResultsByTarget) { var res = tr.Value; if (res.ResultCode != TargetResultCode.Failure) { continue; } resInfo.AppendFormat("### Target '{0}' FAIL\r\n", tr.Key); if (res.Items != null && res.Items.Length > 0) { resInfo.AppendFormat( "Items: {0}\r\n", string.Join(", ", res.Items .Select(it => it.ItemSpec))); } var e = tr.Value?.Exception; if (e != null) { resInfo.AppendFormat( "Exception: {0}\r\nStacktrace:\r\n{1}\r\n", e.Message, e.StackTrace); } } } } } Messages.Print(string.Format( "{0:HH:mm:ss.FFF} QtProjectBuild({1}): [{2}] {3}\r\n{4}", DateTime.Now, Thread.CurrentThread.ManagedThreadId, ConfiguredProject.ProjectConfiguration.Name, resMsg, resInfo.ToString())); } bool ok = false; if (result == null || result.ResultsByTarget == null || result.OverallResult != BuildResultCode.Success) { Messages.Print(string.Format("{0}: background build FAILED!", Path.GetFileName(UnconfiguredProject.FullPath))); } else { var checkResults = result.ResultsByTarget .Where(x => Targets.Contains(x.Key)) .Select(x => x.Value); ok = checkResults.Any() && checkResults.All(x => x.ResultCode == TargetResultCode.Success); if (ok) { msBuildProject.MarkDirty(); } } await writeAccess.ReleaseAsync(); return(ok); }
private async Task RenameItems(Dictionary <string, ProjectItemElement> items, IReadOnlyDictionary <string, string> itemsToRename, ProjectWriteLockReleaser access) { await access.CheckoutAsync(itemsToRename.Keys); foreach (var kvp in itemsToRename) { ProjectItemElement item; if (items.TryGetValue(kvp.Key, out item)) { items.Remove(kvp.Key); item.Include = kvp.Value; items[kvp.Value] = item; } } }
private async Task RenameDirectories(IReadOnlyDictionary <string, string> directoriesToRename, ProjectWriteLockReleaser access) { foreach (var kvp in directoriesToRename) { await RenameItems(_fileItems, kvp.Key, kvp.Value, access); await RenameItems(_directoryItems, kvp.Key, kvp.Value, access); } }
private async Task RemoveItems(ProjectItemGroupElement parent, Dictionary <string, ProjectItemElement> items, IReadOnlyCollection <string> itemsToRemove, ProjectWriteLockReleaser access) { await access.CheckoutAsync(itemsToRemove); foreach (var path in itemsToRemove) { RemoveItem(parent, items, path); } }
private async Task RemoveItems(ProjectItemGroupElement parent, Dictionary<string, ProjectItemElement> items, IReadOnlyCollection<string> itemsToRemove, ProjectWriteLockReleaser access) { await access.CheckoutAsync(itemsToRemove); foreach (var path in itemsToRemove) { RemoveItem(parent, items, path); } }
private Task RemoveItems(ProjectItemGroupElement parent, Dictionary<string, ProjectItemElement> items, string directoryName, ProjectWriteLockReleaser access) { return RemoveItems(parent, items, items.Keys.Where(f => f.StartsWithIgnoreCase(directoryName)).ToList(), access); }
private async Task RemoveDirectories(IReadOnlyCollection<string> directoriesToRemove, ProjectWriteLockReleaser access) { foreach (var directoryName in directoriesToRemove) { await RemoveItems(_filesItemGroup, _fileItems, directoryName, access); await RemoveItems(_directoriesItemGroup, _directoryItems, directoryName, access); } }
private Task RemoveFiles(HashSet<string> filesToRemove, ProjectWriteLockReleaser access) { return RemoveItems(_filesItemGroup, _fileItems, filesToRemove, access); }
private async Task RemoveDirectories(IReadOnlyCollection <string> directoriesToRemove, ProjectWriteLockReleaser access) { foreach (var directoryName in directoriesToRemove) { await RemoveItems(_filesItemGroup, _fileItems, directoryName, access); await RemoveItems(_directoriesItemGroup, _directoryItems, directoryName, access); } }
private Task RenameFiles(IReadOnlyDictionary<string, string> filesToRename, ProjectWriteLockReleaser access) { return RenameItems(_fileItems, filesToRename, access); }
private Task RemoveItems(ProjectItemGroupElement parent, Dictionary <string, ProjectItemElement> items, string directoryName, ProjectWriteLockReleaser access) { return(RemoveItems(parent, items, items.Keys.Where(f => f.StartsWithIgnoreCase(directoryName)).ToList(), access)); }
private async Task RenameDirectories(IReadOnlyDictionary<string, string> directoriesToRename, ProjectWriteLockReleaser access) { foreach (var kvp in directoriesToRename) { await RenameItems(_fileItems, kvp.Key, kvp.Value, access); await RenameItems(_directoryItems, kvp.Key, kvp.Value, access); } }
private Task RenameFiles(IReadOnlyDictionary <string, string> filesToRename, ProjectWriteLockReleaser access) { return(RenameItems(_fileItems, filesToRename, access)); }
private Task RenameItems(Dictionary<string, ProjectItemElement> items, string oldDirectoryName, string newDirectoryName, ProjectWriteLockReleaser access) { var itemsToRename = items.Keys .Where(f => f.StartsWithIgnoreCase(oldDirectoryName)) .ToDictionary(f => f, f => newDirectoryName + f.Substring(oldDirectoryName.Length)); return RenameItems(items, itemsToRename, access); }
private Task RenameItems(Dictionary <string, ProjectItemElement> items, string oldDirectoryName, string newDirectoryName, ProjectWriteLockReleaser access) { var itemsToRename = items.Keys .Where(f => f.StartsWithIgnoreCase(oldDirectoryName)) .ToDictionary(f => f, f => newDirectoryName + f.Substring(oldDirectoryName.Length)); return(RenameItems(items, itemsToRename, access)); }
private async Task RenameItems(Dictionary<string, ProjectItemElement> items, IReadOnlyDictionary<string, string> itemsToRename, ProjectWriteLockReleaser access) { await access.CheckoutAsync(itemsToRename.Keys); foreach (var kvp in itemsToRename) { ProjectItemElement item; if (items.TryGetValue(kvp.Key, out item)) { items.Remove(kvp.Key); item.Include = kvp.Value; items[kvp.Value] = item; } } }
/// <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); using (ProjectWriteLockReleaser access = await ProjectLockService.WriteLockAsync()) { Project project = await access.GetProjectAsync(ActiveConfiguredProject).ConfigureAwait(true); // Handle the removal of normal reference Item Nodes (this excludes any shared import nodes). foreach (IProjectTree 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; } IProjectPropertiesContext nodeItemContext = node.BrowseObjectProperties.Context; ProjectItem 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); } } 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) .ConfigureAwait(true); 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 where 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) .ConfigureAwait(true); importingElementToRemove.Parent.RemoveChild(importingElementToRemove); } } } } }
public Task UpdateFullPathAsync(ProjectWriteLockReleaser access, CancellationToken cancellationToken = default(CancellationToken)) { _inMemoryImportFullPath = _unconfiguredProject.GetInMemoryTargetsFileFullPath(); _inMemoryImport.FullPath = _inMemoryImportFullPath; return(ReevaluateLoadedConfiguredProjects(cancellationToken, access)); }