Skip to content

Commit

Permalink
Added an option to build only solution configurations that exist (#333)
Browse files Browse the repository at this point in the history
  • Loading branch information
odhanson authored Feb 23, 2022
1 parent c5ab6b0 commit f7a0759
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Arguments:
project path An optional path to a project which can include wildcards like **\*.csproj or directories which contain projects files. If not specified, all projects in the current directory will be used.
Options:
-ab|--alwaysbuild <true> Always include the project in the build even if it has no matching configuration. Default: true
-bl|--binarylogger[:<parameters>] Serializes all build events to a compressed binary file.
By default the file is in the current directory and named "slngen.binlog" and contains the source text of project files, including all imported projects and target files encountered during the build. The optional ProjectImports switch controls this behavior:
Expand Down
83 changes: 83 additions & 0 deletions src/Microsoft.VisualStudio.SlnGen.UnitTests/SlnFileTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,89 @@ public void CustomConfigurationAndPlatforms()
ValidateSolutionPlatformAndConfiguration(projectE, solutionFile, "Release", "AnyCPU", expectedIncludeInBuild: true);
}

[Fact]
public void CustomConfigurationAndPlatformsWithAlwaysBuildDisabled()
{
SlnProject projectA = new SlnProject
{
Configurations = new[] { "Debug", "Release" },
FullPath = GetTempFileName(),
IsMainProject = true,
Name = "ProjectA",
Platforms = new[] { "AnyCPU", "x64", "x86" },
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = Guid.NewGuid(),
};

SlnProject projectB = new SlnProject
{
Configurations = new[] { "Debug", "Release" },
FullPath = GetTempFileName(),
IsMainProject = true,
Name = "ProjectB",
Platforms = new[] { "x64", "x86" },
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = Guid.NewGuid(),
};

SlnProject projectC = new SlnProject
{
Configurations = new[] { "Debug", "Release" },
FullPath = GetTempFileName(),
IsMainProject = true,
Name = "ProjectC",
Platforms = new[] { "amd64" },
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = Guid.NewGuid(),
};

SlnProject projectD = new SlnProject
{
Configurations = new[] { "Debug", "Release" },
FullPath = GetTempFileName(),
IsMainProject = true,
Name = "ProjectD",
Platforms = new[] { "Razzle" },
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = Guid.NewGuid(),
};

SlnProject projectE = new SlnProject
{
Configurations = new[] { "Release" },
FullPath = GetTempFileName(),
IsMainProject = true,
Name = "ProjectE",
Platforms = new[] { "AnyCPU" },
ProjectGuid = Guid.NewGuid(),
ProjectTypeGuid = Guid.NewGuid(),
};

SlnFile slnFile = new SlnFile()
{
Configurations = new[] { "Debug" },
Platforms = new[] { "Any CPU" },
};

slnFile.AddProjects(new[] { projectA, projectB, projectC, projectD, projectE });

string solutionFilePath = GetTempFileName();

slnFile.Save(solutionFilePath, useFolders: false, alwaysBuild: false);

SolutionFile solutionFile = SolutionFile.Parse(solutionFilePath);

ValidateSolutionPlatformAndConfiguration(projectA, solutionFile, "Debug", "AnyCPU");

ValidateSolutionPlatformAndConfiguration(projectB, solutionFile, "Debug", "x64");

ValidateSolutionPlatformAndConfiguration(projectC, solutionFile, "Debug", "amd64");

ValidateSolutionPlatformAndConfiguration(projectD, solutionFile, "Debug", "Razzle", expectedIncludeInBuild: false);

ValidateSolutionPlatformAndConfiguration(projectE, solutionFile, "Release", "AnyCPU", expectedIncludeInBuild: false);
}

[Fact]
public void CustomConfigurationAndPlatforms_IgnoresInvalidValues()
{
Expand Down
1 change: 1 addition & 0 deletions src/Microsoft.VisualStudio.SlnGen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ private static void LogTelemetry(ProgramArguments arguments, TimeSpan evaluation
"execute",
new Dictionary<string, object>
{
["AlwaysBuild"] = arguments.EnableAlwaysBuild().ToString(),
["AssemblyInformationalVersion"] = ThisAssembly.AssemblyInformationalVersion,
["DevEnvFullPathSpecified"] = (!arguments.DevEnvFullPath?.LastOrDefault().IsNullOrWhiteSpace()).ToString(),
["EntryProjectCount"] = arguments.Projects?.Length.ToString(),
Expand Down
16 changes: 16 additions & 0 deletions src/Microsoft.VisualStudio.SlnGen/ProgramArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ public sealed class ProgramArguments
ShowInHelpText = false)]
public bool Debug { get; set; }

/// <summary>
/// Gets or sets a value indicating whether or not to disable building projects for configurations that are not supported by those projects
/// </summary>
[Option(
"-ab|--alwaysbuild",
CommandOptionType.MultipleValue,
ValueName = "true",
Description = "Always include the project in the build even if it has no matching configuration. Default: true")]
public string[] AlwaysBuild { get; set; }

/// <summary>
/// Gets or sets the full path to devenv.exe.
/// </summary>
Expand Down Expand Up @@ -268,6 +278,12 @@ public sealed class ProgramArguments
/// </summary>
internal static Func<ProgramArguments, IConsole, int> Execute { get; set; } = Program.Execute;

/// <summary>
/// Gets a value indicating whether or not to always include the project in the build even if it has no matching configuration
/// </summary>
/// <returns>true to always include the project in the build even if it has no matching configuration, otherwise false.</returns>
public bool EnableAlwaysBuild() => GetBoolean(AlwaysBuild);

/// <summary>
/// Gets a value indicating whether or not folders should be collapsed.
/// </summary>
Expand Down
16 changes: 9 additions & 7 deletions src/Microsoft.VisualStudio.SlnGen/SlnFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public static (string solutionFileFullPath, int customProjectTypeGuidCount, int

if (!logger.HasLoggedErrors)
{
solution.Save(solutionFileFullPath, arguments.EnableFolders(), arguments.EnableCollapseFolders());
solution.Save(solutionFileFullPath, arguments.EnableFolders(), arguments.EnableCollapseFolders(), arguments.EnableAlwaysBuild());
}

return (solutionFileFullPath, customProjectTypeGuids.Count, solutionItems.Count, solution.SolutionGuid);
Expand Down Expand Up @@ -360,7 +360,8 @@ public void AddSolutionItems(IEnumerable<string> items)
/// <param name="path">The full path to the file to write to.</param>
/// <param name="useFolders">Specifies if folders should be created.</param>
/// <param name="collapseFolders">An optional value indicating whether or not folders containing a single item should be collapsed into their parent folder.</param>
public void Save(string path, bool useFolders, bool collapseFolders = false)
/// <param name="alwaysBuild">An optional value indicating whether or not to always include the project in the build even if it has no matching configuration.</param>
public void Save(string path, bool useFolders, bool collapseFolders = false, bool alwaysBuild = true)
{
string directoryName = Path.GetDirectoryName(path);

Expand All @@ -373,7 +374,7 @@ public void Save(string path, bool useFolders, bool collapseFolders = false)

using StreamWriter writer = new StreamWriter(fileStream, Encoding.UTF8);

Save(path, writer, useFolders, collapseFolders);
Save(path, writer, useFolders, collapseFolders, alwaysBuild);
}

/// <summary>
Expand All @@ -383,7 +384,8 @@ public void Save(string path, bool useFolders, bool collapseFolders = false)
/// <param name="writer">The <see cref="TextWriter" /> to save the solution file to.</param>
/// <param name="useFolders">Specifies if folders should be created.</param>
/// <param name="collapseFolders">An optional value indicating whether or not folders containing a single item should be collapsed into their parent folder.</param>
internal void Save(string rootPath, TextWriter writer, bool useFolders, bool collapseFolders = false)
/// <param name="alwaysBuild">An optional value indicating whether or not to always include the project in the build even if it has no matching configuration.</param>
internal void Save(string rootPath, TextWriter writer, bool useFolders, bool collapseFolders = false, bool alwaysBuild = true)
{
writer.WriteLine(Header, _fileFormatVersion);

Expand Down Expand Up @@ -483,7 +485,7 @@ internal void Save(string rootPath, TextWriter writer, bool useFolders, bool col

foreach (string configuration in solutionConfigurations)
{
bool foundConfiguration = TryGetProjectSolutionConfiguration(configuration, project, out string projectSolutionConfiguration);
bool foundConfiguration = TryGetProjectSolutionConfiguration(configuration, project, alwaysBuild, out string projectSolutionConfiguration);

foreach (string platform in solutionPlatforms)
{
Expand Down Expand Up @@ -560,7 +562,7 @@ private IEnumerable<string> GetValidSolutionPlatforms(IEnumerable<string> platfo
return values.Any() ? values : new List<string> { "Any CPU" };
}

private bool TryGetProjectSolutionConfiguration(string solutionConfiguration, SlnProject project, out string projectSolutionConfiguration)
private bool TryGetProjectSolutionConfiguration(string solutionConfiguration, SlnProject project, bool alwaysBuild, out string projectSolutionConfiguration)
{
foreach (string projectConfiguration in project.Configurations)
{
Expand All @@ -574,7 +576,7 @@ private bool TryGetProjectSolutionConfiguration(string solutionConfiguration, Sl

projectSolutionConfiguration = project.Configurations.First();

return true;
return alwaysBuild;
}

private bool TryGetProjectSolutionPlatform(string solutionPlatform, SlnProject project, out string projectSolutionPlatform, out string projectBuildPlatform)
Expand Down

0 comments on commit f7a0759

Please sign in to comment.