// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #if FEATURE_FILE_TRACKER using System; using System.IO; using Microsoft.Build.Collections; using Microsoft.Build.Execution; using Microsoft.Build.Shared; #nullable disable namespace Microsoft.Build.BackEnd { /// /// Manages full tracking activation and suspension. /// internal class FullTracking : IDisposable { /// /// The default name of the MSBuild property to read for the relative path to the full tracking .tlog files. /// If this property isn't set in the project, full tracking is turned off. /// private const string FullTrackingDirectoryPropertyName = "MSBuildFullTrackingPath"; /// /// The full path to where full tracking .tlog files should be written. /// private string _tlogDirectory; /// /// A value indicating whether this instance is tracking a full tracking suspension /// (as opposed to activation). /// private TrackingMode _trackingMode; /// /// The name of the task as given to FileTracker.dll. /// private string _taskName; /// /// Initializes a new instance of the class. /// private FullTracking() { _trackingMode = TrackingMode.None; } /// /// The state of the object regarding whether it is actively tracking or suspending tracking. /// private enum TrackingMode { /// /// No tracking or suspension operation is in effect as a result of this instance. /// None, /// /// This instance has invoked full tracking. /// Active, /// /// This instance has suspended full tracking. /// Suspended, } /// /// Disposes the FullTracking object, causing full tracking to end, or resume, /// depending on how this object was created. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// Starts full tracking. /// /// taskLoggingContext.TargetLoggingContext.Target.Name /// taskNode.Name /// buildRequestEntry.ProjectRootDirectory /// buildRequestEntry.RequestConfiguration.Project.PropertiesToBuildWith /// /// An object that will stop full tracking when disposed. /// internal static IDisposable Track(string targetName, string taskName, string projectRootDirectory, PropertyDictionary projectProperties) { FullTracking tracking = new FullTracking(); ProjectPropertyInstance tlogRelativeDirectoryProperty = projectProperties[FullTrackingDirectoryPropertyName]; string tlogRelativeDirectoryValue = null; if (tlogRelativeDirectoryProperty != null) { tlogRelativeDirectoryValue = tlogRelativeDirectoryProperty.EvaluatedValue; } if (!String.IsNullOrEmpty(tlogRelativeDirectoryValue)) { tracking._taskName = GenerateUniqueTaskName(targetName, taskName); tracking._tlogDirectory = Path.Combine(projectRootDirectory, tlogRelativeDirectoryValue); InprocTrackingNativeMethods.StartTrackingContext(tracking._tlogDirectory, tracking._taskName); tracking._trackingMode = TrackingMode.Active; } return tracking; } /// /// Suspends full tracking. /// /// An object that will resume full tracking when disposed. internal static IDisposable Suspend() { FullTracking tracking = new FullTracking(); if (tracking._trackingMode == TrackingMode.Active) { InprocTrackingNativeMethods.SuspendTracking(); tracking._trackingMode = TrackingMode.Suspended; } return tracking; } /// /// Disposes the FullTracking object, causing full tracking to end, or resume, /// depending on how this object was created. /// protected virtual void Dispose(bool disposing) { if (disposing) { switch (_trackingMode) { case TrackingMode.Active: // Stop tracking InprocTrackingNativeMethods.WriteContextTLogs(_tlogDirectory, _taskName); InprocTrackingNativeMethods.EndTrackingContext(); break; case TrackingMode.Suspended: // Stop suspending tracking InprocTrackingNativeMethods.ResumeTracking(); break; default: // nothing to do here if we weren't actively tracking or suspended. break; } } } /// /// Gets the task name to pass to Tracker. /// private static string GenerateUniqueTaskName(string targetName, string taskName) { return "__FT__" + targetName + "-" + taskName; } } } #endif