コード例 #1
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_SectionNotRegisteredInConfigFile()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                   </configSections>
                   <msbuildToolsets>
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
            string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);

            Assertion.AssertEquals(null, defaultToolsVersion);
            Assertion.AssertEquals(0, values.Count);
        }
コード例 #2
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_Basic()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
                     </toolset>
                     <toolset toolsVersion=""3.5"">
                       <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
            string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);

            Assertion.AssertEquals("2.0", defaultToolsVersion);
            Assertion.AssertEquals(2, values.Count);
            Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
            Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v2.0.x86ret", values["2.0"].ToolsPath);
            Assertion.AssertEquals(0, values["3.5"].BuildProperties.Count);
            Assertion.AssertEquals(@"D:\windows\Microsoft.NET\Framework\v3.5.x86ret", values["3.5"].ToolsPath);
        }
コード例 #3
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_XmlEscapedCharacters()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2&gt;.0"">
                     <toolset toolsVersion=""2&gt;.0"">
                       <property name=""MSBuildBinPath"" value=""x""/>
                       <property name=""foo"" value=""some&gt;value""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);

            Assertion.AssertEquals("2>.0", defaultToolsVersion);
            Assertion.AssertEquals(1, values.Count);
            Assertion.AssertEquals(@"some>value", values["2>.0"].BuildProperties["foo"].Value);
        }
コード例 #4
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_PropertyValueIsEmptyString1()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);

            Assertion.AssertEquals(1, values.Count);
            Assertion.AssertEquals(0, values["2.0"].BuildProperties.Count);
            Assertion.AssertEquals(String.Empty, values["2.0"].ToolsPath);
        }
コード例 #5
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_ToolsPathAndBinPathDiffer()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
                       <property name=""MSBuildToolsPath"" value=""D:\windows\Microsoft.NET\Framework\v3.5.x86ret\""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            //this should throw ...
            bool caught = false;
            try
            {
                reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
            }
            catch (InvalidToolsetDefinitionException)
            {
                caught = true;
            }
            Assertion.Assert(caught);
        }
コード例 #6
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void InvalidPropertyNameInConfigFile()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
                       <property name=""&amp;"" value=""foo""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            //this should throw ...
            reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
        }
コード例 #7
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_EmptyMSBuildToolsetsNode()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets/>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            string defaultToolsVersion = reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);

            Assertion.AssertEquals(null, defaultToolsVersion);
            Assertion.AssertEquals(0, values.Count);
        }
コード例 #8
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_OnlyDefaultSpecified()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0""/>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
        }
コード例 #9
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_ConfigurationErrorsExceptionThrown()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"", new ConfigurationErrorsException());

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            // this should throw ...
            reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
        }
コード例 #10
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_DefaultToolsetUndefined()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""nonexistent"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""D:\windows\Microsoft.NET\Framework\v2.0.x86ret\""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            // Does not throw
            reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
        }
コード例 #11
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void GetToolsetDataFromConfiguration_FileEmpty()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));

            reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);
        }
コード例 #12
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void InvalidRelativePath()
        {
            string invalidRelativePath = @"..\|invalid|";
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildBinPath"" value=""" + invalidRelativePath + @"""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
            reader.ReadToolsets(values, new BuildPropertyGroup(), new BuildPropertyGroup(), true);

            // Don't crash (consistent with invalid absolute path)
            Assertion.AssertEquals(invalidRelativePath, values["2.0"].ToolsPath);
        }
コード例 #13
0
ファイル: ToolsetReader_Tests.cs プロジェクト: nikson/msbuild
        public void RelativePathInValue()
        {
            ToolsetConfigurationReaderTestHelper.WriteConfigFile(@"
                 <configuration>
                   <configSections>
                     <section name=""msbuildToolsets"" type=""Microsoft.Build.BuildEngine.ToolsetConfigurationSection, Microsoft.Build.Engine"" />
                   </configSections>
                   <msbuildToolsets default=""2.0"">
                     <toolset toolsVersion=""2.0"">
                       <property name=""MSBuildToolsPath"" value=""..\foo""/>
                       <!-- derelativization occurs before comparing toolspath and binpath -->
                       <property name=""MSBuildBinPath"" value=""..\.\foo""/>
                     </toolset>
                     <toolset toolsVersion=""3.0"">
                       <!-- properties are expanded before derelativization-->
                       <property name=""MSBuildBinPath"" value=""$(DotDotSlash)bar""/>
                     </toolset>
                   </msbuildToolsets>
                 </configuration>");

            ToolsetReader reader = new ToolsetConfigurationReader(new ReadApplicationConfiguration(
                ToolsetConfigurationReaderTestHelper.ReadApplicationConfigurationTest));

            ToolsetCollection values = new ToolsetCollection(new Engine(ToolsetDefinitionLocations.None));
            BuildPropertyGroup pg = new BuildPropertyGroup();
            pg.SetProperty("DotDotSlash", @"..\");
            reader.ReadToolsets(values, new BuildPropertyGroup(), pg, true);

            string expected1 = Path.GetFullPath(Path.Combine(FileUtilities.CurrentExecutableDirectory, @"..\foo"));
            string expected2 = Path.GetFullPath(Path.Combine(FileUtilities.CurrentExecutableDirectory, @"..\bar"));
            Console.WriteLine(values["2.0"].ToolsPath);
            Assertion.AssertEquals(expected1, values["2.0"].ToolsPath);
            Assertion.AssertEquals(expected2, values["3.0"].ToolsPath);
        }
コード例 #14
0
        /// <summary>
        /// Gathers toolset data from the registry and configuration file, if any.
        /// NOTE:  this method is internal for unit testing purposes only.
        /// </summary>
        /// <param name="toolsets"></param>
        /// <param name="registryReader"></param>
        /// <param name="configurationReader"></param>
        /// <param name="globalProperties"></param>
        /// <param name="initialProperties"></param>
        /// <param name="locations"></param>
        /// <returns></returns>
        internal static string ReadAllToolsets(ToolsetCollection toolsets,
                                               ToolsetRegistryReader registryReader,
                                               ToolsetConfigurationReader configurationReader,
                                               BuildPropertyGroup globalProperties,
                                               BuildPropertyGroup initialProperties,
                                               ToolsetDefinitionLocations locations)
        {
            // The 2.0 .NET Framework installer did not write a ToolsVersion key for itself in the registry.
            // The 3.5 installer writes one for 2.0, but 3.5 might not be installed.
            // The 4.0 and subsequent installers can't keep writing the 2.0 one, because (a) it causes SxS issues and (b) we
            // don't want it unless 2.0 is installed.
            // So if the 2.0 framework is actually installed, and we're reading the registry, create a toolset for it.
            // The registry and config file can overwrite it.
            if (
                ((locations & ToolsetDefinitionLocations.Registry) != 0) &&
                !toolsets.Contains("2.0") &&
                FrameworkLocationHelper.PathToDotNetFrameworkV20 != null
                )
            {
                Toolset synthetic20Toolset = new Toolset("2.0", FrameworkLocationHelper.PathToDotNetFrameworkV20, initialProperties);
                toolsets.Add(synthetic20Toolset);
            }

            // The ordering here is important because the configuration file should have greater precedence
            // than the registry
            string defaultToolsVersionFromRegistry = null;

            ToolsetRegistryReader registryReaderToUse = null;

            if ((locations & ToolsetDefinitionLocations.Registry) == ToolsetDefinitionLocations.Registry)
            {
                registryReaderToUse = registryReader ?? new ToolsetRegistryReader();
                // We do not accumulate properties when reading them from the registry, because the order
                // in which values are returned to us is essentially random: so we disallow one property
                // in the registry to refer to another also in the registry
                defaultToolsVersionFromRegistry =
                    registryReaderToUse.ReadToolsets(toolsets, globalProperties, initialProperties, false /* do not accumulate properties */);
            }

            string defaultToolsVersionFromConfiguration = null;

            ToolsetConfigurationReader configurationReaderToUse = null;

            if ((locations & ToolsetDefinitionLocations.ConfigurationFile) == ToolsetDefinitionLocations.ConfigurationFile)
            {
                if (configurationReader == null && ConfigurationFileMayHaveToolsets())
                {
                    // We haven't been passed in a fake configuration reader by a unit test,
                    // and it looks like we have a .config file to read, so create a real
                    // configuration reader
                    configurationReader = new ToolsetConfigurationReader();
                }

                if (configurationReader != null)
                {
                    configurationReaderToUse = configurationReader ?? new ToolsetConfigurationReader();
                    // Accumulation of properties is okay in the config file because it's deterministically ordered
                    defaultToolsVersionFromConfiguration =
                        configurationReaderToUse.ReadToolsets(toolsets, globalProperties, initialProperties, true /* accumulate properties */);
                }
            }

            // We'll use the default from the configuration file if it was specified, otherwise we'll try
            // the one from the registry.  It's possible (and valid) that neither the configuration file
            // nor the registry specify a default, in which case we'll just return null.
            string defaultToolsVersion = defaultToolsVersionFromConfiguration ?? defaultToolsVersionFromRegistry;

            // If we got a default version from the registry or config file, and it
            // actually exists, fine.
            // Otherwise we have to come up with one.
            if (defaultToolsVersion == null || !toolsets.Contains(defaultToolsVersion))
            {
                // We're going to choose a hard coded default tools version of 2.0.
                defaultToolsVersion = Constants.defaultToolsVersion;

                // But don't overwrite any existing tools path for this default we're choosing.
                if (!toolsets.Contains(Constants.defaultToolsVersion))
                {
                    // There's no tools path already for 2.0, so use the path to the v2.0 .NET Framework.
                    // If an old-fashioned caller sets BinPath property, or passed a BinPath to the constructor,
                    // that will overwrite what we're setting here.
                    ErrorUtilities.VerifyThrow(Constants.defaultToolsVersion == "2.0", "Getting 2.0 FX path so default should be 2.0");
                    string pathToFramework = FrameworkLocationHelper.PathToDotNetFrameworkV20;

                    // We could not find the default toolsversion because it was not installed on the machine. Fallback to the
                    // one we expect to always be there when running msbuild 4.0.
                    if (pathToFramework == null)
                    {
                        pathToFramework     = FrameworkLocationHelper.PathToDotNetFrameworkV40;
                        defaultToolsVersion = Constants.defaultFallbackToolsVersion;
                    }

                    // Again don't overwrite any existing tools path for this default we're choosing.
                    if (!toolsets.Contains(defaultToolsVersion))
                    {
                        Toolset defaultToolset = new Toolset(defaultToolsVersion, pathToFramework, initialProperties);
                        toolsets.Add(defaultToolset);
                    }
                }
            }

            return(defaultToolsVersion);
        }
コード例 #15
0
ファイル: ToolsetReader.cs プロジェクト: nikson/msbuild
        /// <summary>
        /// Gathers toolset data from the registry and configuration file, if any.
        /// NOTE:  this method is internal for unit testing purposes only.
        /// </summary>
        /// <param name="toolsets"></param>
        /// <param name="registryReader"></param>
        /// <param name="configurationReader"></param>
        /// <param name="globalProperties"></param>
        /// <param name="initialProperties"></param>
        /// <param name="locations"></param>
        /// <returns></returns>
        internal static string ReadAllToolsets(ToolsetCollection toolsets,
                                               ToolsetRegistryReader registryReader,
                                               ToolsetConfigurationReader configurationReader,
                                               BuildPropertyGroup globalProperties,
                                               BuildPropertyGroup initialProperties,
                                               ToolsetDefinitionLocations locations)
        {
            // The 2.0 .NET Framework installer did not write a ToolsVersion key for itself in the registry. 
            // The 3.5 installer writes one for 2.0, but 3.5 might not be installed.  
            // The 4.0 and subsequent installers can't keep writing the 2.0 one, because (a) it causes SxS issues and (b) we 
            // don't want it unless 2.0 is installed.
            // So if the 2.0 framework is actually installed, and we're reading the registry, create a toolset for it. 
            // The registry and config file can overwrite it.
            if (
                ((locations & ToolsetDefinitionLocations.Registry) != 0) &&
                !toolsets.Contains("2.0") &&
                FrameworkLocationHelper.PathToDotNetFrameworkV20 != null
              )
            {
                Toolset synthetic20Toolset = new Toolset("2.0", FrameworkLocationHelper.PathToDotNetFrameworkV20, initialProperties);
                toolsets.Add(synthetic20Toolset);
            }

            // The ordering here is important because the configuration file should have greater precedence
            // than the registry
            string defaultToolsVersionFromRegistry = null;

            ToolsetRegistryReader registryReaderToUse = null;
            if ((locations & ToolsetDefinitionLocations.Registry) == ToolsetDefinitionLocations.Registry)
            {
                registryReaderToUse = registryReader == null ? new ToolsetRegistryReader() : registryReader;
                // We do not accumulate properties when reading them from the registry, because the order
                // in which values are returned to us is essentially random: so we disallow one property
                // in the registry to refer to another also in the registry
                defaultToolsVersionFromRegistry = 
                    registryReaderToUse.ReadToolsets(toolsets, globalProperties, initialProperties, false /* do not accumulate properties */);
            }

            string defaultToolsVersionFromConfiguration = null;
            
            ToolsetConfigurationReader configurationReaderToUse = null;
            if ((locations & ToolsetDefinitionLocations.ConfigurationFile) == ToolsetDefinitionLocations.ConfigurationFile)
            {
                if (configurationReader == null && ConfigurationFileMayHaveToolsets())
                {
                    // We haven't been passed in a fake configuration reader by a unit test,
                    // and it looks like we have a .config file to read, so create a real
                    // configuration reader
                    configurationReader = new ToolsetConfigurationReader();
                }

                if (configurationReader != null)
                {
                    configurationReaderToUse = configurationReader == null ? new ToolsetConfigurationReader() : configurationReader;
                    // Accumulation of properties is okay in the config file because it's deterministically ordered
                    defaultToolsVersionFromConfiguration =
                        configurationReaderToUse.ReadToolsets(toolsets, globalProperties, initialProperties, true /* accumulate properties */);
                }
            }
            
            // We'll use the default from the configuration file if it was specified, otherwise we'll try
            // the one from the registry.  It's possible (and valid) that neither the configuration file
            // nor the registry specify a default, in which case we'll just return null.
            string defaultToolsVersion = defaultToolsVersionFromConfiguration ?? defaultToolsVersionFromRegistry;

            // If we got a default version from the registry or config file, and it
            // actually exists, fine.
            // Otherwise we have to come up with one.
            if (defaultToolsVersion == null || !toolsets.Contains(defaultToolsVersion))
            {
                // We're going to choose a hard coded default tools version of 2.0.
                defaultToolsVersion = Constants.defaultToolsVersion;

                // But don't overwrite any existing tools path for this default we're choosing.
                if (!toolsets.Contains(Constants.defaultToolsVersion))
                {
                    // There's no tools path already for 2.0, so use the path to the v2.0 .NET Framework.
                    // If an old-fashioned caller sets BinPath property, or passed a BinPath to the constructor,
                    // that will overwrite what we're setting here.
                    ErrorUtilities.VerifyThrow(Constants.defaultToolsVersion == "2.0", "Getting 2.0 FX path so default should be 2.0");
                    string pathToFramework = FrameworkLocationHelper.PathToDotNetFrameworkV20;

                    // We could not find the default toolsversion because it was not installed on the machine. Fallback to the 
                    // one we expect to always be there when running msbuild 4.0.
                    if (pathToFramework == null)
                    {
                        pathToFramework = FrameworkLocationHelper.PathToDotNetFrameworkV40;
                        defaultToolsVersion = Constants.defaultFallbackToolsVersion;
                    }

                    // Again don't overwrite any existing tools path for this default we're choosing.
                    if (!toolsets.Contains(defaultToolsVersion))
                    {
                        Toolset defaultToolset = new Toolset(defaultToolsVersion, pathToFramework, initialProperties);
                        toolsets.Add(defaultToolset);
                    }
                }
            }

            return defaultToolsVersion;
        }