| File: MSBuild\FileBasedProgramsProjectLoader.cs | Web Access |
| Project: src\roslyn\src\Workspaces\MSBuild\Core\Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj (Microsoft.CodeAnalysis.Workspaces.MSBuild) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Xml; using Microsoft.CodeAnalysis.FileBasedPrograms; using Microsoft.DotNet.FileBasedPrograms; namespace Microsoft.CodeAnalysis.MSBuild; internal static class FileBasedProgramsProjectLoader { public static async Task<RemoteProjectFile> LoadFileBasedAppProjectAsync( RemoteBuildHost buildHost, IFileBasedProgramService fileBasedProgramService, string entryPointFilePath, Action<string> reportError, CancellationToken cancellationToken) { var buildService = new FileBasedProgramsBuildService(buildHost, cancellationToken); await using var _ = buildService.ConfigureAwait(false); var projectRootElement = await fileBasedProgramService.LoadFileBasedAppProjectAsync( buildService, FileBasedProgramsBuildService.ProjectCollection, entryPointFilePath, reportError).ConfigureAwait(false); return await buildHost.LoadProjectAsync( projectRootElement.FullPath!, physicalFilePath: entryPointFilePath, projectRootElement.GetRawXml(), LanguageNames.CSharp, globalProperties: fileBasedProgramService.GetGlobalBuildProperties(), cancellationToken).ConfigureAwait(false); } } /// <summary> /// An implementation of <see cref="IBuildService"/> which uses MSBuild over RPC (via <see cref="RemoteBuildHost"/>). /// </summary> file sealed class FileBasedProgramsBuildService(RemoteBuildHost buildHost, CancellationToken cancellationToken) : IBuildService, IAsyncDisposable { public static IProjectCollection ProjectCollection => Microsoft.CodeAnalysis.MSBuild.ProjectCollection.Instance; public ConcurrentBag<IAsyncDisposable> Disposables { get; } = []; public ValueTask<Microsoft.DotNet.FileBasedPrograms.IProjectInstance> CreateProjectInstanceFromProjectRootElementAsync( IProjectRootElement projectRoot, IProjectCollection projectCollection, IDictionary<string, string>? additionalGlobalProperties) { return ProjectInstance.FromProjectRootElementAsync(this, buildHost, (ProjectRootElement)projectRoot, (ProjectCollection)projectCollection, additionalGlobalProperties, cancellationToken); } public IProjectRootElement CreateProjectRootElement(XmlReader xmlReader, IProjectCollection projectCollection, string entryPointFilePath) { xmlReader.MoveToContent(); return new ProjectRootElement(xmlReader.ReadOuterXml()); } public async ValueTask DisposeAsync() { while (Disposables.TryTake(out var disposable)) { await disposable.DisposeAsync().ConfigureAwait(false); } } } /// <summary> /// Our adapter for MSBuild's <c>ProjectCollection</c> in <see cref="FileBasedProgramsBuildService"/> abstraction. /// </summary> file sealed class ProjectCollection : IProjectCollection { public static ProjectCollection Instance { get; } = new(); private ProjectCollection() { } } /// <summary> /// Our adapter for MSBuild's <c>ProjectInstance</c> in <see cref="FileBasedProgramsBuildService"/> abstraction. /// </summary> file sealed class ProjectInstance(RemoteProjectInstance remoteProjectInstance, CancellationToken cancellationToken) : Microsoft.DotNet.FileBasedPrograms.IProjectInstance { public static async ValueTask<Microsoft.DotNet.FileBasedPrograms.IProjectInstance> FromProjectRootElementAsync( FileBasedProgramsBuildService service, RemoteBuildHost buildHost, ProjectRootElement projectRoot, ProjectCollection projectCollection, IDictionary<string, string>? additionalGlobalProperties, CancellationToken cancellationToken) { Debug.Assert(projectCollection == ProjectCollection.Instance); var remoteProjectInstance = await buildHost.LoadProjectInstanceAsync(projectRoot.FullPath!, projectRoot.GetRawXml(), additionalGlobalProperties, cancellationToken).ConfigureAwait(false); service.Disposables.Add(remoteProjectInstance); return new ProjectInstance(remoteProjectInstance, cancellationToken); } public ValueTask<ImmutableArray<ImmutableArray<string>>> GetItemMetadataValuesAsync(string itemType, ImmutableArray<string> metadataNames) => new(remoteProjectInstance.GetItemMetadataValuesAsync(itemType, metadataNames.ToArray(), cancellationToken)); public ValueTask<string> GetPropertyValueAsync(string propertyName) => new(remoteProjectInstance.GetPropertyValueAsync(propertyName, cancellationToken)); public ValueTask<string> ExpandStringAsync(string value) => new(remoteProjectInstance.ExpandStringAsync(value, cancellationToken)); } /// <summary> /// Our adapter for MSBuild's <c>ProjectRootElement</c> in <see cref="FileBasedProgramsBuildService"/> abstraction. /// </summary> file sealed class ProjectRootElement(string content) : IProjectRootElement { public string? FullPath { get; set; } public string GetRawXml() => content; }