From 344226b69fcad8ee5fdd92dc4f28adfa579dd555 Mon Sep 17 00:00:00 2001 From: Corniel Nobel Date: Sun, 17 Nov 2024 14:02:26 +0100 Subject: [PATCH 1/2] Expose collected BuildEvents publically --- src/Buildalyzer/AnalyzerManagerOptions.cs | 7 +- src/Buildalyzer/AnalyzerResults.cs | 4 + src/Buildalyzer/IAnalyzerResults.cs | 11 ++- src/Buildalyzer/ProjectAnalyzer.cs | 90 +++++++++---------- .../Integration/SimpleProjectsFixture.cs | 10 +++ 5 files changed, 70 insertions(+), 52 deletions(-) diff --git a/src/Buildalyzer/AnalyzerManagerOptions.cs b/src/Buildalyzer/AnalyzerManagerOptions.cs index 63332ef0..0b527341 100644 --- a/src/Buildalyzer/AnalyzerManagerOptions.cs +++ b/src/Buildalyzer/AnalyzerManagerOptions.cs @@ -1,21 +1,22 @@ using System.IO; using Buildalyzer.Logging; using Microsoft.Build.Construction; +using Microsoft.Build.Framework; using Microsoft.Extensions.Logging; namespace Buildalyzer; public class AnalyzerManagerOptions { - public ILoggerFactory LoggerFactory { get; set; } + public ILoggerFactory? LoggerFactory { get; set; } /// /// A filter that indicates whether a give project should be loaded. /// Return true to load the project, false to filter it out. /// - public Func ProjectFilter { get; set; } + public Func? ProjectFilter { get; set; } - public TextWriter LogWriter + public TextWriter? LogWriter { set { diff --git a/src/Buildalyzer/AnalyzerResults.cs b/src/Buildalyzer/AnalyzerResults.cs index 12d45cca..d5fb88b3 100644 --- a/src/Buildalyzer/AnalyzerResults.cs +++ b/src/Buildalyzer/AnalyzerResults.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using Microsoft.Build.Framework; namespace Buildalyzer; @@ -19,6 +20,9 @@ internal void Add(IEnumerable results, bool overallSuccess) _overallSuccess = _overallSuccess.HasValue ? _overallSuccess.Value && overallSuccess : overallSuccess; } + /// + public ImmutableArray BuildEventArguments { get; set; } = []; + public IAnalyzerResult this[string targetFramework] => _results[targetFramework]; public IEnumerable TargetFrameworks => _results.Keys.OrderBy(e => e, TargetFrameworkComparer.Instance); diff --git a/src/Buildalyzer/IAnalyzerResults.cs b/src/Buildalyzer/IAnalyzerResults.cs index 6bcd1f79..2da62d89 100644 --- a/src/Buildalyzer/IAnalyzerResults.cs +++ b/src/Buildalyzer/IAnalyzerResults.cs @@ -1,10 +1,13 @@ -namespace Buildalyzer; +using Microsoft.Build.Framework; -public interface IAnalyzerResults : IEnumerable +namespace Buildalyzer; + +public interface IAnalyzerResults : IReadOnlyCollection { - IAnalyzerResult this[string targetFramework] { get; } + /// The collected during the analysis. + ImmutableArray BuildEventArguments { get; } - int Count { get; } + IAnalyzerResult this[string targetFramework] { get; } bool OverallSuccess { get; } diff --git a/src/Buildalyzer/ProjectAnalyzer.cs b/src/Buildalyzer/ProjectAnalyzer.cs index a5429b00..15917547 100644 --- a/src/Buildalyzer/ProjectAnalyzer.cs +++ b/src/Buildalyzer/ProjectAnalyzer.cs @@ -148,62 +148,62 @@ public IAnalyzerResults Build(string targetFramework, BuildEnvironment buildEnvi private IAnalyzerResults BuildTargets( BuildEnvironment buildEnvironment, string targetFramework, string[] targetsToBuild, AnalyzerResults results) { - using (CancellationTokenSource cancellation = new CancellationTokenSource()) - { - using var pipeLogger = new AnonymousPipeLoggerServer(cancellation.Token); - bool receivedAnyEvent = false; + using var cancellation = new CancellationTokenSource(); - void OnPipeLoggerOnAnyEventRaised(object o, BuildEventArgs buildEventArgs) - { - receivedAnyEvent = true; - } + using var pipeLogger = new AnonymousPipeLoggerServer(cancellation.Token); + bool receivedAnyEvent = false; - pipeLogger.AnyEventRaised += OnPipeLoggerOnAnyEventRaised; + pipeLogger.AnyEventRaised += OnPipeLoggerOnAnyEventRaised; - using var eventProcessor = new EventProcessor(Manager, this, BuildLoggers, pipeLogger, results != null); + using var eventCollector = new BuildEventArgsCollector(pipeLogger); + using var eventProcessor = new EventProcessor(Manager, this, BuildLoggers, pipeLogger, true); - // Run MSBuild - int exitCode; - string fileName = GetCommand( - buildEnvironment, - targetFramework, - targetsToBuild, - pipeLogger.GetClientHandle(), - out string arguments); - - using (ProcessRunner processRunner = new ProcessRunner( - fileName, - arguments, - buildEnvironment.WorkingDirectory ?? Path.GetDirectoryName(ProjectFile.Path), - GetEffectiveEnvironmentVariables(buildEnvironment), - Manager.LoggerFactory)) + // Run MSBuild + int exitCode; + string fileName = GetCommand( + buildEnvironment, + targetFramework, + targetsToBuild, + pipeLogger.GetClientHandle(), + out string arguments); + + using (ProcessRunner processRunner = new ProcessRunner( + fileName, + arguments, + buildEnvironment.WorkingDirectory ?? Path.GetDirectoryName(ProjectFile.Path)!, + GetEffectiveEnvironmentVariables(buildEnvironment)!, + Manager.LoggerFactory)) + { + void OnProcessRunnerExited() { - void OnProcessRunnerExited() + if (!receivedAnyEvent && processRunner.ExitCode != 0) { - if (!receivedAnyEvent && processRunner.ExitCode != 0) - { - pipeLogger.Dispose(); - } + pipeLogger.Dispose(); } - - processRunner.Exited += OnProcessRunnerExited; - processRunner.Start(); - try - { - pipeLogger.ReadAll(); - } - catch (ObjectDisposedException) - { - // Ignore - } - processRunner.WaitForExit(); - exitCode = processRunner.ExitCode; } - // Collect the results - results?.Add(eventProcessor.Results, exitCode == 0 && eventProcessor.OverallSuccess); + processRunner.Exited += OnProcessRunnerExited; + processRunner.Start(); + try + { + pipeLogger.ReadAll(); + } + catch (ObjectDisposedException) + { + // Ignore + } + processRunner.WaitForExit(); + exitCode = processRunner.ExitCode; } + + results.BuildEventArguments = [.. eventCollector]; + + // Collect the results + results.Add(eventProcessor.Results, exitCode == 0 && eventProcessor.OverallSuccess); + return results; + + void OnPipeLoggerOnAnyEventRaised(object o, BuildEventArgs buildEventArgs) => receivedAnyEvent = true; } private string GetCommand( diff --git a/tests/Buildalyzer.Tests/Integration/SimpleProjectsFixture.cs b/tests/Buildalyzer.Tests/Integration/SimpleProjectsFixture.cs index 2cf48d57..018ab1a4 100644 --- a/tests/Buildalyzer.Tests/Integration/SimpleProjectsFixture.cs +++ b/tests/Buildalyzer.Tests/Integration/SimpleProjectsFixture.cs @@ -81,6 +81,16 @@ public void Builds_DesignTime( results.Should().AllSatisfy(r => r.Succeeded.Should().BeTrue()); } + [Test] + public void Collects_BuildEventArguments() + { + using var ctx = Context.ForProject(@"SdkNet6Project\SdkNet6Project.csproj"); + + var results = ctx.Analyzer.Build(new EnvironmentOptions()); + + results.BuildEventArguments.Should().HaveCount(18); + } + [Test] public void BuildsProject( [ValueSource(nameof(Preferences))] EnvironmentPreference preference, From 4fbc8efad33b8ff1282ac6c8360cea0ecfe516df Mon Sep 17 00:00:00 2001 From: Corniel Nobel Date: Sun, 17 Nov 2024 14:10:53 +0100 Subject: [PATCH 2/2] Simplify. --- src/Buildalyzer/AnalyzerManagerOptions.cs | 1 - src/Buildalyzer/BuildEventArgsCollector.cs | 4 ++++ src/Buildalyzer/ProjectAnalyzer.cs | 8 +------- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Buildalyzer/AnalyzerManagerOptions.cs b/src/Buildalyzer/AnalyzerManagerOptions.cs index 0b527341..7f0a6860 100644 --- a/src/Buildalyzer/AnalyzerManagerOptions.cs +++ b/src/Buildalyzer/AnalyzerManagerOptions.cs @@ -1,7 +1,6 @@ using System.IO; using Buildalyzer.Logging; using Microsoft.Build.Construction; -using Microsoft.Build.Framework; using Microsoft.Extensions.Logging; namespace Buildalyzer; diff --git a/src/Buildalyzer/BuildEventArgsCollector.cs b/src/Buildalyzer/BuildEventArgsCollector.cs index 20e65bdd..80bef42d 100644 --- a/src/Buildalyzer/BuildEventArgsCollector.cs +++ b/src/Buildalyzer/BuildEventArgsCollector.cs @@ -17,6 +17,10 @@ public BuildEventArgsCollector(EventArgsDispatcher server) /// public int Count => Bag.Count; + /// Indicates that no events has been collected. + [Pure] + public bool None() => Count == 0; + /// public IEnumerator GetEnumerator() => Bag.GetEnumerator(); diff --git a/src/Buildalyzer/ProjectAnalyzer.cs b/src/Buildalyzer/ProjectAnalyzer.cs index 15917547..ac139835 100644 --- a/src/Buildalyzer/ProjectAnalyzer.cs +++ b/src/Buildalyzer/ProjectAnalyzer.cs @@ -151,10 +151,6 @@ private IAnalyzerResults BuildTargets( using var cancellation = new CancellationTokenSource(); using var pipeLogger = new AnonymousPipeLoggerServer(cancellation.Token); - bool receivedAnyEvent = false; - - pipeLogger.AnyEventRaised += OnPipeLoggerOnAnyEventRaised; - using var eventCollector = new BuildEventArgsCollector(pipeLogger); using var eventProcessor = new EventProcessor(Manager, this, BuildLoggers, pipeLogger, true); @@ -176,7 +172,7 @@ private IAnalyzerResults BuildTargets( { void OnProcessRunnerExited() { - if (!receivedAnyEvent && processRunner.ExitCode != 0) + if (eventCollector.None() && processRunner.ExitCode != 0) { pipeLogger.Dispose(); } @@ -202,8 +198,6 @@ void OnProcessRunnerExited() results.Add(eventProcessor.Results, exitCode == 0 && eventProcessor.OverallSuccess); return results; - - void OnPipeLoggerOnAnyEventRaised(object o, BuildEventArgs buildEventArgs) => receivedAnyEvent = true; } private string GetCommand(