void Initialize(IProgressMonitor progressMonitor, List <FileName> filesToParse) { IReadOnlyCollection <ProjectItem> projectItems = project.Items.CreateSnapshot(); lock (lockObj) { if (disposed) { return; } } double scalingFactor = 1.0 / (projectItems.Count + LoadingReferencesWorkAmount); using (IProgressMonitor initReferencesProgressMonitor = progressMonitor.CreateSubTask(LoadingReferencesWorkAmount * scalingFactor), parseProgressMonitor = progressMonitor.CreateSubTask(projectItems.Count * scalingFactor)) { var resolveReferencesTask = Task.Run( delegate { DoResolveReferences(initReferencesProgressMonitor); }, initReferencesProgressMonitor.CancellationToken); ParseFiles(filesToParse, parseProgressMonitor); resolveReferencesTask.Wait(); } }
public TaskToObserverSubscription(Func <IProgressMonitor, Action <T>, Task> func, IProgressMonitor progressMonitor, IObserver <T> observer) { this.observer = observer; this.progressMonitor = progressMonitor; this.childProgressMonitor = progressMonitor.CreateSubTask(1, cts.Token); func(childProgressMonitor, Callback).ContinueWith(TaskCompleted).FireAndForget(); }
void RunThread() { while (true) { JobTask task; // copy fields from this class into local variables to ensure thread-safety // with concurrent Clear() calls double totalWork, workDone; IProgressMonitor progressMonitor; lock (lockObj) { // enqueued null: quit thread and restart (used for cancellation) if (actions.Count == 0 || this.actions.Peek() == null) { this.threadIsRunning = false; this.progressMonitor.Dispose(); this.progressMonitor = null; // restart if necessary: if (actions.Count > 0) { actions.Dequeue(); // dequeue the null if (actions.Count > 0) { SD.MainThread.InvokeAsyncAndForget(StartRunningIfRequired); } else { loadSolutionProjects.RaiseThreadEnded(); } } else { loadSolutionProjects.RaiseThreadEnded(); } return; } task = this.actions.Dequeue(); totalWork = this.totalWork; workDone = this.workDone; progressMonitor = this.progressMonitor; } progressMonitor.Progress = workDone / totalWork; progressMonitor.TaskName = task.name; try { using (IProgressMonitor subTask = progressMonitor.CreateSubTask(task.cost / totalWork)) { subTask.CancellationToken.ThrowIfCancellationRequested(); task.Run(subTask); } lock (lockObj) { this.workDone += task.cost; } } catch (OperationCanceledException) { // ignore cancellation } catch (Exception ex) { MessageService.ShowException(ex, "Error on LoadSolutionProjects thread"); } } }
void StartBuildProjects() { lock (this) { while (workersToStart > 0) { if (buildIsCancelled || projectsReadyForBuildStart.Count == 0) { if (runningWorkers == 0) { BuildDone(); } return; } workersToStart--; int projectToStartIndex = 0; for (int i = 1; i < projectsReadyForBuildStart.Count; i++) { if (CompareBuildOrder(projectsReadyForBuildStart[i], projectsReadyForBuildStart[projectToStartIndex]) < 0) { projectToStartIndex = i; } } BuildNode node = projectsReadyForBuildStart[projectToStartIndex]; projectsReadyForBuildStart.RemoveAt(projectToStartIndex); node.perNodeProgressMonitor = progressMonitor.CreateSubTask(1.0 / nodeDict.Count); node.buildStarted = true; bool hasDependencyErrors = false; foreach (BuildNode n in node.dependencies) { if (!n.buildFinished) { throw new Exception("Trying to build project with unfinished dependencies"); } hasDependencyErrors |= n.hasErrors; } ICSharpCode.Core.LoggingService.Info("Start building " + node.project.Name); runningWorkers++; projectsCurrentlyBuilding.Add(node); if (hasDependencyErrors) { ICSharpCode.Core.LoggingService.Debug("Skipped building " + node.project.Name + " (errors in dependencies)"); node.hasErrors = true; node.Done(false); } else { // do not run "DoStartBuild" inside lock - run it async on the thread pool System.Threading.ThreadPool.QueueUserWorkItem(node.DoStartBuild); } } } }
public static async Task RenameSymbolAsync(ISymbol symbol, string newName, IProgressMonitor progressMonitor, Action <Error> errorCallback) { if (symbol == null) { throw new ArgumentNullException("symbol"); } if (progressMonitor == null) { throw new ArgumentNullException("progressMonitor"); } SD.MainThread.VerifyAccess(); if (SD.ParserService.LoadSolutionProjectsThread.IsRunning) { progressMonitor.ShowingDialog = true; MessageService.ShowMessage("${res:SharpDevelop.Refactoring.LoadSolutionProjectsThreadRunning}"); progressMonitor.ShowingDialog = false; return; } double totalWorkAmount; List <ISymbolSearch> symbolSearches = PrepareSymbolSearch(symbol, progressMonitor.CancellationToken, out totalWorkAmount); double workDone = 0; ParseableFileContentFinder parseableFileContentFinder = new ParseableFileContentFinder(); var errors = new List <Error>(); var changes = new List <PatchedFile>(); foreach (ISymbolSearch s in symbolSearches) { progressMonitor.CancellationToken.ThrowIfCancellationRequested(); using (var childProgressMonitor = progressMonitor.CreateSubTask(s.WorkAmount / totalWorkAmount)) { var args = new SymbolRenameArgs(newName, childProgressMonitor, parseableFileContentFinder); args.ProvideHighlightedLine = false; await s.RenameAsync(args, file => changes.Add(file), error => errors.Add(error)); } workDone += s.WorkAmount; progressMonitor.Progress = workDone / totalWorkAmount; } if (errors.Count == 0) { foreach (var file in changes) { ApplyChanges(file); } } else { foreach (var error in errors) { errorCallback(error); } } }
public async Task RunTestsAsync(IEnumerable <ITest> selectedTests, TestExecutionOptions options, CancellationToken cancellationToken) { this.cancellationToken = cancellationToken; GroupTestsByProject(selectedTests); ClearTasks(); ShowUnitTestsPad(); ShowOutputPad(); ResetTestResults(); saveAllFilesCommand.SaveAllFiles(); // Run the build, if necessary: var projectsToBuild = testsByProject.Keys.Where(p => p.IsBuildNeededBeforeTestRun).Select(p => p.Project).ToList(); if (projectsToBuild.Count > 0) { using (cancellationToken.Register(buildService.CancelBuild)) { var buildOptions = new BuildOptions(BuildTarget.Build); buildOptions.BuildDetection = BuildOptions.BuildOnExecute; var buildResults = await buildService.BuildAsync(projectsToBuild, buildOptions); if (buildResults.Result != BuildResultCode.Success) { return; } } } cancellationToken.ThrowIfCancellationRequested(); using (IProgressMonitor progressMonitor = statusBarService.CreateProgressMonitor(cancellationToken)) { int projectsLeftToRun = testsByProject.Count; foreach (IGrouping <ITestProject, ITest> g in testsByProject.OrderBy(g => g.Key.DisplayName)) { currentProjectBeingTested = g.Key; progressMonitor.TaskName = GetProgressMonitorLabel(currentProjectBeingTested); progressMonitor.Progress = GetProgress(projectsLeftToRun); using (testProgressMonitor = progressMonitor.CreateSubTask(1.0 / testsByProject.Count)) { using (ITestRunner testRunner = currentProjectBeingTested.CreateTestRunner(options)) { testRunner.TestFinished += testRunner_TestFinished; var writer = new MessageViewCategoryTextWriter(testService.UnitTestMessageView); await testRunner.RunAsync(g, testProgressMonitor, writer, testProgressMonitor.CancellationToken); } } projectsLeftToRun--; progressMonitor.CancellationToken.ThrowIfCancellationRequested(); } } ShowErrorList(); }
/// <summary> /// Finds all references to the specified entity. /// The results are reported using the callback. /// FindReferences may internally use parallelism, and may invoke the callback on multiple /// threads in parallel. /// </summary> public static async Task FindReferencesAsync(IEntity entity, IProgressMonitor progressMonitor, Action <SearchedFile> callback) { if (entity == null) { throw new ArgumentNullException("entity"); } if (progressMonitor == null) { throw new ArgumentNullException("progressMonitor"); } if (callback == null) { throw new ArgumentNullException("callback"); } SD.MainThread.VerifyAccess(); if (SD.ParserService.LoadSolutionProjectsThread.IsRunning) { progressMonitor.ShowingDialog = true; MessageService.ShowMessage("${res:SharpDevelop.Refactoring.LoadSolutionProjectsThreadRunning}"); progressMonitor.ShowingDialog = false; return; } double totalWorkAmount; List <ISymbolSearch> symbolSearches = PrepareSymbolSearch(entity, progressMonitor.CancellationToken, out totalWorkAmount); double workDone = 0; ParseableFileContentFinder parseableFileContentFinder = new ParseableFileContentFinder(); foreach (ISymbolSearch s in symbolSearches) { progressMonitor.CancellationToken.ThrowIfCancellationRequested(); using (var childProgressMonitor = progressMonitor.CreateSubTask(s.WorkAmount / totalWorkAmount)) { await s.FindReferencesAsync(new SymbolSearchArgs(childProgressMonitor, parseableFileContentFinder), callback); } workDone += s.WorkAmount; progressMonitor.Progress = workDone / totalWorkAmount; } }
void RunThread() { while (true) { JobTask task; // copy fields from this class into local variables to ensure thread-safety // with concurrent Clear() calls double totalWork, workDone; IProgressMonitor progressMonitor; lock (lockObj) { // enqueued null: quit thread and restart (used for cancellation) if (actions.Count == 0 || this.actions.Peek() == null) { this.threadIsRunning = false; this.progressMonitor.Dispose(); this.progressMonitor = null; // restart if necessary: if (actions.Count > 0) { actions.Dequeue(); // dequeue the null WorkbenchSingleton.SafeThreadAsyncCall(StartRunningIfRequired); } return; } task = this.actions.Dequeue(); totalWork = this.totalWork; workDone = this.workDone; progressMonitor = this.progressMonitor; } progressMonitor.Progress = workDone / totalWork; progressMonitor.TaskName = task.name; try { using (IProgressMonitor subTask = progressMonitor.CreateSubTask(task.cost / totalWork)) { task.Run(subTask); } lock (lockObj) { this.workDone += task.cost; } } catch (OperationCanceledException) { // ignore cancellation } catch (Exception ex) { MessageService.ShowException(ex, "Error on LoadSolutionProjects thread"); } } }
/// <summary> /// Finds all references to the specified entity. /// The results are reported using the callback. /// FindReferences may internally use parallelism, and may invoke the callback on multiple /// threads in parallel. /// </summary> public static async Task FindReferencesAsync(IEntity entity, IProgressMonitor progressMonitor, Action<SearchedFile> callback) { if (entity == null) throw new ArgumentNullException("entity"); if (progressMonitor == null) throw new ArgumentNullException("progressMonitor"); if (callback == null) throw new ArgumentNullException("callback"); SD.MainThread.VerifyAccess(); if (SD.ParserService.LoadSolutionProjectsThread.IsRunning) { progressMonitor.ShowingDialog = true; MessageService.ShowMessage("${res:SharpDevelop.Refactoring.LoadSolutionProjectsThreadRunning}"); progressMonitor.ShowingDialog = false; return; } double totalWorkAmount; List<ISymbolSearch> symbolSearches = PrepareSymbolSearch(entity, progressMonitor.CancellationToken, out totalWorkAmount); double workDone = 0; ParseableFileContentFinder parseableFileContentFinder = new ParseableFileContentFinder(); foreach (ISymbolSearch s in symbolSearches) { progressMonitor.CancellationToken.ThrowIfCancellationRequested(); using (var childProgressMonitor = progressMonitor.CreateSubTask(s.WorkAmount / totalWorkAmount)) { await s.FindReferencesAsync(new SymbolSearchArgs(childProgressMonitor, parseableFileContentFinder), callback); } workDone += s.WorkAmount; progressMonitor.Progress = workDone / totalWorkAmount; } }
public static async Task RenameSymbolAsync(ISymbol symbol, string newName, IProgressMonitor progressMonitor, Action<Error> errorCallback) { if (symbol == null) throw new ArgumentNullException("symbol"); if (progressMonitor == null) throw new ArgumentNullException("progressMonitor"); SD.MainThread.VerifyAccess(); if (SD.ParserService.LoadSolutionProjectsThread.IsRunning) { progressMonitor.ShowingDialog = true; MessageService.ShowMessage("${res:SharpDevelop.Refactoring.LoadSolutionProjectsThreadRunning}"); progressMonitor.ShowingDialog = false; return; } double totalWorkAmount; List<ISymbolSearch> symbolSearches = PrepareSymbolSearch(symbol, progressMonitor.CancellationToken, out totalWorkAmount); double workDone = 0; ParseableFileContentFinder parseableFileContentFinder = new ParseableFileContentFinder(); var errors = new List<Error>(); var changes = new List<PatchedFile>(); foreach (ISymbolSearch s in symbolSearches) { progressMonitor.CancellationToken.ThrowIfCancellationRequested(); using (var childProgressMonitor = progressMonitor.CreateSubTask(s.WorkAmount / totalWorkAmount)) { var args = new SymbolRenameArgs(newName, childProgressMonitor, parseableFileContentFinder); args.ProvideHighlightedLine = false; await s.RenameAsync(args, file => changes.Add(file), error => errors.Add(error)); } workDone += s.WorkAmount; progressMonitor.Progress = workDone / totalWorkAmount; } if (errors.Count == 0) { foreach (var file in changes) { ApplyChanges(file); } } else { foreach (var error in errors) { errorCallback(error); } } }
static ProjectSection SetupSolutionLoadSolutionProjects(Solution newSolution, StreamReader sr, IProgressMonitor progressMonitor) { if (progressMonitor == null) throw new ArgumentNullException("progressMonitor"); string solutionDirectory = Path.GetDirectoryName(newSolution.FileName); ProjectSection nestedProjectsSection = null; IList<ProjectLoadInformation> projectsToLoad = new List<ProjectLoadInformation>(); IList<IList<ProjectSection>> readProjectSections = new List<IList<ProjectSection>>(); // process the solution file contents while (true) { string line = sr.ReadLine(); if (line == null) { break; } Match match = projectLinePattern.Match(line); if (match.Success) { string projectGuid = match.Result("${ProjectGuid}"); string title = match.Result("${Title}"); string location = match.Result("${Location}"); string guid = match.Result("${Guid}"); if (!FileUtility.IsUrl(location)) { location = FileUtility.NormalizePath(Path.Combine(solutionDirectory, location)); } if (projectGuid == FolderGuid) { SolutionFolder newFolder = SolutionFolder.ReadFolder(sr, title, location, guid); newSolution.AddFolder(newFolder); } else { ProjectLoadInformation loadInfo = new ProjectLoadInformation(newSolution, location, title); loadInfo.TypeGuid = projectGuid; loadInfo.Guid = guid; projectsToLoad.Add(loadInfo); IList<ProjectSection> currentProjectSections = new List<ProjectSection>(); ReadProjectSections(sr, currentProjectSections); readProjectSections.Add(currentProjectSections); } match = match.NextMatch(); } else { match = globalSectionPattern.Match(line); if (match.Success) { ProjectSection newSection = ProjectSection.ReadGlobalSection(sr, match.Result("${Name}"), match.Result("${Type}")); // Don't put the NestedProjects section into the global sections list // because it's transformed to a tree representation and the tree representation // is transformed back to the NestedProjects section during save. if (newSection.Name == "NestedProjects") { nestedProjectsSection = newSection; } else { newSolution.Sections.Add(newSection); } } } } // load projects for(int i=0; i<projectsToLoad.Count; i++) { ProjectLoadInformation loadInfo = projectsToLoad[i]; IList<ProjectSection> projectSections = readProjectSections[i]; loadInfo.ProjectSections = projectSections; // set the target platform SolutionItem projectConfig = newSolution.GetProjectConfiguration(loadInfo.Guid); loadInfo.Platform = AbstractProject.GetPlatformNameFromKey(projectConfig.Location); loadInfo.ProgressMonitor = progressMonitor; progressMonitor.Progress = (double)i / projectsToLoad.Count; progressMonitor.TaskName = "Loading " + loadInfo.ProjectName; using (IProgressMonitor nestedProgressMonitor = progressMonitor.CreateSubTask(1.0 / projectsToLoad.Count)) { loadInfo.ProgressMonitor = nestedProgressMonitor; IProject newProject = ProjectBindingService.LoadProject(loadInfo); newProject.IdGuid = loadInfo.Guid; newProject.ProjectSections.AddRange(projectSections); newSolution.AddFolder(newProject); } } return nestedProjectsSection; }
void Initialize(IProgressMonitor progressMonitor, List<FileName> filesToParse) { IReadOnlyCollection<ProjectItem> projectItems = project.Items.CreateSnapshot(); lock (lockObj) { if (disposed) { return; } } double scalingFactor = 1.0 / (projectItems.Count + LoadingReferencesWorkAmount); using (IProgressMonitor initReferencesProgressMonitor = progressMonitor.CreateSubTask(LoadingReferencesWorkAmount * scalingFactor), parseProgressMonitor = progressMonitor.CreateSubTask(projectItems.Count * scalingFactor)) { var resolveReferencesTask = Task.Run( delegate { DoResolveReferences(initReferencesProgressMonitor); }, initReferencesProgressMonitor.CancellationToken); ParseFiles(filesToParse, parseProgressMonitor); resolveReferencesTask.Wait(); } }
public void ReadSolution(Solution solution, IProgressMonitor progress) { ReadFormatHeader(); ReadVersionProperties(solution); // Read solution folder and project entries: var solutionEntries = new List<ProjectLoadInformation>(); var projectInfoDict = new Dictionary<Guid, ProjectLoadInformation>(); var solutionFolderDict = new Dictionary<Guid, SolutionFolder>(); int projectCount = 0; bool fixedGuidConflicts = false; ProjectLoadInformation information; while ((information = ReadProjectEntry(solution)) != null) { solutionEntries.Add(information); if (projectInfoDict.ContainsKey(information.IdGuid)) { // resolve GUID conflicts SD.Log.WarnFormatted("Detected duplicate GUID in .sln file: {0} is used for {1} and {2}", information.IdGuid, information.ProjectName, projectInfoDict[information.IdGuid].ProjectName); information.IdGuid = Guid.NewGuid(); fixedGuidConflicts = true; } projectInfoDict.Add(information.IdGuid, information); if (information.TypeGuid == ProjectTypeGuids.SolutionFolder) { solutionFolderDict.Add(information.IdGuid, CreateSolutionFolder(solution, information)); } else { projectCount++; } } progress.CancellationToken.ThrowIfCancellationRequested(); // Read global sections: if (currentLine != "Global") { if (currentLine == null) throw Error("Unexpected end of file"); else throw Error("Unknown line: " + currentLine); } NextLine(); Dictionary<Guid, SolutionFolder> guidToParentFolderDict = null; SolutionSection section; while ((section = ReadSection(isGlobal: true)) != null) { switch (section.SectionName) { case "SolutionConfigurationPlatforms": var configurations = LoadSolutionConfigurations(section); foreach (var config in configurations.Select(c => c.Configuration).Distinct(ConfigurationAndPlatform.ConfigurationNameComparer)) solution.ConfigurationNames.Add(config, null); foreach (var platform in configurations.Select(c => c.Platform).Distinct(ConfigurationAndPlatform.ConfigurationNameComparer)) solution.PlatformNames.Add(platform, null); break; case "ProjectConfigurationPlatforms": LoadProjectConfigurations(section, projectInfoDict); break; case "NestedProjects": guidToParentFolderDict = LoadNesting(section, solutionFolderDict); break; default: solution.GlobalSections.Add(section); break; } } if (currentLine != "EndGlobal") throw Error("Expected 'EndGlobal'"); NextLine(); if (currentLine != null) throw Error("Expected end of file"); solution.LoadPreferences(); // Now that the project configurations have been set, we can actually load the projects: int projectsLoaded = 0; foreach (var projectInfo in solutionEntries) { // Make copy of IdGuid just in case the project binding writes to projectInfo.IdGuid Guid idGuid = projectInfo.IdGuid; ISolutionItem solutionItem; if (projectInfo.TypeGuid == ProjectTypeGuids.SolutionFolder) { solutionItem = solutionFolderDict[idGuid]; } else { // Load project: projectInfo.ActiveProjectConfiguration = projectInfo.ConfigurationMapping.GetProjectConfiguration(solution.ActiveConfiguration); progress.TaskName = "Loading " + projectInfo.ProjectName; using (projectInfo.ProgressMonitor = progress.CreateSubTask(1.0 / projectCount)) { solutionItem = LoadProjectWithErrorHandling(projectInfo); } if (solutionItem.IdGuid != idGuid) { Guid projectFileGuid = solutionItem.IdGuid; if (!projectInfoDict.ContainsKey(projectFileGuid)) { // We'll use the GUID from the project file. // Register that GUID in the dictionary to avoid its use by multiple projects. projectInfoDict.Add(projectFileGuid, projectInfo); } else { // Cannot use GUID from project file due to conflict. // To fix the problem without potentially introducing new conflicts in other .sln files that contain the project, // we generate a brand new GUID: solutionItem.IdGuid = Guid.NewGuid(); } SD.Log.WarnFormatted("<ProjectGuid> in project '{0}' is '{1}' and does not match the GUID stored in the solution ({2}). " + "The conflict was resolved using the GUID {3}", projectInfo.ProjectName, projectFileGuid, idGuid, solutionItem.IdGuid); fixedGuidConflicts = true; } projectsLoaded++; progress.Progress = (double)projectsLoaded / projectCount; } // Add solutionItem to solution: SolutionFolder folder; if (guidToParentFolderDict != null && guidToParentFolderDict.TryGetValue(idGuid, out folder)) { folder.Items.Add(solutionItem); } else { solution.Items.Add(solutionItem); } } solution.IsDirty = fixedGuidConflicts; // reset IsDirty=false unless we've fixed GUID conflicts }
public void ReadSolution(Solution solution, IProgressMonitor progress) { ReadFormatHeader(); ReadVersionProperties(solution); // Read solution folder and project entries: var solutionEntries = new List <ProjectLoadInformation>(); var projectInfoDict = new Dictionary <Guid, ProjectLoadInformation>(); var solutionFolderDict = new Dictionary <Guid, SolutionFolder>(); int projectCount = 0; bool fixedGuidConflicts = false; ProjectLoadInformation information; while ((information = ReadProjectEntry(solution)) != null) { solutionEntries.Add(information); if (projectInfoDict.ContainsKey(information.IdGuid)) { // resolve GUID conflicts SD.Log.WarnFormatted("Detected duplicate GUID in .sln file: {0} is used for {1} and {2}", information.IdGuid, information.ProjectName, projectInfoDict[information.IdGuid].ProjectName); information.IdGuid = Guid.NewGuid(); fixedGuidConflicts = true; } projectInfoDict.Add(information.IdGuid, information); if (information.TypeGuid == ProjectTypeGuids.SolutionFolder) { solutionFolderDict.Add(information.IdGuid, CreateSolutionFolder(solution, information)); } else { projectCount++; } } progress.CancellationToken.ThrowIfCancellationRequested(); // Read global sections: if (currentLine != "Global") { if (currentLine == null) { throw Error("Unexpected end of file"); } else { throw Error("Unknown line: " + currentLine); } } NextLine(); Dictionary <Guid, SolutionFolder> guidToParentFolderDict = null; SolutionSection section; while ((section = ReadSection(isGlobal: true)) != null) { switch (section.SectionName) { case "SolutionConfigurationPlatforms": var configurations = LoadSolutionConfigurations(section); foreach (var config in configurations.Select(c => c.Configuration).Distinct(ConfigurationAndPlatform.ConfigurationNameComparer)) { solution.ConfigurationNames.Add(config, null); } foreach (var platform in configurations.Select(c => c.Platform).Distinct(ConfigurationAndPlatform.ConfigurationNameComparer)) { solution.PlatformNames.Add(platform, null); } break; case "ProjectConfigurationPlatforms": LoadProjectConfigurations(section, projectInfoDict); break; case "NestedProjects": guidToParentFolderDict = LoadNesting(section, solutionFolderDict); break; default: solution.GlobalSections.Add(section); break; } } if (currentLine != "EndGlobal") { throw Error("Expected 'EndGlobal'"); } NextLine(); if (currentLine != null) { throw Error("Expected end of file"); } solution.LoadPreferences(); // Now that the project configurations have been set, we can actually load the projects: int projectsLoaded = 0; foreach (var projectInfo in solutionEntries) { // Make copy of IdGuid just in case the project binding writes to projectInfo.IdGuid Guid idGuid = projectInfo.IdGuid; ISolutionItem solutionItem; if (projectInfo.TypeGuid == ProjectTypeGuids.SolutionFolder) { solutionItem = solutionFolderDict[idGuid]; } else { // Load project: projectInfo.ActiveProjectConfiguration = projectInfo.ConfigurationMapping.GetProjectConfiguration(solution.ActiveConfiguration); progress.TaskName = "Loading " + projectInfo.ProjectName; using (projectInfo.ProgressMonitor = progress.CreateSubTask(1.0 / projectCount)) { solutionItem = LoadProjectWithErrorHandling(projectInfo); } if (solutionItem.IdGuid != idGuid) { Guid projectFileGuid = solutionItem.IdGuid; if (!projectInfoDict.ContainsKey(projectFileGuid)) { // We'll use the GUID from the project file. // Register that GUID in the dictionary to avoid its use by multiple projects. projectInfoDict.Add(projectFileGuid, projectInfo); } else { // Cannot use GUID from project file due to conflict. // To fix the problem without potentially introducing new conflicts in other .sln files that contain the project, // we generate a brand new GUID: solutionItem.IdGuid = Guid.NewGuid(); } SD.Log.WarnFormatted("<ProjectGuid> in project '{0}' is '{1}' and does not match the GUID stored in the solution ({2}). " + "The conflict was resolved using the GUID {3}", projectInfo.ProjectName, projectFileGuid, idGuid, solutionItem.IdGuid); fixedGuidConflicts = true; } projectsLoaded++; progress.Progress = (double)projectsLoaded / projectCount; } // Add solutionItem to solution: SolutionFolder folder; if (guidToParentFolderDict != null && guidToParentFolderDict.TryGetValue(idGuid, out folder)) { folder.Items.Add(solutionItem); } else { solution.Items.Add(solutionItem); } } solution.IsDirty = fixedGuidConflicts; // reset IsDirty=false unless we've fixed GUID conflicts }
public void ReadSolution(Solution solution, IProgressMonitor progress) { ReadFormatHeader(); ReadVersionProperties(solution); // Read solution folder and project entries: var solutionEntries = new List<ProjectLoadInformation>(); var projectInfoDict = new Dictionary<Guid, ProjectLoadInformation>(); var solutionFolderDict = new Dictionary<Guid, SolutionFolder>(); int projectCount = 0; bool fixedGuidConflicts = false; ProjectLoadInformation information; while ((information = ReadProjectEntry(solution)) != null) { solutionEntries.Add(information); if (projectInfoDict.ContainsKey(information.IdGuid)) { // resolve GUID conflicts information.IdGuid = Guid.NewGuid(); fixedGuidConflicts = true; } projectInfoDict.Add(information.IdGuid, information); if (information.TypeGuid == ProjectTypeGuids.SolutionFolder) { solutionFolderDict.Add(information.IdGuid, CreateSolutionFolder(solution, information)); } else { projectCount++; } } progress.CancellationToken.ThrowIfCancellationRequested(); // Read global sections: if (currentLine != "Global") { if (currentLine == null) throw Error("Unexpected end of file"); else throw Error("Unknown line: " + currentLine); } NextLine(); Dictionary<Guid, SolutionFolder> guidToParentFolderDict = null; SolutionSection section; while ((section = ReadSection(isGlobal: true)) != null) { switch (section.SectionName) { case "SolutionConfigurationPlatforms": var configurations = LoadSolutionConfigurations(section); foreach (var config in configurations.Select(c => c.Configuration).Distinct(ConfigurationAndPlatform.ConfigurationNameComparer)) solution.ConfigurationNames.Add(config, null); foreach (var platform in configurations.Select(c => c.Platform).Distinct(ConfigurationAndPlatform.ConfigurationNameComparer)) solution.PlatformNames.Add(platform, null); break; case "ProjectConfigurationPlatforms": LoadProjectConfigurations(section, projectInfoDict); break; case "NestedProjects": guidToParentFolderDict = LoadNesting(section, solutionFolderDict); break; default: solution.GlobalSections.Add(section); break; } } if (currentLine != "EndGlobal") throw Error("Expected 'EndGlobal'"); NextLine(); if (currentLine != null) throw Error("Expected end of file"); solution.LoadPreferences(); // Now that the project configurations have been set, we can actually load the projects: int projectsLoaded = 0; foreach (var projectInfo in solutionEntries) { ISolutionItem solutionItem; if (projectInfo.TypeGuid == ProjectTypeGuids.SolutionFolder) { solutionItem = solutionFolderDict[projectInfo.IdGuid]; } else { // Load project: projectInfo.ActiveProjectConfiguration = projectInfo.ConfigurationMapping.GetProjectConfiguration(solution.ActiveConfiguration); progress.TaskName = "Loading " + projectInfo.ProjectName; using (projectInfo.ProgressMonitor = progress.CreateSubTask(1.0 / projectCount)) { solutionItem = ProjectBindingService.LoadProject(projectInfo); } projectsLoaded++; progress.Progress = (double)projectsLoaded / projectCount; } // Add solutionItem to solution: SolutionFolder folder; if (guidToParentFolderDict != null && guidToParentFolderDict.TryGetValue(projectInfo.IdGuid, out folder)) { folder.Items.Add(solutionItem); } else { solution.Items.Add(solutionItem); } } solution.IsDirty = fixedGuidConflicts; // reset IsDirty=false unless we've fixed GUID conflicts }