public void ImportInitialPropertiesHasCorrectPrecedence() { BuildPropertyGroup environmentProperties = new BuildPropertyGroup(); environmentProperties.SetProperty("Property1", "Value1"); environmentProperties.SetProperty("Property2", "Value2"); environmentProperties.SetProperty("Property3", "Value3"); environmentProperties.SetProperty("Property4", "Value4"); BuildPropertyGroup reservedProperties = new BuildPropertyGroup(); reservedProperties.SetProperty("Property2", "Value5"); reservedProperties.SetProperty("Property3", "Value6"); reservedProperties.SetProperty("Property4", "Value7"); BuildPropertyGroup toolsVersionDependentProperties = new BuildPropertyGroup(); toolsVersionDependentProperties.SetProperty("Property3", "Value8"); toolsVersionDependentProperties.SetProperty("Property4", "Value9"); BuildPropertyGroup globalProperties = new BuildPropertyGroup(); globalProperties.SetProperty("Property4", "Value10"); BuildPropertyGroup evaluatedProperties = new BuildPropertyGroup(); evaluatedProperties.ImportInitialProperties(environmentProperties, reservedProperties, toolsVersionDependentProperties, globalProperties); Assertion.AssertEquals("Value10", evaluatedProperties["Property4"].Value); Assertion.AssertEquals("Value8", evaluatedProperties["Property3"].Value); Assertion.AssertEquals("Value5", evaluatedProperties["Property2"].Value); Assertion.AssertEquals("Value1", evaluatedProperties["Property1"].Value); }
/// <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.Equals(topLevelNode.NamespaceURI, XMakeAttributes.defaultXmlNamespace, StringComparison.OrdinalIgnoreCase)), 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; } } }
/// <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; } } }