From 31af24286e62c37d08bf240142c47363a3efb081 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 14:56:36 +0200 Subject: [PATCH 01/41] use AnalyzerLoggingContext instead of LoggingService in BuildCheckAcquisitionModule --- .../BuildCheckAcquisitionModule.cs | 13 ++++------- .../IBuildCheckAcquisitionModule.cs | 3 ++- .../BuildCheckConnectorLogger.cs | 8 ++++++- .../BuildCheckManagerProvider.cs | 23 ++++++++++--------- .../Infrastructure/IBuildCheckManager.cs | 2 +- .../Infrastructure/NullBuildCheckManager.cs | 2 +- .../BuildCheckManagerProviderTests.cs | 9 ++++---- 7 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs b/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs index ee755cc7352..cf5dee4cb6d 100644 --- a/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs +++ b/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs @@ -10,15 +10,12 @@ using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Framework; using Microsoft.Build.Shared; +using Microsoft.Build.Experimental.BuildCheck.Logging; namespace Microsoft.Build.Experimental.BuildCheck.Acquisition; internal class BuildCheckAcquisitionModule : IBuildCheckAcquisitionModule { - private readonly ILoggingService _loggingService; - - internal BuildCheckAcquisitionModule(ILoggingService loggingService) => _loggingService = loggingService; - #if FEATURE_ASSEMBLYLOADCONTEXT /// /// AssemblyContextLoader used to load DLLs outside of msbuild.exe directory. @@ -29,7 +26,7 @@ internal class BuildCheckAcquisitionModule : IBuildCheckAcquisitionModule /// /// Creates a list of factory delegates for building analyzer rules instances from a given assembly path. /// - public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, BuildEventContext buildEventContext) + public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, AnalyzerLoggingContext loggingContext) { var analyzersFactories = new List(); @@ -52,7 +49,7 @@ public List CreateBuildAnalyzerFactories(AnalyzerAcquisiti if (availableTypes.Count != analyzerTypes.Count) { - availableTypes.Except(analyzerTypes).ToList().ForEach(t => _loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerBaseTypeNotAssignable", t.Name, t.Assembly)); + availableTypes.Except(analyzerTypes).ToList().ForEach(t => loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerBaseTypeNotAssignable", t.Name, t.Assembly)); } } catch (ReflectionTypeLoadException ex) @@ -61,13 +58,13 @@ public List CreateBuildAnalyzerFactories(AnalyzerAcquisiti { foreach (Exception? loaderException in ex.LoaderExceptions) { - _loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", loaderException?.Message); + loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", loaderException?.Message); } } } catch (Exception ex) { - _loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", ex?.Message); + loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", ex?.Message); } return analyzersFactories; diff --git a/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs b/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs index efb860ef844..6b36835fa6f 100644 --- a/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs +++ b/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Microsoft.Build.Experimental.BuildCheck.Infrastructure; +using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; namespace Microsoft.Build.Experimental.BuildCheck.Acquisition; @@ -12,5 +13,5 @@ internal interface IBuildCheckAcquisitionModule /// /// Creates a list of factory delegates for building analyzer rules instances from a given assembly path. /// - List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, BuildEventContext buildEventContext); + List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, AnalyzerLoggingContext loggingContext); } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index 7dad5f0c4da..d4c5ee0a0f1 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -99,6 +99,12 @@ private void HandleTaskParameterEvent(TaskParameterEventArgs eventArgs) eventArgs); } + private void HandleBuildCheckAcquisitionEvent(BuildCheckAcquisitionEventArgs eventArgs) + => _buildCheckManager + .ProcessAnalyzerAcquisition( + eventArgs.ToAnalyzerAcquisitionData(), + _loggingContextFactory.CreateLoggingContext(GetBuildEventContext(eventArgs))); + private bool IsMetaProjFile(string? projectFile) => !string.IsNullOrEmpty(projectFile) && projectFile!.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase); private void EventSource_AnyEventRaised(object sender, BuildEventArgs e) @@ -161,7 +167,7 @@ private string BuildCsvString(string title, Dictionary rowData { typeof(ProjectStartedEventArgs), (BuildEventArgs e) => _buildCheckManager.StartProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, { typeof(ProjectFinishedEventArgs), (BuildEventArgs e) => _buildCheckManager.EndProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, { typeof(BuildCheckTracingEventArgs), (BuildEventArgs e) => HandleBuildCheckTracingEvent((BuildCheckTracingEventArgs)e) }, - { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => _buildCheckManager.ProcessAnalyzerAcquisition(((BuildCheckAcquisitionEventArgs)e).ToAnalyzerAcquisitionData(), GetBuildEventContext(e)) }, + { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => HandleBuildCheckAcquisitionEvent((BuildCheckAcquisitionEventArgs)e) }, { typeof(TaskStartedEventArgs), (BuildEventArgs e) => HandleTaskStartedEvent((TaskStartedEventArgs)e) }, { typeof(TaskFinishedEventArgs), (BuildEventArgs e) => HandleTaskFinishedEvent((TaskFinishedEventArgs)e) }, { typeof(TaskParameterEventArgs), (BuildEventArgs e) => HandleTaskParameterEvent((TaskParameterEventArgs)e) }, diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index 945990a102b..0b915626a51 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -75,7 +75,7 @@ internal sealed class BuildCheckManager : IBuildCheckManager internal BuildCheckManager(ILoggingService loggingService) { _analyzersRegistry = new List(); - _acquisitionModule = new BuildCheckAcquisitionModule(loggingService); + _acquisitionModule = new BuildCheckAcquisitionModule(); _loggingService = loggingService; _buildCheckCentralContext = new(_configurationProvider); _buildEventsProcessor = new(_buildCheckCentralContext); @@ -101,28 +101,29 @@ public void SetDataSource(BuildCheckDataSource buildCheckDataSource) _tracingReporter.AddSetDataSourceStats(stopwatch.Elapsed); } - public void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, BuildEventContext buildEventContext) + public void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, AnalyzerLoggingContext loggingContext) { Stopwatch stopwatch = Stopwatch.StartNew(); if (IsInProcNode) { - var analyzersFactories = _acquisitionModule.CreateBuildAnalyzerFactories(acquisitionData, buildEventContext); + var analyzersFactories = _acquisitionModule.CreateBuildAnalyzerFactories(acquisitionData, loggingContext); if (analyzersFactories.Count != 0) { - RegisterCustomAnalyzer(BuildCheckDataSource.EventArgs, analyzersFactories, buildEventContext); + RegisterCustomAnalyzer(BuildCheckDataSource.EventArgs, analyzersFactories, loggingContext); } else { - _loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerFailedAcquisition", acquisitionData.AssemblyPath); + loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerFailedAcquisition", acquisitionData.AssemblyPath); } } else { BuildCheckAcquisitionEventArgs eventArgs = acquisitionData.ToBuildEventArgs(); - eventArgs.BuildEventContext = buildEventContext; + eventArgs.BuildEventContext = loggingContext.BuildEventContext!; - _loggingService.LogBuildEvent(eventArgs); + loggingContext.LogBuildEvent(eventArgs); } + stopwatch.Stop(); _tracingReporter.AddAcquisitionStats(stopwatch.Elapsed); } @@ -184,11 +185,11 @@ internal void RegisterCustomAnalyzers( /// /// Represents different data sources used in build check operations. /// A collection of build analyzer factories for rules instantiation. - /// The context of the build event. + /// The logging context of the build event. internal void RegisterCustomAnalyzer( BuildCheckDataSource buildCheckDataSource, IEnumerable factories, - BuildEventContext buildEventContext) + AnalyzerLoggingContext loggingContext) { if (_enabledDataSources[(int)buildCheckDataSource]) { @@ -199,8 +200,8 @@ internal void RegisterCustomAnalyzer( factory, instance.SupportedRules.Select(r => r.Id).ToArray(), instance.SupportedRules.Any(r => r.DefaultConfiguration.IsEnabled == true))); - _loggingService.LogComment(buildEventContext, MessageImportance.Normal, "CustomAnalyzerSuccessfulAcquisition", instance.FriendlyName); - } + loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerSuccessfulAcquisition", instance.FriendlyName); + } } } diff --git a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs index 9f39f8dcb69..0287d68454f 100644 --- a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs @@ -54,7 +54,7 @@ void ProcessTaskParameterEventArgs( void SetDataSource(BuildCheckDataSource buildCheckDataSource); - void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, BuildEventContext buildEventContext); + void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, AnalyzerLoggingContext loggingContext); Dictionary CreateAnalyzerTracingStats(); diff --git a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs index a0136eafac8..7d6b9e28fa9 100644 --- a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs @@ -42,7 +42,7 @@ public void ProcessTaskParameterEventArgs(AnalyzerLoggingContext buildAnalysisCo { } - public void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, BuildEventContext buildEventContext) + public void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, AnalyzerLoggingContext loggingContext) { } diff --git a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs index bf1ccb8105a..30d27523bda 100644 --- a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs +++ b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs @@ -5,10 +5,11 @@ using System.Linq; using System.Reflection; using Microsoft.Build.BackEnd.Logging; -using Microsoft.Build.Experimental.BuildCheck.Acquisition; -using Microsoft.Build.Experimental.BuildCheck.Infrastructure; using Microsoft.Build.Construction; using Microsoft.Build.Experimental.BuildCheck; +using Microsoft.Build.Experimental.BuildCheck.Acquisition; +using Microsoft.Build.Experimental.BuildCheck.Infrastructure; +using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; using Microsoft.Build.UnitTests; using Shouldly; @@ -40,7 +41,7 @@ public void ProcessAnalyzerAcquisitionTest(bool isAnalyzerRuleExist, string[] ex MockBuildCheckAcquisition(isAnalyzerRuleExist); MockEnabledDataSourcesDefinition(); - _testedInstance.ProcessAnalyzerAcquisition(new AnalyzerAcquisitionData("DummyPath"), new BuildEventContext(1, 2, 3, 4, 5, 6, 7)); + _testedInstance.ProcessAnalyzerAcquisition(new AnalyzerAcquisitionData("DummyPath"), new AnalyzerLoggingContext(_loggingService, new BuildEventContext(1, 2, 3, 4, 5, 6, 7))); _logger.AllBuildEvents.Where(be => be.GetType() == typeof(BuildMessageEventArgs)).Select(be => be.Message).ToArray() .ShouldBeEquivalentTo(expectedMessages); @@ -66,7 +67,7 @@ internal sealed class BuildCheckAcquisitionModuleMock : IBuildCheckAcquisitionMo internal BuildCheckAcquisitionModuleMock(bool isAnalyzerRuleExistForTest) => _isAnalyzerRuleExistForTest = isAnalyzerRuleExistForTest; - public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, BuildEventContext buildEventContext) + public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, AnalyzerLoggingContext loggingContext) => _isAnalyzerRuleExistForTest ? new List() { () => new BuildAnalyzerRuleMock("Rule1"), () => new BuildAnalyzerRuleMock("Rule2") } : new List(); From bc63e185928dbe309db08ab8f55ad981f1119ee7 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 15:30:44 +0200 Subject: [PATCH 02/41] include buildCheck unit tests in sln --- MSBuild.Dev.slnf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MSBuild.Dev.slnf b/MSBuild.Dev.slnf index 79c1a4edfdf..893aa59154f 100644 --- a/MSBuild.Dev.slnf +++ b/MSBuild.Dev.slnf @@ -4,6 +4,7 @@ "projects": [ "src\\Build.OM.UnitTests\\Microsoft.Build.Engine.OM.UnitTests.csproj", "src\\Build.UnitTests\\Microsoft.Build.Engine.UnitTests.csproj", + "src\\BuildCheck.UnitTests\\Microsoft.Build.BuildCheck.UnitTests.csproj", "src\\Build\\Microsoft.Build.csproj", "src\\Framework.UnitTests\\Microsoft.Build.Framework.UnitTests.csproj", "src\\Framework\\Microsoft.Build.Framework.csproj", @@ -18,4 +19,4 @@ "src\\Xunit.NetCore.Extensions\\Xunit.NetCore.Extensions.csproj" ] } -} \ No newline at end of file +} From e47a8ff4c194a681caa284d05265acf4cc2fd815 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 15:40:09 +0200 Subject: [PATCH 03/41] use AnalyzerLoggingContext instead of LoggingService in BuildCheckManager --- .../RequestBuilder/RequestBuilder.cs | 5 ++-- .../BuildCheckConnectorLogger.cs | 5 +++- .../BuildCheckManagerProvider.cs | 24 +++++++++---------- .../Infrastructure/IBuildCheckManager.cs | 2 +- .../Infrastructure/NullBuildCheckManager.cs | 2 +- .../BuildCheckManagerProviderTests.cs | 2 +- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs index 577fc877071..ebc47bb26db 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs @@ -10,13 +10,14 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Build.BackEnd.Logging; -using Microsoft.Build.Experimental.BuildCheck.Infrastructure; using Microsoft.Build.Collections; using Microsoft.Build.Evaluation; using Microsoft.Build.Eventing; using Microsoft.Build.Exceptions; using Microsoft.Build.Execution; using Microsoft.Build.Experimental.BuildCheck; +using Microsoft.Build.Experimental.BuildCheck.Infrastructure; +using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; using Microsoft.Build.Internal; using Microsoft.Build.Shared; @@ -1123,7 +1124,7 @@ private async Task BuildProject() { buildCheckManager.StartProjectEvaluation( BuildCheckDataSource.BuildExecution, - _requestEntry.Request.ParentBuildEventContext, + new AnalyzerLoggingContext(_nodeLoggingContext.LoggingService, _requestEntry.Request.ParentBuildEventContext), _requestEntry.RequestConfiguration.ProjectFullPath); _requestEntry.RequestConfiguration.LoadProjectIntoConfiguration( diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index d4c5ee0a0f1..3563c072073 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -66,7 +66,10 @@ private void HandleProjectEvaluationStartedEvent(ProjectEvaluationStartedEventAr { if (!IsMetaProjFile(eventArgs.ProjectFile)) { - _buildCheckManager.StartProjectEvaluation(BuildCheckDataSource.EventArgs, eventArgs.BuildEventContext!, eventArgs.ProjectFile!); + _buildCheckManager.StartProjectEvaluation( + BuildCheckDataSource.EventArgs, + _loggingContextFactory.CreateLoggingContext(eventArgs.BuildEventContext!), + eventArgs.ProjectFile!); } } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index 0b915626a51..718ea78d99c 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -8,10 +8,10 @@ using System.Threading; using Microsoft.Build.BackEnd; using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.BuildCheck.Acquisition; using Microsoft.Build.Experimental.BuildCheck.Analyzers; using Microsoft.Build.Experimental.BuildCheck.Logging; -using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Framework; using Microsoft.Build.Shared; @@ -46,7 +46,7 @@ public void InitializeComponent(IBuildComponentHost host) IBuildCheckManager instance; if (host!.BuildParameters.IsBuildCheckEnabled) { - instance = new BuildCheckManager(host.LoggingService); + instance = new BuildCheckManager(); } else { @@ -66,17 +66,15 @@ internal sealed class BuildCheckManager : IBuildCheckManager private readonly TracingReporter _tracingReporter = new TracingReporter(); private readonly ConfigurationProvider _configurationProvider = new ConfigurationProvider(); private readonly BuildCheckCentralContext _buildCheckCentralContext; - private readonly ILoggingService _loggingService; private readonly List _analyzersRegistry; private readonly bool[] _enabledDataSources = new bool[(int)BuildCheckDataSource.ValuesCount]; private readonly BuildEventsProcessor _buildEventsProcessor; private readonly IBuildCheckAcquisitionModule _acquisitionModule; - internal BuildCheckManager(ILoggingService loggingService) + internal BuildCheckManager() { _analyzersRegistry = new List(); _acquisitionModule = new BuildCheckAcquisitionModule(); - _loggingService = loggingService; _buildCheckCentralContext = new(_configurationProvider); _buildEventsProcessor = new(_buildCheckCentralContext); } @@ -205,7 +203,7 @@ internal void RegisterCustomAnalyzer( } } - private void SetupSingleAnalyzer(BuildAnalyzerFactoryContext analyzerFactoryContext, string projectFullPath, BuildEventContext buildEventContext) + private void SetupSingleAnalyzer(BuildAnalyzerFactoryContext analyzerFactoryContext, string projectFullPath) { // For custom analyzers - it should run only on projects where referenced // (otherwise error out - https://github.com/orgs/dotnet/projects/373/views/1?pane=issue&itemId=57849480) @@ -283,7 +281,7 @@ private void SetupSingleAnalyzer(BuildAnalyzerFactoryContext analyzerFactoryCont } } - private void SetupAnalyzersForNewProject(string projectFullPath, BuildEventContext buildEventContext) + private void SetupAnalyzersForNewProject(string projectFullPath, AnalyzerLoggingContext loggingContext) { // Only add analyzers here // On an execution node - we might remove and dispose the analyzers once project is done @@ -295,11 +293,11 @@ private void SetupAnalyzersForNewProject(string projectFullPath, BuildEventConte { try { - SetupSingleAnalyzer(analyzerFactoryContext, projectFullPath, buildEventContext); + SetupSingleAnalyzer(analyzerFactoryContext, projectFullPath); } catch (BuildCheckConfigurationException e) { - _loggingService.LogErrorFromText(buildEventContext, null, null, null, + loggingContext.LogErrorFromText(null, null, null, new BuildEventFileInfo(projectFullPath), e.Message); analyzersToRemove.Add(analyzerFactoryContext); @@ -309,7 +307,7 @@ private void SetupAnalyzersForNewProject(string projectFullPath, BuildEventConte analyzersToRemove.ForEach(c => { _analyzersRegistry.Remove(c); - _loggingService.LogCommentFromText(buildEventContext, MessageImportance.High, $"Dismounting analyzer '{c.FriendlyName}'"); + loggingContext.LogCommentFromText(MessageImportance.High, $"Dismounting analyzer '{c.FriendlyName}'"); }); foreach (var analyzerToRemove in analyzersToRemove.Select(a => a.MaterializedAnalyzer).Where(a => a != null)) { @@ -377,7 +375,9 @@ public void FinalizeProcessing(LoggingContext loggingContext) loggingContext.LogBuildEvent(analyzerEventArg); } - public void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, BuildEventContext buildEventContext, + public void StartProjectEvaluation( + BuildCheckDataSource buildCheckDataSource, + AnalyzerLoggingContext loggingContext, string fullPath) { if (buildCheckDataSource == BuildCheckDataSource.EventArgs && IsInProcNode) @@ -388,7 +388,7 @@ public void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, Bu return; } - SetupAnalyzersForNewProject(fullPath, buildEventContext); + SetupAnalyzersForNewProject(fullPath, loggingContext); } /* diff --git a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs index 0287d68454f..01864c7f66a 100644 --- a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs @@ -64,7 +64,7 @@ void ProcessTaskParameterEventArgs( // but as well from the ConnectorLogger - as even if interleaved, it gives the info // to manager about what analyzers need to be materialized and configuration fetched. // No unloading of analyzers is yet considered - once loaded it stays for whole build. - void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, BuildEventContext buildEventContext, string fullPath); + void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, AnalyzerLoggingContext loggingContext, string fullPath); void EndProjectEvaluation(BuildCheckDataSource buildCheckDataSource, BuildEventContext buildEventContext); diff --git a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs index 7d6b9e28fa9..c741591cc9a 100644 --- a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs @@ -50,7 +50,7 @@ public void FinalizeProcessing(LoggingContext loggingContext) { } - public void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, BuildEventContext buildEventContext, string fullPath) + public void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, AnalyzerLoggingContext loggingContext, string fullPath) { } diff --git a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs index 30d27523bda..c9eeabed22a 100644 --- a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs +++ b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs @@ -30,7 +30,7 @@ public BuildCheckManagerTests(ITestOutputHelper output) _loggingService = LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); _logger = new MockLogger(); _loggingService.RegisterLogger(_logger); - _testedInstance = new BuildCheckManager(_loggingService); + _testedInstance = new BuildCheckManager(); } [Theory] From 074377515607076832551adebbfce47fdd854ba0 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 19:09:32 +0200 Subject: [PATCH 04/41] create IAnalysisContext in order to handle BuildEventContext --- .../BackEnd/BuildManager/BuildManager.cs | 2 +- .../RequestBuilder/RequestBuilder.cs | 2 +- .../BuildCheckAcquisitionModule.cs | 10 ++-- .../IBuildCheckAcquisitionModule.cs | 2 +- .../AnalyzerContext/AnalysisLoggingContext.cs | 43 ++++++++++++++ .../AnalysisLoggingContextFactory.cs | 22 +++++++ .../AnalyzerContext/IAnalysisContext.cs | 25 ++++++++ .../IAnalysisContextFactory.cs | 11 ++++ .../BuildCheckCentralContext.cs | 28 ++++----- .../BuildCheckConnectorLogger.cs | 59 ++++++++----------- .../BuildCheckManagerProvider.cs | 46 ++++++++------- .../Infrastructure/BuildEventsProcessor.cs | 20 +++---- .../Infrastructure/IBuildCheckManager.cs | 12 ++-- .../Infrastructure/NullBuildCheckManager.cs | 17 ++++-- ...Context.cs => AnalyzerLoggingContext22.cs} | 6 +- ....cs => AnalyzerLoggingContextFactory22.cs} | 6 +- .../IBuildAnalysisLoggingContextFactory.cs | 2 +- .../BuildCheck/OM/BuildCheckDataContext.cs | 12 ++-- src/Build/Instance/ProjectInstance.cs | 2 +- src/Build/Microsoft.Build.csproj | 8 ++- .../BuildCheckManagerProviderTests.cs | 4 +- .../DoubleWritesAnalyzer_Tests.cs | 2 +- 22 files changed, 223 insertions(+), 118 deletions(-) create mode 100644 src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContext.cs create mode 100644 src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContextFactory.cs create mode 100644 src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContext.cs create mode 100644 src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContextFactory.cs rename src/Build/BuildCheck/Logging/{AnalyzerLoggingContext.cs => AnalyzerLoggingContext22.cs} (64%) rename src/Build/BuildCheck/Logging/{AnalyzerLoggingContextFactory.cs => AnalyzerLoggingContextFactory22.cs} (53%) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 99acd7b5ac8..54d7a8a347d 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2999,7 +2999,7 @@ private ILoggingService CreateLoggingService( verbosity: LoggerVerbosity.Quiet); ILogger buildCheckLogger = - new BuildCheckConnectorLogger(new AnalyzerLoggingContextFactory(loggingService), + new BuildCheckConnectorLogger(new AnalysisLoggingContextFactory(loggingService), buildCheckManagerProvider.Instance); ForwardingLoggerRecord[] forwardingLogger = { new ForwardingLoggerRecord(buildCheckLogger, forwardingLoggerDescription) }; diff --git a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs index ebc47bb26db..eb33f28d019 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs @@ -1124,7 +1124,7 @@ private async Task BuildProject() { buildCheckManager.StartProjectEvaluation( BuildCheckDataSource.BuildExecution, - new AnalyzerLoggingContext(_nodeLoggingContext.LoggingService, _requestEntry.Request.ParentBuildEventContext), + new AnalysisLoggingContext(_nodeLoggingContext.LoggingService, _requestEntry.Request.ParentBuildEventContext), _requestEntry.RequestConfiguration.ProjectFullPath); _requestEntry.RequestConfiguration.LoadProjectIntoConfiguration( diff --git a/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs b/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs index cf5dee4cb6d..973b3f6025e 100644 --- a/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs +++ b/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs @@ -26,7 +26,9 @@ internal class BuildCheckAcquisitionModule : IBuildCheckAcquisitionModule /// /// Creates a list of factory delegates for building analyzer rules instances from a given assembly path. /// - public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, AnalyzerLoggingContext loggingContext) + public List CreateBuildAnalyzerFactories( + AnalyzerAcquisitionData analyzerAcquisitionData, + IAnalysisContext analysisContext) { var analyzersFactories = new List(); @@ -49,7 +51,7 @@ public List CreateBuildAnalyzerFactories(AnalyzerAcquisiti if (availableTypes.Count != analyzerTypes.Count) { - availableTypes.Except(analyzerTypes).ToList().ForEach(t => loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerBaseTypeNotAssignable", t.Name, t.Assembly)); + availableTypes.Except(analyzerTypes).ToList().ForEach(t => analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerBaseTypeNotAssignable", t.Name, t.Assembly)); } } catch (ReflectionTypeLoadException ex) @@ -58,13 +60,13 @@ public List CreateBuildAnalyzerFactories(AnalyzerAcquisiti { foreach (Exception? loaderException in ex.LoaderExceptions) { - loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", loaderException?.Message); + analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", loaderException?.Message); } } } catch (Exception ex) { - loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", ex?.Message); + analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerFailedRuleLoading", ex?.Message); } return analyzersFactories; diff --git a/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs b/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs index 6b36835fa6f..99a41e269c8 100644 --- a/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs +++ b/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs @@ -13,5 +13,5 @@ internal interface IBuildCheckAcquisitionModule /// /// Creates a list of factory delegates for building analyzer rules instances from a given assembly path. /// - List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, AnalyzerLoggingContext loggingContext); + List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, IAnalysisContext analysisContext); } diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContext.cs new file mode 100644 index 00000000000..38337ae18a9 --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContext.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.Framework; +using Microsoft.Build.Shared; + +namespace Microsoft.Build.Experimental.BuildCheck; + +internal class AnalysisLoggingContext : IAnalysisContext +{ + private readonly ILoggingService _loggingService; + private readonly BuildEventContext _eventContext; + + public AnalysisLoggingContext(ILoggingService loggingService, BuildEventContext eventContext) + { + _loggingService = loggingService; + _eventContext = eventContext; + } + + public BuildEventContext BuildEventContext => _eventContext; + + public void DispatchBuildEvent(BuildEventArgs buildEvent) + => _loggingService + .LogBuildEvent(buildEvent); + + public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) + => _loggingService + .LogComment(_eventContext, importance, messageResourceName, messageArgs); + + public void DispatchAsCommentFromText(MessageImportance importance, string message) + => _loggingService + .LogCommentFromText(_eventContext, importance, message); + + public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) + => _loggingService + .LogErrorFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); +} diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContextFactory.cs new file mode 100644 index 00000000000..b1a716d7b7f --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContextFactory.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.Framework; + +namespace Microsoft.Build.Experimental.BuildCheck; + +internal class AnalysisLoggingContextFactory : IAnalysisContextFactory +{ + private readonly ILoggingService _loggingService; + + public AnalysisLoggingContextFactory(ILoggingService loggingService) => _loggingService = loggingService; + + public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) + => new AnalysisLoggingContext(_loggingService, eventContext); +} diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContext.cs b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContext.cs new file mode 100644 index 00000000000..be4cb8c6049 --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContext.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Shared; + +namespace Microsoft.Build.Experimental.BuildCheck; + +internal interface IAnalysisContext +{ + BuildEventContext BuildEventContext { get; } + + void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs); + + void DispatchBuildEvent(BuildEventArgs buildEvent); + + void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message); + + void DispatchAsCommentFromText(MessageImportance importance, string message); +} diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContextFactory.cs new file mode 100644 index 00000000000..66cc71f507c --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContextFactory.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Build.Framework; + +namespace Microsoft.Build.Experimental.BuildCheck; + +internal interface IAnalysisContextFactory +{ + IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext); +} diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckCentralContext.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckCentralContext.cs index 32078038875..c798f0c6152 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckCentralContext.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckCentralContext.cs @@ -18,9 +18,7 @@ internal sealed class BuildCheckCentralContext private readonly ConfigurationProvider _configurationProvider; internal BuildCheckCentralContext(ConfigurationProvider configurationProvider) - { - _configurationProvider = configurationProvider; - } + => _configurationProvider = configurationProvider; private record CallbackRegistry( List<(BuildAnalyzerWrapper, Action>)> EvaluatedPropertiesActions, @@ -77,33 +75,33 @@ internal void DeregisterAnalyzer(BuildAnalyzerWrapper analyzer) internal void RunEvaluatedPropertiesActions( EvaluatedPropertiesAnalysisData evaluatedPropertiesAnalysisData, - LoggingContext loggingContext, - Action + IAnalysisContext analysisContext, + Action resultHandler) => RunRegisteredActions(_globalCallbacks.EvaluatedPropertiesActions, evaluatedPropertiesAnalysisData, - loggingContext, resultHandler); + analysisContext, resultHandler); internal void RunParsedItemsActions( ParsedItemsAnalysisData parsedItemsAnalysisData, - LoggingContext loggingContext, - Action + IAnalysisContext analysisContext, + Action resultHandler) => RunRegisteredActions(_globalCallbacks.ParsedItemsActions, parsedItemsAnalysisData, - loggingContext, resultHandler); + analysisContext, resultHandler); internal void RunTaskInvocationActions( TaskInvocationAnalysisData taskInvocationAnalysisData, - LoggingContext loggingContext, - Action + IAnalysisContext analysisContext, + Action resultHandler) => RunRegisteredActions(_globalCallbacks.TaskInvocationActions, taskInvocationAnalysisData, - loggingContext, resultHandler); + analysisContext, resultHandler); private void RunRegisteredActions( List<(BuildAnalyzerWrapper, Action>)> registeredCallbacks, T analysisData, - LoggingContext loggingContext, - Action resultHandler) + IAnalysisContext analysisContext, + Action resultHandler) where T : AnalysisData { string projectFullPath = analysisData.ProjectFilePath; @@ -147,7 +145,7 @@ private void RunRegisteredActions( BuildCheckDataContext context = new BuildCheckDataContext( analyzerCallback.Item1, - loggingContext, + analysisContext, configPerRule, resultHandler, analysisData); diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index 3563c072073..22f841bab27 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -5,9 +5,9 @@ using System.Collections.Generic; using System.Linq; using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.BuildCheck.Acquisition; using Microsoft.Build.Experimental.BuildCheck.Utilities; -using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Framework; namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; @@ -16,14 +16,14 @@ internal sealed class BuildCheckConnectorLogger : ILogger { private readonly Dictionary> _eventHandlers; private readonly IBuildCheckManager _buildCheckManager; - private readonly IBuildAnalysisLoggingContextFactory _loggingContextFactory; + private readonly IAnalysisContextFactory _analyzerContextFactory; internal BuildCheckConnectorLogger( - IBuildAnalysisLoggingContextFactory loggingContextFactory, + IAnalysisContextFactory analyzerContextFactory, IBuildCheckManager buildCheckManager) { _buildCheckManager = buildCheckManager; - _loggingContextFactory = loggingContextFactory; + _analyzerContextFactory = analyzerContextFactory; _eventHandlers = GetBuildEventHandlers(); } @@ -40,6 +40,7 @@ public void Initialize(IEventSource eventSource) { eventSource3.IncludeTaskInputs(); } + if (eventSource is IEventSource4 eventSource4) { eventSource4.IncludeEvaluationPropertiesAndItems(); @@ -55,7 +56,7 @@ private void HandleProjectEvaluationFinishedEvent(ProjectEvaluationFinishedEvent if (!IsMetaProjFile(eventArgs.ProjectFile)) { _buildCheckManager.ProcessEvaluationFinishedEventArgs( - _loggingContextFactory.CreateLoggingContext(eventArgs.BuildEventContext!), + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), eventArgs); _buildCheckManager.EndProjectEvaluation(BuildCheckDataSource.EventArgs, eventArgs.BuildEventContext!); @@ -68,7 +69,7 @@ private void HandleProjectEvaluationStartedEvent(ProjectEvaluationStartedEventAr { _buildCheckManager.StartProjectEvaluation( BuildCheckDataSource.EventArgs, - _loggingContextFactory.CreateLoggingContext(eventArgs.BuildEventContext!), + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), eventArgs.ProjectFile!); } } @@ -82,31 +83,24 @@ private void HandleBuildCheckTracingEvent(BuildCheckTracingEventArgs eventArgs) } private void HandleTaskStartedEvent(TaskStartedEventArgs eventArgs) - { - _buildCheckManager.ProcessTaskStartedEventArgs( - _loggingContextFactory.CreateLoggingContext(eventArgs.BuildEventContext!), - eventArgs); - } + => _buildCheckManager.ProcessTaskStartedEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); private void HandleTaskFinishedEvent(TaskFinishedEventArgs eventArgs) - { - _buildCheckManager.ProcessTaskFinishedEventArgs( - _loggingContextFactory.CreateLoggingContext(eventArgs.BuildEventContext!), - eventArgs); - } + => _buildCheckManager.ProcessTaskFinishedEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); private void HandleTaskParameterEvent(TaskParameterEventArgs eventArgs) - { - _buildCheckManager.ProcessTaskParameterEventArgs( - _loggingContextFactory.CreateLoggingContext(eventArgs.BuildEventContext!), - eventArgs); - } + => _buildCheckManager.ProcessTaskParameterEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); private void HandleBuildCheckAcquisitionEvent(BuildCheckAcquisitionEventArgs eventArgs) - => _buildCheckManager - .ProcessAnalyzerAcquisition( + => _buildCheckManager.ProcessAnalyzerAcquisition( eventArgs.ToAnalyzerAcquisitionData(), - _loggingContextFactory.CreateLoggingContext(GetBuildEventContext(eventArgs))); + _analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(eventArgs))); private bool IsMetaProjFile(string? projectFile) => !string.IsNullOrEmpty(projectFile) && projectFile!.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase); @@ -122,13 +116,12 @@ private void EventSource_AnyEventRaised(object sender, BuildEventArgs e) private void EventSource_BuildFinished(object sender, BuildFinishedEventArgs e) { - LoggingContext loggingContext = _loggingContextFactory.CreateLoggingContext(GetBuildEventContext(e)); - _stats.Merge(_buildCheckManager.CreateAnalyzerTracingStats(), (span1, span2) => span1 + span2); - LogAnalyzerStats(loggingContext); + + LogAnalyzerStats(_analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(e))); } - private void LogAnalyzerStats(LoggingContext loggingContext) + private void LogAnalyzerStats(IAnalysisContext analysisContext) { Dictionary infraStats = new Dictionary(); Dictionary analyzerStats = new Dictionary(); @@ -147,15 +140,15 @@ private void LogAnalyzerStats(LoggingContext loggingContext) } BuildCheckTracingEventArgs statEvent = new BuildCheckTracingEventArgs(_stats, true) - { BuildEventContext = loggingContext.BuildEventContext }; + { BuildEventContext = analysisContext.BuildEventContext }; - loggingContext.LogBuildEvent(statEvent); + analysisContext.DispatchBuildEvent(statEvent); - loggingContext.LogCommentFromText(MessageImportance.Low, $"BuildCheck run times{Environment.NewLine}"); + analysisContext.DispatchAsCommentFromText(MessageImportance.Low, $"BuildCheck run times{Environment.NewLine}"); string infraData = BuildCsvString("Infrastructure run times", infraStats); - loggingContext.LogCommentFromText(MessageImportance.Low, infraData); + analysisContext.DispatchAsCommentFromText(MessageImportance.Low, infraData); string analyzerData = BuildCsvString("Analyzer run times", analyzerStats); - loggingContext.LogCommentFromText(MessageImportance.Low, analyzerData); + analysisContext.DispatchAsCommentFromText(MessageImportance.Low, analyzerData); } private string BuildCsvString(string title, Dictionary rowData) diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index 718ea78d99c..e0afec2b677 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -99,27 +99,29 @@ public void SetDataSource(BuildCheckDataSource buildCheckDataSource) _tracingReporter.AddSetDataSourceStats(stopwatch.Elapsed); } - public void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, AnalyzerLoggingContext loggingContext) + public void ProcessAnalyzerAcquisition( + AnalyzerAcquisitionData acquisitionData, + IAnalysisContext analysisContext) { Stopwatch stopwatch = Stopwatch.StartNew(); if (IsInProcNode) { - var analyzersFactories = _acquisitionModule.CreateBuildAnalyzerFactories(acquisitionData, loggingContext); + var analyzersFactories = _acquisitionModule.CreateBuildAnalyzerFactories(acquisitionData, analysisContext); if (analyzersFactories.Count != 0) { - RegisterCustomAnalyzer(BuildCheckDataSource.EventArgs, analyzersFactories, loggingContext); + RegisterCustomAnalyzer(BuildCheckDataSource.EventArgs, analyzersFactories, analysisContext); } else { - loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerFailedAcquisition", acquisitionData.AssemblyPath); + analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerFailedAcquisition", acquisitionData.AssemblyPath); } } else { BuildCheckAcquisitionEventArgs eventArgs = acquisitionData.ToBuildEventArgs(); - eventArgs.BuildEventContext = loggingContext.BuildEventContext!; + eventArgs.BuildEventContext = analysisContext.BuildEventContext!; - loggingContext.LogBuildEvent(eventArgs); + analysisContext.DispatchBuildEvent(eventArgs); } stopwatch.Stop(); @@ -183,11 +185,11 @@ internal void RegisterCustomAnalyzers( /// /// Represents different data sources used in build check operations. /// A collection of build analyzer factories for rules instantiation. - /// The logging context of the build event. + /// The logging context of the build event. internal void RegisterCustomAnalyzer( BuildCheckDataSource buildCheckDataSource, IEnumerable factories, - AnalyzerLoggingContext loggingContext) + IAnalysisContext analysisContext) { if (_enabledDataSources[(int)buildCheckDataSource]) { @@ -198,7 +200,7 @@ internal void RegisterCustomAnalyzer( factory, instance.SupportedRules.Select(r => r.Id).ToArray(), instance.SupportedRules.Any(r => r.DefaultConfiguration.IsEnabled == true))); - loggingContext.LogComment(MessageImportance.Normal, "CustomAnalyzerSuccessfulAcquisition", instance.FriendlyName); + analysisContext.DispatchAsComment(MessageImportance.Normal, "CustomAnalyzerSuccessfulAcquisition", instance.FriendlyName); } } } @@ -281,7 +283,7 @@ private void SetupSingleAnalyzer(BuildAnalyzerFactoryContext analyzerFactoryCont } } - private void SetupAnalyzersForNewProject(string projectFullPath, AnalyzerLoggingContext loggingContext) + private void SetupAnalyzersForNewProject(string projectFullPath, IAnalysisContext analysisContext) { // Only add analyzers here // On an execution node - we might remove and dispose the analyzers once project is done @@ -297,7 +299,7 @@ private void SetupAnalyzersForNewProject(string projectFullPath, AnalyzerLogging } catch (BuildCheckConfigurationException e) { - loggingContext.LogErrorFromText(null, null, null, + analysisContext.DispatchAsErrorFromText(null, null, null, new BuildEventFileInfo(projectFullPath), e.Message); analyzersToRemove.Add(analyzerFactoryContext); @@ -307,7 +309,7 @@ private void SetupAnalyzersForNewProject(string projectFullPath, AnalyzerLogging analyzersToRemove.ForEach(c => { _analyzersRegistry.Remove(c); - loggingContext.LogCommentFromText(MessageImportance.High, $"Dismounting analyzer '{c.FriendlyName}'"); + analysisContext.DispatchAsCommentFromText(MessageImportance.High, $"Dismounting analyzer '{c.FriendlyName}'"); }); foreach (var analyzerToRemove in analyzersToRemove.Select(a => a.MaterializedAnalyzer).Where(a => a != null)) { @@ -321,28 +323,28 @@ private void SetupAnalyzersForNewProject(string projectFullPath, AnalyzerLogging } public void ProcessEvaluationFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, ProjectEvaluationFinishedEventArgs evaluationFinishedEventArgs) => _buildEventsProcessor - .ProcessEvaluationFinishedEventArgs(buildAnalysisContext, evaluationFinishedEventArgs); + .ProcessEvaluationFinishedEventArgs(analysisContext, evaluationFinishedEventArgs); public void ProcessTaskStartedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskStartedEventArgs taskStartedEventArgs) => _buildEventsProcessor - .ProcessTaskStartedEventArgs(buildAnalysisContext, taskStartedEventArgs); + .ProcessTaskStartedEventArgs(analysisContext, taskStartedEventArgs); public void ProcessTaskFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskFinishedEventArgs taskFinishedEventArgs) => _buildEventsProcessor - .ProcessTaskFinishedEventArgs(buildAnalysisContext, taskFinishedEventArgs); + .ProcessTaskFinishedEventArgs(analysisContext, taskFinishedEventArgs); public void ProcessTaskParameterEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskParameterEventArgs taskParameterEventArgs) => _buildEventsProcessor - .ProcessTaskParameterEventArgs(buildAnalysisContext, taskParameterEventArgs); + .ProcessTaskParameterEventArgs(analysisContext, taskParameterEventArgs); public Dictionary CreateAnalyzerTracingStats() { @@ -377,7 +379,7 @@ public void FinalizeProcessing(LoggingContext loggingContext) public void StartProjectEvaluation( BuildCheckDataSource buildCheckDataSource, - AnalyzerLoggingContext loggingContext, + IAnalysisContext analysisContext, string fullPath) { if (buildCheckDataSource == BuildCheckDataSource.EventArgs && IsInProcNode) @@ -388,7 +390,7 @@ public void StartProjectEvaluation( return; } - SetupAnalyzersForNewProject(fullPath, loggingContext); + SetupAnalyzersForNewProject(fullPath, analysisContext); } /* diff --git a/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs b/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs index e9a5f9e8aa2..b38a3bd4ace 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs @@ -58,7 +58,7 @@ public TaskKey(BuildEventContext context) // This requires MSBUILDLOGPROPERTIESANDITEMSAFTEREVALUATION set to 1 internal void ProcessEvaluationFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, ProjectEvaluationFinishedEventArgs evaluationFinishedEventArgs) { Dictionary propertiesLookup = new Dictionary(); @@ -68,7 +68,7 @@ internal void ProcessEvaluationFinishedEventArgs( EvaluatedPropertiesAnalysisData analysisData = new(evaluationFinishedEventArgs.ProjectFile!, propertiesLookup); - _buildCheckCentralContext.RunEvaluatedPropertiesActions(analysisData, buildAnalysisContext, ReportResult); + _buildCheckCentralContext.RunEvaluatedPropertiesActions(analysisData, analysisContext, ReportResult); if (_buildCheckCentralContext.HasParsedItemsActions) { @@ -79,12 +79,12 @@ internal void ProcessEvaluationFinishedEventArgs( ParsedItemsAnalysisData itemsAnalysisData = new(evaluationFinishedEventArgs.ProjectFile!, new ItemsHolder(xml.Items, xml.ItemGroups)); - _buildCheckCentralContext.RunParsedItemsActions(itemsAnalysisData, buildAnalysisContext, ReportResult); + _buildCheckCentralContext.RunParsedItemsActions(itemsAnalysisData, analysisContext, ReportResult); } } internal void ProcessTaskStartedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskStartedEventArgs taskStartedEventArgs) { if (!_buildCheckCentralContext.HasTaskInvocationActions) @@ -120,7 +120,7 @@ internal void ProcessTaskStartedEventArgs( } internal void ProcessTaskFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskFinishedEventArgs taskFinishedEventArgs) { if (!_buildCheckCentralContext.HasTaskInvocationActions) @@ -136,13 +136,13 @@ internal void ProcessTaskFinishedEventArgs( { // All task parameters have been recorded by now so remove the task from the dictionary and fire the registered build check actions. _tasksBeingExecuted.Remove(taskKey); - _buildCheckCentralContext.RunTaskInvocationActions(taskData.AnalysisData, buildAnalysisContext, ReportResult); + _buildCheckCentralContext.RunTaskInvocationActions(taskData.AnalysisData, analysisContext, ReportResult); } } } internal void ProcessTaskParameterEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskParameterEventArgs taskParameterEventArgs) { if (!_buildCheckCentralContext.HasTaskInvocationActions) @@ -177,13 +177,13 @@ internal void ProcessTaskParameterEventArgs( private static void ReportResult( BuildAnalyzerWrapper analyzerWrapper, - LoggingContext loggingContext, + IAnalysisContext analysisContext, BuildAnalyzerConfigurationInternal[] configPerRule, BuildCheckResult result) { if (!analyzerWrapper.BuildAnalyzer.SupportedRules.Contains(result.BuildAnalyzerRule)) { - loggingContext.LogErrorFromText(null, null, null, + analysisContext.DispatchAsErrorFromText(null, null, null, BuildEventFileInfo.Empty, $"The analyzer '{analyzerWrapper.BuildAnalyzer.FriendlyName}' reported a result for a rule '{result.BuildAnalyzerRule.Id}' that it does not support."); return; @@ -205,6 +205,6 @@ private static void ReportResult( // eventArgs.BuildEventContext = loggingContext.BuildEventContext; eventArgs.BuildEventContext = BuildEventContext.Invalid; - loggingContext.LogBuildEvent(eventArgs); + analysisContext.DispatchBuildEvent(eventArgs); } } diff --git a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs index 01864c7f66a..7a4e06c8ef8 100644 --- a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs @@ -37,24 +37,24 @@ internal enum BuildCheckDataSource internal interface IBuildCheckManager { void ProcessEvaluationFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, ProjectEvaluationFinishedEventArgs projectEvaluationFinishedEventArgs); void ProcessTaskStartedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskStartedEventArgs taskStartedEventArgs); void ProcessTaskFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskFinishedEventArgs taskFinishedEventArgs); void ProcessTaskParameterEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, TaskParameterEventArgs taskParameterEventArgs); void SetDataSource(BuildCheckDataSource buildCheckDataSource); - void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, AnalyzerLoggingContext loggingContext); + void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, IAnalysisContext analysisContext); Dictionary CreateAnalyzerTracingStats(); @@ -64,7 +64,7 @@ void ProcessTaskParameterEventArgs( // but as well from the ConnectorLogger - as even if interleaved, it gives the info // to manager about what analyzers need to be materialized and configuration fetched. // No unloading of analyzers is yet considered - once loaded it stays for whole build. - void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, AnalyzerLoggingContext loggingContext, string fullPath); + void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, IAnalysisContext analysisContext, string fullPath); void EndProjectEvaluation(BuildCheckDataSource buildCheckDataSource, BuildEventContext buildEventContext); diff --git a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs index c741591cc9a..b7aee30814e 100644 --- a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs @@ -18,7 +18,7 @@ public void Shutdown() } public void ProcessEvaluationFinishedEventArgs( - AnalyzerLoggingContext buildAnalysisContext, + IAnalysisContext analysisContext, ProjectEvaluationFinishedEventArgs projectEvaluationFinishedEventArgs) { } @@ -27,22 +27,27 @@ public void SetDataSource(BuildCheckDataSource buildCheckDataSource) { } - public void ProcessTaskStartedEventArgs(AnalyzerLoggingContext buildAnalysisContext, + public void ProcessTaskStartedEventArgs( + IAnalysisContext analysisContext, TaskStartedEventArgs taskStartedEventArgs) { } - public void ProcessTaskFinishedEventArgs(AnalyzerLoggingContext buildAnalysisContext, + public void ProcessTaskFinishedEventArgs( + IAnalysisContext analysisContext, TaskFinishedEventArgs taskFinishedEventArgs) { } - public void ProcessTaskParameterEventArgs(AnalyzerLoggingContext buildAnalysisContext, + public void ProcessTaskParameterEventArgs( + IAnalysisContext analysisContext, TaskParameterEventArgs taskParameterEventArgs) { } - public void ProcessAnalyzerAcquisition(AnalyzerAcquisitionData acquisitionData, AnalyzerLoggingContext loggingContext) + public void ProcessAnalyzerAcquisition( + AnalyzerAcquisitionData acquisitionData, + IAnalysisContext analysisContext) { } @@ -50,7 +55,7 @@ public void FinalizeProcessing(LoggingContext loggingContext) { } - public void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, AnalyzerLoggingContext loggingContext, string fullPath) + public void StartProjectEvaluation(BuildCheckDataSource buildCheckDataSource, IAnalysisContext analysisContext, string fullPath) { } diff --git a/src/Build/BuildCheck/Logging/AnalyzerLoggingContext.cs b/src/Build/BuildCheck/Logging/AnalyzerLoggingContext22.cs similarity index 64% rename from src/Build/BuildCheck/Logging/AnalyzerLoggingContext.cs rename to src/Build/BuildCheck/Logging/AnalyzerLoggingContext22.cs index b7e39eaa8b0..c94fb9d8d52 100644 --- a/src/Build/BuildCheck/Logging/AnalyzerLoggingContext.cs +++ b/src/Build/BuildCheck/Logging/AnalyzerLoggingContext22.cs @@ -7,15 +7,15 @@ namespace Microsoft.Build.Experimental.BuildCheck.Logging; -internal class AnalyzerLoggingContext : LoggingContext +internal class AnalyzerLoggingContext22 : LoggingContext { - public AnalyzerLoggingContext(ILoggingService loggingService, BuildEventContext eventContext) + public AnalyzerLoggingContext22(ILoggingService loggingService, BuildEventContext eventContext) : base(loggingService, eventContext) { IsValid = true; } - public AnalyzerLoggingContext(LoggingContext baseContext) : base(baseContext) + public AnalyzerLoggingContext22(LoggingContext baseContext) : base(baseContext) { IsValid = true; } diff --git a/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory.cs b/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs similarity index 53% rename from src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory.cs rename to src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs index 06b7dd6e033..e4e462bbcec 100644 --- a/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory.cs +++ b/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs @@ -7,8 +7,8 @@ namespace Microsoft.Build.Experimental.BuildCheck.Logging; -internal class AnalyzerLoggingContextFactory(ILoggingService loggingService) : IBuildAnalysisLoggingContextFactory +internal class AnalyzerLoggingContextFactory22(ILoggingService loggingService) : IBuildAnalysisLoggingContextFactory { - public AnalyzerLoggingContext CreateLoggingContext(BuildEventContext eventContext) => - new AnalyzerLoggingContext(loggingService, eventContext); + public AnalyzerLoggingContext22 CreateLoggingContext(BuildEventContext eventContext) => + new AnalyzerLoggingContext22(loggingService, eventContext); } diff --git a/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs b/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs index bbb562c5ec9..3cfac700dc9 100644 --- a/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs +++ b/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs @@ -8,5 +8,5 @@ namespace Microsoft.Build.Experimental.BuildCheck; internal interface IBuildAnalysisLoggingContextFactory { - AnalyzerLoggingContext CreateLoggingContext(BuildEventContext eventContext); + AnalyzerLoggingContext22 CreateLoggingContext(BuildEventContext eventContext); } diff --git a/src/Build/BuildCheck/OM/BuildCheckDataContext.cs b/src/Build/BuildCheck/OM/BuildCheckDataContext.cs index b47f510e165..01db72e1db3 100644 --- a/src/Build/BuildCheck/OM/BuildCheckDataContext.cs +++ b/src/Build/BuildCheck/OM/BuildCheckDataContext.cs @@ -41,19 +41,19 @@ public abstract class AnalysisData(string projectFilePath) public class BuildCheckDataContext where T : AnalysisData { private readonly BuildAnalyzerWrapper _analyzerWrapper; - private readonly LoggingContext _loggingContext; + private readonly IAnalysisContext _analysisContext; private readonly BuildAnalyzerConfigurationInternal[] _configPerRule; - private readonly Action _resultHandler; + private readonly Action _resultHandler; internal BuildCheckDataContext( BuildAnalyzerWrapper analyzerWrapper, - LoggingContext loggingContext, + IAnalysisContext loggingContext, BuildAnalyzerConfigurationInternal[] configPerRule, - Action resultHandler, + Action resultHandler, T data) { _analyzerWrapper = analyzerWrapper; - _loggingContext = loggingContext; + _analysisContext = loggingContext; _configPerRule = configPerRule; _resultHandler = resultHandler; Data = data; @@ -64,7 +64,7 @@ internal BuildCheckDataContext( /// /// public void ReportResult(BuildCheckResult result) - => _resultHandler(_analyzerWrapper, _loggingContext, _configPerRule, result); + => _resultHandler(_analyzerWrapper, _analysisContext, _configPerRule, result); /// /// Data to be analyzed. diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs index c8bdd009a8f..b6e6674cdf1 100644 --- a/src/Build/Instance/ProjectInstance.cs +++ b/src/Build/Instance/ProjectInstance.cs @@ -2940,7 +2940,7 @@ private void Initialize( _itemDefinitions = new RetrievableEntryHashSet(MSBuildNameIgnoreCaseComparer.Default); _hostServices = buildParameters.HostServices; this.ProjectRootElementCache = buildParameters.ProjectRootElementCache; - _loggingContext = new AnalyzerLoggingContext(loggingService, buildEventContext); + _loggingContext = new AnalyzerLoggingContext22(loggingService, buildEventContext); this.EvaluatedItemElements = new List(); _explicitToolsVersionSpecified = (explicitToolsVersion != null); diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index aeedba3e4c2..e74fdde5080 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -160,9 +160,13 @@ + + + + @@ -202,8 +206,8 @@ - - + + diff --git a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs index c9eeabed22a..7f8a16b91ca 100644 --- a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs +++ b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs @@ -41,7 +41,7 @@ public void ProcessAnalyzerAcquisitionTest(bool isAnalyzerRuleExist, string[] ex MockBuildCheckAcquisition(isAnalyzerRuleExist); MockEnabledDataSourcesDefinition(); - _testedInstance.ProcessAnalyzerAcquisition(new AnalyzerAcquisitionData("DummyPath"), new AnalyzerLoggingContext(_loggingService, new BuildEventContext(1, 2, 3, 4, 5, 6, 7))); + _testedInstance.ProcessAnalyzerAcquisition(new AnalyzerAcquisitionData("DummyPath"), new AnalysisLoggingContext(_loggingService, new BuildEventContext(1, 2, 3, 4, 5, 6, 7))); _logger.AllBuildEvents.Where(be => be.GetType() == typeof(BuildMessageEventArgs)).Select(be => be.Message).ToArray() .ShouldBeEquivalentTo(expectedMessages); @@ -67,7 +67,7 @@ internal sealed class BuildCheckAcquisitionModuleMock : IBuildCheckAcquisitionMo internal BuildCheckAcquisitionModuleMock(bool isAnalyzerRuleExistForTest) => _isAnalyzerRuleExistForTest = isAnalyzerRuleExistForTest; - public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, AnalyzerLoggingContext loggingContext) + public List CreateBuildAnalyzerFactories(AnalyzerAcquisitionData analyzerAcquisitionData, IAnalysisContext analysisContext) => _isAnalyzerRuleExistForTest ? new List() { () => new BuildAnalyzerRuleMock("Rule1"), () => new BuildAnalyzerRuleMock("Rule2") } : new List(); diff --git a/src/BuildCheck.UnitTests/DoubleWritesAnalyzer_Tests.cs b/src/BuildCheck.UnitTests/DoubleWritesAnalyzer_Tests.cs index fd1b601af06..b2d3b7bc543 100644 --- a/src/BuildCheck.UnitTests/DoubleWritesAnalyzer_Tests.cs +++ b/src/BuildCheck.UnitTests/DoubleWritesAnalyzer_Tests.cs @@ -41,7 +41,7 @@ public void TriggerTaskInvocationAction(TaskInvocationAnalysisData data) } } - private void ResultHandler(BuildAnalyzerWrapper wrapper, LoggingContext context, BuildAnalyzerConfigurationInternal[] configs, BuildCheckResult result) + private void ResultHandler(BuildAnalyzerWrapper wrapper, IAnalysisContext context, BuildAnalyzerConfigurationInternal[] configs, BuildCheckResult result) => Results.Add(result); } From fc86743f346349d90d299f7f0a1d2278ebf41977 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 19:19:10 +0200 Subject: [PATCH 05/41] add e2e test for analyze on build replay --- src/BuildCheck.UnitTests/EndToEndTests.cs | 83 +++++++++++++++++------ 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 98d53d0e384..e5cbf02a97d 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -31,11 +31,72 @@ public EndToEndTests(ITestOutputHelper output) public void Dispose() => _env.Dispose(); - [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] + // [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] + [Theory] [InlineData(true, true)] [InlineData(false, true)] [InlineData(false, false)] - public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool analysisRequested) + public void SampleAnalyzerIntegrationTest_AnalyzeOnBuild(bool buildInOutOfProcessNode, bool analysisRequested) + { + PrepareSampleProjectsAndConfig(buildInOutOfProcessNode, out TransientTestFile projectFile); + + string output = RunnerUtilities.ExecBootstrapedMSBuild( + $"{Path.GetFileName(projectFile.Path)} /m:1 -nr:False -restore" + + (analysisRequested ? " -analyze" : string.Empty), out bool success, false, _env.Output, timeoutMilliseconds: 120_000); + _env.Output.WriteLine(output); + + success.ShouldBeTrue(); + + // The analyzer warnings should appear - but only if analysis was requested. + if (analysisRequested) + { + output.ShouldContain("BC0101"); + output.ShouldContain("BC0102"); + } + else + { + output.ShouldNotContain("BC0101"); + output.ShouldNotContain("BC0102"); + } + } + + [Theory] + [InlineData(true, true)] + [InlineData(false, true)] + [InlineData(false, false)] + public void SampleAnalyzerIntegrationTest_AnalyzeOnBuildReplay(bool buildInOutOfProcessNode, bool analysisRequested) + { + PrepareSampleProjectsAndConfig(buildInOutOfProcessNode, out TransientTestFile projectFile); + + var projectDirectory = Path.GetDirectoryName(projectFile.Path); + string logFile = _env.ExpectFile(".binlog").Path; + + RunnerUtilities.ExecBootstrapedMSBuild( + $"{Path.GetFileName(projectFile.Path)} /m:1 -nr:False -restore -bl:{logFile}", + out bool success); + + success.ShouldBeTrue(); + + string output = RunnerUtilities.ExecBootstrapedMSBuild( + $"{logFile} -flp:logfile={Path.Combine(projectDirectory!, "logFile.log")};verbosity=diagnostic {(analysisRequested ? "-analyze" : string.Empty)}", + out success, false, _env.Output, timeoutMilliseconds: 130_000); + + _env.Output.WriteLine(output); + + success.ShouldBeTrue(); + + // The conflicting outputs warning appears - but only if analysis was requested + if (analysisRequested) + { + output.ShouldContain("BC0101"); + } + else + { + output.ShouldNotContain("BC0101"); + } + } + + private void PrepareSampleProjectsAndConfig(bool buildInOutOfProcessNode, out TransientTestFile projectFile) { TransientTestFolder workFolder = _env.CreateFolder(createFolder: true); TransientTestFile testFile = _env.CreateFile(workFolder, "somefile"); @@ -87,7 +148,7 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana """; - TransientTestFile projectFile = _env.CreateFile(workFolder, "FooBar.csproj", contents); + projectFile = _env.CreateFile(workFolder, "FooBar.csproj", contents); TransientTestFile projectFile2 = _env.CreateFile(workFolder, "FooBar-Copy.csproj", contents2); TransientTestFile config = _env.CreateFile(workFolder, ".editorconfig", @@ -116,22 +177,6 @@ public void SampleAnalyzerIntegrationTest(bool buildInOutOfProcessNode, bool ana _env.SetEnvironmentVariable("MSBUILDNOINPROCNODE", buildInOutOfProcessNode ? "1" : "0"); _env.SetEnvironmentVariable("MSBUILDLOGPROPERTIESANDITEMSAFTEREVALUATION", "1"); - string output = RunnerUtilities.ExecBootstrapedMSBuild( - $"{Path.GetFileName(projectFile.Path)} /m:1 -nr:False -restore" + - (analysisRequested ? " -analyze" : string.Empty), out bool success, false, _env.Output, timeoutMilliseconds: 120_000); - _env.Output.WriteLine(output); - success.ShouldBeTrue(); - // The analyzer warnings should appear - but only if analysis was requested. - if (analysisRequested) - { - output.ShouldContain("BC0101"); - output.ShouldContain("BC0102"); - } - else - { - output.ShouldNotContain("BC0101"); - output.ShouldNotContain("BC0102"); - } } [Theory] From 6961d579489a1201b93f0cbb6c5997b5d2f3015a Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 20:59:11 +0200 Subject: [PATCH 06/41] implement analyze on binary log replay --- .../BackEnd/BuildManager/BuildManager.cs | 19 ++++ .../AnalysisDispatchingContext.cs | 97 +++++++++++++++++++ .../AnalysisDispatchingContextFactory.cs | 24 +++++ .../AnalysisLoggingContext.cs | 0 .../AnalysisLoggingContextFactory.cs | 0 .../IAnalysisContext.cs | 0 .../IAnalysisContextFactory.cs | 0 src/Build/Microsoft.Build.csproj | 10 +- src/BuildCheck.UnitTests/EndToEndTests.cs | 4 +- src/MSBuild/XMake.cs | 12 ++- 10 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs create mode 100644 src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs rename src/Build/BuildCheck/Infrastructure/{AnalyzerContext => AnalysisContext}/AnalysisLoggingContext.cs (100%) rename src/Build/BuildCheck/Infrastructure/{AnalyzerContext => AnalysisContext}/AnalysisLoggingContextFactory.cs (100%) rename src/Build/BuildCheck/Infrastructure/{AnalyzerContext => AnalysisContext}/IAnalysisContext.cs (100%) rename src/Build/BuildCheck/Infrastructure/{AnalyzerContext => AnalysisContext}/IAnalysisContextFactory.cs (100%) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 54d7a8a347d..db6511ed258 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2951,6 +2951,25 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } + public void AttachBuildCheckForBinaryLogReplay(List loggers, EventArgsDispatcher eventDispatcher) + { + _buildParameters = new BuildParameters + { + IsBuildCheckEnabled = true, + }; + + var buildCheckManagerProvider = + ((IBuildComponentHost)this).GetComponent(BuildComponentType.BuildCheckManagerProvider) as IBuildCheckManagerProvider; + + buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); + + var buildCheckLogger = new BuildCheckConnectorLogger( + new AnalysisDispatchingContextFactory(eventDispatcher), + buildCheckManagerProvider.Instance); + + loggers.Add(buildCheckLogger); + } + /// /// Creates a logging service around the specified set of loggers. /// diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs new file mode 100644 index 00000000000..438288ba73c --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.Framework; +using Microsoft.Build.Logging; +using Microsoft.Build.Shared; + +namespace Microsoft.Build.Experimental.BuildCheck; + +internal class AnalysisDispatchingContext : IAnalysisContext +{ + private readonly EventArgsDispatcher _eventDispatcher; + private readonly BuildEventContext _eventContext; + + public AnalysisDispatchingContext( + EventArgsDispatcher eventDispatcher, + BuildEventContext eventContext) + { + _eventDispatcher = eventDispatcher; + _eventContext = eventContext; + } + + public BuildEventContext BuildEventContext => _eventContext; + + public void DispatchBuildEvent(BuildEventArgs buildEvent) + { + ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); + + BuildWarningEventArgs? warningEvent = buildEvent as BuildWarningEventArgs; + BuildErrorEventArgs? errorEvent = buildEvent as BuildErrorEventArgs; + + _eventDispatcher.Dispatch(buildEvent); + } + + public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) + { + ErrorUtilities.VerifyThrow(!string.IsNullOrEmpty(messageResourceName), "Need resource string for comment message."); + + DispatchAsCommentFromText(_eventContext, importance, ResourceUtilities.GetResourceString(messageResourceName), messageArgs); + } + + public void DispatchAsCommentFromText(MessageImportance importance, string message) + => DispatchAsCommentFromText(_eventContext, importance, message, messageArgs: null); + + private void DispatchAsCommentFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs) + { + ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null"); + ErrorUtilities.VerifyThrow(message != null, "message was null"); + + BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( + message, + helpKeyword: null, + senderName: "MSBuild", + importance, + DateTime.UtcNow, + messageArgs); + buildEvent.BuildEventContext = buildEventContext; + _eventDispatcher.Dispatch(buildEvent); + } + + public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) + { + ErrorUtilities.VerifyThrow(_eventContext != null, "Must specify the buildEventContext"); + ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file."); + ErrorUtilities.VerifyThrow(message != null, "Need error message."); + + string? subcategory = null; + + if (subcategoryResourceName != null) + { + subcategory = AssemblyResources.GetString(subcategoryResourceName); + } + + BuildErrorEventArgs buildEvent = + new BuildErrorEventArgs( + subcategory, + errorCode, + file!.File, + file.Line, + file.Column, + file.EndLine, + file.EndColumn, + message, + helpKeyword, + "MSBuild"); + + buildEvent.BuildEventContext = _eventContext; + + _eventDispatcher.Dispatch(buildEvent); + } +} diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs new file mode 100644 index 00000000000..2cda8d7480e --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.Framework; +using Microsoft.Build.Logging; + +namespace Microsoft.Build.Experimental.BuildCheck; + +internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory +{ + private readonly EventArgsDispatcher _eventDispatcher; + + public AnalysisDispatchingContextFactory(EventArgsDispatcher eventDispatcher) => _eventDispatcher = eventDispatcher; + + public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) + => new AnalysisDispatchingContext(_eventDispatcher, eventContext); +} diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs similarity index 100% rename from src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContext.cs rename to src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContextFactory.cs similarity index 100% rename from src/Build/BuildCheck/Infrastructure/AnalyzerContext/AnalysisLoggingContextFactory.cs rename to src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContextFactory.cs diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs similarity index 100% rename from src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContext.cs rename to src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs diff --git a/src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContextFactory.cs similarity index 100% rename from src/Build/BuildCheck/Infrastructure/AnalyzerContext/IAnalysisContextFactory.cs rename to src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContextFactory.cs diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index e74fdde5080..ad921af14cb 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -160,13 +160,15 @@ - - - + + + + + - + diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index e5cbf02a97d..a2d6069843c 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -64,7 +64,7 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBuild(bool buildInOutOfProces [InlineData(true, true)] [InlineData(false, true)] [InlineData(false, false)] - public void SampleAnalyzerIntegrationTest_AnalyzeOnBuildReplay(bool buildInOutOfProcessNode, bool analysisRequested) + public void SampleAnalyzerIntegrationTest_AnalyzeOnBunaryLogReplay(bool buildInOutOfProcessNode, bool analysisRequested) { PrepareSampleProjectsAndConfig(buildInOutOfProcessNode, out TransientTestFile projectFile); @@ -77,6 +77,8 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBuildReplay(bool buildInOutOf success.ShouldBeTrue(); + // _env.SetEnvironmentVariable("MSBUILDDEBUGONSTART", "1"); + string output = RunnerUtilities.ExecBootstrapedMSBuild( $"{logFile} -flp:logfile={Path.Combine(projectDirectory!, "logFile.log")};verbosity=diagnostic {(analysisRequested ? "-analyze" : string.Empty)}", out success, false, _env.Output, timeoutMilliseconds: 130_000); diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 088d2c00179..35cc5f7f0e3 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -808,7 +808,7 @@ public static ExitType Execute( // as if a build is happening if (FileUtilities.IsBinaryLogFilename(projectFile)) { - ReplayBinaryLog(projectFile, loggers, distributedLoggerRecords, cpuCount); + ReplayBinaryLog(projectFile, loggers.ToList(), distributedLoggerRecords, cpuCount, isBuildCheckEnabled); } else if (outputPropertiesItemsOrTargetResults && FileUtilities.IsSolutionFilename(projectFile)) { @@ -4404,12 +4404,18 @@ private static bool CreateAndConfigureLogger( private static void ReplayBinaryLog( string binaryLogFilePath, - ILogger[] loggers, + List loggers, IEnumerable distributedLoggerRecords, - int cpuCount) + int cpuCount, + bool isBuildCheckEnabled) { var replayEventSource = new BinaryLogReplayEventSource(); + if (isBuildCheckEnabled) + { + BuildManager.DefaultBuildManager.AttachBuildCheckForBinaryLogReplay(loggers, replayEventSource); + } + foreach (var distributedLoggerRecord in distributedLoggerRecords) { ILogger centralLogger = distributedLoggerRecord.CentralLogger; From b9f41657bd129ac39266075b6893014f6b3a8b8c Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 11 Jun 2024 21:15:08 +0200 Subject: [PATCH 07/41] remove old AnalyzerLoggingContext --- ...ngContext22.cs => AlwaysValidLoggingContext.cs} | 6 +++--- .../Logging/AnalyzerLoggingContextFactory22.cs | 14 -------------- .../Logging/IBuildAnalysisLoggingContextFactory.cs | 12 ------------ src/Build/Instance/ProjectInstance.cs | 2 +- src/Build/Microsoft.Build.csproj | 6 ++---- 5 files changed, 6 insertions(+), 34 deletions(-) rename src/Build/BuildCheck/Logging/{AnalyzerLoggingContext22.cs => AlwaysValidLoggingContext.cs} (64%) delete mode 100644 src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs delete mode 100644 src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs diff --git a/src/Build/BuildCheck/Logging/AnalyzerLoggingContext22.cs b/src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs similarity index 64% rename from src/Build/BuildCheck/Logging/AnalyzerLoggingContext22.cs rename to src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs index c94fb9d8d52..23b94ccbf9a 100644 --- a/src/Build/BuildCheck/Logging/AnalyzerLoggingContext22.cs +++ b/src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs @@ -7,15 +7,15 @@ namespace Microsoft.Build.Experimental.BuildCheck.Logging; -internal class AnalyzerLoggingContext22 : LoggingContext +internal class AlwaysValidLoggingContext : LoggingContext { - public AnalyzerLoggingContext22(ILoggingService loggingService, BuildEventContext eventContext) + public AlwaysValidLoggingContext(ILoggingService loggingService, BuildEventContext eventContext) : base(loggingService, eventContext) { IsValid = true; } - public AnalyzerLoggingContext22(LoggingContext baseContext) : base(baseContext) + public AlwaysValidLoggingContext(LoggingContext baseContext) : base(baseContext) { IsValid = true; } diff --git a/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs b/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs deleted file mode 100644 index e4e462bbcec..00000000000 --- a/src/Build/BuildCheck/Logging/AnalyzerLoggingContextFactory22.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Build.BackEnd.Logging; -using Microsoft.Build.Experimental.BuildCheck; -using Microsoft.Build.Framework; - -namespace Microsoft.Build.Experimental.BuildCheck.Logging; - -internal class AnalyzerLoggingContextFactory22(ILoggingService loggingService) : IBuildAnalysisLoggingContextFactory -{ - public AnalyzerLoggingContext22 CreateLoggingContext(BuildEventContext eventContext) => - new AnalyzerLoggingContext22(loggingService, eventContext); -} diff --git a/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs b/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs deleted file mode 100644 index 3cfac700dc9..00000000000 --- a/src/Build/BuildCheck/Logging/IBuildAnalysisLoggingContextFactory.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Build.Experimental.BuildCheck.Logging; -using Microsoft.Build.Framework; - -namespace Microsoft.Build.Experimental.BuildCheck; - -internal interface IBuildAnalysisLoggingContextFactory -{ - AnalyzerLoggingContext22 CreateLoggingContext(BuildEventContext eventContext); -} diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs index b6e6674cdf1..0a42413bac4 100644 --- a/src/Build/Instance/ProjectInstance.cs +++ b/src/Build/Instance/ProjectInstance.cs @@ -2940,7 +2940,7 @@ private void Initialize( _itemDefinitions = new RetrievableEntryHashSet(MSBuildNameIgnoreCaseComparer.Default); _hostServices = buildParameters.HostServices; this.ProjectRootElementCache = buildParameters.ProjectRootElementCache; - _loggingContext = new AnalyzerLoggingContext22(loggingService, buildEventContext); + _loggingContext = new AlwaysValidLoggingContext(loggingService, buildEventContext); this.EvaluatedItemElements = new List(); _explicitToolsVersionSpecified = (explicitToolsVersion != null); diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index ad921af14cb..7bea25150ac 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -1,4 +1,4 @@ - + @@ -195,7 +195,6 @@ - @@ -208,8 +207,7 @@ - - + From 6ed4a7919b60ac5edda15360f245af24c703bf04 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 11:51:22 +0200 Subject: [PATCH 08/41] remove Microsoft.Build.Experimental.BuildCheck.Logging --- .../BackEnd/BuildManager/BuildManager.cs | 1 - .../RequestBuilder/RequestBuilder.cs | 1 - .../BuildCheckAcquisitionModule.cs | 1 - .../IBuildCheckAcquisitionModule.cs | 1 - .../BuildCheckManagerProvider.cs | 1 - .../Infrastructure/BuildEventsProcessor.cs | 3 +-- .../Infrastructure/IBuildCheckManager.cs | 1 - .../Infrastructure/NullBuildCheckManager.cs | 1 - .../Logging/AlwaysValidLoggingContext.cs | 22 ------------------- src/Build/Instance/ProjectInstance.cs | 11 ++++++++-- src/Build/Microsoft.Build.csproj | 1 - .../BuildCheckManagerProviderTests.cs | 1 - 12 files changed, 10 insertions(+), 35 deletions(-) delete mode 100644 src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index db6511ed258..04dde92b045 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -22,7 +22,6 @@ using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.SdkResolution; using Microsoft.Build.Experimental.BuildCheck.Infrastructure; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Evaluation; using Microsoft.Build.Eventing; using Microsoft.Build.Exceptions; diff --git a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs index eb33f28d019..f6422b28e4c 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs @@ -17,7 +17,6 @@ using Microsoft.Build.Execution; using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.BuildCheck.Infrastructure; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; using Microsoft.Build.Internal; using Microsoft.Build.Shared; diff --git a/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs b/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs index 973b3f6025e..77c8d7d4599 100644 --- a/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs +++ b/src/Build/BuildCheck/Acquisition/BuildCheckAcquisitionModule.cs @@ -10,7 +10,6 @@ using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Framework; using Microsoft.Build.Shared; -using Microsoft.Build.Experimental.BuildCheck.Logging; namespace Microsoft.Build.Experimental.BuildCheck.Acquisition; diff --git a/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs b/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs index 99a41e269c8..20259725b4f 100644 --- a/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs +++ b/src/Build/BuildCheck/Acquisition/IBuildCheckAcquisitionModule.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Microsoft.Build.Experimental.BuildCheck.Infrastructure; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; namespace Microsoft.Build.Experimental.BuildCheck.Acquisition; diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index e0afec2b677..6ea3a7cbd23 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -11,7 +11,6 @@ using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.BuildCheck.Acquisition; using Microsoft.Build.Experimental.BuildCheck.Analyzers; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; using Microsoft.Build.Shared; diff --git a/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs b/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs index b38a3bd4ace..87ab7e75054 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildEventsProcessor.cs @@ -12,12 +12,11 @@ using Microsoft.Build.BackEnd; using Microsoft.Build.BackEnd.Components.Caching; using Microsoft.Build.BackEnd.Logging; -using Microsoft.Build.Experimental.BuildCheck.Analyzers; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Collections; using Microsoft.Build.Construction; using Microsoft.Build.Evaluation; using Microsoft.Build.Experimental.BuildCheck; +using Microsoft.Build.Experimental.BuildCheck.Analyzers; using Microsoft.Build.Framework; using Microsoft.Build.Shared; diff --git a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs index 7a4e06c8ef8..41b4e152ce5 100644 --- a/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/IBuildCheckManager.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Experimental.BuildCheck.Acquisition; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; namespace Microsoft.Build.Experimental.BuildCheck; diff --git a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs index b7aee30814e..5df770b8fe1 100644 --- a/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs +++ b/src/Build/BuildCheck/Infrastructure/NullBuildCheckManager.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Experimental.BuildCheck.Acquisition; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Framework; diff --git a/src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs b/src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs deleted file mode 100644 index 23b94ccbf9a..00000000000 --- a/src/Build/BuildCheck/Logging/AlwaysValidLoggingContext.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Build.BackEnd.Logging; -using Microsoft.Build.Experimental.BuildCheck; -using Microsoft.Build.Framework; - -namespace Microsoft.Build.Experimental.BuildCheck.Logging; - -internal class AlwaysValidLoggingContext : LoggingContext -{ - public AlwaysValidLoggingContext(ILoggingService loggingService, BuildEventContext eventContext) - : base(loggingService, eventContext) - { - IsValid = true; - } - - public AlwaysValidLoggingContext(LoggingContext baseContext) : base(baseContext) - { - IsValid = true; - } -} diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs index 0a42413bac4..abae6663917 100644 --- a/src/Build/Instance/ProjectInstance.cs +++ b/src/Build/Instance/ProjectInstance.cs @@ -14,7 +14,6 @@ using Microsoft.Build.BackEnd; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.SdkResolution; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Collections; using Microsoft.Build.Construction; using Microsoft.Build.Definition; @@ -2940,7 +2939,7 @@ private void Initialize( _itemDefinitions = new RetrievableEntryHashSet(MSBuildNameIgnoreCaseComparer.Default); _hostServices = buildParameters.HostServices; this.ProjectRootElementCache = buildParameters.ProjectRootElementCache; - _loggingContext = new AlwaysValidLoggingContext(loggingService, buildEventContext); + _loggingContext = new GenericLoggingContext(loggingService, buildEventContext); this.EvaluatedItemElements = new List(); _explicitToolsVersionSpecified = (explicitToolsVersion != null); @@ -3223,5 +3222,13 @@ private void CreatePropertiesSnapshot(ICollection properties, b _properties.Set(instance); } } + + internal class GenericLoggingContext : LoggingContext + { + public GenericLoggingContext(ILoggingService loggingService, BuildEventContext eventContext) + : base(loggingService, eventContext) => IsValid = true; + + public GenericLoggingContext(LoggingContext baseContext) : base(baseContext) => IsValid = true; + } } } diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 7bea25150ac..1b9c5a81071 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -207,7 +207,6 @@ - diff --git a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs index 7f8a16b91ca..485a1b1b40c 100644 --- a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs +++ b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs @@ -9,7 +9,6 @@ using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.BuildCheck.Acquisition; using Microsoft.Build.Experimental.BuildCheck.Infrastructure; -using Microsoft.Build.Experimental.BuildCheck.Logging; using Microsoft.Build.Framework; using Microsoft.Build.UnitTests; using Shouldly; From b732de8eef79d4e37f429a1c9859265691bf920a Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 12:51:14 +0200 Subject: [PATCH 09/41] create EventCreatorHelper --- .../Logging/LoggingServiceLogMethods.cs | 37 +---------- .../BackEnd/Shared/EventsCreatorHelper.cs | 63 +++++++++++++++++++ .../AnalysisDispatchingContext.cs | 41 +----------- src/Build/Microsoft.Build.csproj | 1 + 4 files changed, 70 insertions(+), 72 deletions(-) create mode 100644 src/Build/BackEnd/Shared/EventsCreatorHelper.cs diff --git a/src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs b/src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs index 547554d06d8..3cb0ff03393 100644 --- a/src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs +++ b/src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Framework; using Microsoft.Build.Framework.Profiler; using Microsoft.Build.Shared; @@ -69,17 +70,8 @@ public void LogCommentFromText(BuildEventContext buildEventContext, MessageImpor { if (!OnlyLogCriticalEvents) { - ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null"); - ErrorUtilities.VerifyThrow(message != null, "message was null"); + BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs); - BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( - message, - helpKeyword: null, - senderName: "MSBuild", - importance, - DateTime.UtcNow, - messageArgs); - buildEvent.BuildEventContext = buildEventContext; ProcessLoggingEvent(buildEvent); } } @@ -136,31 +128,8 @@ public void LogError(BuildEventContext buildEventContext, string subcategoryReso /// Message is null public void LogErrorFromText(BuildEventContext buildEventContext, string subcategoryResourceName, string errorCode, string helpKeyword, BuildEventFileInfo file, string message) { - ErrorUtilities.VerifyThrow(buildEventContext != null, "Must specify the buildEventContext"); - ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file."); - ErrorUtilities.VerifyThrow(message != null, "Need error message."); + BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(buildEventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); - string subcategory = null; - - if (subcategoryResourceName != null) - { - subcategory = AssemblyResources.GetString(subcategoryResourceName); - } - - BuildErrorEventArgs buildEvent = - new BuildErrorEventArgs( - subcategory, - errorCode, - file.File, - file.Line, - file.Column, - file.EndLine, - file.EndColumn, - message, - helpKeyword, - "MSBuild"); - - buildEvent.BuildEventContext = buildEventContext; if (buildEvent.ProjectFile == null && buildEventContext.ProjectContextId != BuildEventContext.InvalidProjectContextId) { _projectFileMap.TryGetValue(buildEventContext.ProjectContextId, out string projectFile); diff --git a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs new file mode 100644 index 00000000000..d7f869d73c7 --- /dev/null +++ b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs @@ -0,0 +1,63 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Shared; + +namespace Microsoft.Build.BackEnd.Shared; + +internal static class EventsCreatorHelper +{ + public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs) + { + ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null"); + ErrorUtilities.VerifyThrow(message != null, "message was null"); + + BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( + message, + helpKeyword: null, + senderName: "MSBuild", + importance, + DateTime.UtcNow, + messageArgs); + buildEvent.BuildEventContext = buildEventContext; + + return buildEvent; + } + + public static BuildErrorEventArgs CreateErrorEventFromText(BuildEventContext buildEventContext, string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) + { + ErrorUtilities.VerifyThrow(buildEventContext != null, "Must specify the buildEventContext"); + ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file."); + ErrorUtilities.VerifyThrow(message != null, "Need error message."); + + string? subcategory = null; + + if (subcategoryResourceName != null) + { + subcategory = AssemblyResources.GetString(subcategoryResourceName); + } + + BuildErrorEventArgs buildEvent = + new BuildErrorEventArgs( + subcategory, + errorCode, + file!.File, + file.Line, + file.Column, + file.EndLine, + file.EndColumn, + message, + helpKeyword, + "MSBuild"); + + buildEvent.BuildEventContext = buildEventContext; + + return buildEvent; + } +} diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 438288ba73c..e26200f6f5d 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using Microsoft.Build.BackEnd.Logging; +using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Framework; using Microsoft.Build.Logging; using Microsoft.Build.Shared; @@ -32,9 +33,6 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) { ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); - BuildWarningEventArgs? warningEvent = buildEvent as BuildWarningEventArgs; - BuildErrorEventArgs? errorEvent = buildEvent as BuildErrorEventArgs; - _eventDispatcher.Dispatch(buildEvent); } @@ -50,47 +48,14 @@ public void DispatchAsCommentFromText(MessageImportance importance, string messa private void DispatchAsCommentFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs) { - ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null"); - ErrorUtilities.VerifyThrow(message != null, "message was null"); + BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs); - BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( - message, - helpKeyword: null, - senderName: "MSBuild", - importance, - DateTime.UtcNow, - messageArgs); - buildEvent.BuildEventContext = buildEventContext; _eventDispatcher.Dispatch(buildEvent); } public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { - ErrorUtilities.VerifyThrow(_eventContext != null, "Must specify the buildEventContext"); - ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file."); - ErrorUtilities.VerifyThrow(message != null, "Need error message."); - - string? subcategory = null; - - if (subcategoryResourceName != null) - { - subcategory = AssemblyResources.GetString(subcategoryResourceName); - } - - BuildErrorEventArgs buildEvent = - new BuildErrorEventArgs( - subcategory, - errorCode, - file!.File, - file.Line, - file.Column, - file.EndLine, - file.EndColumn, - message, - helpKeyword, - "MSBuild"); - - buildEvent.BuildEventContext = _eventContext; + BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); _eventDispatcher.Dispatch(buildEvent); } diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 1b9c5a81071..b46d680e870 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -151,6 +151,7 @@ + From 4c08a5eec0f15459d205e92d10775fb01a09870a Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 12:55:37 +0200 Subject: [PATCH 10/41] renamed BuildEventArgsDispatcher file to EventArgsDispatcher according to the class name --- ...rgsDispatcher.cs => EventArgsDispatcher.cs} | 18 ++++++++++++++++++ src/Build/Microsoft.Build.csproj | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) rename src/Build/Logging/BinaryLogger/{BuildEventArgsDispatcher.cs => EventArgsDispatcher.cs} (90%) diff --git a/src/Build/Logging/BinaryLogger/BuildEventArgsDispatcher.cs b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs similarity index 90% rename from src/Build/Logging/BinaryLogger/BuildEventArgsDispatcher.cs rename to src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs index db24d791ed2..cf56776752c 100644 --- a/src/Build/Logging/BinaryLogger/BuildEventArgsDispatcher.cs +++ b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs @@ -106,6 +106,24 @@ public class EventArgsDispatcher : IEventSource /// public void Dispatch(BuildEventArgs buildEvent) { + BuildWarningEventArgs warningEvent = null; + BuildErrorEventArgs errorEvent = null; + BuildMessageEventArgs messageEvent = null; + + if ((warningEvent = buildEvent as BuildWarningEventArgs) != null && + warningEvent.ProjectFile == null) + { + } + else if ((errorEvent = buildEvent as BuildErrorEventArgs) != null && + errorEvent.ProjectFile == null) + { + } + else if ((messageEvent = buildEvent as BuildMessageEventArgs) != null && + messageEvent.ProjectFile == null) + { + } + + if (buildEvent is BuildMessageEventArgs buildMessageEventArgs) { MessageRaised?.Invoke(null, buildMessageEventArgs); diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index b46d680e870..3843fba847f 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -571,7 +571,7 @@ - + From 0b2e5b5bb4cd67ca800e6d6cb4d2a4702dda7fab Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 17:46:20 +0200 Subject: [PATCH 11/41] 1. decoupled event handling from BuildCheckConnectorLogger in order to reuse it for binlog replay 2. removed inheritance of EventArgsDispatcher from BinaryLogReplayEventSource, instead use it as a field 3. created BuildCheckEventArgsDispatcher --- .../BackEnd/BuildManager/BuildManager.cs | 8 +- .../AnalysisDispatchingContext.cs | 22 +++ .../BuildCheckBuildEventHandler.cs | 154 ++++++++++++++++++ .../BuildCheckConnectorLogger.cs | 129 +-------------- .../BuildCheckEventArgsDispatcher.cs | 31 ++++ .../BinaryLogReplayEventSource.cs | 59 ++++++- .../BinaryLogger/EventArgsDispatcher.cs | 35 ++-- src/Build/Microsoft.Build.csproj | 2 + src/MSBuild/XMake.cs | 9 +- 9 files changed, 289 insertions(+), 160 deletions(-) create mode 100644 src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs create mode 100644 src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 04dde92b045..61bdba09094 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,7 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public void AttachBuildCheckForBinaryLogReplay(List loggers, EventArgsDispatcher eventDispatcher) + public BinaryLogReplayEventSource GetBinaryLogReplayEventSourceWithAttachedBuildCheck() { _buildParameters = new BuildParameters { @@ -2962,11 +2962,9 @@ public void AttachBuildCheckForBinaryLogReplay(List loggers, EventArgsD buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); - var buildCheckLogger = new BuildCheckConnectorLogger( - new AnalysisDispatchingContextFactory(eventDispatcher), - buildCheckManagerProvider.Instance); + var eventDispatcher = new BuildCheckEventArgsDispatcher(buildCheckManagerProvider.Instance); - loggers.Add(buildCheckLogger); + return new BinaryLogReplayEventSource(eventDispatcher); } /// diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index e26200f6f5d..f4ffd7727a6 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -33,6 +33,23 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) { ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); + // BuildWarningEventArgs? warningEvent = null; + // BuildErrorEventArgs? errorEvent = null; + // BuildMessageEventArgs? messageEvent = null; + + // if ((warningEvent = buildEvent as BuildWarningEventArgs) != null && + // warningEvent.ProjectFile == null) + // { + // } + // else if ((errorEvent = buildEvent as BuildErrorEventArgs) != null && + // errorEvent.ProjectFile == null) + // { + // } + // else if ((messageEvent = buildEvent as BuildMessageEventArgs) != null && + // messageEvent.ProjectFile == null) + // { + // } + _eventDispatcher.Dispatch(buildEvent); } @@ -57,6 +74,11 @@ public void DispatchAsErrorFromText(string? subcategoryResourceName, string? err { BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); + // if (buildEvent.ProjectFile == null && + // _eventContext!.ProjectContextId != BuildEventContext.InvalidProjectContextId) + // { + // } + _eventDispatcher.Dispatch(buildEvent); } } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs new file mode 100644 index 00000000000..dc4c9a19bc9 --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Experimental.BuildCheck; +using Microsoft.Build.Experimental.BuildCheck.Acquisition; +using Microsoft.Build.Experimental.BuildCheck.Utilities; +using Microsoft.Build.Framework; + +namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; + +internal class BuildCheckBuildEventHandler +{ + private readonly IBuildCheckManager _buildCheckManager; + private readonly IAnalysisContextFactory _analyzerContextFactory; + + private readonly Dictionary> _eventHandlers; + + internal BuildCheckBuildEventHandler( + IAnalysisContextFactory analyzerContextFactory, + IBuildCheckManager buildCheckManager) + { + _buildCheckManager = buildCheckManager; + _analyzerContextFactory = analyzerContextFactory; + + _eventHandlers = new() + { + { typeof(ProjectEvaluationFinishedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationFinishedEvent((ProjectEvaluationFinishedEventArgs)e) }, + { typeof(ProjectEvaluationStartedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationStartedEvent((ProjectEvaluationStartedEventArgs)e) }, + { typeof(ProjectStartedEventArgs), (BuildEventArgs e) => _buildCheckManager.StartProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, + { typeof(ProjectFinishedEventArgs), (BuildEventArgs e) => _buildCheckManager.EndProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, + { typeof(BuildCheckTracingEventArgs), (BuildEventArgs e) => HandleBuildCheckTracingEvent((BuildCheckTracingEventArgs)e) }, + { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => HandleBuildCheckAcquisitionEvent((BuildCheckAcquisitionEventArgs)e) }, + { typeof(TaskStartedEventArgs), (BuildEventArgs e) => HandleTaskStartedEvent((TaskStartedEventArgs)e) }, + { typeof(TaskFinishedEventArgs), (BuildEventArgs e) => HandleTaskFinishedEvent((TaskFinishedEventArgs)e) }, + { typeof(TaskParameterEventArgs), (BuildEventArgs e) => HandleTaskParameterEvent((TaskParameterEventArgs)e) }, + { typeof(BuildFinishedEventArgs), (BuildEventArgs e) => HandleBuildFinishedEvent((BuildFinishedEventArgs)e) }, + }; + } + + public void HandleBuildEvent(BuildEventArgs e) + { + if (_eventHandlers.TryGetValue(e.GetType(), out Action? handler)) + { + handler(e); + } + } + + private void HandleProjectEvaluationFinishedEvent(ProjectEvaluationFinishedEventArgs eventArgs) + { + if (!IsMetaProjFile(eventArgs.ProjectFile)) + { + _buildCheckManager.ProcessEvaluationFinishedEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); + + _buildCheckManager.EndProjectEvaluation(BuildCheckDataSource.EventArgs, eventArgs.BuildEventContext!); + } + } + + private void HandleProjectEvaluationStartedEvent(ProjectEvaluationStartedEventArgs eventArgs) + { + if (!IsMetaProjFile(eventArgs.ProjectFile)) + { + _buildCheckManager.StartProjectEvaluation( + BuildCheckDataSource.EventArgs, + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs.ProjectFile!); + } + } + + private void HandleBuildCheckTracingEvent(BuildCheckTracingEventArgs eventArgs) + { + if (!eventArgs.IsAggregatedGlobalReport) + { + _stats.Merge(eventArgs.TracingData, (span1, span2) => span1 + span2); + } + } + + private void HandleTaskStartedEvent(TaskStartedEventArgs eventArgs) + => _buildCheckManager.ProcessTaskStartedEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); + + private void HandleTaskFinishedEvent(TaskFinishedEventArgs eventArgs) + => _buildCheckManager.ProcessTaskFinishedEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); + + private void HandleTaskParameterEvent(TaskParameterEventArgs eventArgs) + => _buildCheckManager.ProcessTaskParameterEventArgs( + _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), + eventArgs); + + private void HandleBuildCheckAcquisitionEvent(BuildCheckAcquisitionEventArgs eventArgs) + => _buildCheckManager.ProcessAnalyzerAcquisition( + eventArgs.ToAnalyzerAcquisitionData(), + _analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(eventArgs))); + + private bool IsMetaProjFile(string? projectFile) => !string.IsNullOrEmpty(projectFile) && projectFile!.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase); + + private readonly Dictionary _stats = new Dictionary(); + + private void HandleBuildFinishedEvent(BuildFinishedEventArgs eventArgs) + { + _stats.Merge(_buildCheckManager.CreateAnalyzerTracingStats(), (span1, span2) => span1 + span2); + + LogAnalyzerStats(_analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(eventArgs))); + } + + private void LogAnalyzerStats(IAnalysisContext analysisContext) + { + Dictionary infraStats = new Dictionary(); + Dictionary analyzerStats = new Dictionary(); + + foreach (var stat in _stats) + { + if (stat.Key.StartsWith(BuildCheckConstants.infraStatPrefix)) + { + string newKey = stat.Key.Substring(BuildCheckConstants.infraStatPrefix.Length); + infraStats[newKey] = stat.Value; + } + else + { + analyzerStats[stat.Key] = stat.Value; + } + } + + BuildCheckTracingEventArgs statEvent = new BuildCheckTracingEventArgs(_stats, true) + { BuildEventContext = analysisContext.BuildEventContext }; + + analysisContext.DispatchBuildEvent(statEvent); + + analysisContext.DispatchAsCommentFromText(MessageImportance.Low, $"BuildCheck run times{Environment.NewLine}"); + string infraData = BuildCsvString("Infrastructure run times", infraStats); + analysisContext.DispatchAsCommentFromText(MessageImportance.Low, infraData); + string analyzerData = BuildCsvString("Analyzer run times", analyzerStats); + analysisContext.DispatchAsCommentFromText(MessageImportance.Low, analyzerData); + } + + private string BuildCsvString(string title, Dictionary rowData) + => title + Environment.NewLine + String.Join(Environment.NewLine, rowData.Select(a => $"{a.Key},{a.Value}")) + Environment.NewLine; + + private BuildEventContext GetBuildEventContext(BuildEventArgs e) => e.BuildEventContext + ?? new BuildEventContext( + BuildEventContext.InvalidNodeId, + BuildEventContext.InvalidTargetId, + BuildEventContext.InvalidProjectContextId, + BuildEventContext.InvalidTaskId); +} diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index 22f841bab27..3b6330a5a50 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -14,7 +14,7 @@ namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; internal sealed class BuildCheckConnectorLogger : ILogger { - private readonly Dictionary> _eventHandlers; + private readonly BuildCheckBuildEventHandler _eventHandler; private readonly IBuildCheckManager _buildCheckManager; private readonly IAnalysisContextFactory _analyzerContextFactory; @@ -24,7 +24,7 @@ internal BuildCheckConnectorLogger( { _buildCheckManager = buildCheckManager; _analyzerContextFactory = analyzerContextFactory; - _eventHandlers = GetBuildEventHandlers(); + _eventHandler = new BuildCheckBuildEventHandler(analyzerContextFactory, buildCheckManager); } public LoggerVerbosity Verbosity { get; set; } @@ -34,7 +34,6 @@ internal BuildCheckConnectorLogger( public void Initialize(IEventSource eventSource) { eventSource.AnyEventRaised += EventSource_AnyEventRaised; - eventSource.BuildFinished += EventSource_BuildFinished; if (eventSource is IEventSource3 eventSource3) { @@ -51,128 +50,6 @@ public void Shutdown() { } - private void HandleProjectEvaluationFinishedEvent(ProjectEvaluationFinishedEventArgs eventArgs) - { - if (!IsMetaProjFile(eventArgs.ProjectFile)) - { - _buildCheckManager.ProcessEvaluationFinishedEventArgs( - _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), - eventArgs); - - _buildCheckManager.EndProjectEvaluation(BuildCheckDataSource.EventArgs, eventArgs.BuildEventContext!); - } - } - - private void HandleProjectEvaluationStartedEvent(ProjectEvaluationStartedEventArgs eventArgs) - { - if (!IsMetaProjFile(eventArgs.ProjectFile)) - { - _buildCheckManager.StartProjectEvaluation( - BuildCheckDataSource.EventArgs, - _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), - eventArgs.ProjectFile!); - } - } - - private void HandleBuildCheckTracingEvent(BuildCheckTracingEventArgs eventArgs) - { - if (!eventArgs.IsAggregatedGlobalReport) - { - _stats.Merge(eventArgs.TracingData, (span1, span2) => span1 + span2); - } - } - - private void HandleTaskStartedEvent(TaskStartedEventArgs eventArgs) - => _buildCheckManager.ProcessTaskStartedEventArgs( - _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), - eventArgs); - - private void HandleTaskFinishedEvent(TaskFinishedEventArgs eventArgs) - => _buildCheckManager.ProcessTaskFinishedEventArgs( - _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), - eventArgs); - - private void HandleTaskParameterEvent(TaskParameterEventArgs eventArgs) - => _buildCheckManager.ProcessTaskParameterEventArgs( - _analyzerContextFactory.CreateAnalysisContext(eventArgs.BuildEventContext!), - eventArgs); - - private void HandleBuildCheckAcquisitionEvent(BuildCheckAcquisitionEventArgs eventArgs) - => _buildCheckManager.ProcessAnalyzerAcquisition( - eventArgs.ToAnalyzerAcquisitionData(), - _analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(eventArgs))); - - private bool IsMetaProjFile(string? projectFile) => !string.IsNullOrEmpty(projectFile) && projectFile!.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase); - private void EventSource_AnyEventRaised(object sender, BuildEventArgs e) - { - if (_eventHandlers.TryGetValue(e.GetType(), out Action? handler)) - { - handler(e); - } - } - - private readonly Dictionary _stats = new Dictionary(); - - private void EventSource_BuildFinished(object sender, BuildFinishedEventArgs e) - { - _stats.Merge(_buildCheckManager.CreateAnalyzerTracingStats(), (span1, span2) => span1 + span2); - - LogAnalyzerStats(_analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(e))); - } - - private void LogAnalyzerStats(IAnalysisContext analysisContext) - { - Dictionary infraStats = new Dictionary(); - Dictionary analyzerStats = new Dictionary(); - - foreach (var stat in _stats) - { - if (stat.Key.StartsWith(BuildCheckConstants.infraStatPrefix)) - { - string newKey = stat.Key.Substring(BuildCheckConstants.infraStatPrefix.Length); - infraStats[newKey] = stat.Value; - } - else - { - analyzerStats[stat.Key] = stat.Value; - } - } - - BuildCheckTracingEventArgs statEvent = new BuildCheckTracingEventArgs(_stats, true) - { BuildEventContext = analysisContext.BuildEventContext }; - - analysisContext.DispatchBuildEvent(statEvent); - - analysisContext.DispatchAsCommentFromText(MessageImportance.Low, $"BuildCheck run times{Environment.NewLine}"); - string infraData = BuildCsvString("Infrastructure run times", infraStats); - analysisContext.DispatchAsCommentFromText(MessageImportance.Low, infraData); - string analyzerData = BuildCsvString("Analyzer run times", analyzerStats); - analysisContext.DispatchAsCommentFromText(MessageImportance.Low, analyzerData); - } - - private string BuildCsvString(string title, Dictionary rowData) - { - return title + Environment.NewLine + String.Join(Environment.NewLine, rowData.Select(a => $"{a.Key},{a.Value}")) + Environment.NewLine; - } - - private Dictionary> GetBuildEventHandlers() => new() - { - { typeof(ProjectEvaluationFinishedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationFinishedEvent((ProjectEvaluationFinishedEventArgs)e) }, - { typeof(ProjectEvaluationStartedEventArgs), (BuildEventArgs e) => HandleProjectEvaluationStartedEvent((ProjectEvaluationStartedEventArgs)e) }, - { typeof(ProjectStartedEventArgs), (BuildEventArgs e) => _buildCheckManager.StartProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, - { typeof(ProjectFinishedEventArgs), (BuildEventArgs e) => _buildCheckManager.EndProjectRequest(BuildCheckDataSource.EventArgs, e.BuildEventContext!) }, - { typeof(BuildCheckTracingEventArgs), (BuildEventArgs e) => HandleBuildCheckTracingEvent((BuildCheckTracingEventArgs)e) }, - { typeof(BuildCheckAcquisitionEventArgs), (BuildEventArgs e) => HandleBuildCheckAcquisitionEvent((BuildCheckAcquisitionEventArgs)e) }, - { typeof(TaskStartedEventArgs), (BuildEventArgs e) => HandleTaskStartedEvent((TaskStartedEventArgs)e) }, - { typeof(TaskFinishedEventArgs), (BuildEventArgs e) => HandleTaskFinishedEvent((TaskFinishedEventArgs)e) }, - { typeof(TaskParameterEventArgs), (BuildEventArgs e) => HandleTaskParameterEvent((TaskParameterEventArgs)e) }, - }; - - private BuildEventContext GetBuildEventContext(BuildEventArgs e) => e.BuildEventContext - ?? new BuildEventContext( - BuildEventContext.InvalidNodeId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTaskId); + => _eventHandler.HandleBuildEvent(e); } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs new file mode 100644 index 00000000000..850f398f30f --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Experimental.BuildCheck; +using Microsoft.Build.Experimental.BuildCheck.Infrastructure; +using Microsoft.Build.Framework; +using Microsoft.Build.Logging; + +namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; + +public class BuildCheckEventArgsDispatcher : EventArgsDispatcher +{ + private readonly BuildCheckBuildEventHandler _buildCheckEventHandler; + + internal BuildCheckEventArgsDispatcher(IBuildCheckManager buildCheckManager) + => _buildCheckEventHandler = new BuildCheckBuildEventHandler( + new AnalysisDispatchingContextFactory(this), + buildCheckManager); + + public override void Dispatch(BuildEventArgs buildEvent) + { + base.Dispatch(buildEvent); + + _buildCheckEventHandler.HandleBuildEvent(buildEvent); + } +} diff --git a/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs b/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs index abf9e4e80c9..85c07f6adee 100644 --- a/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs +++ b/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs @@ -59,15 +59,30 @@ void DeferredInitialize( /// by implementing IEventSource and raising corresponding events. /// /// The class is public so that we can call it from MSBuild.exe when replaying a log file. - public sealed class BinaryLogReplayEventSource : EventArgsDispatcher, - IBinaryLogReplaySource + public sealed class BinaryLogReplayEventSource : IBinaryLogReplaySource { private int? _fileFormatVersion; private int? _minimumReaderVersion; + private readonly EventArgsDispatcher _eventDispatcher; + public int FileFormatVersion => _fileFormatVersion ?? throw new InvalidOperationException(ResourceUtilities.GetResourceString("Binlog_Source_VersionUninitialized")); public int MinimumReaderVersion => _minimumReaderVersion ?? throw new InvalidOperationException(ResourceUtilities.GetResourceString("Binlog_Source_VersionUninitialized")); + public BinaryLogReplayEventSource() + { + _eventDispatcher = new EventArgsDispatcher(); + + InitializeEventHandlers(); + } + + public BinaryLogReplayEventSource(EventArgsDispatcher eventDispatcher) + { + _eventDispatcher = eventDispatcher; + + InitializeEventHandlers(); + } + /// Touches the static constructor /// to ensure it initializes /// and @@ -81,9 +96,43 @@ static BinaryLogReplayEventSource() /// public bool AllowForwardCompatibility { private get; init; } +#region EventHandlers /// public event Action? RecoverableReadError; + public event BuildMessageEventHandler? MessageRaised; + public event BuildErrorEventHandler? ErrorRaised; + public event BuildWarningEventHandler? WarningRaised; + public event BuildStartedEventHandler? BuildStarted; + public event BuildFinishedEventHandler? BuildFinished; + public event ProjectStartedEventHandler? ProjectStarted; + public event ProjectFinishedEventHandler? ProjectFinished; + public event TargetStartedEventHandler? TargetStarted; + public event TargetFinishedEventHandler? TargetFinished; + public event TaskStartedEventHandler? TaskStarted; + public event TaskFinishedEventHandler? TaskFinished; + public event CustomBuildEventHandler? CustomEventRaised; + public event BuildStatusEventHandler? StatusEventRaised; + public event AnyEventHandler? AnyEventRaised; + + private void InitializeEventHandlers() + { + _eventDispatcher.MessageRaised += (sender, e) => MessageRaised?.Invoke(sender, e); + _eventDispatcher.ErrorRaised += (sender, e) => ErrorRaised?.Invoke(sender, e); + _eventDispatcher.WarningRaised += (sender, e) => WarningRaised?.Invoke(sender, e); + _eventDispatcher.BuildStarted += (sender, e) => BuildStarted?.Invoke(sender, e); + _eventDispatcher.BuildFinished += (sender, e) => BuildFinished?.Invoke(sender, e); + _eventDispatcher.ProjectStarted += (sender, e) => ProjectStarted?.Invoke(sender, e); + _eventDispatcher.ProjectFinished += (sender, e) => ProjectFinished?.Invoke(sender, e); + _eventDispatcher.TargetStarted += (sender, e) => TargetStarted?.Invoke(sender, e); + _eventDispatcher.TargetFinished += (sender, e) => TargetFinished?.Invoke(sender, e); + _eventDispatcher.TaskStarted += (sender, e) => TaskStarted?.Invoke(sender, e); + _eventDispatcher.TaskFinished += (sender, e) => TaskFinished?.Invoke(sender, e); + _eventDispatcher.CustomEventRaised += (sender, e) => CustomEventRaised?.Invoke(sender, e); + _eventDispatcher.StatusEventRaised += (sender, e) => StatusEventRaised?.Invoke(sender, e); + _eventDispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); + } +#endregion /// /// Read the provided binary log file and raise corresponding events for each BuildEventArgs /// @@ -232,7 +281,7 @@ public void Replay(BuildEventArgsReader reader, CancellationToken cancellationTo bool supportsForwardCompatibility = reader.FileFormatVersion >= BinaryLogger.ForwardCompatibilityMinimalVersion; // Allow any possible deferred subscriptions to be registered - if (HasStructuredEventsSubscribers || !supportsForwardCompatibility) + if (_eventDispatcher.HasStructuredEventsSubscribers || !supportsForwardCompatibility) { _onStructuredReadingOnly?.Invoke(); } @@ -245,7 +294,7 @@ public void Replay(BuildEventArgsReader reader, CancellationToken cancellationTo reader.ArchiveFileEncountered += _archiveFileEncountered; reader.StringReadDone += _stringReadDone; - if (HasStructuredEventsSubscribers || !supportsForwardCompatibility) + if (_eventDispatcher.HasStructuredEventsSubscribers || !supportsForwardCompatibility) { if (this._rawLogRecordReceived != null) { @@ -260,7 +309,7 @@ public void Replay(BuildEventArgsReader reader, CancellationToken cancellationTo while (!cancellationToken.IsCancellationRequested && reader.Read() is { } instance) { - Dispatch(instance); + _eventDispatcher.Dispatch(instance); } } else diff --git a/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs index cf56776752c..37f5e44b893 100644 --- a/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs +++ b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs @@ -104,25 +104,24 @@ public class EventArgsDispatcher : IEventSource /// /// Raise one of the events that is appropriate for the type of the BuildEventArgs /// - public void Dispatch(BuildEventArgs buildEvent) + public virtual void Dispatch(BuildEventArgs buildEvent) { - BuildWarningEventArgs warningEvent = null; - BuildErrorEventArgs errorEvent = null; - BuildMessageEventArgs messageEvent = null; - - if ((warningEvent = buildEvent as BuildWarningEventArgs) != null && - warningEvent.ProjectFile == null) - { - } - else if ((errorEvent = buildEvent as BuildErrorEventArgs) != null && - errorEvent.ProjectFile == null) - { - } - else if ((messageEvent = buildEvent as BuildMessageEventArgs) != null && - messageEvent.ProjectFile == null) - { - } - + // BuildWarningEventArgs? warningEvent = null; + // BuildErrorEventArgs? errorEvent = null; + // BuildMessageEventArgs? messageEvent = null; + + // if ((warningEvent = buildEvent as BuildWarningEventArgs) != null && + // warningEvent.ProjectFile == null) + // { + // } + // else if ((errorEvent = buildEvent as BuildErrorEventArgs) != null && + // errorEvent.ProjectFile == null) + // { + // } + // else if ((messageEvent = buildEvent as BuildMessageEventArgs) != null && + // messageEvent.ProjectFile == null) + // { + // } if (buildEvent is BuildMessageEventArgs buildMessageEventArgs) { diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 3843fba847f..0b57828e95b 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -167,6 +167,8 @@ + + diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 35cc5f7f0e3..3897aac53a7 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -4409,12 +4409,9 @@ private static void ReplayBinaryLog( int cpuCount, bool isBuildCheckEnabled) { - var replayEventSource = new BinaryLogReplayEventSource(); - - if (isBuildCheckEnabled) - { - BuildManager.DefaultBuildManager.AttachBuildCheckForBinaryLogReplay(loggers, replayEventSource); - } + var replayEventSource = isBuildCheckEnabled ? + BuildManager.DefaultBuildManager.GetBinaryLogReplayEventSourceWithAttachedBuildCheck() : + new BinaryLogReplayEventSource(); foreach (var distributedLoggerRecord in distributedLoggerRecords) { From 1e2f0bc01c886bf86014b21d8c9891b73f274c5f Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 18:14:00 +0200 Subject: [PATCH 12/41] use Action dispatch instead of EventArgsDispatcher in AnalysisDisatcherContext; remove commented code --- .../AnalysisDispatchingContext.cs | 35 ++++--------------- .../AnalysisDispatchingContextFactory.cs | 7 ++-- .../BuildCheckEventArgsDispatcher.cs | 2 +- .../BinaryLogger/EventArgsDispatcher.cs | 17 --------- src/BuildCheck.UnitTests/EndToEndTests.cs | 4 +-- 5 files changed, 11 insertions(+), 54 deletions(-) diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index f4ffd7727a6..1ce7f1aa336 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -9,21 +9,20 @@ using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Framework; -using Microsoft.Build.Logging; using Microsoft.Build.Shared; namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContext : IAnalysisContext { - private readonly EventArgsDispatcher _eventDispatcher; + private readonly Action _dispatch; private readonly BuildEventContext _eventContext; public AnalysisDispatchingContext( - EventArgsDispatcher eventDispatcher, + Action dispatch, BuildEventContext eventContext) { - _eventDispatcher = eventDispatcher; + _dispatch = dispatch; _eventContext = eventContext; } @@ -33,24 +32,7 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) { ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); - // BuildWarningEventArgs? warningEvent = null; - // BuildErrorEventArgs? errorEvent = null; - // BuildMessageEventArgs? messageEvent = null; - - // if ((warningEvent = buildEvent as BuildWarningEventArgs) != null && - // warningEvent.ProjectFile == null) - // { - // } - // else if ((errorEvent = buildEvent as BuildErrorEventArgs) != null && - // errorEvent.ProjectFile == null) - // { - // } - // else if ((messageEvent = buildEvent as BuildMessageEventArgs) != null && - // messageEvent.ProjectFile == null) - // { - // } - - _eventDispatcher.Dispatch(buildEvent); + _dispatch!(buildEvent!); } public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) @@ -67,18 +49,13 @@ private void DispatchAsCommentFromText(BuildEventContext buildEventContext, Mess { BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs); - _eventDispatcher.Dispatch(buildEvent); + _dispatch!(buildEvent!); } public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); - // if (buildEvent.ProjectFile == null && - // _eventContext!.ProjectContextId != BuildEventContext.InvalidProjectContextId) - // { - // } - - _eventDispatcher.Dispatch(buildEvent); + _dispatch!(buildEvent!); } } diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs index 2cda8d7480e..bfa256be85a 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.Framework; using Microsoft.Build.Logging; @@ -15,10 +14,10 @@ namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory { - private readonly EventArgsDispatcher _eventDispatcher; + private readonly Action _dispatch; - public AnalysisDispatchingContextFactory(EventArgsDispatcher eventDispatcher) => _eventDispatcher = eventDispatcher; + public AnalysisDispatchingContextFactory(Action dispatch) => _dispatch = dispatch; public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) - => new AnalysisDispatchingContext(_eventDispatcher, eventContext); + => new AnalysisDispatchingContext(_dispatch, eventContext); } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs index 850f398f30f..33344826809 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs @@ -19,7 +19,7 @@ public class BuildCheckEventArgsDispatcher : EventArgsDispatcher internal BuildCheckEventArgsDispatcher(IBuildCheckManager buildCheckManager) => _buildCheckEventHandler = new BuildCheckBuildEventHandler( - new AnalysisDispatchingContextFactory(this), + new AnalysisDispatchingContextFactory(base.Dispatch), buildCheckManager); public override void Dispatch(BuildEventArgs buildEvent) diff --git a/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs index 37f5e44b893..2abf9566c3d 100644 --- a/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs +++ b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs @@ -106,23 +106,6 @@ public class EventArgsDispatcher : IEventSource /// public virtual void Dispatch(BuildEventArgs buildEvent) { - // BuildWarningEventArgs? warningEvent = null; - // BuildErrorEventArgs? errorEvent = null; - // BuildMessageEventArgs? messageEvent = null; - - // if ((warningEvent = buildEvent as BuildWarningEventArgs) != null && - // warningEvent.ProjectFile == null) - // { - // } - // else if ((errorEvent = buildEvent as BuildErrorEventArgs) != null && - // errorEvent.ProjectFile == null) - // { - // } - // else if ((messageEvent = buildEvent as BuildMessageEventArgs) != null && - // messageEvent.ProjectFile == null) - // { - // } - if (buildEvent is BuildMessageEventArgs buildMessageEventArgs) { MessageRaised?.Invoke(null, buildMessageEventArgs); diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index a2d6069843c..23313ad24ec 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -64,7 +64,7 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBuild(bool buildInOutOfProces [InlineData(true, true)] [InlineData(false, true)] [InlineData(false, false)] - public void SampleAnalyzerIntegrationTest_AnalyzeOnBunaryLogReplay(bool buildInOutOfProcessNode, bool analysisRequested) + public void SampleAnalyzerIntegrationTest_AnalyzeOnBinaryLogReplay(bool buildInOutOfProcessNode, bool analysisRequested) { PrepareSampleProjectsAndConfig(buildInOutOfProcessNode, out TransientTestFile projectFile); @@ -77,8 +77,6 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBunaryLogReplay(bool buildInO success.ShouldBeTrue(); - // _env.SetEnvironmentVariable("MSBUILDDEBUGONSTART", "1"); - string output = RunnerUtilities.ExecBootstrapedMSBuild( $"{logFile} -flp:logfile={Path.Combine(projectDirectory!, "logFile.log")};verbosity=diagnostic {(analysisRequested ? "-analyze" : string.Empty)}", out success, false, _env.Output, timeoutMilliseconds: 130_000); From 0cf40b178f97f2bc8751d4866fbe2acb2fb5b8f1 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 18:16:53 +0200 Subject: [PATCH 13/41] rename variable --- .../BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs index 3b6330a5a50..5aa8ca900e9 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckConnectorLogger.cs @@ -16,14 +16,14 @@ internal sealed class BuildCheckConnectorLogger : ILogger { private readonly BuildCheckBuildEventHandler _eventHandler; private readonly IBuildCheckManager _buildCheckManager; - private readonly IAnalysisContextFactory _analyzerContextFactory; + private readonly IAnalysisContextFactory _analysisContextFactory; internal BuildCheckConnectorLogger( IAnalysisContextFactory analyzerContextFactory, IBuildCheckManager buildCheckManager) { _buildCheckManager = buildCheckManager; - _analyzerContextFactory = analyzerContextFactory; + _analysisContextFactory = analyzerContextFactory; _eventHandler = new BuildCheckBuildEventHandler(analyzerContextFactory, buildCheckManager); } From 6feca72c4935d2c2aa6f89ece87fa2e2a005f8d8 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 13 Jun 2024 18:18:32 +0200 Subject: [PATCH 14/41] small fix --- src/MSBuild/XMake.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 3897aac53a7..42815b92567 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -808,7 +808,7 @@ public static ExitType Execute( // as if a build is happening if (FileUtilities.IsBinaryLogFilename(projectFile)) { - ReplayBinaryLog(projectFile, loggers.ToList(), distributedLoggerRecords, cpuCount, isBuildCheckEnabled); + ReplayBinaryLog(projectFile, loggers, distributedLoggerRecords, cpuCount, isBuildCheckEnabled); } else if (outputPropertiesItemsOrTargetResults && FileUtilities.IsSolutionFilename(projectFile)) { @@ -4404,7 +4404,7 @@ private static bool CreateAndConfigureLogger( private static void ReplayBinaryLog( string binaryLogFilePath, - List loggers, + ILogger[] loggers, IEnumerable distributedLoggerRecords, int cpuCount, bool isBuildCheckEnabled) From ea30fc4d924f9463527c6a246678104a219a379a Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Fri, 14 Jun 2024 16:28:02 +0200 Subject: [PATCH 15/41] changed the implementation - introduce BuildCheckBinaryLogReplaySourcerWrapper --- .../BackEnd/BuildManager/BuildManager.cs | 11 ++- ...BuildCheckBinaryLogReplaySourcerWrapper.cs | 76 +++++++++++++++ .../BuildCheckBuildEventHandler.cs | 2 +- .../BuildCheckEventArgsDispatcher.cs | 31 ------ .../Infrastructure/IBuildEventHandler.cs | 11 +++ .../BinaryLogReplayEventSource.cs | 95 +++++++------------ .../Logging/BinaryLogger/BinaryLogger.cs | 2 +- .../BinaryLogger/BuildEventArgsReader.cs | 2 +- .../BinaryLogger/EventArgsDispatcher.cs | 2 +- src/Build/Microsoft.Build.csproj | 3 +- src/MSBuild/XMake.cs | 11 ++- 11 files changed, 142 insertions(+), 104 deletions(-) create mode 100644 src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs delete mode 100644 src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs create mode 100644 src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 61bdba09094..98009f123d8 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -21,12 +21,12 @@ using Microsoft.Build.BackEnd; using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.SdkResolution; -using Microsoft.Build.Experimental.BuildCheck.Infrastructure; using Microsoft.Build.Evaluation; using Microsoft.Build.Eventing; using Microsoft.Build.Exceptions; using Microsoft.Build.Experimental; using Microsoft.Build.Experimental.BuildCheck; +using Microsoft.Build.Experimental.BuildCheck.Infrastructure; using Microsoft.Build.Experimental.ProjectCache; using Microsoft.Build.FileAccesses; using Microsoft.Build.Framework; @@ -2950,7 +2950,8 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public BinaryLogReplayEventSource GetBinaryLogReplayEventSourceWithAttachedBuildCheck() + public BuildCheckBinaryLogReplaySourcerWrapper GetBuildCheckBinaryLogReplayEventSourceWrapper( + BinaryLogReplayEventSource replayEventSource) { _buildParameters = new BuildParameters { @@ -2962,9 +2963,11 @@ public BinaryLogReplayEventSource GetBinaryLogReplayEventSourceWithAttachedBuild buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); - var eventDispatcher = new BuildCheckEventArgsDispatcher(buildCheckManagerProvider.Instance); + var buildCheckEventHandler = new BuildCheckBuildEventHandler( + new AnalysisDispatchingContextFactory(replayEventSource.Dispatch), + buildCheckManagerProvider.Instance); - return new BinaryLogReplayEventSource(eventDispatcher); + return new BuildCheckBinaryLogReplaySourcerWrapper(replayEventSource, buildCheckEventHandler); } /// diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs new file mode 100644 index 00000000000..ad9e61fafc4 --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs @@ -0,0 +1,76 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Logging; + +namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; + +public class BuildCheckBinaryLogReplaySourcerWrapper : IBinaryLogReplaySource +{ + private readonly BinaryLogReplayEventSource _replayEventSource; + private readonly IBuildEventHandler _buildCheckEventHandler; + + public BuildCheckBinaryLogReplaySourcerWrapper( + BinaryLogReplayEventSource replayEventSource, + IBuildEventHandler buildCheckEventHandler) + { + _replayEventSource = replayEventSource; + _buildCheckEventHandler = buildCheckEventHandler; + + InitializeEventHandlers(); + } + + public void Replay(string sourceFilePath, CancellationToken cancellationToken) + => _replayEventSource.Replay(sourceFilePath, cancellationToken, Dispatch); + + private void Dispatch(BuildEventArgs buildEvent) + { + _replayEventSource.Dispatch(buildEvent); + + _buildCheckEventHandler.HandleBuildEvent(buildEvent); + } + + #region Events + + public event BuildMessageEventHandler? MessageRaised; + public event BuildErrorEventHandler? ErrorRaised; + public event BuildWarningEventHandler? WarningRaised; + public event BuildStartedEventHandler? BuildStarted; + public event BuildFinishedEventHandler? BuildFinished; + public event ProjectStartedEventHandler? ProjectStarted; + public event ProjectFinishedEventHandler? ProjectFinished; + public event TargetStartedEventHandler? TargetStarted; + public event TargetFinishedEventHandler? TargetFinished; + public event TaskStartedEventHandler? TaskStarted; + public event TaskFinishedEventHandler? TaskFinished; + public event CustomBuildEventHandler? CustomEventRaised; + public event BuildStatusEventHandler? StatusEventRaised; + public event AnyEventHandler? AnyEventRaised; + + private void InitializeEventHandlers() + { + _replayEventSource.MessageRaised += (sender, e) => MessageRaised?.Invoke(sender, e); + _replayEventSource.ErrorRaised += (sender, e) => ErrorRaised?.Invoke(sender, e); + _replayEventSource.WarningRaised += (sender, e) => WarningRaised?.Invoke(sender, e); + _replayEventSource.BuildStarted += (sender, e) => BuildStarted?.Invoke(sender, e); + _replayEventSource.BuildFinished += (sender, e) => BuildFinished?.Invoke(sender, e); + _replayEventSource.ProjectStarted += (sender, e) => ProjectStarted?.Invoke(sender, e); + _replayEventSource.ProjectFinished += (sender, e) => ProjectFinished?.Invoke(sender, e); + _replayEventSource.TargetStarted += (sender, e) => TargetStarted?.Invoke(sender, e); + _replayEventSource.TargetFinished += (sender, e) => TargetFinished?.Invoke(sender, e); + _replayEventSource.TaskStarted += (sender, e) => TaskStarted?.Invoke(sender, e); + _replayEventSource.TaskFinished += (sender, e) => TaskFinished?.Invoke(sender, e); + _replayEventSource.CustomEventRaised += (sender, e) => CustomEventRaised?.Invoke(sender, e); + _replayEventSource.StatusEventRaised += (sender, e) => StatusEventRaised?.Invoke(sender, e); + _replayEventSource.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); + } + + #endregion +} diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs index dc4c9a19bc9..bc72c651fc7 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs @@ -13,7 +13,7 @@ namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; -internal class BuildCheckBuildEventHandler +internal class BuildCheckBuildEventHandler : IBuildEventHandler { private readonly IBuildCheckManager _buildCheckManager; private readonly IAnalysisContextFactory _analyzerContextFactory; diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs deleted file mode 100644 index 33344826809..00000000000 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckEventArgsDispatcher.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Build.Experimental.BuildCheck; -using Microsoft.Build.Experimental.BuildCheck.Infrastructure; -using Microsoft.Build.Framework; -using Microsoft.Build.Logging; - -namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; - -public class BuildCheckEventArgsDispatcher : EventArgsDispatcher -{ - private readonly BuildCheckBuildEventHandler _buildCheckEventHandler; - - internal BuildCheckEventArgsDispatcher(IBuildCheckManager buildCheckManager) - => _buildCheckEventHandler = new BuildCheckBuildEventHandler( - new AnalysisDispatchingContextFactory(base.Dispatch), - buildCheckManager); - - public override void Dispatch(BuildEventArgs buildEvent) - { - base.Dispatch(buildEvent); - - _buildCheckEventHandler.HandleBuildEvent(buildEvent); - } -} diff --git a/src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs new file mode 100644 index 00000000000..1cd4a78d671 --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Build.Framework; + +namespace Microsoft.Build.Experimental.BuildCheck; + +public interface IBuildEventHandler +{ + void HandleBuildEvent(BuildEventArgs e); +} diff --git a/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs b/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs index 85c07f6adee..59670d19a62 100644 --- a/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs +++ b/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs @@ -11,10 +11,15 @@ namespace Microsoft.Build.Logging { + public interface IBinaryLogReplaySource : IEventSource + { + void Replay(string sourceFilePath, CancellationToken cancellationToken); + } + /// /// Interface for replaying a binary log file (*.binlog) /// - internal interface IBinaryLogReplaySource : + internal interface IBinaryLogEventReaderNotificationsReplaySource : IEventSource, IBuildEventArgsReaderNotifications { @@ -59,30 +64,17 @@ void DeferredInitialize( /// by implementing IEventSource and raising corresponding events. /// /// The class is public so that we can call it from MSBuild.exe when replaying a log file. - public sealed class BinaryLogReplayEventSource : IBinaryLogReplaySource + public sealed class BinaryLogReplayEventSource : + EventArgsDispatcher, + IBinaryLogEventReaderNotificationsReplaySource, + IBinaryLogReplaySource { private int? _fileFormatVersion; private int? _minimumReaderVersion; - private readonly EventArgsDispatcher _eventDispatcher; - public int FileFormatVersion => _fileFormatVersion ?? throw new InvalidOperationException(ResourceUtilities.GetResourceString("Binlog_Source_VersionUninitialized")); public int MinimumReaderVersion => _minimumReaderVersion ?? throw new InvalidOperationException(ResourceUtilities.GetResourceString("Binlog_Source_VersionUninitialized")); - public BinaryLogReplayEventSource() - { - _eventDispatcher = new EventArgsDispatcher(); - - InitializeEventHandlers(); - } - - public BinaryLogReplayEventSource(EventArgsDispatcher eventDispatcher) - { - _eventDispatcher = eventDispatcher; - - InitializeEventHandlers(); - } - /// Touches the static constructor /// to ensure it initializes /// and @@ -96,43 +88,9 @@ static BinaryLogReplayEventSource() /// public bool AllowForwardCompatibility { private get; init; } -#region EventHandlers /// public event Action? RecoverableReadError; - public event BuildMessageEventHandler? MessageRaised; - public event BuildErrorEventHandler? ErrorRaised; - public event BuildWarningEventHandler? WarningRaised; - public event BuildStartedEventHandler? BuildStarted; - public event BuildFinishedEventHandler? BuildFinished; - public event ProjectStartedEventHandler? ProjectStarted; - public event ProjectFinishedEventHandler? ProjectFinished; - public event TargetStartedEventHandler? TargetStarted; - public event TargetFinishedEventHandler? TargetFinished; - public event TaskStartedEventHandler? TaskStarted; - public event TaskFinishedEventHandler? TaskFinished; - public event CustomBuildEventHandler? CustomEventRaised; - public event BuildStatusEventHandler? StatusEventRaised; - public event AnyEventHandler? AnyEventRaised; - - private void InitializeEventHandlers() - { - _eventDispatcher.MessageRaised += (sender, e) => MessageRaised?.Invoke(sender, e); - _eventDispatcher.ErrorRaised += (sender, e) => ErrorRaised?.Invoke(sender, e); - _eventDispatcher.WarningRaised += (sender, e) => WarningRaised?.Invoke(sender, e); - _eventDispatcher.BuildStarted += (sender, e) => BuildStarted?.Invoke(sender, e); - _eventDispatcher.BuildFinished += (sender, e) => BuildFinished?.Invoke(sender, e); - _eventDispatcher.ProjectStarted += (sender, e) => ProjectStarted?.Invoke(sender, e); - _eventDispatcher.ProjectFinished += (sender, e) => ProjectFinished?.Invoke(sender, e); - _eventDispatcher.TargetStarted += (sender, e) => TargetStarted?.Invoke(sender, e); - _eventDispatcher.TargetFinished += (sender, e) => TargetFinished?.Invoke(sender, e); - _eventDispatcher.TaskStarted += (sender, e) => TaskStarted?.Invoke(sender, e); - _eventDispatcher.TaskFinished += (sender, e) => TaskFinished?.Invoke(sender, e); - _eventDispatcher.CustomEventRaised += (sender, e) => CustomEventRaised?.Invoke(sender, e); - _eventDispatcher.StatusEventRaised += (sender, e) => StatusEventRaised?.Invoke(sender, e); - _eventDispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); - } -#endregion /// /// Read the provided binary log file and raise corresponding events for each BuildEventArgs /// @@ -238,6 +196,12 @@ public static BuildEventArgsReader OpenBuildEventsReader( public static BuildEventArgsReader OpenBuildEventsReader(string sourceFilePath) => OpenBuildEventsReader(OpenReader(sourceFilePath), true); + public void Replay(string sourceFilePath, CancellationToken cancellationToken, Action dispatchBuildEvent) + { + using var eventsReader = OpenBuildEventsReader(sourceFilePath); + Replay(eventsReader, cancellationToken, dispatchBuildEvent); + } + /// /// Read the provided binary log file and raise corresponding events for each BuildEventArgs /// @@ -275,13 +239,22 @@ public void Replay(BinaryReader binaryReader, bool closeInput, CancellationToken /// The build events reader - caller is responsible for disposing. /// A indicating the replay should stop as soon as possible. public void Replay(BuildEventArgsReader reader, CancellationToken cancellationToken) + => Replay(reader, cancellationToken, Dispatch); + + /// + /// Read the provided binary log file and raise corresponding events for each BuildEventArgs + /// + /// The build events reader - caller is responsible for disposing. + /// A indicating the replay should stop as soon as possible. + /// Dispatcher of the + private void Replay(BuildEventArgsReader reader, CancellationToken cancellationToken, Action dispatchBuildEvent) { _fileFormatVersion = reader.FileFormatVersion; _minimumReaderVersion = reader.MinimumReaderVersion; bool supportsForwardCompatibility = reader.FileFormatVersion >= BinaryLogger.ForwardCompatibilityMinimalVersion; // Allow any possible deferred subscriptions to be registered - if (_eventDispatcher.HasStructuredEventsSubscribers || !supportsForwardCompatibility) + if (HasStructuredEventsSubscribers || !supportsForwardCompatibility) { _onStructuredReadingOnly?.Invoke(); } @@ -294,7 +267,7 @@ public void Replay(BuildEventArgsReader reader, CancellationToken cancellationTo reader.ArchiveFileEncountered += _archiveFileEncountered; reader.StringReadDone += _stringReadDone; - if (_eventDispatcher.HasStructuredEventsSubscribers || !supportsForwardCompatibility) + if (HasStructuredEventsSubscribers || !supportsForwardCompatibility) { if (this._rawLogRecordReceived != null) { @@ -309,7 +282,7 @@ public void Replay(BuildEventArgsReader reader, CancellationToken cancellationTo while (!cancellationToken.IsCancellationRequested && reader.Read() is { } instance) { - _eventDispatcher.Dispatch(instance); + dispatchBuildEvent(instance); } } else @@ -345,8 +318,8 @@ public void Replay(BuildEventArgsReader reader, CancellationToken cancellationTo private Action? _onRawReadingPossible; private Action? _onStructuredReadingOnly; - /// - void IBinaryLogReplaySource.DeferredInitialize( + /// + void IBinaryLogEventReaderNotificationsReplaySource.DeferredInitialize( Action onRawReadingPossible, Action onStructuredReadingOnly) { @@ -355,8 +328,8 @@ void IBinaryLogReplaySource.DeferredInitialize( } private Action? _embeddedContentRead; - /// - event Action? IBinaryLogReplaySource.EmbeddedContentRead + /// + event Action? IBinaryLogEventReaderNotificationsReplaySource.EmbeddedContentRead { // Explicitly implemented event has to declare explicit add/remove accessors // https://stackoverflow.com/a/2268472/2308106 @@ -381,8 +354,8 @@ event Action? IBuildEventArgsReaderNotifications.ArchiveFi } private Action? _rawLogRecordReceived; - /// - event Action? IBinaryLogReplaySource.RawLogRecordReceived + /// + event Action? IBinaryLogEventReaderNotificationsReplaySource.RawLogRecordReceived { add => _rawLogRecordReceived += value; remove => _rawLogRecordReceived -= value; diff --git a/src/Build/Logging/BinaryLogger/BinaryLogger.cs b/src/Build/Logging/BinaryLogger/BinaryLogger.cs index d4c37461938..221c9ef7c93 100644 --- a/src/Build/Logging/BinaryLogger/BinaryLogger.cs +++ b/src/Build/Logging/BinaryLogger/BinaryLogger.cs @@ -163,7 +163,7 @@ public void Initialize(IEventSource eventSource) bool logPropertiesAndItemsAfterEvaluation = Traits.Instance.EscapeHatches.LogPropertiesAndItemsAfterEvaluation ?? true; ProcessParameters(out bool omitInitialInfo); - var replayEventSource = eventSource as IBinaryLogReplaySource; + var replayEventSource = eventSource as IBinaryLogEventReaderNotificationsReplaySource; try { diff --git a/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs b/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs index 358c410265f..817d8d732d3 100644 --- a/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs +++ b/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs @@ -145,7 +145,7 @@ public void Dispose() internal int FileFormatVersion => _fileFormatVersion; internal int MinimumReaderVersion { get; set; } = BinaryLogger.ForwardCompatibilityMinimalVersion; - /// + /// internal event Action? EmbeddedContentRead; /// diff --git a/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs index 2abf9566c3d..db24d791ed2 100644 --- a/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs +++ b/src/Build/Logging/BinaryLogger/EventArgsDispatcher.cs @@ -104,7 +104,7 @@ public class EventArgsDispatcher : IEventSource /// /// Raise one of the events that is appropriate for the type of the BuildEventArgs /// - public virtual void Dispatch(BuildEventArgs buildEvent) + public void Dispatch(BuildEventArgs buildEvent) { if (buildEvent is BuildMessageEventArgs buildMessageEventArgs) { diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 0b57828e95b..ce4e6da0003 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -166,13 +166,14 @@ + - + diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 42815b92567..68f24f63600 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -4409,9 +4409,14 @@ private static void ReplayBinaryLog( int cpuCount, bool isBuildCheckEnabled) { - var replayEventSource = isBuildCheckEnabled ? - BuildManager.DefaultBuildManager.GetBinaryLogReplayEventSourceWithAttachedBuildCheck() : - new BinaryLogReplayEventSource(); + + IBinaryLogReplaySource replayEventSource = new BinaryLogReplayEventSource(); + + if (isBuildCheckEnabled) + { + replayEventSource = BuildManager.DefaultBuildManager + .GetBuildCheckBinaryLogReplayEventSourceWrapper((BinaryLogReplayEventSource)replayEventSource); + } foreach (var distributedLoggerRecord in distributedLoggerRecords) { From bce1a4471508e95992eced5a33abcced3f3d4db6 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Mon, 17 Jun 2024 13:02:38 +0200 Subject: [PATCH 16/41] make BuildCheckBinaryLogReplaySourcerWrapper internal --- src/Build/BackEnd/BuildManager/BuildManager.cs | 2 +- .../Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 98009f123d8..ec093612169 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,7 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public BuildCheckBinaryLogReplaySourcerWrapper GetBuildCheckBinaryLogReplayEventSourceWrapper( + public IBinaryLogReplaySource GetBuildCheckBinaryLogReplayEventSourceWrapper( BinaryLogReplayEventSource replayEventSource) { _buildParameters = new BuildParameters diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs index ad9e61fafc4..2d675db0527 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs @@ -12,7 +12,7 @@ namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; -public class BuildCheckBinaryLogReplaySourcerWrapper : IBinaryLogReplaySource +internal class BuildCheckBinaryLogReplaySourcerWrapper : IBinaryLogReplaySource { private readonly BinaryLogReplayEventSource _replayEventSource; private readonly IBuildEventHandler _buildCheckEventHandler; From 6506888f21c4b1398ce241333a2f48eaae3fcd59 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Mon, 17 Jun 2024 15:35:48 +0200 Subject: [PATCH 17/41] remove BuildCheckBinaryLogReplaySourcerWrapper --- .../BackEnd/BuildManager/BuildManager.cs | 5 +- ...BuildCheckBinaryLogReplaySourcerWrapper.cs | 76 ------------------- .../BuildCheckBuildEventHandler.cs | 2 +- .../Infrastructure/IBuildEventHandler.cs | 11 --- .../BinaryLogReplayEventSource.cs | 37 ++------- .../Logging/BinaryLogger/BinaryLogger.cs | 2 +- .../BinaryLogger/BuildEventArgsReader.cs | 2 +- src/Build/Microsoft.Build.csproj | 2 - src/MSBuild/XMake.cs | 5 +- 9 files changed, 15 insertions(+), 127 deletions(-) delete mode 100644 src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs delete mode 100644 src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index ec093612169..64c8de664c3 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,8 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public IBinaryLogReplaySource GetBuildCheckBinaryLogReplayEventSourceWrapper( - BinaryLogReplayEventSource replayEventSource) + public void AttachBuildCheckForBinaryLogReplay(BinaryLogReplayEventSource replayEventSource) { _buildParameters = new BuildParameters { @@ -2967,7 +2966,7 @@ public IBinaryLogReplaySource GetBuildCheckBinaryLogReplayEventSourceWrapper( new AnalysisDispatchingContextFactory(replayEventSource.Dispatch), buildCheckManagerProvider.Instance); - return new BuildCheckBinaryLogReplaySourcerWrapper(replayEventSource, buildCheckEventHandler); + replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); } /// diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs deleted file mode 100644 index 2d675db0527..00000000000 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckBinaryLogReplaySourcerWrapper.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Build.Framework; -using Microsoft.Build.Logging; - -namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; - -internal class BuildCheckBinaryLogReplaySourcerWrapper : IBinaryLogReplaySource -{ - private readonly BinaryLogReplayEventSource _replayEventSource; - private readonly IBuildEventHandler _buildCheckEventHandler; - - public BuildCheckBinaryLogReplaySourcerWrapper( - BinaryLogReplayEventSource replayEventSource, - IBuildEventHandler buildCheckEventHandler) - { - _replayEventSource = replayEventSource; - _buildCheckEventHandler = buildCheckEventHandler; - - InitializeEventHandlers(); - } - - public void Replay(string sourceFilePath, CancellationToken cancellationToken) - => _replayEventSource.Replay(sourceFilePath, cancellationToken, Dispatch); - - private void Dispatch(BuildEventArgs buildEvent) - { - _replayEventSource.Dispatch(buildEvent); - - _buildCheckEventHandler.HandleBuildEvent(buildEvent); - } - - #region Events - - public event BuildMessageEventHandler? MessageRaised; - public event BuildErrorEventHandler? ErrorRaised; - public event BuildWarningEventHandler? WarningRaised; - public event BuildStartedEventHandler? BuildStarted; - public event BuildFinishedEventHandler? BuildFinished; - public event ProjectStartedEventHandler? ProjectStarted; - public event ProjectFinishedEventHandler? ProjectFinished; - public event TargetStartedEventHandler? TargetStarted; - public event TargetFinishedEventHandler? TargetFinished; - public event TaskStartedEventHandler? TaskStarted; - public event TaskFinishedEventHandler? TaskFinished; - public event CustomBuildEventHandler? CustomEventRaised; - public event BuildStatusEventHandler? StatusEventRaised; - public event AnyEventHandler? AnyEventRaised; - - private void InitializeEventHandlers() - { - _replayEventSource.MessageRaised += (sender, e) => MessageRaised?.Invoke(sender, e); - _replayEventSource.ErrorRaised += (sender, e) => ErrorRaised?.Invoke(sender, e); - _replayEventSource.WarningRaised += (sender, e) => WarningRaised?.Invoke(sender, e); - _replayEventSource.BuildStarted += (sender, e) => BuildStarted?.Invoke(sender, e); - _replayEventSource.BuildFinished += (sender, e) => BuildFinished?.Invoke(sender, e); - _replayEventSource.ProjectStarted += (sender, e) => ProjectStarted?.Invoke(sender, e); - _replayEventSource.ProjectFinished += (sender, e) => ProjectFinished?.Invoke(sender, e); - _replayEventSource.TargetStarted += (sender, e) => TargetStarted?.Invoke(sender, e); - _replayEventSource.TargetFinished += (sender, e) => TargetFinished?.Invoke(sender, e); - _replayEventSource.TaskStarted += (sender, e) => TaskStarted?.Invoke(sender, e); - _replayEventSource.TaskFinished += (sender, e) => TaskFinished?.Invoke(sender, e); - _replayEventSource.CustomEventRaised += (sender, e) => CustomEventRaised?.Invoke(sender, e); - _replayEventSource.StatusEventRaised += (sender, e) => StatusEventRaised?.Invoke(sender, e); - _replayEventSource.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); - } - - #endregion -} diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs index bc72c651fc7..dc4c9a19bc9 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs @@ -13,7 +13,7 @@ namespace Microsoft.Build.Experimental.BuildCheck.Infrastructure; -internal class BuildCheckBuildEventHandler : IBuildEventHandler +internal class BuildCheckBuildEventHandler { private readonly IBuildCheckManager _buildCheckManager; private readonly IAnalysisContextFactory _analyzerContextFactory; diff --git a/src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs deleted file mode 100644 index 1cd4a78d671..00000000000 --- a/src/Build/BuildCheck/Infrastructure/IBuildEventHandler.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Microsoft.Build.Framework; - -namespace Microsoft.Build.Experimental.BuildCheck; - -public interface IBuildEventHandler -{ - void HandleBuildEvent(BuildEventArgs e); -} diff --git a/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs b/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs index 59670d19a62..1e7ab846695 100644 --- a/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs +++ b/src/Build/Logging/BinaryLogger/BinaryLogReplayEventSource.cs @@ -11,15 +11,10 @@ namespace Microsoft.Build.Logging { - public interface IBinaryLogReplaySource : IEventSource - { - void Replay(string sourceFilePath, CancellationToken cancellationToken); - } - /// /// Interface for replaying a binary log file (*.binlog) /// - internal interface IBinaryLogEventReaderNotificationsReplaySource : + internal interface IBinaryLogReplaySource : IEventSource, IBuildEventArgsReaderNotifications { @@ -66,7 +61,6 @@ void DeferredInitialize( /// The class is public so that we can call it from MSBuild.exe when replaying a log file. public sealed class BinaryLogReplayEventSource : EventArgsDispatcher, - IBinaryLogEventReaderNotificationsReplaySource, IBinaryLogReplaySource { private int? _fileFormatVersion; @@ -196,12 +190,6 @@ public static BuildEventArgsReader OpenBuildEventsReader( public static BuildEventArgsReader OpenBuildEventsReader(string sourceFilePath) => OpenBuildEventsReader(OpenReader(sourceFilePath), true); - public void Replay(string sourceFilePath, CancellationToken cancellationToken, Action dispatchBuildEvent) - { - using var eventsReader = OpenBuildEventsReader(sourceFilePath); - Replay(eventsReader, cancellationToken, dispatchBuildEvent); - } - /// /// Read the provided binary log file and raise corresponding events for each BuildEventArgs /// @@ -239,15 +227,6 @@ public void Replay(BinaryReader binaryReader, bool closeInput, CancellationToken /// The build events reader - caller is responsible for disposing. /// A indicating the replay should stop as soon as possible. public void Replay(BuildEventArgsReader reader, CancellationToken cancellationToken) - => Replay(reader, cancellationToken, Dispatch); - - /// - /// Read the provided binary log file and raise corresponding events for each BuildEventArgs - /// - /// The build events reader - caller is responsible for disposing. - /// A indicating the replay should stop as soon as possible. - /// Dispatcher of the - private void Replay(BuildEventArgsReader reader, CancellationToken cancellationToken, Action dispatchBuildEvent) { _fileFormatVersion = reader.FileFormatVersion; _minimumReaderVersion = reader.MinimumReaderVersion; @@ -282,7 +261,7 @@ private void Replay(BuildEventArgsReader reader, CancellationToken cancellationT while (!cancellationToken.IsCancellationRequested && reader.Read() is { } instance) { - dispatchBuildEvent(instance); + Dispatch(instance); } } else @@ -318,8 +297,8 @@ private void Replay(BuildEventArgsReader reader, CancellationToken cancellationT private Action? _onRawReadingPossible; private Action? _onStructuredReadingOnly; - /// - void IBinaryLogEventReaderNotificationsReplaySource.DeferredInitialize( + /// + void IBinaryLogReplaySource.DeferredInitialize( Action onRawReadingPossible, Action onStructuredReadingOnly) { @@ -328,8 +307,8 @@ void IBinaryLogEventReaderNotificationsReplaySource.DeferredInitialize( } private Action? _embeddedContentRead; - /// - event Action? IBinaryLogEventReaderNotificationsReplaySource.EmbeddedContentRead + /// + event Action? IBinaryLogReplaySource.EmbeddedContentRead { // Explicitly implemented event has to declare explicit add/remove accessors // https://stackoverflow.com/a/2268472/2308106 @@ -354,8 +333,8 @@ event Action? IBuildEventArgsReaderNotifications.ArchiveFi } private Action? _rawLogRecordReceived; - /// - event Action? IBinaryLogEventReaderNotificationsReplaySource.RawLogRecordReceived + /// + event Action? IBinaryLogReplaySource.RawLogRecordReceived { add => _rawLogRecordReceived += value; remove => _rawLogRecordReceived -= value; diff --git a/src/Build/Logging/BinaryLogger/BinaryLogger.cs b/src/Build/Logging/BinaryLogger/BinaryLogger.cs index 221c9ef7c93..d4c37461938 100644 --- a/src/Build/Logging/BinaryLogger/BinaryLogger.cs +++ b/src/Build/Logging/BinaryLogger/BinaryLogger.cs @@ -163,7 +163,7 @@ public void Initialize(IEventSource eventSource) bool logPropertiesAndItemsAfterEvaluation = Traits.Instance.EscapeHatches.LogPropertiesAndItemsAfterEvaluation ?? true; ProcessParameters(out bool omitInitialInfo); - var replayEventSource = eventSource as IBinaryLogEventReaderNotificationsReplaySource; + var replayEventSource = eventSource as IBinaryLogReplaySource; try { diff --git a/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs b/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs index 817d8d732d3..358c410265f 100644 --- a/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs +++ b/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs @@ -145,7 +145,7 @@ public void Dispose() internal int FileFormatVersion => _fileFormatVersion; internal int MinimumReaderVersion { get; set; } = BinaryLogger.ForwardCompatibilityMinimalVersion; - /// + /// internal event Action? EmbeddedContentRead; /// diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index ce4e6da0003..9751b24cce6 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -166,14 +166,12 @@ - - diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 68f24f63600..ae8b83fade1 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -4410,12 +4410,11 @@ private static void ReplayBinaryLog( bool isBuildCheckEnabled) { - IBinaryLogReplaySource replayEventSource = new BinaryLogReplayEventSource(); + var replayEventSource = new BinaryLogReplayEventSource(); if (isBuildCheckEnabled) { - replayEventSource = BuildManager.DefaultBuildManager - .GetBuildCheckBinaryLogReplayEventSourceWrapper((BinaryLogReplayEventSource)replayEventSource); + BuildManager.DefaultBuildManager.AttachBuildCheckForBinaryLogReplay(replayEventSource); } foreach (var distributedLoggerRecord in distributedLoggerRecords) From 30873a4812fc38b2e747923bb46b010a9a9f60ae Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 18 Jun 2024 14:16:30 +0200 Subject: [PATCH 18/41] use the event source that merges events from the binlog replay and nthe new events produced by build check --- .../BackEnd/BuildManager/BuildManager.cs | 16 ++++++++++++++-- .../AnalysisDispatchingContext.cs | 13 +++++++------ .../AnalysisDispatchingContextFactory.cs | 19 ++++++++++--------- src/MSBuild/XMake.cs | 15 +++++++-------- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 64c8de664c3..d9794e794b4 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,7 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public void AttachBuildCheckForBinaryLogReplay(BinaryLogReplayEventSource replayEventSource) + public IEventSource GetMergedEventSource(BinaryLogReplayEventSource replayEventSource) { _buildParameters = new BuildParameters { @@ -2962,11 +2962,23 @@ public void AttachBuildCheckForBinaryLogReplay(BinaryLogReplayEventSource replay buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); + // Create BuildCheckBuildEventHandler that uses the mergedEventSource to invoke new events + var analysisContextFactory = new AnalysisDispatchingContextFactory(); + var buildCheckEventHandler = new BuildCheckBuildEventHandler( - new AnalysisDispatchingContextFactory(replayEventSource.Dispatch), + analysisContextFactory, buildCheckManagerProvider.Instance); + var mergedEventSource = new EventArgsDispatcher(); + // Pass the events from replayEventSource to the mergedEventSource + replayEventSource.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); + + // Pass the events from replayEventSource to the BuildCheckBuildEventHandler to produce new events replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); + // Pass the events produced by BuildCheck to the mergedEventSource + analysisContextFactory.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); + + return mergedEventSource; } /// diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 1ce7f1aa336..044e214923e 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -9,20 +9,21 @@ using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Framework; +using Microsoft.Build.Logging; using Microsoft.Build.Shared; namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContext : IAnalysisContext { - private readonly Action _dispatch; + private readonly EventArgsDispatcher _eventDispatcher; private readonly BuildEventContext _eventContext; public AnalysisDispatchingContext( - Action dispatch, + EventArgsDispatcher dispatch, BuildEventContext eventContext) { - _dispatch = dispatch; + _eventDispatcher = dispatch; _eventContext = eventContext; } @@ -32,7 +33,7 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) { ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); - _dispatch!(buildEvent!); + _eventDispatcher.Dispatch(buildEvent); } public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) @@ -49,13 +50,13 @@ private void DispatchAsCommentFromText(BuildEventContext buildEventContext, Mess { BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs); - _dispatch!(buildEvent!); + _eventDispatcher.Dispatch(buildEvent); } public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); - _dispatch!(buildEvent!); + _eventDispatcher.Dispatch(buildEvent); } } diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs index bfa256be85a..f19b8e2e547 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs @@ -1,12 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Logging; @@ -14,10 +8,17 @@ namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory { - private readonly Action _dispatch; + private readonly EventArgsDispatcher _dispatcher; - public AnalysisDispatchingContextFactory(Action dispatch) => _dispatch = dispatch; + public event AnyEventHandler? AnyEventRaised; + + public AnalysisDispatchingContextFactory() + { + _dispatcher = new EventArgsDispatcher(); + + _dispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); + } public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) - => new AnalysisDispatchingContext(_dispatch, eventContext); + => new AnalysisDispatchingContext(_dispatcher, eventContext); } diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index ae8b83fade1..380069a61e0 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -4412,21 +4412,20 @@ private static void ReplayBinaryLog( var replayEventSource = new BinaryLogReplayEventSource(); - if (isBuildCheckEnabled) - { - BuildManager.DefaultBuildManager.AttachBuildCheckForBinaryLogReplay(replayEventSource); - } + var eventSource = isBuildCheckEnabled ? + BuildManager.DefaultBuildManager.GetMergedEventSource(replayEventSource) : + replayEventSource; foreach (var distributedLoggerRecord in distributedLoggerRecords) { ILogger centralLogger = distributedLoggerRecord.CentralLogger; if (centralLogger is INodeLogger nodeLogger) { - nodeLogger.Initialize(replayEventSource, cpuCount); + nodeLogger.Initialize(eventSource, cpuCount); } else { - centralLogger?.Initialize(replayEventSource); + centralLogger?.Initialize(eventSource); } } @@ -4434,11 +4433,11 @@ private static void ReplayBinaryLog( { if (logger is INodeLogger nodeLogger) { - nodeLogger.Initialize(replayEventSource, cpuCount); + nodeLogger.Initialize(eventSource, cpuCount); } else { - logger.Initialize(replayEventSource); + logger.Initialize(eventSource); } } From 24418b379d5f30e707756bd98ff6ed6eb027fe6e Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 18 Jun 2024 14:16:53 +0200 Subject: [PATCH 19/41] Revert "use the event source that merges events from the binlog replay and nthe new events produced by build check" This reverts commit 30873a4812fc38b2e747923bb46b010a9a9f60ae. --- .../BackEnd/BuildManager/BuildManager.cs | 16 ++-------------- .../AnalysisDispatchingContext.cs | 13 ++++++------- .../AnalysisDispatchingContextFactory.cs | 19 +++++++++---------- src/MSBuild/XMake.cs | 15 ++++++++------- 4 files changed, 25 insertions(+), 38 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index d9794e794b4..64c8de664c3 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,7 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public IEventSource GetMergedEventSource(BinaryLogReplayEventSource replayEventSource) + public void AttachBuildCheckForBinaryLogReplay(BinaryLogReplayEventSource replayEventSource) { _buildParameters = new BuildParameters { @@ -2962,23 +2962,11 @@ public IEventSource GetMergedEventSource(BinaryLogReplayEventSource replayEventS buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); - // Create BuildCheckBuildEventHandler that uses the mergedEventSource to invoke new events - var analysisContextFactory = new AnalysisDispatchingContextFactory(); - var buildCheckEventHandler = new BuildCheckBuildEventHandler( - analysisContextFactory, + new AnalysisDispatchingContextFactory(replayEventSource.Dispatch), buildCheckManagerProvider.Instance); - var mergedEventSource = new EventArgsDispatcher(); - // Pass the events from replayEventSource to the mergedEventSource - replayEventSource.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); - - // Pass the events from replayEventSource to the BuildCheckBuildEventHandler to produce new events replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); - // Pass the events produced by BuildCheck to the mergedEventSource - analysisContextFactory.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); - - return mergedEventSource; } /// diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 044e214923e..1ce7f1aa336 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -9,21 +9,20 @@ using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Framework; -using Microsoft.Build.Logging; using Microsoft.Build.Shared; namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContext : IAnalysisContext { - private readonly EventArgsDispatcher _eventDispatcher; + private readonly Action _dispatch; private readonly BuildEventContext _eventContext; public AnalysisDispatchingContext( - EventArgsDispatcher dispatch, + Action dispatch, BuildEventContext eventContext) { - _eventDispatcher = dispatch; + _dispatch = dispatch; _eventContext = eventContext; } @@ -33,7 +32,7 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) { ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); - _eventDispatcher.Dispatch(buildEvent); + _dispatch!(buildEvent!); } public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) @@ -50,13 +49,13 @@ private void DispatchAsCommentFromText(BuildEventContext buildEventContext, Mess { BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs); - _eventDispatcher.Dispatch(buildEvent); + _dispatch!(buildEvent!); } public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); - _eventDispatcher.Dispatch(buildEvent); + _dispatch!(buildEvent!); } } diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs index f19b8e2e547..bfa256be85a 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs @@ -1,6 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Logging; @@ -8,17 +14,10 @@ namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory { - private readonly EventArgsDispatcher _dispatcher; + private readonly Action _dispatch; - public event AnyEventHandler? AnyEventRaised; - - public AnalysisDispatchingContextFactory() - { - _dispatcher = new EventArgsDispatcher(); - - _dispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); - } + public AnalysisDispatchingContextFactory(Action dispatch) => _dispatch = dispatch; public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) - => new AnalysisDispatchingContext(_dispatcher, eventContext); + => new AnalysisDispatchingContext(_dispatch, eventContext); } diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 380069a61e0..ae8b83fade1 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -4412,20 +4412,21 @@ private static void ReplayBinaryLog( var replayEventSource = new BinaryLogReplayEventSource(); - var eventSource = isBuildCheckEnabled ? - BuildManager.DefaultBuildManager.GetMergedEventSource(replayEventSource) : - replayEventSource; + if (isBuildCheckEnabled) + { + BuildManager.DefaultBuildManager.AttachBuildCheckForBinaryLogReplay(replayEventSource); + } foreach (var distributedLoggerRecord in distributedLoggerRecords) { ILogger centralLogger = distributedLoggerRecord.CentralLogger; if (centralLogger is INodeLogger nodeLogger) { - nodeLogger.Initialize(eventSource, cpuCount); + nodeLogger.Initialize(replayEventSource, cpuCount); } else { - centralLogger?.Initialize(eventSource); + centralLogger?.Initialize(replayEventSource); } } @@ -4433,11 +4434,11 @@ private static void ReplayBinaryLog( { if (logger is INodeLogger nodeLogger) { - nodeLogger.Initialize(eventSource, cpuCount); + nodeLogger.Initialize(replayEventSource, cpuCount); } else { - logger.Initialize(eventSource); + logger.Initialize(replayEventSource); } } From 50ed0b7482bb4bd6c39eea78fc33d655dfe5b8ab Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 18 Jun 2024 14:17:18 +0200 Subject: [PATCH 20/41] Reapply "use the event source that merges events from the binlog replay and nthe new events produced by build check" This reverts commit 24418b379d5f30e707756bd98ff6ed6eb027fe6e. --- .../BackEnd/BuildManager/BuildManager.cs | 16 ++++++++++++++-- .../AnalysisDispatchingContext.cs | 13 +++++++------ .../AnalysisDispatchingContextFactory.cs | 19 ++++++++++--------- src/MSBuild/XMake.cs | 15 +++++++-------- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 64c8de664c3..d9794e794b4 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,7 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public void AttachBuildCheckForBinaryLogReplay(BinaryLogReplayEventSource replayEventSource) + public IEventSource GetMergedEventSource(BinaryLogReplayEventSource replayEventSource) { _buildParameters = new BuildParameters { @@ -2962,11 +2962,23 @@ public void AttachBuildCheckForBinaryLogReplay(BinaryLogReplayEventSource replay buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); + // Create BuildCheckBuildEventHandler that uses the mergedEventSource to invoke new events + var analysisContextFactory = new AnalysisDispatchingContextFactory(); + var buildCheckEventHandler = new BuildCheckBuildEventHandler( - new AnalysisDispatchingContextFactory(replayEventSource.Dispatch), + analysisContextFactory, buildCheckManagerProvider.Instance); + var mergedEventSource = new EventArgsDispatcher(); + // Pass the events from replayEventSource to the mergedEventSource + replayEventSource.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); + + // Pass the events from replayEventSource to the BuildCheckBuildEventHandler to produce new events replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); + // Pass the events produced by BuildCheck to the mergedEventSource + analysisContextFactory.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); + + return mergedEventSource; } /// diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 1ce7f1aa336..044e214923e 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -9,20 +9,21 @@ using Microsoft.Build.BackEnd.Logging; using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Framework; +using Microsoft.Build.Logging; using Microsoft.Build.Shared; namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContext : IAnalysisContext { - private readonly Action _dispatch; + private readonly EventArgsDispatcher _eventDispatcher; private readonly BuildEventContext _eventContext; public AnalysisDispatchingContext( - Action dispatch, + EventArgsDispatcher dispatch, BuildEventContext eventContext) { - _dispatch = dispatch; + _eventDispatcher = dispatch; _eventContext = eventContext; } @@ -32,7 +33,7 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) { ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); - _dispatch!(buildEvent!); + _eventDispatcher.Dispatch(buildEvent); } public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) @@ -49,13 +50,13 @@ private void DispatchAsCommentFromText(BuildEventContext buildEventContext, Mess { BuildMessageEventArgs buildEvent = EventsCreatorHelper.CreateMessageEventFromText(buildEventContext, importance, message, messageArgs); - _dispatch!(buildEvent!); + _eventDispatcher.Dispatch(buildEvent); } public void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { BuildErrorEventArgs buildEvent = EventsCreatorHelper.CreateErrorEventFromText(_eventContext, subcategoryResourceName, errorCode, helpKeyword, file, message); - _dispatch!(buildEvent!); + _eventDispatcher.Dispatch(buildEvent); } } diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs index bfa256be85a..f19b8e2e547 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs @@ -1,12 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Logging; @@ -14,10 +8,17 @@ namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory { - private readonly Action _dispatch; + private readonly EventArgsDispatcher _dispatcher; - public AnalysisDispatchingContextFactory(Action dispatch) => _dispatch = dispatch; + public event AnyEventHandler? AnyEventRaised; + + public AnalysisDispatchingContextFactory() + { + _dispatcher = new EventArgsDispatcher(); + + _dispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); + } public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) - => new AnalysisDispatchingContext(_dispatch, eventContext); + => new AnalysisDispatchingContext(_dispatcher, eventContext); } diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index ae8b83fade1..380069a61e0 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -4412,21 +4412,20 @@ private static void ReplayBinaryLog( var replayEventSource = new BinaryLogReplayEventSource(); - if (isBuildCheckEnabled) - { - BuildManager.DefaultBuildManager.AttachBuildCheckForBinaryLogReplay(replayEventSource); - } + var eventSource = isBuildCheckEnabled ? + BuildManager.DefaultBuildManager.GetMergedEventSource(replayEventSource) : + replayEventSource; foreach (var distributedLoggerRecord in distributedLoggerRecords) { ILogger centralLogger = distributedLoggerRecord.CentralLogger; if (centralLogger is INodeLogger nodeLogger) { - nodeLogger.Initialize(replayEventSource, cpuCount); + nodeLogger.Initialize(eventSource, cpuCount); } else { - centralLogger?.Initialize(replayEventSource); + centralLogger?.Initialize(eventSource); } } @@ -4434,11 +4433,11 @@ private static void ReplayBinaryLog( { if (logger is INodeLogger nodeLogger) { - nodeLogger.Initialize(replayEventSource, cpuCount); + nodeLogger.Initialize(eventSource, cpuCount); } else { - logger.Initialize(replayEventSource); + logger.Initialize(eventSource); } } From 624ff6e6cf250dc02a8c8f862d762effaf52cccc Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 18 Jun 2024 14:27:13 +0200 Subject: [PATCH 21/41] simplify the design: pass the EventArgsDispatcher to the AnalysisDispatchingContextFactory constructor rather thatn create its own --- src/Build/BackEnd/BuildManager/BuildManager.cs | 15 ++++++--------- .../AnalysisDispatchingContextFactory.cs | 10 +++++----- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index d9794e794b4..2f451244f7b 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2962,21 +2962,18 @@ public IEventSource GetMergedEventSource(BinaryLogReplayEventSource replayEventS buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); - // Create BuildCheckBuildEventHandler that uses the mergedEventSource to invoke new events - var analysisContextFactory = new AnalysisDispatchingContextFactory(); - - var buildCheckEventHandler = new BuildCheckBuildEventHandler( - analysisContextFactory, - buildCheckManagerProvider.Instance); - var mergedEventSource = new EventArgsDispatcher(); + // Pass the events from replayEventSource to the mergedEventSource replayEventSource.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); + // Create BuildCheckBuildEventHandler that passes new events to the mergedEventSource + var buildCheckEventHandler = new BuildCheckBuildEventHandler( + new AnalysisDispatchingContextFactory(mergedEventSource), + buildCheckManagerProvider.Instance); + // Pass the events from replayEventSource to the BuildCheckBuildEventHandler to produce new events replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); - // Pass the events produced by BuildCheck to the mergedEventSource - analysisContextFactory.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); return mergedEventSource; } diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs index f19b8e2e547..0a133f90f3d 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContextFactory.cs @@ -8,17 +8,17 @@ namespace Microsoft.Build.Experimental.BuildCheck; internal class AnalysisDispatchingContextFactory : IAnalysisContextFactory { - private readonly EventArgsDispatcher _dispatcher; + private readonly EventArgsDispatcher _eventDispatcher; public event AnyEventHandler? AnyEventRaised; - public AnalysisDispatchingContextFactory() + public AnalysisDispatchingContextFactory(EventArgsDispatcher eventDispatcher) { - _dispatcher = new EventArgsDispatcher(); + _eventDispatcher = eventDispatcher; - _dispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); + _eventDispatcher.AnyEventRaised += (sender, e) => AnyEventRaised?.Invoke(sender, e); } public IAnalysisContext CreateAnalysisContext(BuildEventContext eventContext) - => new AnalysisDispatchingContext(_dispatcher, eventContext); + => new AnalysisDispatchingContext(_eventDispatcher, eventContext); } From 6e81c3b38511f7ec5a2df685fd8b6b0b76e543ed Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 19 Jun 2024 10:05:51 +0200 Subject: [PATCH 22/41] implement BuildCheckReplayModeConnector --- .../BackEnd/BuildManager/BuildManager.cs | 29 ++---------- .../BuildCheckReplayModeConnector.cs | 45 +++++++++++++++++++ src/Build/Microsoft.Build.csproj | 1 + src/MSBuild/XMake.cs | 3 +- 4 files changed, 51 insertions(+), 27 deletions(-) create mode 100644 src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 2f451244f7b..176d34cd714 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,33 +2950,10 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public IEventSource GetMergedEventSource(BinaryLogReplayEventSource replayEventSource) + public void EnableBuildCheck() => _buildParameters = new BuildParameters { - _buildParameters = new BuildParameters - { - IsBuildCheckEnabled = true, - }; - - var buildCheckManagerProvider = - ((IBuildComponentHost)this).GetComponent(BuildComponentType.BuildCheckManagerProvider) as IBuildCheckManagerProvider; - - buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); - - var mergedEventSource = new EventArgsDispatcher(); - - // Pass the events from replayEventSource to the mergedEventSource - replayEventSource.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); - - // Create BuildCheckBuildEventHandler that passes new events to the mergedEventSource - var buildCheckEventHandler = new BuildCheckBuildEventHandler( - new AnalysisDispatchingContextFactory(mergedEventSource), - buildCheckManagerProvider.Instance); - - // Pass the events from replayEventSource to the BuildCheckBuildEventHandler to produce new events - replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); - - return mergedEventSource; - } + IsBuildCheckEnabled = true, + }; /// /// Creates a logging service around the specified set of loggers. diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs new file mode 100644 index 00000000000..44542d5c071 --- /dev/null +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.BackEnd; +using Microsoft.Build.Execution; +using Microsoft.Build.Experimental.BuildCheck.Infrastructure; +using Microsoft.Build.Framework; +using Microsoft.Build.Logging; + +namespace Microsoft.Build.Experimental.BuildCheck; + +public static class BuildCheckReplayModeConnector +{ + public static IEventSource GetMergedEventSource( + BuildManager buildManager, + IEventSource replayEventSource) + { + buildManager.EnableBuildCheck(); + + var buildCheckManagerProvider = ((IBuildComponentHost)buildManager) + .GetComponent(BuildComponentType.BuildCheckManagerProvider) as IBuildCheckManagerProvider; + + buildCheckManagerProvider!.Instance.SetDataSource(BuildCheckDataSource.EventArgs); + + var mergedEventSource = new EventArgsDispatcher(); + + // Pass the events from replayEventSource to the mergedEventSource + replayEventSource.AnyEventRaised += (sender, e) => mergedEventSource.Dispatch(e); + + // Create BuildCheckBuildEventHandler that passes new events to the mergedEventSource + var buildCheckEventHandler = new BuildCheckBuildEventHandler( + new AnalysisDispatchingContextFactory(mergedEventSource), + buildCheckManagerProvider.Instance); + + // Pass the events from replayEventSource to the BuildCheckBuildEventHandler to produce new events + replayEventSource.AnyEventRaised += (sender, e) => buildCheckEventHandler.HandleBuildEvent(e); + + return mergedEventSource; + } +} diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index 9751b24cce6..b03b3ab32c4 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -169,6 +169,7 @@ + diff --git a/src/MSBuild/XMake.cs b/src/MSBuild/XMake.cs index 380069a61e0..882290d86d3 100644 --- a/src/MSBuild/XMake.cs +++ b/src/MSBuild/XMake.cs @@ -25,6 +25,7 @@ using Microsoft.Build.Exceptions; using Microsoft.Build.Execution; using Microsoft.Build.Experimental; +using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.ProjectCache; using Microsoft.Build.Framework; using Microsoft.Build.Framework.Telemetry; @@ -4413,7 +4414,7 @@ private static void ReplayBinaryLog( var replayEventSource = new BinaryLogReplayEventSource(); var eventSource = isBuildCheckEnabled ? - BuildManager.DefaultBuildManager.GetMergedEventSource(replayEventSource) : + BuildCheckReplayModeConnector.GetMergedEventSource(BuildManager.DefaultBuildManager, replayEventSource) : replayEventSource; foreach (var distributedLoggerRecord in distributedLoggerRecords) From 40d0e3b33f6188617d09bb7ee5cfa9cfeb46c362 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 19 Jun 2024 10:21:20 +0200 Subject: [PATCH 23/41] add xml comments --- src/Build/BackEnd/BuildManager/BuildManager.cs | 5 ++++- .../AnalysisContext/AnalysisDispatchingContext.cs | 3 +++ .../AnalysisContext/AnalysisLoggingContext.cs | 3 +++ .../AnalysisContext/IAnalysisContext.cs | 3 +++ .../Infrastructure/BuildCheckReplayModeConnector.cs | 11 ++++++++++- 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 176d34cd714..aad33b3b134 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,7 +2950,10 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - public void EnableBuildCheck() => _buildParameters = new BuildParameters + /// + /// Enables BuildCheck for binary log replay. + /// + public void EnableBuildCheckForBinaryLogReplay() => _buildParameters = new BuildParameters { IsBuildCheckEnabled = true, }; diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 044e214923e..93bd9fcb307 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -14,6 +14,9 @@ namespace Microsoft.Build.Experimental.BuildCheck; +/// +/// that uses to dispatch. +/// internal class AnalysisDispatchingContext : IAnalysisContext { private readonly EventArgsDispatcher _eventDispatcher; diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs index 38337ae18a9..5eae0885477 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs @@ -12,6 +12,9 @@ namespace Microsoft.Build.Experimental.BuildCheck; +/// +/// that uses to dispatch. +/// internal class AnalysisLoggingContext : IAnalysisContext { private readonly ILoggingService _loggingService; diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs index be4cb8c6049..7c4a338500d 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs @@ -11,6 +11,9 @@ namespace Microsoft.Build.Experimental.BuildCheck; +/// +/// Interface for dispatching . +/// internal interface IAnalysisContext { BuildEventContext BuildEventContext { get; } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs index 44542d5c071..7757367cda8 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs @@ -14,13 +14,22 @@ namespace Microsoft.Build.Experimental.BuildCheck; +/// +/// The class that created an for binary log replay with BuildCheck enabled. +/// public static class BuildCheckReplayModeConnector { + /// + /// Gets merged event source for binary log replay with BuildCheck enabled. + /// + /// that has component. + /// The initial event source. + /// The merged event source for binary log replay. public static IEventSource GetMergedEventSource( BuildManager buildManager, IEventSource replayEventSource) { - buildManager.EnableBuildCheck(); + buildManager.EnableBuildCheckForBinaryLogReplay(); var buildCheckManagerProvider = ((IBuildComponentHost)buildManager) .GetComponent(BuildComponentType.BuildCheckManagerProvider) as IBuildCheckManagerProvider; From 1e6694e1d00569b986ee5a08204d99319faf0c01 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 19 Jun 2024 10:47:21 +0200 Subject: [PATCH 24/41] rename method --- src/Build/BackEnd/BuildManager/BuildManager.cs | 10 ++++++---- .../Infrastructure/BuildCheckReplayModeConnector.cs | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index aad33b3b134..e1aad0a0a30 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2951,12 +2951,14 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) } /// - /// Enables BuildCheck for binary log replay. + /// Enables BuildCheck. /// - public void EnableBuildCheckForBinaryLogReplay() => _buildParameters = new BuildParameters + public void EnableBuildCheck() { - IsBuildCheckEnabled = true, - }; + _buildParameters ??= new BuildParameters(); + + _buildParameters.IsBuildCheckEnabled = true; + } /// /// Creates a logging service around the specified set of loggers. diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs index 7757367cda8..6ea375c6faf 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs @@ -29,7 +29,7 @@ public static IEventSource GetMergedEventSource( BuildManager buildManager, IEventSource replayEventSource) { - buildManager.EnableBuildCheckForBinaryLogReplay(); + buildManager.EnableBuildCheck(); var buildCheckManagerProvider = ((IBuildComponentHost)buildManager) .GetComponent(BuildComponentType.BuildCheckManagerProvider) as IBuildCheckManagerProvider; From f9fbfab1255092200c58d9a54af6f8d80b383058 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 19 Jun 2024 13:36:59 +0200 Subject: [PATCH 25/41] make BuildManager.EnableBuildCheck internal --- src/Build/BackEnd/BuildManager/BuildManager.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index e1aad0a0a30..33d40d9d461 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,10 +2950,7 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } - /// - /// Enables BuildCheck. - /// - public void EnableBuildCheck() + internal void EnableBuildCheck() { _buildParameters ??= new BuildParameters(); From 6b98451bc1199593362069d619a6cc8153a314c0 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 20 Jun 2024 14:56:57 +0200 Subject: [PATCH 26/41] add check for BC0102 in the test; set same timeout --- src/BuildCheck.UnitTests/EndToEndTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index 23313ad24ec..fbfe748e717 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -73,13 +73,13 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBinaryLogReplay(bool buildInO RunnerUtilities.ExecBootstrapedMSBuild( $"{Path.GetFileName(projectFile.Path)} /m:1 -nr:False -restore -bl:{logFile}", - out bool success); + out bool success, false, _env.Output, timeoutMilliseconds: 120_000); success.ShouldBeTrue(); string output = RunnerUtilities.ExecBootstrapedMSBuild( $"{logFile} -flp:logfile={Path.Combine(projectDirectory!, "logFile.log")};verbosity=diagnostic {(analysisRequested ? "-analyze" : string.Empty)}", - out success, false, _env.Output, timeoutMilliseconds: 130_000); + out success, false, _env.Output, timeoutMilliseconds: 120_000); _env.Output.WriteLine(output); @@ -89,10 +89,12 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBinaryLogReplay(bool buildInO if (analysisRequested) { output.ShouldContain("BC0101"); + output.ShouldContain("BC0102"); } else { output.ShouldNotContain("BC0101"); + output.ShouldNotContain("BC0102"); } } From b8c171406e0669abbdcdfe0a94c9da47b778d540 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Thu, 20 Jun 2024 15:01:24 +0200 Subject: [PATCH 27/41] remove skip from the test --- src/BuildCheck.UnitTests/EndToEndTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index df31f2253d8..50ce7ce9a37 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -60,7 +60,8 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBuild(bool buildInOutOfProces } } - [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] + // [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] + [Theory] [InlineData(true, true, "warning")] [InlineData(true, true, "error")] [InlineData(true, true, "info")] From fd5e4f529fc1cd4aab240f5953fc448ef3455546 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada <114938397+surayya-MS@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:09:31 +0200 Subject: [PATCH 28/41] Update src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs Co-authored-by: Rainer Sigwald --- .../AnalysisContext/AnalysisDispatchingContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 93bd9fcb307..93eb7c938e2 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -34,7 +34,7 @@ public AnalysisDispatchingContext( public void DispatchBuildEvent(BuildEventArgs buildEvent) { - ErrorUtilities.VerifyThrow(buildEvent != null, "buildEvent is null"); + ErrorUtilities.VerifyThrowArgumentNull(buildEvent, nameof(buildEvent)); _eventDispatcher.Dispatch(buildEvent); } From 00f9681fe6f14fea3197ea43531204bd78ab1430 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada <114938397+surayya-MS@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:09:42 +0200 Subject: [PATCH 29/41] Update src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs Co-authored-by: Rainer Sigwald --- .../AnalysisContext/AnalysisDispatchingContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index 93eb7c938e2..fb05dc0d1be 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -41,7 +41,7 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) { - ErrorUtilities.VerifyThrow(!string.IsNullOrEmpty(messageResourceName), "Need resource string for comment message."); + ErrorUtilities.VerifyThrowArgumentLength(messageResourceName); DispatchAsCommentFromText(_eventContext, importance, ResourceUtilities.GetResourceString(messageResourceName), messageArgs); } From a5057bce19f546970b2b99ba1263de6732c94710 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada <114938397+surayya-MS@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:17:40 +0200 Subject: [PATCH 30/41] Update src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs Co-authored-by: Rainer Sigwald --- .../BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs index dc4c9a19bc9..9880596ef83 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs @@ -101,7 +101,7 @@ private void HandleBuildCheckAcquisitionEvent(BuildCheckAcquisitionEventArgs eve eventArgs.ToAnalyzerAcquisitionData(), _analyzerContextFactory.CreateAnalysisContext(GetBuildEventContext(eventArgs))); - private bool IsMetaProjFile(string? projectFile) => !string.IsNullOrEmpty(projectFile) && projectFile!.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase); + private bool IsMetaProjFile(string? projectFile) => projectFile?.EndsWith(".metaproj", StringComparison.OrdinalIgnoreCase) == true; private readonly Dictionary _stats = new Dictionary(); From c3a47868d72334ecbd0e20bb41626607aaaedd9e Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada <114938397+surayya-MS@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:22:11 +0200 Subject: [PATCH 31/41] Update src/Build/BackEnd/Shared/EventsCreatorHelper.cs Co-authored-by: Rainer Sigwald --- src/Build/BackEnd/Shared/EventsCreatorHelper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs index d7f869d73c7..0b9503569b0 100644 --- a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs +++ b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs @@ -32,9 +32,9 @@ public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext public static BuildErrorEventArgs CreateErrorEventFromText(BuildEventContext buildEventContext, string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { - ErrorUtilities.VerifyThrow(buildEventContext != null, "Must specify the buildEventContext"); - ErrorUtilities.VerifyThrow(file != null, "Must specify the associated file."); - ErrorUtilities.VerifyThrow(message != null, "Need error message."); + ErrorUtilities.VerifyThrowArgumentNull(buildEventContext); + ErrorUtilities.VerifyThrowArgumentNull(file); + ErrorUtilities.VerifyThrowArgumentNull(message); string? subcategory = null; From a2cdd886e86c506408395734aa6b9470a354c891 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada <114938397+surayya-MS@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:22:34 +0200 Subject: [PATCH 32/41] Update src/Build/BackEnd/Shared/EventsCreatorHelper.cs Co-authored-by: Rainer Sigwald --- src/Build/BackEnd/Shared/EventsCreatorHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs index 0b9503569b0..a9233c3f35f 100644 --- a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs +++ b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs @@ -15,8 +15,8 @@ internal static class EventsCreatorHelper { public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs) { - ErrorUtilities.VerifyThrow(buildEventContext != null, "buildEventContext was null"); - ErrorUtilities.VerifyThrow(message != null, "message was null"); + ErrorUtilities.VerifyThrowArgumentNull(buildEventContext); + ErrorUtilities.VerifyThrowArgumentNull(message); BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( message, From 4a7fc21a931dabf6829c6445892e27312039ed64 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Fri, 21 Jun 2024 13:37:33 +0200 Subject: [PATCH 33/41] small fix --- src/Build/BackEnd/Shared/EventsCreatorHelper.cs | 10 +++++----- .../AnalysisContext/AnalysisDispatchingContext.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs index a9233c3f35f..d4ad3a9da88 100644 --- a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs +++ b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs @@ -15,8 +15,8 @@ internal static class EventsCreatorHelper { public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs) { - ErrorUtilities.VerifyThrowArgumentNull(buildEventContext); - ErrorUtilities.VerifyThrowArgumentNull(message); + ErrorUtilities.VerifyThrowArgumentNull(buildEventContext, nameof(buildEventContext)); + ErrorUtilities.VerifyThrowArgumentNull(message, nameof(message)); BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( message, @@ -32,9 +32,9 @@ public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext public static BuildErrorEventArgs CreateErrorEventFromText(BuildEventContext buildEventContext, string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { - ErrorUtilities.VerifyThrowArgumentNull(buildEventContext); - ErrorUtilities.VerifyThrowArgumentNull(file); - ErrorUtilities.VerifyThrowArgumentNull(message); + ErrorUtilities.VerifyThrowArgumentNull(buildEventContext, nameof(buildEventContext)); + ErrorUtilities.VerifyThrowArgumentNull(file, nameof(file)); + ErrorUtilities.VerifyThrowArgumentNull(message, nameof(message)); string? subcategory = null; diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index fb05dc0d1be..ef5ad9622d0 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -41,7 +41,7 @@ public void DispatchBuildEvent(BuildEventArgs buildEvent) public void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs) { - ErrorUtilities.VerifyThrowArgumentLength(messageResourceName); + ErrorUtilities.VerifyThrowInternalLength(messageResourceName,nameof(messageResourceName)); DispatchAsCommentFromText(_eventContext, importance, ResourceUtilities.GetResourceString(messageResourceName), messageArgs); } From 965ad711826bfa6196fee6d9d09c385aa5de5a15 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Fri, 21 Jun 2024 13:59:50 +0200 Subject: [PATCH 34/41] add summary for IAnalysisContext --- .../AnalysisContext/IAnalysisContext.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs index 7c4a338500d..00439c6dd55 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/IAnalysisContext.cs @@ -12,17 +12,32 @@ namespace Microsoft.Build.Experimental.BuildCheck; /// -/// Interface for dispatching . +/// Interface that contains an instance of and methods to dispatch it. /// internal interface IAnalysisContext { + /// + /// Instance of . + /// BuildEventContext BuildEventContext { get; } + /// + /// Dispatch the instance of as a comment. + /// void DispatchAsComment(MessageImportance importance, string messageResourceName, params object?[] messageArgs); + /// + /// Dispatch a . + /// void DispatchBuildEvent(BuildEventArgs buildEvent); + /// + /// Dispatch the instance of as an error message. + /// void DispatchAsErrorFromText(string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message); + /// + /// Dispatch the instance of as a comment with provided text for the message. + /// void DispatchAsCommentFromText(MessageImportance importance, string message); } From 50c1f78ccc6114f96d268eedd70728ba9296aa6c Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Fri, 21 Jun 2024 14:48:13 +0200 Subject: [PATCH 35/41] use VerifyThrowInternalNull instead of VerifyThrowArgumentNull --- src/Build/BackEnd/Shared/EventsCreatorHelper.cs | 10 +++++----- .../AnalysisContext/AnalysisDispatchingContext.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs index d4ad3a9da88..ead0c205d27 100644 --- a/src/Build/BackEnd/Shared/EventsCreatorHelper.cs +++ b/src/Build/BackEnd/Shared/EventsCreatorHelper.cs @@ -15,8 +15,8 @@ internal static class EventsCreatorHelper { public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext buildEventContext, MessageImportance importance, string message, params object?[]? messageArgs) { - ErrorUtilities.VerifyThrowArgumentNull(buildEventContext, nameof(buildEventContext)); - ErrorUtilities.VerifyThrowArgumentNull(message, nameof(message)); + ErrorUtilities.VerifyThrowInternalNull(buildEventContext, nameof(buildEventContext)); + ErrorUtilities.VerifyThrowInternalNull(message, nameof(message)); BuildMessageEventArgs buildEvent = new BuildMessageEventArgs( message, @@ -32,9 +32,9 @@ public static BuildMessageEventArgs CreateMessageEventFromText(BuildEventContext public static BuildErrorEventArgs CreateErrorEventFromText(BuildEventContext buildEventContext, string? subcategoryResourceName, string? errorCode, string? helpKeyword, BuildEventFileInfo file, string message) { - ErrorUtilities.VerifyThrowArgumentNull(buildEventContext, nameof(buildEventContext)); - ErrorUtilities.VerifyThrowArgumentNull(file, nameof(file)); - ErrorUtilities.VerifyThrowArgumentNull(message, nameof(message)); + ErrorUtilities.VerifyThrowInternalNull(buildEventContext, nameof(buildEventContext)); + ErrorUtilities.VerifyThrowInternalNull(file, nameof(file)); + ErrorUtilities.VerifyThrowInternalNull(message, nameof(message)); string? subcategory = null; diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs index ef5ad9622d0..f9e8cd36cfb 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisDispatchingContext.cs @@ -34,7 +34,7 @@ public AnalysisDispatchingContext( public void DispatchBuildEvent(BuildEventArgs buildEvent) { - ErrorUtilities.VerifyThrowArgumentNull(buildEvent, nameof(buildEvent)); + ErrorUtilities.VerifyThrowInternalNull(buildEvent, nameof(buildEvent)); _eventDispatcher.Dispatch(buildEvent); } From 0ed4347e549e5e3b5337478ca723aecef7a34b10 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Mon, 24 Jun 2024 14:43:05 +0200 Subject: [PATCH 36/41] compile all BuildCheck\**\*.cs files instead of manually specifying every sing;e file --- src/Build/Microsoft.Build.csproj | 47 +------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/src/Build/Microsoft.Build.csproj b/src/Build/Microsoft.Build.csproj index b03b3ab32c4..363a6330ddd 100644 --- a/src/Build/Microsoft.Build.csproj +++ b/src/Build/Microsoft.Build.csproj @@ -156,52 +156,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + From d1815bda5c9a1df9b944a20efa0f0492b6d9aa48 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Tue, 25 Jun 2024 11:45:46 +0200 Subject: [PATCH 37/41] add doc comment for BuildManager.EnableBuildCheck method --- src/Build/BackEnd/BuildManager/BuildManager.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 33d40d9d461..1ed093597ed 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -2950,6 +2950,9 @@ private void OnProjectStarted(object sender, ProjectStartedEventArgs e) }); } + /// + /// Sets to true. Used for BuildCheck Replay Mode. + /// internal void EnableBuildCheck() { _buildParameters ??= new BuildParameters(); From 0f7d161de7a0046c708e3dc4fda7fd3e78f27051 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 26 Jun 2024 09:44:57 +0200 Subject: [PATCH 38/41] add skips for e2e flak tests --- src/BuildCheck.UnitTests/EndToEndTests.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/BuildCheck.UnitTests/EndToEndTests.cs b/src/BuildCheck.UnitTests/EndToEndTests.cs index cafebe232a6..412a00895f3 100644 --- a/src/BuildCheck.UnitTests/EndToEndTests.cs +++ b/src/BuildCheck.UnitTests/EndToEndTests.cs @@ -31,8 +31,7 @@ public EndToEndTests(ITestOutputHelper output) public void Dispose() => _env.Dispose(); - // [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] - [Theory] + [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] [InlineData(true, true)] [InlineData(false, true)] [InlineData(false, false)] @@ -60,8 +59,7 @@ public void SampleAnalyzerIntegrationTest_AnalyzeOnBuild(bool buildInOutOfProces } } - // [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] - [Theory] + [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] [InlineData(true, true, "warning")] [InlineData(true, true, "error")] [InlineData(true, true, "info")] @@ -103,7 +101,7 @@ public void SampleAnalyzerIntegrationTest_ReplayBinaryLogOfAnalyzedBuild(bool bu } } - [Theory] + [Theory(Skip = "https://github.com/dotnet/msbuild/issues/10036")] [InlineData(true, true)] [InlineData(false, true)] [InlineData(false, false)] From 5a4e6b059126d76f7515c8416963f5bc63ba0c92 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 26 Jun 2024 09:53:33 +0200 Subject: [PATCH 39/41] fix typo in doc comment --- .../Infrastructure/AnalysisContext/AnalysisLoggingContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs index 5eae0885477..95b62f0e202 100644 --- a/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs +++ b/src/Build/BuildCheck/Infrastructure/AnalysisContext/AnalysisLoggingContext.cs @@ -13,7 +13,7 @@ namespace Microsoft.Build.Experimental.BuildCheck; /// -/// that uses to dispatch. +/// that uses to dispatch. /// internal class AnalysisLoggingContext : IAnalysisContext { From 31a4ac3ad819bcc46e1741d1b0fdf6e1a57edc14 Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 26 Jun 2024 09:58:58 +0200 Subject: [PATCH 40/41] fix typos + improve doc comment --- .../Infrastructure/BuildCheckReplayModeConnector.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs index 6ea375c6faf..e3e5f1cc9d6 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs @@ -15,14 +15,14 @@ namespace Microsoft.Build.Experimental.BuildCheck; /// -/// The class that created an for binary log replay with BuildCheck enabled. +/// The class that creates an for binary log replay with BuildCheck enabled. /// public static class BuildCheckReplayModeConnector { /// - /// Gets merged event source for binary log replay with BuildCheck enabled. + /// Gets merged for binary log replay with BuildCheck enabled. /// - /// that has component. + /// to get the registered component from. /// The initial event source. /// The merged event source for binary log replay. public static IEventSource GetMergedEventSource( From 8311b116e38ad8854fb713cd2c08cf7752d9baad Mon Sep 17 00:00:00 2001 From: Surayya Huseyn Zada Date: Wed, 26 Jun 2024 10:03:54 +0200 Subject: [PATCH 41/41] improve doc comment --- .../BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs index e3e5f1cc9d6..9405818dc9f 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckReplayModeConnector.cs @@ -24,7 +24,7 @@ public static class BuildCheckReplayModeConnector /// /// to get the registered component from. /// The initial event source. - /// The merged event source for binary log replay. + /// The merged . Used for binary log replay. public static IEventSource GetMergedEventSource( BuildManager buildManager, IEventSource replayEventSource)