/// <summary> /// Traverses the predicted project directory outputs and returns a collection of shared directories such that: /// - each directory is unique /// - no directory is nested within any other /// In addition, it adds a catch-all shared opaque directory at the root of the enlistment /// </summary> private ISet <AbsolutePath> GetOutputDirectories( ProjectWithPredictions project) { var sharedOutputDirectories = new HashSet <AbsolutePath>(); // Create a catch-all shared opaque directory at the root. This will likely catch all under-predicted outputs // We still process the predicted outputs just in case any of those happen to fall outside the root sharedOutputDirectories.Add(Root); foreach (AbsolutePath outputDirectory in project.PredictedOutputFolders) { sharedOutputDirectories.Add(outputDirectory); } // Add user-defined additional output directories if (m_resolverSettings.AdditionalOutputDirectories != null) { foreach (AbsolutePath additionalOutputDirectory in m_resolverSettings.AdditionalOutputDirectories) { sharedOutputDirectories.Add(additionalOutputDirectory); } } // Collapse all shared opaque directories to find common ancestors. For the most part, this should result in just the // catch-all shared opaque at the root return(AbsolutePathUtilities.CollapseDirectories(sharedOutputDirectories, PathTable)); }
private void CreateMappingForOutputs(Process process, out MultiValueDictionary <AbsolutePath, ExpandedAbsolutePath> originalDirectories, out MultiValueDictionary <ExpandedAbsolutePath, ExpandedAbsolutePath> redirectedDirectories) { // Collect all predicted outputs (directories and files) for the given process var directories = CollectAllOutputDirectories(m_pathTable, process); // In order to keep the filter configuration to its minimum, let's remove directories that are nested within each other var dedupDirectories = AbsolutePathUtilities.CollapseDirectories(directories, m_pathTable, out var originalToCollapsedMapping); var stringTable = m_pathTable.StringTable; var reserveFoldersResolver = new ReserveFoldersResolver(new object()); originalDirectories = new MultiValueDictionary <AbsolutePath, ExpandedAbsolutePath>(originalToCollapsedMapping.Count); redirectedDirectories = new MultiValueDictionary <ExpandedAbsolutePath, ExpandedAbsolutePath>(dedupDirectories.Count, ExpandedAbsolutePathEqualityComparer.Instance); // Map from original dedup directories to unique redirected directories var uniqueRedirectedDirectories = new Dictionary <AbsolutePath, ExpandedAbsolutePath>(dedupDirectories.Count); foreach (var kvp in originalToCollapsedMapping) { AbsolutePath originalDirectory = kvp.Key; AbsolutePath originalCollapsedDirectory = kvp.Value; if (!uniqueRedirectedDirectories.TryGetValue(originalCollapsedDirectory, out var uniqueRedirectedDirectory)) { uniqueRedirectedDirectory = GetUniqueRedirectedDirectory(process, ref reserveFoldersResolver, originalCollapsedDirectory).Expand(m_pathTable); uniqueRedirectedDirectories.Add(originalCollapsedDirectory, uniqueRedirectedDirectory); redirectedDirectories.Add(uniqueRedirectedDirectory, originalCollapsedDirectory.Expand(m_pathTable)); } // Let's reconstruct the redirected directory var redirectedDirectory = originalDirectory.Relocate(m_pathTable, originalCollapsedDirectory, uniqueRedirectedDirectory.Path); originalDirectories.Add(originalDirectory, redirectedDirectory.Expand(m_pathTable)); } }