/// <summary> /// Uses the given task output specification to (statically) infer the task's outputs. /// </summary> /// <param name="taskOutputSpecification"></param> /// <param name="taskParameterName"></param> /// <param name="itemName">can be null</param> /// <param name="propertyName">can be null</param> /// <param name="bucket"></param> private void InferTaskOutputs ( Lookup lookup, TaskOutput taskOutputSpecification, string taskParameterName, string itemName, string propertyName, ItemBucket bucket ) { // if the task has a value set for the output parameter, expand all embedded properties and item metadata in it XmlAttribute taskParameterAttribute = null; // Lookup attribute name needs to be case-insensitive // DevDiv bugs: 33981 foreach (XmlAttribute taskNodeAttribute in taskNode.Attributes) { if (String.Compare(taskNodeAttribute.Name, taskParameterName, StringComparison.OrdinalIgnoreCase) == 0) { taskParameterAttribute = taskNodeAttribute; break; } } if (taskParameterAttribute != null) { if (taskOutputSpecification.IsItemVector) { // This is an output item. ErrorUtilities.VerifyThrow((itemName != null) && (itemName.Length > 0), "Need item type."); // Expand only with properties first, so that expressions like Include="@(foo)" will transfer the metadata of the "foo" items as well, not just their item specs. Expander propertyAndMetadataExpander = new Expander(bucket.Expander, ExpanderOptions.ExpandPropertiesAndMetadata); List<string> outputItemSpecs = propertyAndMetadataExpander.ExpandAllIntoStringListLeaveEscaped(taskParameterAttribute); foreach (string outputItemSpec in outputItemSpecs) { BuildItemGroup items = bucket.Expander.ExpandSingleItemListExpressionIntoItemsLeaveEscaped(outputItemSpec, taskParameterAttribute); // if the output item-spec is an item vector, get the items in it if (items != null) { foreach (BuildItem item in items) { // we want to preserve the attributes on the item BuildItem clonedItem = item.VirtualClone(); // but we do need to change the item type clonedItem.Name = itemName; lookup.AddNewItem(clonedItem); } } else { // if the output item-spec is not an item vector, accept it as-is lookup.AddNewItem(new BuildItem(itemName, outputItemSpec)); } } } else { // This is an output property. Debug.Assert(taskOutputSpecification.IsProperty); ErrorUtilities.VerifyThrow((propertyName != null) && (propertyName.Length > 0), "Need property name."); string taskParameterValue = bucket.Expander.ExpandAllIntoString(taskParameterAttribute); if (taskParameterValue.Length > 0) { lookup.SetProperty(new BuildProperty(propertyName, taskParameterValue, PropertyType.OutputProperty)); } } } }
private void GatherArrayStringAndValueOutputs(Lookup lookup, TaskOutput taskOutputSpecification, string itemName, string propertyName, PropertyInfo parameter, object outputs) { // if the task has generated outputs (if it didn't, don't do anything) if (outputs != null) { Array convertibleOutputs = (parameter.PropertyType.IsArray) ? (Array)outputs : new object[] { outputs }; if (taskOutputSpecification.IsItemVector) { ErrorUtilities.VerifyThrow((itemName != null) && (itemName.Length > 0), "Need item type."); // to store the outputs as items, use the string representations of the outputs as item-specs foreach (object output in convertibleOutputs) { // if individual outputs in the array are null, ignore them if (output != null) { string stringValueFromTask = (string)Convert.ChangeType(output, typeof(string), CultureInfo.InvariantCulture); // attempting to put an empty string into an item is a no-op (bug #444501). if (stringValueFromTask.Length > 0) { lookup.AddNewItem(new BuildItem(itemName, EscapingUtilities.Escape(stringValueFromTask))); } } } } else { Debug.Assert(taskOutputSpecification.IsProperty); ErrorUtilities.VerifyThrow((propertyName != null) && (propertyName.Length > 0), "Need property name."); // to store an object array in a property, join all the string representations of the objects with // semi-colons to make the property value StringBuilder joinedOutputs = new StringBuilder(); foreach (object output in convertibleOutputs) { // if individual outputs in the array are null, ignore them if (output != null) { if (joinedOutputs.Length > 0) { joinedOutputs.Append(';'); } string stringValueFromTask = (string)Convert.ChangeType(output, typeof(string), CultureInfo.InvariantCulture); joinedOutputs.Append(EscapingUtilities.Escape(stringValueFromTask)); } } lookup.SetProperty(new BuildProperty(propertyName, joinedOutputs.ToString(), PropertyType.OutputProperty)); } } }
private void GatherTaskItemOutputs(Lookup lookup, TaskOutput taskOutputSpecification, string itemName, string propertyName, object outputs) { // if the task has generated outputs (if it didn't, don't do anything) if (outputs != null) { ITaskItem[] taskItemOutputs = (outputs is ITaskItem[]) ? (ITaskItem[])outputs : new ITaskItem[] { (ITaskItem)outputs }; if (taskOutputSpecification.IsItemVector) { ErrorUtilities.VerifyThrow((itemName != null) && (itemName.Length > 0), "Need item type."); foreach (ITaskItem output in taskItemOutputs) { // if individual items in the array are null, ignore them if (output != null) { lookup.AddNewItem(new BuildItem(itemName, output)); } } } else { Debug.Assert(taskOutputSpecification.IsProperty); ErrorUtilities.VerifyThrow((propertyName != null) && (propertyName.Length > 0), "Need property name."); // to store an ITaskItem array in a property, join all the item-specs with semi-colons to make the // property value, and ignore/discard the attributes on the ITaskItems StringBuilder joinedOutputs = new StringBuilder(); foreach (ITaskItem output in taskItemOutputs) { // if individual items in the array are null, ignore them if (output != null) { if (joinedOutputs.Length > 0) { joinedOutputs.Append(';'); } joinedOutputs.Append(EscapingUtilities.Escape(output.ItemSpec)); } } lookup.SetProperty(new BuildProperty(propertyName, joinedOutputs.ToString(), PropertyType.OutputProperty)); } } }