forked from waf/CSharpRepl
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSolutionFileMetadataResolver.cs
More file actions
83 lines (70 loc) · 3.3 KB
/
Copy pathSolutionFileMetadataResolver.cs
File metadata and controls
83 lines (70 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
using System;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CSharpRepl.Services.Dotnet;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;
namespace CSharpRepl.Services.Roslyn.MetadataResolvers;
internal sealed class SolutionFileMetadataResolver : AlternativeReferenceResolver
{
private readonly DotnetBuilder builder;
private readonly IConsoleEx console;
public SolutionFileMetadataResolver(DotnetBuilder builder, IConsoleEx console)
{
this.builder = builder;
this.console = console;
}
public override bool CanResolve(string reference) =>
reference.EndsWith(".sln", StringComparison.OrdinalIgnoreCase) ||
reference.EndsWith(".sln\"", StringComparison.OrdinalIgnoreCase) ||
reference.EndsWith(".slnx", StringComparison.OrdinalIgnoreCase) ||
reference.EndsWith(".slnx\"", StringComparison.OrdinalIgnoreCase) ||
reference.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase) ||
reference.EndsWith(".csproj\"", StringComparison.OrdinalIgnoreCase);
public override async Task<ImmutableArray<PortableExecutableReference>> ResolveAsync(string reference, CancellationToken cancellationToken)
{
var solutionPath = Path.GetFullPath(reference
.Split('\"', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Last());
var (exitCode, _) = await builder.BuildAsync(solutionPath, cancellationToken);
if (exitCode != 0)
{
console.WriteErrorLine("Reference not added: build failed.");
return [];
}
console.WriteLine("Adding references from built project...");
var metadataReferences = await GetMetadataReferences(solutionPath, cancellationToken);
return metadataReferences;
}
private async Task<ImmutableArray<PortableExecutableReference>> GetMetadataReferences(string solutionOrProject, CancellationToken cancellationToken)
{
var workspace = MSBuildWorkspace.Create();
var projects = Path.GetExtension(solutionOrProject) switch
{
".csproj" => [await workspace.OpenProjectAsync(solutionOrProject, cancellationToken: cancellationToken)],
".sln" or ".slnx" => (await workspace.OpenSolutionAsync(solutionOrProject, cancellationToken: cancellationToken)).Projects,
_ => throw new ArgumentException("Unexpected filetype for file " + solutionOrProject)
};
foreach (var error in workspace.Diagnostics.Where(d => d.Kind == WorkspaceDiagnosticKind.Failure))
{
console.WriteErrorLine(error.Message);
}
return projects
.SelectMany(p =>
p.MetadataReferences
.OfType<PortableExecutableReference>()
.Concat(p.OutputFilePath is not null
? [MetadataReference.CreateFromFile(p.OutputFilePath)]
: Array.Empty<PortableExecutableReference>()
)
)
.Distinct()
.ToImmutableArray();
}
}