// 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