Skip to content

Commit bd5b082

Browse files
authored
sln-list: Support for slnx (#44537)
1 parent ffd7663 commit bd5b082

18 files changed

+188
-23
lines changed

src/Cli/dotnet/commands/dotnet-sln/LocalizableStrings.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,4 +183,10 @@
183183
<data name="SlnxGenerated" xml:space="preserve">
184184
<value>.slnx file {0} generated.</value>
185185
</data>
186+
<data name="CannotMigrateSlnx" xml:space="preserve">
187+
<value>Only .sln files can be migrated to .slnx format.</value>
188+
</data>
189+
<data name="SerializerNotFound" xml:space="preserve">
190+
<value>Could not read solution file {0}. Supported files are .sln and .slnx valid solutions.</value>
191+
</data>
186192
</root>

src/Cli/dotnet/commands/dotnet-sln/SlnCommandParser.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using System.CommandLine;
55
using Microsoft.DotNet.Cli.Utils;
66
using Microsoft.DotNet.Tools;
7+
using Microsoft.VisualStudio.SolutionPersistence;
8+
using Microsoft.VisualStudio.SolutionPersistence.Serializer;
79
using NuGet.Packaging;
810
using LocalizableStrings = Microsoft.DotNet.Tools.Sln.LocalizableStrings;
911

@@ -50,11 +52,13 @@ internal static string GetSlnFileFullPath(string slnFileOrDirectory)
5052
{
5153
if (File.Exists(slnFileOrDirectory))
5254
{
53-
return slnFileOrDirectory;
55+
return Path.GetFullPath(slnFileOrDirectory);
5456
}
5557
if (Directory.Exists(slnFileOrDirectory))
5658
{
57-
var files = Directory.GetFiles(slnFileOrDirectory, "*.sln", SearchOption.TopDirectoryOnly);
59+
string[] files = [
60+
..Directory.GetFiles(slnFileOrDirectory, "*.sln", SearchOption.TopDirectoryOnly),
61+
..Directory.GetFiles(slnFileOrDirectory, "*.slnx", SearchOption.TopDirectoryOnly)];
5862
if (files.Length == 0)
5963
{
6064
throw new GracefulException(CommonLocalizableStrings.CouldNotFindSolutionIn, slnFileOrDirectory);
@@ -63,9 +67,19 @@ internal static string GetSlnFileFullPath(string slnFileOrDirectory)
6367
{
6468
throw new GracefulException(CommonLocalizableStrings.MoreThanOneSolutionInDirectory, slnFileOrDirectory);
6569
}
66-
return files.Single().ToString();
70+
return Path.GetFullPath(files.Single());
6771
}
6872
throw new GracefulException(CommonLocalizableStrings.CouldNotFindSolutionOrDirectory, slnFileOrDirectory);
6973
}
74+
75+
internal static ISolutionSerializer GetSolutionSerializer(string solutionFilePath)
76+
{
77+
ISolutionSerializer? serializer = SolutionSerializers.GetSerializerByMoniker(solutionFilePath);
78+
if (serializer is null)
79+
{
80+
throw new GracefulException(LocalizableStrings.SerializerNotFound, solutionFilePath);
81+
}
82+
return serializer;
83+
}
7084
}
7185
}

src/Cli/dotnet/commands/dotnet-sln/list/Program.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
using Microsoft.DotNet.Cli;
66
using Microsoft.DotNet.Cli.Sln.Internal;
77
using Microsoft.DotNet.Cli.Utils;
8-
using Microsoft.DotNet.Tools.Common;
8+
using Microsoft.VisualStudio.SolutionPersistence;
9+
using Microsoft.VisualStudio.SolutionPersistence.Model;
10+
using CommandLocalizableStrings = Microsoft.DotNet.Tools.CommonLocalizableStrings;
911

1012
namespace Microsoft.DotNet.Tools.Sln.List
1113
{
@@ -23,25 +25,36 @@ public ListProjectsInSolutionCommand(
2325

2426
public override int Execute()
2527
{
26-
var slnFile = SlnFileFactory.CreateFromFileOrDirectory(_fileOrDirectory);
28+
string solutionFileFullPath = SlnCommandParser.GetSlnFileFullPath(_fileOrDirectory);
29+
try
30+
{
31+
ListAllProjectsAsync(solutionFileFullPath, CancellationToken.None).Wait();
32+
return 0;
33+
}
34+
catch (Exception ex)
35+
{
36+
throw new GracefulException(CommandLocalizableStrings.InvalidSolutionFormatString, solutionFileFullPath, ex.Message);
37+
}
38+
}
2739

40+
private async Task ListAllProjectsAsync(string solutionFileFullPath, CancellationToken cancellationToken)
41+
{
42+
ISolutionSerializer serializer = SlnCommandParser.GetSolutionSerializer(solutionFileFullPath);
43+
SolutionModel solution = await serializer.OpenAsync(solutionFileFullPath, cancellationToken);
2844
string[] paths;
29-
3045
if (_displaySolutionFolders)
3146
{
32-
paths = slnFile.Projects
33-
.GetProjectsByType(ProjectTypeGuids.SolutionFolderGuid)
34-
.Select(folder => folder.GetFullSolutionFolderPath())
47+
paths = solution.SolutionFolders
48+
// VS-SolutionPersistence does not return a path object, so there might be issues with forward/backward slashes on different platforms
49+
.Select(folder => Path.GetDirectoryName(folder.Path.TrimStart("/")))
3550
.ToArray();
3651
}
3752
else
3853
{
39-
paths = slnFile.Projects
40-
.GetProjectsNotOfType(ProjectTypeGuids.SolutionFolderGuid)
54+
paths = solution.SolutionProjects
4155
.Select(project => project.FilePath)
4256
.ToArray();
4357
}
44-
4558
if (paths.Length == 0)
4659
{
4760
Reporter.Output.WriteLine(CommonLocalizableStrings.NoProjectsFound);
@@ -51,14 +64,14 @@ public override int Execute()
5164
Array.Sort(paths);
5265

5366
string header = _displaySolutionFolders ? LocalizableStrings.SolutionFolderHeader : LocalizableStrings.ProjectsHeader;
54-
Reporter.Output.WriteLine($"{header}");
67+
Reporter.Output.WriteLine(header);
5568
Reporter.Output.WriteLine(new string('-', header.Length));
5669
foreach (string slnProject in paths)
5770
{
5871
Reporter.Output.WriteLine(slnProject);
5972
}
6073
}
61-
return 0;
74+
6275
}
6376
}
6477
}

src/Cli/dotnet/commands/dotnet-sln/migrate/SlnMigrateCommand.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.VisualStudio.SolutionPersistence.Model;
1515
using Microsoft.VisualStudio.SolutionPersistence.Serializer;
1616
using LocalizableStrings = Microsoft.DotNet.Tools.Sln.LocalizableStrings;
17+
using Microsoft.DotNet.Tools.Common;
1718

1819
namespace Microsoft.DotNet.Cli
1920
{
@@ -26,13 +27,17 @@ public SlnMigrateCommand(
2627
IReporter reporter = null)
2728
: base(parseResult)
2829
{
29-
_slnFileOrDirectory = Path.GetFullPath(parseResult.GetValue(SlnCommandParser.SlnArgument));
30+
_slnFileOrDirectory = parseResult.GetValue(SlnCommandParser.SlnArgument);
3031
_reporter = reporter ?? Reporter.Output;
3132
}
3233

3334
public override int Execute()
3435
{
3536
string slnFileFullPath = SlnCommandParser.GetSlnFileFullPath(_slnFileOrDirectory);
37+
if (slnFileFullPath.HasExtension(".slnx"))
38+
{
39+
throw new GracefulException(LocalizableStrings.CannotMigrateSlnx);
40+
}
3641
string slnxFileFullPath = Path.ChangeExtension(slnFileFullPath, "slnx");
3742
try
3843
{
@@ -45,12 +50,7 @@ public override int Execute()
4550

4651
private async Task ConvertToSlnxAsync(string filePath, string slnxFilePath, CancellationToken cancellationToken)
4752
{
48-
// See if the file is a known solution file.
49-
ISolutionSerializer? serializer = SolutionSerializers.GetSerializerByMoniker(filePath);
50-
if (serializer is null)
51-
{
52-
throw new GracefulException("Could not find serializer for file {0}", filePath);
53-
}
53+
ISolutionSerializer serializer = SlnCommandParser.GetSolutionSerializer(filePath);
5454
SolutionModel solution = await serializer.OpenAsync(filePath, cancellationToken);
5555
await SolutionSerializers.SlnXml.SaveAsync(slnxFilePath, solution, cancellationToken);
5656
_reporter.WriteLine(LocalizableStrings.SlnxGenerated, slnxFilePath);

src/Cli/dotnet/commands/dotnet-sln/xlf/LocalizableStrings.cs.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/commands/dotnet-sln/xlf/LocalizableStrings.de.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/commands/dotnet-sln/xlf/LocalizableStrings.es.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/commands/dotnet-sln/xlf/LocalizableStrings.fr.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/commands/dotnet-sln/xlf/LocalizableStrings.it.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Cli/dotnet/commands/dotnet-sln/xlf/LocalizableStrings.ja.xlf

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)