diff --git a/PowerShell.sln b/PowerShell.sln index 224d27ab3f..4938316281 100644 --- a/PowerShell.sln +++ b/PowerShell.sln @@ -31,6 +31,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "powershell-unix", "src\powe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnit.tests", "test\xUnit\xUnit.tests.csproj", "{08704934-9764-48CE-86DB-BCF0A1CF7899}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSVersionInfoGenerator", "src\System.Management.Automation\SourceGenerators\PSVersionInfoGenerator\PSVersionInfoGenerator.csproj", "{B22424E8-0516-4FC3-A9CB-D84D15EF0589}" +EndProject # Configuration mapping comment # All global configurations must be mapped to project configurations # diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.cs b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.cs index 6f5b47cca0..29325d2789 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.cs +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.cs @@ -11,40 +11,70 @@ namespace SMA /// Source Code Generator to create partial PSVersionInfo class. /// [Generator] - public class PSVersionInfoGenerator : ISourceGenerator + public class PSVersionInfoGenerator : IIncrementalGenerator { - /// - /// Generate output PSVersionInfo.g.cs file. - /// This allows to directly get ProductVersion and others without reflection. - /// - /// Generator execution context. - public void Execute(GeneratorExecutionContext context) - { - var result = CreatePSVersionInfoPartialClass(context); - - // We must use specific file name suffix (*.g.cs,*.g, *.i.cs, *.generated.cs, *.designer.cs) - // so that Roslyn analyzers skip the file. - context.AddSource("PSVersionInfo.g.cs", result); - } - /// /// Not used. /// /// Generator initialization context. - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { - // No initialization required for this one. + IncrementalValueProvider buildOptionsProvider = context.AnalyzerConfigOptionsProvider + .Select(static (provider, _) => + { + provider.GlobalOptions.TryGetValue("build_property.ProductVersion", out var productVersion); + provider.GlobalOptions.TryGetValue("build_property.PSCoreBuildVersion", out var mainVersion); + provider.GlobalOptions.TryGetValue("build_property.PowerShellVersion", out var gitDescribe); + provider.GlobalOptions.TryGetValue("build_property.ReleaseTag", out var releaseTag); + + BuildOptions options = new() + { + ProductVersion = productVersion ?? string.Empty, + MainVersion = mainVersion ?? string.Empty, + GitDescribe = gitDescribe ?? string.Empty, + ReleaseTag = releaseTag ?? string.Empty + }; + + return options; + }); + + context.RegisterSourceOutput( + buildOptionsProvider, + static (context, buildOptions) => + { + string gitCommitId = string.IsNullOrEmpty(buildOptions.ReleaseTag) ? buildOptions.GitDescribe : buildOptions.ReleaseTag; + if (gitCommitId.StartsWith("v")) + { + gitCommitId = gitCommitId.Substring(1); + } + + var versions = ParsePSVersion(buildOptions.MainVersion); + string result = string.Format( + CultureInfo.InvariantCulture, + SourceTemplate, + buildOptions.ProductVersion, + gitCommitId, + versions.major, + versions.minor, + versions.patch, + versions.preReleaseLabel); + + // We must use specific file name suffix (*.g.cs,*.g, *.i.cs, *.generated.cs, *.designer.cs) + // so that Roslyn analyzers skip the file. + context.AddSource("PSVersionInfo.g.cs", result); + }); } - /// - /// Generate source code for the partial PSVersionInfo class. - /// - /// Generator execution context. - /// A string with partial PSVersionInfo class. - private static string CreatePSVersionInfoPartialClass(GeneratorExecutionContext context) + private struct BuildOptions { - // We must put " + public string ProductVersion; + public string MainVersion; + public string GitDescribe; + public string ReleaseTag; + } + + // We must put " // This file is auto-generated by PSVersionInfoGenerator. // @@ -81,30 +111,6 @@ namespace System.Management.Automation }} }}"; - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.ProductVersion", out var productVersion); - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.PSCoreBuildVersion", out var mainVersion); - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.PowerShellVersion", out var gitDescribe); - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.ReleaseTag", out var releaseTag); - - string gitCommitId = string.IsNullOrEmpty(releaseTag) ? gitDescribe : releaseTag; - if (gitCommitId.StartsWith("v")) - { - gitCommitId = gitCommitId.Substring(1); - } - - var result = ParsePSVersion(mainVersion); - - return string.Format( - CultureInfo.InvariantCulture, - SourceTemplate, - productVersion, - gitCommitId, - result.major, - result.minor, - result.patch, - result.preReleaseLabel); - } - private static (int major, int minor, int patch, string preReleaseLabel) ParsePSVersion(string mainVersion) { // We only handle the pre-defined PSVersion format here, e.g. 7.x.x or 7.x.x-preview.x diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj index fe82962adc..a8f91c5f9e 100644 --- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj +++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj @@ -10,7 +10,7 @@ 11.0 true true - RS1035 + enable