/// <summary> /// Evaluates a condition in the context of a flattened ProjectInstance, /// avoiding processing where the condition contains constructs that are /// difficult to evaluate statically. /// </summary> /// <returns> /// If condition true or false. If any MSBuild project exception is thrown during evaluation, /// result will be false. /// </returns> /// <exception cref="InvalidProjectFileException"> /// Thrown by MSBuild when evaluation fails. This exception cannot be easily /// handled locally, e.g. by catching and returning false, as it will usually /// leave the Project in a bad state, e.g. an empty Targets collection, /// which will affect downstream code that tries to evaluate targets. /// </exception> public static bool EvaluateConditionCarefully(this ProjectInstance projectInstance, string condition) { // To avoid extra work, return true (default) if condition is empty. if (string.IsNullOrWhiteSpace(condition)) { return(true); } // We cannot handle %(...) metadata accesses in conditions. For example, see these conditions // in Microsoft.WebApplication.targets: // // <Copy SourceFiles="@(Content)" Condition="'%(Content.Link)' == ''" // <Copy SourceFiles="@(Content)" Condition="!$(DisableLinkInCopyWebApplication) And '%(Content.Link)' != ''" // // Attempting to evaluate these conditions throws an MSB4191 exception from // Project.ReevaluateIfNecessary(), trashing Project (Project.Targets collection // becomes empty, for example). Extra info at: // http://stackoverflow.com/questions/4721879/ms-build-access-compiler-settings-in-a-subsequent-task // ProjectInstance.EvaluateCondition() also does not support bare metadata based condition parsing, // it uses the internal Expander class with option ExpandPropertiesAndItems but not the // more extensive ExpandAll or ExpandMetadata. // https://github.com/Microsoft/msbuild/blob/master/src/Build/Instance/ProjectInstance.cs#L1763 if (condition.IndexOf("%(", StringComparison.Ordinal) != -1) { return(false); } return(projectInstance.EvaluateCondition(condition)); }
void LoadUsingTasks(ProjectInstance projectInstance, ProjectRootElement project) { Func <string, bool> cond = s => projectInstance != null?projectInstance.EvaluateCondition(s) : Convert.ToBoolean(s); foreach (var ut in project.UsingTasks) { var ta = assemblies.FirstOrDefault(a => a.AssemblyFile.Equals(ut.AssemblyFile, StringComparison.OrdinalIgnoreCase) || a.AssemblyName.Equals(ut.AssemblyName, StringComparison.OrdinalIgnoreCase)); if (ta == null) { ta = new TaskAssembly() { AssemblyName = ut.AssemblyName, AssemblyFile = ut.AssemblyFile }; ta.LoadedAssembly = ta.AssemblyName != null?Assembly.Load(ta.AssemblyName) : Assembly.LoadFile(ta.AssemblyFile); assemblies.Add(ta); } var pg = ut.ParameterGroup == null ? null : ut.ParameterGroup.Parameters.Select(p => new TaskPropertyInfo(p.Name, Type.GetType(p.ParameterType), cond(p.Output), cond(p.Required))) .ToDictionary(p => p.Name); var task = new TaskDescription() { TaskAssembly = ta, Name = ut.TaskName, TaskFactoryType = string.IsNullOrEmpty(ut.TaskFactory) ? null : LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskFactory), TaskType = string.IsNullOrEmpty(ut.TaskFactory) ? LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskName) : null, TaskFactoryParameters = pg, TaskBody = ut.TaskBody != null && cond(ut.TaskBody.Condition) ? ut.TaskBody.Evaluate : null, }; task_descs.Add(task); } }
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: my guess is the tasks does not have to be loaded entirely but only requested tasks must be loaded at invocation time. void LoadUsingTasks(ProjectInstance projectInstance, IEnumerable <ProjectUsingTaskElement> usingTasks) { Func <string, bool> cond = s => projectInstance != null?projectInstance.EvaluateCondition(s) : Convert.ToBoolean(s); foreach (var ut in usingTasks) { var ta = assemblies.FirstOrDefault(a => a.AssemblyFile.Equals(ut.AssemblyFile, StringComparison.OrdinalIgnoreCase) || a.AssemblyName.Equals(ut.AssemblyName, StringComparison.OrdinalIgnoreCase)); if (ta == null) { var path = Path.GetDirectoryName(string.IsNullOrEmpty(ut.Location.File) ? projectInstance.FullPath : ut.Location.File); ta = new TaskAssembly() { AssemblyName = ut.AssemblyName, AssemblyFile = ut.AssemblyFile }; try { ta.LoadedAssembly = !string.IsNullOrEmpty(ta.AssemblyName) ? Assembly.Load(ta.AssemblyName) : Assembly.LoadFile(Path.Combine(path, ta.AssemblyFile)); } catch { var errorNotLoaded = string.Format("For task '{0}' Specified assembly '{1}' was not found", ut.TaskName, string.IsNullOrEmpty(ta.AssemblyName) ? ta.AssemblyFile : ta.AssemblyName); engine.LogWarningEvent(new BuildWarningEventArgs(null, null, projectInstance.FullPath, ut.Location.Line, ut.Location.Column, 0, 0, errorNotLoaded, null, null)); continue; } assemblies.Add(ta); } var pg = ut.ParameterGroup == null ? null : ut.ParameterGroup.Parameters.Select(p => new TaskPropertyInfo(p.Name, Type.GetType(p.ParameterType), cond(p.Output), cond(p.Required))) .ToDictionary(p => p.Name); Type type = null; string error = null; TaskDescription task = new TaskDescription() { TaskAssembly = ta, Name = ut.TaskName, TaskFactoryParameters = pg, TaskBody = ut.TaskBody != null && cond(ut.TaskBody.Condition) ? ut.TaskBody.Evaluate : null, }; if (string.IsNullOrEmpty(ut.TaskFactory)) { type = LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskName); if (type == null) { error = string.Format("For task '{0}' Specified type '{1}' was not found in assembly '{2}'", ut.TaskName, ut.TaskName, ta.LoadedAssembly.FullName); } else { task.TaskType = type; } } else { type = LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskFactory); if (type == null) { error = string.Format("For task '{0}' Specified factory type '{1}' was not found in assembly '{2}'", ut.TaskName, ut.TaskFactory, ta.LoadedAssembly.FullName); } else { task.TaskFactoryType = type; } } if (error != null) { engine.LogWarningEvent(new BuildWarningEventArgs(null, null, projectInstance.FullPath, ut.Location.Line, ut.Location.Column, 0, 0, error, null, null)); } else { task_descs.Add(task); } } }
public static bool EvaluateCondition(string condition, Dictionary <string, string> conditionParameters) { var projectInstance = new ProjectInstance(ProjectRootElement.Create(), conditionParameters, null, new ProjectCollection()); return(projectInstance.EvaluateCondition(condition)); }