public void ExpandExtensionsPathFallback() { string extnTargetsFileContentTemplate = @" <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' > <Target Name='FromExtn'> <Message Text='Running FromExtn'/> </Target> <Import Project='$(MSBuildExtensionsPath)\\foo\\extn.proj' Condition=""Exists('$(MSBuildExtensionsPath)\foo\extn.proj')"" /> </Project>"; var configFileContents = @" <configuration> <configSections> <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build"" /> </configSections> <msbuildToolsets default=""14.1""> <toolset toolsVersion=""14.1""> <property name=""MSBuildToolsPath"" value="".""/> <property name=""MSBuildBinPath"" value="".""/> <projectImportSearchPaths> <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @"""> <property name=""MSBuildExtensionsPath"" value=""$(FallbackExpandDir1)"" /> </searchPaths> </projectImportSearchPaths> </toolset> </msbuildToolsets> </configuration>"; string extnDir1 = null; string mainProjectPath = null; try { extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("foo", "extn.proj"), extnTargetsFileContentTemplate); mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", GetMainTargetFileContent()); ToolsetConfigurationReaderTestHelper.WriteConfigFile(configFileContents); var reader = GetStandardConfigurationReader(); var projectCollection = new ProjectCollection(new Dictionary <string, string> { ["FallbackExpandDir1"] = extnDir1 }); projectCollection.ResetToolsetsForTests(reader); var logger = new MockLogger(); projectCollection.RegisterLogger(logger); var project = projectCollection.LoadProject(mainProjectPath); Assert.True(project.Build("Main")); logger.AssertLogContains("Running FromExtn"); } finally { FileUtilities.DeleteNoThrow(mainProjectPath); FileUtilities.DeleteDirectoryNoThrow(extnDir1, true); } }
public void FallbackImportWithFileNotFoundWhenPropertyNotDefined() { // Import something from $(UndefinedProperty) string mainTargetsFileContent = @" <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' > <Import Project='$(UndefinedProperty)\filenotfound.props' /> <Target Name='Main' DependsOnTargets='FromExtn' /> </Project>"; string extnDir1 = null; string mainProjectPath = null; try { // The path to "extensions1" fallback should exist, but the file doens't need to extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("file.props"), string.Empty); // Implement fallback for UndefinedProperty, but don't define the property. var configFileContents = @" <configuration> <configSections> <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"" /> </configSections> <msbuildToolsets default=""" + toolsVersionToUse + @"""> <toolset toolsVersion=""" + toolsVersionToUse + @"""> <property name=""MSBuildToolsPath"" value="".""/> <property name=""MSBuildBinPath"" value="".""/> <projectImportSearchPaths> <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @"""> <property name=""UndefinedProperty"" value=""" + extnDir1 + @""" /> </searchPaths> </projectImportSearchPaths> </toolset> </msbuildToolsets> </configuration>"; mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", mainTargetsFileContent); ToolsetConfigurationReaderTestHelper.WriteConfigFile(configFileContents); var reader = GetStandardConfigurationReader(); var projectCollection = new ProjectCollection(new Dictionary <string, string> { ["FallbackExpandDir1"] = extnDir1 }); projectCollection.ResetToolsetsForTests(reader); var logger = new MockLogger(); projectCollection.RegisterLogger(logger); Assert.Throws <InvalidProjectFileException>(() => projectCollection.LoadProject(mainProjectPath)); logger.AssertLogContains(@"MSB4226: The imported project """ + Path.Combine("$(UndefinedProperty)", "filenotfound.props") + @""" was not found. Also, tried to find"); } finally { FileUtilities.DeleteNoThrow(mainProjectPath); FileUtilities.DeleteDirectoryNoThrow(extnDir1, true); } }
private ToolsetConfigurationReader WriteConfigFileAndGetReader(string extnPathPropertyName, params string[] extnDirs) { string combinedExtnDirs = extnDirs != null?String.Join(";", extnDirs) : String.Empty; ToolsetConfigurationReaderTestHelper.WriteConfigFile(@" <configuration> <configSections> <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build"" /> </configSections> <msbuildToolsets default=""14.1""> <toolset toolsVersion=""14.1""> <property name=""MSBuildToolsPath"" value=""."" /> <property name=""MSBuildBinPath"" value=""."" /> <projectImportSearchPaths> <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @"""> <property name=""" + extnPathPropertyName + @""" value=""" + combinedExtnDirs + @""" /> </searchPaths> </projectImportSearchPaths> </toolset> </msbuildToolsets> </configuration>"); return(GetStandardConfigurationReader()); }
public void ImportFromExtensionsPathAnd32And64() { string extnTargetsFileContentTemplate = @" <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' > <Target Name='FromExtn{0}' DependsOnTargets='{1}'> <Message Text='Running FromExtn{0}'/> </Target> {2} </Project> "; var configFileContents = @" <configuration> <configSections> <section name=""msbuildToolsets"" type=""Microsoft.Build.Evaluation.ToolsetConfigurationSection, Microsoft.Build"" /> </configSections> <msbuildToolsets default=""14.1""> <toolset toolsVersion=""14.1""> <property name=""MSBuildToolsPath"" value="".""/> <property name=""MSBuildBinPath"" value=""" + /*v4Folder*/ "." + @"""/> <projectImportSearchPaths> <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @"""> <property name=""MSBuildExtensionsPath"" value=""{0}"" /> <property name=""MSBuildExtensionsPath32"" value=""{1}"" /> <property name=""MSBuildExtensionsPath64"" value=""{2}"" /> </searchPaths> </projectImportSearchPaths> </toolset> </msbuildToolsets> </configuration>"; string extnDir1 = null, extnDir2 = null, extnDir3 = null; string mainProjectPath = null; try { extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("foo", "extn.proj"), String.Format(extnTargetsFileContentTemplate, String.Empty, "FromExtn2", "<Import Project='$(MSBuildExtensionsPath32)\\bar\\extn2.proj' />")); extnDir2 = GetNewExtensionsPathAndCreateFile("extensions2", Path.Combine("bar", "extn2.proj"), String.Format(extnTargetsFileContentTemplate, 2, "FromExtn3", "<Import Project='$(MSBuildExtensionsPath64)\\xyz\\extn3.proj' />")); extnDir3 = GetNewExtensionsPathAndCreateFile("extensions3", Path.Combine("xyz", "extn3.proj"), String.Format(extnTargetsFileContentTemplate, 3, String.Empty, String.Empty)); mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", GetMainTargetFileContent()); var configFilePath = ToolsetConfigurationReaderTestHelper.WriteConfigFile(String.Format(configFileContents, extnDir1, extnDir2, extnDir3)); var reader = GetStandardConfigurationReader(); var projColln = new ProjectCollection(); projColln.ResetToolsetsForTests(reader); var logger = new MockLogger(); projColln.RegisterLogger(logger); var project = projColln.LoadProject(mainProjectPath); Assert.True(project.Build("Main")); logger.AssertLogContains("Running FromExtn3"); logger.AssertLogContains("Running FromExtn2"); logger.AssertLogContains("Running FromExtn"); } finally { if (mainProjectPath != null) { FileUtilities.DeleteNoThrow(mainProjectPath); } if (extnDir1 != null) { FileUtilities.DeleteDirectoryNoThrow(extnDir1, recursive: true); } if (extnDir2 != null) { FileUtilities.DeleteDirectoryNoThrow(extnDir2, recursive: true); } if (extnDir3 != null) { FileUtilities.DeleteDirectoryNoThrow(extnDir3, recursive: true); } } }
/// <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); }
public void FallbackImportWithIndirectReference() { string mainTargetsFileContent = @" <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' > <PropertyGroup> <VSToolsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v99</VSToolsPath> </PropertyGroup> <Import Project='$(VSToolsPath)\DNX\Microsoft.DNX.Props' Condition=""Exists('$(VSToolsPath)\DNX\Microsoft.DNX.Props')"" /> <Target Name='Main' DependsOnTargets='FromExtn' /> </Project>"; string extnTargetsFileContentTemplate = @" <Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003' > <Target Name='FromExtn'> <Message Text='Running FromExtn'/> </Target> </Project>"; var configFileContents = @" <configuration> <configSections> <section name=""msbuildToolsets"" type=""net.r_eg.IeXod.Evaluation.ToolsetConfigurationSection, net.r_eg.IeXod"" /> </configSections> <msbuildToolsets default=""" + toolsVersionToUse + @"""> <toolset toolsVersion=""" + toolsVersionToUse + @"""> <property name=""MSBuildToolsPath"" value="".""/> <property name=""MSBuildBinPath"" value="".""/> <projectImportSearchPaths> <searchPaths os=""" + NativeMethodsShared.GetOSNameForExtensionsPath() + @"""> <property name=""MSBuildExtensionsPath"" value=""$(FallbackExpandDir1)"" /> <property name=""VSToolsPath"" value=""$(FallbackExpandDir1)\Microsoft\VisualStudio\v99"" /> </searchPaths> </projectImportSearchPaths> </toolset> </msbuildToolsets> </configuration>"; string extnDir1 = null; string mainProjectPath = null; try { extnDir1 = GetNewExtensionsPathAndCreateFile("extensions1", Path.Combine("Microsoft", "VisualStudio", "v99", "DNX", "Microsoft.DNX.Props"), extnTargetsFileContentTemplate); mainProjectPath = ObjectModelHelpers.CreateFileInTempProjectDirectory("main.proj", mainTargetsFileContent); ToolsetConfigurationReaderTestHelper.WriteConfigFile(configFileContents); var reader = GetStandardConfigurationReader(); var projectCollection = new ProjectCollection(new Dictionary <string, string> { ["FallbackExpandDir1"] = extnDir1 }); projectCollection.ResetToolsetsForTests(reader); var logger = new MockLogger(); projectCollection.RegisterLogger(logger); var project = projectCollection.LoadProject(mainProjectPath); Assert.True(project.Build("Main")); logger.AssertLogContains("Running FromExtn"); } finally { FileUtilities.DeleteNoThrow(mainProjectPath); FileUtilities.DeleteDirectoryNoThrow(extnDir1, true); } }