Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support solution filters (*.slnf) #1952

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/OmniSharp.Host/Services/OmniSharpEnvironment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ public OmniSharpEnvironment(
{
TargetDirectory = path;
}
else if (File.Exists(path) && Path.GetExtension(path).Equals(".sln", StringComparison.OrdinalIgnoreCase))
else if (File.Exists(path) && (Path.GetExtension(path).Equals(".sln", StringComparison.OrdinalIgnoreCase) || Path.GetExtension(path).Equals(".slnf", StringComparison.OrdinalIgnoreCase)))
{
SolutionFilePath = path;
TargetDirectory = Path.GetDirectoryName(path);
}

if (TargetDirectory == null)
{
throw new ArgumentException("OmniSharp only supports being launched with a directory path or a path to a solution (.sln) file.", nameof(path));
throw new ArgumentException("OmniSharp only supports being launched with a directory path or a path to a solution (.sln, .slnf) file.", nameof(path));
}

HostProcessId = hostPid;
Expand Down
7 changes: 4 additions & 3 deletions src/OmniSharp.MSBuild/ProjectSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,12 @@ public void Initalize(IConfiguration configuration)

private static string FindSolutionFilePath(string rootPath, ILogger logger)
{
// currently, Directory.GetFiles collects files that the file extension has 'sln' prefix.
// this causes collecting unexpected files like 'x.slnx', or 'x.slnproj'.
// currently, Directory.GetFiles on Windows collects files that the file extension has 'sln' prefix, while
// GetFiles on Mono looks for an exact match. Use an approach that works for both.
// see https://docs.microsoft.com/en-us/dotnet/api/system.io.directory.getfiles?view=netframework-4.7.2 ('Note' description)
var solutionsFilePaths = Directory.GetFiles(rootPath, "*.sln").Where(x => Path.GetExtension(x).Equals(".sln", StringComparison.OrdinalIgnoreCase)).ToArray();
var result = SolutionSelector.Pick(solutionsFilePaths, rootPath);
var solutionFiltersFilePaths = Directory.GetFiles(rootPath, "*.slnf").Where(x => Path.GetExtension(x).Equals(".slnf", StringComparison.OrdinalIgnoreCase)).ToArray();
var result = SolutionSelector.Pick(solutionsFilePaths.Concat(solutionFiltersFilePaths).ToArray(), rootPath);

if (result.Message != null)
{
Expand Down
8 changes: 8 additions & 0 deletions src/OmniSharp.MSBuild/SolutionParsing/ProjectBlock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,13 @@ public static ProjectBlock Parse(string headerLine, Scanner scanner)

return new ProjectBlock(projectTypeGuid, projectName, relativePath, projectGuid, sections.ToImmutable());
}

public ProjectBlock WithRelativePath(string relativePath)
{
if (relativePath == RelativePath)
return this;

return new ProjectBlock(ProjectTypeGuid, ProjectName, relativePath, ProjectGuid, Sections);
}
}
}
43 changes: 42 additions & 1 deletion src/OmniSharp.MSBuild/SolutionParsing/SolutionFile.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;

namespace OmniSharp.MSBuild.SolutionParsing
{
Expand Down Expand Up @@ -68,10 +70,49 @@ public static SolutionFile Parse(string text)
}
}

public static SolutionFile ParseSolutionFilter(string basePath, string text)
{
var root = JObject.Parse(text);
var solutionPath = ((string)root["solution"]?["path"])?.Replace('\\', Path.DirectorySeparatorChar);
var includedProjects = (JArray)root["solution"]?["projects"] ?? new JArray();
var includedProjectPaths = includedProjects.Select(t => ((string)t)?.Replace('\\', Path.DirectorySeparatorChar)).ToArray();

var fullSolutionDirectory = Path.GetDirectoryName(Path.Combine(basePath, solutionPath));
var fullSolutionFile = Parse(File.ReadAllText(Path.Combine(basePath, solutionPath)));

var formatVersion = fullSolutionFile.FormatVersion;
var visualStudioVersion = fullSolutionFile.VisualStudioVersion;
var globalSections = fullSolutionFile.GlobalSections;

var projects = ImmutableArray.CreateBuilder<ProjectBlock>();
foreach (var fullProject in fullSolutionFile.Projects)
{
var fullProjectPath = Path.GetFullPath(Path.Combine(fullSolutionDirectory, fullProject.RelativePath));
var includedPath = includedProjectPaths.FirstOrDefault(included => string.Equals(Path.GetFullPath(Path.Combine(fullSolutionDirectory, included)), fullProjectPath, StringComparison.OrdinalIgnoreCase));
if (includedPath is null)
continue;

string relativeProjectPath;
#if NETCOREAPP
relativeProjectPath = Path.GetRelativePath(basePath, fullProjectPath);
#else
var projectUri = new Uri(fullProjectPath, UriKind.Absolute);
var solutionFilterDirectoryUri = new Uri(Path.GetFullPath(basePath) + Path.DirectorySeparatorChar, UriKind.Absolute);
relativeProjectPath = solutionFilterDirectoryUri.MakeRelativeUri(projectUri).OriginalString.Replace('/', Path.DirectorySeparatorChar);
#endif
projects.Add(fullProject.WithRelativePath(relativeProjectPath));
}

return new SolutionFile(formatVersion, visualStudioVersion, projects.ToImmutable(), globalSections);
}

public static SolutionFile ParseFile(string path)
{
var text = File.ReadAllText(path);
return Parse(text);
if (string.Equals(".slnf", Path.GetExtension(path), StringComparison.OrdinalIgnoreCase))
return ParseSolutionFilter(basePath: Path.GetDirectoryName(path), text);
else
return Parse(text);
}

private static Version ParseHeaderAndVersion(Scanner scanner)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace ProjectAndSolution
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"solution": {
"path": "Solution\\ProjectAndSolutionFilter.sln",
"projects": [
"..\\Project\\ProjectAndSolutionFilter.csproj"
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectAndSolutionFilter", "..\Project\ProjectAndSolutionFilter.csproj", "{A4C2694D-AEB4-4CB1-8951-5290424EF883}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Debug|x64.ActiveCfg = Debug|x64
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Debug|x64.Build.0 = Debug|x64
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Debug|x86.ActiveCfg = Debug|x86
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Debug|x86.Build.0 = Debug|x86
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Release|Any CPU.Build.0 = Release|Any CPU
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Release|x64.ActiveCfg = Release|x64
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Release|x64.Build.0 = Release|x64
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Release|x86.ActiveCfg = Release|x86
{A4C2694D-AEB4-4CB1-8951-5290424EF883}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal
28 changes: 28 additions & 0 deletions tests/OmniSharp.MSBuild.Tests/WorkspaceInformationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ public async Task TestProjectAndSolution()
}
}

[Fact]
public async Task TestProjectAndSolutionFilter()
{
using (var testProject = await TestAssets.Instance.GetTestProjectAsync("ProjectAndSolutionFilter"))
using (var host = CreateMSBuildTestHost(testProject.Directory))
{
var workspaceInfo = await host.RequestMSBuildWorkspaceInfoAsync();

Assert.Equal("ProjectAndSolutionFilter.slnf", Path.GetFileName(workspaceInfo.SolutionPath));
Assert.NotNull(workspaceInfo.Projects);
var project = Assert.Single(workspaceInfo.Projects);

Assert.Equal("ProjectAndSolutionFilter", project.AssemblyName);
Assert.Equal("bin/Debug/netcoreapp2.1/", project.OutputPath.EnsureForwardSlashes());
Assert.Equal("obj/Debug/netcoreapp2.1/", project.IntermediateOutputPath.EnsureForwardSlashes());
var expectedTargetPath = $"{testProject.Directory}/Project/{project.OutputPath}ProjectAndSolutionFilter.dll".EnsureForwardSlashes();
Assert.Equal(expectedTargetPath, project.TargetPath.EnsureForwardSlashes());
Assert.Equal("Debug", project.Configuration);
Assert.Equal("AnyCPU", project.Platform);
Assert.True(project.IsExe);
Assert.False(project.IsUnityProject);

Assert.Equal(".NETCoreApp,Version=v2.1", project.TargetFramework);
var targetFramework = Assert.Single(project.TargetFrameworks);
Assert.Equal("netcoreapp2.1", targetFramework.ShortName);
}
}

[Fact]
public async Task ProjectAndSolutionWithProjectSection()
{
Expand Down