public void ExecuteTaskCurrentDirNotEqualExecutionDir() { string theCurrentDirectory = Directory.GetCurrentDirectory(); try { string executionDirectory = "C:\\"; TaskExecutionMode howToExecuteTask = TaskExecutionMode.InferOutputsOnly; XmlDocument doc = new XmlDocument(); XmlElement taskNode = doc.CreateElement("Foo"); TaskExecutionStateHelper executionState = new TaskExecutionStateHelper( howToExecuteTask, LookupHelpers.CreateLookup(projectLevelProprtiesForInference, projectLevelItemsForInference), LookupHelpers.CreateLookup(projectLevelPropertiesForExecution, projectLevelItemsForExecution), taskNode, hostObject, projectFileOfTaskNode, parentProjectFullFileName, executionDirectory, nodeProxyId); executionState.ParentModule = taskExecutionModule; executionState.LoggingService = loggingHelper; executionState.TargetInferenceSuccessful = true; executionState.ExecuteTask(); Assert.IsTrue(string.Compare(Directory.GetCurrentDirectory(), "C:\\", StringComparison.OrdinalIgnoreCase) == 0, "Expected current directory to be c:\\ which should show up as an empty directory string"); } finally { Directory.SetCurrentDirectory(theCurrentDirectory); } }
/// <summary> /// The constructor obtains the state information and the /// callback delegate. /// </summary> internal TaskExecutionState ( TaskExecutionMode howToExecuteTask, Lookup lookupForInference, Lookup lookupForExecution, XmlElement taskXmlNode, ITaskHost hostObject, string projectFileOfTaskNode, string parentProjectFullFileName, string executionDirectory, int handleId, BuildEventContext buildEventContext ) { ErrorUtilities.VerifyThrow(taskXmlNode != null, "Must have task node"); this.howToExecuteTask = howToExecuteTask; this.lookupForInference = lookupForInference; this.lookupForExecution = lookupForExecution; this.hostObject = hostObject; this.projectFileOfTaskNode = projectFileOfTaskNode; this.parentProjectFullFileName = parentProjectFullFileName; this.executionDirectory = executionDirectory; this.handleId = handleId; this.buildEventContext = buildEventContext; this.taskXmlNode = taskXmlNode; }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { SchemaCompareScriptGenerationResult result = this.ComparisonResult.GenerateScript(this.Parameters.TargetDatabaseName); File.WriteAllText(this.Parameters.ScriptFilePath, result.Script); if (!string.IsNullOrEmpty(result.MasterScript)) { // master script is only used if the target is Azure SQL db and the script contains all operations that must be done against the master database string masterScriptPath = Path.Combine(Path.GetDirectoryName(this.Parameters.ScriptFilePath), string.Concat("master_", Path.GetFileName(this.Parameters.ScriptFilePath))); File.WriteAllText(masterScriptPath, result.MasterScript); } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare generate script operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { this.ScriptGenerationResult = this.ComparisonResult.GenerateScript(this.Parameters.TargetDatabaseName, this.CancellationToken); // tests don't create a SqlTask, so only add the script when the SqlTask isn't null if (this.SqlTask != null) { this.SqlTask.AddScript(SqlTaskStatus.Succeeded, this.ScriptGenerationResult.Script); if (!string.IsNullOrEmpty(this.ScriptGenerationResult.MasterScript)) { // master script is only used if the target is Azure SQL db and the script contains all operations that must be done against the master database this.SqlTask.AddScript(SqlTaskStatus.Succeeded, ScriptGenerationResult.MasterScript); } } if (!this.ScriptGenerationResult.Success) { ErrorMessage = this.ScriptGenerationResult.Message; throw new Exception(ErrorMessage); } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare generate script operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
/// <summary> /// Execute the operation for given execution mode /// </summary> /// <param name="mode"></param> public virtual void Execute(TaskExecutionMode mode) { var currentExecutionMode = Server.ConnectionContext.SqlExecutionModes; try { if (Server != null) { Server.ConnectionContext.CapturedSql.Clear(); SetExecutionMode(mode); } Execute(); GenerateScript(mode); } catch { throw; } finally { Server.ConnectionContext.CapturedSql.Clear(); Server.ConnectionContext.SqlExecutionModes = currentExecutionMode; } }
/// <summary> /// Execute the operation for given execution mode /// </summary> /// <param name="mode"></param> public override void Execute(TaskExecutionMode mode) { bool hasAccessToDb = false; try { hasAccessToDb = GainAccessToDatabase(); base.Execute(mode); } catch (DatabaseFullAccessException databaseFullAccessException) { Logger.Write(TraceEventType.Warning, $"Failed to gain access to database. server|database:{ServerName}|{DatabaseName}"); throw databaseFullAccessException; } catch { throw; } finally { if (hasAccessToDb) { ReleaseAccessToDatabase(); } } }
bool Run (IBuildTask buildTask, TaskExecutionMode taskExecutionMode, out bool executeOnErrors) { executeOnErrors = false; // Run the task in batches bool retval = true; if (buckets.Count == 0) { // batched mode, but no values in the corresponding items! retval = Execute (buildTask, taskExecutionMode); if (!retval && !buildTask.ContinueOnError) executeOnErrors = true; return retval; } // batched foreach (Dictionary<string, BuildItemGroup> bucket in buckets) { project.PushBatch (bucket, commonItemsByName); try { retval = Execute (buildTask, taskExecutionMode); if (!retval && !buildTask.ContinueOnError) { executeOnErrors = true; break; } } finally { project.PopBatch (); } } return retval; }
private void AddTaskToTaskGroup(TaskGroup taskGroup, ITask task, TaskExecutionMode taskExecutionMode) { CheckThatTaskWasNotExecutedAlready(task); if (taskGroup == null) { taskGroup = new TaskGroup() { GroupId = Guid.NewGuid().ToString(), }; taskGroup.Tasks.Add((task, taskExecutionMode)); TasksGroups.Add(taskGroup); } else { var existingGroup = TasksGroups.FirstOrDefault(x => x.GroupId == taskGroup.GroupId); if (existingGroup == null) { taskGroup.Tasks.Add((task, taskExecutionMode)); TasksGroups.Add(taskGroup); } else { taskGroup.Tasks.Add((task, taskExecutionMode)); } } }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { SchemaComparison compare = new SchemaComparison(this.Parameters.FilePath); // load xml file because some parsing still needs to be done this.scmpInfo = XDocument.Load(this.Parameters.FilePath); this.Result = new SchemaCompareOpenScmpResult() { DeploymentOptions = new DeploymentOptions(compare.Options), Success = true, SourceEndpointInfo = this.GetEndpointInfo(true, compare.Source), TargetEndpointInfo = this.GetEndpointInfo(false, compare.Target), OriginalTargetName = this.GetOriginalTargetName(), OriginalTargetConnectionString = this.GetOriginalTargetConnectionString(), ExcludedSourceElements = this.GetExcludedElements(compare.ExcludedSourceObjects), ExcludedTargetElements = this.GetExcludedElements(compare.ExcludedTargetObjects) }; } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare open scmp operation failed with exception {0}", e)); throw; } }
internal TaskExecutionStateHelper ( TaskExecutionMode howToExecuteTask, Lookup lookupForInference, Lookup lookupForExecution, XmlElement taskXmlNode, ITaskHost hostObject, string projectFileOfTaskNode, string parentProjectFullFileName, string executionDirectory, int nodeProxyId ) : base(howToExecuteTask, lookupForInference, lookupForExecution, taskXmlNode, hostObject, projectFileOfTaskNode, parentProjectFullFileName, executionDirectory, nodeProxyId, null ) { // Dont need to do anything }
public async Task VerifyTaskWithExecutionMode(TaskExecutionMode executionMode, bool makeTaskFail = false) { serviceHostMock.AddEventHandling(TaskStatusChangedNotification.Type, null); using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { //To make the task fail don't create the schema so create table fails string query = string.Empty; if (!makeTaskFail) { query = $"CREATE SCHEMA [test]"; } SqlTestDb testDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, query, "TaskService"); try { TestConnectionResult connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync(testDb.DatabaseName, queryTempFile.FilePath); string taskName = "task name"; Server server = CreateServerObject(connectionResult.ConnectionInfo); RequstParamStub requstParam = new RequstParamStub { TaskExecutionMode = executionMode, OwnerUri = queryTempFile.FilePath }; SmoScriptableTaskOperationStub taskOperation = new SmoScriptableTaskOperationStub(server); taskOperation.DatabaseName = testDb.DatabaseName; taskOperation.TableName = "newTable"; TaskMetadata taskMetadata = TaskMetadata.Create(requstParam, taskName, taskOperation, ConnectionService.Instance); SqlTask sqlTask = service.TaskManager.CreateTask <SqlTask>(taskMetadata); Task taskToVerify = sqlTask.RunAsync().ContinueWith(task => { if (!makeTaskFail) { if (executionMode == TaskExecutionMode.Script || executionMode == TaskExecutionMode.ExecuteAndScript) { serviceHostMock.Verify(x => x.SendEvent(TaskStatusChangedNotification.Type, It.Is <TaskProgressInfo>(t => !string.IsNullOrEmpty(t.Script))), Times.AtLeastOnce()); } //Verify if the table created if execution mode includes execute bool expected = executionMode == TaskExecutionMode.Execute || executionMode == TaskExecutionMode.ExecuteAndScript; Server serverToverfiy = CreateServerObject(connectionResult.ConnectionInfo); bool actual = serverToverfiy.Databases[testDb.DatabaseName].Tables.Contains(taskOperation.TableName, "test"); Assert.Equal(expected, actual); } else { serviceHostMock.Verify(x => x.SendEvent(TaskStatusChangedNotification.Type, It.Is <TaskProgressInfo>(t => t.Status == SqlTaskStatus.Failed)), Times.AtLeastOnce()); } }); await taskToVerify; } finally { testDb.Cleanup(); } } }
public void AddExecutionMode(TaskExecutionMode mode) // Actorect to change when this class will get more formal { executionMode.Add(mode); if (ContainsExecutionMode(TaskExecutionMode.InstantOverrideAll) && mode == TaskExecutionMode.Chain) { executionMode.Remove(TaskExecutionMode.InstantOverrideAll); } }
public void Add(string dependentTargetName, TaskExecutionMode taskExecMode, bool skipped = false) { Add(new TargetDependency { TargetName = dependentTargetName, TaskExecutionMode = taskExecMode, Skipped = skipped }); }
/// <summary> /// Execute the operation for given execution mode /// </summary> /// <param name="mode"></param> public virtual void Execute(TaskExecutionMode mode) { var currentExecutionMode = Server.ConnectionContext.SqlExecutionModes; try { if (Server != null) { Server.ConnectionContext.CapturedSql.Clear(); switch (mode) { case TaskExecutionMode.Execute: { Server.ConnectionContext.SqlExecutionModes = SqlExecutionModes.ExecuteSql; break; } case TaskExecutionMode.ExecuteAndScript: { Server.ConnectionContext.SqlExecutionModes = SqlExecutionModes.ExecuteAndCaptureSql; break; } case TaskExecutionMode.Script: { Server.ConnectionContext.SqlExecutionModes = SqlExecutionModes.CaptureSql; break; } } } Execute(); if (mode == TaskExecutionMode.Script || mode == TaskExecutionMode.ExecuteAndScript) { this.ScriptContent = GetScriptContent(); if (SqlTask != null) { OnScriptAdded(new TaskScript { Status = SqlTaskStatus.Succeeded, Script = this.ScriptContent }); } } } catch { throw; } finally { Server.ConnectionContext.CapturedSql.Clear(); Server.ConnectionContext.SqlExecutionModes = currentExecutionMode; } }
public static RunType asRunType(TaskExecutionMode taskExecutionMode) { if (taskExecutionMode == TaskExecutionMode.Script) { return(RunType.ScriptToWindow); } else { return(RunType.RunNow); } }
/// <summary> /// Since we could not derrive from TaskEngine and have no Interface, we need to overide the method in here and /// replace the calls when testing the class because of the calls to TaskEngine. If at a future time we get a mock task /// engine, Interface or a non sealed TaskEngine these methods can disappear. /// </summary> /// <returns></returns> virtual internal bool TaskEngineExecuteTask( TaskEngine taskEngine, TaskExecutionMode howTaskShouldBeExecuted, Lookup lookup ) { return(taskEngine.ExecuteTask ( howTaskShouldBeExecuted, lookup )); }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { SchemaCompareEndpoint sourceEndpoint = SchemaCompareUtils.CreateSchemaCompareEndpoint(this.Parameters.SourceEndpointInfo, this.SourceConnectionInfo); SchemaCompareEndpoint targetEndpoint = SchemaCompareUtils.CreateSchemaCompareEndpoint(this.Parameters.TargetEndpointInfo, this.TargetConnectionInfo); SchemaComparison comparison = new SchemaComparison(sourceEndpoint, targetEndpoint); if (this.Parameters.DeploymentOptions != null) { comparison.Options = SchemaCompareUtils.CreateSchemaCompareOptions(this.Parameters.DeploymentOptions); } // for testing schemaCompareStarted?.Invoke(this, new EventArgs()); this.ComparisonResult = comparison.Compare(this.CancellationToken); // try one more time if it didn't work the first time if (!this.ComparisonResult.IsValid) { this.ComparisonResult = comparison.Compare(this.CancellationToken); } // Since DacFx does not throw on schema comparison cancellation, throwing here explicitly to ensure consistency of behavior if (!this.ComparisonResult.IsValid && this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } this.Differences = new List <DiffEntry>(); if (this.ComparisonResult.Differences != null) { foreach (SchemaDifference difference in this.ComparisonResult.Differences) { DiffEntry diffEntry = SchemaCompareUtils.CreateDiffEntry(difference, null); this.Differences.Add(diffEntry); } } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
public void Execute(TaskExecutionMode mode = TaskExecutionMode.Execute) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { SchemaCompareEndpoint sourceEndpoint = SchemaCompareUtils.CreateSchemaCompareEndpoint(this.Parameters.SourceEndpointInfo, this.SourceConnectionString); SchemaCompareEndpoint targetEndpoint = SchemaCompareUtils.CreateSchemaCompareEndpoint(this.Parameters.TargetEndpointInfo, this.TargetConnectionString); SchemaComparison comparison = new SchemaComparison(sourceEndpoint, targetEndpoint); if (Parameters.ExcludedSourceObjects != null) { foreach (var sourceObj in this.Parameters.ExcludedSourceObjects) { SchemaComparisonExcludedObjectId excludedObjId = SchemaCompareUtils.CreateExcludedObject(sourceObj); if (excludedObjId != null) { comparison.ExcludedSourceObjects.Add(excludedObjId); } } } if (Parameters.ExcludedTargetObjects != null) { foreach (var targetObj in this.Parameters.ExcludedTargetObjects) { SchemaComparisonExcludedObjectId excludedObjId = SchemaCompareUtils.CreateExcludedObject(targetObj); if (excludedObjId != null) { comparison.ExcludedTargetObjects.Add(excludedObjId); } } } if (this.Parameters.DeploymentOptions != null) { comparison.Options = SchemaCompareUtils.CreateSchemaCompareOptions(this.Parameters.DeploymentOptions); } comparison.SaveToFile(this.Parameters.ScmpFilePath, true); } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare save settings operation {0} failed with exception {1}", this.OperationId, e)); throw; } }
protected void GenerateScript(TaskExecutionMode mode) { if (mode == TaskExecutionMode.Script || mode == TaskExecutionMode.ExecuteAndScript) { this.ScriptContent = GetScriptContent(); if (SqlTask != null) { OnScriptAdded(new TaskScript { Status = SqlTaskStatus.Succeeded, Script = this.ScriptContent }); } } }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { this.PublishResult = this.ComparisonResult.PublishChangesToTarget(); } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare publish changes operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { this.DacServices = new DacServices(this.SqlConnection.ConnectionString); Execute(); } catch (Exception e) { Logger.Write(TraceEventType.Error, string.Format("DacFx import operation {0} failed with exception {1}", this.OperationId, e)); throw; } }
/// <summary> /// Exclude will return false if included dependencies are found. Include will also include dependencies that need to be included. /// This is the same behavior as SSDT /// </summary> /// <param name="mode"></param> public void Execute(TaskExecutionMode mode) { this.CancellationToken.ThrowIfCancellationRequested(); try { SchemaDifference node = this.FindDifference(this.ComparisonResult.Differences, this.Parameters.DiffEntry); if (node == null) { throw new InvalidOperationException(SR.SchemaCompareExcludeIncludeNodeNotFound); } this.Success = this.Parameters.IncludeRequest ? this.ComparisonResult.Include(node) : this.ComparisonResult.Exclude(node); // if include request (pass or fail), send dependencies that might have been affected by this request, given by GetIncludeDependencies() if (this.Parameters.IncludeRequest) { IEnumerable <SchemaDifference> affectedDependencies = this.ComparisonResult.GetIncludeDependencies(node); this.AffectedDependencies = affectedDependencies.Select(difference => SchemaCompareUtils.CreateDiffEntry(difference: difference, parent: null)).ToList(); } else { // if exclude was successful, the possible affected dependencies are given by GetIncludedDependencies() if (this.Success) { IEnumerable <SchemaDifference> affectedDependencies = this.ComparisonResult.GetIncludeDependencies(node); this.AffectedDependencies = affectedDependencies.Select(difference => SchemaCompareUtils.CreateDiffEntry(difference: difference, parent: null)).ToList(); } // if not successful, send back the exclude dependencies that caused it to fail else { IEnumerable <SchemaDifference> blockingDependencies = this.ComparisonResult.GetExcludeDependencies(node); blockingDependencies = blockingDependencies.Where(difference => difference.Included == node.Included); this.BlockingDependencies = blockingDependencies.Select(difference => SchemaCompareUtils.CreateDiffEntry(difference: difference, parent: null)).ToList(); } } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare publish changes operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
bool Execute(IBuildTask buildTask, TaskExecutionMode taskExecutionMode) { if (ConditionParser.ParseAndEvaluate(buildTask.Condition, project)) { switch (taskExecutionMode) { case TaskExecutionMode.Complete: return(buildTask.Execute()); case TaskExecutionMode.SkipAndSetOutput: return(buildTask.ResolveOutputItems()); default: throw new NotImplementedException(); } } return(true); }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { // Pass in Azure authentication token if needed this.DacServices = this.ConnInfo.ConnectionDetails.AzureAccountToken != null ? new DacServices(this.ConnectionString, new AccessTokenProvider(this.ConnInfo.ConnectionDetails.AzureAccountToken)) : new DacServices(this.ConnectionString); Execute(); } catch (Exception e) { Logger.Write(TraceEventType.Error, string.Format("DacFx import operation {0} failed with exception {1}", this.OperationId, e)); throw; } }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { SchemaCompareEndpoint sourceEndpoint = CreateSchemaCompareEndpoint(this.Parameters.SourceEndpointInfo, this.SourceConnectionString); SchemaCompareEndpoint targetEndpoint = CreateSchemaCompareEndpoint(this.Parameters.TargetEndpointInfo, this.TargetConnectionString); SchemaComparison comparison = new SchemaComparison(sourceEndpoint, targetEndpoint); if (this.Parameters.DeploymentOptions != null) { comparison.Options = this.CreateSchemaCompareOptions(this.Parameters.DeploymentOptions); } this.ComparisonResult = comparison.Compare(); // try one more time if it didn't work the first time if (!this.ComparisonResult.IsValid) { this.ComparisonResult = comparison.Compare(); } this.Differences = new List <DiffEntry>(); foreach (SchemaDifference difference in this.ComparisonResult.Differences) { DiffEntry diffEntry = CreateDiffEntry(difference, null); this.Differences.Add(diffEntry); } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
public void Execute(TaskExecutionMode mode) { this.CancellationToken.ThrowIfCancellationRequested(); try { SchemaDifference node = this.FindDifference(this.ComparisonResult.Differences, this.Parameters.DiffEntry); if (node == null) { throw new InvalidOperationException(SR.SchemaCompareExcludeIncludeNodeNotFound); } this.Success = this.Parameters.IncludeRequest ? this.ComparisonResult.Include(node) : this.ComparisonResult.Exclude(node); } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare publish changes operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
/// <summary> /// Execute a task /// </summary> /// <param name="mode">Task execution mode (e.g. script or execute)</param> /// <exception cref="InvalidOperationException"> /// The method has been called twice in parallel for the same instance. /// </exception> public void Execute(TaskExecutionMode mode) { try { var scriptText = GenerateScript(Parameters, cancellation.Token); if (scriptText != null) { SqlTask?.AddScript(SqlTaskStatus.Succeeded, scriptText); } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format( CultureInfo.InvariantCulture, "SQL Assessment: generate script operation failed with exception {0}", e.Message)); throw; } }
public void TaskExecutionStateTestProperties() { TaskExecutionMode howToExecuteTask = TaskExecutionMode.ExecuteTaskAndGatherOutputs; XmlDocument doc = new XmlDocument(); XmlElement taskNode = doc.CreateElement("Foo"); TaskExecutionStateHelper executionState = new TaskExecutionStateHelper( howToExecuteTask, LookupHelpers.CreateLookup(projectLevelProprtiesForInference, projectLevelItemsForInference), LookupHelpers.CreateLookup(projectLevelPropertiesForExecution, projectLevelItemsForExecution), taskNode, hostObject, projectFileOfTaskNode, parentProjectFullFileName, executionDirectory, nodeProxyId); executionState.HandleId = 1; Assert.AreEqual(1, executionState.HandleId, "Expected NodeProxyId to be equal to 1"); executionState.LoggingService = loggingHelper; Assert.AreEqual(loggingHelper, executionState.LoggingService, "Expected LoggingService to be equal to the loggingService set in the LoggingService property setter"); }
protected void SetExecutionMode(TaskExecutionMode mode) { switch (mode) { case TaskExecutionMode.Execute: { Server.ConnectionContext.SqlExecutionModes = SqlExecutionModes.ExecuteSql; break; } case TaskExecutionMode.ExecuteAndScript: { Server.ConnectionContext.SqlExecutionModes = SqlExecutionModes.ExecuteAndCaptureSql; break; } case TaskExecutionMode.Script: { Server.ConnectionContext.SqlExecutionModes = SqlExecutionModes.CaptureSql; break; } } }
public bool Build (IBuildTask buildTask, TaskExecutionMode taskExecutionMode, out bool executeOnErrors) { executeOnErrors = false; try { Init (); // populate list of referenced items and metadata ParseTaskAttributes (buildTask); if (consumedMetadataReferences.Count == 0) { return Execute (buildTask, taskExecutionMode); } BatchAndPrepareBuckets (); return Run (buildTask, taskExecutionMode, out executeOnErrors); } finally { consumedItemsByName = null; consumedMetadataReferences = null; consumedQMetadataReferences = null; consumedUQMetadataReferences = null; batchedItemsByName = null; commonItemsByName = null; } }
bool Run(IBuildTask buildTask, TaskExecutionMode taskExecutionMode, out bool executeOnErrors) { executeOnErrors = false; // Run the task in batches bool retval = true; if (buckets.Count == 0) { // batched mode, but no values in the corresponding items! retval = Execute(buildTask, taskExecutionMode); if (!retval && !buildTask.ContinueOnError) { executeOnErrors = true; } return(retval); } // batched foreach (Dictionary <string, BuildItemGroup> bucket in buckets) { project.PushBatch(bucket, commonItemsByName); try { retval = Execute(buildTask, taskExecutionMode); if (!retval && !buildTask.ContinueOnError) { executeOnErrors = true; break; } } finally { project.PopBatch(); } } return(retval); }
public void Execute(TaskExecutionMode mode) { if (this.CancellationToken.IsCancellationRequested) { throw new OperationCanceledException(this.CancellationToken); } try { this.PublishResult = this.ComparisonResult.PublishChangesToTarget(this.CancellationToken); if (!this.PublishResult.Success) { // Sending only errors and warnings - because overall message might be too big for task view ErrorMessage = string.Join(Environment.NewLine, this.PublishResult.Errors.Where(x => x.MessageType == SqlServer.Dac.DacMessageType.Error || x.MessageType == SqlServer.Dac.DacMessageType.Warning)); throw new Exception(ErrorMessage); } } catch (Exception e) { ErrorMessage = e.Message; Logger.Write(TraceEventType.Error, string.Format("Schema compare publish changes operation {0} failed with exception {1}", this.OperationId, e.Message)); throw; } }
/// <summary> /// Gathers task outputs in two ways: /// 1) Given an instantiated task that has finished executing, it extracts the outputs using .NET reflection. /// 2) Otherwise, it parses the task's output specifications and (statically) infers the outputs. /// </summary> /// <param name="howToExecuteTask"></param> /// <param name="task"></param> /// <param name="bucket"></param> /// <returns>true, if successful</returns> private bool GatherTaskOutputs(TaskExecutionMode howToExecuteTask, ITask task, ItemBucket bucket) { bool gatheredTaskOutputsSuccessfully = true; foreach (TaskOutput taskOutputSpecification in GetTaskOutputSpecifications(true)) { // if the task's outputs are supposed to be gathered if ( (taskOutputSpecification.ConditionAttribute == null) || Utilities.EvaluateCondition(taskOutputSpecification.ConditionAttribute.Value, taskOutputSpecification.ConditionAttribute, bucket.Expander, null, ParserOptions.AllowAll, loggingServices, buildEventContext) ) { ErrorUtilities.VerifyThrow(taskOutputSpecification.TaskParameterAttribute != null, "Invalid task output specification -- this should have been caught when the <Output> XML was parsed."); ErrorUtilities.VerifyThrow(taskOutputSpecification.TaskParameterAttribute.Value.Length > 0, "Invalid task output specification -- this should have been caught when the <Output> XML was parsed."); // expand all embedded properties, item metadata and item vectors in the task parameter name string taskParameterName = bucket.Expander.ExpandAllIntoString(taskOutputSpecification.TaskParameterAttribute); ProjectErrorUtilities.VerifyThrowInvalidProject(taskParameterName.Length > 0, taskOutputSpecification.TaskParameterAttribute, "InvalidEvaluatedAttributeValue", taskParameterName, taskOutputSpecification.TaskParameterAttribute.Value, XMakeAttributes.taskParameter, XMakeElements.output); string itemName = null; string propertyName = null; // check where the outputs are going -- into a vector, or a property? if (taskOutputSpecification.IsItemVector) { ErrorUtilities.VerifyThrow(taskOutputSpecification.ItemNameAttribute != null, "How can it be an output item if the item name is null? This should have been caught when the <Output> XML was parsed."); ErrorUtilities.VerifyThrow(taskOutputSpecification.ItemNameAttribute.Value.Length > 0, "Invalid task output specification -- this should have been caught when the <Output> XML was parsed."); // expand all embedded properties, item metadata and item vectors in the item type name itemName = bucket.Expander.ExpandAllIntoString(taskOutputSpecification.ItemNameAttribute); ProjectErrorUtilities.VerifyThrowInvalidProject(itemName.Length > 0, taskOutputSpecification.ItemNameAttribute, "InvalidEvaluatedAttributeValue", itemName, taskOutputSpecification.ItemNameAttribute.Value, XMakeAttributes.itemName, XMakeElements.output); } else { ErrorUtilities.VerifyThrow(taskOutputSpecification.IsProperty, "Invalid task output specification -- this should have been caught when the <Output> XML was parsed."); ErrorUtilities.VerifyThrow(taskOutputSpecification.PropertyNameAttribute != null, "How can it be an output property if the property name is null? This should have been caught when the <Output> XML was parsed."); ErrorUtilities.VerifyThrow(taskOutputSpecification.PropertyNameAttribute.Value.Length > 0, "Invalid task output specification -- this should have been caught when the <Output> XML was parsed."); // expand all embedded properties, item metadata and item vectors in the property name propertyName = bucket.Expander.ExpandAllIntoString(taskOutputSpecification.PropertyNameAttribute); ProjectErrorUtilities.VerifyThrowInvalidProject(propertyName.Length > 0, taskOutputSpecification.PropertyNameAttribute, "InvalidEvaluatedAttributeValue", propertyName, taskOutputSpecification.PropertyNameAttribute.Value, XMakeAttributes.propertyName, XMakeElements.output); } // if we're gathering outputs by .NET reflection if (howToExecuteTask == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { gatheredTaskOutputsSuccessfully = GatherGeneratedTaskOutputs(bucket.Lookup, taskOutputSpecification, taskParameterName, itemName, propertyName, task); } // if we're inferring outputs based on information in the task and <Output> tags else { Debug.Assert(howToExecuteTask == TaskExecutionMode.InferOutputsOnly); InferTaskOutputs(bucket.Lookup, taskOutputSpecification, taskParameterName, itemName, propertyName, bucket); } } if (!gatheredTaskOutputsSuccessfully) { break; } } return gatheredTaskOutputsSuccessfully; }
/// <summary> /// Execute a task object for a given bucket. /// </summary> /// <param name="engineProxy"></param> /// <param name="bucket"></param> /// <param name="howToExecuteTask"></param> /// <param name="task"></param> /// <param name="taskResult">Whether the task returned true from Execute</param> /// <returns>true if task executed successfully (possibly failed but continueOnError=true)</returns> private bool ExecuteInstantiatedTask(EngineProxy engineProxy, ItemBucket bucket, TaskExecutionMode howToExecuteTask, ITask task, out bool taskResult) { UpdateContinueOnError(bucket, engineProxy); taskResult = false; bool taskExecutedSuccessfully = true; if (!InitializeTask(task, bucket, engineProxy)) { // The task cannot be initialized. ProjectErrorUtilities.VerifyThrowInvalidProject(false, taskNode, "TaskParametersError", TaskName, String.Empty); } else { bool taskReturned = false; try { taskResult = task.Execute(); taskReturned = true; } // if a logger has failed, abort immediately catch (LoggerException) { // Polite logger failure throw; } catch (InternalLoggerException) { // Logger threw arbitrary exception throw; } // 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. Probably we should try to avoid catching truly fatal exceptions, // e.g., StackOverflowException catch (Exception e) { if (continueOnError) { loggingServices.LogTaskWarningFromException(buildEventContext, e, // Don't try and log the line/column number for this error if // ContinueOnError=true, because it's too expensive to do so, // and this error may be fairly common and expected. new BuildEventFileInfo(projectFileOfTaskNode), TaskName); // Log a message explaining why we converted the previous error into a warning. loggingServices.LogComment(buildEventContext, MessageImportance.Normal, "ErrorConvertedIntoWarning"); } else { loggingServices.LogFatalTaskError(buildEventContext, e, CreateBuildEventFileInfoForTask(), TaskName); } } // If the task returned attempt to gather its outputs. If gathering outputs fails set the taskResults // to false if (taskReturned) { taskResult = GatherTaskOutputs(howToExecuteTask, task, 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 if (!taskResult) { if (!continueOnError) { taskExecutedSuccessfully = false; } else { loggingServices.LogComment(buildEventContext, MessageImportance.Normal, "TaskContinuedDueToContinueOnError", "ContinueOnError", TaskName, "true"); } } } return taskExecutedSuccessfully; }
/// <summary> /// Executes the task. /// </summary> public Task<WorkUnitResult> ExecuteTask(TargetLoggingContext targetLoggingContext, BuildRequestEntry requestEntry, ITargetBuilderCallback targetBuilderCallback, ProjectTargetInstanceChild task, TaskExecutionMode mode, Lookup lookupForInference, Lookup lookupForExecution, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return Task<WorkUnitResult>.FromResult(new WorkUnitResult(WorkUnitResultCode.Canceled, WorkUnitActionCode.Stop, null)); } ProjectOnErrorInstance errorTask = task as ProjectOnErrorInstance; if (null != errorTask) { ErrorTasks.Add(errorTask); } else { ProjectTaskInstance taskInstance = task as ProjectTaskInstance; ExecutedTasks.Add(taskInstance); if ((mode & TaskExecutionMode.InferOutputsOnly) == TaskExecutionMode.InferOutputsOnly) { lookupForInference.AddNewItem(new ProjectItemInstance(requestEntry.RequestConfiguration.Project, taskInstance.Name + "_Item", "Item", task.Location.File)); } else if ((mode & TaskExecutionMode.ExecuteTaskAndGatherOutputs) == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { lookupForExecution.AddNewItem(new ProjectItemInstance(requestEntry.RequestConfiguration.Project, taskInstance.Name + "_Item", "Item", task.Location.File)); } if (String.Equals(taskInstance.Name, "CallTarget", StringComparison.OrdinalIgnoreCase)) { taskInstance.GetParameter("Targets"); char[] splitter = new char[] { ';' }; targetBuilderCallback.LegacyCallTarget(taskInstance.GetParameter("Targets").Split(splitter), false, taskInstance.Location); } _taskNumber++; if (FailTaskNumber == _taskNumber) { if (taskInstance.ContinueOnError == "True") { return Task<WorkUnitResult>.FromResult(new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Continue, null)); } return Task<WorkUnitResult>.FromResult(new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Stop, null)); } } return Task<WorkUnitResult>.FromResult(new WorkUnitResult(WorkUnitResultCode.Success, WorkUnitActionCode.Continue, null)); }
bool Execute (IBuildTask buildTask, TaskExecutionMode taskExecutionMode) { if (ConditionParser.ParseAndEvaluate (buildTask.Condition, project)) { switch (taskExecutionMode) { case TaskExecutionMode.Complete: return buildTask.Execute (); case TaskExecutionMode.SkipAndSetOutput: return buildTask.ResolveOutputItems (); default: throw new NotImplementedException (); } } return true; }
/// <summary> /// Mock out and override the method inside of TaskExecutionState which makes the calls to the task engine. /// </summary> internal override bool TaskEngineExecuteTask(TaskEngine taskEngine, TaskExecutionMode howToExecuteTask, Lookup lookup) { return targetInferenceSuccessful; }
/// <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(); } }
/// <summary> /// Called to execute a task within a target. This method instantiates the task, sets its parameters, and executes it. /// </summary> /// <returns>true, if successful</returns> internal bool ExecuteTask(TaskExecutionMode howToExecuteTask, Lookup lookup) { ErrorUtilities.VerifyThrow(lookup != null, "Need to specify items available to task."); bool taskExecutedSuccessfully = false; EngineProxy engineProxy = null; ArrayList buckets = null; try { engineProxy = new EngineProxy(parentModule, handleId, parentProjectFullFileName, projectFileOfTaskNode, loggingServices, buildEventContext); List<string> taskParameterValues = CreateListOfParameterValues(); buckets = BatchingEngine.PrepareBatchingBuckets(taskNode, taskParameterValues, lookup); lookupHash = null; // Only create a hash table if there are more than one bucket as this is the only time a property can be overridden if (buckets.Count > 1) { lookupHash = Utilities.CreateTableIfNecessary((Hashtable)null); } // Loop through each of the batch buckets and execute them one at a time for (int i=0; i < buckets.Count; i++) { // Execute the batch bucket, pass in which bucket we are executing so that we know when to get a new taskId for the bucket. taskExecutedSuccessfully = ExecuteBucket(engineProxy, (ItemBucket)buckets[i], i, howToExecuteTask); if (!taskExecutedSuccessfully) { break; } } } finally { // Remove the AssemblyResolve handler in the default AppDomain, we are done with the task. if (resolver != null) { resolver.RemoveHandler(); } if (engineProxy != null) { engineProxy.MarkAsInActive(); } // Now all task batches are done, apply all item adds to the outer // target batch; we do this even if the task wasn't found (in that case, // no items or properties will have been added to the scope) if (buckets != null) { foreach (ItemBucket bucket in buckets) { bucket.Lookup.LeaveScope(); } } } return taskExecutedSuccessfully; }
/// <summary> /// Logs a task skipped message if necessary. /// </summary> private void LogSkippedTask(ItemBucket bucket, TaskExecutionMode howToExecuteTask) { // If this is an Intrinsic task, it does not log skips. if (_taskNode != null) { if (howToExecuteTask == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { if (!_targetLoggingContext.LoggingService.OnlyLogCriticalEvents) { // Expand the expression for the Log. string expanded = bucket.Expander.ExpandIntoStringAndUnescape(_targetChildInstance.Condition, ExpanderOptions.ExpandAll, _targetChildInstance.ConditionLocation); // Whilst we are within the processing of the task, we haven't actually started executing it, so // our skip task message needs to be in the context of the target. However any errors should be reported // at the point where the task appears in the project. _targetLoggingContext.LogComment ( MessageImportance.Low, "TaskSkippedFalseCondition", _taskNode.Name, _targetChildInstance.Condition, expanded ); } } } }
/// <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; }
/// <summary> /// Called to execute a task within a target. This method instantiates the task, sets its parameters, and executes it. /// </summary> /// <returns>true, if successful</returns> private async Task<WorkUnitResult> ExecuteTask(TaskExecutionMode mode, Lookup lookup) { ErrorUtilities.VerifyThrowArgumentNull(lookup, "lookup"); WorkUnitResult taskResult = new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Stop, null); TaskHost taskHost = null; List<ItemBucket> buckets = null; try { 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); } List<string> taskParameterValues = CreateListOfParameterValues(); buckets = BatchingEngine.PrepareBatchingBuckets(taskParameterValues, lookup, _targetChildInstance.Location); Dictionary<string, string> lookupHash = null; // Only create a hash table if there are more than one bucket as this is the only time a property can be overridden if (buckets.Count > 1) { lookupHash = new Dictionary<string, string>(MSBuildNameIgnoreCaseComparer.Default); } WorkUnitResult aggregateResult = new WorkUnitResult(); // Loop through each of the batch buckets and execute them one at a time for (int i = 0; i < buckets.Count; i++) { // Execute the batch bucket, pass in which bucket we are executing so that we know when to get a new taskId for the bucket. taskResult = await ExecuteBucket(taskHost, (ItemBucket)buckets[i], mode, lookupHash); aggregateResult = aggregateResult.AggregateResult(taskResult); if (aggregateResult.ActionCode == WorkUnitActionCode.Stop) { break; } } taskResult = aggregateResult; } finally { _taskExecutionHost.CleanupForTask(); if (taskHost != null) { taskHost.MarkAsInactive(); } // Now all task batches are done, apply all item adds to the outer // target batch; we do this even if the task wasn't found (in that case, // no items or properties will have been added to the scope) if (buckets != null) { foreach (ItemBucket bucket in buckets) { bucket.LeaveScope(); } } } return taskResult; }
/// <summary> /// Gathers task outputs in two ways: /// 1) Given an instantiated task that has finished executing, it extracts the outputs using .NET reflection. /// 2) Otherwise, it parses the task's output specifications and (statically) infers the outputs. /// </summary> /// <param name="taskExecutionHost">The task execution host.</param> /// <param name="howToExecuteTask">The task execution mode</param> /// <param name="bucket">The bucket to which the task execution belongs.</param> /// <returns>true, if successful</returns> private bool GatherTaskOutputs(ITaskExecutionHost taskExecutionHost, TaskExecutionMode howToExecuteTask, ItemBucket bucket) { bool gatheredTaskOutputsSuccessfully = true; foreach (ProjectTaskInstanceChild taskOutputSpecification in _taskNode.Outputs) { // if the task's outputs are supposed to be gathered bool condition = ConditionEvaluator.EvaluateCondition ( taskOutputSpecification.Condition, ParserOptions.AllowAll, bucket.Expander, ExpanderOptions.ExpandAll, _buildRequestEntry.ProjectRootDirectory, taskOutputSpecification.ConditionLocation, _targetLoggingContext.LoggingService, _targetLoggingContext.BuildEventContext ); if (condition) { string taskParameterName = null; bool outputTargetIsItem = false; string outputTargetName = null; // check where the outputs are going -- into a vector, or a property? ProjectTaskOutputItemInstance taskOutputItemInstance = taskOutputSpecification as ProjectTaskOutputItemInstance; if (taskOutputItemInstance != null) { // expand all embedded properties, item metadata and item vectors in the item type name outputTargetIsItem = true; outputTargetName = bucket.Expander.ExpandIntoStringAndUnescape(taskOutputItemInstance.ItemType, ExpanderOptions.ExpandAll, taskOutputItemInstance.ItemTypeLocation); taskParameterName = taskOutputItemInstance.TaskParameter; ProjectErrorUtilities.VerifyThrowInvalidProject ( outputTargetName.Length > 0, taskOutputItemInstance.ItemTypeLocation, "InvalidEvaluatedAttributeValue", outputTargetName, taskOutputItemInstance.ItemType, XMakeAttributes.itemName, XMakeElements.output ); } else { ProjectTaskOutputPropertyInstance taskOutputPropertyInstance = taskOutputSpecification as ProjectTaskOutputPropertyInstance; outputTargetIsItem = false; // expand all embedded properties, item metadata and item vectors in the property name outputTargetName = bucket.Expander.ExpandIntoStringAndUnescape(taskOutputPropertyInstance.PropertyName, ExpanderOptions.ExpandAll, taskOutputPropertyInstance.PropertyNameLocation); taskParameterName = taskOutputPropertyInstance.TaskParameter; ProjectErrorUtilities.VerifyThrowInvalidProject ( outputTargetName.Length > 0, taskOutputPropertyInstance.PropertyNameLocation, "InvalidEvaluatedAttributeValue", outputTargetName, taskOutputPropertyInstance.PropertyName, XMakeAttributes.propertyName, XMakeElements.output ); } string unexpandedTaskParameterName = taskParameterName; taskParameterName = bucket.Expander.ExpandIntoStringAndUnescape(taskParameterName, ExpanderOptions.ExpandAll, taskOutputSpecification.TaskParameterLocation); ProjectErrorUtilities.VerifyThrowInvalidProject ( taskParameterName.Length > 0, taskOutputSpecification.TaskParameterLocation, "InvalidEvaluatedAttributeValue", taskParameterName, unexpandedTaskParameterName, XMakeAttributes.taskParameter, XMakeElements.output ); // if we're gathering outputs by .NET reflection if (howToExecuteTask == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { gatheredTaskOutputsSuccessfully = taskExecutionHost.GatherTaskOutputs(taskParameterName, taskOutputSpecification.Location, outputTargetIsItem, outputTargetName); } else { // If we're inferring outputs based on information in the task and <Output> tags ErrorUtilities.VerifyThrow(howToExecuteTask == TaskExecutionMode.InferOutputsOnly, "should be inferring"); // UNDONE: Refactor this method to use the same flag/string paradigm we use above, rather than two strings and the task output spec. InferTaskOutputs(bucket.Lookup, taskOutputSpecification, taskParameterName, outputTargetName, outputTargetName, bucket); } } if (!gatheredTaskOutputsSuccessfully) { break; } } return gatheredTaskOutputsSuccessfully; }
/// <summary> /// Since we could not derrive from TaskEngine and have no Interface, we need to overide the method in here and /// replace the calls when testing the class because of the calls to TaskEngine. If at a future time we get a mock task /// engine, Interface or a non sealed TaskEngine these methods can disappear. /// </summary> /// <returns></returns> virtual internal bool TaskEngineExecuteTask( TaskEngine taskEngine, TaskExecutionMode howTaskShouldBeExecuted, Lookup lookup ) { return taskEngine.ExecuteTask ( howTaskShouldBeExecuted, lookup ); }
/// <summary> /// Execute a single bucket /// </summary> /// <returns>true if execution succeeded</returns> private async Task<WorkUnitResult> ExecuteBucket(TaskHost taskHost, ItemBucket bucket, TaskExecutionMode howToExecuteTask, Dictionary<string, string> lookupHash) { // On Intrinsic tasks, we do not allow batchable params, therefore metadata is excluded. ParserOptions parserOptions = (_taskNode == null) ? ParserOptions.AllowPropertiesAndItemLists : ParserOptions.AllowAll; WorkUnitResult taskResult = new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Stop, null); bool condition = ConditionEvaluator.EvaluateCondition ( _targetChildInstance.Condition, parserOptions, bucket.Expander, ExpanderOptions.ExpandAll, _buildRequestEntry.ProjectRootDirectory, _targetChildInstance.ConditionLocation, _targetLoggingContext.LoggingService, _targetLoggingContext.BuildEventContext ); if (!condition) { LogSkippedTask(bucket, howToExecuteTask); taskResult = new WorkUnitResult(WorkUnitResultCode.Skipped, WorkUnitActionCode.Continue, null); return taskResult; } // If this is an Intrinsic task, it gets handled in a special fashion. if (_taskNode == null) { ExecuteIntrinsicTask(bucket); taskResult = new WorkUnitResult(WorkUnitResultCode.Success, WorkUnitActionCode.Continue, null); } else { if (_componentHost.BuildParameters.SaveOperatingEnvironment) { // Change to the project root directory. // If that directory does not exist, do nothing. (Do not check first as it is almost always there and it is slow) // This is because if the project has not been saved, this directory may not exist, yet it is often useful to still be able to build the project. // No errors are masked by doing this: errors loading the project from disk are reported at load time, if necessary. NativeMethodsShared.SetCurrentDirectory(_buildRequestEntry.ProjectRootDirectory); } if (howToExecuteTask == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { // We need to find the task before logging the task started event so that the using task statement comes before the task started event IDictionary<string, string> taskIdentityParameters = GatherTaskIdentityParameters(bucket.Expander); TaskRequirements? requirements = _taskExecutionHost.FindTask(taskIdentityParameters); if (requirements != null) { TaskLoggingContext taskLoggingContext = _targetLoggingContext.LogTaskBatchStarted(_projectFullPath, _targetChildInstance); try { if ( ((requirements.Value & TaskRequirements.RequireSTAThread) == TaskRequirements.RequireSTAThread) && (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) ) { taskResult = ExecuteTaskInSTAThread(bucket, taskLoggingContext, taskIdentityParameters, taskHost, howToExecuteTask); } else { taskResult = await InitializeAndExecuteTask(taskLoggingContext, bucket, taskIdentityParameters, taskHost, howToExecuteTask); } if (lookupHash != null) { List<string> overrideMessages = bucket.Lookup.GetPropertyOverrideMessages(lookupHash); if (overrideMessages != null) { foreach (string s in overrideMessages) { taskLoggingContext.LogCommentFromText(MessageImportance.Low, s); } } } } catch (InvalidProjectFileException e) { // Make sure the Invalid Project error gets logged *before* TaskFinished. Otherwise, // the log is confusing. taskLoggingContext.LogInvalidProjectFileError(e); _continueOnError = ContinueOnError.ErrorAndStop; } finally { // Flag the completion of the task. taskLoggingContext.LogTaskBatchFinished(_projectFullPath, taskResult.ResultCode == WorkUnitResultCode.Success || taskResult.ResultCode == WorkUnitResultCode.Skipped); if (taskResult.ResultCode == WorkUnitResultCode.Failed && _continueOnError == ContinueOnError.WarnAndContinue) { // We coerce the failing result to a successful result. taskResult = new WorkUnitResult(WorkUnitResultCode.Success, taskResult.ActionCode, taskResult.Exception); } } } } else { ErrorUtilities.VerifyThrow(howToExecuteTask == TaskExecutionMode.InferOutputsOnly, "should be inferring"); ErrorUtilities.VerifyThrow ( GatherTaskOutputs(null, howToExecuteTask, bucket), "The method GatherTaskOutputs() should never fail when inferring task outputs." ); if (lookupHash != null) { List<string> overrideMessages = bucket.Lookup.GetPropertyOverrideMessages(lookupHash); if (overrideMessages != null) { foreach (string s in overrideMessages) { _targetLoggingContext.LogCommentFromText(MessageImportance.Low, s); } } } taskResult = new WorkUnitResult(WorkUnitResultCode.Success, WorkUnitActionCode.Continue, null); } } return taskResult; }
/// <summary> /// Execute a single bucket /// </summary> /// <returns>true if execution succeeded</returns> private bool ExecuteBucket(EngineProxy engineProxy, ItemBucket bucket, int bucketNumber, TaskExecutionMode howToExecuteTask) { if ( (this.conditionAttribute != null) && !Utilities.EvaluateCondition(this.conditionAttribute.Value, this.conditionAttribute, bucket.Expander, null, ParserOptions.AllowAll, loggingServices, buildEventContext) ) { // Condition is false if (howToExecuteTask == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { if (!loggingServices.OnlyLogCriticalEvents) { // Expand the expression for the Log. string expanded = bucket.Expander.ExpandAllIntoString(this.conditionAttribute); // Whilst we are within the processing of the task, we haven't actually started executing it, so // our skip task message needs to be in the context of the target. However any errors should be reported // at the point where the task appears in the project. BuildEventContext skipTaskContext = new BuildEventContext(buildEventContext.NodeId, buildEventContext.TargetId, buildEventContext.ProjectContextId, BuildEventContext.InvalidTaskId); loggingServices.LogComment(skipTaskContext, "TaskSkippedFalseCondition", TaskName, this.conditionAttribute.Value, expanded); } } return true; } bool taskExecutedSuccessfully = true; // Condition is true if (howToExecuteTask == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { // Now that we know we will need to execute the task, // Ensure the TaskEngine is initialized with the task class // This does the work of task discovery, if it // hasn't already been done. bool taskClassWasFound = FindTask(); if (!taskClassWasFound) { // Task wasn't discovered, we cannot continue return false; } // Now instantiate, initialize, and execute the task ITask task; // If this is the first bucket use the task context originally given to it, for the remaining buckets get a unique id for them if (bucketNumber != 0) { // Ask the parent engine the next Id which should be used for the taskId. buildEventContext = new BuildEventContext(buildEventContext.NodeId, buildEventContext.TargetId, buildEventContext.ProjectContextId, parentModule.GetNextTaskId()); // For each batch the engineProxy needs to have the correct buildEventContext as all messages comming from a task will have the buildEventContext of the EngineProxy. engineProxy.BuildEventContext = buildEventContext; } loggingServices.LogTaskStarted(buildEventContext, TaskName, parentProjectFullFileName, projectFileOfTaskNode); AppDomain taskAppDomain = PrepareAppDomain(); bool taskResult = false; try { task = InstantiateTask(taskAppDomain); // If task cannot be instantiated, we consider its declaration/usage to be invalid. ProjectErrorUtilities.VerifyThrowInvalidProject(task != null, taskNode, "TaskDeclarationOrUsageError", TaskName); taskExecutedSuccessfully = ExecuteInstantiatedTask(engineProxy, bucket, howToExecuteTask, task, out taskResult); if (lookupHash != null) { List<string> overrideMessages = bucket.Lookup.GetPropertyOverrideMessages(lookupHash); if (overrideMessages != null) { foreach (string s in overrideMessages) { loggingServices.LogCommentFromText(buildEventContext, MessageImportance.Low, s); } } } } catch (InvalidProjectFileException e) { // Make sure the Invalid Project error gets logged *before* TaskFinished. Otherwise, // the log is confusing. loggingServices.LogInvalidProjectFileError(buildEventContext, e); throw; } finally { // Flag the completion of the task. loggingServices.LogTaskFinished( buildEventContext, TaskName, parentProjectFullFileName, projectFileOfTaskNode, taskResult); task = null; if (taskAppDomain != null) { AppDomain.Unload(taskAppDomain); taskAppDomain = null; } } } else { Debug.Assert(howToExecuteTask == TaskExecutionMode.InferOutputsOnly); ErrorUtilities.VerifyThrow(GatherTaskOutputs(howToExecuteTask, null, bucket), "The method GatherTaskOutputs() should never fail when inferring task outputs."); if (lookupHash != null) { List<string> overrideMessages = bucket.Lookup.GetPropertyOverrideMessages(lookupHash); if (overrideMessages != null) { foreach (string s in overrideMessages) { loggingServices.LogCommentFromText(buildEventContext, MessageImportance.Low, s); } } } } return taskExecutedSuccessfully; }
/// <summary> /// Builds the task specified by the XML. /// </summary> /// <param name="loggingContext">The logging context of the target</param> /// <param name="requestEntry">The build request entry being built</param> /// <param name="targetBuilderCallback">The target builder callback.</param> /// <param name="taskInstance">The task instance.</param> /// <param name="mode">The mode in which to execute tasks.</param> /// <param name="inferLookup">The lookup to be used for inference.</param> /// <param name="executeLookup">The lookup to be used during execution.</param> /// <returns>The result of running the task batch.</returns> /// <remarks> /// The ExecuteTask method takes a task as specified by XML and executes it. This procedure is comprised /// of the following steps: /// 1. Loading the Task from its containing assembly by looking it up in the task registry /// 2. Determining if the task is batched. If it is, create the batches and execute each as if it were a non-batched task /// 3. If the task is not batched, execute it. /// 4. If the task was batched, hold on to its Lookup until all of the natches are done, then merge them. /// </remarks> public async Task<WorkUnitResult> ExecuteTask(TargetLoggingContext loggingContext, BuildRequestEntry requestEntry, ITargetBuilderCallback targetBuilderCallback, ProjectTargetInstanceChild taskInstance, TaskExecutionMode mode, Lookup inferLookup, Lookup executeLookup, CancellationToken cancellationToken) { ErrorUtilities.VerifyThrow(taskInstance != null, "Need to specify the task instance."); _buildRequestEntry = requestEntry; _targetBuilderCallback = targetBuilderCallback; _cancellationToken = cancellationToken; _targetChildInstance = taskInstance; // In the case of Intrinsic tasks, taskNode will end up null. Currently this is how we distinguish // intrinsic from extrinsic tasks. _taskNode = taskInstance as ProjectTaskInstance; if (_taskNode != null && requestEntry.Request.HostServices != null) { _taskHostObject = requestEntry.Request.HostServices.GetHostObject(requestEntry.RequestConfiguration.Project.FullPath, loggingContext.Target.Name, _taskNode.Name); } _projectFullPath = requestEntry.RequestConfiguration.Project.FullPath; // this.handleId = handleId; No handles // this.parentModule = parentModule; No task execution module _continueOnError = ContinueOnError.ErrorAndStop; _targetLoggingContext = loggingContext; WorkUnitResult taskResult = new WorkUnitResult(WorkUnitResultCode.Failed, WorkUnitActionCode.Stop, null); if ((mode & TaskExecutionMode.InferOutputsOnly) == TaskExecutionMode.InferOutputsOnly) { taskResult = await ExecuteTask(TaskExecutionMode.InferOutputsOnly, inferLookup); } if ((mode & TaskExecutionMode.ExecuteTaskAndGatherOutputs) == TaskExecutionMode.ExecuteTaskAndGatherOutputs) { taskResult = await ExecuteTask(TaskExecutionMode.ExecuteTaskAndGatherOutputs, executeLookup); } return taskResult; }
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; }