Skip to content

Commit

Permalink
feat: support parsing and retrieving SolutionGuid (#26)
Browse files Browse the repository at this point in the history
* Support parsing and retrieving SolutionGuid
Closes #23

* Fixed coding style
Moved sln contents to external files
Simplified and refactored code
  • Loading branch information
icnocop authored Aug 25, 2023
1 parent 1f7285f commit 227b46f
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 26 deletions.
62 changes: 62 additions & 0 deletions src/SlnParser.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,53 @@ namespace SlnParser.Tests
{
public class IntegrationTests
{
[Fact]
public void Parse_WithEmptySolutionFile_IsParsedCorrectly()
{
var solutionFile = LoadSolution("Empty");

var sut = new SolutionParser();

var solution = sut.Parse(solutionFile);

solution
.FileFormatVersion
.Should()
.Be(string.Empty);

var visualStudioVersion = solution.VisualStudioVersion;

visualStudioVersion
.MinimumVersion
.Should()
.Be(string.Empty);

visualStudioVersion
.Version
.Should()
.Be(string.Empty);

solution
.Guid
.Should()
.Be(null);

solution
.ConfigurationPlatforms
.Should()
.HaveCount(0);

solution
.AllProjects
.Should()
.HaveCount(0);

solution
.Projects
.Should()
.HaveCount(0);
}

[Fact]
[Category("ParseSolution:SlnParser")]
public void Should_Be_Able_To_Parse_SlnParser_Solution_Correctly()
Expand Down Expand Up @@ -371,7 +418,22 @@ public void Parse_WithProjectWithoutPlatform_IsParsedCorrectly()
project.TypeGuid.Should().Be("D183A3D8-5FD8-494B-B014-37F57B35E655");
project.Type.Should().Be(ProjectType.Unknown);
}

[Fact]
public void Parse_WithSolutionGuid_IsParsedCorrectly()
{
var solutionFile = LoadSolution("SolutionGuid");

var sut = new SolutionParser();

var solution = sut.Parse(solutionFile);

solution
.Guid
.Should()
.Be("7F92F20E-4C3D-4316-BF60-105559EFEAFF");
}

private static FileInfo LoadSolution(string solutionName)
{
var solutionFileName = $"./Solutions/{solutionName}.sln";
Expand Down
1 change: 1 addition & 0 deletions src/SlnParser.Tests/Solutions/Empty.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

5 changes: 5 additions & 0 deletions src/SlnParser.Tests/Solutions/SolutionGuid.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F92F20E-4C3D-4316-BF60-105559EFEAFF}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ internal interface IParseSolutionConfigurationPlatform
{
IEnumerable<ProjectConfigurationPlatform> Parse(
IEnumerable<string> fileContents,
string startSection);
string sectionName);
}
}
11 changes: 11 additions & 0 deletions src/SlnParser/Contracts/Helper/ISectionParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace SlnParser.Contracts.Helper
{
internal interface ISectionParser
{
IEnumerable<string> GetFileContentsInGlobalSection(
IEnumerable<string> fileContents,
string sectionName);
}
}
8 changes: 7 additions & 1 deletion src/SlnParser/Contracts/ISolution.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;

namespace SlnParser.Contracts
Expand Down Expand Up @@ -42,5 +43,10 @@ public interface ISolution
/// The <see cref="ConfigurationPlatform" />s configured for this solution
/// </summary>
IReadOnlyCollection<ConfigurationPlatform> ConfigurationPlatforms { get; }

/// <summary>
/// The <see cref="Guid"/> of the solution.
/// </summary>
Guid? Guid { get; }
}
}
6 changes: 5 additions & 1 deletion src/SlnParser/Contracts/Solution.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;

namespace SlnParser.Contracts
Expand Down Expand Up @@ -36,5 +37,8 @@ public Solution()

/// <inheritdoc />
public IReadOnlyCollection<ConfigurationPlatform> ConfigurationPlatforms { get; internal set; }

/// <inheritdoc/>
public Guid? Guid { get; internal set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public void Enrich(Solution solution, IEnumerable<string> fileContents)
{
var projectConfigurations = _parseSolutionConfigurationPlatform.Parse(
fileContents,
"GlobalSection(ProjectConfiguration");
"ProjectConfiguration");
MapConfigurationPlatformsToProjects(solution, projectConfigurations);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void Enrich(Solution solution, IEnumerable<string> fileContents)
{
var projectConfigurations = _parseSolutionConfigurationPlatform.Parse(
fileContents,
"GlobalSection(SolutionConfiguration");
"SolutionConfiguration");
solution.ConfigurationPlatforms = projectConfigurations
.Select(projectConfiguration => projectConfiguration.ConfigurationPlatform)
.ToList()
Expand Down
38 changes: 38 additions & 0 deletions src/SlnParser/Helper/EnrichSolutionWithSolutionGuid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using SlnParser.Contracts;
using SlnParser.Contracts.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace SlnParser.Helper
{
internal sealed class EnrichSolutionWithSolutionGuid : IEnrichSolution
{
private readonly ISectionParser _sectionParser = new SectionParser();

public void Enrich(Solution solution, IEnumerable<string> fileContents)
{
var extensibilityGlobals = _sectionParser.GetFileContentsInGlobalSection(
fileContents,
"ExtensibilityGlobals");

solution.Guid = extensibilityGlobals
.Select(ExtractSolutionGuid)
.FirstOrDefault(x => x.HasValue);
}

private Guid? ExtractSolutionGuid(string line)
{
const string pattern = @"\s*SolutionGuid\s*=\s*{([A-Fa-f0-9\-]+)}";
var match = Regex.Match(line, pattern);
if (!match.Success)
{
return null;
}

var guidString = match.Groups[1].Value;
return new Guid(guidString);
}
}
}
34 changes: 34 additions & 0 deletions src/SlnParser/Helper/SectionParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using SlnParser.Contracts.Helper;
using System.Collections.Generic;
using System.Linq;

namespace SlnParser.Helper
{
internal class SectionParser : ISectionParser
{
public IEnumerable<string> GetFileContentsInGlobalSection(
IEnumerable<string> fileContents,
string sectionName)
{
var startSection = $"GlobalSection({sectionName}";
const string endSection = "EndGlobalSection";

return GetFileContentsInSection(fileContents, startSection, endSection);
}

private static IEnumerable<string> GetFileContentsInSection(
IEnumerable<string> fileContents,
string startSection,
string endSection)
{
var section = fileContents
.SkipWhile(line => !line.StartsWith(startSection))
.TakeWhile(line => !line.StartsWith(endSection))
.Where(line => !line.StartsWith(startSection))
.Where(line => !line.StartsWith(endSection))
.Where(line => !string.IsNullOrWhiteSpace(line));

return section.ToList();
}
}
}
26 changes: 6 additions & 20 deletions src/SlnParser/Helper/SolutionConfigurationPlatformParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,21 @@ namespace SlnParser.Helper
{
internal sealed class SolutionConfigurationPlatformParser : IParseSolutionConfigurationPlatform
{
private readonly ISectionParser _sectionParser = new SectionParser();

public IEnumerable<ProjectConfigurationPlatform> Parse(
IEnumerable<string> fileContents,
string startSection)
string sectionName)
{
if (fileContents == null) throw new ArgumentNullException(nameof(fileContents));
if (string.IsNullOrWhiteSpace(startSection))
throw new ArgumentException("Value cannot be null or whitespace.", nameof(startSection));
if (string.IsNullOrWhiteSpace(sectionName))
throw new ArgumentException("Value cannot be null or whitespace.", nameof(sectionName));

var sectionContents = GetFileContentsInSection(fileContents, startSection);
var sectionContents = _sectionParser.GetFileContentsInGlobalSection(fileContents, sectionName);
var projectConfigurationPlatforms = ParseConfigurationPlatforms(sectionContents);
return projectConfigurationPlatforms;
}

private static IEnumerable<string> GetFileContentsInSection(
IEnumerable<string> fileContents,
string startSection)
{
const string endSection = "EndGlobalSection";

var section = fileContents
.SkipWhile(line => !line.StartsWith(startSection))
.TakeWhile(line => !line.StartsWith(endSection))
.Where(line => !line.StartsWith(startSection))
.Where(line => !line.StartsWith(endSection))
.Where(line => !string.IsNullOrWhiteSpace(line));

return section.ToList();
}

private static IEnumerable<ProjectConfigurationPlatform> ParseConfigurationPlatforms(
IEnumerable<string> sectionFileContents)
{
Expand Down
3 changes: 2 additions & 1 deletion src/SlnParser/SolutionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ public SolutionParser()
* because we need the parsed projects before we can map the configurations to them
*/
new EnrichSolutionWithProjectConfigurationPlatforms(),
new EnrichSolutionWithSolutionFolderFiles()
new EnrichSolutionWithSolutionFolderFiles(),
new EnrichSolutionWithSolutionGuid(),
};
}

Expand Down

0 comments on commit 227b46f

Please sign in to comment.