| File: BackEnd\Components\Logging\TargetLoggingContext.cs | Web Access |
| Project: src\msbuild\src\Build\Microsoft.Build.csproj (Microsoft.Build) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Collections.Generic; using Microsoft.Build.Execution; using Microsoft.Build.Framework; using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem; #nullable disable namespace Microsoft.Build.BackEnd.Logging { /// <summary> /// A logging context for building a specific target within a project. /// </summary> internal class TargetLoggingContext : BuildLoggingContext { /// <summary> /// The project to which this target is attached. /// </summary> private ProjectLoggingContext _projectLoggingContext; /// <summary> /// The target being built. /// </summary> private ProjectTargetInstance _target; /// <summary> /// Creates a new target logging context from an existing project context and target. /// </summary> internal TargetLoggingContext(ProjectLoggingContext projectLoggingContext, string projectFullPath, ProjectTargetInstance target, string parentTargetName, TargetBuiltReason buildReason) : base(projectLoggingContext, CreateInitialContext(projectLoggingContext, projectFullPath, target, parentTargetName, buildReason)) { _projectLoggingContext = projectLoggingContext; _target = target; this.IsValid = true; } private static BuildEventContext CreateInitialContext(ProjectLoggingContext projectLoggingContext, string projectFullPath, ProjectTargetInstance target, string parentTargetName, TargetBuiltReason buildReason) { BuildEventContext buildEventContext = projectLoggingContext.LoggingService.LogTargetStarted( projectLoggingContext.BuildEventContext, target.Name, projectFullPath, target.Location.File, parentTargetName, buildReason); return buildEventContext; } /// <summary> /// Constructor used to support out-of-proc task host (proxy for in-proc logging service.) /// </summary> internal TargetLoggingContext(ILoggingService loggingService, BuildEventContext outOfProcContext) : base(loggingService, outOfProcContext, true) { this.IsValid = true; } /// <summary> /// Retrieves the project logging context. /// </summary> internal ProjectLoggingContext ProjectLoggingContext { get { return _projectLoggingContext; } } /// <summary> /// Retrieves the target. /// </summary> internal ProjectTargetInstance Target { get { return _target; } } /// <summary> /// Log that a target has finished /// </summary> internal void LogTargetBatchFinished(string projectFullPath, bool success, IEnumerable<TaskItem> targetOutputs) { this.CheckValidity(); TargetOutputItemsInstanceEnumeratorProxy targetOutputWrapper = null; // Only log target outputs if we are going to log a target finished event and the environment variable is set and the target outputs are not null if (!LoggingService.OnlyLogCriticalEvents && (LoggingService.EnableTargetOutputLogging || Traits.Instance.EnableTargetOutputLogging) && targetOutputs != null) { targetOutputWrapper = new TargetOutputItemsInstanceEnumeratorProxy(targetOutputs); } LoggingService.LogTargetFinished(BuildEventContext, _target.Name, projectFullPath, _target.Location.File, success, targetOutputWrapper); this.IsValid = false; } /// <summary> /// Log that a task is about to start /// </summary> internal TaskLoggingContext LogTaskBatchStarted(string projectFullPath, ProjectTargetInstanceChild task, string taskAssemblyLocation) { this.CheckValidity(); return new TaskLoggingContext(this, projectFullPath, task, taskAssemblyLocation); } /// <summary> /// An enumerable wrapper for items that clones items as they are requested, /// so that writes have no effect on the items. /// </summary> /// <remarks> /// This class is designed to be passed to loggers. /// The expense of copying items is only incurred if and when /// a logger chooses to enumerate over it. /// </remarks> internal class TargetOutputItemsInstanceEnumeratorProxy : IEnumerable<TaskItem> { /// <summary> /// Enumerable that this proxies /// </summary> private IEnumerable<TaskItem> _backingItems; /// <summary> /// Constructor /// </summary> /// <param name="backingItems">Enumerator this class should proxy</param> internal TargetOutputItemsInstanceEnumeratorProxy(IEnumerable<TaskItem> backingItems) { _backingItems = backingItems; } // For performance reasons we need to expose the raw items to BinaryLogger // as we know we're not going to mutate anything. This allows us to bypass DeepClone // for each item internal IEnumerable<TaskItem> BackingItems => _backingItems; /// <summary> /// Returns an enumerator that provides copies of the items /// in the backing store. /// Each dictionary entry has key of the item type and value of an ITaskItem. /// Type of the enumerator is imposed by backwards compatibility for ProjectStartedEvent. /// </summary> public IEnumerator<TaskItem> GetEnumerator() { foreach (TaskItem item in _backingItems) { yield return item.DeepClone(); } } /// <summary> /// Returns an enumerator that provides copies of the items /// in the backing store. /// </summary> IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } } } }