void BuildProject(InternalBuildArguments args) { var request = submission.BuildRequest; var parameters = submission.BuildManager.OngoingBuildParameters; this.project = args.Project; string directoryBackup = Directory.GetCurrentDirectory(); Directory.SetCurrentDirectory(project.Directory); event_source.FireBuildStarted(this, new BuildStartedEventArgs("Build Started", null, DateTime.Now)); try { var initialGlobalPropertiesFormatted = "Initial Global Properties:\n" + string.Join(Environment.NewLine, project.Properties.OrderBy(p => p.Name).Where(p => p.IsImmutable).Select(p => string.Format("{0} = {1}", p.Name, p.EvaluatedValue)).ToArray()); LogMessageEvent(new BuildMessageEventArgs(initialGlobalPropertiesFormatted, null, null, MessageImportance.Low)); var initialProjectPropertiesFormatted = "Initial Project Properties:\n" + string.Join(Environment.NewLine, project.Properties.OrderBy(p => p.Name).Where(p => !p.IsImmutable).Select(p => string.Format("{0} = {1}", p.Name, p.EvaluatedValue)).ToArray()); LogMessageEvent(new BuildMessageEventArgs(initialProjectPropertiesFormatted, null, null, MessageImportance.Low)); var initialItemsFormatted = "Initial Items:\n" + string.Join(Environment.NewLine, project.Items.OrderBy(i => i.ItemType).Select(i => string.Format("{0} : {1}", i.ItemType, i.EvaluatedInclude)).ToArray()); LogMessageEvent(new BuildMessageEventArgs(initialItemsFormatted, null, null, MessageImportance.Low)); // null targets -> success. empty targets -> success(!) foreach (var targetName in (request.ProjectInstance.InitialTargets).Where(t => t != null)) { BuildTargetByName(targetName, args); } if (request.TargetNames == null) { args.Result.OverallResult = args.CheckCancel() ? BuildResultCode.Failure : args.Result.ResultsByTarget.Any(p => p.Value.ResultCode == TargetResultCode.Failure) ? BuildResultCode.Failure : BuildResultCode.Success; } else { foreach (var targetName in (args.TargetNames ?? request.TargetNames).Where(t => t != null)) { if (!BuildTargetByName(targetName, args)) { break; } } // FIXME: check .NET behavior, whether cancellation always results in failure. args.Result.OverallResult = args.CheckCancel() ? BuildResultCode.Failure : args.Result.ResultsByTarget.Any(p => p.Value.ResultCode == TargetResultCode.Failure) ? BuildResultCode.Failure : BuildResultCode.Success; } } catch (Exception ex) { args.Result.OverallResult = BuildResultCode.Failure; LogErrorEvent(new BuildErrorEventArgs(null, null, project.FullPath, 0, 0, 0, 0, "Unhandled exception occured during a build", null, null)); LogMessageEvent(new BuildMessageEventArgs("Exception details: " + ex, null, null, MessageImportance.Low)); throw; // BuildSubmission re-catches this. } finally { event_source.FireBuildFinished(this, new BuildFinishedEventArgs("Build Finished.", null, args.Result.OverallResult == BuildResultCode.Success, DateTime.Now)); Directory.SetCurrentDirectory(directoryBackup); } }
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); }
bool BuildTargetByName(string targetName, InternalBuildArguments args) { var request = submission.BuildRequest; var parameters = submission.BuildManager.OngoingBuildParameters; ProjectTargetInstance target; TargetResult dummyResult; if (args.Result.ResultsByTarget.TryGetValue(targetName, out dummyResult) && dummyResult.ResultCode == TargetResultCode.Success) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because it was already built successfully.", targetName), null, null, MessageImportance.Low)); return(true); // do not add result. } var targetResult = new TargetResult(); // null key is allowed and regarded as blind success(!) (as long as it could retrieve target) if (!request.ProjectInstance.Targets.TryGetValue(targetName, out target)) { // FIXME: from MSBuild.exe it is given MSB4057. Can we assign a number too? throw new InvalidOperationException(string.Format("target '{0}' was not found in project '{1}'", targetName, project.FullPath)); } else if (!args.Project.EvaluateCondition(target.Condition)) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because condition '{1}' was not met.", target.Name, target.Condition), null, null, MessageImportance.Low)); targetResult.Skip(); } else { // process DependsOnTargets first. foreach (var dep in project.ExpandString(target.DependsOnTargets).Split(';').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s))) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' depends on '{1}'.", target.Name, dep), null, null, MessageImportance.Low)); if (!BuildTargetByName(dep, args)) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Quit target '{0}', as dependency target '{1}' has failed.", target.Name, dep), null, null, MessageImportance.Low)); return(false); } } Func <string, ITaskItem> creator = s => new TargetOutputTaskItem() { ItemSpec = s }; event_source.FireTargetStarted(this, new TargetStartedEventArgs("Target Started", null, target.Name, project.FullPath, target.FullPath)); try { // FIXME: examine in which scenario Inputs/Outputs inconsistency results in errors. Now it rather prevents csproj build. /*if (!string.IsNullOrEmpty (target.Inputs) != !string.IsNullOrEmpty (target.Outputs)) { * targetResult.Failure (new InvalidProjectFileException (target.Location, null, string.Format ("Target {0} has mismatching Inputs and Outputs specification. When one is specified, another one has to be specified too.", targetName), null, null, null)); * } else*/{ bool skip = false; if (!string.IsNullOrEmpty(target.Inputs)) { var inputs = args.Project.GetAllItems(target.Inputs, string.Empty, creator, creator, s => true, (t, s) => { }); if (!inputs.Any()) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because there is no input.", target.Name), null, null, MessageImportance.Low)); skip = true; } else { var outputs = args.Project.GetAllItems(target.Outputs, string.Empty, creator, creator, s => true, (t, s) => { }); var needsUpdates = GetOlderOutputsThanInputs(inputs, outputs).FirstOrDefault(); if (needsUpdates != null) { LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' needs to be built because new output {1} is needed.", target.Name, needsUpdates.ItemSpec), null, null, MessageImportance.Low)); } else { LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because all the outputs are newer than all the inputs.", target.Name), null, null, MessageImportance.Low)); skip = true; } } } if (skip) { targetResult.Skip(); } else { if (DoBuildTarget(target, targetResult, args)) { var items = args.Project.GetAllItems(target.Outputs, string.Empty, creator, creator, s => true, (t, s) => { }); targetResult.Success(items); } } } } finally { event_source.FireTargetFinished(this, new TargetFinishedEventArgs("Target Finished", null, targetName, project.FullPath, target.FullPath, targetResult.ResultCode != TargetResultCode.Failure)); } } args.AddTargetResult(targetName, targetResult); return(targetResult.ResultCode != TargetResultCode.Failure); }
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> (); #if NET_4_5 factoryIdentityParameters ["MSBuildRuntime"] = taskInstance.MSBuildRuntime; factoryIdentityParameters ["MSBuildArchitecture"] = taskInstance.MSBuildArchitecture; #endif 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; }
bool BuildTargetByName (string targetName, InternalBuildArguments args) { var request = submission.BuildRequest; var parameters = submission.BuildManager.OngoingBuildParameters; ProjectTargetInstance target; TargetResult dummyResult; if (args.Result.ResultsByTarget.TryGetValue (targetName, out dummyResult) && dummyResult.ResultCode == TargetResultCode.Success) { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Target '{0}' was skipped because it was already built successfully.", targetName), null, null, MessageImportance.Low)); return true; // do not add result. } var targetResult = new TargetResult (); // null key is allowed and regarded as blind success(!) (as long as it could retrieve target) if (!request.ProjectInstance.Targets.TryGetValue (targetName, out target)) // FIXME: from MSBuild.exe it is given MSB4057. Can we assign a number too? throw new InvalidOperationException (string.Format ("target '{0}' was not found in project '{1}'", targetName, project.FullPath)); else if (!args.Project.EvaluateCondition (target.Condition)) { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Target '{0}' was skipped because condition '{1}' was not met.", target.Name, target.Condition), null, null, MessageImportance.Low)); targetResult.Skip (); } else { // process DependsOnTargets first. foreach (var dep in project.ExpandString (target.DependsOnTargets).Split (';').Select (s => s.Trim ()).Where (s => !string.IsNullOrEmpty (s))) { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Target '{0}' depends on '{1}'.", target.Name, dep), null, null, MessageImportance.Low)); if (!BuildTargetByName (dep, args)) { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Quit target '{0}', as dependency target '{1}' has failed.", target.Name, dep), null, null, MessageImportance.Low)); return false; } } Func<string,ITaskItem> creator = s => new TargetOutputTaskItem () { ItemSpec = s }; event_source.FireTargetStarted (this, new TargetStartedEventArgs ("Target Started", null, target.Name, project.FullPath, target.FullPath)); try { // FIXME: examine in which scenario Inputs/Outputs inconsistency results in errors. Now it rather prevents csproj build. /*if (!string.IsNullOrEmpty (target.Inputs) != !string.IsNullOrEmpty (target.Outputs)) { targetResult.Failure (new InvalidProjectFileException (target.Location, null, string.Format ("Target {0} has mismatching Inputs and Outputs specification. When one is specified, another one has to be specified too.", targetName), null, null, null)); } else*/ { bool skip = false; if (!string.IsNullOrEmpty (target.Inputs)) { var inputs = args.Project.GetAllItems (target.Inputs, string.Empty, creator, creator, s => true, (t, s) => { }); if (!inputs.Any ()) { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Target '{0}' was skipped because there is no input.", target.Name), null, null, MessageImportance.Low)); skip = true; } else { var outputs = args.Project.GetAllItems (target.Outputs, string.Empty, creator, creator, s => true, (t, s) => { }); var needsUpdates = GetOlderOutputsThanInputs (inputs, outputs).FirstOrDefault (); if (needsUpdates != null) LogMessageEvent (new BuildMessageEventArgs (string.Format ("Target '{0}' needs to be built because new output {1} is needed.", target.Name, needsUpdates.ItemSpec), null, null, MessageImportance.Low)); else { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Target '{0}' was skipped because all the outputs are newer than all the inputs.", target.Name), null, null, MessageImportance.Low)); skip = true; } } } if (skip) { targetResult.Skip (); } else { if (DoBuildTarget (target, targetResult, args)) { var items = args.Project.GetAllItems (target.Outputs, string.Empty, creator, creator, s => true, (t, s) => { }); targetResult.Success (items); } } } } finally { event_source.FireTargetFinished (this, new TargetFinishedEventArgs ("Target Finished", null, targetName, project.FullPath, target.FullPath, targetResult.ResultCode != TargetResultCode.Failure)); } } args.AddTargetResult (targetName, targetResult); return targetResult.ResultCode != TargetResultCode.Failure; }
void BuildProject (InternalBuildArguments args) { var request = submission.BuildRequest; var parameters = submission.BuildManager.OngoingBuildParameters; this.project = args.Project; string directoryBackup = Directory.GetCurrentDirectory (); Directory.SetCurrentDirectory (project.Directory); event_source.FireBuildStarted (this, new BuildStartedEventArgs ("Build Started", null, DateTime.Now)); try { var initialGlobalPropertiesFormatted = "Initial Global Properties:\n" + string.Join (Environment.NewLine, project.Properties.OrderBy (p => p.Name).Where (p => p.IsImmutable).Select (p => string.Format ("{0} = {1}", p.Name, p.EvaluatedValue)).ToArray ()); LogMessageEvent (new BuildMessageEventArgs (initialGlobalPropertiesFormatted, null, null, MessageImportance.Low)); var initialProjectPropertiesFormatted = "Initial Project Properties:\n" + string.Join (Environment.NewLine, project.Properties.OrderBy (p => p.Name).Where (p => !p.IsImmutable).Select (p => string.Format ("{0} = {1}", p.Name, p.EvaluatedValue)).ToArray ()); LogMessageEvent (new BuildMessageEventArgs (initialProjectPropertiesFormatted, null, null, MessageImportance.Low)); var initialItemsFormatted = "Initial Items:\n" + string.Join (Environment.NewLine, project.Items.OrderBy (i => i.ItemType).Select (i => string.Format ("{0} : {1}", i.ItemType, i.EvaluatedInclude)).ToArray ()); LogMessageEvent (new BuildMessageEventArgs (initialItemsFormatted, null, null, MessageImportance.Low)); // null targets -> success. empty targets -> success(!) foreach (var targetName in (request.ProjectInstance.InitialTargets).Where (t => t != null)) BuildTargetByName (targetName, args); if (request.TargetNames == null) args.Result.OverallResult = args.CheckCancel () ? BuildResultCode.Failure : args.Result.ResultsByTarget.Any (p => p.Value.ResultCode == TargetResultCode.Failure) ? BuildResultCode.Failure : BuildResultCode.Success; else { foreach (var targetName in (args.TargetNames ?? request.TargetNames).Where (t => t != null)) { if (!BuildTargetByName (targetName, args)) break; } // FIXME: check .NET behavior, whether cancellation always results in failure. args.Result.OverallResult = args.CheckCancel () ? BuildResultCode.Failure : args.Result.ResultsByTarget.Any (p => p.Value.ResultCode == TargetResultCode.Failure) ? BuildResultCode.Failure : BuildResultCode.Success; } } catch (Exception ex) { args.Result.OverallResult = BuildResultCode.Failure; LogErrorEvent (new BuildErrorEventArgs (null, null, project.FullPath, 0, 0, 0, 0, "Unhandled exception occured during a build", null, null)); LogMessageEvent (new BuildMessageEventArgs ("Exception details: " + ex, null, null, MessageImportance.Low)); throw; // BuildSubmission re-catches this. } finally { event_source.FireBuildFinished (this, new BuildFinishedEventArgs ("Build Finished.", null, args.Result.OverallResult == BuildResultCode.Success, DateTime.Now)); Directory.SetCurrentDirectory (directoryBackup); } }
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; } var propsToRestore = new Dictionary<string,string> (); var itemsToRemove = new List<ProjectItemInstance> (); try { // Evaluate additional target properties foreach (var c in target.Children.OfType<ProjectPropertyGroupTaskInstance> ()) { if (!args.Project.EvaluateCondition (c.Condition)) continue; foreach (var p in c.Properties) { if (!args.Project.EvaluateCondition (p.Condition)) continue; var value = args.Project.ExpandString (p.Value); propsToRestore.Add (p.Name, project.GetPropertyValue (value)); project.SetProperty (p.Name, value); } } // Evaluate additional target items foreach (var c in target.Children.OfType<ProjectItemGroupTaskInstance> ()) { if (!args.Project.EvaluateCondition (c.Condition)) continue; foreach (var item in c.Items) { if (!args.Project.EvaluateCondition (item.Condition)) continue; Func<string,ProjectItemInstance> creator = i => new ProjectItemInstance (project, item.ItemType, item.Metadata.Select (m => new KeyValuePair<string,string> (m.Name, m.Value)), i); foreach (var ti in project.GetAllItems (item.Include, item.Exclude, creator, creator, s => s == item.ItemType, (ti, s) => ti.SetMetadata ("RecurseDir", s))) itemsToRemove.Add (ti); } } foreach (var c in target.Children.OfType<ProjectOnErrorInstance> ()) { if (!args.Project.EvaluateCondition (c.Condition)) continue; throw new NotImplementedException (); } // run tasks foreach (var ti in target.Children.OfType<ProjectTaskInstance> ()) { current_task = ti; if (!args.Project.EvaluateCondition (ti.Condition)) { LogMessageEvent (new BuildMessageEventArgs (string.Format ("Task '{0}' was skipped because condition '{1}' wasn't met.", ti.Name, ti.Condition), null, null, MessageImportance.Low)); continue; } if (!RunBuildTask (target, ti, targetResult, args)) return false; } } finally { // restore temporary property state to the original state. foreach (var p in propsToRestore) { if (p.Value == string.Empty) project.RemoveProperty (p.Key); else project.SetProperty (p.Key, p.Value); } foreach (var item in itemsToRemove) project.RemoveItem (item); } return true; }