Skip to content

Commit

Permalink
Add support for nested paths in SlnGenSolutionFolder (#467)
Browse files Browse the repository at this point in the history
  • Loading branch information
insouciiance authored Mar 9, 2023
1 parent 9ad5d3e commit b5bdeb8
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 20 deletions.
34 changes: 34 additions & 0 deletions src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnHierarchyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,40 @@ public void HierarchyWithCollapsedFoldersIsCorrectlyFormed()
StringCompareShould.IgnoreLineEndings);
}

[Fact]
public void SlnGenSolutionFolderNestedHierarchy()
{
SlnProject[] projects =
{
new SlnProject
{
FullPath = "baz.csproj",
Name = "baz",
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = SlnProject.DefaultLegacyProjectTypeGuid,
SolutionFolder = Path.Combine("zoo", "foo", "bar", "baz"),
},
new SlnProject
{
FullPath = "baz1.csproj",
Name = "baz1",
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = SlnProject.DefaultLegacyProjectTypeGuid,
SolutionFolder = Path.Combine("zoo", "foo", "bar", "baz1"),
},
};

SlnHierarchy hierarchy = SlnHierarchy.CreateFromProjectSolutionFolder(projects);

GetFolderStructureAsString(hierarchy.Folders).ShouldBe(
$@"zoo - zoo
zoo{Path.DirectorySeparatorChar}foo - foo
zoo{Path.DirectorySeparatorChar}foo{Path.DirectorySeparatorChar}bar - bar
zoo{Path.DirectorySeparatorChar}foo{Path.DirectorySeparatorChar}bar{Path.DirectorySeparatorChar}baz - baz
zoo{Path.DirectorySeparatorChar}foo{Path.DirectorySeparatorChar}bar{Path.DirectorySeparatorChar}baz1 - baz1",
StringCompareShould.IgnoreLineEndings);
}

private static string GetFolderStructureAsString(IEnumerable<SlnFolder> folders)
{
return string.Join(
Expand Down
14 changes: 3 additions & 11 deletions src/Microsoft.VisualStudio.SlnGen/SlnFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,15 +209,6 @@ public static (string solutionFileFullPath, int customProjectTypeGuidCount, int

solution.AddSolutionItems(solutionItems);

if (!arguments.EnableFolders())
{
foreach (SlnProject project in solution._projects.Distinct(new EqualityComparer<SlnProject>((x, y) => string.Equals(x.SolutionFolder, y.SolutionFolder)))
.Where(i => !string.IsNullOrWhiteSpace(i.SolutionFolder) && i.SolutionFolder.Contains(Path.DirectorySeparatorChar)))
{
logger.LogError($"The value of SlnGenSolutionFolder \"{project.SolutionFolder}\" cannot contain directory separators.");
}
}

if (!logger.HasLoggedErrors)
{
solution.Save(solutionFileFullPath, arguments.EnableFolders(), arguments.EnableCollapseFolders(), arguments.EnableAlwaysBuild());
Expand Down Expand Up @@ -439,7 +430,7 @@ internal void Save(string rootPath, TextWriter writer, bool useFolders, bool col
{
foreach (SlnFolder folder in hierarchy.Folders)
{
string projectSolutionPath = (useFolders ? folder.FullPath.ToRelativePath(rootPath) : folder.Name).ToSolutionPath();
string projectSolutionPath = (useFolders ? folder.FullPath.ToRelativePath(rootPath) : folder.FullPath).ToSolutionPath();

// Try to preserve the folder GUID if a matching relative folder path was parsed from an existing solution
if (ExistingProjectGuids != null && ExistingProjectGuids.TryGetValue(projectSolutionPath, out Guid projectGuid))
Expand Down Expand Up @@ -531,7 +522,8 @@ internal void Save(string rootPath, TextWriter writer, bool useFolders, bool col
writer.WriteLine($@" {project.ProjectGuid.ToSolutionString()} = {folder.FolderGuid.ToSolutionString()}");
}

if (useFolders)
// guard against synthetic root name
if (folder.Parent.Name != string.Empty)
{
writer.WriteLine($@" {folder.FolderGuid.ToSolutionString()} = {folder.Parent.FolderGuid.ToSolutionString()}");
}
Expand Down
40 changes: 31 additions & 9 deletions src/Microsoft.VisualStudio.SlnGen/SlnHierarchy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,41 @@ public static SlnHierarchy CreateFromProjectSolutionFolder(IReadOnlyList<SlnProj

foreach (SlnProject project in projects.Where(i => !string.IsNullOrWhiteSpace(i.SolutionFolder)))
{
if (!hierarchy._pathToSlnFolderMap.TryGetValue(project.SolutionFolder, out SlnFolder folder))
string[] nestedFolders = project.SolutionFolder.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);

for (int i = 0; i < nestedFolders.Length; i++)
{
folder = new SlnFolder(project.SolutionFolder)
{
Parent = hierarchy._rootFolder,
};
string folderPath = string.Join(Path.DirectorySeparatorChar.ToString(), nestedFolders, 0, i + 1);

hierarchy._pathToSlnFolderMap.Add(project.SolutionFolder, folder);
if (!hierarchy._pathToSlnFolderMap.TryGetValue(folderPath, out SlnFolder nested))
{
SlnFolder parent;

if (i == 0)
{
parent = hierarchy._rootFolder;
}
else
{
string parentString = Path.GetDirectoryName(folderPath);
parent = hierarchy._pathToSlnFolderMap[parentString];
}

nested = new SlnFolder(folderPath)
{
Parent = parent,
};

hierarchy._pathToSlnFolderMap.Add(folderPath, nested);

parent.Folders.Add(nested);
}

hierarchy._rootFolder.Folders.Add(folder);
if (i == nestedFolders.Length - 1)
{
nested.Projects.Add(project);
}
}

folder.Projects.Add(project);
}

return hierarchy;
Expand Down

0 comments on commit b5bdeb8

Please sign in to comment.