diff --git a/dir.props b/dir.props index 3921a44c476..6513b304d0d 100644 --- a/dir.props +++ b/dir.props @@ -103,6 +103,7 @@ $(DefineConstants);FEATURE_APARTMENT_STATE $(DefineConstants);FEATURE_APM $(DefineConstants);FEATURE_APPDOMAIN + true $(DefineConstants);FEATURE_APPDOMAIN_UNHANDLED_EXCEPTION $(DefineConstants);FEATURE_ASSEMBLY_LOADFROM $(DefineConstants);FEATURE_ASSEMBLY_LOCATION @@ -122,13 +123,16 @@ $(DefineConstants);FEATURE_HANDLEREF $(DefineConstants);FEATURE_MEMORYSTREAM_GETBUFFER $(DefineConstants);FEATURE_OSVERSION + $(DefineConstants);FEATURE_PARALLEL_BUILD $(DefineConstants);FEATURE_REFLECTION_EMIT_DEBUG_INFO $(DefineConstants);FEATURE_REGISTRYHIVE_DYNDATA $(DefineConstants);FEATURE_RESOURCE_EXPOSURE $(DefineConstants);FEATURE_SECURITY_PERMISSIONS + $(DefineConstants);FEATURE_SECURITY_PRINCIPAL_WINDOWS $(DefineConstants);FEATURE_SPECIAL_FOLDERS true $(DefineConstants);FEATURE_SYSTEM_CONFIGURATION + true $(DefineConstants);FEATURE_THREAD_ABORT $(DefineConstants);FEATURE_THREAD_CULTURE $(DefineConstants);FEATURE_THREAD_PRIORITY diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index b1fb76c85e9..1f7985cdae1 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -310,6 +310,7 @@ internal static void SetEnvironment(IDictionary newEnvironment) /// internal static long GenerateHostHandshakeFromBase(long baseHandshake, long clientHandshake) { +#if FEATURE_SECURITY_PRINCIPAL_WINDOWS // If we are running in elevated privs, we will only accept a handshake from an elevated process as well. WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); @@ -328,6 +329,7 @@ internal static long GenerateHostHandshakeFromBase(long baseHandshake, long clie baseHandshake = ~baseHandshake; } } +#endif // Mask out the first byte. That's because old // builds used a single, non zero initial byte, diff --git a/src/Shared/FrameworkLocationHelper.cs b/src/Shared/FrameworkLocationHelper.cs index 8899d52cdbd..28650c7a097 100644 --- a/src/Shared/FrameworkLocationHelper.cs +++ b/src/Shared/FrameworkLocationHelper.cs @@ -14,7 +14,9 @@ using Microsoft.Build.Evaluation; using Microsoft.Win32; +#if FEATURE_SYSTEM_CONFIGURATION using PropertyElement = Microsoft.Build.Evaluation.ToolsetElement.PropertyElement; +#endif using System.Reflection; using System.Runtime.InteropServices; diff --git a/src/Shared/LogMessagePacketBase.cs b/src/Shared/LogMessagePacketBase.cs index 0b6107eac40..7fa9f0b4c6e 100644 --- a/src/Shared/LogMessagePacketBase.cs +++ b/src/Shared/LogMessagePacketBase.cs @@ -14,7 +14,9 @@ using Microsoft.Build.Framework; using Microsoft.Build.BackEnd; +#if FEATURE_APPDOMAIN using TaskEngineAssemblyResolver = Microsoft.Build.BackEnd.Logging.TaskEngineAssemblyResolver; +#endif namespace Microsoft.Build.Shared { @@ -136,10 +138,12 @@ private static int GetDefaultPacketVersion() /// private static HashSet s_customEventsLoaded = new HashSet(StringComparer.OrdinalIgnoreCase); +#if FEATURE_APPDOMAIN /// /// The resolver used to load custom event types. /// private static TaskEngineAssemblyResolver s_resolver; +#endif /// /// The object used to synchronize access to shared data. @@ -389,12 +393,14 @@ internal void ReadFromStream(INodePacketTranslator translator) } } +#if FEATURE_APPDOMAIN if (resolveAssembly) { s_resolver = new TaskEngineAssemblyResolver(); s_resolver.InstallHandler(); s_resolver.Initialize(fileLocation); } +#endif try { @@ -404,11 +410,13 @@ internal void ReadFromStream(INodePacketTranslator translator) } finally { +#if FEATURE_APPDOMAIN if (resolveAssembly) { s_resolver.RemoveHandler(); s_resolver = null; } +#endif } } diff --git a/src/Shared/TaskEngineAssemblyResolver.cs b/src/Shared/TaskEngineAssemblyResolver.cs index 96c3871d960..2209b117bac 100644 --- a/src/Shared/TaskEngineAssemblyResolver.cs +++ b/src/Shared/TaskEngineAssemblyResolver.cs @@ -15,9 +15,7 @@ namespace Microsoft.Build.BackEnd.Logging /// This is a helper class to install an AssemblyResolver event handler in whatever AppDomain this class is created in. /// internal class TaskEngineAssemblyResolver -#if FEATURE_APPDOMAIN : MarshalByRefObject -#endif { /// /// This public default constructor is needed so that instances of this class can be created by NDP. @@ -114,7 +112,6 @@ internal Assembly ResolveAssembly(object sender, ResolveEventArgs args) return null; } -#if FEATURE_APPDOMAIN /// /// Overridden to give this class infinite lease time. Otherwise we end up with a limited /// lease (5 minutes I think) and instances can expire if they take long time processing. @@ -125,7 +122,6 @@ public override object InitializeLifetimeService() // null means infinite lease time return null; } -#endif // path to the task assembly, but only if it's loaded using LoadFrom. If it's loaded with Load, this is null. private string _taskAssemblyFile = null; diff --git a/src/Shared/TaskHostConfiguration.cs b/src/Shared/TaskHostConfiguration.cs index 1ab3294c8a7..0f5f93862c6 100644 --- a/src/Shared/TaskHostConfiguration.cs +++ b/src/Shared/TaskHostConfiguration.cs @@ -15,6 +15,7 @@ using System.Text; using Microsoft.Build.Shared; +using System.Reflection; namespace Microsoft.Build.BackEnd { @@ -49,10 +50,12 @@ internal class TaskHostConfiguration : INodePacket /// private CultureInfo _uiCulture = CultureInfo.CurrentUICulture; +#if FEATURE_APPDOMAIN /// /// The AppDomainSetup that we may want to use on AppDomainIsolated tasks. /// private AppDomainSetup _appDomainSetup; +#endif /// /// Line number where the instance of this task is defined. @@ -79,10 +82,14 @@ internal class TaskHostConfiguration : INodePacket /// private string _taskName; +#if FEATURE_ASSEMBLY_LOADFROM /// /// Location of the assembly containing the task to be executed. /// private string _taskLocation; +#else + private AssemblyName _taskAssemblyName; +#endif /// /// The set of parameters to apply to the task prior to execution. @@ -112,18 +119,26 @@ public TaskHostConfiguration IDictionary buildProcessEnvironment, CultureInfo culture, CultureInfo uiCulture, +#if FEATURE_APPDOMAIN AppDomainSetup appDomainSetup, +#endif int lineNumberOfTask, int columnNumberOfTask, string projectFileOfTask, bool continueOnError, string taskName, +#if FEATURE_ASSEMBLY_LOADFROM string taskLocation, +#else + AssemblyName taskAssemblyName, +#endif IDictionary taskParameters ) { ErrorUtilities.VerifyThrowInternalLength(taskName, "taskName"); +#if FEATURE_ASSEMBLY_LOADFROM ErrorUtilities.VerifyThrowInternalLength(taskLocation, "taskLocation"); +#endif _nodeId = nodeId; _startupDirectory = startupDirectory; @@ -140,13 +155,19 @@ public TaskHostConfiguration _culture = culture; _uiCulture = uiCulture; +#if FEATURE_ASSEMBLY_LOADFROM _appDomainSetup = appDomainSetup; +#endif _lineNumberOfTask = lineNumberOfTask; _columnNumberOfTask = columnNumberOfTask; _projectFileOfTask = projectFileOfTask; _continueOnError = continueOnError; _taskName = taskName; +#if FEATURE_ASSEMBLY_LOADFROM _taskLocation = taskLocation; +#else + _taskAssemblyName = taskAssemblyName; +#endif if (taskParameters != null) { @@ -216,6 +237,7 @@ public CultureInfo UICulture { return _uiCulture; } } +#if FEATURE_APPDOMAIN /// /// The AppDomain configuration bytes that we may want to use to initialize /// AppDomainIsolated tasks. @@ -226,6 +248,7 @@ public AppDomainSetup AppDomainSetup get { return _appDomainSetup; } } +#endif /// /// Line number where the instance of this task is defined. @@ -277,6 +300,7 @@ public string TaskName { return _taskName; } } +#if FEATURE_ASSEMBLY_LOADFROM /// /// Path to the assembly to load the task from. /// @@ -286,6 +310,7 @@ public string TaskLocation get { return _taskLocation; } } +#endif /// /// Parameters to set on the instantiated task prior to execution. @@ -325,7 +350,9 @@ public void Translate(INodePacketTranslator translator) translator.Translate(ref _columnNumberOfTask); translator.Translate(ref _projectFileOfTask); translator.Translate(ref _taskName); +#if FEATURE_ASSEMBLY_LOADFROM translator.Translate(ref _taskLocation); +#endif translator.TranslateDictionary(ref _taskParameters, StringComparer.OrdinalIgnoreCase, TaskParameter.FactoryForDeserialization); translator.Translate(ref _continueOnError); } diff --git a/src/Shared/TaskLoader.cs b/src/Shared/TaskLoader.cs index 6a44898959f..6bcadac14af 100644 --- a/src/Shared/TaskLoader.cs +++ b/src/Shared/TaskLoader.cs @@ -46,15 +46,30 @@ internal static bool IsTaskClass(Type type, object unused) /// /// Creates an ITask instance and returns it. /// - internal static ITask CreateTask(LoadedType loadedType, string taskName, string taskLocation, int taskLine, int taskColumn, LogError logError, AppDomainSetup appDomainSetup, bool isOutOfProc, out AppDomain taskAppDomain) + internal static ITask CreateTask(LoadedType loadedType, string taskName, string taskLocation, int taskLine, int taskColumn, LogError logError +#if FEATURE_APPDOMAIN + , AppDomainSetup appDomainSetup +#endif + , bool isOutOfProc +#if FEATURE_APPDOMAIN + , out AppDomain taskAppDomain +#endif + ) { +#if FEATURE_APPDOMAIN bool separateAppDomain = loadedType.HasLoadInSeparateAppDomainAttribute(); +#else + bool separateAppDomain = false; +#endif s_resolverLoadedType = null; +#if FEATURE_APPDOMAIN taskAppDomain = null; +#endif ITask taskInstanceInOtherAppDomain = null; try { +#if FEATURE_APPDOMAIN if (separateAppDomain) { if (!loadedType.Type.GetTypeInfo().IsMarshalByRef) @@ -109,12 +124,14 @@ internal static ITask CreateTask(LoadedType loadedType, string taskName, string } } else +#endif { // perf improvement for the same appdomain case - we already have the type object // and don't want to go through reflection to recreate it from the name. return (ITask)Activator.CreateInstance(loadedType.Type); } +#if FEATURE_APPDOMAIN if (loadedType.Assembly.AssemblyFile != null) { taskInstanceInOtherAppDomain = (ITask)taskAppDomain.CreateInstanceFromAndUnwrap(loadedType.Assembly.AssemblyFile, loadedType.Type.FullName); @@ -146,18 +163,22 @@ internal static ITask CreateTask(LoadedType loadedType, string taskName, string } return taskInstanceInOtherAppDomain; +#endif } finally { +#if FEATURE_APPDOMAIN // Don't leave appdomains open if (taskAppDomain != null && taskInstanceInOtherAppDomain == null) { AppDomain.Unload(taskAppDomain); RemoveAssemblyResolver(); } +#endif } } +#if FEATURE_APPDOMAIN /// /// This is a resolver to help created AppDomains when they are unable to load an assembly into their domain we will help /// them succeed by providing the already loaded one in the currentdomain so that they can derive AssemblyName info from it @@ -187,5 +208,6 @@ internal static void RemoveAssemblyResolver() s_resolverLoadedType = null; } } +#endif } } \ No newline at end of file diff --git a/src/Shared/TaskLoggingHelper.cs b/src/Shared/TaskLoggingHelper.cs index 62ebdf75d55..a0c958b5a89 100644 --- a/src/Shared/TaskLoggingHelper.cs +++ b/src/Shared/TaskLoggingHelper.cs @@ -7,8 +7,10 @@ using System.IO; using System.Resources; using System.Text; +#if FEATURE_APPDOMAIN using System.Runtime.Remoting.Lifetime; using System.Runtime.Remoting; +#endif using Microsoft.Build.Framework; using Microsoft.Build.Shared; @@ -64,12 +66,14 @@ public TaskLoggingHelper(IBuildEngine buildEngine, string taskName) #region Properties +#if FEATURE_APPDOMAIN /// /// A client sponsor is a class /// which will respond to a lease renewal request and will /// increase the lease time allowing the object to stay in memory /// private ClientSponsor _sponsor; +#endif // We have to pass an instance of ITask to BuildEngine, and since we call into the engine from this class we // need to store the actual task instance. diff --git a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs index 8e95fa1d47b..a7a51e32ed4 100644 --- a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs +++ b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildManager.cs @@ -1626,8 +1626,10 @@ private NodeConfiguration GetNodeConfiguration() ( -1, /* must be assigned by the NodeManager */ _buildParameters, - remoteLoggers.ToArray(), - AppDomain.CurrentDomain.SetupInformation + remoteLoggers.ToArray() +#if FEATURE_APPDOMAIN + , AppDomain.CurrentDomain.SetupInformation +#endif ); } diff --git a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs index ca6ba797ded..4b137674259 100644 --- a/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs +++ b/src/XMakeBuildEngine/BackEnd/BuildManager/BuildParameters.cs @@ -29,6 +29,7 @@ namespace Microsoft.Build.Execution { + using System.Diagnostics; using Utilities = Microsoft.Build.Internal.Utilities; /// @@ -811,6 +812,7 @@ internal ProjectRootElementCache ProjectRootElementCache set; } +#if FEATURE_APPDOMAIN /// /// Information for configuring child AppDomains. /// @@ -819,6 +821,7 @@ internal AppDomainSetup AppDomainSetup get; set; } +#endif /// /// (for diagnostic use) Whether or not this is out of proc @@ -1002,7 +1005,11 @@ private void FindMSBuildExe() } // Use the default location of the directory from which the engine was loaded. +#if FEATURE_APPDOMAIN path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MSBuild.exe"); +#else + path = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName); +#endif if (path != null && CheckMSBuildExeExistsAt(path)) { _nodeExeLocation = path; @@ -1025,6 +1032,7 @@ private void FindMSBuildExe() } } +#if FEATURE_APPDOMAIN // Search in the location of any assemblies we have loaded. foreach (System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { @@ -1056,6 +1064,7 @@ private void FindMSBuildExe() } } } +#endif // Search in the framework directory. Checks the COMPLUS_INSTALL_ROOT among other things. path = FrameworkLocationHelper.PathToDotNetFrameworkV40; diff --git a/src/XMakeBuildEngine/BackEnd/Components/BuildComponentFactoryCollection.cs b/src/XMakeBuildEngine/BackEnd/Components/BuildComponentFactoryCollection.cs index 632714e8451..6a8e22307b7 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/BuildComponentFactoryCollection.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/BuildComponentFactoryCollection.cs @@ -66,8 +66,10 @@ public void RegisterDefaultFactories() _componentEntriesByType[BuildComponentType.TaskHostNodeManager] = new BuildComponentEntry(BuildComponentType.TaskHostNodeManager, TaskHostNodeManager.CreateComponent, CreationPattern.Singleton); _componentEntriesByType[BuildComponentType.InProcNodeProvider] = new BuildComponentEntry(BuildComponentType.InProcNodeProvider, NodeProviderInProc.CreateComponent, CreationPattern.Singleton); +#if FEATURE_APPDOMAIN _componentEntriesByType[BuildComponentType.OutOfProcNodeProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcNodeProvider, NodeProviderOutOfProc.CreateComponent, CreationPattern.Singleton); _componentEntriesByType[BuildComponentType.OutOfProcTaskHostNodeProvider] = new BuildComponentEntry(BuildComponentType.OutOfProcTaskHostNodeProvider, NodeProviderOutOfProcTaskHost.CreateComponent, CreationPattern.Singleton); +#endif // PropertyCache, // RemoteNodeProvider, diff --git a/src/XMakeBuildEngine/BackEnd/Components/Communications/LogMessagePacket.cs b/src/XMakeBuildEngine/BackEnd/Components/Communications/LogMessagePacket.cs index d87faf474a0..07ae6abbbd4 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/Communications/LogMessagePacket.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/Communications/LogMessagePacket.cs @@ -14,7 +14,9 @@ using Microsoft.Build.Framework; using Microsoft.Build.Shared; using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem; +#if FEATURE_APPDOMAIN using TaskEngineAssemblyResolver = Microsoft.Build.BackEnd.Logging.TaskEngineAssemblyResolver; +#endif namespace Microsoft.Build.BackEnd { diff --git a/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskBuilder.cs b/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskBuilder.cs index c0e6e89df5a..1a02d1701aa 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskBuilder.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskBuilder.cs @@ -303,7 +303,11 @@ private async Task ExecuteTask(TaskExecutionMode mode, Lookup lo if (_taskNode != null) { taskHost = new TaskHost(_componentHost, _buildRequestEntry, _targetChildInstance.Location, _targetBuilderCallback); - _taskExecutionHost.InitializeForTask(taskHost, _targetLoggingContext, _buildRequestEntry.RequestConfiguration.Project, _taskNode.Name, _taskNode.Location, _taskHostObject, _continueOnError != ContinueOnError.ErrorAndStop, taskHost.AppDomainSetup, taskHost.IsOutOfProc, _cancellationToken); + _taskExecutionHost.InitializeForTask(taskHost, _targetLoggingContext, _buildRequestEntry.RequestConfiguration.Project, _taskNode.Name, _taskNode.Location, _taskHostObject, _continueOnError != ContinueOnError.ErrorAndStop, +#if FEATURE_APPDOMAIN + taskHost.AppDomainSetup, +#endif + taskHost.IsOutOfProc, _cancellationToken); } List taskParameterValues = CreateListOfParameterValues(); diff --git a/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskHost.cs b/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskHost.cs index bc46cfe3d4f..34acd2a405c 100644 --- a/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskHost.cs +++ b/src/XMakeBuildEngine/BackEnd/Components/RequestBuilder/TaskHost.cs @@ -9,8 +9,10 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; +#if FEATURE_APPDOMAIN using System.Runtime.Remoting.Lifetime; using System.Runtime.Remoting; +#endif using System.Threading; using System.Text; using Microsoft.Build.Framework; @@ -82,12 +84,14 @@ internal class TaskHost : /// private object _callbackMonitor; +#if FEATURE_APPDOMAIN /// /// A client sponsor is a class /// which will respond to a lease renewal request and will /// increase the lease time allowing the object to stay in memory /// private ClientSponsor _sponsor; +#endif /// /// Legacy continue on error value per batch exposed via IBuildEngine @@ -214,6 +218,7 @@ internal TaskLoggingContext LoggingContext { _taskLoggingContext = value; } } +#if FEATURE_APPDOMAIN /// /// For configuring child AppDomains. /// @@ -224,6 +229,7 @@ internal AppDomainSetup AppDomainSetup return _host.BuildParameters.AppDomainSetup; } } +#endif /// /// Whether or not this is out of proc. diff --git a/src/XMakeBuildEngine/BackEnd/Node/InProcNode.cs b/src/XMakeBuildEngine/BackEnd/Node/InProcNode.cs index 845a50361c3..145b3949dbc 100644 --- a/src/XMakeBuildEngine/BackEnd/Node/InProcNode.cs +++ b/src/XMakeBuildEngine/BackEnd/Node/InProcNode.cs @@ -513,8 +513,10 @@ private void HandleNodeConfiguration(NodeConfiguration configuration) _componentHost.BuildParameters.NodeId = configuration.NodeId; _shutdownException = null; +#if FEATURE_APPDOMAIN // And the AppDomainSetup _componentHost.BuildParameters.AppDomainSetup = configuration.AppDomainSetup; +#endif // Declare in-proc _componentHost.BuildParameters.IsOutOfProc = false; diff --git a/src/XMakeBuildEngine/BackEnd/Node/NodeConfiguration.cs b/src/XMakeBuildEngine/BackEnd/Node/NodeConfiguration.cs index 4abf13326d6..26b8d890600 100644 --- a/src/XMakeBuildEngine/BackEnd/Node/NodeConfiguration.cs +++ b/src/XMakeBuildEngine/BackEnd/Node/NodeConfiguration.cs @@ -34,10 +34,12 @@ internal class NodeConfiguration : INodePacket /// private BuildParameters _buildParameters; +#if FEATURE_APPDOMAIN /// /// The app domain information needed for setting up AppDomain-isolated tasks. /// private AppDomainSetup _appDomainSetup; +#endif /// /// The forwarding loggers to use. @@ -55,14 +57,18 @@ public NodeConfiguration ( int nodeId, BuildParameters buildParameters, - LoggerDescription[] forwardingLoggers, - AppDomainSetup appDomainSetup + LoggerDescription[] forwardingLoggers +#if FEATURE_APPDOMAIN + , AppDomainSetup appDomainSetup +#endif ) { _nodeId = nodeId; _buildParameters = buildParameters; _forwardingLoggers = forwardingLoggers; +#if FEATURE_APPDOMAIN _appDomainSetup = appDomainSetup; +#endif } /// @@ -106,6 +112,7 @@ public LoggerDescription[] LoggerDescriptions { return _forwardingLoggers; } } +#if FEATURE_APPDOMAIN /// /// Retrieves the app domain setup information. /// @@ -115,6 +122,7 @@ public AppDomainSetup AppDomainSetup get { return _appDomainSetup; } } +#endif #region INodePacket Members @@ -162,7 +170,11 @@ internal static INodePacket FactoryForDeserialization(INodePacketTranslator tran /// internal NodeConfiguration Clone() { - return new NodeConfiguration(_nodeId, _buildParameters, _forwardingLoggers, _appDomainSetup); + return new NodeConfiguration(_nodeId, _buildParameters, _forwardingLoggers +#if FEATURE_APPDOMAIN + , _appDomainSetup +#endif + ); } } } diff --git a/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/AddInParts/ITaskExecutionHost.cs b/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/AddInParts/ITaskExecutionHost.cs index 1193be9d244..0ae715f2007 100644 --- a/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/AddInParts/ITaskExecutionHost.cs +++ b/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/AddInParts/ITaskExecutionHost.cs @@ -67,7 +67,11 @@ bool LogTaskInputs /// /// Initialize the host with the objects required to communicate with the host process. /// - void InitializeForTask(IBuildEngine2 buildEngine, TargetLoggingContext loggingContext, ProjectInstance projectInstance, string taskName, ElementLocation taskLocation, ITaskHost taskHost, bool continueOnError, AppDomainSetup appDomainSetup, bool isOutOfProc, CancellationToken cancellationToken); + void InitializeForTask(IBuildEngine2 buildEngine, TargetLoggingContext loggingContext, ProjectInstance projectInstance, string taskName, ElementLocation taskLocation, ITaskHost taskHost, bool continueOnError, +#if FEATURE_APPDOMAIN + AppDomainSetup appDomainSetup, +#endif + bool isOutOfProc, CancellationToken cancellationToken); /// /// Ask the task host to find its task in the registry and get it ready for initializing the batch diff --git a/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/TaskExecutionHost.cs b/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/TaskExecutionHost.cs index 051fe2f0d50..51950c7e666 100644 --- a/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/TaskExecutionHost.cs +++ b/src/XMakeBuildEngine/BackEnd/TaskExecutionHost/TaskExecutionHost.cs @@ -23,7 +23,9 @@ using Microsoft.Build.BackEnd.Logging; using System.Globalization; using System.Reflection; +#if FEATURE_APPDOMAIN using System.Runtime.Remoting; +#endif using TaskItem = Microsoft.Build.Execution.ProjectItemInstance.TaskItem; @@ -52,10 +54,12 @@ internal class TaskExecutionHost : ITaskExecutionHost, IDisposable /// private bool _logTaskInputs; +#if FEATURE_APPDOMAIN /// /// Resolver to assist in resolving types when a new appdomain is created /// private TaskEngineAssemblyResolver _resolver; +#endif /// /// The interface used to call back into the build engine. @@ -234,6 +238,7 @@ internal TaskFactoryWrapper _UNITTESTONLY_TaskFactoryWrapper } } +#if FEATURE_APPDOMAIN /// /// App domain configuration. /// @@ -242,6 +247,7 @@ internal AppDomainSetup AppDomainSetup get; set; } +#endif /// /// Whether or not this is out-of-proc. @@ -266,7 +272,11 @@ public virtual void Dispose() /// /// Initialize to run a specific task. /// - void ITaskExecutionHost.InitializeForTask(IBuildEngine2 buildEngine, TargetLoggingContext loggingContext, ProjectInstance projectInstance, string taskName, ElementLocation taskLocation, ITaskHost taskHost, bool continueOnError, AppDomainSetup appDomainSetup, bool isOutOfProc, CancellationToken cancellationToken) + void ITaskExecutionHost.InitializeForTask(IBuildEngine2 buildEngine, TargetLoggingContext loggingContext, ProjectInstance projectInstance, string taskName, ElementLocation taskLocation, ITaskHost taskHost, bool continueOnError, +#if FEATURE_APPDOMAIN + AppDomainSetup appDomainSetup, +#endif + bool isOutOfProc, CancellationToken cancellationToken) { _buildEngine = buildEngine; _projectInstance = projectInstance; @@ -277,7 +287,9 @@ void ITaskExecutionHost.InitializeForTask(IBuildEngine2 buildEngine, TargetLoggi _taskHost = taskHost; _continueOnError = continueOnError; _taskExecutionIdle.Set(); +#if FEATURE_APPDOMAIN this.AppDomainSetup = appDomainSetup; +#endif this.IsOutOfProc = isOutOfProc; } @@ -332,6 +344,7 @@ bool ITaskExecutionHost.InitializeForBatch(TaskLoggingContext loggingContext, It return false; } +#if FEATURE_APPDOMAIN // If the task assembly is loaded into a separate AppDomain using LoadFrom, then we have a problem // to solve - when the task class Type is marshalled back into our AppDomain, it's not just transferred // here. Instead, NDP will try to Load (not LoadFrom!) the task assembly into our AppDomain, and since @@ -343,6 +356,7 @@ bool ITaskExecutionHost.InitializeForBatch(TaskLoggingContext loggingContext, It _resolver.Initialize(_taskFactoryWrapper.TaskFactoryLoadedType.Assembly.AssemblyFile); _resolver.InstallHandler(); } +#endif // We instantiate a new task object for each batch _taskInstance = InstantiateTask(taskIdentityParameters); @@ -577,11 +591,13 @@ void ITaskExecutionHost.CleanupForBatch() /// void ITaskExecutionHost.CleanupForTask() { +#if FEATURE_APPDOMAIN if (_resolver != null) { _resolver.RemoveHandler(); _resolver = null; } +#endif _taskFactoryWrapper = null; @@ -996,7 +1012,11 @@ private ITask InstantiateTask(IDictionary taskIdentityParameters AssemblyTaskFactory assemblyTaskFactory = _taskFactoryWrapper.TaskFactory as AssemblyTaskFactory; if (assemblyTaskFactory != null) { - task = assemblyTaskFactory.CreateTaskInstance(_taskLocation, _taskLoggingContext, _buildComponentHost, taskIdentityParameters, this.AppDomainSetup, this.IsOutOfProc); + task = assemblyTaskFactory.CreateTaskInstance(_taskLocation, _taskLoggingContext, _buildComponentHost, taskIdentityParameters, +#if FEATURE_APPDOMAIN + this.AppDomainSetup, +#endif + this.IsOutOfProc); } else { diff --git a/src/XMakeBuildEngine/Debugger/DebuggerManager.cs b/src/XMakeBuildEngine/Debugger/DebuggerManager.cs index 44ee479553a..636ffb5b93d 100644 --- a/src/XMakeBuildEngine/Debugger/DebuggerManager.cs +++ b/src/XMakeBuildEngine/Debugger/DebuggerManager.cs @@ -9,7 +9,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +#if FEATURE_DEBUGGER using System.Diagnostics.SymbolStore; +#endif using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -78,10 +80,12 @@ public static class DebuggerManager /// private static MethodInfo s_islandCallback; +#if FEATURE_DEBUGGER /// /// Cached mapping of file path to symbol store documents /// private static Dictionary s_sources = new Dictionary(StringComparer.OrdinalIgnoreCase); +#endif /// /// The single dynamic module used. @@ -362,6 +366,7 @@ private static void CreateDynamicModule() // of debuggable reflection-emit. ErrorUtilities.VerifyThrow(s_dynamicModule == null, "Already emitted"); +#if FEATURE_DEBUGGER // In a later release, this could be changed to use LightweightCodeGen (DynamicMethod instead of AssemblyBuilder); // currently they don't support sequence points, so they can't be debugged in the normal way AssemblyBuilder assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("msbuild"), AssemblyBuilderAccess.Run); @@ -382,6 +387,7 @@ private static void CreateDynamicModule() s_dynamicModule = assembly.DefineDynamicModule(name, true /* track debug information */); #else s_dynamicModule = assembly.DefineDynamicModule(name); +#endif #endif } @@ -436,6 +442,7 @@ private static string CreateIsland(TypeBuilder typeBuilder, DebuggerState state) // } ILGenerator generator = method.GetILGenerator(); +#if FEATURE_DEBUGGER ISymbolDocumentWriter source; if (!s_sources.TryGetValue(state.Location.File, out source)) { @@ -453,6 +460,7 @@ private static string CreateIsland(TypeBuilder typeBuilder, DebuggerState state) generator.EmitCall(OpCodes.Call, s_islandCallback /* method */, null /* no opt params */); generator.Emit(OpCodes.Ret); // Return from state +#endif return method.Name; } diff --git a/src/XMakeBuildEngine/Definition/ToolsetReader.cs b/src/XMakeBuildEngine/Definition/ToolsetReader.cs index 99154c20075..8b52c368e47 100644 --- a/src/XMakeBuildEngine/Definition/ToolsetReader.cs +++ b/src/XMakeBuildEngine/Definition/ToolsetReader.cs @@ -88,7 +88,11 @@ internal abstract class ToolsetReader /// internal static string ReadAllToolsets(Dictionary toolsets, PropertyDictionary environmentProperties, PropertyDictionary globalProperties, ToolsetDefinitionLocations locations) { - return ReadAllToolsets(toolsets, null, null, environmentProperties, globalProperties, locations); + return ReadAllToolsets(toolsets, null, +#if FEATURE_SYSTEM_CONFIGURATION + null, +#endif + environmentProperties, globalProperties, locations); } /// @@ -99,7 +103,9 @@ internal static string ReadAllToolsets ( Dictionary toolsets, ToolsetRegistryReader registryReader, +#if FEATURE_SYSTEM_CONFIGURATION ToolsetConfigurationReader configurationReader, +#endif PropertyDictionary environmentProperties, PropertyDictionary globalProperties, ToolsetDefinitionLocations locations @@ -116,6 +122,7 @@ ToolsetDefinitionLocations locations string overrideTasksPathFromConfiguration = null; string defaultOverrideToolsVersionFromConfiguration = null; +#if FEATURE_SYSTEM_CONFIGURATION if ((locations & ToolsetDefinitionLocations.ConfigurationFile) == ToolsetDefinitionLocations.ConfigurationFile) { @@ -139,6 +146,7 @@ ToolsetDefinitionLocations locations out defaultOverrideToolsVersionFromConfiguration); } } +#endif string defaultToolsVersionFromRegistry = null; string overrideTasksPathFromRegistry = null; diff --git a/src/XMakeBuildEngine/Evaluation/IntrinsicFunctions.cs b/src/XMakeBuildEngine/Evaluation/IntrinsicFunctions.cs index d2ec682e843..33fd705c901 100644 --- a/src/XMakeBuildEngine/Evaluation/IntrinsicFunctions.cs +++ b/src/XMakeBuildEngine/Evaluation/IntrinsicFunctions.cs @@ -14,8 +14,10 @@ using Microsoft.Build.Shared; using Microsoft.Win32; +#if FEATURE_APPDOMAIN // Needed for DoesTaskHostExistForParameters using NodeProviderOutOfProcTaskHost = Microsoft.Build.BackEnd.NodeProviderOutOfProcTaskHost; +#endif namespace Microsoft.Build.Evaluation { @@ -352,12 +354,14 @@ internal static bool DoesTaskHostExist(string runtime, string architecture) parameters.Add(XMakeAttributes.architecture, architecture); TaskHostContext desiredContext = CommunicationsUtilities.GetTaskHostContext(parameters); +#if FEATURE_APPDOMAIN string taskHostLocation = NodeProviderOutOfProcTaskHost.GetMSBuildLocationFromHostContext(desiredContext); if (taskHostLocation != null && FileUtilities.FileExistsNoThrow(taskHostLocation)) { return true; } +#endif return false; } diff --git a/src/XMakeBuildEngine/Evaluation/ProjectRootElementCache.cs b/src/XMakeBuildEngine/Evaluation/ProjectRootElementCache.cs index baa24d08b5f..0fbfd48386d 100644 --- a/src/XMakeBuildEngine/Evaluation/ProjectRootElementCache.cs +++ b/src/XMakeBuildEngine/Evaluation/ProjectRootElementCache.cs @@ -20,7 +20,9 @@ using System.Globalization; using Microsoft.Build.BackEnd; +#if FEATURE_APPDOMAIN using OutOfProcNode = Microsoft.Build.Execution.OutOfProcNode; +#endif namespace Microsoft.Build.Evaluation { @@ -610,7 +612,11 @@ private void DebugTraceCache(string message, string param1) { if (s_debugLogCacheActivity) { +#if FEATURE_APPDOMAIN string prefix = OutOfProcNode.IsOutOfProcNode ? "C" : "P"; +#else + string prefix = "P"; +#endif Trace.WriteLine(prefix + " " + Process.GetCurrentProcess().Id + " | " + message + param1); } } diff --git a/src/XMakeBuildEngine/Instance/TaskFactories/AssemblyTaskFactory.cs b/src/XMakeBuildEngine/Instance/TaskFactories/AssemblyTaskFactory.cs index 006836017d3..83af7738fcf 100644 --- a/src/XMakeBuildEngine/Instance/TaskFactories/AssemblyTaskFactory.cs +++ b/src/XMakeBuildEngine/Instance/TaskFactories/AssemblyTaskFactory.cs @@ -44,10 +44,12 @@ internal class AssemblyTaskFactory : ITaskFactory2 /// private LoadedType _loadedType; +#if FEATURE_APPDOMAIN /// /// A cache of tasks and the AppDomains they are loaded in. /// private Dictionary _tasksAndAppDomains = new Dictionary(); +#endif /// /// the set of parameters owned by this particular task host @@ -238,8 +240,10 @@ public void CleanupTask(ITask task) } else { +#if FEATURE_APPDOMAIN // It's really not necessary to do it for TaskHostTasks TaskLoader.RemoveAssemblyResolver(); +#endif } } @@ -320,7 +324,11 @@ string taskProjectFile /// /// Create an instance of the wrapped ITask for a batch run of the task. /// - internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary taskIdentityParameters, AppDomainSetup appDomainSetup, bool isOutOfProc) + internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary taskIdentityParameters, +#if FEATURE_APPDOMAIN + AppDomainSetup appDomainSetup, +#endif + bool isOutOfProc) { bool useTaskFactory = false; IDictionary mergedParameters = null; @@ -366,19 +374,35 @@ internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingConte mergedParameters[XMakeAttributes.architecture] = XMakeAttributes.GetCurrentMSBuildArchitecture(); } - TaskHostTask task = new TaskHostTask(taskLocation, taskLoggingContext, buildComponentHost, mergedParameters, _loadedType, appDomainSetup); + TaskHostTask task = new TaskHostTask(taskLocation, taskLoggingContext, buildComponentHost, mergedParameters, _loadedType +#if FEATURE_APPDOMAIN + , appDomainSetup +#endif + ); return task; } else { +#if FEATURE_APPDOMAIN AppDomain taskAppDomain = null; +#endif - ITask taskInstance = TaskLoader.CreateTask(_loadedType, _taskName, taskLocation.File, taskLocation.Line, taskLocation.Column, new TaskLoader.LogError(ErrorLoggingDelegate), appDomainSetup, isOutOfProc, out taskAppDomain); + ITask taskInstance = TaskLoader.CreateTask(_loadedType, _taskName, taskLocation.File, taskLocation.Line, taskLocation.Column, new TaskLoader.LogError(ErrorLoggingDelegate) +#if FEATURE_APPDOMAIN + , appDomainSetup +#endif + , isOutOfProc +#if FEATURE_APPDOMAIN + , out taskAppDomain +#endif + ); +#if FEATURE_APPDOMAIN if (taskAppDomain != null) { _tasksAndAppDomains[taskInstance] = taskAppDomain; } +#endif return taskInstance; } diff --git a/src/XMakeBuildEngine/Instance/TaskFactories/TaskHostTask.cs b/src/XMakeBuildEngine/Instance/TaskFactories/TaskHostTask.cs index 7974281c1be..1d1b9b65db6 100644 --- a/src/XMakeBuildEngine/Instance/TaskFactories/TaskHostTask.cs +++ b/src/XMakeBuildEngine/Instance/TaskFactories/TaskHostTask.cs @@ -81,11 +81,13 @@ internal class TaskHostTask : IGeneratedTask, ICancelableTask, INodePacketFactor /// private LoadedType _taskType; +#if FEATURE_APPDOMAIN /// /// The AppDomainSetup we'll want to apply to the AppDomain that we may /// want to load the OOP task into. /// private AppDomainSetup _appDomainSetup; +#endif /// /// The task host context of the task host we're launching -- used to @@ -98,10 +100,12 @@ internal class TaskHostTask : IGeneratedTask, ICancelableTask, INodePacketFactor /// private bool _connectedToTaskHost = false; +#if FEATURE_APPDOMAIN /// /// The provider for task host nodes. /// private NodeProviderOutOfProcTaskHost _taskHostProvider; +#endif /// /// Lock object to serialize access to the task host. @@ -127,7 +131,11 @@ internal class TaskHostTask : IGeneratedTask, ICancelableTask, INodePacketFactor /// /// Constructor /// - public TaskHostTask(IElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary taskHostParameters, LoadedType taskType, AppDomainSetup appDomainSetup) + public TaskHostTask(IElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary taskHostParameters, LoadedType taskType +#if FEATURE_APPDOMAIN + , AppDomainSetup appDomainSetup +#endif + ) { ErrorUtilities.VerifyThrowInternalNull(taskType, "taskType"); @@ -135,7 +143,9 @@ public TaskHostTask(IElementLocation taskLocation, TaskLoggingContext taskLoggin _taskLoggingContext = taskLoggingContext; _buildComponentHost = buildComponentHost; _taskType = taskType; +#if FEATURE_APPDOMAIN _appDomainSetup = appDomainSetup; +#endif _taskHostParameters = taskHostParameters; _packetFactory = new NodePacketFactory(); @@ -223,6 +233,7 @@ public void Cancel() { if (!_taskCancelled) { +#if FEATURE_APPDOMAIN lock (_taskHostLock) { if (_taskHostProvider != null && _connectedToTaskHost) @@ -230,6 +241,7 @@ public void Cancel() _taskHostProvider.SendData(_requiredContext, new TaskHostTaskCancelled()); } } +#endif _taskCancelled = true; } @@ -248,8 +260,10 @@ public bool Execute() // set up the node lock (_taskHostLock) { +#if FEATURE_APPDOMAIN _taskHostProvider = (NodeProviderOutOfProcTaskHost)_buildComponentHost.GetComponent(BuildComponentType.OutOfProcTaskHostNodeProvider); ErrorUtilities.VerifyThrowInternalNull(_taskHostProvider, "taskHostProvider"); +#endif } TaskHostConfiguration hostConfiguration = @@ -260,13 +274,19 @@ public bool Execute() CommunicationsUtilities.GetEnvironmentVariables(), _buildComponentHost.BuildParameters.Culture, _buildComponentHost.BuildParameters.UICulture, +#if FEATURE_APPDOMAIN _appDomainSetup, +#endif BuildEngine.LineNumberOfTaskNode, BuildEngine.ColumnNumberOfTaskNode, BuildEngine.ProjectFileOfTaskNode, BuildEngine.ContinueOnError, _taskType.Type.FullName, +#if FEATURE_ASSEMBLY_LOADFROM _taskType.Type.GetTypeInfo().Assembly.Location, +#else + _taskType.Type.GetTypeInfo().Assembly.GetName(), +#endif _setParameters ); @@ -275,7 +295,9 @@ public bool Execute() lock (_taskHostLock) { _requiredContext = CommunicationsUtilities.GetTaskHostContext(_taskHostParameters); +#if FEATURE_APPDOMAIN _connectedToTaskHost = _taskHostProvider.AcquireAndSetUpHost(_requiredContext, this, this, hostConfiguration); +#endif } if (_connectedToTaskHost) @@ -318,7 +340,9 @@ public bool Execute() { lock (_taskHostLock) { +#if FEATURE_APPDOMAIN _taskHostProvider.DisconnectFromHost(_requiredContext); +#endif _connectedToTaskHost = false; } } @@ -475,7 +499,13 @@ private void HandleTaskHostTaskComplete(TaskHostTaskComplete taskHostTaskComplet else { exceptionMessage = "TaskInstantiationFailureError"; - exceptionMessageArgs = new string[] { _taskType.Type.Name, _taskType.Type.GetTypeInfo().Assembly.Location, String.Empty }; + exceptionMessageArgs = new string[] { _taskType.Type.Name, +#if FEATURE_ASSEMBLY_LOADFROM + _taskType.Type.GetTypeInfo().Assembly.Location, +#else + _taskType.Type.GetTypeInfo().Assembly.FullName, +#endif + String.Empty }; } _taskLoggingContext.LogFatalError(new BuildEventFileInfo(_taskLocation), taskHostTaskComplete.TaskException, taskHostTaskComplete.TaskExceptionMessage, taskHostTaskComplete.TaskExceptionMessageArgs); @@ -559,7 +589,11 @@ private void HandleLoggedMessage(LogMessagePacket logMessagePacket) /// private void LogErrorUnableToCreateTaskHost(TaskHostContext requiredContext, string runtime, string architecture, NodeFailedToLaunchException e) { +#if FEATURE_APPDOMAIN string msbuildLocation = NodeProviderOutOfProcTaskHost.GetMSBuildLocationFromHostContext(requiredContext); +#else + string msbuildLocation = null; +#endif if (msbuildLocation == null) { diff --git a/src/XMakeBuildEngine/Instance/TaskRegistry.cs b/src/XMakeBuildEngine/Instance/TaskRegistry.cs index ab3ebcfda64..11de9b3801e 100644 --- a/src/XMakeBuildEngine/Instance/TaskRegistry.cs +++ b/src/XMakeBuildEngine/Instance/TaskRegistry.cs @@ -20,7 +20,9 @@ using ILoggingService = Microsoft.Build.BackEnd.Logging.ILoggingService; using InvalidProjectFileException = Microsoft.Build.Exceptions.InvalidProjectFileException; +#if FEATURE_APPDOMAIN using TaskEngineAssemblyResolver = Microsoft.Build.BackEnd.Logging.TaskEngineAssemblyResolver; +#endif using ProjectXmlUtilities = Microsoft.Build.Internal.ProjectXmlUtilities; using TargetLoggingContext = Microsoft.Build.BackEnd.Logging.TargetLoggingContext; using System.Collections.ObjectModel; @@ -1233,10 +1235,13 @@ private bool GetTaskFactory(TargetLoggingContext targetLoggingContext, ElementLo ITaskFactory factory = null; LoadedType loadedType = null; + bool isAssemblyTaskFactory = String.Equals(TaskFactoryAttributeName, AssemblyTaskFactory, StringComparison.OrdinalIgnoreCase); bool isTaskHostFactory = String.Equals(TaskFactoryAttributeName, TaskHostFactory, StringComparison.OrdinalIgnoreCase); +#if FEATURE_APPDOMAIN if (isAssemblyTaskFactory || isTaskHostFactory) +#endif { bool explicitlyLaunchTaskHost = isTaskHostFactory || @@ -1251,6 +1256,7 @@ private bool GetTaskFactory(TargetLoggingContext targetLoggingContext, ElementLo loadedType = taskFactory.InitializeFactory(taskFactoryLoadInfo, RegisteredName, ParameterGroupAndTaskBody.UsingTaskParameters, ParameterGroupAndTaskBody.InlineTaskXmlBody, TaskFactoryParameters, explicitlyLaunchTaskHost, targetLoggingContext, elementLocation, taskProjectFile); factory = taskFactory; } +#if FEATURE_APPDOMAIN else { // We are not one of the default factories. @@ -1351,9 +1357,7 @@ private bool GetTaskFactory(TargetLoggingContext targetLoggingContext, ElementLo } finally { -#if FEATURE_APPDOMAIN taskFactoryLoggingHost.MarkAsInactive(); -#endif } if (!initialized) @@ -1408,6 +1412,7 @@ private bool GetTaskFactory(TargetLoggingContext targetLoggingContext, ElementLo } } } +#endif _taskFactoryWrapperInstance = new TaskFactoryWrapper(factory, loadedType, RegisteredName, TaskFactoryParameters); } diff --git a/src/XMakeBuildEngine/Microsoft.Build.csproj b/src/XMakeBuildEngine/Microsoft.Build.csproj index a2b2eeb1156..cf678447966 100644 --- a/src/XMakeBuildEngine/Microsoft.Build.csproj +++ b/src/XMakeBuildEngine/Microsoft.Build.csproj @@ -116,7 +116,7 @@ - + @@ -139,7 +139,7 @@ - + true @@ -206,7 +206,7 @@ - + @@ -221,9 +221,9 @@ - - - + + + true @@ -235,7 +235,7 @@ - + @@ -356,8 +356,8 @@ - - + + true