TeamCity.MSBuild.Logger/BuildEventManager.cs (140 lines of code) (raw):

namespace TeamCity.MSBuild.Logger { using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Microsoft.Build.Framework; // ReSharper disable once ClassNeverInstantiated.Global internal class BuildEventManager: IBuildEventManager { [NotNull] private readonly IStringService _stringService; private readonly IDictionary<string, int> _projectTargetKey = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private readonly IDictionary<string, int> _projectKey = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private readonly IDictionary<BuildEventContext, ProjectStartedEventMinimumFields> _projectStartedEvents = new Dictionary<BuildEventContext, ProjectStartedEventMinimumFields>(ComparerContextNodeId.Shared); private readonly IDictionary<BuildEventContext, TargetStartedEventMinimumFields> _targetStartedEvents = new Dictionary<BuildEventContext, TargetStartedEventMinimumFields>(ComparerContextNodeIdTargetId.Shared); private int _projectIncrementKey; public BuildEventManager( [NotNull] IStringService stringService) { _stringService = stringService ?? throw new ArgumentNullException(nameof(stringService)); } public void AddProjectStartedEvent(ProjectStartedEventArgs e, bool requireTimestamp) { if (e == null) throw new ArgumentNullException(nameof(e)); var projectStartedEvent = GetProjectStartedEvent(e.ParentProjectBuildEventContext); int projectIncrementKey; int entryPointKey; lock (_projectStartedEvents) { if (_projectStartedEvents.ContainsKey(e.BuildEventContext)) { return; } if (!_projectKey.TryGetValue(e.ProjectFile, out projectIncrementKey)) { _projectIncrementKey += 1; _projectKey.Add(e.ProjectFile, _projectIncrementKey); projectIncrementKey = _projectIncrementKey; } if (!_projectTargetKey.TryGetValue(e.ProjectFile, out entryPointKey)) { _projectTargetKey.Add(e.ProjectFile, 1); } else { _projectTargetKey[e.ProjectFile] = entryPointKey + 1; } } _projectStartedEvents.Add(e.BuildEventContext, new ProjectStartedEventMinimumFields(projectIncrementKey, entryPointKey, e, projectStartedEvent, requireTimestamp)); } public void AddTargetStartedEvent(TargetStartedEventArgs e, bool requireTimeStamp) { if (e == null) throw new ArgumentNullException(nameof(e)); if (_targetStartedEvents.ContainsKey(e.BuildEventContext)) { return; } _targetStartedEvents.Add(e.BuildEventContext, new TargetStartedEventMinimumFields(e, requireTimeStamp)); } public void SetErrorWarningFlagOnCallStack(BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); foreach (var projectCall in GetProjectCallStack(e)) { if (projectCall != null) { projectCall.ErrorInProject = true; } } } public IEnumerable<string> ProjectCallStackFromProject(BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); var projectStartedEvent = GetProjectStartedEvent(e); if (projectStartedEvent == null) { return Enumerable.Empty<string>(); } return ( from projectCall in GetProjectCallStack(e) select string.IsNullOrEmpty(projectCall.TargetNames) ? _stringService.FormatResourceString("ProjectStackWithTargetNames", projectCall.ProjectFile, projectCall.TargetNames, projectCall.FullProjectKey) : _stringService.FormatResourceString("ProjectStackWithDefaultTargets", projectCall.ProjectFile, projectCall.FullProjectKey)) .Reverse(); } public ProjectStartedEventMinimumFields GetProjectStartedEvent(BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); return _projectStartedEvents.TryGetValue(e, out var result) ? result : null; } public TargetStartedEventMinimumFields GetTargetStartedEvent(BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); return _targetStartedEvents.TryGetValue(e, out var result) ? result : null; } public void RemoveProjectStartedEvent(BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); var projectStartedEvent = GetProjectStartedEvent(e); if (projectStartedEvent == null || projectStartedEvent.ErrorInProject) { return; } _projectStartedEvents.Remove(e); } public void RemoveTargetStartedEvent(BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); var targetStartedEvent = GetTargetStartedEvent(e); if (targetStartedEvent == null || targetStartedEvent.ErrorInTarget) { return; } _targetStartedEvents.Remove(e); } public void Reset() { _projectTargetKey.Clear(); _projectKey.Clear(); _projectStartedEvents.Clear(); _targetStartedEvents.Clear(); _projectIncrementKey = 0; } [NotNull] private IEnumerable<ProjectStartedEventMinimumFields> GetProjectCallStack([NotNull] BuildEventContext e) { if (e == null) throw new ArgumentNullException(nameof(e)); var projectStartedEvent = GetProjectStartedEvent(e); if (projectStartedEvent == null) { yield break; } yield return projectStartedEvent; while (projectStartedEvent.ParentProjectStartedEvent != null) { projectStartedEvent = projectStartedEvent.ParentProjectStartedEvent; yield return projectStartedEvent; } } } }