/// <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> /// 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> /// 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> /// This constructor allows all output data to be initialized. /// </summary> /// <owner>SumedhK</owner> /// <param name="node">The XML element for the Output tag.</param> internal TaskOutput(XmlElement node) { ErrorUtilities.VerifyThrow(node != null, "Need the XML for the <Output> tag."); ProjectXmlUtilities.VerifyThrowProjectNoChildElements(node); int requiredData = 0; string taskName = node.ParentNode.Name; foreach (XmlAttribute outputAttribute in node.Attributes) { switch (outputAttribute.Name) { case XMakeAttributes.taskParameter: ProjectErrorUtilities.VerifyThrowInvalidProject(outputAttribute.Value.Length > 0, outputAttribute, "InvalidAttributeValue", outputAttribute.Value, outputAttribute.Name, XMakeElements.output); ProjectErrorUtilities.VerifyThrowInvalidProject(!XMakeAttributes.IsSpecialTaskAttribute(outputAttribute.Value) && !XMakeAttributes.IsBadlyCasedSpecialTaskAttribute(outputAttribute.Value), outputAttribute, "BadlyCasedSpecialTaskAttribute", outputAttribute.Value, taskName, taskName); this.taskParameterAttribute = outputAttribute; break; case XMakeAttributes.itemName: ProjectErrorUtilities.VerifyThrowInvalidProject(outputAttribute.Value.Length > 0, outputAttribute, "InvalidAttributeValue", outputAttribute.Value, outputAttribute.Name, XMakeElements.output); this.itemNameAttribute = outputAttribute; requiredData++; break; case XMakeAttributes.propertyName: ProjectErrorUtilities.VerifyThrowInvalidProject(outputAttribute.Value.Length > 0, outputAttribute, "InvalidAttributeValue", outputAttribute.Value, outputAttribute.Name, XMakeElements.output); ProjectErrorUtilities.VerifyThrowInvalidProject(!ReservedPropertyNames.IsReservedProperty(outputAttribute.Value), node, "CannotModifyReservedProperty", outputAttribute.Value); this.propertyNameAttribute = outputAttribute; requiredData++; break; case XMakeAttributes.condition: this.conditionAttribute = outputAttribute; break; default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(outputAttribute); break; } } /* NOTE: * TaskParameter must be specified * either ItemName or PropertyName must be specified * if ItemName is specified, then PropertyName cannot be specified * if PropertyName is specified, then ItemName cannot be specified * only Condition is truly optional */ ProjectErrorUtilities.VerifyThrowInvalidProject((this.taskParameterAttribute != null) && (requiredData == 1), node, "InvalidTaskOutputSpecification", taskName); }
/// <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 group of item definitions and adds to the dictionary as necessary. /// </summary> /// <exception cref="InvalidProjectFileException">If the item definitions are incorrectly defined</exception> internal void Evaluate(BuildPropertyGroup properties, ItemDefinitionsDictionary itemDefinitionsDictionary) { Expander expander = new Expander(properties); if (!Utilities.EvaluateCondition(condition, conditionAttribute, expander, ParserOptions.AllowProperties, parentProject)) { return; } List <XmlElement> childElements = ProjectXmlUtilities.GetValidChildElements(element); foreach (XmlElement child in childElements) { EvaluateItemDefinitionElement(child, properties, itemDefinitionsDictionary); } }
/// <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> /// 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> /// Sets or removes an attribute from the target element. Marks the target dirty after the update /// </summary> /// <param name="attributeName"></param> /// <param name="attributeValue"></param> /// <returns>XmlAttribute which has been updated</returns> internal XmlAttribute SetOrRemoveTargetAttribute ( string attributeName, string attributeValue ) { XmlAttribute updatedAttribute = null; // If this Target object is not actually represented by a // <Target> element in the parentProject.file, then do not allow // the caller to set the condition. error.VerifyThrowInvalidOperation(this.targetElement != null, "CannotSetCondition"); // If this item was imported from another parentProject. we don't allow modifying it. error.VerifyThrowInvalidOperation(!this.importedFromAnotherProject, "CannotModifyImportedProjects"); updatedAttribute = ProjectXmlUtilities.SetOrRemoveAttribute(this.targetElement, attributeName, attributeValue); // Mark the project dirty after an attribute has been updated this.MarkTargetAsDirty(); return(updatedAttribute); }
/// <summary> /// Constructor, that initializes the property with cloned information. /// /// Callers -- Please ensure that the propertyValue passed into this constructor /// is actually computed by calling GetXmlNodeInnerContents on the propertyElement. /// </summary> /// <param name="propertyElement"></param> /// <param name="propertyValue"></param> /// <param name="propertyType"></param> /// <owner>rgoel</owner> private BuildProperty ( XmlElement propertyElement, string propertyValue, PropertyType propertyType ) { // Make sure the property node has been given to us. ErrorUtilities.VerifyThrow(propertyElement != null, "Need an XML node representing the property element."); // Validate that the property name doesn't contain any illegal characters. XmlUtilities.VerifyThrowProjectValidElementName(propertyElement); this.propertyElement = propertyElement; // Loop through the list of attributes on the property element. foreach (XmlAttribute propertyAttribute in propertyElement.Attributes) { switch (propertyAttribute.Name) { case XMakeAttributes.condition: // We found the "condition" attribute. Process it. this.conditionAttribute = propertyAttribute; break; default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(propertyAttribute); break; } } this.propertyValue = propertyValue; this.finalValueEscaped = propertyValue; this.type = propertyType; }
/// <summary> /// Helper method for processing the children of a When. Only parses Choose, /// PropertyGroup, and ItemGroup. All other tags result in an error. /// </summary> /// <remarks> /// </remarks> /// <owner>DavidLe</owner> /// <param name="parentNode"></param> /// <param name="parentProjectForChildren"></param> /// <param name="importedFromAnotherProject"></param> /// <param name="options"></param> /// <param name="nestingDepth">Number of parent <Choose> elements this is nested inside</param> private void ProcessWhenChildren ( XmlElement parentNode, Project parentProjectForChildren, bool importedFromAnotherProject, int nestingDepth ) { // Loop through the child nodes of the <When> element. foreach (XmlNode whenChildNode in parentNode) { switch (whenChildNode.NodeType) { // Handle XML comments under the <When> node (just ignore them). case XmlNodeType.Comment: // fall through case XmlNodeType.Whitespace: // ignore whitespace break; case XmlNodeType.Element: { // Make sure this element doesn't have a custom namespace ProjectXmlUtilities.VerifyThrowProjectValidNamespace((XmlElement)whenChildNode); // The only three types of child nodes that a <When> element can contain // are <PropertyGroup>, <ItemGroup> and <Choose>. switch (whenChildNode.Name) { case XMakeElements.itemGroup: BuildItemGroup newItemGroup = new BuildItemGroup((XmlElement)whenChildNode, importedFromAnotherProject, parentProjectForChildren); this.propertyAndItemLists.InsertAtEnd(newItemGroup); break; // Process the <PropertyGroup> element. case XMakeElements.propertyGroup: BuildPropertyGroup newPropertyGroup = new BuildPropertyGroup(parentProjectForChildren, (XmlElement)whenChildNode, importedFromAnotherProject); newPropertyGroup.EnsureNoReservedProperties(); this.propertyAndItemLists.InsertAtEnd(newPropertyGroup); break; // Process the <Choose> element. case XMakeElements.choose: Choose newChoose = new Choose(parentProjectForChildren, this.PropertyAndItemLists, (XmlElement)whenChildNode, importedFromAnotherProject, nestingDepth); this.propertyAndItemLists.InsertAtEnd(newChoose); break; default: { ProjectXmlUtilities.ThrowProjectInvalidChildElement(whenChildNode); break; } } } break; default: { ProjectXmlUtilities.ThrowProjectInvalidChildElement(whenChildNode); break; } } } }
/// <summary> /// Used to load information about default MSBuild tasks i.e. tasks that do not need to be explicitly declared in projects /// with the <UsingTask> element. Default task information is read from special files, which are located in the same /// directory as the MSBuild binaries. /// </summary> /// <remarks> /// 1) a default tasks file needs the <Project> root tag in order to be well-formed /// 2) the XML declaration tag <?xml ...> is ignored /// 3) comment tags are always ignored regardless of their placement /// 4) the rest of the tags are expected to be <UsingTask> tags /// </remarks> private void RegisterDefaultTasks(BuildEventContext buildEventContext) { if (!defaultTasksRegistrationAttempted) { try { this.defaultTaskRegistry = new TaskRegistry(); string[] defaultTasksFiles = { }; try { defaultTasksFiles = getFiles(toolset.ToolsPath, defaultTasksFilePattern); if (defaultTasksFiles.Length == 0) { loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, String.Empty); } } // handle security problems when finding the default tasks files catch (UnauthorizedAccessException e) { loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, e.Message); } // handle problems when reading the default tasks files catch (Exception e) // Catching Exception, but rethrowing unless it's an IO related exception. { if (ExceptionHandling.NotExpectedException(e)) { throw; } loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, e.Message); } BuildPropertyGroup propertyBag = null; foreach (string defaultTasksFile in defaultTasksFiles) { try { XmlDocument defaultTasks = loadXmlFromPath(defaultTasksFile); // look for the first root tag that is not a comment or an XML declaration -- this should be the <Project> tag // NOTE: the XML parser will guarantee there is only one real root element in the file // but we need to find it amongst the other types of XmlNode at the root. foreach (XmlNode topLevelNode in defaultTasks.ChildNodes) { if (XmlUtilities.IsXmlRootElement(topLevelNode)) { ProjectErrorUtilities.VerifyThrowInvalidProject(topLevelNode.LocalName == XMakeElements.project, topLevelNode, "UnrecognizedElement", topLevelNode.Name); ProjectErrorUtilities.VerifyThrowInvalidProject((topLevelNode.Prefix.Length == 0) && (String.Compare(topLevelNode.NamespaceURI, XMakeAttributes.defaultXmlNamespace, StringComparison.OrdinalIgnoreCase) == 0), topLevelNode, "ProjectMustBeInMSBuildXmlNamespace", XMakeAttributes.defaultXmlNamespace); // the <Project> tag can only the XML namespace -- no other attributes foreach (XmlAttribute projectAttribute in topLevelNode.Attributes) { ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(projectAttribute.Name == XMakeAttributes.xmlns, projectAttribute); } // look at all the child tags of the <Project> root tag we found foreach (XmlNode usingTaskNode in topLevelNode.ChildNodes) { if (usingTaskNode.NodeType != XmlNodeType.Comment) { ProjectErrorUtilities.VerifyThrowInvalidProject(usingTaskNode.Name == XMakeElements.usingTask, usingTaskNode, "UnrecognizedElement", usingTaskNode.Name); // Initialize the property bag if it hasn't been already. if (propertyBag == null) { // Set the value of the MSBuildBinPath/ToolsPath properties. BuildPropertyGroup reservedPropertyBag = new BuildPropertyGroup(); reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.binPath, EscapingUtilities.Escape(toolset.ToolsPath), PropertyType.ReservedProperty)); reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.toolsPath, EscapingUtilities.Escape(toolset.ToolsPath), PropertyType.ReservedProperty)); // Also set MSBuildAssemblyVersion so that the tasks file can tell between v4 and v12 MSBuild reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.assemblyVersion, Constants.AssemblyVersion, PropertyType.ReservedProperty)); propertyBag = new BuildPropertyGroup(); propertyBag.ImportInitialProperties(parentEngine.EnvironmentProperties, reservedPropertyBag, BuildProperties, parentEngine.GlobalProperties); } defaultTaskRegistry.RegisterTask(new UsingTask((XmlElement)usingTaskNode, true), new Expander(propertyBag), loggingServices, buildEventContext); } } break; } } } // handle security problems when loading the default tasks file catch (UnauthorizedAccessException e) { loggingServices.LogError(buildEventContext, new BuildEventFileInfo(defaultTasksFile), "DefaultTasksFileFailure", e.Message); break; } // handle problems when loading the default tasks file catch (IOException e) { loggingServices.LogError(buildEventContext, new BuildEventFileInfo(defaultTasksFile), "DefaultTasksFileFailure", e.Message); break; } // handle XML errors in the default tasks file catch (XmlException e) { ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(e), "DefaultTasksFileFailure", e.Message); } } } finally { defaultTasksRegistrationAttempted = true; } } }
internal BuildItemGroupChildXml(XmlElement element, ChildType childTypeExpected) { ErrorUtilities.VerifyThrow(element != null, "Need an XML node."); ErrorUtilities.VerifyThrowNoAssert(childTypeExpected != ChildType.Invalid, "Can't expect invalid childtype"); ProjectXmlUtilities.VerifyThrowProjectValidNameAndNamespace(element); this.element = element; // Loop through each of the attributes on the item element. foreach (XmlAttribute attribute in element.Attributes) { switch (attribute.Name) { case XMakeAttributes.include: this.includeAttribute = attribute; break; case XMakeAttributes.exclude: this.excludeAttribute = attribute; break; case XMakeAttributes.condition: this.conditionAttribute = attribute; break; case XMakeAttributes.xmlns: // We already verified that the namespace is correct break; case XMakeAttributes.remove: this.removeAttribute = attribute; break; case XMakeAttributes.keepMetadata: case XMakeAttributes.removeMetadata: case XMakeAttributes.keepDuplicates: // Ignore these - they are part of the new OM. break; default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(attribute); break; } } this.childType = ChildType.Invalid; // Default to modify, if that's one of the child types we are told to expect. if ((childTypeExpected & ChildType.BuildItemModify) == ChildType.BuildItemModify) { this.childType = ChildType.BuildItemModify; } if (this.includeAttribute != null) { ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute((childTypeExpected & ChildType.BuildItemAdd) == ChildType.BuildItemAdd, includeAttribute); ProjectErrorUtilities.VerifyThrowInvalidProject(Include.Length > 0, element, "MissingRequiredAttribute", XMakeAttributes.include, element.Name); ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(removeAttribute == null, removeAttribute); this.childType = ChildType.BuildItemAdd; } if (this.excludeAttribute != null) { ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute((childTypeExpected & ChildType.BuildItemAdd) == ChildType.BuildItemAdd, excludeAttribute); ProjectErrorUtilities.VerifyThrowInvalidProject(Include.Length > 0, element, "MissingRequiredAttribute", XMakeAttributes.include, element.Name); ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(removeAttribute == null, removeAttribute); this.childType = ChildType.BuildItemAdd; } if (this.removeAttribute != null) { ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute((childTypeExpected & ChildType.BuildItemRemove) == ChildType.BuildItemRemove, removeAttribute); ProjectErrorUtilities.VerifyThrowInvalidProject(Remove.Length > 0, element, "MissingRequiredAttribute", XMakeAttributes.remove, element.Name); ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(includeAttribute == null, includeAttribute); ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(excludeAttribute == null, excludeAttribute); this.childType = ChildType.BuildItemRemove; } if (this.childType == ChildType.Invalid) { // So the xml wasn't consistent with any of the child types that we were told to expect. // Figure out the most reasonable message to produce. if ((childTypeExpected & ChildType.BuildItemAdd) == ChildType.BuildItemAdd) { ProjectErrorUtilities.VerifyThrowInvalidProject(Include.Length > 0, element, "MissingRequiredAttribute", XMakeAttributes.include, element.Name); } else if ((childTypeExpected & ChildType.BuildItemRemove) == ChildType.BuildItemRemove) { ProjectErrorUtilities.VerifyThrowInvalidProject(Remove.Length > 0, element, "MissingRequiredAttribute", XMakeAttributes.remove, element.Name); } else { ErrorUtilities.ThrowInternalError("Unexpected child type"); } } // Validate each of the child nodes beneath the item. List <XmlElement> children = ProjectXmlUtilities.GetValidChildElements(element); if (this.childType == ChildType.BuildItemRemove && children.Count != 0) { ProjectErrorUtilities.ThrowInvalidProject(element, "ChildElementsBelowRemoveNotAllowed", children[0].Name); } foreach (XmlElement child in children) { ProjectXmlUtilities.VerifyThrowProjectValidNameAndNamespace(child); ProjectErrorUtilities.VerifyThrowInvalidProject(!FileUtilities.IsItemSpecModifier(child.Name), child, "ItemSpecModifierCannotBeCustomMetadata", child.Name); ProjectErrorUtilities.VerifyThrowInvalidProject(XMakeElements.IllegalItemPropertyNames[child.Name] == null, child, "CannotModifyReservedItemMetadata", child.Name); } }
/// <summary> /// Gets all child elements, ignoring whitespace and comments, and any conditions /// </summary> internal List <XmlElement> GetChildren() { List <XmlElement> children = ProjectXmlUtilities.GetValidChildElements(element); return(children); }
/// <summary> /// Creates a new UsingTask object /// </summary> /// <param name="usingTaskNode"></param> /// <param name="isImported"></param> /// <owner>LukaszG</owner> internal UsingTask(XmlElement usingTaskNode, bool isImported) { this.importedFromAnotherProject = isImported; // make sure this really is a <UsingTask> tag ErrorUtilities.VerifyThrow(usingTaskNode.Name == XMakeElements.usingTask, "Expected <{0}> element; received <{1}> element.", XMakeElements.usingTask, usingTaskNode.Name); bool illegalChildElementFound = false; XmlElement illegalChildElement = null; foreach (XmlElement childElement in usingTaskNode.ChildNodes) { switch (childElement.Name) { case XMakeElements.usingTaskBody: // ignore break; case XMakeElements.usingTaskParameter: // ignore break; case XMakeElements.usingTaskParameterGroup: // ignore break; default: illegalChildElementFound = true; illegalChildElement = childElement; break; } if (illegalChildElementFound) { break; } } // UsingTask has no valid child elements in 3.5 syntax, but in 4.0 syntax it does. // So ignore any valid 4.0 child elements and try to load the project as usual, but // still error out if something we don't expect is found. if (illegalChildElementFound) { ProjectXmlUtilities.ThrowProjectInvalidChildElement(illegalChildElement); } foreach (XmlAttribute usingTaskAttribute in usingTaskNode.Attributes) { switch (usingTaskAttribute.Name) { // get the task name case XMakeAttributes.taskName: taskNameAttribute = usingTaskAttribute; break; // get the assembly name or the assembly file/path, whichever is specified... case XMakeAttributes.assemblyName: assemblyNameAttribute = usingTaskAttribute; break; case XMakeAttributes.assemblyFile: assemblyFileAttribute = usingTaskAttribute; break; // ignore any RequiredRuntime XML attribute // (we'll make this actually do something when we run on a CLR other than v2.0) case XMakeAttributes.requiredRuntime: // Do nothing break; // get the condition, if any case XMakeAttributes.condition: conditionAttribute = usingTaskAttribute; break; // This is only recognized by the new OM: // Just ignore it case XMakeAttributes.requiredPlatform: // Do nothing break; // This is only recognized by the new OM: // Just ignore it case XMakeAttributes.taskFactory: // Do nothing break; // This is only recognized by the new OM: // Just ignore it case XMakeAttributes.runtime: // Do nothing break; // This is only recognized by the new OM: // Just ignore it case XMakeAttributes.architecture: // Do nothing break; default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(usingTaskAttribute); break; } } ProjectErrorUtilities.VerifyThrowInvalidProject(taskNameAttribute != null, usingTaskNode, "MissingRequiredAttribute", XMakeAttributes.taskName, XMakeElements.usingTask); ProjectErrorUtilities.VerifyThrowInvalidProject(taskNameAttribute.Value.Length > 0, taskNameAttribute, "InvalidAttributeValue", taskNameAttribute.Value, XMakeAttributes.taskName, XMakeElements.usingTask); ProjectErrorUtilities.VerifyThrowInvalidProject((assemblyNameAttribute != null) || (assemblyFileAttribute != null), usingTaskNode, "UsingTaskAssemblySpecification", XMakeElements.usingTask, XMakeAttributes.assemblyName, XMakeAttributes.assemblyFile); ProjectErrorUtilities.VerifyThrowInvalidProject((assemblyNameAttribute == null) || (assemblyFileAttribute == null), usingTaskNode, "UsingTaskAssemblySpecification", XMakeElements.usingTask, XMakeAttributes.assemblyName, XMakeAttributes.assemblyFile); ProjectErrorUtilities.VerifyThrowInvalidProject((assemblyNameAttribute == null) || (assemblyNameAttribute.Value.Length > 0), assemblyNameAttribute, "InvalidAttributeValue", String.Empty, XMakeAttributes.assemblyName, XMakeElements.usingTask); ProjectErrorUtilities.VerifyThrowInvalidProject((assemblyFileAttribute == null) || (assemblyFileAttribute.Value.Length > 0), assemblyFileAttribute, "InvalidAttributeValue", String.Empty, XMakeAttributes.assemblyFile, XMakeElements.usingTask); }
/// <summary> /// Internal constructor /// </summary> /// <param name="importElement"></param> /// <param name="isImported"></param> /// <owner>LukaszG</owner> internal Import(XmlElement importElement, Project parentProject, bool isImported) { this.importedFromAnotherProject = isImported; // Make sure the <Import> node has been given to us. ErrorUtilities.VerifyThrow(importElement != null, "Need an XML node representing the <Import> element."); this.importElement = importElement; // Make sure we have a valid parent Project ErrorUtilities.VerifyThrow(parentProject != null, "Need a parent Project object to instantiate an Import."); this.parentProject = parentProject; // Make sure this really is the <Import> node. ProjectXmlUtilities.VerifyThrowElementName(importElement, XMakeElements.import); // Loop through the list of attributes on the <Import> element. foreach (XmlAttribute importAttribute in importElement.Attributes) { switch (importAttribute.Name) { // The "project" attribute points us at the project file to import. case XMakeAttributes.project: // Just store the attribute value at this point. We want to make sure that we evaluate any // Condition attribute before looking at the Project attribute - if the Condition is going to be false, // it's legitimate for the value of the Project attribute to be completely invalid. // For example, <Import Project="$(A)" Condition="$(A)!=''"/> should not cause an error // that the Project attribute is empty. this.projectPathAttribute = importAttribute; break; // If the "condition" attribute is present, then it must evaluate to "true". case XMakeAttributes.condition: this.conditionAttribute = importAttribute; break; // We've come across an attribute in the <Import> element that we // don't recognize. Fail due to invalid project file. default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(importAttribute); break; } } ProjectErrorUtilities.VerifyThrowInvalidProject((this.projectPathAttribute != null) && (this.projectPathAttribute.Value.Length != 0), importElement, "MissingRequiredAttribute", XMakeAttributes.project, XMakeElements.import); // Make sure this node has no children. Our schema doesn't support having // children beneath the <Import> element. if (importElement.HasChildNodes) { // Don't put the "if" condition inside the first parameter to // VerifyThrow..., because we'll get null reference exceptions, // since the parameter importElement.FirstChild.Name is being // passed in regardless of whether the condition holds true or not. ProjectXmlUtilities.ThrowProjectInvalidChildElement(importElement.FirstChild); } }
/// <summary> /// Initializes a persisted target from an existing <Target> element which exists either in the main parent project /// file or one of the imported files. /// </summary> /// <param name="targetElement"></param> /// <param name="project"></param> /// <param name="importedFromAnotherProject"></param> internal Target ( XmlElement targetElement, Project project, bool importedFromAnotherProject ) { // Make sure a valid node has been given to us. error.VerifyThrow(targetElement != null, "Need a valid XML node."); // Make sure this really is the <target> node. ProjectXmlUtilities.VerifyThrowElementName(targetElement, XMakeElements.target); this.targetElement = targetElement; this.parentProject = project; this.parentEngine = project.ParentEngine; this.conditionAttribute = null; this.taskElementList = null; this.importedFromAnotherProject = importedFromAnotherProject; this.buildState = BuildState.NotStarted; this.id = project.ParentEngine.GetNextTargetId(); // The target name and target dependendencies (dependencies on other // targets) are specified as attributes of the <target> element. XmlAttribute returnsAttribute = null; // Loop through all the attributes on the <target> element. foreach (XmlAttribute targetAttribute in targetElement.Attributes) { switch (targetAttribute.Name) { // Process the "condition" attribute. case XMakeAttributes.condition: this.conditionAttribute = targetAttribute; break; // Process the "name" attribute. case XMakeAttributes.name: this.targetName = EscapingUtilities.UnescapeAll(targetAttribute.Value); // Target names cannot contain MSBuild special characters, embedded properties, // or item lists. int indexOfSpecialCharacter = this.targetName.IndexOfAny(XMakeElements.illegalTargetNameCharacters); if (indexOfSpecialCharacter >= 0) { ProjectErrorUtilities.VerifyThrowInvalidProject(false, targetAttribute, "NameInvalid", targetName, targetName[indexOfSpecialCharacter]); } break; // Process the "dependsOnTargets" attribute. case XMakeAttributes.dependsOnTargets: this.dependsOnTargetsAttribute = targetAttribute; break; case XMakeAttributes.inputs: this.inputsAttribute = targetAttribute; recalculateBatchableParameters = true; break; case XMakeAttributes.outputs: this.outputsAttribute = targetAttribute; recalculateBatchableParameters = true; break; // This is only recognized by the new OM: // so that the compat tests keep passing, // ignore it. case XMakeAttributes.keepDuplicateOutputs: break; // This is only recognized by the new OM: // so that the compat tests keep passing, // ignore it. case XMakeAttributes.returns: returnsAttribute = targetAttribute; break; // These are only recognized by the new OM: // while the solution wrapper generator is using // the old OM to parse projects for dependencies, // we must make sure to not fail for these case XMakeAttributes.beforeTargets: case XMakeAttributes.afterTargets: break; default: ProjectXmlUtilities.ThrowProjectInvalidAttribute(targetAttribute); break; } } // Hack to help the 3.5 engine at least pretend to still be able to build on top of // the 4.0 targets. In cases where there is no Outputs attribute, just a Returns attribute, // we can approximate the correct behaviour by making the Returns attribute our "outputs" attribute. if (this.outputsAttribute == null && returnsAttribute != null) { this.outputsAttribute = returnsAttribute; recalculateBatchableParameters = true; } // It's considered an error if a target does not have a name. ProjectErrorUtilities.VerifyThrowInvalidProject((targetName != null) && (targetName.Length > 0), targetElement, "MissingRequiredAttribute", XMakeAttributes.name, XMakeElements.target); this.taskElementList = new ArrayList(); // Process each of the child nodes beneath the <Target>. XmlElement anyOnErrorElement = null; List <XmlElement> childElements = ProjectXmlUtilities.GetValidChildElements(targetElement); foreach (XmlElement childElement in childElements) { bool onErrorOutOfOrder = false; switch (childElement.Name) { case XMakeElements.onError: anyOnErrorElement = childElement; break; default: onErrorOutOfOrder = (anyOnErrorElement != null); this.taskElementList.Add(new BuildTask(childElement, this, this.importedFromAnotherProject)); break; } // Check for out-of-order OnError ProjectErrorUtilities.VerifyThrowInvalidProject(!onErrorOutOfOrder, anyOnErrorElement, "NodeMustBeLastUnderElement", XMakeElements.onError, XMakeElements.target, childElement.Name); } }
/// <summary> /// Constructor for the Choose object. Parses the contents of the Choose /// and sets up list of When blocks /// </summary> /// <remarks> /// </remarks> /// <owner>DavidLe</owner> /// <param name="parentProject"></param> /// <param name="parentGroupingCollection"></param> /// <param name="chooseElement"></param> /// <param name="importedFromAnotherProject"></param> /// <param name="nestingDepth">stack overflow guard</param> internal Choose ( Project parentProject, GroupingCollection parentGroupingCollection, XmlElement chooseElement, bool importedFromAnotherProject, int nestingDepth ) { whenClauseList = new ArrayList(); error.VerifyThrow(chooseElement != null, "Need valid <Choose> element."); // Make sure this really is the <Choose> node. ProjectXmlUtilities.VerifyThrowElementName(chooseElement, XMakeElements.choose); // Stack overflow guard. The only way in the MSBuild file format that MSBuild elements can be // legitimately nested without limit is the <Choose> construct. So, enforce a nesting limit // to avoid blowing our stack. nestingDepth++; ProjectErrorUtilities.VerifyThrowInvalidProject(nestingDepth <= maximumChooseNesting, chooseElement, "ChooseOverflow", maximumChooseNesting); this.importedFromAnotherProject = importedFromAnotherProject; // This <Choose> is coming from an existing XML element, so // walk through all the attributes and child elements, creating the // necessary When objects. // No attributes on the <Choose> element, so don't allow any. ProjectXmlUtilities.VerifyThrowProjectNoAttributes(chooseElement); bool foundOtherwise = false; // Loop through the child nodes of the <Choose> element. foreach (XmlNode chooseChildNode in chooseElement) { switch (chooseChildNode.NodeType) { // Handle XML comments under the <PropertyGroup> node (just ignore them). case XmlNodeType.Comment: // fall through case XmlNodeType.Whitespace: // ignore whitespace break; case XmlNodeType.Element: // The only two types of child nodes that a <Choose> element can contain // is are <When> elements and zero or one <Otherwise> elements. ProjectXmlUtilities.VerifyThrowProjectValidNamespace((XmlElement)chooseChildNode); if (chooseChildNode.Name == XMakeElements.when) { // don't allow <When> to follow <Otherwise> ProjectErrorUtilities.VerifyThrowInvalidProject(!foundOtherwise, chooseChildNode, "WhenNotAllowedAfterOtherwise"); When newWhen = new When(parentProject, parentGroupingCollection, (XmlElement)chooseChildNode, importedFromAnotherProject, When.Options.ProcessWhen, nestingDepth); this.whenClauseList.Add(newWhen); } else if (chooseChildNode.Name == XMakeElements.otherwise) { ProjectErrorUtilities.VerifyThrowInvalidProject(!foundOtherwise, chooseChildNode, "MultipleOtherwise"); When newWhen = new When(parentProject, parentGroupingCollection, (XmlElement)chooseChildNode, importedFromAnotherProject, When.Options.ProcessOtherwise, nestingDepth); otherwiseClause = newWhen; foundOtherwise = true; } else { ProjectXmlUtilities.ThrowProjectInvalidChildElement(chooseChildNode); } break; default: // Unrecognized child element. ProjectXmlUtilities.ThrowProjectInvalidChildElement(chooseChildNode); break; } } ProjectErrorUtilities.VerifyThrowInvalidProject(this.whenClauseList.Count != 0, chooseElement, "ChooseMustContainWhen"); }