/// <summary> /// Expands the given unexpanded property expression using the properties in the /// given expander. /// </summary> private string ExpandPropertyUnescaped(ToolsetPropertyDefinition property, Expander <ProjectPropertyInstance, ProjectItemInstance> expander) { try { return(expander.ExpandIntoStringAndUnescape(property.Value, ExpanderOptions.ExpandProperties, property.Source)); } catch (InvalidProjectFileException ex) { InvalidToolsetDefinitionException.Throw(ex, "ErrorEvaluatingToolsetPropertyExpression", property.Value, property.Source.LocationString, ex.BaseMessage); } return(string.Empty); }
/// <summary> /// Sets the given property in the given property group. /// </summary> private void SetProperty(ToolsetPropertyDefinition property, PropertyDictionary <ProjectPropertyInstance> propertyGroup, PropertyDictionary <ProjectPropertyInstance> globalProperties) { try { // Global properties cannot be overwritten if (globalProperties[property.Name] == null) { propertyGroup.Set(ProjectPropertyInstance.Create(property.Name, EscapingUtilities.UnescapeAll(property.Value), true /* may be reserved */, false /* not immutable */)); } } catch (ArgumentException ex) { InvalidToolsetDefinitionException.Throw(ex, "InvalidPropertyNameInToolset", property.Name, property.Source.LocationString, ex.Message); } }
/// <summary> /// Reads the settings for a specified tools version /// </summary> private Toolset ReadToolset ( ToolsetPropertyDefinition toolsVersion, PropertyDictionary <ProjectPropertyInstance> globalProperties, PropertyDictionary <ProjectPropertyInstance> initialProperties, bool accumulateProperties ) { // Initial properties is the set of properties we're going to use to expand property expressions like $(foo) // in the values we read out of the registry or config file. We'll add to it as we pick up properties (including binpath) // from the registry or config file, so that properties there can be referenced in values below them. // After processing all the properties, we don't need initialProperties anymore. string toolsPath = null; string binPath = null; PropertyDictionary <ProjectPropertyInstance> properties = new PropertyDictionary <ProjectPropertyInstance>(); IEnumerable <ToolsetPropertyDefinition> rawProperties = GetPropertyDefinitions(toolsVersion.Name); Expander <ProjectPropertyInstance, ProjectItemInstance> expander = new Expander <ProjectPropertyInstance, ProjectItemInstance>(initialProperties, FileSystems.Default); foreach (ToolsetPropertyDefinition property in rawProperties) { EvaluateAndSetProperty(property, properties, globalProperties, initialProperties, accumulateProperties, ref toolsPath, ref binPath, ref expander); } Dictionary <string, SubToolset> subToolsets = new Dictionary <string, SubToolset>(StringComparer.OrdinalIgnoreCase); IEnumerable <string> subToolsetVersions = GetSubToolsetVersions(toolsVersion.Name); foreach (string subToolsetVersion in subToolsetVersions) { string subToolsetToolsPath = null; string subToolsetBinPath = null; IEnumerable <ToolsetPropertyDefinition> rawSubToolsetProperties = GetSubToolsetPropertyDefinitions(toolsVersion.Name, subToolsetVersion); PropertyDictionary <ProjectPropertyInstance> subToolsetProperties = new PropertyDictionary <ProjectPropertyInstance>(); // If we have a sub-toolset, any values defined here will override the toolset properties. foreach (ToolsetPropertyDefinition property in rawSubToolsetProperties) { EvaluateAndSetProperty(property, subToolsetProperties, globalProperties, initialProperties, false /* do not ever accumulate sub-toolset properties */, ref subToolsetToolsPath, ref subToolsetBinPath, ref expander); } if (subToolsetToolsPath != null || subToolsetBinPath != null) { InvalidToolsetDefinitionException.Throw("MSBuildToolsPathNotSupportedInSubToolsets", toolsVersion.Name, toolsVersion.Source.LocationString, subToolsetVersion); } subToolsets[subToolsetVersion] = new SubToolset(subToolsetVersion, subToolsetProperties); } // All tools versions must specify a value for MSBuildToolsPath (or MSBuildBinPath) if (String.IsNullOrEmpty(toolsPath) && String.IsNullOrEmpty(binPath)) { return(null); } // If both MSBuildBinPath and MSBuildToolsPath are present, they must be the same if (toolsPath != null && binPath != null && !toolsPath.Equals(binPath, StringComparison.OrdinalIgnoreCase)) { InvalidToolsetDefinitionException.Throw("ConflictingValuesOfMSBuildToolsPath", toolsVersion.Name, toolsVersion.Source.LocationString); } AppendStandardProperties(properties, globalProperties, toolsVersion.Name, null, toolsPath); Toolset toolset = null; try { var importSearchPathsTable = GetProjectImportSearchPathsTable(toolsVersion.Name, NativeMethodsShared.GetOSNameForExtensionsPath()); toolset = new Toolset(toolsVersion.Name, toolsPath == null ? binPath : toolsPath, properties, _environmentProperties, globalProperties, subToolsets, MSBuildOverrideTasksPath, DefaultOverrideToolsVersion, importSearchPathsTable); } catch (ArgumentException e) { InvalidToolsetDefinitionException.Throw("ErrorCreatingToolset", toolsVersion.Name, e.Message); } return(toolset); }
/// <summary> /// Sets the given property in the given property group. /// </summary> private void SetProperty(ToolsetPropertyDefinition property, PropertyDictionary<ProjectPropertyInstance> propertyGroup, PropertyDictionary<ProjectPropertyInstance> globalProperties) { try { // Global properties cannot be overwritten if (globalProperties[property.Name] == null) { propertyGroup.Set(ProjectPropertyInstance.Create(property.Name, EscapingUtilities.UnescapeAll(property.Value), true /* may be reserved */, false /* not immutable */)); } } catch (ArgumentException ex) { InvalidToolsetDefinitionException.Throw(ex, "InvalidPropertyNameInToolset", property.Name, property.Source.LocationString, ex.Message); } }
/// <summary> /// Expands the given unexpanded property expression using the properties in the /// given expander. /// </summary> private string ExpandPropertyLeaveEscaped(ToolsetPropertyDefinition property, Expander<ProjectPropertyInstance, ProjectItemInstance> expander) { try { return expander.ExpandIntoStringLeaveEscaped(property.Value, ExpanderOptions.ExpandProperties, property.Source); } catch (InvalidProjectFileException ex) { InvalidToolsetDefinitionException.Throw(ex, "ErrorEvaluatingToolsetPropertyExpression", property.Value, property.Source.LocationString, ex.BaseMessage); } return string.Empty; }
/// <summary> /// Processes a particular ToolsetPropertyDefinition into the correct value and location in the initial and/or final property set. /// </summary> /// <param name="property">The ToolsetPropertyDefinition being analyzed.</param> /// <param name="properties">The final set of properties that we wish this toolset property to be added to. </param> /// <param name="globalProperties">The global properties, used for expansion and to make sure none are overridden.</param> /// <param name="initialProperties">The initial properties, used for expansion and added to if "accumulateProperties" is true.</param> /// <param name="accumulateProperties">If "true", we add this property to the initialProperties dictionary, as well, so that properties later in the toolset can use this value.</param> /// <param name="toolsPath">If this toolset property is the "MSBuildToolsPath" property, we will return the value in this parameter.</param> /// <param name="binPath">If this toolset property is the "MSBuildBinPath" property, we will return the value in this parameter.</param> /// <param name="expander">The expander used to expand the value of the properties. Ref because if we are accumulating the properties, we need to re-create the expander to account for the new property value.</param> private void EvaluateAndSetProperty(ToolsetPropertyDefinition property, PropertyDictionary<ProjectPropertyInstance> properties, PropertyDictionary<ProjectPropertyInstance> globalProperties, PropertyDictionary<ProjectPropertyInstance> initialProperties, bool accumulateProperties, ref string toolsPath, ref string binPath, ref Expander<ProjectPropertyInstance, ProjectItemInstance> expander) { if (0 == String.Compare(property.Name, ReservedPropertyNames.toolsPath, StringComparison.OrdinalIgnoreCase)) { toolsPath = ExpandPropertyLeaveEscaped(property, expander); toolsPath = ExpandRelativePathsRelativeToExeLocation(toolsPath); if (accumulateProperties) { SetProperty ( new ToolsetPropertyDefinition(ReservedPropertyNames.toolsPath, toolsPath, property.Source), initialProperties, globalProperties ); } } else if (0 == String.Compare(property.Name, ReservedPropertyNames.binPath, StringComparison.OrdinalIgnoreCase)) { binPath = ExpandPropertyLeaveEscaped(property, expander); binPath = ExpandRelativePathsRelativeToExeLocation(binPath); if (accumulateProperties) { SetProperty ( new ToolsetPropertyDefinition(ReservedPropertyNames.binPath, binPath, property.Source), initialProperties, globalProperties ); } } else if (ReservedPropertyNames.IsReservedProperty(property.Name)) { // We don't allow toolsets to define reserved properties string baseMessage = ResourceUtilities.FormatResourceString("CannotModifyReservedProperty", property.Name); InvalidToolsetDefinitionException.Throw("InvalidPropertyNameInToolset", property.Name, property.Source.LocationString, baseMessage); } else { // It's an arbitrary property property.Value = ExpandPropertyLeaveEscaped(property, expander); SetProperty(property, properties, globalProperties); if (accumulateProperties) { SetProperty(property, initialProperties, globalProperties); } } if (accumulateProperties) { expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(initialProperties); } }
/// <summary> /// Reads the settings for a specified tools version /// </summary> private Toolset ReadToolset ( ToolsetPropertyDefinition toolsVersion, PropertyDictionary<ProjectPropertyInstance> globalProperties, PropertyDictionary<ProjectPropertyInstance> initialProperties, bool accumulateProperties ) { // Initial properties is the set of properties we're going to use to expand property expressions like $(foo) // in the values we read out of the registry or config file. We'll add to it as we pick up properties (including binpath) // from the registry or config file, so that properties there can be referenced in values below them. // After processing all the properties, we don't need initialProperties anymore. string toolsPath = null; string binPath = null; PropertyDictionary<ProjectPropertyInstance> properties = new PropertyDictionary<ProjectPropertyInstance>(); IEnumerable<ToolsetPropertyDefinition> rawProperties = GetPropertyDefinitions(toolsVersion.Name); Expander<ProjectPropertyInstance, ProjectItemInstance> expander = new Expander<ProjectPropertyInstance, ProjectItemInstance>(initialProperties); foreach (ToolsetPropertyDefinition property in rawProperties) { EvaluateAndSetProperty(property, properties, globalProperties, initialProperties, accumulateProperties, ref toolsPath, ref binPath, ref expander); } Dictionary<string, SubToolset> subToolsets = new Dictionary<string, SubToolset>(StringComparer.OrdinalIgnoreCase); IEnumerable<string> subToolsetVersions = GetSubToolsetVersions(toolsVersion.Name); foreach (string subToolsetVersion in subToolsetVersions) { string subToolsetToolsPath = null; string subToolsetBinPath = null; IEnumerable<ToolsetPropertyDefinition> rawSubToolsetProperties = GetSubToolsetPropertyDefinitions(toolsVersion.Name, subToolsetVersion); PropertyDictionary<ProjectPropertyInstance> subToolsetProperties = new PropertyDictionary<ProjectPropertyInstance>(); // If we have a sub-toolset, any values defined here will override the toolset properties. foreach (ToolsetPropertyDefinition property in rawSubToolsetProperties) { EvaluateAndSetProperty(property, subToolsetProperties, globalProperties, initialProperties, false /* do not ever accumulate sub-toolset properties */, ref subToolsetToolsPath, ref subToolsetBinPath, ref expander); } if (subToolsetToolsPath != null || subToolsetBinPath != null) { InvalidToolsetDefinitionException.Throw("MSBuildToolsPathNotSupportedInSubToolsets", toolsVersion.Name, toolsVersion.Source.LocationString, subToolsetVersion); } subToolsets[subToolsetVersion] = new SubToolset(subToolsetVersion, subToolsetProperties); } // All tools versions must specify a value for MSBuildToolsPath (or MSBuildBinPath) if (String.IsNullOrEmpty(toolsPath) && String.IsNullOrEmpty(binPath)) { return null; } // If both MSBuildBinPath and MSBuildToolsPath are present, they must be the same if (toolsPath != null && binPath != null && !toolsPath.Equals(binPath, StringComparison.OrdinalIgnoreCase)) { InvalidToolsetDefinitionException.Throw("ConflictingValuesOfMSBuildToolsPath", toolsVersion.Name, toolsVersion.Source.LocationString); } Toolset toolset = null; try { var importSearchPathsTable = GetProjectImportSearchPathsTable(toolsVersion.Name, NativeMethodsShared.GetOSNameForExtensionsPath()); toolset = new Toolset(toolsVersion.Name, toolsPath == null ? binPath : toolsPath, properties, _environmentProperties, globalProperties, subToolsets, MSBuildOverrideTasksPath, DefaultOverrideToolsVersion, importSearchPathsTable); } catch (ArgumentException e) { InvalidToolsetDefinitionException.Throw("ErrorCreatingToolset", toolsVersion.Name, e.Message); } return toolset; }