///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Reflection;
using JetBrains.Build.Omea.Util;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace JetBrains.Build.Omea.Infra
{
///
/// The resolved part of the task that sets up the appdomain and commences the execution.
/// Must be marshal-by-value.
/// Any execution exceptions are written into the under the id.
///
[Serializable]
public class ProbingTaskResolved
{
#region Init
public ProbingTaskResolved(Bag bag)
{
Bag = bag;
}
#endregion
#region Attributes
///
/// Gets or sets the property bag with the task parameters.
///
public Bag Bag { get; set; }
#endregion
#region Operations
public void Execute()
{
try
{
using(new AssemblyResolver(Bag.Get(AttributeName.AfxProbingDirectories), AppDomain.CurrentDomain))
ExecuteResolved();
}
catch(Exception ex)
{
SetException(ex);
}
}
///
/// Records the exceptions in the resolved executor.
/// Null on success.
///
public void SetException(Exception value)
{
Bag.Set(AttributeName.AfxException, value);
}
#endregion
#region Implementation
///
/// Executes under the assembly resolver.
///
private void ExecuteResolved()
{
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
ExecuteResolved_PreloadAssemblies();
ExecuteResolved_RunTask();
}
///
/// Preloads some assemblies into the current appdomain.
///
private void ExecuteResolved_PreloadAssemblies()
{
if(Bag.Contains(AttributeName.LoadAssemblies))
{
foreach(ITaskItem assemblyname in Bag.Get(AttributeName.LoadAssemblies))
Assembly.Load(assemblyname.ItemSpec);
}
}
///
/// Runs the resolved part of the task.
///
private void ExecuteResolved_RunTask()
{
// Load the resolved part DLL
Assembly assemblyResolved = Assembly.Load(ProbingTask.ResolvedPartAssemblyName);
if(assemblyResolved == null)
throw new InvalidOperationException(string.Format("Failed to load the assembly with the resolved parts of the task, assembly name: “{0}”.", ProbingTask.ResolvedPartAssemblyName));
// Create class
string sUnresolvedTaskName = Bag.GetString(AttributeName.AfxUnresolvedTaskName);
string sResolvedClassName = ProbingTask.ResolvedPartAssemblyName + ".Tasks." + sUnresolvedTaskName + "Resolved";
object oInstance = assemblyResolved.CreateInstance(sResolvedClassName);
if(oInstance == null)
throw new InvalidOperationException(string.Format("Failed to load the resolved class for the task “{0}” from the resolved assembly, expected name: “{1}”.", sUnresolvedTaskName, sResolvedClassName));
var oInstanceAsTask = oInstance as ITaskBaseResolved;
if(oInstanceAsTask == null)
throw new InvalidOperationException(string.Format("The resolved class “{1}” for the task “{0}” (instantiated as “{3}”) does not implement the required resolved task interface “{2}”.", sUnresolvedTaskName, sResolvedClassName, typeof(ITaskBaseResolved).AssemblyQualifiedName, oInstance.GetType().AssemblyQualifiedName));
Bag.Get(AttributeName.AfxLog).LogMessage(MessageImportance.Low, "Executing resolved part of the task, appdomain “{1}”, class “{0}”.", oInstance.GetType().AssemblyQualifiedName, AppDomain.CurrentDomain.FriendlyName);
// Set up and run!
oInstanceAsTask.Bag = Bag;
oInstanceAsTask.Execute();
}
///
/// Reports the unhandled exceptions in the appdomain.
///
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
SetException((args.ExceptionObject as Exception) ?? new Exception("Unidentified failure."));
}
#endregion
}
}