File: Build\ProjectNodeMap.cs
Web Access
Project: ..\..\..\src\BuiltInTools\dotnet-watch\dotnet-watch.csproj (dotnet-watch)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
 
using Microsoft.Build.Graph;
using Microsoft.Extensions.Logging;
 
namespace Microsoft.DotNet.Watch
{
    internal readonly struct ProjectNodeMap(ProjectGraph graph, ILogger logger)
    {
        public readonly ProjectGraph Graph = graph;
 
        // full path of proj file to list of nodes representing all target frameworks of the project:
        public readonly IReadOnlyDictionary<string, IReadOnlyList<ProjectGraphNode>> Map = 
            graph.ProjectNodes.GroupBy(n => n.ProjectInstance.FullPath).ToDictionary(
                keySelector: static g => g.Key,
                elementSelector: static g => (IReadOnlyList<ProjectGraphNode>)[.. g]);
 
        public IReadOnlyList<ProjectGraphNode> GetProjectNodes(string projectPath)
        {
            if (Map.TryGetValue(projectPath, out var rootProjectNodes))
            {
                return rootProjectNodes;
            }
 
            logger.LogError("Project '{ProjectPath}' not found in the project graph.", projectPath);
            return [];
        }
 
        public ProjectGraphNode? TryGetProjectNode(string projectPath, string? targetFramework)
        {
            var projectNodes = GetProjectNodes(projectPath);
            if (projectNodes is [])
            {
                return null;
            }
 
            if (targetFramework == null)
            {
                if (projectNodes.Count > 1)
                {
                    logger.LogError("Project '{ProjectPath}' targets multiple frameworks. Specify which framework to run using '--framework'.", projectPath);
                    return null;
                }
 
                return projectNodes[0];
            }
 
            ProjectGraphNode? candidate = null;
            foreach (var node in projectNodes)
            {
                if (node.ProjectInstance.GetPropertyValue("TargetFramework") == targetFramework)
                {
                    if (candidate != null)
                    {
                        // shouldn't be possible:
                        logger.LogWarning("Project '{ProjectPath}' has multiple instances targeting {TargetFramework}.", projectPath, targetFramework);
                        return candidate;
                    }
 
                    candidate = node;
                }
            }
 
            if (candidate == null)
            {
                logger.LogError("Project '{ProjectPath}' doesn't have a target for {TargetFramework}.", projectPath, targetFramework);
            }
 
            return candidate;
        }
    }
}