use vs persistence
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
using Microsoft.VisualStudio.SolutionPersistence.Model;
|
||||||
|
|
||||||
|
namespace SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
|
public class IntermediateSolutionModel
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required string FilePath { get; set; }
|
||||||
|
public required List<IntermediateProjectModel> Projects { get; set; }
|
||||||
|
public required List<IntermediateSlnFolderModel> SolutionFolders { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IntermediateSlnFolderModel
|
||||||
|
{
|
||||||
|
public required SolutionFolderModel Model { get; set; }
|
||||||
|
public required List<IntermediateSlnFolderModel> Folders { get; set; }
|
||||||
|
public required List<IntermediateProjectModel> Projects { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IntermediateProjectModel
|
||||||
|
{
|
||||||
|
public required SolutionProjectModel Model { get; set; }
|
||||||
|
public required string FullFilePath { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
|
public class SharpIdeSolutionModel
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required string FilePath { get; set; }
|
||||||
|
public required List<SharpIdeProjectModel> Projects { get; set; }
|
||||||
|
public required List<SharpIdeSolutionFolder> Folders { get; set; }
|
||||||
|
}
|
||||||
|
public class SharpIdeSolutionFolder
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required List<SharpIdeSolutionFolder> Folders { get; set; }
|
||||||
|
public required List<SharpIdeProjectModel> Projects { get; set; }
|
||||||
|
}
|
||||||
|
public class SharpIdeProjectModel
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required string FilePath { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
using Ardalis.GuardClauses;
|
||||||
|
using Microsoft.VisualStudio.SolutionPersistence.Model;
|
||||||
|
using Microsoft.VisualStudio.SolutionPersistence.Serializer;
|
||||||
|
|
||||||
|
namespace SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
|
public class VsPersistenceMapper
|
||||||
|
{
|
||||||
|
public static async Task<SharpIdeSolutionModel> GetSolutionModel(string solutionFilePath, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
// This intermediate model is pretty much useless, but I have left it around as we grab the project nodes with it, which we might use later.
|
||||||
|
var intermediateModel = await GetIntermediateModel(solutionFilePath, cancellationToken);
|
||||||
|
|
||||||
|
var solutionName = Path.GetFileName(solutionFilePath);
|
||||||
|
var solutionModel = new SharpIdeSolutionModel
|
||||||
|
{
|
||||||
|
Name = solutionName,
|
||||||
|
FilePath = solutionFilePath,
|
||||||
|
Projects = intermediateModel.Projects.Select(GetSharpIdeProjectModel).ToList(),
|
||||||
|
Folders = intermediateModel.SolutionFolders.Select(s => new SharpIdeSolutionFolder
|
||||||
|
{
|
||||||
|
Name = s.Model.Name,
|
||||||
|
Folders = s.Folders.Select(GetSharpIdeSolutionFolder).ToList(),
|
||||||
|
Projects = s.Projects.Select(GetSharpIdeProjectModel).ToList()
|
||||||
|
}).ToList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return solutionModel;
|
||||||
|
}
|
||||||
|
private static SharpIdeProjectModel GetSharpIdeProjectModel(IntermediateProjectModel projectModel) => new SharpIdeProjectModel()
|
||||||
|
{
|
||||||
|
Name = projectModel.Model.DisplayName!,
|
||||||
|
FilePath = projectModel.Model.FilePath,
|
||||||
|
};
|
||||||
|
|
||||||
|
private static SharpIdeSolutionFolder GetSharpIdeSolutionFolder(IntermediateSlnFolderModel folderModel) => new SharpIdeSolutionFolder()
|
||||||
|
{
|
||||||
|
Name = folderModel.Model.Name,
|
||||||
|
Folders = folderModel.Folders.Select(GetSharpIdeSolutionFolder).ToList(),
|
||||||
|
Projects = folderModel.Projects.Select(GetSharpIdeProjectModel).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
public static async Task<IntermediateSolutionModel> GetIntermediateModel(string solutionFilePath,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var serializer = SolutionSerializers.GetSerializerByMoniker(solutionFilePath);
|
||||||
|
Guard.Against.Null(serializer, nameof(serializer));
|
||||||
|
var vsSolution = await serializer.OpenAsync(solutionFilePath, cancellationToken);
|
||||||
|
|
||||||
|
var rootFolders = vsSolution.SolutionFolders
|
||||||
|
.Where(f => f.Parent is null)
|
||||||
|
.Select(f => BuildFolderTree(f, vsSolution.SolutionFolders, vsSolution.SolutionProjects))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var solutionModel = new IntermediateSolutionModel
|
||||||
|
{
|
||||||
|
Name = Path.GetFileName(solutionFilePath),
|
||||||
|
FilePath = solutionFilePath,
|
||||||
|
Projects = vsSolution.SolutionProjects.Where(p => p.Parent is null).Select(s => new IntermediateProjectModel
|
||||||
|
{
|
||||||
|
Model = s,
|
||||||
|
FullFilePath = Path.GetFullPath(s.FilePath)
|
||||||
|
}).ToList(),
|
||||||
|
SolutionFolders = rootFolders
|
||||||
|
};
|
||||||
|
return solutionModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntermediateSlnFolderModel BuildFolderTree(SolutionFolderModel folder,
|
||||||
|
IReadOnlyList<SolutionFolderModel> allSolutionFolders, IReadOnlyList<SolutionProjectModel> allSolutionProjects)
|
||||||
|
{
|
||||||
|
var childFolders = allSolutionFolders
|
||||||
|
.Where(f => f.Parent == folder)
|
||||||
|
.Select(f => BuildFolderTree(f, allSolutionFolders, allSolutionProjects))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var projectsInFolder = allSolutionProjects
|
||||||
|
.Where(p => p.Parent == folder)
|
||||||
|
.Select(s => new IntermediateProjectModel
|
||||||
|
{
|
||||||
|
Model = s,
|
||||||
|
FullFilePath = Path.GetFullPath(s.FilePath)
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new IntermediateSlnFolderModel
|
||||||
|
{
|
||||||
|
Model = folder,
|
||||||
|
Folders = childFolders,
|
||||||
|
Projects = projectsInFolder
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,12 +7,14 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Ardalis.GuardClauses" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.Build" Version="17.14.8" ExcludeAssets="runtime" />
|
<PackageReference Include="Microsoft.Build" Version="17.14.8" ExcludeAssets="runtime" />
|
||||||
<PackageReference Include="Microsoft.Build.Locator" Version="1.9.1" />
|
<PackageReference Include="Microsoft.Build.Locator" Version="1.9.1" />
|
||||||
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="17.14.8" ExcludeAssets="runtime" />
|
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="17.14.8" ExcludeAssets="runtime" />
|
||||||
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.14.8" ExcludeAssets="runtime" />
|
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.14.8" ExcludeAssets="runtime" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.14.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.14.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.14.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.14.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.SolutionPersistence" Version="1.0.52" />
|
||||||
<PackageReference Include="NuGet.Protocol" Version="6.14.0" />
|
<PackageReference Include="NuGet.Protocol" Version="6.14.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@using Ardalis.GuardClauses
|
@using Ardalis.GuardClauses
|
||||||
@using Microsoft.Build.Construction
|
@using Microsoft.Build.Construction
|
||||||
@using SharpIDE.Application.Features.SolutionDiscovery
|
@using SharpIDE.Application.Features.SolutionDiscovery
|
||||||
|
@using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence
|
||||||
|
|
||||||
@if (_solutionFile is null)
|
@if (_solutionFile is null)
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,9 @@
|
|||||||
[Parameter, EditorRequired]
|
[Parameter, EditorRequired]
|
||||||
public string SolutionFilePath { get; set; } = null!;
|
public string SolutionFilePath { get; set; } = null!;
|
||||||
|
|
||||||
|
[Parameter, EditorRequired]
|
||||||
|
public SharpIdeSolutionModel SolutionModel { get; set; } = null!;
|
||||||
|
|
||||||
private SolutionFile _solutionFile = null!;
|
private SolutionFile _solutionFile = null!;
|
||||||
private List<ProjectInSolution> _rootNodes = [];
|
private List<ProjectInSolution> _rootNodes = [];
|
||||||
private Dictionary<string, Folder?> _folders = new();
|
private Dictionary<string, Folder?> _folders = new();
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
@using SharpIDE.Application.Features.Build
|
@using SharpIDE.Application.Features.Build
|
||||||
|
@using SharpIDE.Application.Features.SolutionDiscovery
|
||||||
|
@using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence
|
||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
@inject IDialogService DialogService
|
@inject IDialogService DialogService
|
||||||
@@ -11,7 +13,7 @@
|
|||||||
<MudDrawer @bind-Open="@_drawerOpen" Width="400px" ClipMode="DrawerClipMode.Always">
|
<MudDrawer @bind-Open="@_drawerOpen" Width="400px" ClipMode="DrawerClipMode.Always">
|
||||||
@if (_solutionFilePath is not null)
|
@if (_solutionFilePath is not null)
|
||||||
{
|
{
|
||||||
<SolutionExplorer SolutionFilePath="@_solutionFilePath"/>
|
<SolutionExplorer SolutionModel="@_solutionModel" SolutionFilePath="@_solutionFilePath"/>
|
||||||
}
|
}
|
||||||
@* <NavMenu/> *@
|
@* <NavMenu/> *@
|
||||||
</MudDrawer>
|
</MudDrawer>
|
||||||
@@ -35,6 +37,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string? _solutionFilePath;
|
private string? _solutionFilePath;
|
||||||
|
private SharpIdeSolutionModel? _solutionModel;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
@@ -46,5 +49,7 @@
|
|||||||
_solutionFilePath = solutionFilePath;
|
_solutionFilePath = solutionFilePath;
|
||||||
|
|
||||||
await BuildService.BuildSolutionAsync(_solutionFilePath);
|
await BuildService.BuildSolutionAsync(_solutionFilePath);
|
||||||
|
var solutionModel = await RoslynTest.Analyse(_solutionFilePath);
|
||||||
|
_solutionModel = solutionModel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"DOTNET_ENVIRONMENT": "Development"
|
"DOTNET_ENVIRONMENT": "Development",
|
||||||
|
"MSBUILD_PARSE_SLN_WITH_SOLUTIONPERSISTENCE" : "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"(Watch)": {
|
"(Watch)": {
|
||||||
@@ -15,7 +16,8 @@
|
|||||||
"commandLineArgs": "watch run",
|
"commandLineArgs": "watch run",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"DOTNET_ENVIRONMENT": "Development",
|
"DOTNET_ENVIRONMENT": "Development",
|
||||||
"DOTNET_WATCH_RESTART_ON_RUDE_EDIT": "true"
|
"DOTNET_WATCH_RESTART_ON_RUDE_EDIT": "true",
|
||||||
|
"MSBUILD_PARSE_SLN_WITH_SOLUTIONPERSISTENCE" : "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user