|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// THE ASSEMBLY BUILT FROM THIS SOURCE FILE HAS BEEN DEPRECATED FOR YEARS. IT IS BUILT ONLY TO PROVIDE
// BACKWARD COMPATIBILITY FOR API USERS WHO HAVE NOT YET MOVED TO UPDATED APIS. PLEASE DO NOT SEND PULL
// REQUESTS THAT CHANGE THIS FILE WITHOUT FIRST CHECKING WITH THE MAINTAINERS THAT THE FIX IS REQUIRED.
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using Microsoft.Build.Framework;
using Microsoft.Build.BuildEngine.Shared;
namespace Microsoft.Build.BuildEngine
{
/// <summary>
/// This class wraps BuildEventArgs and used for sending BuildEventArgs across the node boundary
/// </summary>
internal class NodeLoggingEvent
{
// Enumeration of logging event types, this is used to recreate the correct type on deserialization
private enum LoggingEventType
{
CustomEvent = 0,
BuildErrorEvent = 1,
BuildFinishedEvent = 2,
BuildMessageEvent = 3,
BuildStartedEvent = 4,
BuildWarningEvent = 5,
ProjectFinishedEvent = 6,
ProjectStartedEvent = 7,
TargetStartedEvent = 8,
TargetFinishedEvent = 9,
TaskStartedEvent = 10,
TaskFinishedEvent = 11,
TaskCommandLineEvent = 12
}
#region Constructors
/// <summary>
/// This new constructor is required for custom serialization
/// </summary>
internal NodeLoggingEvent()
{
}
/// <summary>
/// Create an instance of this class wrapping given BuildEventArgs
/// </summary>
internal NodeLoggingEvent(BuildEventArgs eventToLog)
{
this.e = eventToLog;
}
#endregion
#region Properties
/// <summary>
/// The BuildEventArgs wrapped by this class
/// </summary>
internal BuildEventArgs BuildEvent
{
get
{
return this.e;
}
}
/// <summary>
/// The ID of the central logger to which this event should be forwarded. By default
/// all regular non-forwarded events are sent to all loggers registered on the parent.
/// </summary>
internal virtual int LoggerId
{
get
{
return 0;
}
}
#endregion
#region CustomSerializationToStream
/// <summary>
/// Converts a BuildEventArg into its associated enumeration Id.
/// Any event which is a derrived event not in the predefined list will be
/// considered a custom event and use .net serialization
/// </summary>
private LoggingEventType GetLoggingEventId(BuildEventArgs eventArg)
{
Type eventType = eventArg.GetType();
if (eventType == typeof(BuildMessageEventArgs))
{
return LoggingEventType.BuildMessageEvent;
}
else if (eventType == typeof(TaskCommandLineEventArgs))
{
return LoggingEventType.TaskCommandLineEvent;
}
else if (eventType == typeof(ProjectFinishedEventArgs))
{
return LoggingEventType.ProjectFinishedEvent;
}
else if (eventType == typeof(ProjectStartedEventArgs))
{
return LoggingEventType.ProjectStartedEvent;
}
else if (eventType == typeof(TargetStartedEventArgs))
{
return LoggingEventType.TargetStartedEvent;
}
else if (eventType == typeof(TargetFinishedEventArgs))
{
return LoggingEventType.TargetFinishedEvent;
}
else if (eventType == typeof(TaskStartedEventArgs))
{
return LoggingEventType.TaskStartedEvent;
}
else if (eventType == typeof(TaskFinishedEventArgs))
{
return LoggingEventType.TaskFinishedEvent;
}
else if (eventType == typeof(BuildFinishedEventArgs))
{
return LoggingEventType.BuildFinishedEvent;
}
else if (eventType == typeof(BuildStartedEventArgs))
{
return LoggingEventType.BuildStartedEvent;
}
else if (eventType == typeof(BuildWarningEventArgs))
{
return LoggingEventType.BuildWarningEvent;
}
if (eventType == typeof(BuildErrorEventArgs))
{
return LoggingEventType.BuildErrorEvent;
}
else
{
return LoggingEventType.CustomEvent;
}
}
/// <summary>
/// Takes in a id (LoggingEventType as an int) and creates the correct specific logging class
/// </summary>
private BuildEventArgs GetBuildEventArgFromId(LoggingEventType id)
{
switch (id)
{
case LoggingEventType.BuildErrorEvent:
return new BuildErrorEventArgs(null, null, null, -1, -1, -1, -1, null, null, null);
case LoggingEventType.BuildFinishedEvent:
return new BuildFinishedEventArgs(null, null, false);
case LoggingEventType.BuildMessageEvent:
return new BuildMessageEventArgs(null, null, null, MessageImportance.Normal);
case LoggingEventType.BuildStartedEvent:
return new BuildStartedEventArgs(null, null);
case LoggingEventType.BuildWarningEvent:
return new BuildWarningEventArgs(null, null, null, -1, -1, -1, -1, null, null, null);
case LoggingEventType.ProjectFinishedEvent:
return new ProjectFinishedEventArgs(null, null, null, false);
case LoggingEventType.ProjectStartedEvent:
return new ProjectStartedEventArgs(-1, null, null, null, null, null, null, null);
case LoggingEventType.TargetStartedEvent:
return new TargetStartedEventArgs(null, null, null, null, null);
case LoggingEventType.TargetFinishedEvent:
return new TargetFinishedEventArgs(null, null, null, null, null, false);
case LoggingEventType.TaskStartedEvent:
return new TaskStartedEventArgs(null, null, null, null, null);
case LoggingEventType.TaskFinishedEvent:
return new TaskFinishedEventArgs(null, null, null, null, null, false);
case LoggingEventType.TaskCommandLineEvent:
return new TaskCommandLineEventArgs(null, null, MessageImportance.Normal);
default:
ErrorUtilities.VerifyThrow(false, "Should not get to the default of getBuildEventArgFromId ID:" + id);
return null;
}
}
internal virtual void WriteToStream(BinaryWriter writer, Hashtable loggingTypeCache)
{
LoggingEventType id = GetLoggingEventId(e);
writer.Write((byte)id);
if (id != LoggingEventType.CustomEvent)
{
if (!loggingTypeCache.ContainsKey(id))
{
Type eventType = e.GetType();
MethodInfo methodInfo = eventType.GetMethod("WriteToStream", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
loggingTypeCache.Add(id, methodInfo);
}
if (loggingTypeCache[id] != null)
{
((MethodInfo)loggingTypeCache[id]).Invoke(e, new object[] { writer });
}
else
{
// The customer serialization methods are not availiable, default to .net serialization
writer.BaseStream.Position--;
writer.Write((byte)0);
binaryFormatter.Serialize(writer.BaseStream, e);
}
}
else
{
writer.Write(e.GetType().Assembly.Location);
binaryFormatter.Serialize(writer.BaseStream, e);
}
}
internal virtual void CreateFromStream(BinaryReader reader, Hashtable loggingTypeCache)
{
LoggingEventType id = (LoggingEventType)reader.ReadByte();
if (LoggingEventType.CustomEvent != id)
{
e = GetBuildEventArgFromId(id);
if (!loggingTypeCache.Contains(id))
{
Type eventType = e.GetType();
MethodInfo methodInfo = eventType.GetMethod("CreateFromStream", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod);
loggingTypeCache.Add(id, methodInfo);
}
int packetVersion = (Environment.Version.Major * 10) + Environment.Version.Minor;
((MethodInfo)loggingTypeCache[id]).Invoke(e, new object[] { reader, packetVersion });
}
else
{
string fileLocation = reader.ReadString();
bool resolveAssembly = false;
lock (lockObject)
{
if (customEventsLoaded == null)
{
customEventsLoaded = new Hashtable(StringComparer.OrdinalIgnoreCase);
resolveAssembly = true;
}
else
{
if (!customEventsLoaded.Contains(fileLocation))
{
resolveAssembly = true;
}
}
// If we are to resolve the assembly add it to the list of assemblies resolved
if (resolveAssembly)
{
customEventsLoaded.Add(fileLocation, null);
}
}
if (resolveAssembly)
{
resolver = new TaskEngineAssemblyResolver();
resolver.InstallHandler();
resolver.Initialize(fileLocation);
}
try
{
e = (BuildEventArgs)binaryFormatter.Deserialize(reader.BaseStream);
}
finally
{
if (resolveAssembly)
{
resolver.RemoveHandler();
resolver = null;
}
}
}
}
#endregion
#region Data
// The actual event wrapped by this container class
private BuildEventArgs e;
// Just need one of each per app domain
private static BinaryFormatter binaryFormatter = new BinaryFormatter();
private TaskEngineAssemblyResolver resolver;
private static Hashtable customEventsLoaded;
private static object lockObject = new object();
#endregion
}
/// <summary>
/// This class is used to associate wrapped BuildEventArgs with a loggerId which
/// identifies which central logger this event should be delivered to.
/// </summary>
internal class NodeLoggingEventWithLoggerId : NodeLoggingEvent
{
#region Constructors
internal NodeLoggingEventWithLoggerId()
{
}
/// <summary>
/// Create a wrapper for a given event associated with a particular loggerId
/// </summary>
internal NodeLoggingEventWithLoggerId(BuildEventArgs eventToLog, int loggerId)
: base(eventToLog)
{
this.loggerId = loggerId;
}
#endregion
#region Properties
/// <summary>
/// The ID of the central logger to which this event should be forwarded
/// </summary>
internal override int LoggerId
{
get
{
return loggerId;
}
}
#endregion
#region CustomSerializationToStream
internal override void WriteToStream(BinaryWriter writer, Hashtable loggingTypeCache)
{
base.WriteToStream(writer, loggingTypeCache);
writer.Write((Int32)loggerId);
}
internal override void CreateFromStream(BinaryReader reader, Hashtable loggingTypeCache)
{
base.CreateFromStream(reader, loggingTypeCache);
loggerId = reader.ReadInt32();
}
#endregion
#region Data
// The id of the central logger to which this event should be forwarded
private int loggerId;
#endregion
}
}
|