Exemple #1
0
        /// <summary>
        /// Indicates to the TaskHost that it is no longer needed.
        /// Called by TaskBuilder when the task using the EngineProxy is done.
        /// </summary>
        internal void MarkAsInactive()
        {
            lock (_callbackMonitor)
            {
                VerifyActiveProxy();
                _activeProxy = false;

                // Since the task has a pointer to this class it may store it in a static field. Null out
                // internal data so the leak of this object doesn't lead to a major memory leak.
                _host         = null;
                _requestEntry = null;

                // Don't bother clearing the tiny task location
                _taskLoggingContext    = null;
                _targetBuilderCallback = null;

                // Clear out the sponsor (who is responsible for keeping the EngineProxy remoting lease alive until the task is done)
                // this will be null if the engine proxy was never sent across an AppDomain boundary.
                if (_sponsor != null)
                {
                    ILease lease = (ILease)RemotingServices.GetLifetimeService(this);

                    if (lease != null)
                    {
                        lease.Unregister(_sponsor);
                    }

                    _sponsor.Close();
                    _sponsor = null;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Create an instance of the wrapped ITask for a batch run of the task.
        /// </summary>
        internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary <string, string> taskIdentityParameters,
#if FEATURE_APPDOMAIN
                                          AppDomainSetup appDomainSetup,
#endif
                                          bool isOutOfProc)
        {
            bool useTaskFactory = false;
            IDictionary <string, string> mergedParameters = null;

            _taskLoggingContext = taskLoggingContext;

            // Optimization for the common (vanilla AssemblyTaskFactory) case -- only calculate
            // the task factory parameters if we have any to calculate; otherwise even if we
            // still launch the task factory, it will be with parameters corresponding to the
            // current process.
            if ((_factoryIdentityParameters != null && _factoryIdentityParameters.Count > 0) || (taskIdentityParameters != null && taskIdentityParameters.Count > 0))
            {
                VerifyThrowIdentityParametersValid(taskIdentityParameters, taskLocation, _taskName, "MSBuildRuntime", "MSBuildArchitecture");

                mergedParameters = MergeTaskFactoryParameterSets(_factoryIdentityParameters, taskIdentityParameters);
                useTaskFactory   = !NativeMethodsShared.IsMono &&
                                   (_taskHostFactoryExplicitlyRequested ||
                                    !TaskHostParametersMatchCurrentProcess(mergedParameters));
            }
            else
            {
                // if we don't have any task host parameters specified on either the using task or the
                // task invocation, then we will run in-proc UNLESS "TaskHostFactory" is explicitly specified
                // as the task factory.
                useTaskFactory = _taskHostFactoryExplicitlyRequested;
            }

            if (useTaskFactory)
            {
                ErrorUtilities.VerifyThrowInternalNull(buildComponentHost, "buildComponentHost");

                mergedParameters = mergedParameters ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                string runtime      = null;
                string architecture = null;

                if (!mergedParameters.TryGetValue(XMakeAttributes.runtime, out runtime))
                {
                    mergedParameters[XMakeAttributes.runtime] = XMakeAttributes.MSBuildRuntimeValues.clr4;
                }

                if (!mergedParameters.TryGetValue(XMakeAttributes.architecture, out architecture))
                {
                    mergedParameters[XMakeAttributes.architecture] = XMakeAttributes.GetCurrentMSBuildArchitecture();
                }

                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)
#if FEATURE_APPDOMAIN
                                                           , appDomainSetup
#endif
                                                           , isOutOfProc
#if FEATURE_APPDOMAIN
                                                           , out taskAppDomain
#endif
                                                           );

#if FEATURE_APPDOMAIN
                if (taskAppDomain != null)
                {
                    _tasksAndAppDomains[taskInstance] = taskAppDomain;
                }
#endif

                return(taskInstance);
            }
        }
        /// <summary>
        /// Create an instance of the wrapped ITask for a batch run of the task.
        /// </summary>
        internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary<string, string> taskIdentityParameters, AppDomainSetup appDomainSetup, bool isOutOfProc)
        {
            bool useTaskFactory = false;
            IDictionary<string, string> mergedParameters = null;
            _taskLoggingContext = taskLoggingContext;

            // Optimization for the common (vanilla AssemblyTaskFactory) case -- only calculate 
            // the task factory parameters if we have any to calculate; otherwise even if we 
            // still launch the task factory, it will be with parameters corresponding to the 
            // current process. 
            if ((_factoryIdentityParameters != null && _factoryIdentityParameters.Count > 0) || (taskIdentityParameters != null && taskIdentityParameters.Count > 0))
            {
                VerifyThrowIdentityParametersValid(taskIdentityParameters, taskLocation, _taskName, "MSBuildRuntime", "MSBuildArchitecture");

                mergedParameters = MergeTaskFactoryParameterSets(_factoryIdentityParameters, taskIdentityParameters);
                useTaskFactory = _taskHostFactoryExplicitlyRequested || !TaskHostParametersMatchCurrentProcess(mergedParameters);
            }
            else
            {
                // if we don't have any task host parameters specified on either the using task or the 
                // task invocation, then we will run in-proc UNLESS "TaskHostFactory" is explicitly specified
                // as the task factory.  
                useTaskFactory = _taskHostFactoryExplicitlyRequested;
            }

            if (useTaskFactory)
            {
                ErrorUtilities.VerifyThrowInternalNull(buildComponentHost, "buildComponentHost");

                mergedParameters = mergedParameters ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

                string runtime = null;
                string architecture = null;

                if (!mergedParameters.TryGetValue(XMakeAttributes.runtime, out runtime))
                {
                    mergedParameters[XMakeAttributes.runtime] = XMakeAttributes.MSBuildRuntimeValues.clr4;
                }

                if (!mergedParameters.TryGetValue(XMakeAttributes.architecture, out architecture))
                {
                    mergedParameters[XMakeAttributes.architecture] = XMakeAttributes.GetCurrentMSBuildArchitecture();
                }

                TaskHostTask task = new TaskHostTask(taskLocation, taskLoggingContext, buildComponentHost, mergedParameters, _loadedType, appDomainSetup);
                return task;
            }
            else
            {
                AppDomain taskAppDomain = null;

                ITask taskInstance = TaskLoader.CreateTask(_loadedType, _taskName, taskLocation.File, taskLocation.Line, taskLocation.Column, new TaskLoader.LogError(ErrorLoggingDelegate), appDomainSetup, isOutOfProc, out taskAppDomain);

                if (taskAppDomain != null)
                {
                    _tasksAndAppDomains[taskInstance] = taskAppDomain;
                }

                return taskInstance;
            }
        }
Exemple #4
0
        /// <summary>
        /// Execute a task object for a given bucket.
        /// </summary>
        /// <param name="taskExecutionHost">The host used to execute the task.</param>
        /// <param name="taskLoggingContext">The logging context.</param>
        /// <param name="taskHost">The task host for the task.</param>
        /// <param name="bucket">The batching bucket</param>
        /// <param name="howToExecuteTask">The task execution mode</param>
        /// <returns>The result of running the task.</returns>
        private async Task<WorkUnitResult> ExecuteInstantiatedTask(ITaskExecutionHost taskExecutionHost, TaskLoggingContext taskLoggingContext, TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask)
        {
            UpdateContinueOnError(bucket, taskHost);

            bool taskResult = false;

            WorkUnitResultCode resultCode = WorkUnitResultCode.Success;
            WorkUnitActionCode actionCode = WorkUnitActionCode.Continue;

            if (!taskExecutionHost.SetTaskParameters(_taskNode.ParametersForBuild))
            {
                // The task cannot be initialized.
                ProjectErrorUtilities.VerifyThrowInvalidProject(false, _targetChildInstance.Location, "TaskParametersError", _taskNode.Name, String.Empty);
            }
            else
            {
                bool taskReturned = false;
                Exception taskException = null;

                // If this is the MSBuild task, we need to execute it's special internal method.
                TaskExecutionHost host = taskExecutionHost as TaskExecutionHost;
                Type taskType = host.TaskInstance.GetType();

                try
                {
                    if (taskType == typeof(MSBuild))
                    {
                        MSBuild msbuildTask = host.TaskInstance as MSBuild;
                        ErrorUtilities.VerifyThrow(msbuildTask != null, "Unexpected MSBuild internal task.");
                        _targetBuilderCallback.EnterMSBuildCallbackState();

                        try
                        {
                            taskResult = await msbuildTask.ExecuteInternal();
                        }
                        finally
                        {
                            _targetBuilderCallback.ExitMSBuildCallbackState();
                        }
                    }
                    else if (taskType == typeof(CallTarget))
                    {
                        CallTarget callTargetTask = host.TaskInstance as CallTarget;
                        taskResult = await callTargetTask.ExecuteInternal();
                    }
                    else
                    {
                        using (FullTracking.Track(taskLoggingContext.TargetLoggingContext.Target.Name, _taskNode.Name, _buildRequestEntry.ProjectRootDirectory, _buildRequestEntry.RequestConfiguration.Project.PropertiesToBuildWith))
                        {
                            taskResult = taskExecutionHost.Execute();
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (ExceptionHandling.IsCriticalException(ex) || (Environment.GetEnvironmentVariable("MSBUILDDONOTCATCHTASKEXCEPTIONS") == "1"))
                    {
                        throw;
                    }

                    taskException = ex;
                }

                if (taskException == null)
                {
                    taskReturned = true;

                    // Set the property "MSBuildLastTaskResult" to reflect whether the task succeeded or not.
                    // The main use of this is if ContinueOnError is true -- so that the next task can consult the result.
                    // So we want it to be "false" even if ContinueOnError is true. 
                    // The constants "true" and "false" should NOT be localized. They become property values.
                    bucket.Lookup.SetProperty(ProjectPropertyInstance.Create(ReservedPropertyNames.lastTaskResult, taskResult ? "true" : "false", true/* may be reserved */, _buildRequestEntry.RequestConfiguration.Project.IsImmutable));
                }
                else
                {
                    Type type = taskException.GetType();

                    if (type == typeof(LoggerException))
                    {
                        // if a logger has failed, abort immediately
                        // Polite logger failure
                        _continueOnError = ContinueOnError.ErrorAndStop;

                        // Rethrow wrapped in order to avoid losing the callstack
                        throw new LoggerException(taskException.Message, taskException);
                    }
                    else if (type == typeof(InternalLoggerException))
                    {
                        // Logger threw arbitrary exception
                        _continueOnError = ContinueOnError.ErrorAndStop;
                        InternalLoggerException ex = taskException as InternalLoggerException;

                        // Rethrow wrapped in order to avoid losing the callstack
                        throw new InternalLoggerException(taskException.Message, taskException, ex.BuildEventArgs, ex.ErrorCode, ex.HelpKeyword, ex.InitializationException);
                    }
                    else if (type == typeof(ThreadAbortException))
                    {
                        Thread.ResetAbort();
                        _continueOnError = ContinueOnError.ErrorAndStop;

                        // Cannot rethrow wrapped as ThreadAbortException is sealed and has no appropriate constructor
                        // Stack will be lost
                        throw taskException;
                    }
                    else if (type == typeof(BuildAbortedException))
                    {
                        _continueOnError = ContinueOnError.ErrorAndStop;

                        // Rethrow wrapped in order to avoid losing the callstack
                        throw new BuildAbortedException(taskException.Message, ((BuildAbortedException)taskException));
                    }
                    else if (type == typeof(CircularDependencyException))
                    {
                        _continueOnError = ContinueOnError.ErrorAndStop;
                        ProjectErrorUtilities.ThrowInvalidProject(taskLoggingContext.Task.Location, "CircularDependency", taskLoggingContext.TargetLoggingContext.Target.Name);
                    }
                    else if (type == typeof(InvalidProjectFileException))
                    {
                        // Just in case this came out of a task, make sure it's not
                        // marked as having been logged.
                        InvalidProjectFileException ipex = (InvalidProjectFileException)taskException;
                        ipex.HasBeenLogged = false;

                        if (_continueOnError != ContinueOnError.ErrorAndStop)
                        {
                            taskLoggingContext.LogInvalidProjectFileError(ipex);
                            taskLoggingContext.LogComment(MessageImportance.Normal, "ErrorConvertedIntoWarning");
                        }
                        else
                        {
                            // Rethrow wrapped in order to avoid losing the callstack
                            throw new InvalidProjectFileException(ipex.Message, ipex);
                        }
                    }
                    else if (type == typeof(Exception) || type.IsSubclassOf(typeof(Exception)))
                    {
                        // Occasionally, when debugging a very uncommon task exception, it is useful to loop the build with 
                        // a debugger attached to break on 2nd chance exceptions.
                        // That requires that there needs to be a way to not catch here, by setting an environment variable.
                        if (ExceptionHandling.IsCriticalException(taskException) || (Environment.GetEnvironmentVariable("MSBUILDDONOTCATCHTASKEXCEPTIONS") == "1"))
                        {
                            // Wrapping in an Exception will unfortunately mean that this exception would fly through any IsCriticalException above.
                            // However, we should not have any, also we should not have stashed such an exception anyway.
                            throw new Exception(taskException.Message, taskException);
                        }

                        Exception exceptionToLog = taskException;

                        if (exceptionToLog is TargetInvocationException)
                        {
                            exceptionToLog = exceptionToLog.InnerException;
                        }

                        // handle any exception thrown by the task during execution
                        // NOTE: We catch ALL exceptions here, to attempt to completely isolate the Engine
                        // from failures in the task.
                        if (_continueOnError == ContinueOnError.WarnAndContinue)
                        {
                            taskLoggingContext.LogTaskWarningFromException
                            (
                                new BuildEventFileInfo(_targetChildInstance.Location),
                                exceptionToLog,
                                _taskNode.Name
                            );

                            // Log a message explaining why we converted the previous error into a warning.
                            taskLoggingContext.LogComment(MessageImportance.Normal, "ErrorConvertedIntoWarning");
                        }
                        else
                        {
                            taskLoggingContext.LogFatalTaskError
                            (
                                new BuildEventFileInfo(_targetChildInstance.Location),
                                exceptionToLog,
                                _taskNode.Name
                            );
                        }
                    }
                    else
                    {
                        ErrorUtilities.ThrowInternalErrorUnreachable();
                    }
                }

                // If the task returned attempt to gather its outputs.  If gathering outputs fails set the taskResults
                // to false
                if (taskReturned)
                {
                    taskResult = GatherTaskOutputs(taskExecutionHost, howToExecuteTask, bucket) && taskResult;
                }

                // If the taskResults are false look at ContinueOnError.  If ContinueOnError=false (default)
                // mark the taskExecutedSuccessfully=false.  Otherwise let the task succeed but log a normal
                // pri message that says this task is continuing because ContinueOnError=true
                resultCode = taskResult ? WorkUnitResultCode.Success : WorkUnitResultCode.Failed;
                actionCode = WorkUnitActionCode.Continue;
                if (resultCode == WorkUnitResultCode.Failed)
                {
                    if (_continueOnError == ContinueOnError.ErrorAndStop)
                    {
                        actionCode = WorkUnitActionCode.Stop;
                    }
                    else
                    {
                        // This is the ErrorAndContinue or WarnAndContinue case...
                        string settingString = "true";
                        if (_taskNode.ContinueOnErrorLocation != null)
                        {
                            settingString = bucket.Expander.ExpandIntoStringAndUnescape(_taskNode.ContinueOnError, ExpanderOptions.ExpandAll, _taskNode.ContinueOnErrorLocation); // expand embedded item vectors after expanding properties and item metadata
                        }

                        taskLoggingContext.LogComment
                        (
                            MessageImportance.Normal,
                            "TaskContinuedDueToContinueOnError",
                            "ContinueOnError",
                            _taskNode.Name,
                            settingString
                        );

                        actionCode = WorkUnitActionCode.Continue;
                    }
                }
            }

            WorkUnitResult result = new WorkUnitResult(resultCode, actionCode, null);

            return result;
        }
Exemple #5
0
        /// <summary>
        /// Initializes and executes the task.
        /// </summary>
        private async Task<WorkUnitResult> InitializeAndExecuteTask(TaskLoggingContext taskLoggingContext, ItemBucket bucket, IDictionary<string, string> taskIdentityParameters, TaskHost taskHost, TaskExecutionMode howToExecuteTask)
        {
            if (!_taskExecutionHost.InitializeForBatch(taskLoggingContext, bucket, taskIdentityParameters))
            {
                ProjectErrorUtilities.ThrowInvalidProject(_targetChildInstance.Location, "TaskDeclarationOrUsageError", _taskNode.Name);
            }

            try
            {
                // UNDONE: Move this and the task host.
                taskHost.LoggingContext = taskLoggingContext;
                WorkUnitResult executionResult = await ExecuteInstantiatedTask(_taskExecutionHost, taskLoggingContext, taskHost, bucket, howToExecuteTask);

                ErrorUtilities.VerifyThrow(executionResult != null, "Unexpected null execution result");

                return executionResult;
            }
            finally
            {
                _taskExecutionHost.CleanupForBatch();
            }
        }
Exemple #6
0
        private WorkUnitResult ExecuteTaskInSTAThread(ItemBucket bucket, TaskLoggingContext taskLoggingContext, IDictionary<string, string> taskIdentityParameters, TaskHost taskHost, TaskExecutionMode howToExecuteTask)
        {
            WorkUnitResult taskResult = new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Stop, null);
            Thread staThread = null;
            Exception exceptionFromExecution = null;
            ManualResetEvent taskRunnerFinished = new ManualResetEvent(false);
            try
            {
                ThreadStart taskRunnerDelegate = delegate ()
                {
                    Lookup.Scope scope = bucket.Lookup.EnterScope("STA Thread for Task");
                    try
                    {
                        taskResult = InitializeAndExecuteTask(taskLoggingContext, bucket, taskIdentityParameters, taskHost, howToExecuteTask).Result;
                    }
                    catch (Exception e)
                    {
                        if (ExceptionHandling.IsCriticalException(e))
                        {
                            throw;
                        }

                        exceptionFromExecution = e;
                    }
                    finally
                    {
                        scope.LeaveScope();
                        taskRunnerFinished.Set();
                    }
                };

                staThread = new Thread(taskRunnerDelegate);
                staThread.SetApartmentState(ApartmentState.STA);
                staThread.Name = "MSBuild STA task runner thread";
                staThread.CurrentCulture = _componentHost.BuildParameters.Culture;
                staThread.CurrentUICulture = _componentHost.BuildParameters.UICulture;
                staThread.Start();

                // TODO: Why not just Join on the thread???
                taskRunnerFinished.WaitOne();
            }
            finally
            {
                taskRunnerFinished.Close();
                taskRunnerFinished = null;
            }

            if (exceptionFromExecution != null)
            {
                // Unfortunately this will reset the callstack
                throw exceptionFromExecution;
            }

            return taskResult;
        }
        /// <summary>
        /// Create an instance of the wrapped ITask for a batch run of the task.
        /// </summary>
        public ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, AppDomainSetup appDomainSetup, bool isOutOfProc)
        {
            separateAppDomain = false;
            separateAppDomain = loadedType.HasLoadInSeparateAppDomainAttribute();

            taskAppDomain = null;

            if (separateAppDomain)
            {
                if (!loadedType.Type.IsMarshalByRef)
                {
                    taskLoggingContext.LogError
                    (
                        new BuildEventFileInfo(taskLocation),
                        "TaskNotMarshalByRef",
                        taskName
                     );

                    return null;
                }
                else
                {
                    // Our task depend on this name to be precisely that, so if you change it make sure
                    // you also change the checks in the tasks run in separate AppDomains. Better yet, just don't change it.

                    // Make sure we copy the appdomain configuration and send it to the appdomain we create so that if the creator of the current appdomain
                    // has done the binding redirection in code, that we will get those settings as well.
                    AppDomainSetup appDomainInfo = new AppDomainSetup();

                    // Get the current app domain setup settings
                    byte[] currentAppdomainBytes = appDomainSetup.GetConfigurationBytes();

                    // Apply the appdomain settings to the new appdomain before creating it
                    appDomainInfo.SetConfigurationBytes(currentAppdomainBytes);
                    taskAppDomain = AppDomain.CreateDomain(isOutOfProc ? "taskAppDomain (out-of-proc)" : "taskAppDomain (in-proc)", null, appDomainInfo);

                    // Hook up last minute dumping of any exceptions 
                    taskAppDomain.UnhandledException += new UnhandledExceptionEventHandler(ExceptionHandling.UnhandledExceptionHandler);
                }
            }

            // instantiate the task in given domain
            if (taskAppDomain == null || taskAppDomain == AppDomain.CurrentDomain)
            {
                // 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.
                taskInstance = (ITask)Activator.CreateInstance(loadedType.Type);

                return taskInstance;
            }

            if (loadedType.Assembly.AssemblyFile != null)
            {
                taskInstance = (ITask)taskAppDomain.CreateInstanceFromAndUnwrap(loadedType.Assembly.AssemblyFile, loadedType.Type.FullName);

                // this will force evaluation of the task class type and try to load the task assembly
                Type taskType = taskInstance.GetType();

                // If the types don't match, we have a problem. It means that our AppDomain was able to load
                // a task assembly using Load, and loaded a different one. I don't see any other choice than
                // to fail here.
                if (taskType != loadedType.Type)
                {
                    taskLoggingContext.LogError
                    (
                    new BuildEventFileInfo(taskLocation),
                    "ConflictingTaskAssembly",
                    loadedType.Assembly.AssemblyFile,
                    loadedType.Type.Assembly.Location
                    );

                    taskInstance = null;
                }
            }
            else
            {
                taskInstance = (ITask)taskAppDomain.CreateInstanceAndUnwrap(loadedType.Type.Assembly.FullName, loadedType.Type.FullName);
            }

            return taskInstance;
        }
Exemple #8
0
        /// <summary>
        /// Indicates to the TaskHost that it is no longer needed.
        /// Called by TaskBuilder when the task using the EngineProxy is done.
        /// </summary>
        internal void MarkAsInactive()
        {
            lock (_callbackMonitor)
            {
                VerifyActiveProxy();
                _activeProxy = false;

                // Since the task has a pointer to this class it may store it in a static field. Null out
                // internal data so the leak of this object doesn't lead to a major memory leak.            
                _host = null;
                _requestEntry = null;

                // Don't bother clearing the tiny task location
                _taskLoggingContext = null;
                _targetBuilderCallback = null;

                // Clear out the sponsor (who is responsible for keeping the EngineProxy remoting lease alive until the task is done)
                // this will be null if the engineproxy was never sent across an appdomain boundry.
                if (_sponsor != null)
                {
                    ILease lease = (ILease)RemotingServices.GetLifetimeService(this);

                    if (lease != null)
                    {
                        lease.Unregister(_sponsor);
                    }

                    _sponsor.Close();
                    _sponsor = null;
                }
            }
        }