diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj index 968bc48..644847c 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/Microsoft.CodeDom.Providers.DotNetCompilerPlatform.nuproj @@ -29,14 +29,41 @@ $(OutputPath) tasks - - content\net45 + + content\net45\app.config.install.xdt - - content\net46 + + content\net45\web.config.install.xdt - - content\net472 + + content\net45\app.config.uninstall.xdt + + + content\net45\web.config.uninstall.xdt + + + content\net46\app.config.install.xdt + + + content\net46\web.config.install.xdt + + + content\net46\app.config.uninstall.xdt + + + content\net46\web.config.uninstall.xdt + + + content\net472\app.config.install.xdt + + + content\net472\web.config.install.xdt + + + content\net472\app.config.uninstall.xdt + + + content\net472\web.config.uninstall.xdt build\net45 diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/config.install.xdt similarity index 58% rename from src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.install.xdt rename to src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/config.install.xdt index f08974c..c73b188 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.install.xdt +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/config.install.xdt @@ -1,5 +1,6 @@ + @@ -23,13 +24,7 @@ - + @@ -46,13 +41,7 @@ - + \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/app.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/config.uninstall.xdt similarity index 89% rename from src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/app.config.uninstall.xdt rename to src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/config.uninstall.xdt index 38e9649..5cd1161 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/app.config.uninstall.xdt +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/config.uninstall.xdt @@ -1,7 +1,7 @@ - + diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/app.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/app.config.install.xdt deleted file mode 100644 index f081013..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/app.config.install.xdt +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/app.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/app.config.uninstall.xdt deleted file mode 100644 index 38e9649..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/app.config.uninstall.xdt +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.uninstall.xdt deleted file mode 100644 index 5733481..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net45/web.config.uninstall.xdt +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/app.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/app.config.install.xdt deleted file mode 100644 index 635c965..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/app.config.install.xdt +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.install.xdt deleted file mode 100644 index 3abe3d3..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.install.xdt +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.uninstall.xdt deleted file mode 100644 index 5733481..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net46/web.config.uninstall.xdt +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/app.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/app.config.install.xdt deleted file mode 100644 index c706a33..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/app.config.install.xdt +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/app.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/app.config.uninstall.xdt deleted file mode 100644 index 38e9649..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/app.config.uninstall.xdt +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/web.config.install.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/web.config.install.xdt deleted file mode 100644 index 4716868..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/web.config.install.xdt +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/web.config.uninstall.xdt b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/web.config.uninstall.xdt deleted file mode 100644 index 5733481..0000000 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/content/net472/web.config.uninstall.xdt +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/common.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/common.ps1 new file mode 100644 index 0000000..a03ecb6 --- /dev/null +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/common.ps1 @@ -0,0 +1,227 @@ +# Copyright (c) .NET Foundation. All rights reserved. +# Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +## +## Assigning a "DefaultValue" to a ParameterDescription will result in emitting this parameter when +## writing out a default compiler declaration. +## +## Setting IsRequired to $true will require the attribute to be set on all declarations in config. +## +Add-Type @" + using System; + + public class CompilerParameterDescription { + public string Name; + public string DefaultValue; + public bool IsRequired; + public bool IsProviderOption; + } + + public class CodeDomProviderDescription { + public string TypeName; + public string Assembly; + public string Version; + public string FileExtension; + public CompilerParameterDescription[] Parameters; + } +"@ + +function InstallCodeDomProvider($providerDescription) { + ##### Update/Rehydrate config declarations ##### + $config = ReadConfigFile + $rehydratedCount = RehydrateOldDeclarations $config $providerDescription + $updatedCount = UpdateDeclarations $config $providerDescription + if ($updatedCount -le 0) { AddDefaultDeclaration $config $providerDescription } + SaveConfigFile $config +} + +function UninstallCodeDomProvider($providerType) { + ##### Dehydrate config declarations ##### + $config = ReadConfigFile + DehydrateDeclarations $config $providerType + SaveConfigFile $config +} + +function GetConfigFileName() { + # Try web.config first. Then fall back to app.config. + $configFile = $project.ProjectItems | where { $_.Name -ieq "web.config" } + if ($configFile -eq $null) { $configFile = $project.ProjectItems | where { $_.Name -ieq "app.config" } } + $configPath = $configFile.Properties | where { $_.Name -ieq "LocalPath" } + if ($configPath -eq $null) { $configPath = $configFile.Properties | where { $_.Name -ieq "FullPath" } } + return $configPath.Value +} + +function GetTempFileName() { + $uname = $project.UniqueName + if ([io.path]::IsPathRooted($uname)) { $uname = $project.Name } + return [io.path]::Combine($env:TEMP, "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.Temp", $uname + ".xml") +} + +function ReadConfigFile() { + $configFile = GetConfigFileName + $configObj = @{ fileName = $configFile; xml = (Select-Xml -Path "$configFile" -XPath /).Node } + $configObj.xml.PreserveWhitespace = $true + return $configObj +} + +function DehydrateDeclarations($config, $typeName) { + $tempFile = GetTempFileName + $xml + $count = 0 + + if ([io.file]::Exists($tempFile)) { + $xml = (Select-Xml -Path "$tempFile" -XPath /).Node + } else { + $xml = New-Object System.Xml.XmlDocument + $xml.PreserveWhitespace = $true + $xml.AppendChild($xml.CreateElement("driedDeclarations")) + } + + foreach ($rec in $config.xml.configuration["system.codedom"].compilers.compiler | where { IsSameType $_.type $typeName }) { + # Remove records from config. + $config.xml.configuration["system.codedom"].compilers.RemoveChild($rec) + + # Add the record to the temp stash. Don't worry about duplicates. + AppendProviderNode $xml.ImportNode($rec, $true) $xml.DocumentElement + $count++ + } + + # Save the dehydrated declarations + $tmpFolder = Split-Path $tempFile + md -Force $tmpFolder + $xml.Save($tempFile) + return $count +} + +function RehydrateOldDeclarations($config, $providerDescription) { + $tempFile = GetTempFileName + if (![io.file]::Exists($tempFile)) { return 0 } + + $count = 0 + $xml = (Select-Xml -Path "$tempFile" -XPath /).Node + $xml.PreserveWhitespace = $true + + foreach($rec in $xml.driedDeclarations.add | where { IsSameType $_.type ($providerDescription.TypeName + "," + $providerDescription.Assembly) }) { + # Remove records that match type, even if we don't end up rehydrating them. + $xml.driedDeclarations.RemoveChild($rec) + + # Skip if an existing record of the same file extension already exists. + $existingRecord = $config.xml.configuration["system.codedom"].compilers.compiler | where { $_.extension -eq $rec.extension } + if ($existingRecord -ne $null) { continue } + + # Bring the record back to life + AppendProviderNode $config.xml.ImportNode($rec, $true) $config.xml.configuration["system.codedom"].compilers + $count++ + } + + # Make dried record removal permanent + $xml.Save($tempFile) + + return $count +} + +function UpdateDeclarations($config, $providerDescription) { + $count = 0 + + foreach ($provider in $config.xml.configuration["system.codedom"].compilers.compiler | where { IsSameType $_.type ($providerDescription.TypeName + "," + $providerDescription.Assembly) }) { + # Count the existing declaration as found + $count++ + + # Update type + $provider.type = "$($providerDescription.TypeName), $($providerDescription.Assembly), Version=$($providerDescription.Version), Culture=neutral, PublicKeyToken=31bf3856ad364e35" + + # Add default attributes if they are required and not already present + foreach ($p in $providerDescription.Parameters | where { ($_.IsRequired -eq $true) and ($_.IsProviderOption -eq $false) }) { + if ($provider.($p.Name) -eq $null) { + if ($p.DefaultValue -eq $null) { + Write-Host "Failed to add parameter to '$($provider.name)' codeDom provider: '$($p.Name)' is required, but does not have a default value." + return + } + $provider.SetAttribute($p.Name, $p.DefaultValue) + } + } + + # Do the same thing for default providerOptions if not already present + foreach ($p in $providerDescription.Parameters | where { ($_.IsRequired -eq $true) and ($_.IsProviderOption -eq $true)}) { + if ($provider.($p.Name) -eq $null) { + if ($p.DefaultValue -eq $null) { + Write-Host "Failed to add providerOption to '$($provider.name)' codeDom provider: '$($p.Name)' is required, but does not have a default value." + return + } + $po = $config.xml.CreateElement("providerOption") + $po.SetAttribute("name", $p.Name) + $po.SetAttribute("value", $p.DefaultValue) + $provider.AppendChild($po) + } + } + } + + return $count +} + +function AddDefaultDeclaration($config, $providerDescription) { + $dd = $config.xml.CreateElement("compiler") + + # file extension first + $dd.SetAttribute("extension", $providerDescription.FileExtension) + + # everything else in the middle + foreach ($p in $providerDescription.Parameters) { + if ($p.IsRequired -and ($p.DefaultValue -eq $null)) { + Write-Host "Failed to add default declaration for code dom extension '$($providerDescription.FileExtension)': '$($p.Name)' is required, but does not have a default value." + return + } + + if ($p.DefaultValue -ne $null) { + if ($p.IsProviderOption -eq $true) { + $po = $config.xml.CreateElement("providerOption") + $po.SetAttribute("name", $p.Name) + $po.SetAttribute("value", $p.DefaultValue) + $dd.AppendChild($po) + } else { + $dd.SetAttribute($p.Name, $p.DefaultValue) + } + } + } + + # type last + $dd.SetAttribute("type", "$($providerDescription.TypeName), $($providerDescription.Assembly), Version=$($providerDescription.Version), Culture=neutral, PublicKeyToken=31bf3856ad364e35") + + AppendProviderNode $dd $config.xml.configuration["system.codedom"].compilers +} + +function AppendProviderNode($provider, $parent) { + $lastSibling = $parent.ChildNodes | where { $_ -isnot [System.Xml.XmlWhitespace] } | select -Last 1 + if ($lastSibling -ne $null) { + $wsBefore = $lastSibling.PreviousSibling | where { $_ -is [System.Xml.XmlWhitespace] } + $parent.InsertAfter($provider, $lastSibling) + if ($wsBefore -ne $null) { $parent.InsertAfter($wsBefore.Clone(), $lastSibling) | Out-Null } + return + } + $parent.AppendChild($provider) +} + +function SaveConfigFile($config) { + $config.xml.Save($config.fileName) +} + +function IsSameType($typeString1, $typeString2) { + + if (($typeString1 -eq $null) -or ($typeString2 -eq $null)) { return $false } + + # First check the type + $t1 = $typeString1.Split(',')[0].Trim() + $t2 = $typeString2.Split(',')[0].Trim() + if ($t1 -cne $t2) { return $false } + + # Then check for assembly match if possible + $a1 = $typeString1.Split(',')[1] + $a2 = $typeString2.Split(',')[1] + if (($a1 -ne $null) -and ($a2 -ne $null)) { + return ($a1.Trim() -eq $a2.Trim()) + } + + # Don't care about assembly. Match is good. + return $true +} diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 index 2cfc630..b2940bb 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/install.ps1 @@ -20,6 +20,56 @@ $projectTargetFramework = $project.Properties.Item('TargetFrameworkMoniker').Val $shouldUseRoslyn45 = $projectTargetFramework -match '4.5' $binDirectory = Join-Path $projectRoot 'bin' +# +# Some things vary depending on which framework version you target. Set the defaults first +# so the variables are scoped for the entire script. If you target an older framework, +# (4.5-4.7.1) then we need to change some of these. +# +$compilerPackageToolsDirectory = Join-Path $compilerPackageDirectory 'tools\roslyn472' +$csLanguageVersion = 'default' +$vbLanguageVersion = 'default' +if ($projectTargetFramework -match '^4\.5') +{ + $compilerPackageToolsDirectory = Join-Path $compilerPackageDirectory 'tools\roslyn45' + $csLanguageVersion = '6' + $vbLanguageVersion = '14' +} +else if (($projectTargetFramework -match '^4\.6') or ($projectTargetFramework -match '^4\.7$') or ($projectTargetFramework -match '^4\.7\.[01]')) +{ + $compilerPackageToolsDirectory = Join-Path $compilerPackageDirectory 'tools\roslyn46' + $csLanguageVersion = 'default' + $vbLanguageVersion = 'default' +} + + +# Fill out the config entries for these code dom providers here. Using powershell to do +# this allows us to cache and restore customized attribute values from previous versions of +# this package in the upgrade scenario. +. "$PSScriptRoot\common.ps1" +$csCodeDomProvider = [CodeDomProviderDescription]@{ + TypeName="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider"; + AssemblyRef="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"; + Version="3.4.0.0"; + FileExtension=".cs"; + Parameters=@( + [CompilerParameterDescription]@{ Name="language"; DefaultValue="c#;cs;csharp"; IsRequired=$true; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="warningLevel"; DefaultValue="4"; IsRequired=$false; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="compilerOptions"; DefaultValue="/langversion:" + $csLanguageVersion + " /nowarn:1659;1699;1701;612;618"; IsRequired=$false; IsProviderOption=$false }); +} +InstallCodeDomProvider $csCodeDomProvider +$vbCodeDomProvider = [CodeDomProviderDescription]@{ + TypeName="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider"; + Assembly="Microsoft.CodeDom.Providers.DotNetCompilerPlatform"; + Version="3.4.0.0"; + FileExtension=".vb"; + Parameters=@( + [CompilerParameterDescription]@{ Name="language"; DefaultValue="vb;vbs;visualbasic;vbscript"; IsRequired=$true; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="warningLevel"; DefaultValue="4"; IsRequired=$false; IsProviderOption=$false }, + [CompilerParameterDescription]@{ Name="compilerOptions"; DefaultValue="/langversion:" + $vbLanguageVersion + " /nowarn:41008,40000,40008 /define:_MYTYPE=\"Web\" /optionInfer+"; IsRequired=$false; IsProviderOption=$false }); +} +InstallCodeDomProvider $vbCodeDomProvider + + # We need to copy the provider assembly into the bin\ folder, otherwise # Microsoft.VisualStudio.Web.Host.exe cannot find the assembly. # However, users will see the error after they clean solutions. @@ -50,14 +100,6 @@ if ($project.Type -eq 'Web Site') { break } - if($shouldUseRoslyn45) - { - $compilerPackageToolsDirectory = Join-Path $compilerPackageDirectory 'tools\roslyn45' - } - else - { - $compilerPackageToolsDirectory = Join-Path $compilerPackageDirectory 'tools\roslynlatest' - } $roslynSubDirectory = Join-Path $binDirectory $roslynSubFolder New-Item $roslynSubDirectory -type directory -force | Out-Null Copy-Item $compilerPackageToolsDirectory\* $roslynSubDirectory -force | Out-Null diff --git a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 index 917ca16..ecabcc5 100644 --- a/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 +++ b/src/Packages/Microsoft.CodeDom.Providers.DotNetCompilerPlatform/tools/uninstall.ps1 @@ -8,6 +8,15 @@ param($installPath, $toolsPath, $package, $project) + +# First save the code dom compiler declarations off to a temp file so they can be restored +# in the event that this is a package upgrade scenario. +. "$PSScriptRoot\common.ps1" +CommonUninstall "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform" +CommonUninstall "Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform" + + +# Then remove the compiler bits from the bin directory $roslynSubFolder = 'roslyn' if ($project -eq $null) { diff --git a/src/Packages/Packages.csproj b/src/Packages/Packages.csproj index 86231bc..1a382de 100644 --- a/src/Packages/Packages.csproj +++ b/src/Packages/Packages.csproj @@ -22,8 +22,34 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + +