private async Task <Possible <ProjectGraphResult> > TryComputeBuildGraphAsync(IEnumerable <AbsolutePath> msBuildSearchLocations, IEnumerable <AbsolutePath> dotnetSearchLocations, IEnumerable <AbsolutePath> parsingEntryPoints, BuildParameters.IBuildParameters buildParameters) { // We create a unique output file on the obj folder associated with the current front end, and using a GUID as the file name AbsolutePath outputDirectory = m_host.GetFolderForFrontEnd(MsBuildFrontEnd.Name); AbsolutePath outputFile = outputDirectory.Combine(m_context.PathTable, Guid.NewGuid().ToString()); // We create a unique response file that will contain the tool arguments AbsolutePath responseFile = outputDirectory.Combine(m_context.PathTable, Guid.NewGuid().ToString()); // Make sure the directories are there FileUtilities.CreateDirectory(outputDirectory.ToString(m_context.PathTable)); Possible <ProjectGraphWithPredictionsResult <AbsolutePath> > maybeProjectGraphResult = await ComputeBuildGraphAsync(responseFile, parsingEntryPoints, outputFile, msBuildSearchLocations, dotnetSearchLocations, buildParameters); if (!maybeProjectGraphResult.Succeeded) { // A more specific error has been logged already return(maybeProjectGraphResult.Failure); } var projectGraphResult = maybeProjectGraphResult.Result; if (m_resolverSettings.KeepProjectGraphFile != true) { DeleteGraphBuilderRelatedFiles(outputFile, responseFile); } else { // Graph-related files are requested to be left on disk. Let's print a message with their location. Tracing.Logger.Log.GraphBuilderFilesAreNotRemoved(m_context.LoggingContext, outputFile.ToString(m_context.PathTable), responseFile.ToString(m_context.PathTable)); } if (!projectGraphResult.Succeeded) { var failure = projectGraphResult.Failure; Tracing.Logger.Log.ProjectGraphConstructionError(m_context.LoggingContext, failure.HasLocation ? failure.Location : m_resolverSettings.Location(m_context.PathTable), failure.Message); return(new MsBuildGraphConstructionFailure(m_resolverSettings, m_context.PathTable)); } ProjectGraphWithPredictions <AbsolutePath> projectGraph = projectGraphResult.Result; // The module contains all project files that are part of the graph var projectFiles = new HashSet <AbsolutePath>(); foreach (ProjectWithPredictions <AbsolutePath> node in projectGraph.ProjectNodes) { projectFiles.Add(node.FullPath); } var moduleDescriptor = ModuleDescriptor.CreateWithUniqueId(m_context.StringTable, m_resolverSettings.ModuleName, this); var moduleDefinition = ModuleDefinition.CreateModuleDefinitionWithImplicitReferences( moduleDescriptor, m_resolverSettings.RootTraversal, m_resolverSettings.File, projectFiles, allowedModuleDependencies: null, // no module policies cyclicalFriendModules: null); // no whitelist of cycles return(new ProjectGraphResult(projectGraph, moduleDefinition, projectGraphResult.PathToMsBuild, projectGraphResult.PathToDotNetExe)); }
/// <summary> /// Validates that a <param name="projectGraph"/> is contained by a set of <see cref="projectChains"/>. If <param name="assertEqual"/> is specified, /// the graph must match exactly (not just be a sub-graph). /// </summary> public void ValidateGraphIsSubgraphOfChains(ProjectGraphWithPredictions <string> projectGraph, bool assertEqual, params string[] projectChains) { var projectsAndReferences = ProcessProjectChains(projectChains, out var entryPoint); if (assertEqual) { // Number of projects should be equal Assert.True(projectGraph.ProjectNodes.Length == projectsAndReferences.Keys.Count, $"Expected {projectGraph.ProjectNodes.Length} nodes but found '{projectsAndReferences.Keys.Count}'"); } foreach (ProjectWithPredictions <string> node in projectGraph.ProjectNodes) { // We should be able to find the corresponding project in the chains string nodeName = Path.GetFileName(node.FullPath); Assert.True(projectsAndReferences.ContainsKey(nodeName)); // And its references should match IEnumerable <string> nodeReferenceNames = node.ProjectReferences.Select(nodeReference => Path.GetFileName(nodeReference.FullPath)); if (!projectsAndReferences[nodeName].SetEquals(nodeReferenceNames)) { var difference = new HashSet <string>(projectsAndReferences[nodeName]); difference.SymmetricExceptWith(nodeReferenceNames); Assert.True(false, $"Expected same set of references but these elements are not in the intersection of them: {string.Join(",", difference)}"); } } }
/// <nodoc/> public ProjectGraphResult(ProjectGraphWithPredictions <AbsolutePath> projectGraphWithPredictions, ModuleDefinition moduleDefinition, AbsolutePath msBuildExeLocation) { Contract.Requires(projectGraphWithPredictions != null); Contract.Requires(moduleDefinition != null); Contract.Requires(msBuildExeLocation.IsValid); ProjectGraph = projectGraphWithPredictions; ModuleDefinition = moduleDefinition; MsBuildExeLocation = msBuildExeLocation; }