public void ParseBasicRemoveOperation() { XmlElement xml = CreateBasicRemoveElement(); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemRemove); Assertion.AssertEquals("i1", child.Remove); }
public void ExpectAnyGetModify() { XmlElement xml = XmlTestUtilities.CreateBasicElement("i"); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.Any); Assertion.AssertEquals(ChildType.BuildItemModify, child.ChildType); }
/// <summary> /// Add items to the world. This is the in-target equivalent of an item include expression outside of a target. /// </summary> private void ExecuteAdd(BuildItemGroupChildXml child, ItemBucket bucket) { // By making the items "not persisted", we ensure they are cleaned away when the project is reset BuildItem item = new BuildItem(child.Element, false /* not imported */, false /* not persisted */, itemDefinitionLibrary); // If the condition on the item is false, Evaluate returns an empty group BuildItemGroup itemsToAdd = item.Evaluate(bucket.Expander, executionDirectory, true /* expand metadata */, ParserOptions.AllowAll, loggingServices, buildEventContext); bucket.Lookup.AddNewItems(itemsToAdd); }
/// <summary> /// Modifies items in the world - specifically, changes their metadata. Changes to items that are part of the project manifest are backed up, so /// they can be reverted when the project is reset after the end of the build. /// </summary> /// <param name="child"></param> /// <param name="bucket"></param> private void ExecuteModify(BuildItemGroupChildXml child, ItemBucket bucket) { if (!Utilities.EvaluateCondition(child.Condition, child.ConditionAttribute, bucket.Expander, ParserOptions.AllowAll, loggingServices, buildEventContext)) { return; } BuildItemGroup group = (BuildItemGroup)bucket.Lookup.GetItems(child.Name); if (group == null) { // No items of this type to modify return; } // Figure out what metadata names and values we need to set Dictionary <string, string> metadataToSet = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); List <XmlElement> metadataElements = child.GetChildren(); foreach (XmlElement metadataElement in metadataElements) { bool metadataCondition = true; XmlAttribute conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(metadataElement, true /*no other attributes allowed*/); if (conditionAttribute != null) { metadataCondition = Utilities.EvaluateCondition(conditionAttribute.Value, conditionAttribute, bucket.Expander, ParserOptions.AllowAll, loggingServices, buildEventContext); } if (metadataCondition) { string unevaluatedMetadataValue = Utilities.GetXmlNodeInnerContents(metadataElement); string evaluatedMetadataValue = bucket.Expander.ExpandAllIntoStringLeaveEscaped(unevaluatedMetadataValue, metadataElement); // The last metadata with a particular name, wins, so we just set through the indexer here. metadataToSet[metadataElement.Name] = evaluatedMetadataValue; } } bucket.Lookup.ModifyItems(child.Name, group, metadataToSet); }
/// <summary> /// Remove items from the world. Removes to items that are part of the project manifest are backed up, so /// they can be reverted when the project is reset after the end of the build. /// </summary> private void ExecuteRemove(BuildItemGroupChildXml child, ItemBucket bucket) { if (!Utilities.EvaluateCondition(child.Condition, child.ConditionAttribute, bucket.Expander, ParserOptions.AllowAll, loggingServices, buildEventContext)) { return; } BuildItemGroup group = bucket.Lookup.GetItems(child.Name); if (group == null) { // No items of this type to remove return; } List <BuildItem> itemsToRemove = BuildItemGroup.FindItemsMatchingSpecification(group, child.Remove, child.RemoveAttribute, bucket.Expander, executionDirectory); if (itemsToRemove != null) { bucket.Lookup.RemoveItems(itemsToRemove); } }
/// <summary> /// Creates an IntrinsicTask object around a "task" node /// </summary> internal IntrinsicTask(XmlElement taskNodeXmlElement, EngineLoggingServices loggingServices, BuildEventContext eventContext, string executionDirectory, ItemDefinitionLibrary itemDefinitionLibrary) { this.taskNodeXmlElement = taskNodeXmlElement; this.conditionAttribute = taskNodeXmlElement.Attributes[XMakeAttributes.condition]; this.loggingServices = loggingServices; this.buildEventContext = eventContext; this.executionDirectory = executionDirectory; this.itemDefinitionLibrary = itemDefinitionLibrary; ErrorUtilities.VerifyThrow(IsIntrinsicTaskName(taskNodeXmlElement.Name), "Only PropertyGroup and ItemGroup are known intrinsic tasks"); switch (taskNodeXmlElement.Name) { case XMakeElements.propertyGroup: backingType = BackingType.PropertyGroup; // If the backing type is a property group, we can just use a property group object; its semantics aren't // tangled up with the project object. Put another way, we only really need the code that understands the XML // format of a property group, and we can get that without the rest of BuildPropertyGroup getting in the way. // Specify that these properties are output properties, so they get reverted when the project is reset. backingPropertyGroup = new BuildPropertyGroup(null /* no parent project */, taskNodeXmlElement, PropertyType.OutputProperty); break; case XMakeElements.itemGroup: backingType = BackingType.ItemGroup; // If the backing type is an item group, we just re-use the code that understands the XML format of an item group; // the semantics of BuildItemGroup are too coupled to its current use in the Project object for us to re-use it. backingItemGroupXml = new BuildItemGroupXml(taskNodeXmlElement); List <XmlElement> children = backingItemGroupXml.GetChildren(); backingBuildItemGroupChildren = new List <BuildItemGroupChildXml>(children.Count); foreach (XmlElement child in children) { BuildItemGroupChildXml childXml = new BuildItemGroupChildXml(child, ChildType.Any); backingBuildItemGroupChildren.Add(childXml); } break; } }
/// <summary> /// Creates an IntrinsicTask object around a "task" node /// </summary> internal IntrinsicTask(XmlElement taskNodeXmlElement, EngineLoggingServices loggingServices, BuildEventContext eventContext, string executionDirectory, ItemDefinitionLibrary itemDefinitionLibrary) { this.taskNodeXmlElement = taskNodeXmlElement; this.conditionAttribute = taskNodeXmlElement.Attributes[XMakeAttributes.condition]; this.loggingServices = loggingServices; this.buildEventContext = eventContext; this.executionDirectory = executionDirectory; this.itemDefinitionLibrary = itemDefinitionLibrary; ErrorUtilities.VerifyThrow(IsIntrinsicTaskName(taskNodeXmlElement.Name), "Only PropertyGroup and ItemGroup are known intrinsic tasks"); switch (taskNodeXmlElement.Name) { case XMakeElements.propertyGroup: backingType = BackingType.PropertyGroup; // If the backing type is a property group, we can just use a property group object; its semantics aren't // tangled up with the project object. Put another way, we only really need the code that understands the XML // format of a property group, and we can get that without the rest of BuildPropertyGroup getting in the way. // Specify that these properties are output properties, so they get reverted when the project is reset. backingPropertyGroup = new BuildPropertyGroup(null /* no parent project */, taskNodeXmlElement, PropertyType.OutputProperty); break; case XMakeElements.itemGroup: backingType = BackingType.ItemGroup; // If the backing type is an item group, we just re-use the code that understands the XML format of an item group; // the semantics of BuildItemGroup are too coupled to its current use in the Project object for us to re-use it. backingItemGroupXml = new BuildItemGroupXml(taskNodeXmlElement); List<XmlElement> children = backingItemGroupXml.GetChildren(); backingBuildItemGroupChildren = new List<BuildItemGroupChildXml>(children.Count); foreach (XmlElement child in children) { BuildItemGroupChildXml childXml = new BuildItemGroupChildXml(child, ChildType.Any); backingBuildItemGroupChildren.Add(childXml); } break; } }
public void ParseModify() { XmlDocument doc = new XmlDocument(); XmlElement element = doc.CreateElement("i", XMakeAttributes.defaultXmlNamespace); BuildItemGroupChildXml child = new BuildItemGroupChildXml(element, ChildType.BuildItemModify); Assertion.AssertEquals(ChildType.BuildItemModify, child.ChildType); }
public void RemoveAttributeMissing() { XmlDocument doc = new XmlDocument(); XmlElement element = doc.CreateElement("i", XMakeAttributes.defaultXmlNamespace); BuildItemGroupChildXml child = new BuildItemGroupChildXml(element, ChildType.BuildItemRemove); }
public void InvalidlyNamedMetadata() { XmlElement xml = XmlTestUtilities.CreateBasicElementWithOneAttribute("i", "Include", "i1"); XmlElement child1 = xml.OwnerDocument.CreateElement("m", XMakeAttributes.defaultXmlNamespace); XmlElement child2 = xml.OwnerDocument.CreateElement("Filename", XMakeAttributes.defaultXmlNamespace); xml.AppendChild(child1); xml.AppendChild(child2); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemAdd); }
/// <summary> /// Remove items from the world. Removes to items that are part of the project manifest are backed up, so /// they can be reverted when the project is reset after the end of the build. /// </summary> private void ExecuteRemove(BuildItemGroupChildXml child, ItemBucket bucket) { if (!Utilities.EvaluateCondition(child.Condition, child.ConditionAttribute, bucket.Expander, ParserOptions.AllowAll, loggingServices, buildEventContext)) { return; } BuildItemGroup group = bucket.Lookup.GetItems(child.Name); if (group == null) { // No items of this type to remove return; } List<BuildItem> itemsToRemove = BuildItemGroup.FindItemsMatchingSpecification(group, child.Remove, child.RemoveAttribute, bucket.Expander, executionDirectory); if (itemsToRemove != null) { bucket.Lookup.RemoveItems(itemsToRemove); } }
public void InvalidExcludeWithoutInclude() { XmlElement xml = XmlTestUtilities.CreateBasicElementWithOneAttribute("i", "Exclude", "i1"); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemAdd); }
public void ExpectModifyGetRemove() { XmlElement xml = XmlTestUtilities.CreateBasicElementWithOneAttribute("i", "Remove", "i1"); ; BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemModify); }
public void ExpectAddGetRemove() { XmlElement xml = CreateBasicRemoveElement(); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemAdd); }
/// <summary> /// Adds batchable parameters from an item element into the list. If the item element was a task, these /// would be its raw parameter values. /// </summary> private void GetBatchableValuesFromBuildItemGroupChild(List<string> parameterValues, BuildItemGroupChildXml child) { AddIfNotEmptyString(parameterValues, child.Include); AddIfNotEmptyString(parameterValues, child.Exclude); AddIfNotEmptyString(parameterValues, child.Remove); AddIfNotEmptyString(parameterValues, child.Condition); List<XmlElement> metadataElements = child.GetChildren(); foreach (XmlElement metadataElement in metadataElements) { AddIfNotEmptyString(parameterValues, Utilities.GetXmlNodeInnerContents(metadataElement)); XmlAttribute conditionAttribute = metadataElement.Attributes[XMakeAttributes.condition]; if (conditionAttribute != null) { AddIfNotEmptyString(parameterValues, conditionAttribute.Value); } } }
/// <summary> /// Modifies items in the world - specifically, changes their metadata. Changes to items that are part of the project manifest are backed up, so /// they can be reverted when the project is reset after the end of the build. /// </summary> /// <param name="child"></param> /// <param name="bucket"></param> private void ExecuteModify(BuildItemGroupChildXml child, ItemBucket bucket) { if (!Utilities.EvaluateCondition(child.Condition, child.ConditionAttribute, bucket.Expander, ParserOptions.AllowAll, loggingServices, buildEventContext)) { return; } BuildItemGroup group = (BuildItemGroup)bucket.Lookup.GetItems(child.Name); if (group == null) { // No items of this type to modify return; } // Figure out what metadata names and values we need to set Dictionary<string, string> metadataToSet = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); List<XmlElement> metadataElements = child.GetChildren(); foreach (XmlElement metadataElement in metadataElements) { bool metadataCondition = true; XmlAttribute conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(metadataElement, true /*no other attributes allowed*/); if (conditionAttribute != null) { metadataCondition = Utilities.EvaluateCondition(conditionAttribute.Value, conditionAttribute, bucket.Expander, ParserOptions.AllowAll, loggingServices, buildEventContext); } if (metadataCondition) { string unevaluatedMetadataValue = Utilities.GetXmlNodeInnerContents(metadataElement); string evaluatedMetadataValue = bucket.Expander.ExpandAllIntoStringLeaveEscaped(unevaluatedMetadataValue, metadataElement); // The last metadata with a particular name, wins, so we just set through the indexer here. metadataToSet[metadataElement.Name] = evaluatedMetadataValue; } } bucket.Lookup.ModifyItems(child.Name, group, metadataToSet); }
/// <summary> /// Adds batchable parameters from an item element into the list. If the item element was a task, these /// would be its raw parameter values. /// </summary> private void GetBatchableValuesFromBuildItemGroupChild(List <string> parameterValues, BuildItemGroupChildXml child) { AddIfNotEmptyString(parameterValues, child.Include); AddIfNotEmptyString(parameterValues, child.Exclude); AddIfNotEmptyString(parameterValues, child.Remove); AddIfNotEmptyString(parameterValues, child.Condition); List <XmlElement> metadataElements = child.GetChildren(); foreach (XmlElement metadataElement in metadataElements) { AddIfNotEmptyString(parameterValues, Utilities.GetXmlNodeInnerContents(metadataElement)); XmlAttribute conditionAttribute = metadataElement.Attributes[XMakeAttributes.condition]; if (conditionAttribute != null) { AddIfNotEmptyString(parameterValues, conditionAttribute.Value); } } }
/// <summary> /// Updates the build item xml backing store with the passed in xml backing store. /// </summary> internal void UpdateBackingXml(BuildItemGroupChildXml backingXml) { xml = backingXml; this.name = xml.Name; }
public void ExpectRemoveGetAdd() { XmlElement xml = XmlTestUtilities.CreateBasicElementWithOneAttribute("i", "Include", "i1");; BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemRemove); }
/// <summary> /// Common code for constructors. If an ownerDocument is passed in, it's a persisted element. /// </summary> /// <param name="itemName">can be null</param> /// <param name="itemDefinitionLibrary">can only be null if ownerDocument is null</param> private void BuildItemHelper(XmlDocument ownerDocument, string itemName, string itemInclude, bool createCustomMetadataCache, ItemDefinitionLibrary itemDefinitionLibraryToUse) { // Only check for null. It's legal to make BuildItems with empty // item specs -- this is to be consistent with how we shipped TaskItem. // See #567058. ErrorUtilities.VerifyThrowArgumentNull(itemInclude, "itemInclude"); // Validate that the item name doesn't contain any illegal characters. if (itemName != null) { XmlUtilities.VerifyThrowValidElementName(itemName); ErrorUtilities.VerifyThrowInvalidOperation(XMakeElements.IllegalItemPropertyNames[itemName] == null, "CannotModifyReservedItem", itemName); } // If no owner document was passed in, then it's not going to have an // XML element backing it. if (ownerDocument == null) { this.include = itemInclude; this.isPartOfProjectManifest = false; } else { ErrorUtilities.VerifyThrowArgumentLength(itemName, "itemType"); MustHaveItemDefinitionLibrary(itemDefinitionLibraryToUse); // The caller has given us an owner document, so we're going to create a // new item element associated with that document. The new item element // doesn't actually get added to the XML document automatically. this.xml = new BuildItemGroupChildXml(ownerDocument, itemName, itemInclude); this.isPartOfProjectManifest = true; } if (createCustomMetadataCache) { // PERF NOTE: only create cache if told to do so, because creating // this cache for a large number of items is expensive InitializeCustomMetadataCache(); } this.name = itemName; // The evaluated and final item specs start off initialized to the "Include" attribute. this.evaluatedItemSpecEscaped = itemInclude; this.finalItemSpecEscaped = itemInclude; this.importedFromAnotherProject = false; this.itemDefinitionLibrary = itemDefinitionLibraryToUse; }
public void InvalidIncludeAndRemoveTogether() { XmlElement xml = CreateBasicRemoveElement(); xml.SetAttribute("Include", "i2"); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemRemove); }
/// <summary> /// Initializes a persisted item from an existing item element which exists either in the main project file or in one of /// the imported files. /// </summary> /// <param name="itemElementToParse"></param> private void InitializeFromItemElement(XmlElement element) { this.xml = new BuildItemGroupChildXml(element, ChildType.BuildItemAdd); this.name = xml.Name; this.itemSpecModifiers = null; this.recursivePortionOfFinalItemSpecDirectory = null; this.evaluatedItemSpecEscaped = xml.Include; this.finalItemSpecEscaped = xml.Include; InitializeCustomMetadataCache(); }
public void InvalidRemoveWithSomeMetadataChildren() { XmlElement xml = CreateBasicRemoveElement(); XmlElement child1 = xml.OwnerDocument.CreateElement("m", XMakeAttributes.defaultXmlNamespace); child1.InnerText = "m1"; xml.AppendChild(child1); BuildItemGroupChildXml child = new BuildItemGroupChildXml(xml, ChildType.BuildItemRemove); }