bool RunBuildTask(ProjectTargetInstance target, ProjectTaskInstance taskInstance, TargetResult targetResult, InternalBuildArguments args) { var request = submission.BuildRequest; var host = request.HostServices == null ? null : request.HostServices.GetHostObject(request.ProjectFullPath, target.Name, taskInstance.Name); // Create Task instance. var factoryIdentityParameters = new Dictionary <string, string> (); factoryIdentityParameters ["MSBuildRuntime"] = taskInstance.MSBuildRuntime; factoryIdentityParameters ["MSBuildArchitecture"] = taskInstance.MSBuildArchitecture; var task = args.BuildTaskFactory.CreateTask(taskInstance.Name, factoryIdentityParameters, this); if (task == null) { throw new InvalidOperationException(string.Format("TaskFactory {0} returned null Task", args.BuildTaskFactory)); } LogMessageEvent(new BuildMessageEventArgs(string.Format("Using task {0} from {1}", taskInstance.Name, task.GetType()), null, null, MessageImportance.Low)); task.HostObject = host; task.BuildEngine = this; // Prepare task parameters. var evaluator = new ExpressionEvaluator(project); var evaluatedTaskParams = taskInstance.Parameters.Select(p => new KeyValuePair <string, string> (p.Key, project.ExpandString(evaluator, p.Value))); var requiredProps = task.GetType().GetProperties() .Where(p => p.CanWrite && p.GetCustomAttributes(typeof(RequiredAttribute), true).Any()); var missings = requiredProps.Where(p => !evaluatedTaskParams.Any(tp => tp.Key.Equals(p.Name, StringComparison.OrdinalIgnoreCase))); if (missings.Any()) { throw new InvalidOperationException(string.Format("Task {0} of type {1} is used without specifying mandatory property: {2}", taskInstance.Name, task.GetType(), string.Join(", ", missings.Select(p => p.Name).ToArray()))); } foreach (var p in evaluatedTaskParams) { switch (p.Key.ToLower()) { case "condition": case "continueonerror": continue; } var prop = task.GetType().GetProperty(p.Key); if (prop == null) { throw new InvalidOperationException(string.Format("Task {0} does not have property {1}", taskInstance.Name, p.Key)); } if (!prop.CanWrite) { throw new InvalidOperationException(string.Format("Task {0} has property {1} but it is read-only.", taskInstance.Name, p.Key)); } if (string.IsNullOrEmpty(p.Value) && !requiredProps.Contains(prop)) { continue; } try { prop.SetValue(task, ConvertTo(p.Value, prop.PropertyType, evaluator), null); } catch (Exception ex) { throw new InvalidOperationException(string.Format("Failed to convert '{0}' for property '{1}' of type {2}", p.Value, prop.Name, prop.PropertyType), ex); } } // Do execute task. bool taskSuccess = false; event_source.FireTaskStarted(this, new TaskStartedEventArgs("Task Started", null, project.FullPath, taskInstance.FullPath, taskInstance.Name)); try { taskSuccess = task.Execute(); if (!taskSuccess) { targetResult.Failure(null); if (!ContinueOnError) { return(false); } } else { // Evaluate task output properties and items. foreach (var to in taskInstance.Outputs) { if (!project.EvaluateCondition(to.Condition)) { continue; } var toItem = to as ProjectTaskOutputItemInstance; var toProp = to as ProjectTaskOutputPropertyInstance; string taskParameter = toItem != null ? toItem.TaskParameter : toProp.TaskParameter; var pi = task.GetType().GetProperty(taskParameter); if (pi == null) { throw new InvalidOperationException(string.Format("Task {0} does not have property {1} specified as TaskParameter", taskInstance.Name, toItem.TaskParameter)); } if (!pi.CanRead) { throw new InvalidOperationException(string.Format("Task {0} has property {1} specified as TaskParameter, but it is write-only", taskInstance.Name, toItem.TaskParameter)); } var value = pi.GetValue(task, null); var valueString = ConvertFrom(value); if (toItem != null) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Output Item {0} from TaskParameter {1}: {2}", toItem.ItemType, toItem.TaskParameter, valueString), null, null, MessageImportance.Low)); Action <ITaskItem> addItem = i => { var metadata = new ArrayList(i.MetadataNames).ToArray().Cast <string> ().Select(n => new KeyValuePair <string, string> (n, i.GetMetadata(n))); args.Project.AddItem(toItem.ItemType, i.ItemSpec, metadata); }; var taskItemArray = value as ITaskItem []; if (taskItemArray != null) { foreach (var ti in taskItemArray) { addItem(ti); } } else { var taskItem = value as ITaskItem; if (taskItem != null) { addItem(taskItem); } else { foreach (var item in valueString.Split(';')) { args.Project.AddItem(toItem.ItemType, item); } } } } else { LogMessageEvent(new BuildMessageEventArgs(string.Format("Output Property {0} from TaskParameter {1}: {2}", toProp.PropertyName, toProp.TaskParameter, valueString), null, null, MessageImportance.Low)); args.Project.SetProperty(toProp.PropertyName, valueString); } } } } finally { event_source.FireTaskFinished(this, new TaskFinishedEventArgs("Task Finished", null, project.FullPath, taskInstance.FullPath, taskInstance.Name, taskSuccess)); } return(true); }
// FIXME: Exception should be caught at caller site. bool DoBuildTarget(ProjectTargetInstance target, TargetResult targetResult, InternalBuildArguments args) { var request = submission.BuildRequest; // Here we check cancellation (only after TargetStarted event). if (args.CheckCancel()) { targetResult.Failure(new BuildAbortedException("Build has canceled")); return(false); } try { foreach (var child in target.Children) { // Evaluate additional target properties var tp = child as ProjectPropertyGroupTaskInstance; if (tp != null) { if (!args.Project.EvaluateCondition(tp.Condition)) { continue; } foreach (var p in tp.Properties) { if (!args.Project.EvaluateCondition(p.Condition)) { continue; } var value = args.Project.ExpandString(p.Value); project.SetProperty(p.Name, value); } continue; } var ii = child as ProjectItemGroupTaskInstance; if (ii != null) { if (!args.Project.EvaluateCondition(ii.Condition)) { continue; } foreach (var item in ii.Items) { if (!args.Project.EvaluateCondition(item.Condition)) { continue; } project.AddItem(item.ItemType, project.ExpandString(item.Include)); } continue; } var task = child as ProjectTaskInstance; if (task != null) { current_task = task; if (!args.Project.EvaluateCondition(task.Condition)) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Task '{0}' was skipped because condition '{1}' wasn't met.", task.Name, task.Condition), null, null, MessageImportance.Low)); continue; } if (!RunBuildTask(target, task, targetResult, args)) { return(false); } continue; } var onError = child as ProjectOnErrorInstance; if (onError != null) { continue; // evaluated under catch clause. } throw new NotSupportedException(string.Format("Unexpected Target element children \"{0}\"", child.GetType())); } } catch (Exception ex) { // fallback task specified by OnError element foreach (var c in target.Children.OfType <ProjectOnErrorInstance> ()) { if (!args.Project.EvaluateCondition(c.Condition)) { continue; } foreach (var fallbackTarget in project.ExpandString(c.ExecuteTargets).Split(';')) { BuildTargetByName(fallbackTarget, args); } } int line = target.Location != null ? target.Location.Line : 0; int col = target.Location != null ? target.Location.Column : 0; LogErrorEvent(new BuildErrorEventArgs(null, null, target.FullPath, line, col, 0, 0, ex.Message, null, null)); targetResult.Failure(ex); return(false); } return(true); }