Skip to content

Commit 3940a3f

Browse files
committed
revert "Revert ".slnx support - use the new parser for .sln and .slnx (dotnet#10836)""
1 parent d047377 commit 3940a3f

File tree

9 files changed

+907
-1237
lines changed

9 files changed

+907
-1237
lines changed

documentation/wiki/ChangeWaves.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ A wave of features is set to "rotate out" (i.e. become standard functionality) t
2525
## Current Rotation of Change Waves
2626

2727
### 17.14
28-
- ~[.SLNX support - use the new parser for .sln and .slnx](https://github.com/dotnet/msbuild/pull/10836)~ reverted after compat problems discovered
28+
- [.SLNX support - use the new parser for .sln and .slnx](https://github.com/dotnet/msbuild/pull/10836)
2929
- [Support custom culture in RAR](https://github.com/dotnet/msbuild/pull/11000)
3030
- [VS Telemetry](https://github.com/dotnet/msbuild/pull/11255)
3131

eng/BootStrapMsBuild.targets

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
<_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('Newtonsoft.Json'))' == 'true'" />
3636
<_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('NuGetSdkResolver'))' == 'true'" />
3737
<_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('Microsoft.Extensions.'))' == 'true'" />
38-
38+
<_NuGetRuntimeDependencies Include="%(RuntimeCopyLocalItems.Identity)" Condition="'@(RuntimeCopyLocalItems->Contains('Microsoft.VisualStudio.SolutionPersistence'))' == 'true'" />
39+
3940
<!-- NuGet.targets and NuGet.RestoreEx.targets will be in the RuntimeTargetsCopyLocalItems ItemGroup -->
4041
<_NuGetRuntimeDependencies Include="%(RuntimeTargetsCopyLocalItems.Identity)" Condition="'@(RuntimeTargetsCopyLocalItems->Contains('NuGet.'))' == 'true'" />
4142

@@ -48,7 +49,7 @@
4849

4950
<Target Name="RemoveExtraAssemblyReferences" BeforeTargets="ResolveAssemblyReferences">
5051
<!-- This is really hacky, but these references will cause issues when trying to 'build' this project.
51-
To acquire the NuGet binaries we depend on for local run-time ('bootstrap'), we we are using a PackageReference (to
52+
To acquire the NuGet binaries we depend on for local run-time ('bootstrap'), we are using a PackageReference (to
5253
'NuGet.Build.Tasks' and 'Microsoft.Build.NuGetSdkResolver'). This has the advantage of using NuGets compatibility
5354
check to ensure we choose the right version of those assemblies. But, at 'bootstrap' time these runtime dependencies
5455
need to be in a specific location that does not mesh with NuGet. To resolve this, we include the default

src/Build.OM.UnitTests/Construction/SolutionFile_Tests.cs

+75-619
Large diffs are not rendered by default.

src/Build.UnitTests/Construction/SolutionFile_Tests.cs src/Build.UnitTests/Construction/SolutionFile_OldParser_Tests.cs

+129-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Collections;
66
using System.Collections.Generic;
77
using System.IO;
8+
using System.Text;
89
using Microsoft.Build.Construction;
910
using Microsoft.Build.Exceptions;
1011
using Microsoft.Build.Shared;
@@ -16,11 +17,11 @@
1617

1718
namespace Microsoft.Build.UnitTests.Construction
1819
{
19-
public class SolutionFile_Tests
20+
public class SolutionFile_OldParser_Tests
2021
{
2122
public ITestOutputHelper TestOutputHelper { get; }
2223

23-
public SolutionFile_Tests(ITestOutputHelper testOutputHelper)
24+
public SolutionFile_OldParser_Tests(ITestOutputHelper testOutputHelper)
2425
{
2526
TestOutputHelper = testOutputHelper;
2627
}
@@ -104,6 +105,42 @@ public void ParseFirstProjectLineWithDifferentSpacing()
104105
proj.ProjectGuid.ShouldBe("Unique name-GUID");
105106
}
106107

108+
/// <summary>
109+
/// A slightly more complicated test where there is some different whitespace.
110+
/// </summary>
111+
[Fact]
112+
public void ParseSolutionWithDifferentSpacing()
113+
{
114+
string solutionFileContents =
115+
@"
116+
Microsoft Visual Studio Solution File, Format Version 9.00
117+
# Visual Studio 2005
118+
Project(' { Project GUID} ') = ' Project name ', ' Relative path to project file ' , ' {0ABED153-9451-483C-8140-9E8D7306B216} '
119+
EndProject
120+
Global
121+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
122+
Debug|AnyCPU = Debug|AnyCPU
123+
Release|AnyCPU = Release|AnyCPU
124+
EndGlobalSection
125+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
126+
{0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
127+
{0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
128+
{0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
129+
{0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
130+
EndGlobalSection
131+
GlobalSection(SolutionProperties) = preSolution
132+
HideSolutionNode = FALSE
133+
EndGlobalSection
134+
EndGlobal
135+
";
136+
137+
SolutionFile solution = ParseSolutionHelper(solutionFileContents);
138+
139+
Assert.Equal("Project name", solution.ProjectsInOrder[0].ProjectName);
140+
Assert.Equal("Relative path to project file", solution.ProjectsInOrder[0].RelativePath);
141+
Assert.Equal("{0ABED153-9451-483C-8140-9E8D7306B216}", solution.ProjectsInOrder[0].ProjectGuid);
142+
}
143+
107144
/// <summary>
108145
/// First project line with an empty project name. This is somewhat malformed, but we should
109146
/// still behave reasonably instead of crashing.
@@ -687,6 +724,43 @@ public void ParseFirstProjectLineWhereProjectNameHasSpecialCharacters()
687724
proj.ProjectGuid.ShouldBe("Unique name-GUID");
688725
}
689726

727+
/// <summary>
728+
/// Test some characters that are valid in a file name but that also could be
729+
/// considered a delimiter by a parser. Does quoting work for special characters?
730+
/// </summary>
731+
[Fact]
732+
public void ParseSolutionWhereProjectNameHasSpecialCharacters()
733+
{
734+
string solutionFileContents =
735+
@"
736+
Microsoft Visual Studio Solution File, Format Version 9.00
737+
# Visual Studio 2005
738+
Project('{Project GUID}') = 'MyProject,(=IsGreat)', 'Relative path to project file' , '{0ABED153-9451-483C-8140-9E8D7306B216}'
739+
EndProject
740+
Global
741+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
742+
Debug|AnyCPU = Debug|AnyCPU
743+
Release|AnyCPU = Release|AnyCPU
744+
EndGlobalSection
745+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
746+
{0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
747+
{0ABED153-9451-483C-8140-9E8D7306B216}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
748+
{0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
749+
{0ABED153-9451-483C-8140-9E8D7306B216}.Release|AnyCPU.Build.0 = Release|AnyCPU
750+
EndGlobalSection
751+
GlobalSection(SolutionProperties) = preSolution
752+
HideSolutionNode = FALSE
753+
EndGlobalSection
754+
EndGlobal
755+
";
756+
757+
SolutionFile solution = ParseSolutionHelper(solutionFileContents);
758+
759+
Assert.Equal("MyProject,(=IsGreat)", solution.ProjectsInOrder[0].ProjectName);
760+
Assert.Equal("Relative path to project file", solution.ProjectsInOrder[0].RelativePath);
761+
Assert.Equal("{0ABED153-9451-483C-8140-9E8D7306B216}", solution.ProjectsInOrder[0].ProjectGuid);
762+
}
763+
690764
/// <summary>
691765
/// Test some characters that are valid in a file name but that also could be
692766
/// considered a delimiter by a parser. Does quoting work for special characters?
@@ -2355,5 +2429,58 @@ public void ParseSolutionWithParentedPaths()
23552429
solution.ProjectsInOrder[0].AbsolutePath.ShouldBe(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(solution.FullPath)!, expectedRelativePath)));
23562430
solution.ProjectsInOrder[0].ProjectGuid.ShouldBe("{0ABED153-9451-483C-8140-9E8D7306B216}");
23572431
}
2432+
2433+
/// <summary>
2434+
/// Parse solution file with comments
2435+
/// </summary>
2436+
[Fact]
2437+
public void ParseSolutionWithComments()
2438+
{
2439+
const string solutionFileContent = @"
2440+
Microsoft Visual Studio Solution File, Format Version 12.00
2441+
# Visual Studio Version 16
2442+
VisualStudioVersion = 16.0.29123.89
2443+
MinimumVisualStudioVersion = 10.0.40219.1
2444+
Project('{9A19103F-16F7-4668-BE54-9A1E7A4F7556}') = 'SlnCommentTest', 'SlnCommentTest.csproj', '{00000000-0000-0000-FFFF-FFFFFFFFFFFF}'
2445+
EndProject
2446+
Project('{2150E333-8FDC-42A3-9474-1A3956D46DE8}') = 'Solution Items', 'Solution Items', '{054DED3B-B890-4652-B449-839F581E5D86}'
2447+
ProjectSection(SolutionItems) = preProject
2448+
SlnFile.txt = SlnFile.txt
2449+
EndProjectSection
2450+
EndProject
2451+
Global
2452+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2453+
Debug|Any CPU = Debug|Any CPU
2454+
Release|Any CPU = Release|Any CPU
2455+
EndGlobalSection
2456+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
2457+
{00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2458+
{00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
2459+
{00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
2460+
{00000000-0000-0000-FFFF-FFFFFFFFFFFF}.Release|Any CPU.Build.0 = Release|Any CPU
2461+
EndGlobalSection
2462+
GlobalSection(SolutionProperties) = preSolution
2463+
HideSolutionNode = FALSE
2464+
EndGlobalSection
2465+
GlobalSection(ExtensibilityGlobals) = postSolution
2466+
SolutionGuid = {FFFFFFFF-FFFF-FFFF-0000-000000000000}
2467+
EndGlobalSection
2468+
EndGlobal
2469+
";
2470+
2471+
StringBuilder stringBuilder = new StringBuilder();
2472+
2473+
// Put comment between all lines
2474+
const string comment = "\t# comment";
2475+
string[] lines = solutionFileContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
2476+
for (int i = 0; i < lines.Length; i++)
2477+
{
2478+
stringBuilder.AppendLine(comment);
2479+
stringBuilder.AppendLine(lines[i]);
2480+
}
2481+
stringBuilder.AppendLine(comment);
2482+
2483+
Should.NotThrow(() => ParseSolutionHelper(stringBuilder.ToString()));
2484+
}
23582485
}
23592486
}

src/Build.UnitTests/Construction/SolutionFilter_Tests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ public void SolutionFilterFiltersProjects(bool graphBuild)
7272
");
7373
// Slashes here (and in the .slnf) are hardcoded as backslashes intentionally to support the common case.
7474
TransientTestFile solutionFile = testEnvironment.CreateFile(simpleProjectFolder, "SimpleProject.sln",
75-
@"
75+
"""
7676
Microsoft Visual Studio Solution File, Format Version 12.00
7777
# Visual Studio Version 16
7878
VisualStudioVersion = 16.0.29326.124
7979
MinimumVisualStudioVersion = 10.0.40219.1
80-
Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""SimpleProject"", ""SimpleProject\SimpleProject.csproj"", ""{79B5EBA6-5D27-4976-BC31-14422245A59A}""
80+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleProject", "SimpleProject\SimpleProject.csproj", "{79B5EBA6-5D27-4976-BC31-14422245A59A}"
8181
EndProject
82-
Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""ClassLibrary"", ""..\ClassLibrary\ClassLibrary\ClassLibrary.csproj"", ""{8EFCCA22-9D51-4268-90F7-A595E11FCB2D}""
82+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClassLibrary", "..\ClassLibrary\ClassLibrary\ClassLibrary.csproj", "{8EFCCA22-9D51-4268-90F7-A595E11FCB2D}"
8383
EndProject
8484
Global
8585
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -107,7 +107,7 @@ public void SolutionFilterFiltersProjects(bool graphBuild)
107107
SolutionGuid = {DE7234EC-0C4D-4070-B66A-DCF1B4F0CFEF}
108108
EndGlobalSection
109109
EndGlobal
110-
");
110+
""");
111111
TransientTestFile filterFile = testEnvironment.CreateFile(folder, "solutionFilter.slnf",
112112
/*lang=json*/
113113
"""

0 commit comments

Comments
 (0)