/// <summary> /// Initializes a new instance of the <see cref="FileExpressionLiteral"/> class. /// </summary> /// <param name="rawExpression">An unprocessed string for a single expression.</param> /// <param name="project">The project where the expression exists.</param> /// <param name="task">The task where the expression exists.</param> public FileExpressionLiteral(string rawExpression, ProjectInstance project, ProjectTaskInstance task = null) : base(rawExpression, project, task) { string expandedFileListString = project.ExpandString(ProcessedExpression); EvaluatedFiles = expandedFileListString.SplitStringList(); }
/// <summary> /// Evaluates a given value in a project's context. /// </summary> /// <param name="projectInstance">The MSBuild Project instance to use for the evaluation context.</param> /// <param name="unevaluatedValue">Unevaluated value.</param> /// <returns>List of evaluated values.</returns> public static IEnumerable <string> EvaluateValue(this ProjectInstance projectInstance, string unevaluatedValue) { if (string.IsNullOrWhiteSpace(unevaluatedValue)) { return(Enumerable.Empty <string>()); } string evaluated = projectInstance.ExpandString(unevaluatedValue); return(SplitStringListEnumerable(evaluated)); }
private IEnumerable <string> GetTargetDependencies(string targetName) { ProjectTargetInstance targetInstance; if (projectInstance.Targets.TryGetValue(targetName, out targetInstance)) { return(SplitTargets(projectInstance.ExpandString(targetInstance.DependsOnTargets))); } else { return(Enumerable.Empty <string>()); } }
public void ExpandStringWithMetadata() { string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'> <ItemGroup> <Foo Include='xxx'><M>x</M></Foo> <Foo Include='yyy'><M>y</M></Foo> </ItemGroup> </Project>"; var xml = XmlReader.Create(new StringReader(project_xml)); var root = ProjectRootElement.Create(xml); root.FullPath = "ProjectInstanceTest.ExpandStringWithMetadata.proj"; var proj = new ProjectInstance(root); Assert.AreEqual("xxx;yyy", proj.ExpandString("@(FOO)"), "#1"); // so, metadata is gone... }
/// <summary> /// Evaluates a batch expression, e.g. '%(Compile.fileName).%(Compile.extension))'. /// </summary> /// <param name="expression">An unprocessed string for a single expression.</param> /// <param name="project">The project where the expression exists.</param> /// <param name="task">The task where the expression exists.</param> private static List <string> EvaluateBatchedExpression(string expression, ProjectInstance project, ProjectTaskInstance task) { expression = ProcessExpression(expression, project, task); // Copy task has batching in it. Get the batched items if possible, then parse inputs. Match regexMatch = BatchedItemRegex.Match(expression); if (regexMatch.Success) { // If the user didn't specify a metadata item, then we default to Identity string transformItem = string.IsNullOrEmpty(regexMatch.Groups[2].Value) ? BatchedItemRegex.Replace(expression, @"%(Identity)") : BatchedItemRegex.Replace(expression, @"%($2)"); // Convert the batch into a transform. If this is an item -> metadata based transition then it will do the replacements for you. string expandedString = project.ExpandString($"@({regexMatch.Groups["ItemType"].Value}-> '{transformItem}')"); return(expandedString.SplitStringList()); } else { throw new InvalidOperationException(); } }
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); }
/// <summary> /// Evaluates a literal expression, e.g. '$(Outdir)\foo.dll'. /// </summary> /// <param name="expression">An unprocessed string for a single expression.</param> /// <param name="project">The project where the expression exists.</param> /// <param name="task">The task where the expression exists.</param> /// <returns>The set of all files in the evaluated expression.</returns> private static List <string> EvaluateLiteralExpression(string expression, ProjectInstance project, ProjectTaskInstance task) { expression = ProcessExpression(expression, project, task); expression = project.ExpandString(expression); return(expression.SplitStringList()); }
// 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); Func <string, string> expand = s => projectInstance != null?projectInstance.ExpandString(s) : s; foreach (var ut in usingTasks) { var aName = expand(ut.AssemblyName); var aFile = expand(ut.AssemblyFile); if (string.IsNullOrEmpty(aName) && string.IsNullOrEmpty(aFile)) { var errorNoAssembly = string.Format("Task '{0}' does not specify either of AssemblyName or AssemblyFile.", ut.TaskName); engine.LogWarningEvent(new BuildWarningEventArgs(null, null, projectInstance.FullPath, ut.Location.Line, ut.Location.Column, 0, 0, errorNoAssembly, null, null)); continue; } var ta = assemblies.FirstOrDefault(a => a.AssemblyFile.Equals(aFile, StringComparison.OrdinalIgnoreCase) || a.AssemblyName.Equals(aName, StringComparison.OrdinalIgnoreCase)); if (ta == null) { var path = Path.GetDirectoryName(string.IsNullOrEmpty(ut.Location.File) ? projectInstance.FullPath : ut.Location.File); ta = new TaskAssembly() { AssemblyName = aName, AssemblyFile = aFile }; 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) ? Path.Combine(path, 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.TaskBody : 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); } } }