Skip to content

Commit

Permalink
Bring back MSBuildWorkspace.TryApplyChanges
Browse files Browse the repository at this point in the history
This removes the #ifdefing and instead of modifying the MSBuild
project instances in-process, it RPCs to a build host process to do it.
  • Loading branch information
jasonmalinowski committed Oct 28, 2023
1 parent 9842dbc commit 52be409
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 112 deletions.
10 changes: 10 additions & 0 deletions src/Workspaces/Core/MSBuild.BuildHost/IRemoteProjectFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,14 @@ internal interface IRemoteProjectFile : IDisposable
{
Task<ImmutableArray<ProjectFileInfo>> GetProjectFileInfosAsync(CancellationToken cancellationToken);
Task<ImmutableArray<DiagnosticLogItem>> GetDiagnosticLogItemsAsync(CancellationToken cancellationToken);

Task<string> GetDocumentExtensionAsync(SourceCodeKind sourceCodeKind, CancellationToken cancellationToken);
Task AddDocumentAsync(string filePath, string? logicalPath, CancellationToken cancellationToken);
Task RemoveDocumentAsync(string filePath, CancellationToken cancellationToken);
Task AddMetadataReferenceAsync(string metadataReferenceIdentity, MetadataReferenceProperties properties, string? hintPath, CancellationToken cancellationToken);
Task AddProjectReferenceAsync(string projectName, ProjectFileReference reference, CancellationToken cancellationToken);
Task RemoveProjectReferenceAsync(string projectName, string projectFilePath, CancellationToken cancellationToken);
Task AddAnalyzerReferenceAsync(string fullPath, CancellationToken cancellationToken);
Task RemoveAnalyzerReferenceAsync(string fullPath, CancellationToken cancellationToken);
Task SaveAsync(CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -388,66 +388,21 @@ public void RemoveDocument(string filePath)
}
}

public void AddMetadataReference(MetadataReference reference, AssemblyIdentity identity)
public void AddMetadataReference(string metadataReferenceIdentity, MetadataReferenceProperties properties, string? hintPath)
{
if (_loadedProject is null)
{
return;
}

if (reference is PortableExecutableReference peRef && peRef.FilePath != null)
{
var metadata = new Dictionary<string, string>();
if (!peRef.Properties.Aliases.IsEmpty)
{
metadata.Add(MetadataNames.Aliases, string.Join(",", peRef.Properties.Aliases));
}

if (IsInGAC(peRef.FilePath) && identity != null)
{
// Since the location of the reference is in GAC, need to use full identity name to find it again.
// This typically happens when you base the reference off of a reflection assembly location.
_loadedProject.AddItem(ItemNames.Reference, identity.GetDisplayName(), metadata);
}
else if (IsFrameworkReferenceAssembly(peRef.FilePath))
{
// just use short name since this will be resolved by msbuild relative to the known framework reference assemblies.
var fileName = identity != null ? identity.Name : Path.GetFileNameWithoutExtension(peRef.FilePath);
_loadedProject.AddItem(ItemNames.Reference, fileName, metadata);
}
else // other location -- need hint to find correct assembly
{
var relativePath = PathUtilities.GetRelativePath(_loadedProject.DirectoryPath, peRef.FilePath);
var fileName = Path.GetFileNameWithoutExtension(peRef.FilePath);
metadata.Add(MetadataNames.HintPath, relativePath);
_loadedProject.AddItem(ItemNames.Reference, fileName, metadata);
}
}
}

private static bool IsInGAC(string filePath)
{
return GlobalAssemblyCacheLocation.RootLocations.Any(static (gloc, filePath) => PathUtilities.IsChildPath(gloc, filePath), filePath);
}

private static string? s_frameworkRoot;
private static string FrameworkRoot
{
get
{
if (RoslynString.IsNullOrEmpty(s_frameworkRoot))
{
var runtimeDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
s_frameworkRoot = Path.GetDirectoryName(runtimeDir); // back out one directory level to be root path of all framework versions
}
var metadata = new Dictionary<string, string>();
if (!properties.Aliases.IsEmpty)
metadata.Add(MetadataNames.Aliases, string.Join(",", properties.Aliases));

return s_frameworkRoot ?? throw new InvalidOperationException($"Unable to get {nameof(FrameworkRoot)}");
}
}
if (hintPath is not null)
metadata.Add(MetadataNames.HintPath, hintPath);

private static bool IsFrameworkReferenceAssembly(string filePath)
{
return PathUtilities.IsChildPath(FrameworkRoot, filePath);
_loadedProject.AddItem(ItemNames.Reference, metadataReferenceIdentity, metadata);
}

public void RemoveMetadataReference(MetadataReference reference, AssemblyIdentity identity)
Expand Down Expand Up @@ -576,38 +531,32 @@ public void RemoveProjectReference(string projectName, string projectFilePath)
return item;
}

public void AddAnalyzerReference(AnalyzerReference reference)
public void AddAnalyzerReference(string fullPath)
{
if (_loadedProject is null)
{
return;
}

if (reference is AnalyzerFileReference fileRef)
{
var relativePath = PathUtilities.GetRelativePath(_loadedProject.DirectoryPath, fileRef.FullPath);
_loadedProject.AddItem(ItemNames.Analyzer, relativePath);
}
var relativePath = PathUtilities.GetRelativePath(_loadedProject.DirectoryPath, fullPath);
_loadedProject.AddItem(ItemNames.Analyzer, relativePath);
}

public void RemoveAnalyzerReference(AnalyzerReference reference)
public void RemoveAnalyzerReference(string fullPath)
{
if (_loadedProject is null)
{
return;
}

if (reference is AnalyzerFileReference fileRef)
{
var relativePath = PathUtilities.GetRelativePath(_loadedProject.DirectoryPath, fileRef.FullPath);
var relativePath = PathUtilities.GetRelativePath(_loadedProject.DirectoryPath, fullPath);

var analyzers = _loadedProject.GetItems(ItemNames.Analyzer);
var item = analyzers.FirstOrDefault(it => PathUtilities.PathsEqual(it.EvaluatedInclude, relativePath)
|| PathUtilities.PathsEqual(it.EvaluatedInclude, fileRef.FullPath));
if (item != null)
{
_loadedProject.RemoveItem(item);
}
var analyzers = _loadedProject.GetItems(ItemNames.Analyzer);
var item = analyzers.FirstOrDefault(it => PathUtilities.PathsEqual(it.EvaluatedInclude, relativePath)
|| PathUtilities.PathsEqual(it.EvaluatedInclude, fullPath));
if (item != null)
{
_loadedProject.RemoveItem(item);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,12 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<RootNamespace>Microsoft.CodeAnalysis</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TargetFrameworks>$(SourceBuildTargetFrameworks);net472</TargetFrameworks>
<!-- We'll always be running our build host with the same host that is used to launch the language server process directly, so we don't need to create another one -->
<UseAppHost>false</UseAppHost>
<!-- Set to false since it's also set in Microsoft.CodeAnalysis.LanguageServer -->
<SelfContained>false</SelfContained>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\..\Compilers\Shared\GlobalAssemblyCacheHelpers\GlobalAssemblyCacheLocation.cs">
<Link>InternalUtilities\GlobalAssemblyCache.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" ExcludeAssets="Runtime" PrivateAssets="All" />
<PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" ExcludeAssets="Runtime" />
Expand Down
50 changes: 50 additions & 0 deletions src/Workspaces/Core/MSBuild.BuildHost/RemoteProjectFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,54 @@ public Task<ImmutableArray<ProjectFileInfo>> GetProjectFileInfosAsync(Cancellati
public Task<ImmutableArray<DiagnosticLogItem>> GetDiagnosticLogItemsAsync(CancellationToken cancellationToken)
=> Task.FromResult(_projectFile.Log.ToImmutableArray());

public Task<string> GetDocumentExtensionAsync(SourceCodeKind sourceCodeKind, CancellationToken cancellationToken)
=> Task.FromResult(_projectFile.GetDocumentExtension(sourceCodeKind));

public Task AddDocumentAsync(string filePath, string? logicalPath, CancellationToken cancellationToken)
{
_projectFile.AddDocument(filePath, logicalPath);
return Task.CompletedTask;
}

public Task RemoveDocumentAsync(string filePath, CancellationToken cancellationToken)
{
_projectFile.RemoveDocument(filePath);
return Task.CompletedTask;
}

public Task AddMetadataReferenceAsync(string metadataReferenceIdentity, MetadataReferenceProperties properties, string? hintPath, CancellationToken cancellationToken)
{
_projectFile.AddMetadataReference(metadataReferenceIdentity, properties, hintPath);
return Task.CompletedTask;
}

public Task AddProjectReferenceAsync(string projectName, ProjectFileReference reference, CancellationToken cancellationToken)
{
_projectFile.AddProjectReference(projectName, reference);
return Task.CompletedTask;
}

public Task RemoveProjectReferenceAsync(string projectName, string projectFilePath, CancellationToken cancellationToken)
{
_projectFile.RemoveProjectReference(projectName, projectFilePath);
return Task.CompletedTask;
}

public Task AddAnalyzerReferenceAsync(string fullPath, CancellationToken cancellationToken)
{
_projectFile.AddAnalyzerReference(fullPath);
return Task.CompletedTask;
}

public Task RemoveAnalyzerReferenceAsync(string fullPath, CancellationToken cancellationToken)
{
_projectFile.RemoveAnalyzerReference(fullPath);
return Task.CompletedTask;
}

public Task SaveAsync(CancellationToken cancellationToken)
{
_projectFile.Save();
return Task.CompletedTask;
}
}
Loading

0 comments on commit 52be409

Please sign in to comment.