/// <summary> /// Constructor for the When block. Parses the contents of the When block (property /// groups, item groups, and nested chooses) and stores them. /// </summary> /// <remarks> /// </remarks> /// <owner>DavidLe</owner> /// <param name="parentProject"></param> /// <param name="parentGroupingCollection"></param> /// <param name="whenElement"></param> /// <param name="importedFromAnotherProject"></param> /// <param name="options"></param> /// <param name="nestingDepth">stack overflow guard</param> internal When( Project parentProject, GroupingCollection parentGroupingCollection, XmlElement whenElement, bool importedFromAnotherProject, Options options, int nestingDepth ) { // Make sure the <When> node has been given to us. error.VerifyThrow(whenElement != null, "Need valid (non-null) <When> element."); // Make sure this really is the <When> node. error.VerifyThrow(whenElement.Name == XMakeElements.when || whenElement.Name == XMakeElements.otherwise, "Expected <{0}> or <{1}> element; received <{2}> element.", XMakeElements.when, XMakeElements.otherwise, whenElement.Name); this.propertyAndItemLists = new GroupingCollection(parentGroupingCollection); this.parentProject = parentProject; string elementName = ((options == Options.ProcessWhen) ? XMakeElements.when : XMakeElements.otherwise); if (options == Options.ProcessWhen) { conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(whenElement, /*verify sole attribute*/ true); ProjectErrorUtilities.VerifyThrowInvalidProject(conditionAttribute != null, whenElement, "MissingCondition", XMakeElements.when); } else { ProjectXmlUtilities.VerifyThrowProjectNoAttributes(whenElement); } ProcessWhenChildren(whenElement, parentProject, importedFromAnotherProject, nestingDepth); }
/// <summary> /// Given the properties and dictionary of previously encountered item definitions, evaluates /// this specific item definition element and adds to the dictionary as necessary. /// </summary> /// <exception cref="InvalidProjectFileException">If the item definition is incorrectly defined</exception> private void EvaluateItemDefinitionElement(XmlElement itemDefinitionElement, BuildPropertyGroup properties, ItemDefinitionsDictionary itemDefinitionsDictionary) { ProjectXmlUtilities.VerifyThrowProjectValidNameAndNamespace(itemDefinitionElement); XmlAttribute conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(itemDefinitionElement, /* sole attribute */ true); string condition = ProjectXmlUtilities.GetAttributeValue(conditionAttribute); MetadataDictionary metadataDictionary = null; string itemType = itemDefinitionElement.Name; itemDefinitionsDictionary.TryGetValue(itemType, out metadataDictionary); Expander expander = new Expander(properties, itemType, metadataDictionary); if (!Utilities.EvaluateCondition(condition, conditionAttribute, expander, ParserOptions.AllowPropertiesAndItemMetadata, parentProject)) { return; } List <XmlElement> childElements = ProjectXmlUtilities.GetValidChildElements(itemDefinitionElement); foreach (XmlElement child in childElements) { EvaluateItemDefinitionChildElement(child, properties, itemDefinitionsDictionary); } }
/// <summary> /// BuildItemGroup element is provided /// </summary> internal BuildItemGroupXml(XmlElement element) { ErrorUtilities.VerifyThrowNoAssert(element != null, "Need a valid XML node."); ProjectXmlUtilities.VerifyThrowElementName(element, XMakeElements.itemGroup); this.element = element; this.conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(element, true /*no other attributes allowed*/); }
/// <summary> /// Read in and validate an <ItemDefinitionGroup> element and all its children. /// This is currently only called from ItemDefinitionLibrary. Projects don't know about it. /// </summary> internal BuildItemDefinitionGroupXml(XmlElement element, Project parentProject) { ProjectXmlUtilities.VerifyThrowElementName(element, XMakeElements.itemDefinitionGroup); ProjectXmlUtilities.VerifyThrowProjectValidNamespace(element); this.element = element; this.parentProject = parentProject; this.conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(element, /* sole attribute */ true); this.condition = ProjectXmlUtilities.GetAttributeValue(conditionAttribute); // Currently, don't bother validating the children until evaluation time }
/// <summary> /// Given the properties and dictionary of previously encountered item definitions, evaluates /// this specific item definition child element and adds to the dictionary as necessary. /// </summary> /// <exception cref="InvalidProjectFileException">If the item definition is incorrectly defined</exception> private void EvaluateItemDefinitionChildElement(XmlElement itemDefinitionChildElement, BuildPropertyGroup properties, ItemDefinitionsDictionary itemDefinitionsDictionary) { ProjectXmlUtilities.VerifyThrowProjectValidNameAndNamespace(itemDefinitionChildElement); ProjectErrorUtilities.VerifyThrowInvalidProject(!FileUtilities.IsItemSpecModifier(itemDefinitionChildElement.Name), itemDefinitionChildElement, "ItemSpecModifierCannotBeCustomMetadata", itemDefinitionChildElement.Name); ProjectErrorUtilities.VerifyThrowInvalidProject(XMakeElements.IllegalItemPropertyNames[itemDefinitionChildElement.Name] == null, itemDefinitionChildElement, "CannotModifyReservedItemMetadata", itemDefinitionChildElement.Name); XmlAttribute conditionAttribute = ProjectXmlUtilities.GetConditionAttribute(itemDefinitionChildElement, /* sole attribute */ true); string condition = ProjectXmlUtilities.GetAttributeValue(conditionAttribute); MetadataDictionary metadataDictionary = null; string itemType = itemDefinitionChildElement.ParentNode.Name; itemDefinitionsDictionary.TryGetValue(itemType, out metadataDictionary); Expander expander = new Expander(properties, itemType, metadataDictionary); if (!Utilities.EvaluateCondition(condition, conditionAttribute, expander, ParserOptions.AllowPropertiesAndItemMetadata, parentProject)) { return; } string unevaluatedMetadataValue = Utilities.GetXmlNodeInnerContents(itemDefinitionChildElement); bool containsItemVector = ItemExpander.ExpressionContainsItemVector(unevaluatedMetadataValue); // We don't allow expressions like @(foo) in the value, as no items exist at this point. ProjectErrorUtilities.VerifyThrowInvalidProject(!containsItemVector, itemDefinitionChildElement, "MetadataDefinitionCannotContainItemVectorExpression", unevaluatedMetadataValue, itemDefinitionChildElement.Name); string evaluatedMetadataValue = expander.ExpandAllIntoStringLeaveEscaped(unevaluatedMetadataValue, itemDefinitionChildElement); if (metadataDictionary == null) { metadataDictionary = new MetadataDictionary(StringComparer.OrdinalIgnoreCase); itemDefinitionsDictionary.Add(itemType, metadataDictionary); } // We only store the evaluated value; build items store the unevaluated value as well, but apparently only to // gather recursive portions (its re-evaluation always goes back to the XML). // Overwrite any existing default value for this particular metadata metadataDictionary[itemDefinitionChildElement.Name] = evaluatedMetadataValue; }
/// <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); }