diff --git a/src/Build.UnitTests/BackEnd/AssemblyTaskFactory_Tests.cs b/src/Build.UnitTests/BackEnd/AssemblyTaskFactory_Tests.cs index 500f4ded77f..3ef0a1ae0ad 100644 --- a/src/Build.UnitTests/BackEnd/AssemblyTaskFactory_Tests.cs +++ b/src/Build.UnitTests/BackEnd/AssemblyTaskFactory_Tests.cs @@ -712,7 +712,7 @@ private void SetupTaskFactory(TaskHostParameters factoryParameters, bool explici factoryParameters = factoryParameters.WithTaskHostFactoryExplicitlyRequested(true); } - _loadedType = _taskFactory.InitializeFactory(_loadInfo, "TaskToTestFactories", new Dictionary(), string.Empty, factoryParameters, explicitlyLaunchTaskHost, new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4)), ElementLocation.Create("NONE"), String.Empty); + _loadedType = _taskFactory.InitializeFactory(_loadInfo, "TaskToTestFactories", new Dictionary(), string.Empty, factoryParameters, explicitlyLaunchTaskHost, new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)), ElementLocation.Create("NONE"), String.Empty); Assert.True(_loadedType.Assembly.Equals(_loadInfo)); // "Expected the AssemblyLoadInfo to be equal" } diff --git a/src/Build.UnitTests/BackEnd/BatchingEngine_Tests.cs b/src/Build.UnitTests/BackEnd/BatchingEngine_Tests.cs index 837ca550c2d..1530dd11d5a 100644 --- a/src/Build.UnitTests/BackEnd/BatchingEngine_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BatchingEngine_Tests.cs @@ -57,7 +57,7 @@ public void GetBuckets() parameters, CreateLookup(itemsByType, properties), MockElementLocation.Instance, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); Assert.Equal(5, buckets.Count); @@ -74,7 +74,7 @@ public void GetBuckets() Directory.GetCurrentDirectory(), MockElementLocation.Instance, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4)))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)))); Assert.Equal("a.doc;b.doc;c.doc;d.doc;e.doc", bucket.Expander.ExpandIntoStringAndUnescape("@(doc)", ExpanderOptions.ExpandItems, MockElementLocation.Instance)); Assert.Equal("unittests.foo", bucket.Expander.ExpandIntoStringAndUnescape("$(bogus)$(UNITTESTS)", ExpanderOptions.ExpandPropertiesAndMetadata, MockElementLocation.Instance)); } @@ -146,7 +146,7 @@ public void ValidUnqualifiedMetadataReference() parameters, CreateLookup(itemsByType, properties), null, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); Assert.Equal(2, buckets.Count); } @@ -184,7 +184,7 @@ public void InvalidUnqualifiedMetadataReference() parameters, CreateLookup(itemsByType, properties), MockElementLocation.Instance, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); }); } /// @@ -209,7 +209,7 @@ public void NoItemsConsumed() parameters, CreateLookup(itemsByType, properties), MockElementLocation.Instance, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); }); } /// @@ -239,7 +239,7 @@ public void Regress_Mutation_DuplicateBatchingBucketsAreFoldedTogether() parameters, CreateLookup(itemsByType, properties), null, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); // If duplicate buckets have been folded correctly, then there will be exactly one bucket here // containing both a.foo and b.foo. diff --git a/src/Build.UnitTests/BackEnd/BuildRequestEngine_Tests.cs b/src/Build.UnitTests/BackEnd/BuildRequestEngine_Tests.cs index 3d9c91ca2c4..f8f5da044f1 100644 --- a/src/Build.UnitTests/BackEnd/BuildRequestEngine_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildRequestEngine_Tests.cs @@ -335,7 +335,7 @@ public void TestEngineShutdownWhileActive() BuildRequest request = CreateNewBuildRequest(1, targets); VerifyEngineStatus(BuildRequestEngineStatus.Uninitialized, true); - _engine.InitializeForBuild(new NodeLoggingContext(_host.LoggingService, 0, false)); + _engine.InitializeForBuild(CreateForTesting(_host)); // We neeed to get the status changed AutoResetEvent returned to the non-signaled state correctly after each status change for verifying the engine status via waiting for a signal next time. // Make sure it returns back to the non-signaled state. VerifyEngineStatus(BuildRequestEngineStatus.Idle); @@ -366,7 +366,7 @@ public void TestSimpleBuildScenario() BuildRequest request = CreateNewBuildRequest(1, targets); VerifyEngineStatus(BuildRequestEngineStatus.Uninitialized, true); - _engine.InitializeForBuild(new NodeLoggingContext(_host.LoggingService, 0, false)); + _engine.InitializeForBuild(CreateForTesting(_host)); VerifyEngineStatus(BuildRequestEngineStatus.Idle); _engine.SubmitBuildRequest(request); @@ -400,7 +400,7 @@ public void TestBuildWithChildren() // Kick it off VerifyEngineStatus(BuildRequestEngineStatus.Uninitialized, true); - _engine.InitializeForBuild(new NodeLoggingContext(_host.LoggingService, 0, false)); + _engine.InitializeForBuild(CreateForTesting(_host)); VerifyEngineStatus(BuildRequestEngineStatus.Idle); _engine.SubmitBuildRequest(request); @@ -455,7 +455,7 @@ public void TestBuildWithNewConfiguration() // Kick it off VerifyEngineStatus(BuildRequestEngineStatus.Uninitialized, true); - _engine.InitializeForBuild(new NodeLoggingContext(_host.LoggingService, 0, false)); + _engine.InitializeForBuild(CreateForTesting(_host)); VerifyEngineStatus(BuildRequestEngineStatus.Idle); _engine.SubmitBuildRequest(request); @@ -501,6 +501,8 @@ public void TestShutdown() { } + private NodeLoggingContext CreateForTesting(MockHost host) => new NodeLoggingContext(host.LoggingService, BuildEventContext.Invalid.WithNodeId(0), 0, false); + private BuildRequest CreateNewBuildRequest(int configurationId, string[] targets) { BuildRequest request = new BuildRequest(1 /* submission id */, _nodeRequestId++, configurationId, targets, null, BuildEventContext.Invalid, null); diff --git a/src/Build.UnitTests/BackEnd/BuildResult_Tests.cs b/src/Build.UnitTests/BackEnd/BuildResult_Tests.cs index 1b94ac3357f..9469731503b 100644 --- a/src/Build.UnitTests/BackEnd/BuildResult_Tests.cs +++ b/src/Build.UnitTests/BackEnd/BuildResult_Tests.cs @@ -309,7 +309,7 @@ public void TestEnumerator() [Fact] public void TestTranslation() { - BuildRequest request = new BuildRequest(1, 1, 2, new string[] { "alpha", "omega" }, null, new BuildEventContext(1, 1, 2, 3, 4, 5), null); + BuildRequest request = new BuildRequest(1, 1, 2, new string[] { "alpha", "omega" }, null, BuildEventContext.CreateInitial(1, 1).WithEvaluationId(2).WithProjectInstanceId(3).WithProjectContextId(4).WithTaskId(5), null); BuildResult result = new BuildResult(request, new BuildAbortedException()); TaskItem fooTaskItem = new TaskItem("foo", "asdf.proj"); diff --git a/src/Build.UnitTests/BackEnd/EventSourceSink_Tests.cs b/src/Build.UnitTests/BackEnd/EventSourceSink_Tests.cs index 0f6e34c6449..8a3b305b9fd 100644 --- a/src/Build.UnitTests/BackEnd/EventSourceSink_Tests.cs +++ b/src/Build.UnitTests/BackEnd/EventSourceSink_Tests.cs @@ -756,7 +756,7 @@ internal sealed class RaiseEventHelper /// private static BuildWarningEventArgs s_buildWarning = new BuildWarningEventArgs("SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender") { - BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6) + BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6) }; /// diff --git a/src/Build.UnitTests/BackEnd/IntrinsicTask_Tests.cs b/src/Build.UnitTests/BackEnd/IntrinsicTask_Tests.cs index 0ae6ed74774..d3c6ff9a0d4 100644 --- a/src/Build.UnitTests/BackEnd/IntrinsicTask_Tests.cs +++ b/src/Build.UnitTests/BackEnd/IntrinsicTask_Tests.cs @@ -3958,7 +3958,7 @@ private static IntrinsicTask CreateIntrinsicTask(string content) ProjectInstance projectInstance = project.CreateProjectInstance(); ProjectTargetInstanceChild targetChild = projectInstance.Targets["t"].Children.First(); - NodeLoggingContext nodeContext = new NodeLoggingContext(new MockLoggingService(), 1, false); + NodeLoggingContext nodeContext = new NodeLoggingContext(new MockLoggingService(), BuildEventContext.Invalid.WithNodeId(1), 1, false); BuildRequestEntry entry = new BuildRequestEntry(new BuildRequest(1 /* submissionId */, 0, 1, new string[] { "t" }, null, BuildEventContext.Invalid, null), new BuildRequestConfiguration(1, new BuildRequestData("projectFile", new Dictionary(), "3.5", Array.Empty(), null), "2.0"), CreateStubTaskEnvironment()); entry.RequestConfiguration.Project = projectInstance; IntrinsicTask task = IntrinsicTask.InstantiateTask( @@ -3993,7 +3993,7 @@ internal static void AssertItemEvaluationFromTarget(string projectContents, stri var projectInstance = project.CreateProjectInstance(); var targetChild = projectInstance.Targets["t"].Children.First(); - var nodeContext = new NodeLoggingContext(new MockLoggingService(), 1, false); + var nodeContext = new NodeLoggingContext(new MockLoggingService(), BuildEventContext.Invalid.WithNodeId(1), 1, false); var entry = new BuildRequestEntry(new BuildRequest(1 /* submissionId */, 0, 1, new string[] { targetName }, null, BuildEventContext.Invalid, null), new BuildRequestConfiguration(1, new BuildRequestData("projectFile", new Dictionary(), "3.5", Array.Empty(), null), "2.0"), CreateStubTaskEnvironment()); entry.RequestConfiguration.Project = projectInstance; var task = IntrinsicTask.InstantiateTask( diff --git a/src/Build.UnitTests/BackEnd/LoggingContext_Tests.cs b/src/Build.UnitTests/BackEnd/LoggingContext_Tests.cs index 020d527ab3f..25a9ebae717 100644 --- a/src/Build.UnitTests/BackEnd/LoggingContext_Tests.cs +++ b/src/Build.UnitTests/BackEnd/LoggingContext_Tests.cs @@ -23,13 +23,15 @@ public LoggingContext_Tests(ITestOutputHelper outputHelper) _output = outputHelper; } + private NodeLoggingContext CreateNodeLoggingContext(int nodeId, bool isInProc) => new NodeLoggingContext(new MockLoggingService(_output.WriteLine), BuildEventContext.Invalid.WithNodeId(nodeId), nodeId, isInProc); + /// /// A few simple tests for NodeLoggingContexts. /// [Fact] public void CreateValidNodeLoggingContexts() { - NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 1, true); + NodeLoggingContext context = CreateNodeLoggingContext(1, true); context.IsInProcNode.ShouldBeTrue(); context.IsValid.ShouldBeTrue(); @@ -38,7 +40,7 @@ public void CreateValidNodeLoggingContexts() context.BuildEventContext.NodeId.ShouldBe(1); - NodeLoggingContext context2 = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 2, false); + NodeLoggingContext context2 = CreateNodeLoggingContext(2, false); context2.IsInProcNode.ShouldBeFalse(); context2.IsValid.ShouldBeTrue(); @@ -58,14 +60,14 @@ public void InvalidNodeIdOnNodeLoggingContext() { Assert.Throws(() => { - _ = new NodeLoggingContext(new MockLoggingService(), -2, true); + _ = CreateNodeLoggingContext(-2, true); }); } [Fact] public void HasLoggedErrors() { - NodeLoggingContext context = new NodeLoggingContext(new MockLoggingService(_output.WriteLine), 1, true); + NodeLoggingContext context = CreateNodeLoggingContext(1, true); context.HasLoggedErrors.ShouldBeFalse(); context.LogCommentFromText(Framework.MessageImportance.High, "Test message"); diff --git a/src/Build.UnitTests/BackEnd/LoggingService_Tests.cs b/src/Build.UnitTests/BackEnd/LoggingService_Tests.cs index 4d42f596bcb..dc7d9baedec 100644 --- a/src/Build.UnitTests/BackEnd/LoggingService_Tests.cs +++ b/src/Build.UnitTests/BackEnd/LoggingService_Tests.cs @@ -788,13 +788,15 @@ public void TreatWarningsAsErrorWhenAllSpecified(int loggerMode, int nodeId) [Fact] public void VerifyWarningsPromotedToErrorsAreCounted() { - ILoggingService ls = LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); + var submissionId = 1; + var nodeId = 1; + ILoggingService ls = LoggingService.CreateLoggingService(LoggerMode.Synchronous, nodeId); ls.WarningsAsErrors = new HashSet(); ls.WarningsAsErrors.Add("FOR123"); BuildWarningEventArgs warningArgs = new("abc", "FOR123", "", 0, 0, 0, 0, "warning message", "keyword", "sender"); - warningArgs.BuildEventContext = new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidProjectContextId, 5, 6); + warningArgs.BuildEventContext = BuildEventContext.Invalid.WithSubmissionId(submissionId).WithNodeId(nodeId); ls.LogBuildEvent(warningArgs); - ls.HasBuildSubmissionLoggedErrors(1).ShouldBeTrue(); + ls.HasBuildSubmissionLoggedErrors(submissionId).ShouldBeTrue(); } /// @@ -952,13 +954,11 @@ private MockLogger GetLoggedEventsWithWarningsAsErrorsOrMessages( { IBuildComponentHost host = new MockHost(); - BuildEventContext buildEventContext = new BuildEventContext( - submissionId: 0, - nodeId: 1, - projectInstanceId: 2, - projectContextId: -1, - targetId: -1, - taskId: -1); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(0, 1) + .WithProjectInstanceId(2) + .WithProjectContextId(-1) + .WithTargetId(-1) + .WithTaskId(-1); BuildRequestData buildRequestData = new BuildRequestData("projectFile", new Dictionary(), "Current", new[] { "Build" }, null); @@ -974,7 +974,9 @@ private MockLogger GetLoggedEventsWithWarningsAsErrorsOrMessages( loggingService.RegisterLogger(logger); - BuildEventContext projectStarted = loggingService.LogProjectStarted(buildEventContext, 0, buildEventContext.ProjectInstanceId, BuildEventContext.Invalid, "projectFile", "Build", Enumerable.Empty(), Enumerable.Empty()); + var projectStartedArgs = loggingService.CreateProjectStartedForLocalProject(BuildEventContext.Invalid, buildEventContext.ProjectInstanceId, "projectFile", "Build", null, Enumerable.Empty(), Enumerable.Empty(), null); + loggingService.LogProjectStarted(projectStartedArgs); + BuildEventContext projectStarted = projectStartedArgs.BuildEventContext; if (warningsAsErrorsForProject != null) { diff --git a/src/Build.UnitTests/BackEnd/LoggingServicesLogMethod_Tests.cs b/src/Build.UnitTests/BackEnd/LoggingServicesLogMethod_Tests.cs index 3fe5fcd8e6e..7ab72b7448c 100644 --- a/src/Build.UnitTests/BackEnd/LoggingServicesLogMethod_Tests.cs +++ b/src/Build.UnitTests/BackEnd/LoggingServicesLogMethod_Tests.cs @@ -33,12 +33,12 @@ public class LoggingServicesLogMethod_Tests /// /// A generic valid build event context which can be used in the tests. /// - private static BuildEventContext s_buildEventContext = new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4); + private static readonly BuildEventContext s_taskBuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 1).WithTargetId(2).WithTaskId(4); /// - /// buildevent context for target events, note the invalid taskId, target started and finished events have this. + /// buildevent context for target events - this will have invalid TaskId, target started and finished events have this. /// - private static BuildEventContext s_targetBuildEventContext = new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, -1); + private static readonly BuildEventContext s_targetBuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 2).WithTargetId(2); #endregion #region Event based logging method tests @@ -102,7 +102,7 @@ public void LogErrorNullMessageResource() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogError(s_buildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), null, "MyTask"); + service.LogError(s_taskBuildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), null, "MyTask"); }); } @@ -115,7 +115,7 @@ public void LogErrorEmptyMessageResource() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogError(s_buildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), string.Empty, "MyTask"); + service.LogError(s_taskBuildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), string.Empty, "MyTask"); }); } @@ -135,7 +135,7 @@ public void LogErrorGoodParameters() ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogError(s_buildEventContext, subcategoryKey, fileInfo, "FatalTaskError", taskName); + service.LogError(s_taskBuildEventContext, subcategoryKey, fileInfo, "FatalTaskError", taskName); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, subcategory); } @@ -165,7 +165,7 @@ public void LogInvalidProjectFileErrorNullException() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogInvalidProjectFileError(s_buildEventContext, null); + service.LogInvalidProjectFileError(s_taskBuildEventContext, null); }); } @@ -182,21 +182,21 @@ public void LogInvalidProjectFileError() // Log the exception for the first time Assert.False(exception.HasBeenLogged); - service.LogInvalidProjectFileError(s_buildEventContext, exception); + service.LogInvalidProjectFileError(s_taskBuildEventContext, exception); Assert.True(exception.HasBeenLogged); BuildEventFileInfo fileInfo = new BuildEventFileInfo(exception.ProjectFile, exception.LineNumber, exception.ColumnNumber, exception.EndLineNumber, exception.EndColumnNumber); VerifyBuildErrorEventArgs(fileInfo, exception.ErrorCode, exception.HelpKeyword, exception.BaseMessage, service, exception.ErrorSubcategory); // Verify when the exception is logged again that it does not actually get logged due to it already being logged service.ResetProcessedBuildEvent(); - service.LogInvalidProjectFileError(s_buildEventContext, exception); + service.LogInvalidProjectFileError(s_taskBuildEventContext, exception); Assert.Null(service.ProcessedBuildEvent); // Reset the HasLogged field and verify OnlyLogCriticalEvents does not effect the logging of the message service.ResetProcessedBuildEvent(); service.OnlyLogCriticalEvents = true; exception.HasBeenLogged = false; - service.LogInvalidProjectFileError(s_buildEventContext, exception); + service.LogInvalidProjectFileError(s_taskBuildEventContext, exception); VerifyBuildErrorEventArgs(fileInfo, exception.ErrorCode, exception.HelpKeyword, exception.BaseMessage, service, exception.ErrorSubcategory); } @@ -226,7 +226,7 @@ public void LogFatalErrorNullFileInfo() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalError(s_buildEventContext, new Exception("SuperException"), null, "FatalTaskError", "TaskName"); + service.LogFatalError(s_taskBuildEventContext, new Exception("SuperException"), null, "FatalTaskError", "TaskName"); }); } @@ -244,7 +244,7 @@ public void LogFatalErrorNullException() string message; GenerateMessageFromExceptionAndResource(null, resourceName, out errorCode, out helpKeyword, out message, parameters); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalError(s_buildEventContext, null, fileInfo, resourceName, parameters); + service.LogFatalError(s_taskBuildEventContext, null, fileInfo, resourceName, parameters); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, null); } @@ -258,7 +258,7 @@ public void LogFatalErrorNullMessageResourceName() { BuildEventFileInfo fileInfo = new BuildEventFileInfo("foo.cs", 1, 2, 3, 4); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalError(s_buildEventContext, new Exception("SuperException"), fileInfo, null); + service.LogFatalError(s_taskBuildEventContext, new Exception("SuperException"), fileInfo, null); }); } @@ -272,7 +272,7 @@ public void LogFatalErrorEmptyMessageResourceName() { BuildEventFileInfo fileInfo = new BuildEventFileInfo("foo.cs", 1, 2, 3, 4); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalError(s_buildEventContext, new Exception("SuperException"), fileInfo, string.Empty, null); + service.LogFatalError(s_taskBuildEventContext, new Exception("SuperException"), fileInfo, string.Empty, null); }); } @@ -293,7 +293,7 @@ public void LogFatalErrorAllGoodInput() ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalError(s_buildEventContext, exception, fileInfo, resourceName, parameter); + service.LogFatalError(s_taskBuildEventContext, exception, fileInfo, resourceName, parameter); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, null); } #endregion @@ -315,7 +315,7 @@ public void LogFatalBuildErrorGoodInput() GenerateMessageFromExceptionAndResource(exception, resourceName, out errorCode, out helpKeyword, out message); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalBuildError(s_buildEventContext, exception, fileInfo); + service.LogFatalBuildError(s_taskBuildEventContext, exception, fileInfo); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, null); } #endregion @@ -332,7 +332,7 @@ public void LogFatalTaskErrorNullTaskNameName() { BuildEventFileInfo fileInfo = new BuildEventFileInfo("foo.cs", 1, 2, 3, 4); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalTaskError(s_buildEventContext, new Exception("SuperException"), fileInfo, null); + service.LogFatalTaskError(s_taskBuildEventContext, new Exception("SuperException"), fileInfo, null); }); } @@ -351,13 +351,13 @@ public void LogFatalTaskError() string message; GenerateMessageFromExceptionAndResource(exception, resourceName, out errorCode, out helpKeyword, out message, parameters); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogFatalTaskError(s_buildEventContext, exception, fileInfo, parameters); + service.LogFatalTaskError(s_taskBuildEventContext, exception, fileInfo, parameters); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, null); // Test when the task name is empty GenerateMessageFromExceptionAndResource(exception, resourceName, out errorCode, out helpKeyword, out message, String.Empty); service.ResetProcessedBuildEvent(); - service.LogFatalTaskError(s_buildEventContext, exception, fileInfo, string.Empty); + service.LogFatalTaskError(s_taskBuildEventContext, exception, fileInfo, string.Empty); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, null); } #endregion @@ -385,7 +385,7 @@ public void LogErrorFromTextNullFileInfo() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogErrorFromText(s_buildEventContext, "SubCategoryForSolutionParsingErrors", "WarningCode", "HelpKeyword", null, "Message"); + service.LogErrorFromText(s_taskBuildEventContext, "SubCategoryForSolutionParsingErrors", "WarningCode", "HelpKeyword", null, "Message"); }); } @@ -509,7 +509,7 @@ public void LogTaskWarningFromExceptionNullTaskName() { BuildEventFileInfo fileInfo = new BuildEventFileInfo("foo.cs", 1, 2, 3, 4); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogTaskWarningFromException(s_buildEventContext, null, fileInfo, null); + service.LogTaskWarningFromException(s_taskBuildEventContext, null, fileInfo, null); }); } @@ -523,7 +523,7 @@ public void LogTaskWarningFromExceptionEmptyTaskName() { BuildEventFileInfo fileInfo = new BuildEventFileInfo("foo.cs", 1, 2, 3, 4); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogTaskWarningFromException(s_buildEventContext, null, fileInfo, null); + service.LogTaskWarningFromException(s_taskBuildEventContext, null, fileInfo, null); }); } @@ -544,14 +544,14 @@ public void LogTaskWarningFromException() // Check with a null exception GenerateMessageFromExceptionAndResource(null, resourceName, out warningCode, out helpKeyword, out message, parameters); - service.LogTaskWarningFromException(s_buildEventContext, null, fileInfo, parameters); + service.LogTaskWarningFromException(s_taskBuildEventContext, null, fileInfo, parameters); VerifyBuildWarningEventArgs(fileInfo, warningCode, helpKeyword, message, service, null); // Check when the exception is not null service.ResetProcessedBuildEvent(); Exception exception = new Exception("SuperException"); GenerateMessageFromExceptionAndResource(exception, resourceName, out warningCode, out helpKeyword, out message, parameters); - service.LogTaskWarningFromException(s_buildEventContext, exception, fileInfo, parameters); + service.LogTaskWarningFromException(s_taskBuildEventContext, exception, fileInfo, parameters); VerifyBuildWarningEventArgs(fileInfo, warningCode, helpKeyword, message, service, null); } #endregion @@ -566,7 +566,7 @@ public void LogWarningNullMessageResource() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogWarning(s_buildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), null, "MyTask"); + service.LogWarning(s_taskBuildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), null, "MyTask"); }); } @@ -579,7 +579,7 @@ public void LogWarningEmptyMessageResource() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogWarning(s_buildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), string.Empty, "MyTask"); + service.LogWarning(s_taskBuildEventContext, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo("foo.cs"), string.Empty, "MyTask"); }); } @@ -619,7 +619,7 @@ public void LogWarningFromTextNullFileInfo() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogWarningFromText(s_buildEventContext, "SubCategoryForSolutionParsingErrors", "WarningCode", "HelpKeyword", null, "Message"); + service.LogWarningFromText(s_taskBuildEventContext, "SubCategoryForSolutionParsingErrors", "WarningCode", "HelpKeyword", null, "Message"); }); } @@ -676,7 +676,7 @@ public void LogCommentNullMessageResourceName() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogComment(s_buildEventContext, MessageImportance.Low, null, null); + service.LogComment(s_taskBuildEventContext, MessageImportance.Low, null, null); }); } @@ -689,7 +689,7 @@ public void LogCommentEmptyMessageResourceName() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogComment(s_buildEventContext, MessageImportance.Low, String.Empty, null); + service.LogComment(s_taskBuildEventContext, MessageImportance.Low, String.Empty, null); }); } @@ -706,13 +706,13 @@ public void LogCommentGoodMessage() ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); // Verify message is logged when OnlyLogCriticalEvents is false - service.LogComment(s_buildEventContext, messageImportance, "BuildFinishedSuccess"); + service.LogComment(s_taskBuildEventContext, messageImportance, "BuildFinishedSuccess"); VerityBuildMessageEventArgs(service, messageImportance, message); // Verify no message is logged when OnlyLogCriticalEvents is true service.ResetProcessedBuildEvent(); service.OnlyLogCriticalEvents = true; - service.LogComment(s_buildEventContext, MessageImportance.Normal, "BuildFinishedSuccess"); + service.LogComment(s_taskBuildEventContext, MessageImportance.Normal, "BuildFinishedSuccess"); Assert.Null(service.ProcessedBuildEvent); } @@ -729,7 +729,7 @@ public void LogCommentFromTextNullMessage() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogCommentFromText(s_buildEventContext, MessageImportance.Low, null); + service.LogCommentFromText(s_taskBuildEventContext, MessageImportance.Low, null); }); } @@ -740,7 +740,7 @@ public void LogCommentFromTextNullMessage() public void LogCommentFromTextEmptyMessage() { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogCommentFromText(s_buildEventContext, MessageImportance.Low, string.Empty); + service.LogCommentFromText(s_taskBuildEventContext, MessageImportance.Low, string.Empty); } /// @@ -766,12 +766,12 @@ public void LogCommentFromTextGoodMessage() string message = ResourceUtilities.GetResourceString("BuildFinishedSuccess"); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogCommentFromText(s_buildEventContext, messageImportance, ResourceUtilities.GetResourceString("BuildFinishedSuccess")); + service.LogCommentFromText(s_taskBuildEventContext, messageImportance, ResourceUtilities.GetResourceString("BuildFinishedSuccess")); VerityBuildMessageEventArgs(service, messageImportance, message); service.ResetProcessedBuildEvent(); service.OnlyLogCriticalEvents = true; - service.LogCommentFromText(s_buildEventContext, MessageImportance.Normal, ResourceUtilities.GetResourceString("BuildFinishedSuccess")); + service.LogCommentFromText(s_taskBuildEventContext, MessageImportance.Normal, ResourceUtilities.GetResourceString("BuildFinishedSuccess")); Assert.Null(service.ProcessedBuildEvent); } #endregion @@ -782,20 +782,6 @@ public void LogCommentFromTextGoodMessage() #region ProjectStarted - /// - /// Expect an exception to be thrown if a null build event context is passed in - /// and OnlyLogCriticalEvents is false - /// - [Fact] - public void ProjectStartedNullBuildEventContext() - { - Assert.Throws(() => - { - ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogProjectStarted(null, 1, 2, s_buildEventContext, "ProjectFile", "TargetNames", null, null); - }); - } - /// /// Expect an exception to be thrown if a null build event context is passed in /// and OnlyLogCriticalEvents is false @@ -806,7 +792,8 @@ public void ProjectStartedNullParentBuildEventContext() Assert.Throws(() => { ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogProjectStarted(s_buildEventContext, 1, 2, null, "ProjectFile", "TargetNames", null, null); + var args = service.CreateProjectStartedForLocalProject(null, 2, "ProjectFile", "TargetNames", null, null, null, null); + service.LogProjectStarted(args); }); } @@ -841,8 +828,10 @@ public void ProjectStartedEventTests(string projectFile, string targetNames) BuildRequestConfiguration config = new BuildRequestConfiguration(2, data, "4.0"); cache.AddConfiguration(config); - BuildEventContext context = service.LogProjectStarted(s_buildEventContext, 1, 2, s_buildEventContext, projectFile, targetNames, null, null); - BuildEventContext parentBuildEventContext = s_buildEventContext; + var args = service.CreateProjectStartedForLocalProject(s_taskBuildEventContext, 2, projectFile, targetNames, null, null, null, null); + service.LogProjectStarted(args); + BuildEventContext context = args.BuildEventContext; + BuildEventContext parentBuildEventContext = s_taskBuildEventContext; VerifyProjectStartedEventArgs(service, context.ProjectContextId, message, projectFile, targetNames, parentBuildEventContext, context); service.ResetProcessedBuildEvent(); @@ -857,6 +846,7 @@ public void ProjectStartedProvidedProjectContextId() const int SubmissionId = 1; const int EvaluationId = 2; const int ConfigurationId = 3; + BuildEventContext context = BuildEventContext.CreateInitial(SubmissionId, Scheduler.InProcNodeId).WithEvaluationId(EvaluationId).WithProjectInstanceId(ConfigurationId); const string ProjectFile = "SomeProjectFile"; MockHost componentHost = new MockHost(); @@ -867,22 +857,15 @@ public void ProjectStartedProvidedProjectContextId() BuildRequestConfiguration config = new BuildRequestConfiguration(ConfigurationId, data, "4.0"); cache.AddConfiguration(config); - BuildEventContext projectCacheBuildEventContext = service.CreateProjectCacheBuildEventContext(SubmissionId, EvaluationId, ConfigurationId, ProjectFile); + BuildEventContext projectCacheBuildEventContext = service.CreateProjectCacheBuildEventContext(context, ProjectFile); projectCacheBuildEventContext.NodeId.ShouldBe(Scheduler.InProcNodeId); projectCacheBuildEventContext.ProjectContextId.ShouldNotBe(BuildEventContext.InvalidProjectContextId); - BuildEventContext nodeBuildEventContext = new BuildEventContext(Scheduler.InProcNodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); - BuildEventContext projectStartedBuildEventContext = service.LogProjectStarted( - nodeBuildEventContext, - submissionId: SubmissionId, - configurationId: ConfigurationId, - parentBuildEventContext: BuildEventContext.Invalid, - projectFile: ProjectFile, - targetNames: "TargetNames", - properties: null, - items: null, - evaluationId: EvaluationId, - projectContextId: projectCacheBuildEventContext.ProjectContextId); + BuildEventContext nodeBuildEventContext = BuildEventContext.CreateInitial(0, Scheduler.InProcNodeId); + var args = service.CreateProjectStartedForLocalProject(BuildEventContext.Invalid, ConfigurationId, ProjectFile, "TargetNames", null, null, null, null); + args.BuildEventContext = args.BuildEventContext.WithProjectContextId(projectCacheBuildEventContext.ProjectContextId); // Use provided project context ID + service.LogProjectStarted(args); + BuildEventContext projectStartedBuildEventContext = args.BuildEventContext; projectStartedBuildEventContext.ProjectContextId.ShouldBe(projectCacheBuildEventContext.ProjectContextId); } @@ -906,62 +889,15 @@ public void ProjectStartedProvidedUnknownProjectContextIdInProcNode() BuildRequestConfiguration config = new BuildRequestConfiguration(ConfigurationId, data, "4.0"); cache.AddConfiguration(config); - BuildEventContext nodeBuildEventContext = new BuildEventContext(Scheduler.InProcNodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); + BuildEventContext parentBuildEventContext = BuildEventContext.CreateInitial(SubmissionId, Scheduler.InProcNodeId).WithEvaluationId(EvaluationId); + BuildEventContext remoteBuildEventContextWithKnownBadContextOnCurrentNode = parentBuildEventContext.WithProjectContextId(ProjectContextId); Assert.Throws(() => { - service.LogProjectStarted( - nodeBuildEventContext, - submissionId: SubmissionId, - configurationId: ConfigurationId, - parentBuildEventContext: BuildEventContext.Invalid, - projectFile: ProjectFile, - targetNames: "TargetNames", - properties: null, - items: null, - evaluationId: EvaluationId, - projectContextId: ProjectContextId); + var args = service.CreateProjectStartedForCachedProject(parentBuildEventContext, remoteBuildEventContextWithKnownBadContextOnCurrentNode, BuildEventContext.Invalid, null, ProjectFile, "TargetNames", null); + service.LogProjectStarted(args); }); } - /// - /// Expect an unknown project context id to be accepted on an out-of-proc node. - /// - [Fact] - public void ProjectStartedProvidedUnknownProjectContextIdOutOfProcNode() - { - const int SubmissionId = 1; - const int EvaluationId = 2; - const int ConfigurationId = 3; - const string ProjectFile = "SomeProjectFile"; - const int NodeId = 2; - const int ProjectContextId = 123; - - // Ensure we didn't pick the one bad const value - NodeId.ShouldNotBe(Scheduler.InProcNodeId); - - MockHost componentHost = new MockHost(); - ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1, componentHost); - ConfigCache cache = (ConfigCache)componentHost.GetComponent(BuildComponentType.ConfigCache); - - BuildRequestData data = new BuildRequestData(ProjectFile, new Dictionary(StringComparer.OrdinalIgnoreCase), "toolsVersion", Array.Empty(), null); - BuildRequestConfiguration config = new BuildRequestConfiguration(ConfigurationId, data, "4.0"); - cache.AddConfiguration(config); - - BuildEventContext nodeBuildEventContext = new BuildEventContext(NodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); - BuildEventContext projectStartedBuildEventContext = service.LogProjectStarted( - nodeBuildEventContext, - submissionId: SubmissionId, - configurationId: ConfigurationId, - parentBuildEventContext: BuildEventContext.Invalid, - projectFile: ProjectFile, - targetNames: "TargetNames", - properties: null, - items: null, - evaluationId: EvaluationId, - projectContextId: ProjectContextId); - projectStartedBuildEventContext.ProjectContextId.ShouldBe(ProjectContextId); - } - #endregion #region ProjectFinished @@ -1276,8 +1212,8 @@ public void LogTelemetryTest() TestLogTelemetry(buildEventContext: null, eventName: "no context and no properties", properties: null); TestLogTelemetry(buildEventContext: null, eventName: "no context but with properties", properties: eventProperties); - TestLogTelemetry(buildEventContext: s_buildEventContext, eventName: "event context but no properties", properties: null); - TestLogTelemetry(buildEventContext: s_buildEventContext, eventName: "event context and properties", properties: eventProperties); + TestLogTelemetry(buildEventContext: s_taskBuildEventContext, eventName: "event context but no properties", properties: null); + TestLogTelemetry(buildEventContext: s_taskBuildEventContext, eventName: "event context and properties", properties: eventProperties); } private void TestLogTelemetry(BuildEventContext buildEventContext, string eventName, IDictionary properties) @@ -1348,7 +1284,7 @@ private void TestLogErrorFromText(string errorCode, string helpKeyword, string s } ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogErrorFromText(s_buildEventContext, subcategoryKey, errorCode, helpKeyword, fileInfo, message); + service.LogErrorFromText(s_taskBuildEventContext, subcategoryKey, errorCode, helpKeyword, fileInfo, message); VerifyBuildErrorEventArgs(fileInfo, errorCode, helpKeyword, message, service, subcategory); } @@ -1369,7 +1305,7 @@ private void TestLogWarningFromText(string warningCode, string helpKeyword, stri } ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogWarningFromText(s_buildEventContext, subcategoryKey, warningCode, helpKeyword, fileInfo, message); + service.LogWarningFromText(s_taskBuildEventContext, subcategoryKey, warningCode, helpKeyword, fileInfo, message); VerifyBuildWarningEventArgs(fileInfo, warningCode, helpKeyword, message, service, subcategory); } @@ -1387,7 +1323,7 @@ private void TestLogWarning(string taskName, string subCategoryKey) string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(out warningCode, out helpKeyword, "FatalTaskError", taskName); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogWarning(s_buildEventContext, subCategoryKey, fileInfo, "FatalTaskError", taskName); + service.LogWarning(s_taskBuildEventContext, subCategoryKey, fileInfo, "FatalTaskError", taskName); VerifyBuildWarningEventArgs(fileInfo, warningCode, helpKeyword, message, service, subcategory); } @@ -1403,11 +1339,11 @@ private void TestProjectFinishedEvent(string projectFile, bool success) ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1, componentHost); try { - service.LogProjectFinished(s_buildEventContext, projectFile, success); + service.LogProjectFinished(s_taskBuildEventContext, projectFile, success); } catch (InternalErrorException ex) { - Assert.Contains("ContextID " + s_buildEventContext.ProjectContextId, ex.Message); + Assert.Contains("ContextID " + s_taskBuildEventContext.ProjectContextId, ex.Message); } finally { @@ -1421,15 +1357,9 @@ private void TestProjectFinishedEvent(string projectFile, bool success) cache.AddConfiguration(config); // Now do it the right way -- with a matching ProjectStarted. - BuildEventContext projectContext = service.LogProjectStarted( - new BuildEventContext(1, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId), - 1, - 2, - s_buildEventContext, - projectFile, - null, - null, - null); + var projectStartedArgs = service.CreateProjectStartedForLocalProject(s_taskBuildEventContext, 2, projectFile, null, null, null, null, null); + service.LogProjectStarted(projectStartedArgs); + BuildEventContext projectContext = projectStartedArgs.BuildEventContext; service.LogProjectFinished(projectContext, projectFile, success); @@ -1450,12 +1380,12 @@ private void TestTaskStartedEvent(string taskName, string projectFile, string pr string taskAssemblyLocation = Assembly.GetExecutingAssembly().Location; ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogTaskStarted(s_buildEventContext, taskName, projectFile, projectFileOfTask, taskAssemblyLocation); + service.LogTaskStarted(s_taskBuildEventContext, taskName, projectFile, projectFileOfTask, taskAssemblyLocation); VerifyTaskStartedEvent(taskName, projectFile, projectFileOfTask, message, service, taskAssemblyLocation); service.ResetProcessedBuildEvent(); service.OnlyLogCriticalEvents = true; - service.LogTaskStarted(s_buildEventContext, taskName, projectFile, projectFileOfTask, taskAssemblyLocation); + service.LogTaskStarted(s_taskBuildEventContext, taskName, projectFile, projectFileOfTask, taskAssemblyLocation); Assert.Null(service.ProcessedBuildEvent); } @@ -1470,12 +1400,12 @@ private void TestTaskFinished(string taskName, string projectFile, string projec { string message = ResourceUtilities.FormatResourceStringStripCodeAndKeyword(succeeded ? "TaskFinishedSuccess" : "TaskFinishedFailure", taskName); ProcessBuildEventHelper service = (ProcessBuildEventHelper)ProcessBuildEventHelper.CreateLoggingService(LoggerMode.Synchronous, 1); - service.LogTaskFinished(s_buildEventContext, taskName, projectFile, projectFileOfTask, succeeded); + service.LogTaskFinished(s_taskBuildEventContext, taskName, projectFile, projectFileOfTask, succeeded); VerifyTaskFinishedEvent(taskName, projectFile, projectFileOfTask, succeeded, message, service); service.ResetProcessedBuildEvent(); service.OnlyLogCriticalEvents = true; - service.LogTaskFinished(s_buildEventContext, taskName, projectFile, projectFileOfTask, succeeded); + service.LogTaskFinished(s_taskBuildEventContext, taskName, projectFile, projectFileOfTask, succeeded); Assert.Null(service.ProcessedBuildEvent); } @@ -1624,7 +1554,7 @@ private void VerifyTaskFinishedEvent(string taskName, string projectFile, string taskName, succeeded, service.ProcessedBuildEvent.Timestamp); - taskEvent.BuildEventContext = s_buildEventContext; + taskEvent.BuildEventContext = s_taskBuildEventContext; Assert.True(((TaskFinishedEventArgs)service.ProcessedBuildEvent).IsEquivalent(taskEvent)); } @@ -1646,7 +1576,7 @@ private void VerifyTaskStartedEvent(string taskName, string projectFile, string taskName, service.ProcessedBuildEvent.Timestamp, taskAssemblyLocation); - taskEvent.BuildEventContext = s_buildEventContext; + taskEvent.BuildEventContext = s_taskBuildEventContext; Assert.True(((TaskStartedEventArgs)service.ProcessedBuildEvent).IsEquivalent(taskEvent)); } @@ -1710,7 +1640,7 @@ private void VerityBuildMessageEventArgs(ProcessBuildEventHelper service, Messag messageImportance, service.ProcessedBuildEvent.Timestamp); - buildMessageEvent.BuildEventContext = s_buildEventContext; + buildMessageEvent.BuildEventContext = s_taskBuildEventContext; Assert.True(((BuildMessageEventArgs)service.ProcessedBuildEvent).IsEquivalent(buildMessageEvent)); } @@ -1737,7 +1667,7 @@ private void VerifyBuildWarningEventArgs(BuildEventFileInfo fileInfo, string war helpKeyword, "MSBuild", service.ProcessedBuildEvent.Timestamp); - buildEvent.BuildEventContext = s_buildEventContext; + buildEvent.BuildEventContext = s_taskBuildEventContext; Assert.True(buildEvent.IsEquivalent((BuildWarningEventArgs)service.ProcessedBuildEvent)); } @@ -1764,7 +1694,7 @@ private void VerifyBuildErrorEventArgs(BuildEventFileInfo fileInfo, string error helpKeyword, "MSBuild", service.ProcessedBuildEvent.Timestamp); - buildEvent.BuildEventContext = s_buildEventContext; + buildEvent.BuildEventContext = s_taskBuildEventContext; Assert.True(buildEvent.IsEquivalent((BuildErrorEventArgs)service.ProcessedBuildEvent)); } diff --git a/src/Build.UnitTests/BackEnd/MockLoggingService.cs b/src/Build.UnitTests/BackEnd/MockLoggingService.cs index fa5f97176c2..3756a3d5485 100644 --- a/src/Build.UnitTests/BackEnd/MockLoggingService.cs +++ b/src/Build.UnitTests/BackEnd/MockLoggingService.cs @@ -520,12 +520,12 @@ public void LogBuildCanceled() } /// - public BuildEventContext CreateEvaluationBuildEventContext(int nodeId, int submissionId) - => new BuildEventContext(0, 0, 0, 0, 0, 0, 0); + public BuildEventContext CreateEvaluationBuildEventContext(BuildEventContext parentBuildEventContext) + => parentBuildEventContext.WithEvaluationId(0); /// - public BuildEventContext CreateProjectCacheBuildEventContext(int submissionId, int evaluationId, int projectInstanceId, string projectFile) - => new BuildEventContext(0, 0, 0, 0, 0, 0, 0); + public BuildEventContext CreateProjectCacheBuildEventContext(BuildEventContext parentBuildEventContext, string projectFile) + => parentBuildEventContext.WithProjectContextId(0); /// public void LogProjectEvaluationStarted(BuildEventContext eventContext, string projectFile) @@ -545,40 +545,27 @@ public void LogProjectEvaluationFinished( { } - /// - /// Logs a project started event - /// - public BuildEventContext LogProjectStarted( - BuildEventContext nodeBuildEventContext, - int submissionId, - int configurationId, - BuildEventContext parentBuildEventContext, - string projectFile, - string targetNames, - IEnumerable properties, - IEnumerable items, - int evaluationId = BuildEventContext.InvalidEvaluationId, - int projectContextId = BuildEventContext.InvalidProjectContextId) - { - return new BuildEventContext(0, 0, 0, 0); - } - public void LogProjectStarted(ProjectStartedEventArgs args) { } - public ProjectStartedEventArgs CreateProjectStarted( - BuildEventContext nodeBuildEventContext, - int submissionId, - int configurationId, + public ProjectStartedEventArgs CreateProjectStartedForLocalProject( BuildEventContext parentBuildEventContext, + int configurationId, string projectFile, string targetNames, + IDictionary globalProperties, IEnumerable properties, IEnumerable items, - int evaluationId = BuildEventContext.InvalidEvaluationId, - int projectContextId = BuildEventContext.InvalidProjectContextId) + string toolsVersion) { - return new ProjectStartedEventArgs( + // Create a mock project context ID for testing + int projectContextId = configurationId; + + BuildEventContext projectBuildEventContext = parentBuildEventContext + .WithProjectInstanceId(configurationId) + .WithProjectContextId(projectContextId); + + var buildEvent = new ProjectStartedEventArgs( configurationId, message: null, helpKeyword: null, @@ -586,7 +573,42 @@ public ProjectStartedEventArgs CreateProjectStarted( targetNames, properties, items, - parentBuildEventContext); + parentBuildEventContext, + globalProperties, + toolsVersion); + + buildEvent.BuildEventContext = projectBuildEventContext; + return buildEvent; + } + + public ProjectStartedEventArgs CreateProjectStartedForCachedProject( + BuildEventContext currentNodeBuildEventContext, + BuildEventContext remoteNodeEvaluationBuildEventContext, + BuildEventContext parentBuildEventContext, + IDictionary globalProperties, + string projectFile, + string targetNames, + string toolsVersion) + { + BuildEventContext projectBuildEventContext = parentBuildEventContext + .WithProjectInstanceId(remoteNodeEvaluationBuildEventContext.ProjectInstanceId) + .WithProjectContextId(remoteNodeEvaluationBuildEventContext.ProjectContextId); + + var buildEvent = new ProjectStartedEventArgs( + remoteNodeEvaluationBuildEventContext.ProjectInstanceId, + message: null, + helpKeyword: null, + projectFile, + targetNames, + null, // No properties for cache scenarios in mock + null, // No items for cache scenarios in mock + parentBuildEventContext, + globalProperties, + toolsVersion, + remoteNodeEvaluationBuildEventContext); // Pass original context + + buildEvent.BuildEventContext = projectBuildEventContext; + return buildEvent; } /// @@ -609,7 +631,7 @@ public void LogProjectFinished(BuildEventContext projectBuildEventContext, strin /// The build event context for the target public BuildEventContext LogTargetStarted(BuildEventContext projectBuildEventContext, string targetName, string projectFile, string projectFileOfTargetElement, string parentTargetName, TargetBuiltReason buildReason) { - return new BuildEventContext(0, 0, 0, 0); + return BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0); } /// @@ -647,7 +669,7 @@ public void LogTaskStarted(BuildEventContext targetBuildEventContext, string tas /// The task logging context public BuildEventContext LogTaskStarted2(BuildEventContext targetBuildEventContext, string taskName, string projectFile, string projectFileOfTaskNode, int line, int column, string taskAssemblyLocation) { - return new BuildEventContext(0, 0, 0, 0); + return BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0); } /// diff --git a/src/Build.UnitTests/BackEnd/NodePackets_Tests.cs b/src/Build.UnitTests/BackEnd/NodePackets_Tests.cs index 8ca50416de7..5577f65a441 100644 --- a/src/Build.UnitTests/BackEnd/NodePackets_Tests.cs +++ b/src/Build.UnitTests/BackEnd/NodePackets_Tests.cs @@ -123,7 +123,7 @@ public void VerifyEventType() private static BuildEventContext CreateBuildEventContext() { - return new BuildEventContext(1, 2, 3, 4, 5, 6, 7); + return BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7); } private static ProjectEvaluationStartedEventArgs CreateProjectEvaluationStarted() @@ -262,7 +262,7 @@ public void TestTranslation() { new ResponseFileUsedEventArgs("path"), new UninitializedPropertyReadEventArgs("prop", "message", "help", "sender", MessageImportance.Normal), - new EnvironmentVariableReadEventArgs("env", "message", "file", 0, 0) { BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6) }, + new EnvironmentVariableReadEventArgs("env", "message", "file", 0, 0) { BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6) }, new PropertyReassignmentEventArgs("prop", "prevValue", "newValue", "loc", "message", "help", "sender", MessageImportance.Normal), new PropertyInitialValueSetEventArgs("prop", "val", "propsource", "message", "help", "sender", MessageImportance.Normal), new MetaprojectGeneratedEventArgs("metaName", "path", "message"), @@ -294,31 +294,31 @@ public void TestTranslation() { ExtendedData = /*lang=json*/ "{'long-json':'mostly-strings'}", ExtendedMetadata = new Dictionary { { "m1", "v1" }, { "m2", "v2" } }, - BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7) + BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) }, new ExtendedBuildWarningEventArgs("extWarn", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", DateTime.UtcNow, "arg1") { ExtendedData = /*lang=json*/ "{'long-json':'mostly-strings'}", ExtendedMetadata = new Dictionary { { "m1", "v1" }, { "m2", "v2" } }, - BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7) + BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) }, new ExtendedBuildMessageEventArgs("extWarn", "SubCategoryForSchemaValidationErrors", "MSB4000", "file", 1, 2, 3, 4, "message", "help", "sender", MessageImportance.Normal, DateTime.UtcNow, "arg1") { ExtendedData = /*lang=json*/ "{'long-json':'mostly-strings'}", ExtendedMetadata = new Dictionary { { "m1", "v1" }, { "m2", "v2" } }, - BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7) + BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) }, new ExtendedCustomBuildEventArgs("extCustom", "message", "help", "sender", DateTime.UtcNow, "arg1") { ExtendedData = /*lang=json*/ "{'long-json':'mostly-strings'}", ExtendedMetadata = new Dictionary { { "m1", "v1" }, { "m2", "v2" } }, - BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7) + BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) }, new ExtendedCriticalBuildMessageEventArgs("extCritMsg", "Subcategory", "Code", "File", 1, 2, 3, 4, "{0}", "HelpKeyword", "Sender", DateTime.Now, "arg1") { ExtendedData = /*lang=json*/ "{'long-json':'mostly-strings'}", ExtendedMetadata = new Dictionary { { "m1", "v1" }, { "m2", "v2" } }, - BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7) + BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) }, new GeneratedFileUsedEventArgs("path", "some content"), }; diff --git a/src/Build.UnitTests/BackEnd/RequestBuilder_Tests.cs b/src/Build.UnitTests/BackEnd/RequestBuilder_Tests.cs index 80e9c990ba6..610c47ce664 100644 --- a/src/Build.UnitTests/BackEnd/RequestBuilder_Tests.cs +++ b/src/Build.UnitTests/BackEnd/RequestBuilder_Tests.cs @@ -336,10 +336,7 @@ private void WaitForEvent(WaitHandle evt, string eventName) } } - private NodeLoggingContext GetNodeLoggingContext() - { - return new NodeLoggingContext(_host, 1, false); - } + private NodeLoggingContext GetNodeLoggingContext() => new NodeLoggingContext(_host, BuildEventContext.Invalid.WithNodeId(1), 1, false); } internal sealed class TestTargetBuilder : ITargetBuilder, IBuildComponent diff --git a/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs b/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs index 95730b3440a..bc967b4087b 100644 --- a/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs +++ b/src/Build.UnitTests/BackEnd/SdkResolverService_Tests.cs @@ -38,7 +38,10 @@ public SdkResolverService_Tests() _loggingContext = new MockLoggingContext( loggingService, - new BuildEventContext(0, 0, BuildEventContext.InvalidProjectContextId, 0, 0)); + BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 0) + .WithProjectInstanceId(0) + .WithTargetId(0) + .WithTaskId(0)); } [Fact] diff --git a/src/Build.UnitTests/BackEnd/TargetBuilder_Tests.cs b/src/Build.UnitTests/BackEnd/TargetBuilder_Tests.cs index 005ef4da7bb..1f9085cf7f3 100644 --- a/src/Build.UnitTests/BackEnd/TargetBuilder_Tests.cs +++ b/src/Build.UnitTests/BackEnd/TargetBuilder_Tests.cs @@ -1694,7 +1694,9 @@ private ProjectInstance CreateTestProject(string projectBodyContents, string ini /// The context private ProjectLoggingContext GetProjectLoggingContext(BuildRequestEntry entry) { - return new ProjectLoggingContext(new NodeLoggingContext(_host, 1, false), entry); + var nodeContext = new NodeLoggingContext(_host, BuildEventContext.Invalid.WithNodeId(1), 1, false); + var (_, context) = ProjectLoggingContext.CreateForLocalBuild(nodeContext, entry); + return context; } /// diff --git a/src/Build.UnitTests/BackEnd/TargetEntry_Tests.cs b/src/Build.UnitTests/BackEnd/TargetEntry_Tests.cs index 8607e64e572..c5174969040 100644 --- a/src/Build.UnitTests/BackEnd/TargetEntry_Tests.cs +++ b/src/Build.UnitTests/BackEnd/TargetEntry_Tests.cs @@ -1086,7 +1086,9 @@ private ProjectInstance CreateTestProject(bool returnsAttributeEnabled) /// The project logging context. private ProjectLoggingContext GetProjectLoggingContext(BuildRequestEntry entry) { - return new ProjectLoggingContext(new NodeLoggingContext(_host, 1, false), entry); + var nodeContext = new NodeLoggingContext(_host, BuildEventContext.Invalid.WithNodeId(1), 1, false); + var (_, context) = ProjectLoggingContext.CreateForLocalBuild(nodeContext, entry); + return context; } /// diff --git a/src/Build.UnitTests/BackEnd/TaskExecutionHost_Tests.cs b/src/Build.UnitTests/BackEnd/TaskExecutionHost_Tests.cs index 6db852567a5..eb13030672d 100644 --- a/src/Build.UnitTests/BackEnd/TaskExecutionHost_Tests.cs +++ b/src/Build.UnitTests/BackEnd/TaskExecutionHost_Tests.cs @@ -981,7 +981,7 @@ public void TestTaskResolutionFailureWithUsingTask() _loggingService = new MockLoggingService(); Dispose(); _host = new TaskExecutionHost(); - TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)); + TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, BuildEventContext.CreateInitial(1, 1).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(1)); ProjectInstance project = CreateTestProject(); _host.InitializeForTask( @@ -1010,7 +1010,7 @@ public void TestTaskResolutionFailureWithNoUsingTask() { Dispose(); _host = new TaskExecutionHost(); - TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)); + TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, BuildEventContext.CreateInitial(1, 1).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(1)); ProjectInstance project = CreateTestProject(); _host.InitializeForTask( @@ -1240,7 +1240,7 @@ private void InitializeHost(bool throwOnExecute) _logger = new MockLogger(); _loggingService.RegisterLogger(_logger); _host = new TaskExecutionHost(); - TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)); + TargetLoggingContext tlc = new TargetLoggingContext(_loggingService, BuildEventContext.CreateInitial(1, 1).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(1)); // Set up a temporary project and add some items to it. ProjectInstance project = CreateTestProject(); diff --git a/src/Build.UnitTests/BackEnd/TaskRegistry_Tests.cs b/src/Build.UnitTests/BackEnd/TaskRegistry_Tests.cs index 6c4b7461b8a..dccf8c936f6 100644 --- a/src/Build.UnitTests/BackEnd/TaskRegistry_Tests.cs +++ b/src/Build.UnitTests/BackEnd/TaskRegistry_Tests.cs @@ -69,7 +69,7 @@ public class TaskRegistry_Tests /// /// Build event context to use when logging /// - private readonly BuildEventContext _loggerContext = new BuildEventContext(2, 2, 2, 2); + private readonly BuildEventContext _loggerContext = BuildEventContext.CreateInitial(2, 2).WithEvaluationId(2).WithProjectInstanceId(2); /// /// Element location to use when logging @@ -1135,7 +1135,7 @@ public void TaskFactoryWithNullTaskTypeLogsError() TaskRegistry registry = CreateTaskRegistryAndRegisterTasks(elementList); - InvalidProjectFileException exception = Should.Throw(() => registry.GetRegisteredTask("Task1", "none", TaskHostParameters.Empty, false, new TargetLoggingContext(_loggingService, new BuildEventContext(1, 1, BuildEventContext.InvalidProjectContextId, 1)), ElementLocation.Create("none", 1, 2), false)); + InvalidProjectFileException exception = Should.Throw(() => registry.GetRegisteredTask("Task1", "none", TaskHostParameters.Empty, false, new TargetLoggingContext(_loggingService, BuildEventContext.CreateInitial(1, 1).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(1)), ElementLocation.Create("none", 1, 2), false)); exception.ErrorCode.ShouldBe("MSB4175"); @@ -2118,7 +2118,7 @@ internal static Expander GetExpand pg, secondaryItemsByName, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); return expander; } diff --git a/src/Build.UnitTests/BuildEventArgsSerialization_Tests.cs b/src/Build.UnitTests/BuildEventArgsSerialization_Tests.cs index 2eef5fde018..06772812c88 100644 --- a/src/Build.UnitTests/BuildEventArgsSerialization_Tests.cs +++ b/src/Build.UnitTests/BuildEventArgsSerialization_Tests.cs @@ -90,7 +90,7 @@ public void RoundtripBuildFinishedEventArgs() null, succeeded: true, eventTimestamp: DateTime.Parse("12/12/2015 06:11:56 PM")); - args.BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6); + args.BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6); Roundtrip(args, e => ToString(e.BuildEventContext), @@ -159,10 +159,10 @@ public void RoundtripProjectStartedEventArgs() targetNames: "Build", properties: new List() { new DictionaryEntry("Key", "Value") }, items: new List() { new DictionaryEntry("Key", new MyTaskItem() { ItemSpec = "TestItemSpec" }) }, - parentBuildEventContext: new BuildEventContext(7, 8, 9, 10, 11, 12), + parentBuildEventContext: BuildEventContext.CreateInitial(7, 8).WithEvaluationId(9).WithProjectInstanceId(10).WithProjectContextId(11).WithTaskId(12), globalProperties: new Dictionary() { { "GlobalKey", "GlobalValue" } }, toolsVersion: "Current"); - args.BuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6); + args.BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6); Roundtrip(args, e => ToString(e.BuildEventContext), @@ -263,7 +263,7 @@ public void RoundtripTaskStartedEventArgs() public void RoundtripEnvironmentVariableReadEventArgs() { EnvironmentVariableReadEventArgs args = new("VarName", "VarValue", "file", 10, 20); - args.BuildEventContext = new BuildEventContext(4, 5, 6, 7); + args.BuildEventContext = BuildEventContext.CreateInitial(4, 5).WithEvaluationId(6).WithProjectInstanceId(7); Roundtrip(args, e => e.Message, e => e.EnvironmentVariableName, @@ -343,7 +343,7 @@ public void RoundtripExtendedErrorEventArgs_SerializedAsError(bool withOptionalD { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) : null, }; Roundtrip(args, @@ -416,7 +416,7 @@ public void RoundtripExtendedWarningEventArgs_SerializedAsWarning(bool withOptio { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) : null, }; Roundtrip(args, @@ -492,7 +492,7 @@ public void RoundtripExtendedBuildMessageEventArgs_SerializedAsMessage(bool with { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) : null, }; Roundtrip(args, @@ -580,7 +580,7 @@ public void ExtendedCustomBuildEventArgs_SerializedAsMessage(bool withOptionalDa { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) : null, }; @@ -675,7 +675,7 @@ public void RoundtripExtendedCriticalBuildMessageEventArgs(bool withOptionalData { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7) : null, }; @@ -851,7 +851,7 @@ public void RoundtripTargetSkippedEventArgs() SkipReason = TargetSkipReason.PreviouslyBuiltSuccessfully, Condition = "$(condition) == true", EvaluatedCondition = "true == true", - OriginalBuildEventContext = new BuildEventContext(1, 2, 3, 4, 5, 6, 7), + OriginalBuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTaskId(6).WithTargetId(7), OriginallySucceeded = false, TargetFile = "foo.csproj" }; diff --git a/src/Build.UnitTests/ConfigureableForwardingLogger_Tests.cs b/src/Build.UnitTests/ConfigureableForwardingLogger_Tests.cs index 7ccdbeeb57b..3f945c1089b 100644 --- a/src/Build.UnitTests/ConfigureableForwardingLogger_Tests.cs +++ b/src/Build.UnitTests/ConfigureableForwardingLogger_Tests.cs @@ -49,7 +49,7 @@ protected override void ForwardToCentralLogger(BuildEventArgs e) public ConfigureableForwardingLogger_Tests() { - BuildEventContext context = new BuildEventContext(1, 2, 3, 4); + BuildEventContext context = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); _error.BuildEventContext = context; _warning.BuildEventContext = context; _targetStarted.BuildEventContext = context; diff --git a/src/Build.UnitTests/ConsoleLogger_Tests.cs b/src/Build.UnitTests/ConsoleLogger_Tests.cs index 139e461cc40..c5465da400d 100644 --- a/src/Build.UnitTests/ConsoleLogger_Tests.cs +++ b/src/Build.UnitTests/ConsoleLogger_Tests.cs @@ -458,19 +458,19 @@ public void NullEventFields() // Not all parameters are null here, but that's fine, we assume the engine will never // fire a ProjectStarted without a project name, etc. es.Consume(new BuildStartedEventArgs(null, null)); - es.Consume(new ProjectStartedEventArgs(1, null, null, "p", null, null, null, parentBuildEventContext: new BuildEventContext(1, 1, 1, 1)) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new TargetStartedEventArgs(null, null, "t", null, null) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new TaskStartedEventArgs(null, null, null, null, "task") { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new BuildMessageEventArgs(null, null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new BuildWarningEventArgs(null, null, null, 0, 0, 0, 0, null, null, null) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new BuildErrorEventArgs(null, null, null, 0, 0, 0, 0, null, null, null) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new TaskFinishedEventArgs(null, null, null, null, "task", true) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new TargetFinishedEventArgs(null, null, "t", null, null, true) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new ProjectFinishedEventArgs(null, null, "p", true) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new BuildFinishedEventArgs(null, null, true) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new BuildFinishedEventArgs(null, null, true) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new BuildFinishedEventArgs(null, null, true) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); - es.Consume(new MyCustomBuildEventArgs2() { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + es.Consume(new ProjectStartedEventArgs(1, null, null, "p", null, null, null, parentBuildEventContext: BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1)) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new TargetStartedEventArgs(null, null, "t", null, null) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new TaskStartedEventArgs(null, null, null, null, "task") { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new BuildMessageEventArgs(null, null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new BuildWarningEventArgs(null, null, null, 0, 0, 0, 0, null, null, null) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new BuildErrorEventArgs(null, null, null, 0, 0, 0, 0, null, null, null) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new TaskFinishedEventArgs(null, null, null, null, "task", true) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new TargetFinishedEventArgs(null, null, "t", null, null, true) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new ProjectFinishedEventArgs(null, null, "p", true) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new BuildFinishedEventArgs(null, null, true) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new BuildFinishedEventArgs(null, null, true) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new BuildFinishedEventArgs(null, null, true) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); + es.Consume(new MyCustomBuildEventArgs2() { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); // No exception raised } @@ -483,7 +483,7 @@ public void NullEventFieldsParallel() sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es, 2); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs(null, null); bse.BuildEventContext = buildEventContext; @@ -600,7 +600,7 @@ public void SingleMessageTest(LoggerVerbosity loggerVerbosity, MessageImportance BuildMessageEventArgs be = new BuildMessageEventArgs(message, "help", "sender", messageImportance) { - BuildEventContext = new BuildEventContext(1, 2, 3, 4) + BuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 1).WithTargetId(2).WithProjectContextId(3).WithTaskId(4) }; eventSourceSink.Consume(be); @@ -656,7 +656,7 @@ public void ColorTest(string expectedMessageType, string expectedColor) throw new InvalidOperationException($"Invalid expectedMessageType '{expectedMessageType}'"); } - buildEventArgs.BuildEventContext = new BuildEventContext(1, 2, 3, 4); + buildEventArgs.BuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 1).WithTargetId(2).WithProjectContextId(3).WithTaskId(4); EventSourceSink eventSourceSink = new EventSourceSink(); SimulatedConsole console = new SimulatedConsole(); @@ -685,13 +685,13 @@ public void TestQuietWithHighMessage() sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; es.Consume(bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 1, 1, 1)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1)); pse.BuildEventContext = buildEventContext; es.Consume(pse); @@ -735,13 +735,13 @@ public void TestQuietWithError() sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; es.Consume(bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 2, 3, 4)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)); pse.BuildEventContext = buildEventContext; es.Consume(pse); @@ -796,13 +796,13 @@ public void TestQuietWithWarning() sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; es.Consume(bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 2, 3, 4)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)); pse.BuildEventContext = buildEventContext; es.Consume(pse); @@ -858,13 +858,13 @@ public void TestMinimalWithNormalMessage() sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; es.Consume(bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 1, 1, 1)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1)); pse.BuildEventContext = buildEventContext; es.Consume(pse); @@ -911,13 +911,13 @@ public void TestMinimalWithError() sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; es.Consume(bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 2, 3, 4)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)); pse.BuildEventContext = buildEventContext; es.Consume(pse); @@ -971,13 +971,13 @@ public void TestMinimalWithWarning() sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; es.Consume(bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 2, 3, 4)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)); pse.BuildEventContext = buildEventContext; es.Consume(pse); @@ -1032,13 +1032,13 @@ public void TestDirectEventHandlers() sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es); - BuildEventContext buildEventContext = new BuildEventContext(1, 2, 3, 4); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); BuildStartedEventArgs bse = new BuildStartedEventArgs("bs", null); bse.BuildEventContext = buildEventContext; L.BuildStartedHandler(null, bse); - ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, new BuildEventContext(1, 2, 3, 4)); + ProjectStartedEventArgs pse = new ProjectStartedEventArgs(-1, "ps", null, "fname", "", null, null, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)); pse.BuildEventContext = buildEventContext; L.ProjectStartedHandler(null, pse); @@ -1091,7 +1091,7 @@ public void CustomDisplayedAtDetailed() L.Initialize(es); MyCustomBuildEventArgs c = new MyCustomBuildEventArgs("msg"); - c.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + c.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(c); @@ -1109,7 +1109,7 @@ public void CustomDisplayedAtDiagnosticMP() MyCustomBuildEventArgs c = new MyCustomBuildEventArgs("msg"); - c.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + c.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(c); sc.ToString().ShouldContain("msg"); @@ -1124,7 +1124,7 @@ public void CustomNotDisplayedAtNormal() L.Initialize(es); MyCustomBuildEventArgs c = new MyCustomBuildEventArgs("msg"); - c.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + c.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(c); @@ -1147,7 +1147,7 @@ private void WriteAndValidateProperties(BaseConsoleLogger cl, SimulatedConsole s string prop3; BuildEventArgs buildEvent = new BuildErrorEventArgs("", "", "", 0, 0, 0, 0, "", "", ""); - buildEvent.BuildEventContext = new BuildEventContext(1, 2, 3, 4); + buildEvent.BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); ((ParallelConsoleLogger)cl).WriteProperties(buildEvent, properties); prop1 = String.Format(CultureInfo.CurrentCulture, "{0} = {1}", "prop1", "val1"); prop2 = String.Format(CultureInfo.CurrentCulture, "{0} = {1}", "prop2", "val2"); @@ -1352,7 +1352,7 @@ private void WriteAndValidateItems(BaseConsoleLogger cl, SimulatedConsole sc, bo string item3metadatum = string.Empty; BuildEventArgs buildEvent = new BuildErrorEventArgs("", "", "", 0, 0, 0, 0, "", "", ""); - buildEvent.BuildEventContext = new BuildEventContext(1, 2, 3, 4); + buildEvent.BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); ((ParallelConsoleLogger)cl).WriteItems(buildEvent, items); item1spec = Environment.NewLine + " spec" + Environment.NewLine; item2spec = Environment.NewLine + " spec2" + Environment.NewLine; @@ -1409,7 +1409,7 @@ public void WriteItemsEmptyList() SimulatedConsole sc = new SimulatedConsole(); BaseConsoleLogger cl = new ParallelConsoleLogger(LoggerVerbosity.Diagnostic, sc.Write, null, null); BuildEventArgs buildEvent = new BuildErrorEventArgs("", "", "", 0, 0, 0, 0, "", "", ""); - buildEvent.BuildEventContext = new BuildEventContext(1, 2, 3, 4); + buildEvent.BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); ((ParallelConsoleLogger)cl).WriteItems(buildEvent, items); string log = sc.ToString(); @@ -1429,7 +1429,7 @@ public void WritePropertiesEmptyList() SimulatedConsole sc = new SimulatedConsole(); var cl = new ParallelConsoleLogger(LoggerVerbosity.Diagnostic, sc.Write, null, null); BuildEventArgs buildEvent = new BuildErrorEventArgs("", "", "", 0, 0, 0, 0, "", "", ""); - buildEvent.BuildEventContext = new BuildEventContext(1, 2, 3, 4); + buildEvent.BuildEventContext = BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4); cl.WriteProperties(buildEvent, properties); string log = sc.ToString(); @@ -1535,13 +1535,13 @@ public void ResetConsoleLoggerStateTestBasic() // Introduce a warning BuildWarningEventArgs bwea = new BuildWarningEventArgs("VBC", "31415", "file.vb", 42, 0, 0, 0, "Some long message", "help", "sender"); - bwea.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + bwea.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(bwea); // Introduce an error BuildErrorEventArgs beea = new BuildErrorEventArgs("VBC", "31415", "file.vb", 42, 0, 0, 0, "Some long message", "help", "sender"); - beea.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + beea.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(beea); @@ -1622,13 +1622,13 @@ public void ResetConsoleLoggerState_Initialize() // Introduce a warning BuildWarningEventArgs bwea = new BuildWarningEventArgs("VBC", "31415", "file.vb", 42, 0, 0, 0, "Some long message", "help", "sender"); - bwea.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + bwea.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(bwea); // Introduce an error BuildErrorEventArgs beea = new BuildErrorEventArgs("VBC", "31415", "file.vb", 42, 0, 0, 0, "Some long message", "help", "sender"); - beea.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + beea.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(beea); @@ -1704,8 +1704,8 @@ public void ResetConsoleLoggerState_PerformanceCounters() // BuildStarted Event es.Consume(new BuildStartedEventArgs("bs", null)); // Project Started Event - ProjectStartedEventArgs project1Started = new ProjectStartedEventArgs(1, null, null, "p", "t", null, null, new BuildEventContext(BuildEventContext.InvalidNodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId)); - project1Started.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + ProjectStartedEventArgs project1Started = new ProjectStartedEventArgs(1, null, null, "p", "t", null, null, BuildEventContext.CreateInitial(0, BuildEventContext.InvalidNodeId)); + project1Started.BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); es.Consume(project1Started); TargetStartedEventArgs targetStarted1 = new TargetStartedEventArgs(null, null, "t", null, null); targetStarted1.BuildEventContext = project1Started.BuildEventContext; @@ -1733,7 +1733,7 @@ public void ResetConsoleLoggerState_PerformanceCounters() ProjectStartedEventArgs project2Started = new ProjectStartedEventArgs(2, null, null, "p2", "t2", null, null, project1Started.BuildEventContext); // Project Started Event - project2Started.BuildEventContext = new BuildEventContext(2, 2, 2, 2); + project2Started.BuildEventContext = BuildEventContext.CreateInitial(2, 2).WithEvaluationId(2).WithProjectInstanceId(2); es.Consume(project2Started); TargetStartedEventArgs targetStarted2 = new TargetStartedEventArgs(null, null, "t2", null, null); targetStarted2.BuildEventContext = project2Started.BuildEventContext; @@ -1818,7 +1818,7 @@ public void DeferredMessages() L.Initialize(es, 2); es.Consume(new BuildStartedEventArgs("bs", null)); TaskCommandLineEventArgs messsage1 = new TaskCommandLineEventArgs("Message", null, MessageImportance.High); - messsage1.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + messsage1.BuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 1).WithTargetId(1).WithProjectContextId(1).WithTaskId(1); // Message Event es.Consume(messsage1); es.Consume(new BuildFinishedEventArgs("bf", null, true)); @@ -1832,7 +1832,7 @@ public void DeferredMessages() L.Initialize(es, 2); es.Consume(new BuildStartedEventArgs("bs", null)); BuildMessageEventArgs messsage2 = new BuildMessageEventArgs("Message", null, null, MessageImportance.High); - messsage2.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + messsage2.BuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 1).WithTargetId(2).WithProjectContextId(3).WithTaskId(4); // Message Event es.Consume(messsage2); es.Consume(new BuildFinishedEventArgs("bf", null, true)); @@ -1846,7 +1846,7 @@ public void DeferredMessages() L.Initialize(es, 2); es.Consume(new BuildStartedEventArgs("bs", null)); messsage2 = new BuildMessageEventArgs("Message", null, null, MessageImportance.High); - messsage2.BuildEventContext = new BuildEventContext(1, 1, 1, 1); + messsage2.BuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 1).WithTargetId(2).WithProjectContextId(3).WithTaskId(4); // Message Event es.Consume(messsage2); ProjectStartedEventArgs project = new ProjectStartedEventArgs(1, "Hello,", "HI", "None", "Build", null, null, messsage1.BuildEventContext); @@ -1878,8 +1878,7 @@ public void VerifyMPLoggerSwitch() L.Initialize(es); } es.Consume(new BuildStartedEventArgs("bs", null)); - BuildEventContext context = new BuildEventContext(1, 1, 1, 1); - BuildEventContext context2 = new BuildEventContext(2, 2, 2, 2); + BuildEventContext context = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); ProjectStartedEventArgs project = new ProjectStartedEventArgs(1, "Hello,", "HI", "None", "Build", null, null, context); project.BuildEventContext = context; @@ -1908,8 +1907,8 @@ public void TestPrintTargetNamePerMessage() ConsoleLogger L = new ConsoleLogger(LoggerVerbosity.Normal, sc.Write, sc.SetColor, sc.ResetColor); L.Initialize(es, 2); es.Consume(new BuildStartedEventArgs("bs", null)); - BuildEventContext context = new BuildEventContext(1, 1, 1, 1); - BuildEventContext context2 = new BuildEventContext(2, 2, 2, 2); + BuildEventContext context = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1); + BuildEventContext context2 = BuildEventContext.CreateInitial(2, 2).WithEvaluationId(2).WithProjectInstanceId(2); ProjectStartedEventArgs project = new ProjectStartedEventArgs(1, "Hello,", "HI", "None", "Build", null, null, context); project.BuildEventContext = context; diff --git a/src/Build.UnitTests/Construction/SolutionFilter_Tests.cs b/src/Build.UnitTests/Construction/SolutionFilter_Tests.cs index 593dc8bf5c0..681d55529ac 100644 --- a/src/Build.UnitTests/Construction/SolutionFilter_Tests.cs +++ b/src/Build.UnitTests/Construction/SolutionFilter_Tests.cs @@ -28,7 +28,7 @@ public class SolutionFilter_Tests : IDisposable { private readonly ITestOutputHelper output; - private static readonly BuildEventContext _buildEventContext = new BuildEventContext(0, 0, BuildEventContext.InvalidProjectContextId, 0); + private static readonly BuildEventContext _buildEventContext = BuildEventContext.CreateInitial(0, 0).WithProjectContextId(BuildEventContext.InvalidProjectContextId); public SolutionFilter_Tests(ITestOutputHelper output) { diff --git a/src/Build.UnitTests/Construction/SolutionProjectGenerator_Tests.cs b/src/Build.UnitTests/Construction/SolutionProjectGenerator_Tests.cs index c57f5ebedb9..a75bec5bf33 100644 --- a/src/Build.UnitTests/Construction/SolutionProjectGenerator_Tests.cs +++ b/src/Build.UnitTests/Construction/SolutionProjectGenerator_Tests.cs @@ -36,7 +36,7 @@ public class SolutionProjectGenerator_Tests : IDisposable private string _originalVisualStudioVersion = null; - private static readonly BuildEventContext _buildEventContext = new BuildEventContext(0, 0, BuildEventContext.InvalidProjectContextId, 0); + private static readonly BuildEventContext _buildEventContext = BuildEventContext.CreateInitial(0, 0).WithProjectContextId(BuildEventContext.InvalidProjectContextId); private const string _longLineString = "a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-a-really-long-string-"; diff --git a/src/Build.UnitTests/Definition/ToolsVersion_Tests.cs b/src/Build.UnitTests/Definition/ToolsVersion_Tests.cs index 23d5fc1aa63..927e0c163c4 100644 --- a/src/Build.UnitTests/Definition/ToolsVersion_Tests.cs +++ b/src/Build.UnitTests/Definition/ToolsVersion_Tests.cs @@ -35,7 +35,7 @@ public void OverrideTasksAreFoundInOverridePath() using var collection = new ProjectCollection(); Toolset t = new Toolset("toolsversionname", dir, new PropertyDictionary(), collection, new DirectoryGetFiles(this.getFiles), new LoadXmlFromPath(this.loadXmlFromPath), overrideDir, new DirectoryExists(this.directoryExists)); - LoggingContext loggingContext = TestLoggingContext.CreateTestContext(new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = TestLoggingContext.CreateTestContext(BuildEventContext.CreateInitial(1, 2).WithEvaluationId(BuildEventContext.InvalidProjectContextId).WithProjectInstanceId(4)); TaskRegistry taskRegistry = (TaskRegistry)t.GetTaskRegistry(loggingContext, e.ProjectRootElementCache); TaskRegistry taskoverrideRegistry = (TaskRegistry)t.GetOverrideTaskRegistry(loggingContext, e.ProjectRootElementCache); @@ -81,7 +81,7 @@ public void OverrideTaskPathIsRelative() MockLogger mockLogger = new MockLogger(); LoggingService service = (LoggingService)LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); service.RegisterLogger(mockLogger); - LoggingContext loggingContext = new TestLoggingContext(service, new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = new TestLoggingContext(service, BuildEventContext.CreateInitial(1, 2).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(4)); TaskRegistry taskoverrideRegistry = (TaskRegistry)t.GetOverrideTaskRegistry(loggingContext, e.ProjectRootElementCache); @@ -101,7 +101,7 @@ public void OverrideTaskPathHasInvalidChars() MockLogger mockLogger = new MockLogger(); LoggingService service = (LoggingService)LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); service.RegisterLogger(mockLogger); - LoggingContext loggingContext = new TestLoggingContext(service, new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = new TestLoggingContext(service, BuildEventContext.CreateInitial(1, 2).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(4)); TaskRegistry taskoverrideRegistry = (TaskRegistry)t.GetOverrideTaskRegistry(loggingContext, e.ProjectRootElementCache); Assert.NotNull(taskoverrideRegistry); @@ -120,7 +120,7 @@ public void OverrideTaskPathHasTooLongOfAPath() MockLogger mockLogger = new MockLogger(); LoggingService service = (LoggingService)LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); service.RegisterLogger(mockLogger); - LoggingContext loggingContext = new TestLoggingContext(service, new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = new TestLoggingContext(service, BuildEventContext.CreateInitial(1, 2).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(4)); TaskRegistry taskoverrideRegistry = (TaskRegistry)t.GetOverrideTaskRegistry(loggingContext, e.ProjectRootElementCache); Assert.NotNull(taskoverrideRegistry); @@ -140,7 +140,7 @@ public void OverrideTaskPathIsNotFound() MockLogger mockLogger = new MockLogger(); LoggingService service = (LoggingService)LoggingService.CreateLoggingService(LoggerMode.Synchronous, 1); service.RegisterLogger(mockLogger); - LoggingContext loggingContext = new TestLoggingContext(service, new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = new TestLoggingContext(service, BuildEventContext.CreateInitial(1, 2).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(4)); TaskRegistry taskoverrideRegistry = (TaskRegistry)t.GetOverrideTaskRegistry(loggingContext, e.ProjectRootElementCache); Assert.NotNull(taskoverrideRegistry); @@ -164,7 +164,7 @@ public void DefaultTasksAreFoundInToolsPath() null, new DirectoryExists(this.directoryExists)); - LoggingContext loggingContext = TestLoggingContext.CreateTestContext(new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = TestLoggingContext.CreateTestContext(BuildEventContext.CreateInitial(1, 2).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(4)); TaskRegistry taskRegistry = (TaskRegistry)t.GetTaskRegistry(loggingContext, ProjectCollection.GlobalProjectCollection.ProjectRootElementCache); string[] expectedRegisteredTasks = { "a1", "a2", "a3", "a4", "b1", "e1", "g1", "g2", "g3" }; @@ -931,7 +931,7 @@ public void InlineTasksInDotTasksFile() null, new DirectoryExists(directoryExists)); - LoggingContext loggingContext = TestLoggingContext.CreateTestContext(new BuildEventContext(1, 2, BuildEventContext.InvalidProjectContextId, 4)); + LoggingContext loggingContext = TestLoggingContext.CreateTestContext(BuildEventContext.CreateInitial(1, 2).WithProjectContextId(BuildEventContext.InvalidProjectContextId).WithTaskId(4)); TaskRegistry taskRegistry = (TaskRegistry)t.GetTaskRegistry(loggingContext, ProjectCollection.GlobalProjectCollection.ProjectRootElementCache); diff --git a/src/Build.UnitTests/Evaluation/Evaluator_Tests.cs b/src/Build.UnitTests/Evaluation/Evaluator_Tests.cs index 7c289d90ef0..b3ef3bbda53 100644 --- a/src/Build.UnitTests/Evaluation/Evaluator_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Evaluator_Tests.cs @@ -4497,7 +4497,7 @@ public void VerifyConditionEvaluatorResetStateOnFailure() Directory.GetCurrentDirectory(), MockElementLocation.Instance, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); Assert.Fail("Expect exception due to the value of property \"TargetOSFamily\" is not a number."); } catch (InvalidProjectFileException e) @@ -4515,7 +4515,7 @@ public void VerifyConditionEvaluatorResetStateOnFailure() Directory.GetCurrentDirectory(), MockElementLocation.Instance, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4)))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)))); } /// diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index 46762a8712e..0167d9aa165 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -98,7 +98,7 @@ public void ExpandAllIntoTaskItems3() pg, itemsByType, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); IList itemsOut = expander.ExpandIntoTaskItemsLeaveEscaped("foo;bar;@(compile);@(resource)", ExpanderOptions.ExpandPropertiesAndItems, MockElementLocation.Instance); @@ -847,7 +847,7 @@ private Expander CreateExpander() pg, ig, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); return expander; } @@ -2366,7 +2366,7 @@ public void PropertyFunctionInCondition() Directory.GetCurrentDirectory(), MockElementLocation.Instance, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4)))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)))); Assert.True( ConditionEvaluator.EvaluateCondition( @"'$(PathRoot.EndsWith(" + Path.DirectorySeparatorChar + "))' == 'false'", @@ -2376,7 +2376,7 @@ public void PropertyFunctionInCondition() Directory.GetCurrentDirectory(), MockElementLocation.Instance, FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4)))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4)))); } /// @@ -5239,7 +5239,10 @@ public void FastPathValidationTest(string methodInvocationMetadata) loggingService.RegisterLogger(logger); var loggingContext = new MockLoggingContext( loggingService, - new BuildEventContext(0, 0, BuildEventContext.InvalidProjectContextId, 0, 0)); + BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 0) + .WithProjectInstanceId(0) + .WithTargetId(0) + .WithTaskId(0)); _ = new Expander( new PropertyDictionary(), @@ -5276,7 +5279,10 @@ public void PropertyFunctionRegisterBuildCheck() loggingService.RegisterLogger(logger); var loggingContext = new MockLoggingContext( loggingService, - new BuildEventContext(0, 0, BuildEventContext.InvalidProjectContextId, 0, 0)); + BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 0) + .WithProjectInstanceId(0) + .WithTargetId(0) + .WithTaskId(0)); var dummyAssemblyFile = env.CreateFile(env.CreateFolder(), "test.dll"); var result = new Expander(new PropertyDictionary(), FileSystems.Default, loggingContext) diff --git a/src/Build.UnitTests/Evaluation/ItemSpec_Tests.cs b/src/Build.UnitTests/Evaluation/ItemSpec_Tests.cs index 06b32c45258..68c7b7127fd 100644 --- a/src/Build.UnitTests/Evaluation/ItemSpec_Tests.cs +++ b/src/Build.UnitTests/Evaluation/ItemSpec_Tests.cs @@ -93,7 +93,7 @@ private ProjectInstanceExpander CreateExpander(Dictionary item new PropertyDictionary(), itemDictionary, (IFileSystem)FileSystems.Default, - new TestLoggingContext(null!, new BuildEventContext(1, 2, 3, 4))); + new TestLoggingContext(null!, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); } private static ItemDictionary ToItemDictionary(Dictionary itemTypes) diff --git a/src/Build.UnitTests/Evaluation/UsedUninitializedProperties_Tests.cs b/src/Build.UnitTests/Evaluation/UsedUninitializedProperties_Tests.cs index f9de1bc6144..63ece0629cd 100644 --- a/src/Build.UnitTests/Evaluation/UsedUninitializedProperties_Tests.cs +++ b/src/Build.UnitTests/Evaluation/UsedUninitializedProperties_Tests.cs @@ -15,7 +15,7 @@ public sealed class UsedUninitializedProperties_Tests [Fact] public void Basics() { - PropertiesUseTracker props = new(TestLoggingContext.CreateTestContext(new BuildEventContext(1, 2, 3, 4))); + PropertiesUseTracker props = new(TestLoggingContext.CreateTestContext(BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4))); Assert.False(props.TryGetPropertyElementLocation("Hello", out IElementLocation? elementLocation)); Assert.Null(elementLocation); diff --git a/src/Build.UnitTests/FileLogger_Tests.cs b/src/Build.UnitTests/FileLogger_Tests.cs index 28161a9a783..005d40996f7 100644 --- a/src/Build.UnitTests/FileLogger_Tests.cs +++ b/src/Build.UnitTests/FileLogger_Tests.cs @@ -58,7 +58,7 @@ public void BasicNoExistingFile() try { log = FileUtilities.GetTemporaryFileName(); - SetUpFileLoggerAndLogMessage("logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); VerifyFileContent(log, "message here"); } finally @@ -84,7 +84,7 @@ public void InvalidFile() try { - SetUpFileLoggerAndLogMessage("logfile=||invalid||", new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("logfile=||invalid||", new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); } finally { @@ -111,7 +111,7 @@ public void SpecificVerbosity() fl.Parameters = "verbosity=diagnostic;logfile=" + log; // diagnostic specific setting fl.Verbosity = LoggerVerbosity.Quiet; // quiet global setting fl.Initialize(es); - fl.MessageHandler(null, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + fl.MessageHandler(null, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); fl.Shutdown(); // expect message to appear because diagnostic not quiet verbosity was used @@ -213,7 +213,7 @@ public void ValidEncoding() try { log = FileUtilities.GetTemporaryFileName(); - SetUpFileLoggerAndLogMessage("encoding=utf-16;logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("encoding=utf-16;logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); byte[] content = ReadRawBytes(log); // FF FE is the BOM for UTF16 @@ -240,7 +240,7 @@ public void ValidEncoding2() try { log = FileUtilities.GetTemporaryFileName(); - SetUpFileLoggerAndLogMessage("encoding=utf-8;logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("encoding=utf-8;logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); byte[] content = ReadRawBytes(log); // EF BB BF is the BOM for UTF8 @@ -290,7 +290,7 @@ public void BasicExistingFileNoAppend() { log = FileUtilities.GetTemporaryFileName(); WriteContentToFile(log); - SetUpFileLoggerAndLogMessage("logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); VerifyFileContent(log, "message here"); } finally @@ -314,7 +314,7 @@ public void BasicExistingFileAppend() { log = FileUtilities.GetTemporaryFileName(); WriteContentToFile(log); - SetUpFileLoggerAndLogMessage("append;logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("append;logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); VerifyFileContent(log, "existing content\nmessage here"); } finally @@ -339,7 +339,7 @@ public void BasicNoExistingDirectory() try { - SetUpFileLoggerAndLogMessage("logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = new BuildEventContext(1, 1, 1, 1) }); + SetUpFileLoggerAndLogMessage("logfile=" + log, new BuildMessageEventArgs("message here", null, null, MessageImportance.High) { BuildEventContext = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1) }); VerifyFileContent(log, "message here"); } finally diff --git a/src/Build.UnitTests/Instance/ProjectInstance_Internal_Tests.cs b/src/Build.UnitTests/Instance/ProjectInstance_Internal_Tests.cs index fd8ba8841d0..3f2e8f91197 100644 --- a/src/Build.UnitTests/Instance/ProjectInstance_Internal_Tests.cs +++ b/src/Build.UnitTests/Instance/ProjectInstance_Internal_Tests.cs @@ -857,7 +857,7 @@ public void GetImportPathsAndImportPathsIncludingDuplicates(bool useDirectConstr using ProjectCollection projectCollection = new ProjectCollection(); BuildParameters buildParameters = new BuildParameters(projectCollection) { ProjectLoadSettings = projectLoadSettings }; - BuildEventContext buildEventContext = new BuildEventContext(0, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(BuildEventContext.InvalidProjectContextId).WithProjectInstanceId(BuildEventContext.InvalidTaskId); using ProjectRootElementFromString projectRootElementFromString = new(projectFileContent); ProjectRootElement rootElement = projectRootElementFromString.Project; diff --git a/src/Build.UnitTests/TerminalLogger_Tests.cs b/src/Build.UnitTests/TerminalLogger_Tests.cs index 575b727ad46..4ca45c495ff 100644 --- a/src/Build.UnitTests/TerminalLogger_Tests.cs +++ b/src/Build.UnitTests/TerminalLogger_Tests.cs @@ -249,14 +249,12 @@ public void CreateTerminalOrConsoleLogger_ParsesVerbosity(string? argsString, Lo /// private BuildEventContext MakeBuildEventContext(int evalId = 1, int projectContextId = 1, int nodeId = 1) { - return new BuildEventContext( - submissionId: -1, - nodeId: nodeId, - evaluationId: evalId, - projectInstanceId: -1, - projectContextId: projectContextId, - targetId: 1, - taskId: 1); + return BuildEventContext.CreateInitial(-1, nodeId) + .WithEvaluationId(evalId) + .WithProjectInstanceId(-1) + .WithProjectContextId(projectContextId) + .WithTargetId(1) + .WithTaskId(1); } private BuildStartedEventArgs MakeBuildStartedEventArgs(BuildEventContext? buildEventContext = null) @@ -722,7 +720,7 @@ public Task LogEvaluationErrorFromEngine() "MSB0001", "EvaluationError", "MSBUILD", 0, 0, 0, 0, "An error occurred during evaluation.", null, null) { - BuildEventContext = new BuildEventContext(1, -1, -1, -1) // context that belongs to no project + BuildEventContext = BuildEventContext.CreateInitial(1, -1).WithEvaluationId(-1).WithProjectInstanceId(-1) // context that belongs to no project }); }); diff --git a/src/Build/BackEnd/BuildManager/BuildManager.cs b/src/Build/BackEnd/BuildManager/BuildManager.cs index 7a70791f17b..aea9408d8d7 100644 --- a/src/Build/BackEnd/BuildManager/BuildManager.cs +++ b/src/Build/BackEnd/BuildManager/BuildManager.cs @@ -1453,13 +1453,7 @@ internal void ExecuteSubmission( where TResultData : BuildResultBase { // For the current submission we only know the SubmissionId and that it happened on scheduler node - all other BuildEventContext dimensions are unknown now. - BuildEventContext buildEventContext = new BuildEventContext( - submission.SubmissionId, - nodeId: 1, - BuildEventContext.InvalidProjectInstanceId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidTaskId); + BuildEventContext buildEventContext = submission.BuildEventContext; BuildSubmissionStartedEventArgs submissionStartedEvent = new( submission.BuildRequestDataBase.GlobalPropertiesLookup, @@ -1547,7 +1541,7 @@ private void LoadSolutionIntoConfiguration(BuildRequestConfiguration config, Bui var buildEventContext = request.BuildEventContext; if (buildEventContext == BuildEventContext.Invalid) { - buildEventContext = new BuildEventContext(request.SubmissionId, 0, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + buildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithSubmissionId(request.SubmissionId); } var instances = ProjectInstance.LoadSolutionForBuild( @@ -1809,13 +1803,20 @@ void LogInvalidProjectFileError(InvalidProjectFileException projectException) { if (!projectException.HasBeenLogged) { - BuildEventContext buildEventContext = new BuildEventContext(submission.SubmissionId, 1, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + BuildEventContext buildEventContext = CreateErrorLoggingContext(submission.SubmissionId); ((IBuildComponentHost)this).LoggingService.LogInvalidProjectFileError(buildEventContext, projectException); projectException.HasBeenLogged = true; } } } + /// + /// Creates a BuildEventContext suitable for error logging for the given submission. + /// + /// The submission ID + /// A BuildEventContext for logging errors + private static BuildEventContext CreateErrorLoggingContext(int submissionId) => Scheduler.s_schedulerInProcNodeBuildEventContext.WithSubmissionId(submissionId); + /// /// Waits to drain all events of logging service. /// This method shall be used carefully because during draining, LoggingService will block all incoming events. @@ -1918,7 +1919,7 @@ void IssueBuildSubmissionToSchedulerImpl(BuildSubmission submission, bool allowM { if (!projectException.HasBeenLogged) { - BuildEventContext projectBuildEventContext = new BuildEventContext(submission.SubmissionId, 1, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + BuildEventContext projectBuildEventContext = CreateErrorLoggingContext(submission.SubmissionId); ((IBuildComponentHost)this).LoggingService.LogInvalidProjectFileError(projectBuildEventContext, projectException); projectException.HasBeenLogged = true; } @@ -1934,7 +1935,7 @@ void IssueBuildSubmissionToSchedulerImpl(BuildSubmission submission, bool allowM if (ex is not InvalidProjectFileException) { - var buildEventContext = new BuildEventContext(submission.SubmissionId, 1, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + var buildEventContext = CreateErrorLoggingContext(submission.SubmissionId); ((IBuildComponentHost)this).LoggingService.LogFatalBuildError(buildEventContext, ex, new BuildEventFileInfo(submission.BuildRequestData.ProjectFullPath)); } } @@ -1992,14 +1993,7 @@ private void ExecuteGraphBuildScheduler(GraphBuildSubmission submission) null, _buildParameters, ((IBuildComponentHost)this).LoggingService, - new BuildEventContext( - submission.SubmissionId, - _buildParameters.NodeId, - BuildEventContext.InvalidEvaluationId, - BuildEventContext.InvalidProjectInstanceId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidTaskId), + BuildEventContext.CreateInitial(submission.SubmissionId, _buildParameters.NodeId), SdkResolverService, submission.SubmissionId, projectLoadSettings); @@ -2502,6 +2496,11 @@ private void HandleResult(int node, BuildResult result) configuration.ProjectDefaultTargets ??= result.DefaultTargets; configuration.ProjectInitialTargets ??= result.InitialTargets; configuration.ProjectTargets ??= result.ProjectTargets; + // Update the evaluation ID if it's valid (not InvalidEvaluationId) + if (result.EvaluationId != BuildEventContext.InvalidEvaluationId) + { + configuration.ProjectEvaluationId = result.EvaluationId; + } } // Only report results to the project cache services if it's the result for a build submission. @@ -2521,7 +2520,9 @@ private void HandleResult(int node, BuildResult result) { BuildEventContext buildEventContext = _projectStartedEvents.TryGetValue(result.SubmissionId, out BuildEventArgs? buildEventArgs) ? buildEventArgs.BuildEventContext! - : new BuildEventContext(result.SubmissionId, node, configuration.Project?.EvaluationId ?? BuildEventContext.InvalidEvaluationId, configuration.ConfigurationId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + : BuildEventContext.CreateInitial(result.SubmissionId, node) + .WithEvaluationId(configuration.ProjectEvaluationId) + .WithProjectInstanceId(configuration.ConfigurationId); try { _projectCacheService.HandleBuildResultAsync(configuration, result, buildEventContext, _executionCancellationTokenSource!.Token).Wait(); @@ -2560,9 +2561,8 @@ private void HandleNodeShutdown(int node, NodeShutdown shutdownPacket) ILoggingService loggingService = ((IBuildComponentHost)this).GetComponent(BuildComponentType.LoggingService); foreach (BuildSubmissionBase submission in _buildSubmissions.Values) { - BuildEventContext buildEventContext = new BuildEventContext(submission.SubmissionId, BuildEventContext.InvalidNodeId, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); string exception = ExceptionHandling.ReadAnyExceptionFromFile(_instantiationTimeUtc); - loggingService?.LogError(buildEventContext, new BuildEventFileInfo(string.Empty) /* no project file */, "ChildExitedPrematurely", node, ExceptionHandling.DebugDumpPath, exception); + loggingService?.LogError(submission.BuildEventContext, new BuildEventFileInfo(string.Empty) /* no project file */, "ChildExitedPrematurely", node, ExceptionHandling.DebugDumpPath, exception); } } else if (shutdownPacket.Reason == NodeShutdownReason.Error && _buildSubmissions.Values.Count == 0) @@ -2716,7 +2716,7 @@ private void PerformSchedulingActions(IEnumerable responses) if (newNodes?.Count != response.NumberOfNodesToCreate || newNodes.Any(n => n == null)) { - BuildEventContext buildEventContext = new BuildEventContext(0, Scheduler.VirtualNode, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + BuildEventContext buildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithSubmissionId(0); ((IBuildComponentHost)this).LoggingService.LogError(buildEventContext, new BuildEventFileInfo(String.Empty), "UnableToCreateNode", response.RequiredNodeType.ToString("G")); throw new BuildAbortedException(ResourceUtilities.FormatResourceStringStripCodeAndKeyword("UnableToCreateNode", response.RequiredNodeType.ToString("G"))); diff --git a/src/Build/BackEnd/BuildManager/BuildSubmissionBase.cs b/src/Build/BackEnd/BuildManager/BuildSubmissionBase.cs index 8195c79aa0e..7b3921c8c04 100644 --- a/src/Build/BackEnd/BuildManager/BuildSubmissionBase.cs +++ b/src/Build/BackEnd/BuildManager/BuildSubmissionBase.cs @@ -3,6 +3,7 @@ using System; using System.Threading; +using Microsoft.Build.BackEnd; using Microsoft.Build.Shared; namespace Microsoft.Build.Execution @@ -43,6 +44,7 @@ protected internal BuildSubmissionBase(BuildManager buildManager, int submission CompletionEvent = new ManualResetEvent(false); LoggingCompleted = false; CompletionInvoked = 0; + BuildEventContext = Framework.BuildEventContext.CreateInitial(submissionId, Scheduler.VirtualNode); } /// @@ -55,6 +57,11 @@ protected internal BuildSubmissionBase(BuildManager buildManager, int submission /// public int SubmissionId { get; } + /// + /// The build event context for this submission. This will have the submission ID set, and a nodeId of the scheduler's virtual node.. + /// + public Framework.BuildEventContext BuildEventContext { get; } + /// /// The asynchronous context provided to , if any. /// diff --git a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs index 8c66af36507..69eda444542 100644 --- a/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs +++ b/src/Build/BackEnd/Components/BuildRequestEngine/BuildRequestEngine.cs @@ -852,6 +852,7 @@ private void EvaluateRequestStates() completedEntry.Result.DefaultTargets = configuration.ProjectDefaultTargets; completedEntry.Result.InitialTargets = configuration.ProjectInitialTargets; completedEntry.Result.ProjectTargets = configuration.ProjectTargets; + completedEntry.Result.EvaluationId = configuration.ProjectEvaluationId; } TraceEngine("ERS: Request is now {0}({1}) (nr {2}) has had its builder cleaned up.", completedEntry.Request.GlobalRequestId, completedEntry.Request.ConfigurationId, completedEntry.Request.NodeRequestId); diff --git a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs index e5eecc0ef06..b24df6b862b 100644 --- a/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs +++ b/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs @@ -291,7 +291,7 @@ bool TryReuseAnyFromPossibleRunningNodes(int currentProcessId, int nodeId) string msg = ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword("NodeReused", nodeId, nodeToReuse.Id); _componentHost.LoggingService.LogBuildEvent(new BuildMessageEventArgs(msg, null, null, MessageImportance.Low) { - BuildEventContext = new BuildEventContext(nodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId) + BuildEventContext = BuildEventContext.CreateInitial(0 /* submission ID */, nodeId) }); CreateNodeContext(nodeId, nodeToReuse, nodeStream); diff --git a/src/Build/BackEnd/Components/Logging/EvaluationLoggingContext.cs b/src/Build/BackEnd/Components/Logging/EvaluationLoggingContext.cs index 15f4387218a..861b8a373a5 100644 --- a/src/Build/BackEnd/Components/Logging/EvaluationLoggingContext.cs +++ b/src/Build/BackEnd/Components/Logging/EvaluationLoggingContext.cs @@ -22,7 +22,7 @@ internal class EvaluationLoggingContext : LoggingContext public EvaluationLoggingContext(ILoggingService loggingService, BuildEventContext buildEventContext, string projectFile) : base( loggingService, - loggingService.CreateEvaluationBuildEventContext(buildEventContext.NodeId, buildEventContext.SubmissionId)) + loggingService.CreateEvaluationBuildEventContext(buildEventContext)) { _projectFile = projectFile; IsValid = true; diff --git a/src/Build/BackEnd/Components/Logging/ILoggingService.cs b/src/Build/BackEnd/Components/Logging/ILoggingService.cs index 9296eb45927..f49d301fad4 100644 --- a/src/Build/BackEnd/Components/Logging/ILoggingService.cs +++ b/src/Build/BackEnd/Components/Logging/ILoggingService.cs @@ -497,20 +497,17 @@ MessageImportance MinimumRequiredMessageImportance /// /// Create an evaluation context, by generating a new evaluation id. /// - /// The node id - /// The submission id + /// The parent context to derive the new evaluation context from /// - BuildEventContext CreateEvaluationBuildEventContext(int nodeId, int submissionId); + BuildEventContext CreateEvaluationBuildEventContext(BuildEventContext parentContext); /// - /// Create a project cache context, by generating a new project context id. + /// Create a project-level build event context, by generating a new project context id and applying it to a parent context scope. /// - /// The submission id - /// The evaluation id - /// The project instance id + /// The parent context to derive the new project cache context from /// Project file being built /// - BuildEventContext CreateProjectCacheBuildEventContext(int submissionId, int evaluationId, int projectInstanceId, string projectFile); + BuildEventContext CreateProjectCacheBuildEventContext(BuildEventContext parentBuildEventContext, string projectFile); /// /// Logs that a project evaluation has started @@ -538,45 +535,58 @@ void LogProjectEvaluationFinished( IEnumerable items, ProfilerResult? profilerResult); + void LogProjectStarted(ProjectStartedEventArgs args); + /// - /// Log that a project has started - /// - /// The logging context of the node which is building this project. - /// The id of the build submission. - /// The id of the project configuration which is about to start - /// The build context of the parent project which asked this project to build - /// The project file path of the project about to be built - /// The entrypoint target names for this project - /// The initial properties of the project - /// The initial items of the project - /// EvaluationId of the project instance - /// The project context id - /// The BuildEventContext to use for this project. - BuildEventContext LogProjectStarted( - BuildEventContext nodeBuildEventContext, - int submissionId, - int configurationId, + /// Creates a ProjectStartedEventArgs for a locally-building project - + /// meaning one that is not served from cache and is building on the current node. + /// + /// The parent build event context for the project that is starting. + /// The configuration ID of the project that is starting. + /// The project file path of the project that is starting. + /// The target names that are being built. + /// The global properties for the project instance. + /// The initial properties for the project instance, if any. + /// The initial items for the project instance, if any. + /// The tools version for the project instance. + /// + /// We _could_ pass in BuildRequest/BuildRequestConfiguration for most of this data, but that makes layering/dependency + /// tracking of the namespaces more complex, and we don't really need the full objects here. + /// + ProjectStartedEventArgs CreateProjectStartedForLocalProject( BuildEventContext parentBuildEventContext, + int configurationId, string projectFile, string targetNames, + IDictionary globalProperties, IEnumerable properties, IEnumerable items, - int evaluationId = BuildEventContext.InvalidEvaluationId, - int projectContextId = BuildEventContext.InvalidProjectContextId); - - void LogProjectStarted(ProjectStartedEventArgs args); - - ProjectStartedEventArgs CreateProjectStarted( - BuildEventContext nodeBuildEventContext, - int submissionId, - int configurationId, + string toolsVersion); + + /// + /// Creates a ProjectStartedEventArgs for a project that was already built on another node, so + /// is being served from cache. Unlike the local-build case, we don't have properties/items + /// because they were not deserialized from the cache. + /// + /// The build event context on the current node. + /// The complete evaluation build event context on the remote node. + /// The parent build event context for the project that is already built. + /// The global properties for the project instance, from the configuration. + /// The project file path of the project that is already built. + /// The target names that were built. + /// The tools version for the project instance. + /// + /// We _could_ pass in BuildRequest/BuildRequestConfiguration for most of this data, but that makes layering/dependency + /// tracking of the namespaces more complex, and we don't really need the full objects here. + /// + ProjectStartedEventArgs CreateProjectStartedForCachedProject( + BuildEventContext currentNodeBuildEventContext, + BuildEventContext remoteNodeEvaluationBuildEventContext, BuildEventContext parentBuildEventContext, + IDictionary globalProperties, string projectFile, string targetNames, - IEnumerable properties, - IEnumerable items, - int evaluationId = BuildEventContext.InvalidEvaluationId, - int projectContextId = BuildEventContext.InvalidProjectContextId); + string toolsVersion); /// /// Log that the project has finished diff --git a/src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs b/src/Build/BackEnd/Components/Logging/LoggingServiceLogMethods.cs index 31c9f55eeb0..9cf574438a8 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 System.Diagnostics; using Microsoft.Build.BackEnd.Shared; using Microsoft.Build.Experimental.BuildCheck; using Microsoft.Build.Experimental.BuildCheck.Infrastructure; @@ -401,14 +402,12 @@ public void LogBuildCanceled() } /// - public BuildEventContext CreateEvaluationBuildEventContext(int nodeId, int submissionId) - => new BuildEventContext(submissionId, nodeId, NextEvaluationId, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + public BuildEventContext CreateEvaluationBuildEventContext(BuildEventContext parentContext) + => parentContext.WithEvaluationId(NextEvaluationId); /// public BuildEventContext CreateProjectCacheBuildEventContext( - int submissionId, - int evaluationId, - int projectInstanceId, + BuildEventContext parentBuildEventContext, string projectFile) { int projectContextId = NextProjectId; @@ -416,11 +415,8 @@ public BuildEventContext CreateProjectCacheBuildEventContext( // In the future if some LogProjectCacheStarted event is created, move this there to align with evaluation and build execution. _projectFileMap[projectContextId] = projectFile; - // Because the project cache runs in the BuildManager, it makes some sense to associate logging with the in-proc node. - // If a invalid node id is used the messages become deferred in the console logger and spit out at the end. - int nodeId = Scheduler.InProcNodeId; - - return new BuildEventContext(submissionId, nodeId, evaluationId, projectInstanceId, projectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + return parentBuildEventContext + .WithProjectContextId(projectContextId); } /// @@ -470,128 +466,144 @@ public void LogProjectEvaluationFinished( ProcessLoggingEvent(buildEvent); } - /// - /// Logs that a project build has started - /// - /// The event context of the node which is spawning this project. - /// The id of the submission. - /// The id of the project configuration which is about to start - /// BuildEventContext of the project who is requesting "projectFile" to build - /// Project file to build - /// Target names to build - /// Initial property list - /// Initial items list - /// EvaluationId of the project instance - /// The project context id - /// The build event context for the project. - /// parentBuildEventContext is null - /// projectBuildEventContext is null - public BuildEventContext LogProjectStarted( - BuildEventContext nodeBuildEventContext, - int submissionId, - int configurationId, + public void LogProjectStarted(ProjectStartedEventArgs buildEvent) + { + ProcessLoggingEvent(buildEvent); + } + + /// + public ProjectStartedEventArgs CreateProjectStartedForLocalProject( BuildEventContext parentBuildEventContext, + int configurationId, string projectFile, string targetNames, + IDictionary globalProperties, IEnumerable properties, IEnumerable items, - int evaluationId = BuildEventContext.InvalidEvaluationId, - int projectContextId = BuildEventContext.InvalidProjectContextId) + string toolsVersion) { - var args = CreateProjectStarted(nodeBuildEventContext, - submissionId, - configurationId, - parentBuildEventContext, - projectFile, - targetNames, - properties, - items, - evaluationId, - projectContextId); + var projectContextId = GenerateNewProjectContextId(projectFile); + + ErrorUtilities.VerifyThrow(parentBuildEventContext != null, "Need a parentBuildEventContext"); + BuildEventContext projectBuildEventContext = parentBuildEventContext + .WithProjectInstanceId(configurationId) + .WithProjectContextId(projectContextId); - this.LogProjectStarted(args); + var buildEvent = new ProjectStartedEventArgs( + configurationId, + message: null, + helpKeyword: null, + projectFile, + targetNames, + properties, + items, + parentBuildEventContext, + globalProperties, + toolsVersion); + buildEvent.BuildEventContext = projectBuildEventContext; - return args.BuildEventContext; + return buildEvent; } - public void LogProjectStarted(ProjectStartedEventArgs buildEvent) + /// + /// Ensures that the projectContextId is valid and updates the project file map to track which contexts apply to which project files. + /// + /// The project file path to be associated with this project context ID. + /// The project context ID to use (either the provided one or a newly generated one). + private int GenerateNewProjectContextId(string projectFile) { - ProcessLoggingEvent(buildEvent); + var generatedProjectContextId = NextProjectId; + + // PERF: Not using VerifyThrow to avoid boxing of projectBuildEventContext.ProjectContextId in the non-error case. + if (_projectFileMap.ContainsKey(generatedProjectContextId)) + { + ErrorUtilities.ThrowInternalError("ContextID {0} for project {1} should not already be in the ID-to-file mapping!", generatedProjectContextId, projectFile); + } + + _projectFileMap[generatedProjectContextId] = projectFile; + return generatedProjectContextId; } - public ProjectStartedEventArgs CreateProjectStarted( - BuildEventContext nodeBuildEventContext, - int submissionId, - int configurationId, - BuildEventContext parentBuildEventContext, - string projectFile, - string targetNames, - IEnumerable properties, - IEnumerable items, - int evaluationId = BuildEventContext.InvalidEvaluationId, - int projectContextId = BuildEventContext.InvalidProjectContextId) + /// + /// Validates that a preexisting projectContextId is valid and updates the project file map to track which contexts apply to which project files. + /// + /// The remote node evaluation context containing the project context ID to validate. + /// The project file path to be associated with this project context ID. + /// The node ID of the current node - used to validate that only the in-proc scheduler node is re-using cached project context IDs. + /// Either the same context, if the projectContextId exists in the map already, or a new context with a generated projectContextId if it did not. + private BuildEventContext ValidatePreexistingProjectContextId(BuildEventContext remoteNodeEvaluationContext, string projectFile, int currentNodeId) { - ErrorUtilities.VerifyThrow(nodeBuildEventContext != null, "Need a nodeBuildEventContext"); - - if (projectContextId == BuildEventContext.InvalidProjectContextId) + if (remoteNodeEvaluationContext.ProjectContextId == BuildEventContext.InvalidProjectContextId) { - projectContextId = NextProjectId; + // No projectContextId was provided, so generate a new one to represent this invocation of the project + int newProjectContextId = GenerateNewProjectContextId(projectFile); + return remoteNodeEvaluationContext.WithProjectContextId(newProjectContextId); + } - // PERF: Not using VerifyThrow to avoid boxing of projectBuildEventContext.ProjectContextId in the non-error case. - if (_projectFileMap.ContainsKey(projectContextId)) + // A projectContextId was provided, so use it with some sanity checks + else if (_projectFileMap.TryGetValue(remoteNodeEvaluationContext.ProjectContextId, out string existingProjectFile)) + { + if (!projectFile.Equals(existingProjectFile, StringComparison.OrdinalIgnoreCase)) { - ErrorUtilities.ThrowInternalError("ContextID {0} for project {1} should not already be in the ID-to-file mapping!", projectContextId, projectFile); + ErrorUtilities.ThrowInternalError("ContextID {0} was already in the ID-to-project file mapping but the project file {1} did not match the provided one {2}!", remoteNodeEvaluationContext.ProjectContextId, existingProjectFile, projectFile); } - - _projectFileMap[projectContextId] = projectFile; + return remoteNodeEvaluationContext; } else { - // A projectContextId was provided, so use it with some sanity checks - if (_projectFileMap.TryGetValue(projectContextId, out string existingProjectFile)) + // Currently, an existing projectContextId can only be provided in the project cache scenario, which runs on the in-proc node. + // If there was a cache miss and the build was scheduled on a worker node, it may not have seen this projectContextId yet. + // So we only need this sanity check for the in-proc node. + if (currentNodeId == Scheduler.InProcNodeId) { - if (!projectFile.Equals(existingProjectFile, StringComparison.OrdinalIgnoreCase)) - { - ErrorUtilities.ThrowInternalError("ContextID {0} was already in the ID-to-project file mapping but the project file {1} did not match the provided one {2}!", projectContextId, existingProjectFile, projectFile); - } + ErrorUtilities.ThrowInternalError("ContextID {0} should have been in the ID-to-project file mapping but wasn't!", remoteNodeEvaluationContext.ProjectContextId); } - else - { - // Currently, an existing projectContextId can only be provided in the project cache scenario, which runs on the in-proc node. - // If there was a cache miss and the build was scheduled on a worker node, it may not have seen this projectContextId yet. - // So we only need this sanity check for the in-proc node. - if (nodeBuildEventContext.NodeId == Scheduler.InProcNodeId) - { - ErrorUtilities.ThrowInternalError("ContextID {0} should have been in the ID-to-project file mapping but wasn't!", projectContextId); - } - - _projectFileMap[projectContextId] = projectFile; - } - } - - BuildEventContext projectBuildEventContext = new BuildEventContext(submissionId, nodeBuildEventContext.NodeId, evaluationId, configurationId, projectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); - ErrorUtilities.VerifyThrow(parentBuildEventContext != null, "Need a parentBuildEventContext"); - - ErrorUtilities.VerifyThrow(_configCache.Value.HasConfiguration(configurationId), "Cannot find the project configuration while injecting non-serialized data from out-of-proc node."); - var buildRequestConfiguration = _configCache.Value[configurationId]; + _projectFileMap[remoteNodeEvaluationContext.ProjectContextId] = projectFile; + return remoteNodeEvaluationContext; + } + } - // Always log GlobalProperties on ProjectStarted - // See https://github.com/dotnet/msbuild/issues/6341 for details - IDictionary globalProperties = buildRequestConfiguration.GlobalProperties.ToDictionary(); + /// + public ProjectStartedEventArgs CreateProjectStartedForCachedProject( + BuildEventContext currentNodeBuildEventContext, + BuildEventContext remoteNodeEvaluationBuildEventContext, + BuildEventContext parentBuildEventContext, + IDictionary globalProperties, + string projectFile, + string targetNames, + string toolsVersion) + { + Debug.Assert(currentNodeBuildEventContext.NodeId == Scheduler.VirtualNode, "Cached project build events should only be logged from the scheduler virtual node."); - var buildEvent = new ProjectStartedEventArgs( - configurationId, - message: null, - helpKeyword: null, - projectFile, - targetNames, - properties, - items, - parentBuildEventContext, - globalProperties, - buildRequestConfiguration.ToolsVersion); - buildEvent.BuildEventContext = projectBuildEventContext; + BuildEventContext validatedRemoteNodeEvaluationBuildContext = ValidatePreexistingProjectContextId( + remoteNodeEvaluationBuildEventContext, + projectFile, + currentNodeBuildEventContext.NodeId); + + int configurationId = remoteNodeEvaluationBuildEventContext.ProjectInstanceId; + + // we need to be a valid BuildEventContext for a ProjectLoggingContext out of this, so we need to make sure + // we have ProjectContextId set. + BuildEventContextBuilder thisEventBuildEventContext = parentBuildEventContext + .WithProjectInstanceId(configurationId) + .WithProjectContextId(validatedRemoteNodeEvaluationBuildContext.ProjectContextId); + + ProjectStartedEventArgs buildEvent = new( + projectId: configurationId, + message: null, + helpKeyword: null, + projectFile: projectFile, + targetNames: targetNames, + properties: null, // Do not log properties on cached project builds - callers must look up from the 'real' ProjectStartedEventArgs if needed + items: null, // Do not log items on cached project builds - callers must look up from the 'real' ProjectStartedEventArgs if needed + parentBuildEventContext: parentBuildEventContext, + globalProperties: globalProperties, + toolsVersion: toolsVersion, + originalBuildEventContext: validatedRemoteNodeEvaluationBuildContext) + { + BuildEventContext = thisEventBuildEventContext, + }; return buildEvent; } @@ -641,13 +653,7 @@ public void LogProjectFinished(BuildEventContext projectBuildEventContext, strin public BuildEventContext LogTargetStarted(BuildEventContext projectBuildEventContext, string targetName, string projectFile, string projectFileOfTargetElement, string parentTargetName, TargetBuiltReason buildReason) { ErrorUtilities.VerifyThrow(projectBuildEventContext != null, "projectBuildEventContext is null"); - BuildEventContext targetBuildEventContext = new BuildEventContext( - projectBuildEventContext.SubmissionId, - projectBuildEventContext.NodeId, - projectBuildEventContext.ProjectInstanceId, - projectBuildEventContext.ProjectContextId, - NextTargetId, - BuildEventContext.InvalidTaskId); + BuildEventContext targetBuildEventContext = projectBuildEventContext.WithTargetId(NextTargetId); if (!OnlyLogCriticalEvents) { @@ -738,13 +744,7 @@ public void LogTaskStarted(BuildEventContext taskBuildEventContext, string taskN public BuildEventContext LogTaskStarted2(BuildEventContext targetBuildEventContext, string taskName, string projectFile, string projectFileOfTaskNode, int line, int column, string taskAssemblyLocation) { ErrorUtilities.VerifyThrow(targetBuildEventContext != null, "targetBuildEventContext is null"); - BuildEventContext taskBuildEventContext = new BuildEventContext( - targetBuildEventContext.SubmissionId, - targetBuildEventContext.NodeId, - targetBuildEventContext.ProjectInstanceId, - targetBuildEventContext.ProjectContextId, - targetBuildEventContext.TargetId, - NextTaskId); + BuildEventContext taskBuildEventContext = targetBuildEventContext.WithTaskId(NextTaskId); if (!OnlyLogCriticalEvents) { diff --git a/src/Build/BackEnd/Components/Logging/NodeLoggingContext.cs b/src/Build/BackEnd/Components/Logging/NodeLoggingContext.cs index e03c8ed13e7..608f946f3fa 100644 --- a/src/Build/BackEnd/Components/Logging/NodeLoggingContext.cs +++ b/src/Build/BackEnd/Components/Logging/NodeLoggingContext.cs @@ -18,10 +18,11 @@ internal class NodeLoggingContext : BuildLoggingContext /// Used to create the initial, base logging context for the node. /// /// The logging service to use. + /// The parent build event context to associate this node logging context with /// The /// true if this is an in-process node, otherwise false. - internal NodeLoggingContext(ILoggingService loggingService, int nodeId, bool inProcNode) - : base(loggingService, new BuildEventContext(nodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId), inProcNode) + internal NodeLoggingContext(ILoggingService loggingService, BuildEventContext parentContext, int nodeId, bool inProcNode) + : base(loggingService, parentContext.WithNodeId(nodeId), inProcNode) { ErrorUtilities.VerifyThrow(nodeId != BuildEventContext.InvalidNodeId, "Should not ever be given an invalid NodeId"); @@ -66,25 +67,20 @@ internal ProjectLoggingContext LogProjectStarted(BuildRequestEntry requestEntry) internal (ProjectStartedEventArgs, ProjectLoggingContext) CreateProjectLoggingContext(BuildRequestEntry requestEntry) { ErrorUtilities.VerifyThrow(this.IsValid, "Build not started."); - return ProjectLoggingContext.CreateLoggingContext(this, requestEntry); + return ProjectLoggingContext.CreateForLocalBuild(this, requestEntry); } /// - /// Log that a project has started if it is serviced from the cache + /// Log that a project has started if it is serviced from the cache. + /// Uses cache-specific pathway that immediately logs ProjectStarted with minimal data. /// /// The build request. /// The configuration used to build the request. - /// The BuildEventContext to use for this project. - internal ProjectLoggingContext LogProjectStarted(BuildRequest request, BuildRequestConfiguration configuration) + /// The ProjectLoggingContext for this cached project. + internal ProjectLoggingContext LogProjectStartedFromCache(BuildRequest request, BuildRequestConfiguration configuration) { ErrorUtilities.VerifyThrow(this.IsValid, "Build not started."); - - // If we can retrieve the evaluationId from the project, do so. Don't if it's not available or - // if we'd have to retrieve it from the cache in order to access it. - // Order is important here because the Project getter will throw if IsCached. - int evaluationId = (configuration != null && !configuration.IsCached && configuration.Project != null) ? configuration.Project.EvaluationId : BuildEventContext.InvalidEvaluationId; - - return new ProjectLoggingContext(this, request, configuration.ProjectFullPath, configuration.ToolsVersion, evaluationId); + return ProjectLoggingContext.CreateForCacheBuild(this, request, configuration); } /// @@ -93,7 +89,7 @@ internal ProjectLoggingContext LogProjectStarted(BuildRequest request, BuildRequ /// internal void LogRequestHandledFromCache(BuildRequest request, BuildRequestConfiguration configuration, BuildResult result) { - ProjectLoggingContext projectLoggingContext = LogProjectStarted(request, configuration); + ProjectLoggingContext projectLoggingContext = LogProjectStartedFromCache(request, configuration); // When pulling a request from the cache, we want to make sure we log a target skipped event for any targets which // were used to build the request including default and initial targets. diff --git a/src/Build/BackEnd/Components/Logging/ProjectLoggingContext.cs b/src/Build/BackEnd/Components/Logging/ProjectLoggingContext.cs index 6f467e25d9b..4f867503883 100644 --- a/src/Build/BackEnd/Components/Logging/ProjectLoggingContext.cs +++ b/src/Build/BackEnd/Components/Logging/ProjectLoggingContext.cs @@ -3,7 +3,6 @@ using System.Collections; using System.Collections.Generic; -using System.Linq; using Microsoft.Build.Collections; using Microsoft.Build.Execution; using Microsoft.Build.Framework; @@ -31,231 +30,162 @@ internal class ProjectLoggingContext : BuildLoggingContext private readonly ProjectTelemetry _projectTelemetry = new ProjectTelemetry(); /// - /// Constructs a project logging context. + /// Private constructor - use factory methods instead. /// - internal ProjectLoggingContext(NodeLoggingContext nodeLoggingContext, BuildRequestEntry requestEntry) - : this - ( - nodeLoggingContext, - requestEntry.Request.SubmissionId, - requestEntry.Request.ConfigurationId, - requestEntry.RequestConfiguration.ProjectFullPath, - requestEntry.Request.Targets, - requestEntry.RequestConfiguration.ToolsVersion, - requestEntry.RequestConfiguration.Project.PropertiesToBuildWith, - requestEntry.RequestConfiguration.Project.ItemsToBuildWith, - requestEntry.Request.ParentBuildEventContext, - requestEntry.RequestConfiguration.Project.EvaluationId, - requestEntry.Request.ProjectContextId) - { - } - - /// - /// Constructs a project logging context. - /// - internal ProjectLoggingContext( + private ProjectLoggingContext( NodeLoggingContext nodeLoggingContext, - BuildRequest request, + BuildEventContext buildEventContext, string projectFullPath, - string toolsVersion, - int evaluationId = BuildEventContext.InvalidEvaluationId) - : this - ( - nodeLoggingContext, - request.SubmissionId, - request.ConfigurationId, - projectFullPath, - request.Targets, - toolsVersion, - projectProperties: null, - projectItems: null, - request.ParentBuildEventContext, - evaluationId, - request.ProjectContextId) + string toolsVersion) + : base(nodeLoggingContext, buildEventContext) { + _projectFullPath = projectFullPath; + + // No need to log a redundant message in the common case + if (toolsVersion != "Current") + { + LoggingService.LogComment(BuildEventContext, MessageImportance.Low, "ToolsVersionInEffectForBuild", toolsVersion); + } + + IsValid = true; } /// - /// Creates ProjectLoggingContext, without logging ProjectStartedEventArgs as a side effect. - /// The ProjectStartedEventArgs is returned as well - so that it can be later logged explicitly + /// Creates ProjectLoggingContext for real local project builds. + /// Returns both ProjectStartedEventArgs (for caller to configure) and ProjectLoggingContext. + /// Does NOT log ProjectStarted immediately. /// - public static (ProjectStartedEventArgs, ProjectLoggingContext) CreateLoggingContext( + public static (ProjectStartedEventArgs, ProjectLoggingContext) CreateForLocalBuild( NodeLoggingContext nodeLoggingContext, BuildRequestEntry requestEntry) { - ProjectStartedEventArgs args = CreateProjectStarted( - nodeLoggingContext, - requestEntry.Request.SubmissionId, - requestEntry.Request.ConfigurationId, + IEnumerable properties = GetProjectProperties( + nodeLoggingContext.LoggingService, + requestEntry.RequestConfiguration.Project?.PropertiesToBuildWith); + IEnumerable items = GetProjectItems( + nodeLoggingContext.LoggingService, + requestEntry.RequestConfiguration.Project?.ItemsToBuildWith); + + IDictionary globalProperties = requestEntry.RequestConfiguration.GlobalProperties.ToDictionary(); + + BuildEventContext parentBuildEventContext = requestEntry.Request.ParentBuildEventContext == BuildEventContext.Invalid + ? nodeLoggingContext.BuildEventContext.WithEvaluationId(requestEntry.RequestConfiguration.ProjectEvaluationId).WithSubmissionId(requestEntry.Request.SubmissionId) + : requestEntry.Request.ParentBuildEventContext; + + ProjectStartedEventArgs args = nodeLoggingContext.LoggingService.CreateProjectStartedForLocalProject( + parentBuildEventContext, + requestEntry.RequestConfiguration.ConfigurationId, requestEntry.RequestConfiguration.ProjectFullPath, - requestEntry.Request.Targets, - requestEntry.RequestConfiguration.ToolsVersion, - requestEntry.RequestConfiguration.Project.PropertiesToBuildWith, - requestEntry.RequestConfiguration.Project.ItemsToBuildWith, - requestEntry.Request.ParentBuildEventContext, - requestEntry.RequestConfiguration.Project.EvaluationId, - requestEntry.Request.ProjectContextId); - - return (args, new ProjectLoggingContext(nodeLoggingContext, args)); - } - - private ProjectLoggingContext( - NodeLoggingContext nodeLoggingContext, - ProjectStartedEventArgs projectStarted) - : base(nodeLoggingContext, projectStarted.BuildEventContext) - { - _projectFullPath = projectStarted.ProjectFile; + string.Join(";", requestEntry.Request.Targets), + globalProperties, + properties, + items, + requestEntry.RequestConfiguration.ToolsVersion); - // No need to log a redundant message in the common case - if (projectStarted.ToolsVersion != "Current") - { - LoggingService.LogComment(this.BuildEventContext, MessageImportance.Low, "ToolsVersionInEffectForBuild", projectStarted.ToolsVersion); - } + var context = new ProjectLoggingContext( + nodeLoggingContext, + args.BuildEventContext, + args.ProjectFile, + args.ToolsVersion); - this.IsValid = true; + return (args, context); } /// - /// Constructs a project logging contexts. + /// Creates ProjectLoggingContext for cached project builds. + /// Immediately logs ProjectStarted event with minimal data. /// - private ProjectLoggingContext( + public static ProjectLoggingContext CreateForCacheBuild( NodeLoggingContext nodeLoggingContext, - int submissionId, - int configurationId, - string projectFullPath, - List targets, - string toolsVersion, - PropertyDictionary projectProperties, - IItemDictionary projectItems, - BuildEventContext parentBuildEventContext, - int evaluationId, - int projectContextId) - : base(nodeLoggingContext, - CreateInitialContext(nodeLoggingContext, - submissionId, - configurationId, - projectFullPath, - targets, - toolsVersion, - projectProperties, - projectItems, - parentBuildEventContext, - evaluationId, - projectContextId)) + BuildRequest request, + BuildRequestConfiguration configuration) { - _projectFullPath = projectFullPath; - - // No need to log a redundant message in the common case - if (toolsVersion != "Current") - { - LoggingService.LogComment(this.BuildEventContext, MessageImportance.Low, "ToolsVersionInEffectForBuild", toolsVersion); - } + BuildEventContext buildEventContext = CreateAndLogProjectStartedForCache( + nodeLoggingContext, + request, + configuration); - this.IsValid = true; + return new ProjectLoggingContext( + nodeLoggingContext, + buildEventContext, + configuration.ProjectFullPath, + configuration.ToolsVersion); } - private static BuildEventContext CreateInitialContext( + /// + /// Creates BuildEventContext and logs ProjectStarted for cache scenarios. + /// + private static BuildEventContext CreateAndLogProjectStartedForCache( NodeLoggingContext nodeLoggingContext, - int submissionId, - int configurationId, - string projectFullPath, - List targets, - string toolsVersion, - PropertyDictionary projectProperties, - IItemDictionary projectItems, - BuildEventContext parentBuildEventContext, - int evaluationId, - int projectContextId) + BuildRequest newRequestThatWasServedFromCache, + BuildRequestConfiguration configuration) { - ProjectStartedEventArgs args = CreateProjectStarted( - nodeLoggingContext, - submissionId, - configurationId, - projectFullPath, - targets, - toolsVersion, - projectProperties, - projectItems, - parentBuildEventContext, - evaluationId, - projectContextId); + // Create a remote node evaluation context with the original evaluation ID + BuildEventContext remoteNodeEvaluationBuildEventContext = BuildEventContext.CreateInitial( + configuration.ResultsNodeId, // Use the node that originally built this project configuration + newRequestThatWasServedFromCache.SubmissionId) + .WithEvaluationId(configuration.ProjectEvaluationId) + .WithProjectInstanceId(configuration.ConfigurationId); + // we don't know the projectContextId of the remote eval, so we don't set it at all. + // the new request _does not have_ a valid projectContextId to go off of. + + IDictionary globalProperties = configuration.GlobalProperties.ToDictionary(); + + ProjectStartedEventArgs args = nodeLoggingContext.LoggingService.CreateProjectStartedForCachedProject( + nodeLoggingContext.BuildEventContext, // Current node context + remoteNodeEvaluationBuildEventContext, // Original remote node context + newRequestThatWasServedFromCache.ParentBuildEventContext, + globalProperties, + configuration.ProjectFullPath, + string.Join(";", newRequestThatWasServedFromCache.Targets), + configuration.ToolsVersion); nodeLoggingContext.LoggingService.LogProjectStarted(args); - return args.BuildEventContext; } - private static ProjectStartedEventArgs CreateProjectStarted( - NodeLoggingContext nodeLoggingContext, - int submissionId, - int configurationId, - string projectFullPath, - List targets, - string toolsVersion, - PropertyDictionary projectProperties, - IItemDictionary projectItems, - BuildEventContext parentBuildEventContext, - int evaluationId, - int projectContextId) + /// + /// Gets project properties for logging if appropriate - as determined by the logging service. + /// + private static IEnumerable GetProjectProperties( + ILoggingService loggingService, + PropertyDictionary projectProperties) { - IEnumerable properties = null; - IEnumerable items = null; - - ILoggingService loggingService = nodeLoggingContext.LoggingService; - - string[] propertiesToSerialize = loggingService.PropertiesToSerialize; - - // If we are only logging critical events lets not pass back the items or properties - if (!loggingService.OnlyLogCriticalEvents && - loggingService.IncludeEvaluationPropertiesAndItemsInProjectStartedEvent && - (!loggingService.RunningOnRemoteNode || loggingService.SerializeAllProperties)) + if (projectProperties == null || + loggingService.OnlyLogCriticalEvents || + !loggingService.IncludeEvaluationPropertiesAndItemsInProjectStartedEvent || + (loggingService.RunningOnRemoteNode && !loggingService.SerializeAllProperties)) { - if (projectProperties is null) - { - properties = []; - } - else if (Traits.LogAllEnvironmentVariables) - { - properties = projectProperties.GetCopyOnReadEnumerable(property => new DictionaryEntry(property.Name, property.EvaluatedValue)); - } - else - { - properties = projectProperties.Filter(p => p is not EnvironmentDerivedProjectPropertyInstance || EnvironmentUtilities.IsWellKnownEnvironmentDerivedProperty(p.Name), p => new DictionaryEntry(p.Name, p.EvaluatedValue)); - } - - items = projectItems?.GetCopyOnReadEnumerable(item => new DictionaryEntry(item.ItemType, new TaskItem(item))) ?? []; + return null; } - if (projectProperties != null && - loggingService.IncludeEvaluationPropertiesAndItemsInProjectStartedEvent && - propertiesToSerialize?.Length > 0 && - !loggingService.SerializeAllProperties) + if (Traits.LogAllEnvironmentVariables) + { + return projectProperties.GetCopyOnReadEnumerable(property => new DictionaryEntry(property.Name, property.EvaluatedValue)); + } + else { - PropertyDictionary projectPropertiesToSerialize = new PropertyDictionary(); - foreach (string propertyToGet in propertiesToSerialize) - { - ProjectPropertyInstance instance = projectProperties[propertyToGet]; - { - if (instance != null) - { - projectPropertiesToSerialize.Set(instance); - } - } - } + return projectProperties.Filter( + p => p is not EnvironmentDerivedProjectPropertyInstance || EnvironmentUtilities.IsWellKnownEnvironmentDerivedProperty(p.Name), + p => new DictionaryEntry(p.Name, p.EvaluatedValue)); + } + } - properties = projectPropertiesToSerialize.Select((ProjectPropertyInstance property) => new DictionaryEntry(property.Name, property.EvaluatedValue)); + /// + /// Gets project items for logging if appropriate - as determined by the logging service. + /// + private static IEnumerable GetProjectItems( + ILoggingService loggingService, + IItemDictionary projectItems) + { + if (projectItems == null || + loggingService.OnlyLogCriticalEvents || + !loggingService.IncludeEvaluationPropertiesAndItemsInProjectStartedEvent || + (loggingService.RunningOnRemoteNode && !loggingService.SerializeAllProperties)) + { + return null; } - return loggingService.CreateProjectStarted( - nodeLoggingContext.BuildEventContext, - submissionId, - configurationId, - parentBuildEventContext, - projectFullPath, - string.Join(";", targets), - properties, - items, - evaluationId, - projectContextId); + return projectItems.GetCopyOnReadEnumerable(item => new DictionaryEntry(item.ItemType, new TaskItem(item))); } /// @@ -269,9 +199,9 @@ private static ProjectStartedEventArgs CreateProjectStarted( /// Did the build succeede or not internal void LogProjectFinished(bool success) { - ErrorUtilities.VerifyThrow(this.IsValid, "invalid"); + ErrorUtilities.VerifyThrow(IsValid, "invalid"); LoggingService.LogProjectFinished(BuildEventContext, _projectFullPath, success); - this.IsValid = false; + IsValid = false; } /// @@ -279,7 +209,7 @@ internal void LogProjectFinished(bool success) /// internal TargetLoggingContext LogTargetBatchStarted(string projectFullPath, ProjectTargetInstance target, string parentTargetName, TargetBuiltReason buildReason) { - ErrorUtilities.VerifyThrow(this.IsValid, "invalid"); + ErrorUtilities.VerifyThrow(IsValid, "invalid"); return new TargetLoggingContext(this, projectFullPath, target, parentTargetName, buildReason); } } diff --git a/src/Build/BackEnd/Components/ProjectCache/ProjectCacheService.cs b/src/Build/BackEnd/Components/ProjectCache/ProjectCacheService.cs index 97f373790bd..51b128919c3 100644 --- a/src/Build/BackEnd/Components/ProjectCache/ProjectCacheService.cs +++ b/src/Build/BackEnd/Components/ProjectCache/ProjectCacheService.cs @@ -533,11 +533,7 @@ public void PostCacheRequest(CacheRequest cacheRequest, CancellationToken cancel BuildRequestData buildRequest = new BuildRequestData( cacheRequest.Configuration.Project, cacheRequest.Submission.BuildRequestData?.TargetNames.ToArray() ?? []); - BuildEventContext buildEventContext = _loggingService.CreateProjectCacheBuildEventContext( - cacheRequest.Submission.SubmissionId, - evaluationId: cacheRequest.Configuration.Project.EvaluationId, - projectInstanceId: cacheRequest.Configuration.ConfigurationId, - projectFile: cacheRequest.Configuration.Project.FullPath); + BuildEventContext buildEventContext = _loggingService.CreateProjectCacheBuildEventContext(GetCacheRequestBuildEventContext(cacheRequest), projectFile: cacheRequest.Configuration.Project.FullPath); CacheResult cacheResult; try @@ -562,11 +558,11 @@ void EvaluateProjectIfNecessary(BuildSubmission submission, BuildRequestConfigur { if (!configuration.IsLoaded) { + BuildEventContext parentBuildContext = submission.BuildEventContext; configuration.LoadProjectIntoConfiguration( _buildManager, submission.BuildRequestData!.Flags, - submission.SubmissionId, - Scheduler.InProcNodeId); + parentBuildContext); // If we're taking the time to evaluate, avoid having other nodes to repeat the same evaluation. // Based on the assumption that ProjectInstance serialization is faster than evaluating from scratch. @@ -576,6 +572,8 @@ void EvaluateProjectIfNecessary(BuildSubmission submission, BuildRequestConfigur } } + private BuildEventContext GetCacheRequestBuildEventContext(CacheRequest cacheRequest) => Scheduler.s_schedulerNodeBuildEventContext.WithEvaluationId(cacheRequest.Configuration.ProjectEvaluationId).WithProjectInstanceId(cacheRequest.Configuration.ConfigurationId); + private async ValueTask GetCacheResultAsync(BuildRequestData buildRequest, BuildRequestConfiguration buildRequestConfiguration, BuildEventContext buildEventContext, CancellationToken cancellationToken) { ErrorUtilities.VerifyThrowInternalNull(buildRequest.ProjectInstance, nameof(buildRequest.ProjectInstance)); diff --git a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs index d99df97edb7..920a4225479 100644 --- a/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs +++ b/src/Build/BackEnd/Components/RequestBuilder/RequestBuilder.cs @@ -865,6 +865,8 @@ private async Task RequestThreadProc(bool setThreadParameters) { ErrorUtilities.VerifyThrow(result == null, "Result already set when exception was thrown."); result = new BuildResult(_requestEntry.Request, thrownException); + // Populate the evaluation ID from the configuration for sending to the central node + result.EvaluationId = _requestEntry.RequestConfiguration.ProjectEvaluationId; } ReportResultAndCleanUp(result); @@ -1019,7 +1021,10 @@ private BuildResult[] GetResultsForContinuation(FullyQualifiedBuildRequest[] req results = new Dictionary(); for (int i = 0; i < requests.Length; i++) { - results[i] = new BuildResult(new BuildRequest(), new BuildAbortedException()); + var result = new BuildResult(new BuildRequest(), new BuildAbortedException()); + // Populate the evaluation ID from the configuration for sending to the central node + result.EvaluationId = _requestEntry.RequestConfiguration.ProjectEvaluationId; + results[i] = result; } } @@ -1119,8 +1124,7 @@ private async Task BuildProject() _requestEntry.RequestConfiguration.LoadProjectIntoConfiguration( _componentHost, RequestEntry.Request.BuildRequestDataFlags, - RequestEntry.Request.SubmissionId, - _nodeLoggingContext.BuildEventContext.NodeId); + _nodeLoggingContext.BuildEventContext.WithSubmissionId(RequestEntry.Request.SubmissionId)); } // Set SDK-resolved environment variables if they haven't been set yet for this configuration @@ -1140,13 +1144,8 @@ private async Task BuildProject() } catch { - // make sure that any errors thrown by a child project are logged in the context of their parent project: create a temporary projectLoggingContext - _projectLoggingContext = new ProjectLoggingContext( - _nodeLoggingContext, - _requestEntry.Request, - _requestEntry.RequestConfiguration.ProjectFullPath, - _requestEntry.RequestConfiguration.ToolsVersion); - + // make sure that any errors thrown by a child project are logged in the context of their parent project + _projectLoggingContext = _nodeLoggingContext.LogProjectStarted(_requestEntry); throw; } finally @@ -1212,6 +1211,9 @@ private async Task BuildProject() BuildResult result = await _targetBuilder.BuildTargets(_projectLoggingContext, _requestEntry, this, allTargets, _requestEntry.RequestConfiguration.BaseLookup, _cancellationTokenSource.Token); + // Populate the evaluation ID from the configuration for sending to the central node + result.EvaluationId = _requestEntry.RequestConfiguration.ProjectEvaluationId; + UpdateStatisticsPostBuild(); result = _requestEntry.Request.ProxyTargets == null diff --git a/src/Build/BackEnd/Components/Scheduler/Scheduler.cs b/src/Build/BackEnd/Components/Scheduler/Scheduler.cs index 402ab04ea5d..bf9bed4a57a 100644 --- a/src/Build/BackEnd/Components/Scheduler/Scheduler.cs +++ b/src/Build/BackEnd/Components/Scheduler/Scheduler.cs @@ -42,7 +42,7 @@ internal class Scheduler : IScheduler internal const int ResultsTransferredId = -2; /// - /// The in-proc node id + /// The in-proc node id for the worker node that performs work the scheduler itself assigns on the same 'logical' node. /// internal const int InProcNodeId = 1; @@ -58,6 +58,16 @@ internal class Scheduler : IScheduler /// private const double DefaultCustomSchedulerForSQLConfigurationLimitMultiplier = 1.1; + /// + /// The build event context for the scheduler node - can be used as a 'root' context for contexts' derived or needed when running scheduler operations + /// + internal static BuildEventContext s_schedulerNodeBuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, VirtualNode); + + /// + /// The build event context for the in-proc node - the worker node that executes on the same 'logical' node as the scheduler + /// + internal static BuildEventContext s_schedulerInProcNodeBuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, InProcNodeId); + #region Scheduler Data /// @@ -600,7 +610,7 @@ public void Reset() public void WriteDetailedSummary(int submissionId) { ILoggingService loggingService = _componentHost.LoggingService; - BuildEventContext context = new BuildEventContext(submissionId, 0, 0, 0, 0, 0); + BuildEventContext context = s_schedulerNodeBuildEventContext.WithSubmissionId(submissionId); loggingService.LogComment(context, MessageImportance.Normal, "DetailedSummaryHeader"); foreach (SchedulableRequest request in _schedulingData.GetRequestsByHierarchy(null)) @@ -675,7 +685,7 @@ public void InitializeComponent(IBuildComponentHost host) _componentHost = host; _resultsCache = (IResultsCache)_componentHost.GetComponent(BuildComponentType.ResultsCache); _configCache = (IConfigCache)_componentHost.GetComponent(BuildComponentType.ConfigCache); - _inprocNodeContext = new NodeLoggingContext(_componentHost.LoggingService, InProcNodeId, true); + _inprocNodeContext = new NodeLoggingContext(_componentHost.LoggingService, s_schedulerNodeBuildEventContext, InProcNodeId, true); } /// @@ -2037,13 +2047,7 @@ private bool CheckIfCacheMissOnReferencedProjectIsAllowedAndErrorIfNot(int nodeF string projectFullPath = _configCache[request.ConfigurationId].ProjectFullPath; string parentProjectFullPath = GetParentConfigurationId(request, _configCache, _schedulingData).ProjectFullPath; _componentHost.LoggingService.LogComment( - new BuildEventContext( - request.SubmissionId, - 1, - BuildEventContext.InvalidProjectInstanceId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidTaskId), + s_schedulerNodeBuildEventContext.WithSubmissionId(request.SubmissionId), MessageImportance.Normal, "SkippedConstraintsOnRequest", parentProjectFullPath, @@ -2198,8 +2202,7 @@ private ScheduleResponse GetResponseForResult(int parentRequestNode, BuildReques private void LogRequestHandledFromCache(BuildRequest request, BuildResult result) { BuildRequestConfiguration configuration = _configCache[request.ConfigurationId]; - int nodeId = _schedulingData.GetAssignedNodeForRequestConfiguration(request.ConfigurationId); - NodeLoggingContext nodeContext = new NodeLoggingContext(_componentHost.LoggingService, nodeId, true); + NodeLoggingContext nodeContext = new NodeLoggingContext(_componentHost.LoggingService, s_schedulerNodeBuildEventContext, VirtualNode, true); nodeContext.LogRequestHandledFromCache(request, configuration, result); TraceScheduler( @@ -2950,7 +2953,7 @@ private void DumpRequestSpec(StreamWriter file, SchedulableRequest request, int private void WriteSchedulingPlan(int submissionId) { SchedulingPlan plan = new SchedulingPlan(_configCache, _schedulingData); - plan.WritePlan(submissionId, _componentHost.LoggingService, new BuildEventContext(submissionId, 0, 0, 0, 0, 0)); + plan.WritePlan(submissionId, _componentHost.LoggingService, s_schedulerNodeBuildEventContext.WithSubmissionId(submissionId)); } /// @@ -2959,7 +2962,7 @@ private void WriteSchedulingPlan(int submissionId) private void ReadSchedulingPlan(int submissionId) { _schedulingPlan = new SchedulingPlan(_configCache, _schedulingData); - _schedulingPlan.ReadPlan(submissionId, _componentHost.LoggingService, new BuildEventContext(submissionId, 0, 0, 0, 0, 0)); + _schedulingPlan.ReadPlan(submissionId, _componentHost.LoggingService, s_schedulerNodeBuildEventContext.WithSubmissionId(submissionId)); } #endregion diff --git a/src/Build/BackEnd/Node/InProcNode.cs b/src/Build/BackEnd/Node/InProcNode.cs index b86e29247f3..a86ba2a1579 100644 --- a/src/Build/BackEnd/Node/InProcNode.cs +++ b/src/Build/BackEnd/Node/InProcNode.cs @@ -38,6 +38,11 @@ internal class InProcNode : INode, INodePacketFactory /// private string _savedCurrentDirectory; + /// + /// The build event context for this node - will usually only have the node id set. + /// + private BuildEventContext _buildEventContext; + /// /// The node logging context. /// @@ -502,8 +507,10 @@ private void HandleNodeConfiguration(NodeConfiguration configuration) ILoggingService loggingService = _componentHost.LoggingService; loggingService.OnLoggingThreadException += OnLoggingThreadException; + _buildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithNodeId(configuration.NodeId); + // Now prep the buildRequestEngine for the build. - _loggingContext = new NodeLoggingContext(loggingService, configuration.NodeId, true /* inProcNode */); + _loggingContext = new NodeLoggingContext(loggingService, _buildEventContext, configuration.NodeId, true /* inProcNode */); _buildRequestEngine.OnEngineException += _engineExceptionEventHandler; _buildRequestEngine.OnNewConfigurationRequest += _newConfigurationRequestEventHandler; diff --git a/src/Build/BackEnd/Node/OutOfProcNode.cs b/src/Build/BackEnd/Node/OutOfProcNode.cs index 7225c1a9988..571491af7d8 100644 --- a/src/Build/BackEnd/Node/OutOfProcNode.cs +++ b/src/Build/BackEnd/Node/OutOfProcNode.cs @@ -65,6 +65,7 @@ public class OutOfProcNode : INode, IBuildComponentHost, INodePacketFactory, INo /// private BuildParameters _buildParameters; + /// /// The logging service. /// @@ -100,6 +101,11 @@ public class OutOfProcNode : INode, IBuildComponentHost, INodePacketFactory, INo /// private NodeConfiguration _currentConfiguration; + /// + /// The build event context for this node, will usually only have the node ID set. + /// + private BuildEventContext _buildEventContext; + /// /// The queue of packets we have received but which have not yet been processed. /// @@ -845,8 +851,9 @@ private void HandleNodeConfiguration(NodeConfiguration configuration) _loggingService.SerializeAllProperties = false; } + _buildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithNodeId(configuration.NodeId); // Now prep the buildRequestEngine for the build. - _loggingContext = new NodeLoggingContext(_loggingService, configuration.NodeId, false /* inProcNode */); + _loggingContext = new NodeLoggingContext(_loggingService, _buildEventContext, configuration.NodeId, false /* inProcNode */); if (_shutdownException != null) { diff --git a/src/Build/BackEnd/Shared/BuildRequestConfiguration.cs b/src/Build/BackEnd/Shared/BuildRequestConfiguration.cs index 2d40523d648..114b6f8bb7a 100644 --- a/src/Build/BackEnd/Shared/BuildRequestConfiguration.cs +++ b/src/Build/BackEnd/Shared/BuildRequestConfiguration.cs @@ -140,6 +140,11 @@ internal class BuildRequestConfiguration : IEquatable /// private string _savedCurrentDirectory; + /// + /// Saves the evaluation ID for the project so that it's accessible even when the underlying Project becomes cached + /// + private int _projectEvaluationId = BuildEventContext.InvalidEvaluationId; + #endregion /// @@ -186,6 +191,7 @@ internal BuildRequestConfiguration(int configId, BuildRequestData data, string d _projectInitialTargets = data.ProjectInstance.InitialTargets; _projectDefaultTargets = data.ProjectInstance.DefaultTargets; _projectTargets = GetProjectTargets(data.ProjectInstance.Targets); + _projectEvaluationId = data.ProjectInstance.EvaluationId; if (data.PropertiesToTransfer != null) { _transferredProperties = new List(); @@ -223,6 +229,7 @@ internal BuildRequestConfiguration(int configId, ProjectInstance instance) _projectInitialTargets = instance.InitialTargets; _projectDefaultTargets = instance.DefaultTargets; _projectTargets = GetProjectTargets(instance.Targets); + _projectEvaluationId = instance.EvaluationId; IsCacheable = false; } @@ -247,6 +254,7 @@ private BuildRequestConfiguration(int configId, BuildRequestConfiguration other) IsCacheable = other.IsCacheable; _configId = configId; RequestedTargets = other.RequestedTargets; + _projectEvaluationId = other._projectEvaluationId; } /// @@ -289,6 +297,15 @@ internal BuildRequestConfiguration() /// public bool IsCached { get; private set; } + /// + /// A short + /// + public int ProjectEvaluationId + { + get => _projectEvaluationId; + internal set => _projectEvaluationId = value; + } + /// /// Flag indicating if this configuration represents a traversal project. Traversal projects /// are projects which typically do little or no work themselves, but have references to other @@ -423,7 +440,8 @@ private void SetProjectBasedState(ProjectInstance project) _projectDefaultTargets = null; _projectInitialTargets = null; _projectTargets = null; - + + _projectEvaluationId = _project.EvaluationId; ProjectDefaultTargets = _project.DefaultTargets; ProjectInitialTargets = _project.InitialTargets; ProjectTargets = GetProjectTargets(_project.Targets); @@ -441,8 +459,7 @@ private void SetProjectBasedState(ProjectInstance project) internal void LoadProjectIntoConfiguration( IBuildComponentHost componentHost, BuildRequestDataFlags buildRequestDataFlags, - int submissionId, - int nodeId) + BuildEventContext parentBuildEventContext) { ErrorUtilities.VerifyThrow(!IsLoaded, "Already loaded the project for this configuration id {0}.", ConfigurationId); @@ -493,16 +510,9 @@ internal void LoadProjectIntoConfiguration( toolsVersionOverride, componentHost.BuildParameters, componentHost.LoggingService, - new BuildEventContext( - submissionId, - nodeId, - BuildEventContext.InvalidEvaluationId, - BuildEventContext.InvalidProjectInstanceId, - BuildEventContext.InvalidProjectContextId, - BuildEventContext.InvalidTargetId, - BuildEventContext.InvalidTaskId), + parentBuildEventContext, sdkResolverService, - submissionId, + parentBuildEventContext.SubmissionId, projectLoadSettings); }); } @@ -940,6 +950,7 @@ public void Translate(ITranslator translator) translator.Translate(ref _transferredProperties, ProjectPropertyInstance.FactoryForDeserialization); translator.Translate(ref _resultsNodeId); translator.Translate(ref _savedCurrentDirectory); + translator.Translate(ref _projectEvaluationId); translator.TranslateDictionary(ref _savedEnvironmentVariables, CommunicationsUtilities.EnvironmentVariableComparer); // if the entire state is translated, then the transferred state represents the full evaluation data @@ -958,6 +969,7 @@ internal void TranslateForFutureUse(ITranslator translator) translator.Translate(ref _projectDefaultTargets); translator.Translate(ref _projectInitialTargets); translator.Translate(ref _projectTargets); + translator.Translate(ref _projectEvaluationId); translator.TranslateDictionary(ref _globalProperties, ProjectPropertyInstance.FactoryForDeserialization); } diff --git a/src/Build/BackEnd/Shared/BuildResult.cs b/src/Build/BackEnd/Shared/BuildResult.cs index 87f110cb8d8..9b3656025ae 100644 --- a/src/Build/BackEnd/Shared/BuildResult.cs +++ b/src/Build/BackEnd/Shared/BuildResult.cs @@ -86,7 +86,8 @@ public class BuildResult : BuildResultBase, INodePacket, IBuildResults /// /// Allows to serialize and deserialize different versions of the build result. /// - private int _version = Traits.Instance.EscapeHatches.DoNotVersionBuildResult ? 0 : 1; + private int _version = + Traits.Instance.EscapeHatches.DoNotVersionBuildResult ? 0 : 2; /// /// The request caused a circular dependency in scheduling. @@ -100,6 +101,11 @@ public class BuildResult : BuildResultBase, INodePacket, IBuildResults /// private Exception? _requestException; + /// + /// The evaluation ID of the project used for this build. + /// + private int _evaluationId = BuildEventContext.InvalidEvaluationId; + /// /// The overall result calculated in the constructor. /// @@ -495,6 +501,17 @@ internal HashSet? ProjectTargets set => _projectTargets = value; } + /// + /// The evaluation ID of the project used for this build. + /// + internal int EvaluationId + { + [DebuggerStepThrough] + get => _evaluationId; + [DebuggerStepThrough] + set => _evaluationId = value; + } + /// /// Container used to transport errors from the scheduler (issued while computing a build result) /// to the TaskHost that has the proper logging context (project id, target id, task id, file location) @@ -695,6 +712,11 @@ void ITranslatable.Translate(ITranslator translator) { translator.TranslateEnum(ref _buildRequestDataFlags, (int)_buildRequestDataFlags); } + + if (_version >= 2) + { + translator.Translate(ref _evaluationId); + } } /// diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs index 0c9dcb341d1..880767c47a6 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckBuildEventHandler.cs @@ -182,9 +182,5 @@ 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); + ?? BuildEventContext.Invalid; } diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index 89998bad255..b48be3bdca8 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -649,7 +649,7 @@ public void StartProjectRequest(ICheckContext checkContext, string projectFullPa { foreach (BuildEventArgs deferredArgs in list) { - deferredArgs.BuildEventContext = deferredArgs.BuildEventContext!.WithInstanceIdAndContextId(buildEventContext); + deferredArgs.BuildEventContext = deferredArgs.BuildEventContext!.WithProjectInstanceId(buildEventContext.ProjectInstanceId).WithProjectContextId(buildEventContext.ProjectContextId); checkContext.DispatchBuildEvent(deferredArgs); } list.Clear(); diff --git a/src/Build/Definition/Project.cs b/src/Build/Definition/Project.cs index 4638632614c..57b03015b1c 100644 --- a/src/Build/Definition/Project.cs +++ b/src/Build/Definition/Project.cs @@ -67,7 +67,11 @@ public class Project : ILinkableObject /// /// Context to log messages and events in. /// - private static readonly BuildEventContext s_buildEventContext = new BuildEventContext(0 /* node ID */, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); + /// + /// This should only be used on pathways that create Projects outside of the MSBuild exe workflow - users directly loading Projects, etc. + /// In such cases we don't have a live set of nodes (yet?), but we still need contexts for message association. + /// + private static readonly BuildEventContext s_errorBuildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithSubmissionId(0); private ProjectLink implementation; private IProjectLinkInternal implementationInternal; @@ -1922,7 +1926,7 @@ public ProjectImpl(Project owner, XmlReader xmlReader, IDictionary loggers, IEnum { if (!IsBuildEnabled) { - LoggingService.LogError(s_buildEventContext, new BuildEventFileInfo(FullPath), "SecurityProjectBuildDisabled"); + LoggingService.LogError(s_errorBuildEventContext, new BuildEventFileInfo(FullPath), "SecurityProjectBuildDisabled"); if (LoggingService is LoggingService defaultLoggingService) { defaultLoggingService.WaitForLoggingToProcessEvents(); @@ -3553,7 +3557,7 @@ public string ExpandItemIncludeBestEffortLeaveEscaped(ProjectItemElement renamed _data.Expander, LoggingService, FullPath, - s_buildEventContext); + s_errorBuildEventContext); if (items.Count != 1) { @@ -3620,7 +3624,7 @@ private List AddItemHelper(ProjectItemElement itemElement, string u _data.Expander, LoggingService, FullPath, - s_buildEventContext); + s_errorBuildEventContext); foreach (ProjectItem item in items) { @@ -3708,7 +3712,7 @@ private void ReevaluateIfNecessary( } catch (InvalidProjectFileException ex) { - loggingServiceForEvaluation.LogInvalidProjectFileError(s_buildEventContext, ex); + loggingServiceForEvaluation.LogInvalidProjectFileError(s_errorBuildEventContext, ex); throw; } } @@ -3747,7 +3751,7 @@ private void Reevaluate( ProjectCollection, Owner._directoryCacheFactory, ProjectCollection.ProjectRootElementCache, - s_buildEventContext, + s_errorBuildEventContext, evaluationContext.SdkResolverService, BuildEventContext.InvalidSubmissionId, evaluationContext, diff --git a/src/Build/Definition/ProjectCollection.cs b/src/Build/Definition/ProjectCollection.cs index 5cc3c9ca91d..b02a7a0b368 100644 --- a/src/Build/Definition/ProjectCollection.cs +++ b/src/Build/Definition/ProjectCollection.cs @@ -99,6 +99,15 @@ public class ProjectCollection : IToolsetProvider, IBuildComponent, IDisposable /// private static ProjectCollection s_globalProjectCollection; + /// + /// Context to log messages and events in. + /// + /// + /// This should only be used on pathways that create ProjectCollections outside of the MSBuild exe workflow - users directly loading Projects, etc. + /// In such cases we don't have a live set of nodes (yet?), but we still need contexts for message association. + /// + private static readonly BuildEventContext s_errorBuildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithSubmissionId(0); + /// /// Gets the file version of the file in which the Engine assembly lies. /// @@ -383,8 +392,7 @@ public ProjectCollection(IDictionary globalProperties, IEnumerab } catch (InvalidProjectFileException ex2) { - BuildEventContext buildEventContext = new BuildEventContext(0 /* node ID */, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); - LoggingService.LogInvalidProjectFileError(buildEventContext, ex2); + LoggingService.LogInvalidProjectFileError(s_errorBuildEventContext, ex2); throw; } } @@ -1260,8 +1268,7 @@ public Project LoadProject(string fileName, IDictionary globalPr } catch (InvalidProjectFileException ex) { - var buildEventContext = new BuildEventContext(0 /* node ID */, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); - LoggingService.LogInvalidProjectFileError(buildEventContext, ex); + LoggingService.LogInvalidProjectFileError(s_errorBuildEventContext, ex); throw; } } diff --git a/src/Build/Instance/ProjectInstance.cs b/src/Build/Instance/ProjectInstance.cs index da0ac9603d0..39e0919debf 100644 --- a/src/Build/Instance/ProjectInstance.cs +++ b/src/Build/Instance/ProjectInstance.cs @@ -77,6 +77,16 @@ public enum ProjectInstanceSettings [DebuggerDisplay(@"{FullPath} #Targets={TargetsCount} DefaultTargets={(DefaultTargets == null) ? System.String.Empty : System.String.Join("";"", DefaultTargets.ToArray())} ToolsVersion={Toolset.ToolsVersion} InitialTargets={(InitialTargets == null) ? System.String.Empty : System.String.Join("";"", InitialTargets.ToArray())} #GlobalProperties={GlobalProperties.Count} #Properties={Properties.Count} #ItemTypes={ItemTypes.Count} #Items={Items.Count}")] public class ProjectInstance : IPropertyProvider, IItemProvider, IEvaluatorData, ITranslatable { + + /// + /// Context to log messages and events in. + /// + /// + /// This should only be used on pathways that create ProjectInstances outside of the MSBuild exe workflow - users directly loading Projects, etc. + /// In such cases we don't have a live set of nodes (yet?), but we still need contexts for message association. + /// + private static readonly BuildEventContext s_errorBuildEventContext = Scheduler.s_schedulerNodeBuildEventContext.WithSubmissionId(0); + /// /// Targets in the project after overrides have been resolved. /// This is an unordered collection keyed by target name. @@ -312,7 +322,7 @@ private ProjectInstance(string projectFile, IDictionary globalPr Interactive = interactive }; - BuildEventContext buildEventContext = new BuildEventContext(buildParameters.NodeId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); + BuildEventContext buildEventContext = s_errorBuildEventContext.WithNodeId(buildParameters.NodeId).WithSubmissionId(0); ProjectRootElement xml = ProjectRootElement.OpenProjectOrSolution(projectFile, globalProperties, toolsVersion, buildParameters.ProjectRootElementCache, true /*Explicitly Loaded*/); Initialize(xml, globalProperties, toolsVersion, subToolsetVersion, 0 /* no solution version provided */, buildParameters, projectCollection.LoggingService, buildEventContext, @@ -542,14 +552,12 @@ static List GetImportFullPathsIncludingDuplicates(ObjectModelRemoting.Pr private ProjectInstance(ProjectRootElement xml, IDictionary globalProperties, string toolsVersion, string subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings? projectLoadSettings, EvaluationContext evaluationContext, IDirectoryCacheFactory directoryCacheFactory, bool interactive) { - BuildEventContext buildEventContext = new BuildEventContext(0, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); - BuildParameters buildParameters = new BuildParameters(projectCollection) { Interactive = interactive }; - Initialize(xml, globalProperties, toolsVersion, subToolsetVersion, 0 /* no solution version specified */, buildParameters, projectCollection.LoggingService, buildEventContext, + Initialize(xml, globalProperties, toolsVersion, subToolsetVersion, 0 /* no solution version specified */, buildParameters, projectCollection.LoggingService, s_errorBuildEventContext, projectLoadSettings: projectLoadSettings, evaluationContext: evaluationContext, directoryCacheFactory: directoryCacheFactory); } @@ -617,8 +625,8 @@ internal ProjectInstance(string projectFile, ProjectInstance projectToInheritFro /// A new project instance internal ProjectInstance(ProjectRootElement xml, IDictionary globalProperties, string toolsVersion, int visualStudioVersionFromSolution, ProjectCollection projectCollection, ISdkResolverService sdkResolverService, int submissionId) { - BuildEventContext buildEventContext = new BuildEventContext(0, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTaskId); - Initialize(xml, globalProperties, toolsVersion, null, visualStudioVersionFromSolution, new BuildParameters(projectCollection), projectCollection.LoggingService, buildEventContext, sdkResolverService, submissionId); + BuildEventContext buildEventContext = BuildEventContext.CreateInitial(0 /* submission ID */, 0 /* node ID */); + Initialize(xml, globalProperties, toolsVersion, null, visualStudioVersionFromSolution, new BuildParameters(projectCollection), projectCollection.LoggingService, s_errorBuildEventContext, sdkResolverService, submissionId); } /// @@ -632,7 +640,7 @@ internal ProjectInstance(ProjectRootElement xml, IDictionary glo /// internal ProjectInstance(ProjectRootElement xml, IDictionary globalProperties, string toolsVersion, ILoggingService loggingService, int visualStudioVersionFromSolution, ProjectCollection projectCollection, ISdkResolverService sdkResolverService, int submissionId) { - BuildEventContext buildEventContext = new BuildEventContext(submissionId, 0, BuildEventContext.InvalidProjectInstanceId, BuildEventContext.InvalidProjectContextId, BuildEventContext.InvalidTargetId, BuildEventContext.InvalidTaskId); + BuildEventContext buildEventContext = s_errorBuildEventContext.WithSubmissionId(submissionId); Initialize(xml, globalProperties, toolsVersion, null, visualStudioVersionFromSolution, new BuildParameters(projectCollection), loggingService, buildEventContext, sdkResolverService, submissionId); } diff --git a/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs b/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs index 69afeee1674..dd38e66145f 100644 --- a/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs +++ b/src/Build/Logging/BinaryLogger/BuildEventArgsReader.cs @@ -1475,14 +1475,12 @@ private BuildEventContext ReadBuildEventContext() evaluationId = ReadInt32(); } - var result = new BuildEventContext( - submissionId, - nodeId, - evaluationId, - projectInstanceId, - projectContextId, - targetId, - taskId); + var result = BuildEventContext.CreateInitial(submissionId, nodeId) + .WithEvaluationId(evaluationId) + .WithProjectInstanceId(projectInstanceId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); return result; } diff --git a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs index 1cd861e4c98..281441bb16a 100644 --- a/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs +++ b/src/BuildCheck.UnitTests/BuildCheckManagerProviderTests.cs @@ -42,7 +42,7 @@ public void ProcessCheckAcquisitionTest(bool isCheckRuleExist, string[] expected MockBuildCheckAcquisition(isCheckRuleExist); MockEnabledDataSourcesDefinition(); - _testedInstance.ProcessCheckAcquisition(new CheckAcquisitionData("DummyPath", "ProjectPath"), new CheckLoggingContext(_loggingService, new BuildEventContext(1, 2, 3, 4, 5, 6, 7))); + _testedInstance.ProcessCheckAcquisition(new CheckAcquisitionData("DummyPath", "ProjectPath"), new CheckLoggingContext(_loggingService, BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7))); _logger.AllBuildEvents.Where(be => be.GetType() == typeof(BuildMessageEventArgs)).Select(be => be.Message).ToArray() .ShouldBeEquivalentTo(expectedMessages); diff --git a/src/Framework.UnitTests/CustomEventArgSerialization_Tests.cs b/src/Framework.UnitTests/CustomEventArgSerialization_Tests.cs index 0da144267c5..a6c0f7536ac 100644 --- a/src/Framework.UnitTests/CustomEventArgSerialization_Tests.cs +++ b/src/Framework.UnitTests/CustomEventArgSerialization_Tests.cs @@ -16,6 +16,9 @@ namespace Microsoft.Build.UnitTests { public class CustomEventArgSerialization_Tests : IDisposable { + + private static readonly BuildEventContext defaultContext = BuildEventContext.CreateInitial(5, 4).WithEvaluationId(3).WithProjectInstanceId(2); + // Generic build class to test custom serialization of abstract class BuildEventArgs internal sealed class GenericBuildEventArg : BuildEventArgs { @@ -59,7 +62,7 @@ public void TestGenericBuildEventArgs() { // Test using reasonable messages GenericBuildEventArg genericEvent = new GenericBuildEventArg("Message", "HelpKeyword", "SenderName"); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -76,7 +79,7 @@ public void TestGenericBuildEventArgs() // Test using empty strings _stream.Position = 0; genericEvent = new GenericBuildEventArg(string.Empty, string.Empty, string.Empty); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -101,7 +104,7 @@ public void TestGenericBuildEventArgs() // Deserialize and Verify _stream.Position = 0; newGenericEvent = new GenericBuildEventArg(null, null, null); - newGenericEvent.BuildEventContext = new BuildEventContext(1, 3, 4, 5); + newGenericEvent.BuildEventContext = BuildEventContext.CreateInitial(1, 3).WithEvaluationId(4).WithProjectInstanceId(5); newGenericEvent.CreateFromStream(_reader, _eventArgVersion); _stream.Position.ShouldBe(streamWriteEndPosition); // "Stream End Positions Should Match" VerifyGenericEventArg(genericEvent, newGenericEvent); @@ -125,7 +128,7 @@ public void TestBuildErrorEventArgs() { // Test using reasonable messages BuildErrorEventArgs genericEvent = new BuildErrorEventArgs("Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "SenderName"); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -142,7 +145,7 @@ public void TestBuildErrorEventArgs() // Test using empty strings _stream.Position = 0; genericEvent = new BuildErrorEventArgs(string.Empty, string.Empty, string.Empty, 1, 2, 3, 4, string.Empty, string.Empty, string.Empty); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -176,7 +179,7 @@ public void TestBuildErrorEventArgs() // Test using HelpLink _stream.Position = 0; genericEvent = new BuildErrorEventArgs("Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "SenderName", "HelpLink", DateTime.Now); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -210,7 +213,7 @@ public void TestBuildFinishedEventArgs() { // Test using reasonable messages BuildFinishedEventArgs genericEvent = new BuildFinishedEventArgs("Message", "HelpKeyword", true); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -225,7 +228,7 @@ public void TestBuildFinishedEventArgs() // Test using empty strings _stream.Position = 0; genericEvent = new BuildFinishedEventArgs(string.Empty, string.Empty, true); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -258,7 +261,7 @@ public void TestBuildMessageEventArgs() { // Test using reasonable messages BuildMessageEventArgs genericEvent = new BuildMessageEventArgs("Message", "HelpKeyword", "SenderName", MessageImportance.High); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -276,7 +279,7 @@ public void TestBuildMessageEventArgs() _stream.Position = 0; // Make sure empty strings are passed correctly genericEvent = new BuildMessageEventArgs(string.Empty, string.Empty, string.Empty, MessageImportance.Low); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -328,7 +331,7 @@ public void TestBuildMessageEventArgsWithFileInfo() { // Test using reasonable messages BuildMessageEventArgs messageEvent = new BuildMessageEventArgs("SubCategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "SenderName", MessageImportance.High); - messageEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + messageEvent.BuildEventContext = defaultContext; // Serialize messageEvent.WriteToStream(_writer); @@ -345,7 +348,7 @@ public void TestBuildMessageEventArgsWithFileInfo() _stream.Position = 0; // Make sure empty strings are passed correctly messageEvent = new BuildMessageEventArgs(string.Empty, string.Empty, string.Empty, 1, 2, 3, 4, string.Empty, string.Empty, string.Empty, MessageImportance.Low); - messageEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + messageEvent.BuildEventContext = defaultContext; // Serialize messageEvent.WriteToStream(_writer); @@ -381,7 +384,7 @@ public void TestCriticalBuildMessageEventArgs() { // Test using reasonable messages CriticalBuildMessageEventArgs criticalMessageEvent = new CriticalBuildMessageEventArgs("SubCategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "SenderName"); - criticalMessageEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + criticalMessageEvent.BuildEventContext = defaultContext; // Serialize criticalMessageEvent.WriteToStream(_writer); @@ -399,7 +402,7 @@ public void TestCriticalBuildMessageEventArgs() _stream.Position = 0; // Make sure empty strings are passed correctly criticalMessageEvent = new CriticalBuildMessageEventArgs(string.Empty, string.Empty, string.Empty, 1, 2, 3, 4, string.Empty, string.Empty, string.Empty); - criticalMessageEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + criticalMessageEvent.BuildEventContext = defaultContext; // Serialize criticalMessageEvent.WriteToStream(_writer); @@ -435,7 +438,7 @@ public void TestBuildWarningEventArgs() { // Test with reasonable messages BuildWarningEventArgs genericEvent = new BuildWarningEventArgs("Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "SenderName"); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -452,7 +455,7 @@ public void TestBuildWarningEventArgs() // Test with empty strings _stream.Position = 0; genericEvent = new BuildWarningEventArgs(string.Empty, string.Empty, string.Empty, 1, 2, 3, 4, string.Empty, string.Empty, string.Empty); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -486,7 +489,7 @@ public void TestBuildWarningEventArgs() // Test with help link _stream.Position = 0; genericEvent = new BuildWarningEventArgs("Subcategory", "Code", "File", 1, 2, 3, 4, "Message", "HelpKeyword", "SenderName", "HelpLink", DateTime.Now, null); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -520,7 +523,7 @@ public void TestProjectFinishedEventArgs() { // Test with reasonable values ProjectFinishedEventArgs genericEvent = new ProjectFinishedEventArgs("Message", "HelpKeyword", "ProjectFile", true); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -538,7 +541,7 @@ public void TestProjectFinishedEventArgs() // Test with empty strings _stream.Position = 0; genericEvent = new ProjectFinishedEventArgs(string.Empty, string.Empty, string.Empty, true); - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; // Serialize genericEvent.WriteToStream(_writer); @@ -586,8 +589,8 @@ public void TestProjectStartedPropertySerialization() propertyList.Add(new DictionaryEntry("WorkSpaceOwner", "The workspace owner")); propertyList.Add(new DictionaryEntry("IAmBlank", string.Empty)); - ProjectStartedEventArgs genericEvent = new ProjectStartedEventArgs(8, "Message", "HelpKeyword", "ProjectFile", null, propertyList, null, new BuildEventContext(7, 8, 9, 10)); - genericEvent.BuildEventContext = new BuildEventContext(7, 8, 9, 10); + ProjectStartedEventArgs genericEvent = new ProjectStartedEventArgs(8, "Message", "HelpKeyword", "ProjectFile", null, propertyList, null, BuildEventContext.CreateInitial(7, 8).WithEvaluationId(9).WithProjectInstanceId(10)); + genericEvent.BuildEventContext = BuildEventContext.CreateInitial(7, 8).WithEvaluationId(9).WithProjectInstanceId(10); // Serialize genericEvent.WriteToStream(_writer); @@ -650,8 +653,8 @@ private void AssertDictionaryEntry(List entryList, List { { "Key", "Value" } } }; - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; TelemetryEventArgs newGenericEvent = RoundTrip(genericEvent); @@ -994,7 +997,7 @@ public void TestTelemetryEventArgs_NullProperties() { // Test using reasonable values TelemetryEventArgs genericEvent = new TelemetryEventArgs { EventName = "Good", Properties = null }; - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; TelemetryEventArgs newGenericEvent = RoundTrip(genericEvent); @@ -1011,7 +1014,7 @@ public void TestTelemetryEventArgs_NullEventName() { // Test using null event name TelemetryEventArgs genericEvent = new TelemetryEventArgs { EventName = null, Properties = new Dictionary { { "Key", "Value" } } }; - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; TelemetryEventArgs newGenericEvent = RoundTrip(genericEvent); @@ -1024,7 +1027,7 @@ public void TestTelemetryEventArgs_NullPropertyValue() { // Test using null property value name TelemetryEventArgs genericEvent = new TelemetryEventArgs { EventName = "Good", Properties = new Dictionary { { "Key", null } } }; - genericEvent.BuildEventContext = new BuildEventContext(5, 4, 3, 2); + genericEvent.BuildEventContext = defaultContext; TelemetryEventArgs newGenericEvent = RoundTrip(genericEvent); diff --git a/src/Framework.UnitTests/EventArgs_Tests.cs b/src/Framework.UnitTests/EventArgs_Tests.cs index 451ec654a16..626089c167a 100644 --- a/src/Framework.UnitTests/EventArgs_Tests.cs +++ b/src/Framework.UnitTests/EventArgs_Tests.cs @@ -29,7 +29,10 @@ public class EventArgs_Tests public EventArgs_Tests() { s_baseGenericEvent = new GenericBuildEventArgs("Message", "HelpKeyword", "senderName"); - s_baseGenericEvent.BuildEventContext = new BuildEventContext(9, 8, 7, 6); + s_baseGenericEvent.BuildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, 9) + .WithProjectContextId(7) + .WithTargetId(8) + .WithTaskId(6); } /// @@ -57,19 +60,19 @@ public void EventArgsCtors() [Fact] public void ExerciseBuildEventContext() { - BuildEventContext parentBuildEventContext = new BuildEventContext(0, 0, 0, 0, 0, 0, 0); - - BuildEventContext currentBuildEventContext = new BuildEventContext(0, 1, 2, 3, 4, 5, 6); - - BuildEventContext currentBuildEventContextSubmission = new BuildEventContext(1, 0, 0, 0, 0, 0, 0); - BuildEventContext currentBuildEventContextNode = new BuildEventContext(0, 1, 0, 0, 0, 0, 0); - BuildEventContext currentBuildEventContextEvaluation = new BuildEventContext(0, 0, 1, 0, 0, 0, 0); - BuildEventContext currentBuildEventContextProjectInstance = new BuildEventContext(0, 0, 0, 1, 0, 0, 0); - BuildEventContext currentBuildEventProjectContext = new BuildEventContext(0, 0, 0, 0, 1, 0, 0); - BuildEventContext currentBuildEventContextTarget = new BuildEventContext(0, 0, 0, 0, 0, 1, 0); - BuildEventContext currentBuildEventContextTask = new BuildEventContext(0, 0, 0, 0, 0, 0, 1); - BuildEventContext allDifferent = new BuildEventContext(1, 1, 1, 1, 1, 1, 1); - BuildEventContext allSame = new BuildEventContext(0, 0, 0, 0, 0, 0, 0); + BuildEventContext parentBuildEventContext = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(0).WithTaskId(0); + + BuildEventContext currentBuildEventContext = BuildEventContext.CreateInitial(0, 1).WithEvaluationId(2).WithProjectInstanceId(3).WithProjectContextId(4).WithTargetId(5).WithTaskId(6); + + BuildEventContext currentBuildEventContextSubmission = BuildEventContext.CreateInitial(1, 0).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(0).WithTaskId(0); + BuildEventContext currentBuildEventContextNode = BuildEventContext.CreateInitial(0, 1).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(0).WithTaskId(0); + BuildEventContext currentBuildEventContextEvaluation = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(1).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(0).WithTaskId(0); + BuildEventContext currentBuildEventContextProjectInstance = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(1).WithProjectContextId(0).WithTargetId(0).WithTaskId(0); + BuildEventContext currentBuildEventProjectContext = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(1).WithTargetId(0).WithTaskId(0); + BuildEventContext currentBuildEventContextTarget = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(1).WithTaskId(0); + BuildEventContext currentBuildEventContextTask = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(0).WithTaskId(1); + BuildEventContext allDifferent = BuildEventContext.CreateInitial(1, 1).WithEvaluationId(1).WithProjectInstanceId(1).WithProjectContextId(1).WithTargetId(1).WithTaskId(1); + BuildEventContext allSame = BuildEventContext.CreateInitial(0, 0).WithEvaluationId(0).WithProjectInstanceId(0).WithProjectContextId(0).WithTargetId(0).WithTaskId(0); ProjectStartedEventArgs startedEvent = new ProjectStartedEventArgs(-1, "Message", "HELP", "File", "Targets", null, null, parentBuildEventContext); startedEvent.BuildEventContext = currentBuildEventContext; diff --git a/src/Framework.UnitTests/ExtendedBuildEventArgs_Tests.cs b/src/Framework.UnitTests/ExtendedBuildEventArgs_Tests.cs index 47a7bbe5b54..cf36b3856fa 100644 --- a/src/Framework.UnitTests/ExtendedBuildEventArgs_Tests.cs +++ b/src/Framework.UnitTests/ExtendedBuildEventArgs_Tests.cs @@ -26,7 +26,7 @@ public void ExtendedCustomBuildEventArgs_SerializationDeserialization(bool withO { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7) : null, }; using MemoryStream stream = new MemoryStream(); @@ -64,7 +64,7 @@ public void ExtendedErrorEventArgs_SerializationDeserialization(bool withOptiona { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7) : null, }; using MemoryStream stream = new MemoryStream(); @@ -103,7 +103,7 @@ public void ExtendedWarningEventArgs_SerializationDeserialization(bool withOptio { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7) : null, }; using MemoryStream stream = new MemoryStream(); @@ -141,7 +141,7 @@ public void ExtendedMessageEventArgs_SerializationDeserialization(bool withOptio { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7) : null, }; using MemoryStream stream = new MemoryStream(); @@ -178,7 +178,7 @@ public void ExtendedCriticalMessageEventArgs_SerializationDeserialization(bool w { ExtendedData = withOptionalData ? /*lang=json*/ "{'long-json':'mostly-strings'}" : null, ExtendedMetadata = withOptionalData ? new Dictionary { { "m1", "v1" }, { "m2", "v2" } } : null, - BuildEventContext = withOptionalData ? new BuildEventContext(1, 2, 3, 4, 5, 6, 7) : null, + BuildEventContext = withOptionalData ? BuildEventContext.CreateInitial(1, 2).WithEvaluationId(3).WithProjectInstanceId(4).WithProjectContextId(5).WithTargetId(6).WithTaskId(7) : null, }; using MemoryStream stream = new MemoryStream(); diff --git a/src/Framework.UnitTests/ProjectStartedEventArgs_Tests.cs b/src/Framework.UnitTests/ProjectStartedEventArgs_Tests.cs index a8ba7a3286a..067ad3f27db 100644 --- a/src/Framework.UnitTests/ProjectStartedEventArgs_Tests.cs +++ b/src/Framework.UnitTests/ProjectStartedEventArgs_Tests.cs @@ -21,7 +21,6 @@ public class ProjectStartedEventArgs_Tests /// public ProjectStartedEventArgs_Tests() { - BuildEventContext parentBuildEventContext = new BuildEventContext(2, 3, 4, 5); } /// diff --git a/src/Framework/BinaryTranslator.cs b/src/Framework/BinaryTranslator.cs index 3760eec83e3..ced71dafa92 100644 --- a/src/Framework/BinaryTranslator.cs +++ b/src/Framework/BinaryTranslator.cs @@ -493,14 +493,20 @@ public void Translate(ref TimeSpan value) /// The context to be translated. public void Translate(ref BuildEventContext value) { - value = new BuildEventContext( - _reader.ReadInt32(), - _reader.ReadInt32(), - _reader.ReadInt32(), - _reader.ReadInt32(), - _reader.ReadInt32(), - _reader.ReadInt32(), - _reader.ReadInt32()); + int submissionId = _reader.ReadInt32(); + int nodeId = _reader.ReadInt32(); + int evaluationId = _reader.ReadInt32(); + int projectInstanceId = _reader.ReadInt32(); + int projectContextId = _reader.ReadInt32(); + int targetId = _reader.ReadInt32(); + int taskId = _reader.ReadInt32(); + + value = BuildEventContext.CreateInitial(submissionId, nodeId) + .WithEvaluationId(evaluationId) + .WithProjectInstanceId(projectInstanceId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); } #endif diff --git a/src/Framework/BuildEventArgs.cs b/src/Framework/BuildEventArgs.cs index a26e7b26948..ed5672ab1c1 100644 --- a/src/Framework/BuildEventArgs.cs +++ b/src/Framework/BuildEventArgs.cs @@ -241,11 +241,19 @@ internal virtual void CreateFromStream(BinaryReader reader, int version) int submissionId = reader.ReadInt32(); int projectInstanceId = reader.ReadInt32(); int evaluationId = reader.ReadInt32(); - buildEventContext = new BuildEventContext(submissionId, nodeId, evaluationId, projectInstanceId, projectContextId, targetId, taskId); + buildEventContext = BuildEventContext.CreateInitial(submissionId, nodeId) + .WithEvaluationId(evaluationId) + .WithProjectInstanceId(projectInstanceId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); } else { - buildEventContext = new BuildEventContext(nodeId, targetId, projectContextId, taskId); + buildEventContext = BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, nodeId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); } } } diff --git a/src/Framework/BuildEventContext.cs b/src/Framework/BuildEventContext.cs index 83a7a1f9330..05260665f79 100644 --- a/src/Framework/BuildEventContext.cs +++ b/src/Framework/BuildEventContext.cs @@ -7,7 +7,11 @@ namespace Microsoft.Build.Framework { /// /// Will provide location information for an event, this is especially - /// needed in a multi processor environment + /// needed in a multi processor environment. + /// + /// BuildEventContext objects should be created using the static CreateInitial method + /// for the root context, then using the fluent WithXxx methods to create derived contexts + /// that preserve all ID properties while updating specific ones. /// [Serializable] public class BuildEventContext @@ -51,52 +55,12 @@ public class BuildEventContext #endregion - #region Constructor - /// - /// This is the original constructor. No one should ever use this except internally for backward compatibility. + /// Constructs a BuildEventContext with all parameters specified. + /// This constructor should only be used internally for serialization/deserialization + /// and by the fluent WithXxx methods. External code should use CreateInitial() and fluent methods. /// - public BuildEventContext( - int nodeId, - int targetId, - int projectContextId, - int taskId) - : this(InvalidSubmissionId, nodeId, InvalidEvaluationId, InvalidProjectInstanceId, projectContextId, targetId, taskId) - { - // UNDONE: This is obsolete. - } - - /// - /// Constructs a BuildEventContext with a specified project instance id. - /// - public BuildEventContext( - int nodeId, - int projectInstanceId, - int projectContextId, - int targetId, - int taskId) - : this(InvalidSubmissionId, nodeId, InvalidEvaluationId, projectInstanceId, projectContextId, targetId, taskId) - { - } - - /// - /// Constructs a BuildEventContext with a specific submission id - /// - public BuildEventContext( - int submissionId, - int nodeId, - int projectInstanceId, - int projectContextId, - int targetId, - int taskId) - : this(submissionId, nodeId, InvalidEvaluationId, projectInstanceId, projectContextId, targetId, taskId) - { - } - - /// - /// Constructs a BuildEventContext - /// - public BuildEventContext( + internal BuildEventContext( int submissionId, int nodeId, int evaluationId, @@ -114,24 +78,87 @@ public BuildEventContext( _projectInstanceId = projectInstanceId; } - #endregion - internal BuildEventContext WithInstanceIdAndContextId(int projectInstanceId, int projectContextId) - { - return new BuildEventContext(_submissionId, _nodeId, _evaluationId, projectInstanceId, projectContextId, - _targetId, _taskId); - } + #region Builders - internal BuildEventContext WithInstanceIdAndContextId(BuildEventContext other) - { - return WithInstanceIdAndContextId(other.ProjectInstanceId, other.ProjectContextId); - } + /// + /// Creates an initial BuildEventContext for the beginning of a build. + /// Uses the efficient builder pattern to minimize allocations. + /// + /// The submission ID + /// The node ID + /// A new BuildEventContext with the specified submission and node ID + public static BuildEventContextBuilder CreateInitial(int submissionId, int nodeId) => new BuildEventContextBuilder().WithSubmissionId(submissionId).WithNodeId(nodeId); + + /// + /// Creates a new builder with the specified submission ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new submission ID + /// A builder with the updated submission ID + public BuildEventContextBuilder WithSubmissionId(int submissionId) => Builder(this).WithSubmissionId(submissionId); + + /// + /// Creates a new builder with the specified node ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new node ID + /// A builder with the updated node ID + public BuildEventContextBuilder WithNodeId(int nodeId) => Builder(this).WithNodeId(nodeId); + + /// + /// Creates a new builder with the specified evaluation ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new evaluation ID + /// A builder with the updated evaluation ID + public BuildEventContextBuilder WithEvaluationId(int evaluationId) => Builder(this).WithEvaluationId(evaluationId); + + /// + /// Creates a new builder with the specified project instance ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new project instance ID + /// A builder with the updated project instance ID + public BuildEventContextBuilder WithProjectInstanceId(int projectInstanceId) => Builder(this).WithProjectInstanceId(projectInstanceId); + + /// + /// Creates a new builder with the specified project context ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new project context ID + /// A builder with the updated project context ID + public BuildEventContextBuilder WithProjectContextId(int projectContextId) => Builder(this).WithProjectContextId(projectContextId); + + /// + /// Creates a new builder with the specified target ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new target ID + /// A builder with the updated target ID + public BuildEventContextBuilder WithTargetId(int targetId) => Builder(this).WithTargetId(targetId); + + /// + /// Creates a new builder with the specified task ID, preserving all other IDs. + /// Returns a builder to enable efficient chaining without intermediate allocations. + /// Call Build() to create the final BuildEventContext. + /// + /// The new task ID + /// A builder with the updated task ID + public BuildEventContextBuilder WithTaskId(int taskId) => Builder(this).WithTaskId(taskId); + #endregion #region Properties /// /// Returns a default invalid BuildEventContext /// - public static BuildEventContext Invalid { get; } = new BuildEventContext(InvalidNodeId, InvalidTargetId, InvalidProjectContextId, InvalidTaskId); + public static BuildEventContext Invalid { get; } = new(InvalidSubmissionId, InvalidNodeId, InvalidEvaluationId, InvalidProjectInstanceId, InvalidProjectContextId, InvalidTargetId, InvalidTaskId); /// /// Retrieves the Evaluation id. @@ -159,7 +186,7 @@ internal BuildEventContext WithInstanceIdAndContextId(BuildEventContext other) public int TaskId => _taskId; /// - /// Retrieves the project instance id. + /// Retrieves the project instance id, AKA the Configuration Id (AKA BuildRequestConfiguration.Id) /// public int ProjectInstanceId => _projectInstanceId; @@ -297,20 +324,180 @@ public override bool Equals(object? obj) /// /// BuildEventContext to compare to this instance /// True if the value fields are the same, false if otherwise - private bool InternalEquals(BuildEventContext buildEventContext) - { - return _nodeId == buildEventContext.NodeId + private bool InternalEquals(BuildEventContext buildEventContext) => _nodeId == buildEventContext.NodeId && _projectContextId == buildEventContext.ProjectContextId && _targetId == buildEventContext.TargetId && _taskId == buildEventContext.TaskId && _evaluationId == buildEventContext._evaluationId && _projectInstanceId == buildEventContext._projectInstanceId; - } #endregion - public override string ToString() + public override string ToString() => $"Node={NodeId} Submission={SubmissionId} ProjectContext={ProjectContextId} ProjectInstance={ProjectInstanceId} Eval={EvaluationId} Target={TargetId} Task={TaskId}"; + + #region Builder Pattern + + /// + /// Creates a new builder initialized from an existing BuildEventContext. + /// This allows for efficient copying and modification of existing contexts. + /// + /// The BuildEventContext to copy values from + /// A new BuildEventContextBuilder initialized with the source values + public static BuildEventContextBuilder Builder(BuildEventContext source) => new(source); + + #endregion + } + + /// + /// A ref struct builder for efficiently constructing BuildEventContext instances. + /// This builder eliminates heap allocations during the building process and provides + /// a fluent API for setting context properties. + /// + /// Usage: + /// var context = BuildEventContext.Builder() + /// .WithSubmissionId(1) + /// .WithNodeId(2) + /// .WithProjectInstanceId(3) + /// .Build(); + /// + public ref struct BuildEventContextBuilder + { + private int _submissionId; + private int _nodeId; + private int _evaluationId; + private int _projectInstanceId; + private int _projectContextId; + private int _targetId; + private int _taskId; + + /// + /// Initializes a new BuildEventContextBuilder with invalid values for all IDs. + /// + public BuildEventContextBuilder() + { + _submissionId = BuildEventContext.InvalidSubmissionId; + _nodeId = BuildEventContext.InvalidNodeId; + _evaluationId = BuildEventContext.InvalidEvaluationId; + _projectInstanceId = BuildEventContext.InvalidProjectInstanceId; + _projectContextId = BuildEventContext.InvalidProjectContextId; + _targetId = BuildEventContext.InvalidTargetId; + _taskId = BuildEventContext.InvalidTaskId; + } + + /// + /// Initializes a new BuildEventContextBuilder with values from an existing BuildEventContext. + /// + /// The BuildEventContext to copy values from + public BuildEventContextBuilder(BuildEventContext source) + { + _submissionId = source.SubmissionId; + _nodeId = source.NodeId; + _evaluationId = source.EvaluationId; + _projectInstanceId = source.ProjectInstanceId; + _projectContextId = source.ProjectContextId; + _targetId = source.TargetId; + _taskId = source.TaskId; + } + + /// + /// Sets the submission ID and returns this builder for chaining. + /// + /// The submission ID + /// This builder instance + public BuildEventContextBuilder WithSubmissionId(int submissionId) + { + _submissionId = submissionId; + return this; + } + + /// + /// Sets the node ID and returns this builder for chaining. + /// + /// The node ID + /// This builder instance + public BuildEventContextBuilder WithNodeId(int nodeId) + { + _nodeId = nodeId; + return this; + } + + /// + /// Sets the evaluation ID and returns this builder for chaining. + /// + /// The evaluation ID + /// This builder instance + public BuildEventContextBuilder WithEvaluationId(int evaluationId) + { + _evaluationId = evaluationId; + return this; + } + + /// + /// Sets the project instance ID and returns this builder for chaining. + /// + /// The project instance ID + /// This builder instance + public BuildEventContextBuilder WithProjectInstanceId(int projectInstanceId) + { + _projectInstanceId = projectInstanceId; + return this; + } + + /// + /// Sets the project context ID and returns this builder for chaining. + /// + /// The project context ID + /// This builder instance + public BuildEventContextBuilder WithProjectContextId(int projectContextId) + { + _projectContextId = projectContextId; + return this; + } + + /// + /// Sets the target ID and returns this builder for chaining. + /// + /// The target ID + /// This builder instance + public BuildEventContextBuilder WithTargetId(int targetId) + { + _targetId = targetId; + return this; + } + + /// + /// Sets the task ID and returns this builder for chaining. + /// + /// The task ID + /// This builder instance + public BuildEventContextBuilder WithTaskId(int taskId) + { + _taskId = taskId; + return this; + } + + /// + /// Builds the final BuildEventContext instance. + /// This is the only operation that allocates memory on the heap. + /// + /// A new BuildEventContext with the configured values + public readonly BuildEventContext Build() => new BuildEventContext( + _submissionId, + _nodeId, + _evaluationId, + _projectInstanceId, + _projectContextId, + _targetId, + _taskId); + + /// + /// Implicit conversion from builder to BuildEventContext for convenience. + /// This allows the builder to be used directly where a BuildEventContext is expected. + /// + /// The builder to convert + /// A new BuildEventContext built from the builder + public static implicit operator BuildEventContext(BuildEventContextBuilder builder) { - return $"Node={NodeId} Submission={SubmissionId} ProjectContext={ProjectContextId} ProjectInstance={ProjectInstanceId} Eval={EvaluationId} Target={TargetId} Task={TaskId}"; + return builder.Build(); } } } diff --git a/src/Framework/CompatibilitySuppressions.xml b/src/Framework/CompatibilitySuppressions.xml index d61bb3c6b1f..a6692f1f847 100644 --- a/src/Framework/CompatibilitySuppressions.xml +++ b/src/Framework/CompatibilitySuppressions.xml @@ -1,6 +1,181 @@  + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + lib/net10.0/Microsoft.Build.Framework.dll + lib/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + lib/net10.0/Microsoft.Build.Framework.dll + lib/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + lib/net10.0/Microsoft.Build.Framework.dll + lib/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32) + lib/net10.0/Microsoft.Build.Framework.dll + lib/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + lib/net472/Microsoft.Build.Framework.dll + lib/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + lib/net472/Microsoft.Build.Framework.dll + lib/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + lib/net472/Microsoft.Build.Framework.dll + lib/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32) + lib/net472/Microsoft.Build.Framework.dll + lib/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/net10.0/Microsoft.Build.Framework.dll + ref/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/net10.0/Microsoft.Build.Framework.dll + ref/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/net10.0/Microsoft.Build.Framework.dll + ref/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32) + ref/net10.0/Microsoft.Build.Framework.dll + ref/net10.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/net472/Microsoft.Build.Framework.dll + ref/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/net472/Microsoft.Build.Framework.dll + ref/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/net472/Microsoft.Build.Framework.dll + ref/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32) + ref/net472/Microsoft.Build.Framework.dll + ref/net472/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/netstandard2.0/Microsoft.Build.Framework.dll + ref/netstandard2.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/netstandard2.0/Microsoft.Build.Framework.dll + ref/netstandard2.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32) + ref/netstandard2.0/Microsoft.Build.Framework.dll + ref/netstandard2.0/Microsoft.Build.Framework.dll + true + + + CP0002 + M:Microsoft.Build.Framework.BuildEventContext.#ctor(System.Int32,System.Int32,System.Int32,System.Int32) + ref/netstandard2.0/Microsoft.Build.Framework.dll + ref/netstandard2.0/Microsoft.Build.Framework.dll + true + + + CP0009 + T:Microsoft.Build.Framework.BuildEventContext + lib/net10.0/Microsoft.Build.Framework.dll + lib/net10.0/Microsoft.Build.Framework.dll + true + + + CP0009 + T:Microsoft.Build.Framework.BuildEventContext + lib/net472/Microsoft.Build.Framework.dll + lib/net472/Microsoft.Build.Framework.dll + true + + + CP0009 + T:Microsoft.Build.Framework.BuildEventContext + ref/net10.0/Microsoft.Build.Framework.dll + ref/net10.0/Microsoft.Build.Framework.dll + true + + + CP0009 + T:Microsoft.Build.Framework.BuildEventContext + ref/net472/Microsoft.Build.Framework.dll + ref/net472/Microsoft.Build.Framework.dll + true + + + CP0009 + T:Microsoft.Build.Framework.BuildEventContext + ref/netstandard2.0/Microsoft.Build.Framework.dll + ref/netstandard2.0/Microsoft.Build.Framework.dll + true + PKV004 .NETCoreApp,Version=v2.0 diff --git a/src/Framework/ProjectStartedEventArgs.cs b/src/Framework/ProjectStartedEventArgs.cs index 6033d11cb53..3b9ac663c0d 100644 --- a/src/Framework/ProjectStartedEventArgs.cs +++ b/src/Framework/ProjectStartedEventArgs.cs @@ -118,6 +118,38 @@ public ProjectStartedEventArgs( this.ToolsVersion = toolsVersion; } + /// + /// This constructor allows event data to be initialized including the original build event context. + /// Sender is assumed to be "MSBuild". + /// + /// project id + /// text message + /// help keyword + /// project name + /// targets we are going to build (empty indicates default targets) + /// list of properties + /// list of items + /// event context info for the parent project + /// An containing global properties. + /// The tools version. + /// original build event context from the remote node. This should contain node, submission, evaluation and projectInstance Ids at minimum. + public ProjectStartedEventArgs( + int projectId, + string message, + string helpKeyword, + string? projectFile, + string? targetNames, + IEnumerable? properties, + IEnumerable? items, + BuildEventContext? parentBuildEventContext, + IDictionary? globalProperties, + string? toolsVersion, + BuildEventContext? originalBuildEventContext) + : this(projectId, message, helpKeyword, projectFile, targetNames, properties, items, parentBuildEventContext, globalProperties, toolsVersion) + { + this.originalBuildEventContext = originalBuildEventContext; + } + /// /// This constructor allows event data to be initialized. Also the timestamp can be set /// Sender is assumed to be "MSBuild". @@ -140,7 +172,7 @@ public ProjectStartedEventArgs( : base(message, helpKeyword, "MSBuild", eventTimestamp) { this.projectFile = projectFile; - this.targetNames = targetNames ?? String.Empty; + this.targetNames = targetNames ?? string.Empty; this.properties = properties; this.items = items; } @@ -174,6 +206,36 @@ public ProjectStartedEventArgs( this.projectId = projectId; } + /// + /// This constructor allows event data to be initialized including the original build event context. + /// Sender is assumed to be "MSBuild". + /// + /// project id + /// text message + /// help keyword + /// project name + /// targets we are going to build (empty indicates default targets) + /// list of properties + /// list of items + /// event context info for the parent project + /// original build event context from the remote node + /// The of the event. + public ProjectStartedEventArgs( + int projectId, + string message, + string helpKeyword, + string? projectFile, + string? targetNames, + IEnumerable? properties, + IEnumerable? items, + BuildEventContext? parentBuildEventContext, + BuildEventContext? originalBuildEventContext, + DateTime eventTimestamp) + : this(projectId, message, helpKeyword, projectFile, targetNames, properties, items, parentBuildEventContext, eventTimestamp) + { + this.originalBuildEventContext = originalBuildEventContext; + } + // ProjectId is only contained in the project started event. // This number indicated the instance id of the project and can be // used when debugging to determine if two projects with the same name @@ -206,6 +268,22 @@ public BuildEventContext? ParentProjectBuildEventContext } } + [OptionalField(VersionAdded = 3)] + private BuildEventContext? originalBuildEventContext; + + /// + /// The (possibly null) from the original project build. + /// This contains the full context data from when the project was first built on the original node, + /// and should be used for evaluation ID tracking and build correlation in distributed scenarios. + /// + public BuildEventContext? OriginalBuildEventContext + { + get + { + return originalBuildEventContext; + } + } + /// /// The name of the project file /// @@ -351,7 +429,7 @@ public IEnumerable? Items internal override void WriteToStream(BinaryWriter writer) { base.WriteToStream(writer); - writer.Write((Int32)projectId); + writer.Write(projectId); if (parentProjectBuildEventContext == null) { @@ -360,12 +438,15 @@ internal override void WriteToStream(BinaryWriter writer) else { writer.Write((byte)1); - writer.Write((Int32)parentProjectBuildEventContext.NodeId); - writer.Write((Int32)parentProjectBuildEventContext.ProjectContextId); - writer.Write((Int32)parentProjectBuildEventContext.TargetId); - writer.Write((Int32)parentProjectBuildEventContext.TaskId); - writer.Write((Int32)parentProjectBuildEventContext.SubmissionId); - writer.Write((Int32)parentProjectBuildEventContext.ProjectInstanceId); + writer.Write(parentProjectBuildEventContext.NodeId); + writer.Write(parentProjectBuildEventContext.ProjectContextId); + writer.Write(parentProjectBuildEventContext.TargetId); + writer.Write(parentProjectBuildEventContext.TaskId); + // added these in version 20 + writer.Write(parentProjectBuildEventContext.SubmissionId); + writer.Write(parentProjectBuildEventContext.ProjectInstanceId); + // added this in version 36 + writer.Write(parentProjectBuildEventContext.EvaluationId); } writer.WriteOptionalString(projectFile); @@ -402,6 +483,23 @@ internal override void WriteToStream(BinaryWriter writer) WriteCollection(writer, WarningsAsErrors); WriteCollection(writer, WarningsNotAsErrors); WriteCollection(writer, WarningsAsMessages); + + // Write OriginalBuildEventContext (version 3+ field) + if (originalBuildEventContext == null) + { + writer.Write((byte)0); + } + else + { + writer.Write((byte)1); + writer.Write(originalBuildEventContext.SubmissionId); + writer.Write(originalBuildEventContext.NodeId); + writer.Write(originalBuildEventContext.EvaluationId); + writer.Write(originalBuildEventContext.ProjectInstanceId); + writer.Write(originalBuildEventContext.ProjectContextId); + writer.Write(originalBuildEventContext.TargetId); + writer.Write(originalBuildEventContext.TaskId); + } } /// @@ -425,16 +523,28 @@ internal override void CreateFromStream(BinaryReader reader, int version) int targetId = reader.ReadInt32(); int taskId = reader.ReadInt32(); + var builder = + BuildEventContext.CreateInitial(BuildEventContext.InvalidSubmissionId, nodeId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); + if (version > 20) { int submissionId = reader.ReadInt32(); int projectInstanceId = reader.ReadInt32(); - parentProjectBuildEventContext = new BuildEventContext(submissionId, nodeId, projectInstanceId, projectContextId, targetId, taskId); - } - else - { - parentProjectBuildEventContext = new BuildEventContext(nodeId, targetId, projectContextId, taskId); + + builder = builder.WithSubmissionId(submissionId) + .WithProjectInstanceId(projectInstanceId); + + if (version >= 36) + { + int evaluationId = reader.ReadInt32(); + builder = builder.WithEvaluationId(evaluationId); + } } + + parentProjectBuildEventContext = builder.Build(); } projectFile = reader.ReadByte() == 0 ? null : reader.ReadString(); @@ -474,6 +584,32 @@ internal override void CreateFromStream(BinaryReader reader, int version) WarningsAsErrors = ReadStringSet(reader); WarningsNotAsErrors = ReadStringSet(reader); WarningsAsMessages = ReadStringSet(reader); + + // Read OriginalBuildEventContext (version 3+ field) + if (version >= 3) + { + if (reader.ReadByte() == 0) + { + originalBuildEventContext = null; + } + else + { + int submissionId = reader.ReadInt32(); + int nodeId = reader.ReadInt32(); + int evaluationId = reader.ReadInt32(); + int projectInstanceId = reader.ReadInt32(); + int projectContextId = reader.ReadInt32(); + int targetId = reader.ReadInt32(); + int taskId = reader.ReadInt32(); + + originalBuildEventContext = BuildEventContext.CreateInitial(submissionId, nodeId) + .WithEvaluationId(evaluationId) + .WithProjectInstanceId(projectInstanceId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); + } + } } private static void WriteCollection(BinaryWriter writer, ICollection? collection) @@ -522,6 +658,7 @@ private void SetDefaultsBeforeSerialization(StreamingContext sc) // Don't want to set the default before deserialization is completed to a new event context because // that would most likely be a lot of wasted allocations parentProjectBuildEventContext = null; + originalBuildEventContext = null; } [OnDeserialized] @@ -531,6 +668,11 @@ private void SetDefaultsAfterSerialization(StreamingContext sc) { parentProjectBuildEventContext = BuildEventContext.Invalid; } + + if (originalBuildEventContext == null) + { + originalBuildEventContext = BuildEventContext.Invalid; + } } #endregion diff --git a/src/Shared/BinaryReaderExtensions.cs b/src/Shared/BinaryReaderExtensions.cs index 9078401ba2f..c0b65c11bce 100644 --- a/src/Shared/BinaryReaderExtensions.cs +++ b/src/Shared/BinaryReaderExtensions.cs @@ -88,7 +88,12 @@ public static BuildEventContext ReadBuildEventContext(this BinaryReader reader) int projectInstanceId = reader.ReadInt32(); int evaluationId = reader.ReadInt32(); - var buildEventContext = new BuildEventContext(submissionId, nodeId, evaluationId, projectInstanceId, projectContextId, targetId, taskId); + var buildEventContext = BuildEventContext.CreateInitial(submissionId, nodeId) + .WithEvaluationId(evaluationId) + .WithProjectInstanceId(projectInstanceId) + .WithProjectContextId(projectContextId) + .WithTargetId(targetId) + .WithTaskId(taskId); return buildEventContext; } #endif